aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/java/coffee/liz/abstractionengine
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2026-02-15 10:08:30 -0800
committerElizabeth Hunt <me@liz.coffee>2026-02-15 10:12:08 -0800
commitd6a294e14604aecd9046cbc19dc1837ca694fbb0 (patch)
tree616e87e59f9ee95253acce05aa26405523a9acd7 /core/src/main/java/coffee/liz/abstractionengine
parent347564c592325007cb81dbdf1a07831c2ae003c3 (diff)
downloadthe-abstraction-engine-java-d6a294e14604aecd9046cbc19dc1837ca694fbb0.tar.gz
the-abstraction-engine-java-d6a294e14604aecd9046cbc19dc1837ca694fbb0.zip
feat: Adding ValueEmitter, LambdaEvaluatorSystem
Diffstat (limited to 'core/src/main/java/coffee/liz/abstractionengine')
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java11
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java5
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java7
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java5
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java18
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java2
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java28
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java6
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java6
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java5
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java15
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/LambdaTerm.java12
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java (renamed from core/src/main/java/coffee/liz/abstractionengine/component/LambdaTerm.java)8
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java3
-rw-r--r--core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java82
23 files changed, 167 insertions, 83 deletions
diff --git a/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java b/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
index 806d05e..b2ccb5e 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/AbstractionEngineGridWorld.java
@@ -5,22 +5,21 @@ import coffee.liz.abstractionengine.grid.system.GridCollisionPropagatationSystem
import coffee.liz.abstractionengine.grid.system.GridIndexSystem;
import coffee.liz.abstractionengine.grid.system.GridMovementSystem;
import coffee.liz.abstractionengine.grid.system.GridPhysicsSystem;
+import coffee.liz.abstractionengine.grid.system.LambdaEvaluatorSystem;
import coffee.liz.ecs.DAGWorld;
import coffee.liz.ecs.math.Vec2;
+import coffee.liz.lambda.ast.SourceCode;
import lombok.extern.log4j.Log4j2;
import java.time.Duration;
-import java.util.Map;
/** Grid world implementation for the abstraction engine. */
@Log4j2
public class AbstractionEngineGridWorld extends DAGWorld<GridInputState> {
- /** Initialize world with systems and player. */
- public AbstractionEngineGridWorld(final Vec2<Integer> gridDimensions) {
- super(Map.of(GridMovementSystem.class, new GridMovementSystem(), GridPhysicsSystem.class,
- new GridPhysicsSystem(), GridIndexSystem.class, new GridIndexSystem(gridDimensions),
- GridCollisionPropagatationSystem.class, new GridCollisionPropagatationSystem()));
+ public AbstractionEngineGridWorld(final Vec2<Integer> gridDimensions, final SourceCode.Syntax preferredSyntax) {
+ super(new GridMovementSystem(), new GridPhysicsSystem(), new GridIndexSystem(gridDimensions),
+ new GridCollisionPropagatationSystem(), new LambdaEvaluatorSystem(preferredSyntax));
}
/**
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java
index 3ea4701..86a573c 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/Abstraction.java
@@ -22,7 +22,7 @@ public class Abstraction extends Actor {
@Getter
private final Animation<TextureRegion> animation;
- private final Entity abstractionEntity;
+ // private final Entity abstractionEntity;
private boolean isActive;
private float stateTime = 0f;
@@ -33,24 +33,20 @@ public class Abstraction extends Actor {
public Abstraction() {
final Texture texture = new Texture(Gdx.files.internal("sprites/abstraction.png"));
final TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / ABSTRACTION_FRAMES.getX(),
- texture.getHeight() / ABSTRACTION_FRAMES.getY());
- final TextureRegion[] anim = {
- tmp[0][0],
- tmp[1][0],
- tmp[2][0],
- tmp[3][0]
- };
+ texture.getHeight() / ABSTRACTION_FRAMES.getY());
+ final TextureRegion[] anim = {tmp[0][0], tmp[1][0], tmp[2][0], tmp[3][0]};
this.animation = new Animation<>(0.25f, anim);
addListener(new InputListener() {
@Override
- public void enter (final InputEvent event, final float x, final float y, final int pointer, @Null final Actor fromActor) {
+ public void enter(final InputEvent event, final float x, final float y, final int pointer,
+ @Null final Actor fromActor) {
log.info("Entered mouse {}", event);
}
-
@Override
- public boolean touchDown (final InputEvent event, final float x, final float y, final int pointer, final int button) {
+ public boolean touchDown(final InputEvent event, final float x, final float y, final int pointer,
+ final int button) {
log.info("TouchDown!!!");
return false;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java b/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
index c4bb5e3..8f75d97 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/actor/LifeGridActor.java
@@ -9,6 +9,7 @@ import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.math.Vec2f;
import coffee.liz.ecs.math.Vec2i;
import coffee.liz.ecs.model.World;
+import coffee.liz.ecs.model.Query;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
@@ -98,7 +99,7 @@ public class LifeGridActor extends Actor {
}
private void drawCells(final Vec2<Float> cellSize) {
- world.query(Set.of(GridPosition.class, CellState.class)).forEach(entity -> {
+ world.resolve(Query.allOf(GridPosition.class, CellState.class)).forEach(entity -> {
final CellState state = entity.get(CellState.class);
final Vec2<Integer> gridPos = entity.get(GridPosition.class).getPosition();
final Vec2<Float> drawPos = gridPos.floatValue().scale(cellSize).plus(parallaxOffset);
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java b/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
index 7662700..b5ed2d1 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/config/Settings.java
@@ -1,5 +1,6 @@
package coffee.liz.abstractionengine.app.config;
+import coffee.liz.lambda.ast.SourceCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -14,6 +15,8 @@ public class Settings {
private boolean playMusic = true;
@Builder.Default
private boolean vimMode = true;
+ @Builder.Default
+ private SourceCode.Syntax preferredSyntax = SourceCode.Syntax.ARROW;
@Builder.Default
private KeyBinds keyBinds = KeyBinds.builder().build();
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
index 5660ff3..1ea5d32 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/life/EntropyAudioSystem.java
@@ -150,7 +150,7 @@ public class EntropyAudioSystem implements System<LifeInput> {
}
@Override
- public void close() {
+ public void dispose() {
running = false;
FunctionUtils.wrapCheckedException(() -> audioThread.join(AUDIO_THREAD_TIMEOUT));
device.dispose();
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
index 70bb973..e96127c 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/GameScreen.java
@@ -65,6 +65,6 @@ public class GameScreen implements Screen {
@Override
public void dispose() {
- FunctionUtils.wrapCheckedException(outerWorld::close);
+ FunctionUtils.wrapCheckedException(outerWorld::dispose);
}
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
index 46b5192..b8cfbbc 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/MainMenu.java
@@ -34,8 +34,7 @@ public class MainMenu implements Screen {
private static final Vec2<Float> BUTTON_SIZE = AbstractionEngineGame.WORLD_SIZE.scale(1 / 4f, 1 / 15f);
private static final float PARALLAX_STRENGTH = 3f;
- private final World<LifeInput> world = new DAGWorld<>(Map.of(LifeSystem.class, new LifeSystem(GRID_DIMENSIONS),
- EntropyAudioSystem.class, new EntropyAudioSystem()));
+ private final World<LifeInput> world = new DAGWorld<>(new LifeSystem(GRID_DIMENSIONS), new EntropyAudioSystem());
private final AbstractionEngineGame game;
private final Set<Vec2<Integer>> initialAlive = createGliderPattern();
@@ -162,7 +161,7 @@ public class MainMenu implements Screen {
*/
@Override
public void dispose() {
- FunctionUtils.wrapCheckedException(world::close);
+ FunctionUtils.wrapCheckedException(world::dispose);
stage.dispose();
}
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
index 137a5b0..260c191 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/GameScreenWorld.java
@@ -9,12 +9,9 @@ import coffee.liz.ecs.DAGWorld;
import coffee.liz.ecs.math.Vec2;
import com.badlogic.gdx.utils.viewport.FitViewport;
-import java.util.Map;
-
public class GameScreenWorld extends DAGWorld<FrameState> {
public GameScreenWorld(final Vec2<Integer> gridSize, final FitViewport viewport, final Settings settings) {
- super(Map.of(InputSystem.class, new InputSystem(), GridWorldBridgeSystem.class,
- new GridWorldBridgeSystem(gridSize), GridInterpolationSystem.class, new GridInterpolationSystem(),
- RenderSystem.class, new RenderSystem(viewport, gridSize, settings)));
+ super(new InputSystem(), new GridWorldBridgeSystem(gridSize, settings), new GridInterpolationSystem(),
+ new RenderSystem(viewport, gridSize, settings));
}
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
index 0d2d34b..d0acfbc 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridInterpolationSystem.java
@@ -10,6 +10,7 @@ import coffee.liz.ecs.math.Vec2f;
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 java.time.Duration;
import java.util.Collection;
@@ -33,7 +34,7 @@ public class GridInterpolationSystem implements System<FrameState> {
public void update(final World<FrameState> world, final FrameState state, final Duration dt) {
final GridWorldBridgeSystem bridgeSystem = world.getSystem(GridWorldBridgeSystem.class);
- world.query(Set.of(ExternalWorldEntityRef.class, ActorHolder.class)).forEach(entity -> {
+ world.resolve(Query.allOf(ExternalWorldEntityRef.class, ActorHolder.class)).forEach(entity -> {
final Actor actor = entity.get(ActorHolder.class).getActor();
final boolean isAlreadyInterpolating = !actor.getActions().isEmpty();
if (isAlreadyInterpolating) {
@@ -62,7 +63,7 @@ public class GridInterpolationSystem implements System<FrameState> {
}
private Interpolation interpolationType(final EntityType type) {
- return switch(type) {
+ return switch (type) {
case PLAYER -> Interpolation.pow3;
default -> new Interpolation.Swing(1.15f);
};
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java
index dac5a32..3d76853 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/GridWorldBridgeSystem.java
@@ -5,6 +5,7 @@ import coffee.liz.abstractionengine.app.AbstractionEngineGame;
import coffee.liz.abstractionengine.app.actor.Abstraction;
import coffee.liz.abstractionengine.app.actor.Penguin;
import coffee.liz.abstractionengine.app.actor.Wall;
+import coffee.liz.abstractionengine.app.config.Settings;
import coffee.liz.abstractionengine.app.screen.game.FrameState;
import coffee.liz.abstractionengine.app.screen.game.component.ActorHolder;
import coffee.liz.abstractionengine.app.screen.game.component.ExternalWorldEntityRef;
@@ -18,6 +19,7 @@ import coffee.liz.ecs.math.Vec2i;
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 lombok.Getter;
import java.time.Duration;
@@ -41,12 +43,14 @@ public class GridWorldBridgeSystem implements System<FrameState> {
@Getter
private final Vec2<Float> worldToGrid;
- public GridWorldBridgeSystem(final Vec2<Integer> gridSize) {
+ public GridWorldBridgeSystem(final Vec2<Integer> gridSize, final Settings settings) {
this.gridSize = gridSize;
- this.outerWorld = new AbstractionEngineGridWorld(gridSize);
+ this.outerWorld = new AbstractionEngineGridWorld(gridSize, settings.getPreferredSyntax());
- this.gridToWorld = AbstractionEngineGame.WORLD_SIZE.scale(gridSize.floatValue().transform(x -> 1f / x, y -> 1f / y));
- this.worldToGrid = gridSize.floatValue().scale(AbstractionEngineGame.WORLD_SIZE.floatValue().transform(x -> 1f/x, y -> 1f/y));
+ this.gridToWorld = AbstractionEngineGame.WORLD_SIZE
+ .scale(gridSize.floatValue().transform(x -> 1f / x, y -> 1f / y));
+ this.worldToGrid = gridSize.floatValue()
+ .scale(AbstractionEngineGame.WORLD_SIZE.floatValue().transform(x -> 1f / x, y -> 1f / y));
}
public void initLevel() {
@@ -71,7 +75,7 @@ public class GridWorldBridgeSystem implements System<FrameState> {
}
private void syncEntities(final World<FrameState> world) {
- final Set<Entity> gridEntities = outerWorld.query(Set.of(GridPosition.class, EntityType.class));
+ final Set<Entity> gridEntities = outerWorld.resolve(Query.allOf(GridPosition.class, EntityType.class));
final Set<Integer> seenGridIds = new HashSet<>();
for (final Entity gridEntity : gridEntities) {
@@ -100,8 +104,8 @@ public class GridWorldBridgeSystem implements System<FrameState> {
}
@Override
- public void close() {
- FunctionUtils.wrapCheckedException(outerWorld::close);
+ public void dispose() {
+ FunctionUtils.wrapCheckedException(outerWorld::dispose);
}
private Actor createActor(final EntityType type, final Stage stage) {
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
index 401ed89..32b9ebd 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/screen/game/system/RenderSystem.java
@@ -70,7 +70,7 @@ public class RenderSystem implements System<FrameState> {
}
@Override
- public void close() {
+ public void dispose() {
uiStage.dispose();
stage.dispose();
shapeRenderer.dispose();
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
index abae5fb..285bbde 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/context/KeyContext.java
@@ -19,6 +19,9 @@ import coffee.liz.abstractionengine.app.ui.editor.vim.state.PendingOperator;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.VisualLineState;
import coffee.liz.abstractionengine.app.ui.editor.vim.state.VisualState;
import com.badlogic.gdx.Input;
+import lombok.Getter;
+import lombok.Setter;
+
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Consumer;
@@ -31,6 +34,7 @@ public class KeyContext {
private final Register register;
private final VimConfig config;
+ @Getter
private String statusText;
private String lastSearchQuery;
private SearchDirection lastSearchDirection;
@@ -39,6 +43,7 @@ public class KeyContext {
private String searchIteratorText;
private int suppressedTypedCommands;
private boolean suppressNextRedoTyped;
+ @Setter
private KeyEvent currentKeyEvent;
public KeyContext(final EditorBuffer editorBuffer, final Consumer<String> statusUpdater,
@@ -73,18 +78,10 @@ public class KeyContext {
return config;
}
- public void setCurrentKeyEvent(final KeyEvent currentKeyEvent) {
- this.currentKeyEvent = currentKeyEvent;
- }
-
public KeyEvent currentKeyEvent() {
return currentKeyEvent;
}
- public String getStatusText() {
- return statusText;
- }
-
public void publishStatus(final String status) {
if (!status.equals(statusText)) {
statusText = status;
@@ -361,7 +358,7 @@ public class KeyContext {
public void deleteCharUnderCursor() {
final String text = editorBuffer.getText();
final int cursor = editorBuffer.getCursorPosition();
- if (cursor >= text.length() || text.charAt(cursor) == '\n') {
+ if (cursor >= text.length() || text.charAt(cursor) == ' ') {
return;
}
register.setText(String.valueOf(text.charAt(cursor)));
@@ -432,7 +429,9 @@ public class KeyContext {
return;
}
- final int insertAt = Math.min(cursor + 1, text.length());
+ final boolean cursorOnEmptyLine = cursor < text.length() && text.charAt(cursor) == '\n'
+ && navigation.findLineStart(text, cursor) == cursor;
+ final int insertAt = cursorOnEmptyLine ? cursor : Math.min(cursor + 1, text.length());
editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
invalidateSearchIterator();
@@ -452,9 +451,8 @@ public class KeyContext {
return;
}
- final int insertAt = cursor;
- editorBuffer.setText(text.substring(0, insertAt) + register.getText() + text.substring(insertAt));
- editorBuffer.setCursorPosition(insertAt + register.getText().length() - 1);
+ editorBuffer.setText(text.substring(0, cursor) + register.getText() + text.substring(cursor));
+ editorBuffer.setCursorPosition(cursor + register.getText().length() - 1);
invalidateSearchIterator();
}
@@ -737,10 +735,6 @@ public class KeyContext {
editorBuffer.clearSelection();
}
- public void setSelectionEndpoints(final int selectionStart, final int cursorPosition) {
- editorBuffer.setSelectionEndpoints(selectionStart, cursorPosition);
- }
-
public Register register() {
return register;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
index bd9b1d0..95dc2bc 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/handler/NormalModeHandler.java
@@ -84,8 +84,8 @@ public class NormalModeHandler implements ModeHandler<NormalState> {
if (character == 'i' && (operator == PendingOperator.DELETE || operator == PendingOperator.YANK
|| operator == PendingOperator.CHANGE)) {
- return HandleResult.handled(new NormalState(state.count(), mapInnerOperator(operator),
- state.preferredColumn()));
+ return HandleResult
+ .handled(new NormalState(state.count(), mapInnerOperator(operator), state.preferredColumn()));
}
if (isInnerWordOperator(operator)) {
@@ -96,7 +96,7 @@ public class NormalModeHandler implements ModeHandler<NormalState> {
}
final int start = context.cursor();
- final int updatedPreferred = applyMotion(character, repeats, state.preferredColumn(), context, true);
+ final int updatedPreferred = applyMotion(character, repeats, state.preferredColumn(), context, false);
int end = context.cursor();
if (character == '$') {
end = Math.min(context.text().length(), end + 1);
diff --git a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
index b74c1df..10af095 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/app/ui/editor/vim/navigation/TextNavigation.java
@@ -85,7 +85,11 @@ public class TextNavigation {
return 0;
}
- return text.length() - 1;
+ int index = text.length() - 1;
+ while (index > 0 && (text.charAt(index) == '\n' || text.charAt(index) == '\r')) {
+ index--;
+ }
+ return index;
}
public int maxCursorPositionInNormalMode(final String text) {
diff --git a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
index d8299aa..871c6d0 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/entity/EntityFactory.java
@@ -2,6 +2,7 @@ package coffee.liz.abstractionengine.entity;
import coffee.liz.abstractionengine.grid.component.GridControllable;
import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.abstractionengine.grid.component.LambdaTerm;
import coffee.liz.ecs.math.Mat2;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.model.Entity;
@@ -51,6 +52,10 @@ public final class EntityFactory {
return world.createEntity().add(new GridPosition(position)).add(EntityType.ABSTRACTION)
.add(new EntityTypeGridCollidable());
}
+
+ public static Entity addToWorld(final World<?> world, final Vec2<Integer> position, final LambdaTerm term) {
+ return addToWorld(world, position).add(term);
+ }
}
/**
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
index 6ab0d2b..5134719 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/GridInputState.java
@@ -19,19 +19,4 @@ public class GridInputState {
/** Movement {@link Vec2} direction. */
@Nullable
private final Vec2<Integer> movement;
-
- /** Lambda term update to apply. */
- @Nullable
- private final UpdateLambdaTerm updateLambdaTerm;
-
- /** Update lambda term with target entity. */
- @Getter
- @RequiredArgsConstructor
- public static class UpdateLambdaTerm {
- /** {@link Entity} to update. */
- private final Entity toUpdate;
-
- /** {@link LambdaProgram} to apply. */
- private final LambdaProgram lambdaProgram;
- }
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/component/LambdaTerm.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/LambdaTerm.java
new file mode 100644
index 0000000..9ed1e9c
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/LambdaTerm.java
@@ -0,0 +1,12 @@
+package coffee.liz.abstractionengine.grid.component;
+
+import coffee.liz.ecs.model.Component;
+import coffee.liz.lambda.ast.SourceCode;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Data
+public class LambdaTerm implements Component {
+ private final SourceCode term;
+}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/component/LambdaTerm.java b/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java
index b0d1358..77ff4e8 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/component/LambdaTerm.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/component/Substitution.java
@@ -1,8 +1,7 @@
-package coffee.liz.abstractionengine.component;
+package coffee.liz.abstractionengine.grid.component;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.model.Component;
-import coffee.liz.lambda.ast.Expression;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@@ -10,8 +9,7 @@ import java.util.Map;
@RequiredArgsConstructor
@Data
-public class LambdaTerm implements Component {
+public class Substitution implements Component {
+ private final Vec2<Integer> spawnMomentum;
private final Map<String, Vec2<Integer>> termDependencies;
-
- private final Expression term;
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
index ee77256..470c72f 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/BaseGridIndexSystem.java
@@ -4,6 +4,7 @@ import coffee.liz.abstractionengine.grid.component.GridPosition;
import coffee.liz.ecs.math.Mat2;
import coffee.liz.ecs.math.Vec2;
import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.Query;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
import lombok.Getter;
@@ -36,7 +37,7 @@ public abstract class BaseGridIndexSystem<T> implements System<T> {
@Override
public void update(final World<T> world, final T state, final Duration dt) {
rows.forEach(row -> row.forEach(Set::clear));
- world.query(Set.of(GridPosition.class)).forEach(entity -> {
+ world.resolve(Query.allOf(GridPosition.class)).forEach(entity -> {
final GridPosition position = entity.get(GridPosition.class);
rows.get(position.getPosition().getY()).get(position.getPosition().getX()).add(entity);
});
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
index 23a821d..9980795 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystem.java
@@ -10,6 +10,7 @@ import coffee.liz.ecs.math.Vec2i;
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 java.time.Duration;
import java.util.ArrayList;
@@ -31,7 +32,7 @@ public class GridCollisionPropagatationSystem implements System<GridInputState>
@Override
public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)).forEach(pusher -> {
+ world.resolve(Query.allOf(GridMomentum.class, GridPosition.class, GridCollidable.class)).forEach(pusher -> {
final Vec2<Integer> velocity = pusher.get(GridMomentum.class).getVelocity();
if (velocity.equals(Vec2i.ZERO)) {
return;
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
index 02f012b..c402fcc 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridMovementSystem.java
@@ -6,6 +6,7 @@ import coffee.liz.abstractionengine.grid.component.GridMomentum;
import coffee.liz.abstractionengine.grid.component.GridPosition;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
+import coffee.liz.ecs.model.Query;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -25,7 +26,7 @@ public class GridMovementSystem implements System<GridInputState> {
@Override
public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridControllable.class, GridPosition.class))
+ world.resolve(Query.allOf(GridControllable.class, GridPosition.class))
.forEach(entity -> entity.add(new GridMomentum(state.getMovement())));
}
}
diff --git a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
index 5e0e632..676dd1b 100644
--- a/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystem.java
@@ -6,6 +6,7 @@ import coffee.liz.abstractionengine.grid.component.GridPosition;
import coffee.liz.ecs.math.Vec2i;
import coffee.liz.ecs.model.System;
import coffee.liz.ecs.model.World;
+import coffee.liz.ecs.model.Query;
import java.time.Duration;
import java.util.Collection;
@@ -20,7 +21,7 @@ public class GridPhysicsSystem implements System<GridInputState> {
@Override
public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
- world.query(Set.of(GridMomentum.class, GridPosition.class)).forEach(entity -> {
+ world.resolve(Query.allOf(GridMomentum.class, GridPosition.class)).forEach(entity -> {
final GridMomentum momentum = entity.get(GridMomentum.class);
final GridPosition position = entity.get(GridPosition.class);
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
new file mode 100644
index 0000000..74bc3fc
--- /dev/null
+++ b/core/src/main/java/coffee/liz/abstractionengine/grid/system/LambdaEvaluatorSystem.java
@@ -0,0 +1,82 @@
+package coffee.liz.abstractionengine.grid.system;
+
+import coffee.liz.abstractionengine.entity.EntityFactory;
+import coffee.liz.abstractionengine.entity.EntityType;
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridMomentum;
+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.System;
+import coffee.liz.ecs.model.World;
+import coffee.liz.ecs.model.Query;
+import coffee.liz.lambda.LambdaDriver;
+import coffee.liz.lambda.ast.SourceCode;
+import coffee.liz.lambda.eval.Environment;
+import coffee.liz.lambda.eval.Value;
+import coffee.liz.lambda.format.ValueEmitter;
+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;
+
+@Log4j2
+public class LambdaEvaluatorSystem implements System<GridInputState> {
+ private final SourceCode.Syntax preferredSyntax;
+
+ public LambdaEvaluatorSystem(final SourceCode.Syntax preferredSyntax) {
+ this.preferredSyntax = preferredSyntax;
+ }
+
+ @Override
+ public Collection<Class<? extends System<GridInputState>>> getDependencies() {
+ return List.of(GridCollisionPropagatationSystem.class);
+ }
+
+ @Override
+ public void update(final World<GridInputState> world, final GridInputState state, final Duration dt) {
+ final GridIndexSystem gridIndexSystem = world.getSystem(GridIndexSystem.class);
+
+ 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 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 boolean dependenciesSatisified = dependencies.keySet()
+ .equals(substitution.getTermDependencies().keySet());
+ if (!dependenciesSatisified) {
+ 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);
+ final Vec2<Integer> spawnMomentum = substitution.getSpawnMomentum();
+
+ EntityFactory.Abstraction.addToWorld(world, position.getPosition(), new LambdaTerm(emittedResult))
+ .add(EntityType.ABSTRACTION).add(new GridPosition(position.getPosition()))
+ .add(new GridMomentum(spawnMomentum));
+ });
+ }
+}