diff options
Diffstat (limited to 'src/engine/entities')
-rw-r--r-- | src/engine/entities/FunctionApplication.ts | 120 |
1 files changed, 95 insertions, 25 deletions
diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts index 4d5729f..f4201de 100644 --- a/src/engine/entities/FunctionApplication.ts +++ b/src/engine/entities/FunctionApplication.ts @@ -24,8 +24,9 @@ import { Game } from ".."; import { Grid as GridSystem, SystemNames } from "../systems"; import { colors, tryWrap } from "../utils"; import { - InvalidLambdaTermError, + DebrujinIndex, SymbolTable, + Visitors, emitNamed, interpret, } from "../../interpreter"; @@ -41,16 +42,9 @@ const APPLICATION_RESULTS: Record< export class FunctionApplication extends Entity { private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec; - private symbolTable: SymbolTable; - constructor(gridPosition: Coord2D, lambdaTerm: string) { super(EntityNames.FunctionApplication); - this.symbolTable = new SymbolTable(); - Object.keys(APPLICATION_RESULTS).forEach((key) => { - this.symbolTable.add(key); - }); - const dimension = { width: FunctionApplication.spriteSpec.width, height: FunctionApplication.spriteSpec.height, @@ -151,7 +145,10 @@ export class FunctionApplication extends Entity { ); const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code); - const result = tryWrap(() => interpret(newCode, this.symbolTable, true)); + const { symbolTable, visitors } = this.getVisitors(game); + const result = tryWrap(() => + interpret(newCode, symbolTable, true, visitors), + ); applicationTerm.last = result; if (result.error || !result.data) { console.error(result.error); @@ -166,13 +163,6 @@ export class FunctionApplication extends Entity { let applicationResultingEntity: Entity | null = null; // this should be its own function const { data } = result; - if ("application" in data) { - // if we get an application that means we didn't interpret correctly. - // this should "not" happen and should be fatal. - throw new InvalidLambdaTermError( - "produced term should not be an application", - ); - } if ("abstraction" in data) { const code = emitNamed(data); applicationResultingEntity = new FunctionBox(grid.gridPosition, code); @@ -187,20 +177,100 @@ export class FunctionApplication extends Entity { } game.removeEntity(entity.id); - if (applicationResultingEntity) { - const grid = applicationResultingEntity.getComponent<Grid>( + if (!applicationResultingEntity) { + return; + } + + applicationResultingEntity.getComponent<Grid>( + ComponentNames.Grid, + ).movingDirection = entityGrid.previousDirection; + game.addEntity(applicationResultingEntity); + } + + private getVisitors(game: Game): { + visitors: Visitors; + symbolTable: SymbolTable; + } { + const directionKeywords = { + _LEFT: Direction.LEFT, + _RIGHT: Direction.RIGHT, + _DOWN: Direction.DOWN, + _UP: Direction.UP, + }; + const entityKeywords = { + _KEY: (pos: Coord2D) => new Key(pos), + }; + + const visitors: Visitors = new Map(); + visitors.set("_SPAWN", (_term) => { + const position = this.getComponent<Grid>( ComponentNames.Grid, - ); - grid.movingDirection = entityGrid.previousDirection; - applicationResultingEntity.addComponent(grid); + ).gridPosition; + return { + abstraction: { + param: "_DIRECTION", + body: (direction) => { + const destinationDirection = + directionKeywords[ + (direction as DebrujinIndex) + .name! as keyof typeof directionKeywords + ]; + const destination = game + .getSystem<GridSystem>(SystemNames.Grid) + .getNewGridPosition(position, destinationDirection); + return { + abstraction: { + param: "_ENTITY", + body: (entityType) => { + const entityFactory = + entityKeywords[ + (entityType as DebrujinIndex) + .name! as keyof typeof entityKeywords + ]; + const newEntity = entityFactory(destination); + game.addEntity(newEntity); + return { + abstraction: { + param: "_x", + body: (_t) => { + return { + application: { + left: { + index: 1, + name: "_SPAWN", + }, + args: [direction, entityType], + }, + }; + }, + }, + }; + }, + }, + }; + }, + }, + }; + }); - game.addEntity(applicationResultingEntity); - } + return { + visitors, + symbolTable: SymbolTable.from( + Array.from(visitors.keys()) + .concat(Object.keys(APPLICATION_RESULTS)) + .concat(Object.keys(directionKeywords)) + .concat(Object.keys(entityKeywords)) + .concat(["_x"]), + ), + }; + } - SOUNDS.get(LambdaTransformSound.name)!.play(); + private addParticles(game: Game, position: Coord2D) { + const gridSystem = game.getSystem<GridSystem>(SystemNames.Grid); const { dimension } = gridSystem; + SOUNDS.get(LambdaTransformSound.name)!.play(); const particles = new Particles({ - center: gridSystem.gridToScreenPosition(nextPosition), + center: gridSystem.gridToScreenPosition(position), spawnerDimensions: { width: dimension.width / 2, height: dimension.height / 2, |