diff options
Diffstat (limited to 'core/src/main/java/coffee/liz/abstractionengine/grid')
| -rw-r--r-- | core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java | 19 | ||||
| -rw-r--r-- | core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java | 52 |
2 files changed, 44 insertions, 27 deletions
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java index 77ff4e8..9f58ff2 100644 --- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java +++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java @@ -2,14 +2,29 @@ package coffee.liz.abstractionengine.grid.component; import coffee.liz.ecs.math.Vec2; import coffee.liz.ecs.model.Component; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.RequiredArgsConstructor; -import java.util.Map; +import java.util.List; @RequiredArgsConstructor +@AllArgsConstructor @Data +@Builder(toBuilder = true) public class Substitution implements Component { + /** + * Produced terms spawn with this momentum. + */ private final Vec2<Integer> spawnMomentum; - private final Map<String, Vec2<Integer>> termDependencies; + + /** + * Left-to-right dependencies' grid positions to apply in order. + * i.e. [(0, 0), (0, 1)] would apply lambda term at (0, 0) then (0, 1) to a -> b -> a => (0, 0) + */ + private final List<Vec2<Integer>> termDependencies; + + @Builder.Default + private boolean isActive = true; } diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java index 74bc3fc..f93d60b 100644 --- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java +++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java @@ -8,12 +8,16 @@ import coffee.liz.abstractionengine.grid.component.GridPosition; import coffee.liz.abstractionengine.grid.component.LambdaTerm; import coffee.liz.abstractionengine.grid.component.Substitution; import coffee.liz.ecs.math.Vec2; +import coffee.liz.ecs.model.Entity; import coffee.liz.ecs.model.System; import coffee.liz.ecs.model.World; import coffee.liz.ecs.model.Query; import coffee.liz.lambda.LambdaDriver; +import coffee.liz.lambda.ast.LambdaProgram; import coffee.liz.lambda.ast.SourceCode; import coffee.liz.lambda.eval.Environment; +import coffee.liz.lambda.eval.NormalOrderEvaluator; +import coffee.liz.lambda.eval.Thunk; import coffee.liz.lambda.eval.Value; import coffee.liz.lambda.format.ValueEmitter; import lombok.extern.log4j.Log4j2; @@ -21,10 +25,7 @@ import lombok.extern.log4j.Log4j2; import java.time.Duration; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; -import java.util.stream.Collectors; +import java.util.Objects; @Log4j2 public class LambdaEvaluatorSystem implements System<GridInputState> { @@ -45,38 +46,39 @@ public class LambdaEvaluatorSystem implements System<GridInputState> { world.resolve(Query.allOf(Substitution.class, LambdaTerm.class, GridPosition.class)).forEach(entity -> { final LambdaTerm term = entity.get(LambdaTerm.class); - final Substitution substitution = entity.get(Substitution.class); final GridPosition position = entity.get(GridPosition.class); + final Substitution substitution = entity.get(Substitution.class); - final Map<String, Supplier<Value>> dependencies = substitution.getTermDependencies().entrySet().stream() - .map(e -> { - final String symbol = e.getKey(); - // Ideally we should only ever have one match to replace the symbol with. - // But maybe there's a use-case where this is not the case? - final Optional<SourceCode> sourceCode = gridIndexSystem.entitiesAt(e.getValue()).stream() - .filter(_entity -> _entity.has(LambdaTerm.class)) - .map(_entity -> _entity.get(LambdaTerm.class)).map(LambdaTerm::getTerm).findFirst(); - // TODO: Map error - final Optional<Supplier<Value>> val = sourceCode.map(s -> () -> LambdaDriver.interpret(s)); - return Map.entry(symbol, val); - }).filter(e -> e.getValue().isPresent()) - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get())); + final List<Entity> resolvedDependencies = substitution.getTermDependencies().stream() + .map(dependencyPos -> gridIndexSystem.entitiesAt(dependencyPos).stream() + .filter(_entity -> _entity.has(LambdaTerm.class)) + .findFirst() + .orElse(null)) + .toList(); - final boolean dependenciesSatisified = dependencies.keySet() - .equals(substitution.getTermDependencies().keySet()); + final boolean dependenciesSatisified = resolvedDependencies.stream().allMatch(Objects::nonNull); if (!dependenciesSatisified) { + entity.add(substitution.toBuilder().isActive(true).build()); return; } - final Environment env = dependencies.entrySet().stream().reduce(Environment.root(), - (_env, e) -> _env.extend(e.getKey(), e.getValue()), (a, b) -> b); - final Value evaluationResult = LambdaDriver.interpret(term.getTerm(), List.of(), env); - final SourceCode emittedResult = ValueEmitter.emit(evaluationResult, preferredSyntax); + if (!substitution.isActive()) { + return; + } + + Value result = LambdaDriver.interpret(term.getTerm()); + for (final Entity dependency : resolvedDependencies) { + result = new Value.Application(result, LambdaDriver.interpret(dependency.get(LambdaTerm.class).getTerm())); + } + + final SourceCode emittedResult = ValueEmitter.emit(LambdaDriver.interpret(ValueEmitter.emit(result, preferredSyntax)), preferredSyntax); final Vec2<Integer> spawnMomentum = substitution.getSpawnMomentum(); - EntityFactory.Abstraction.addToWorld(world, position.getPosition(), new LambdaTerm(emittedResult)) + final Entity producedTerm = EntityFactory.Abstraction.addToWorld(world, position.getPosition(), new LambdaTerm(emittedResult)) .add(EntityType.ABSTRACTION).add(new GridPosition(position.getPosition())) .add(new GridMomentum(spawnMomentum)); + entity.add(substitution.toBuilder().isActive(false).build()); + log.info("Entity {} produced {}", entity, producedTerm); }); } } |
