diff --git a/src/common/ecs/compiler.ts b/src/common/ecs/compiler.ts index d3ddbd98..64e912ec 100644 --- a/src/common/ecs/compiler.ts +++ b/src/common/ecs/compiler.ts @@ -338,6 +338,7 @@ export class ECSCompiler extends Tokenizer { if (cmd == 'comment') { this.expectTokenTypes([ECSTokenType.CodeFragment]); } + // TODO: need to make these local names, otherwise we get "duplicate name" if (cmd == 'system') { let sys = this.annotate(() => this.parseSystem()); this.em.defineSystem(sys); @@ -350,7 +351,13 @@ export class ECSCompiler extends Tokenizer { parseScopeUsing() { let instlist = this.parseList(this.parseSystemInstanceRef, ','); + let params = {}; + if (this.peekToken().str == 'with') { + this.consumeToken(); + params = this.parseSystemInstanceParameters(); + } for (let inst of instlist) { + inst.params = params; this.currentScope?.newSystemInstance(inst); } } @@ -464,10 +471,6 @@ export class ECSCompiler extends Tokenizer { let system = this.em.getSystemByName(name); if (!system) this.compileError(`I couldn't find a system named "${name}".`, this.lasttoken.$loc); let params = {}; - if (this.peekToken().str == 'with') { - this.consumeToken(); - params = this.parseSystemInstanceParameters(); - } let inst = { system, params, id: 0 }; return inst; } @@ -475,6 +478,9 @@ export class ECSCompiler extends Tokenizer { parseSystemInstanceParameters() : SystemInstanceParameters { let scope = this.currentScope; if (scope == null) throw new Error(); + if (this.peekToken().str == '[') { + return { query: this.parseQuery() }; + } this.expectToken('#'); let entname = this.expectIdent(); this.expectToken('.'); diff --git a/src/common/ecs/ecs.ts b/src/common/ecs/ecs.ts index 2b50c45a..1129251f 100644 --- a/src/common/ecs/ecs.ts +++ b/src/common/ecs/ecs.ts @@ -61,6 +61,7 @@ export interface System extends SourceLocated { } export interface SystemInstanceParameters { + query?: Query; refEntity?: Entity; refField?: ComponentFieldPair; } @@ -600,6 +601,8 @@ class ActionEval { this.qr = this.qr.intersection(new EntitySet(scope, rq)); //console.log('with', instance.params, rq, this.qr); } + } else if (instance.params.query) { + this.qr = this.qr.intersection(new EntitySet(scope, instance.params.query)); } this.entities = this.qr.entities; //let query = (this.action as ActionWithQuery).query; @@ -767,10 +770,18 @@ class ActionEval { } __data(args: string[]) { let { component, field, bitofs } = this.parseFieldArgs(args); - if (this.qr.entities.length != 1) throw new ECSError(`data command operates on exactly one entity`); // TODO? + if (this.qr.entities.length != 1) throw new ECSError(`data operates on exactly one entity`, this.action); // TODO? let eid = this.qr.entities[0].id; // TODO? return this.dialect.datasymbol(component, field, eid, bitofs); } + __const(args: string[]) { + let { component, field, bitofs } = this.parseFieldArgs(args); + if (this.qr.entities.length != 1) throw new ECSError(`const operates on exactly one entity`, this.action); // TODO? + let constVal = this.qr.entities[0].consts[mksymbol(component, field.name)]; + if (constVal === undefined) throw new ECSError(`field is not constant`, this.action); // TODO? + if (typeof constVal !== 'number') throw new ECSError(`field is not numeric`, this.action); // TODO? + return constVal << bitofs; + } __index(args: string[]) { // TODO: check select type and if we actually have an index... let ident = args[0];