From dbc84c94b209cf48ff0350b2b20f7e2a7de0ebef Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Thu, 3 Feb 2022 19:38:35 -0600 Subject: [PATCH] ecs: no error if select is empty --- src/common/ecs/compiler.ts | 4 +++- src/common/ecs/ecs.ts | 29 ++++++++++++++--------------- src/worker/tools/cc65.ts | 8 ++++++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/common/ecs/compiler.ts b/src/common/ecs/compiler.ts index 4f74380f..1bd61d6a 100644 --- a/src/common/ecs/compiler.ts +++ b/src/common/ecs/compiler.ts @@ -232,7 +232,6 @@ export class ECSCompiler extends Tokenizer { join = this.parseQuery(); } let emits; - let limit; if (this.peekToken().str == 'limit') { this.consumeToken(); if (!query) { this.compileError(`A "${select}" query can't include a limit.`); } @@ -350,6 +349,9 @@ export class ECSCompiler extends Tokenizer { if (!field) { this.internalError(); throw new Error(); } this.expectToken('='); let value = this.parseDataValue(field); + let symtype = this.currentScope.isConstOrInit(comps[0], name); + if (symtype && symtype != cmd) + this.compileError(`I can't mix const and init values for a given field in a scope.`); if (cmd == 'const') this.currentScope.setConstValue(e, comps[0], name, value); if (cmd == 'init') this.currentScope.setInitValue(e, comps[0], name, value); } diff --git a/src/common/ecs/ecs.ts b/src/common/ecs/ecs.ts index f3ac0c21..dc2ecf57 100644 --- a/src/common/ecs/ecs.ts +++ b/src/common/ecs/ecs.ts @@ -100,9 +100,7 @@ export interface ComponentType extends SourceLocated { export interface Query extends SourceLocated { include: ComponentType[]; // TODO: make ComponentType - listen?: ComponentType[]; exclude?: ComponentType[]; - updates?: ComponentType[]; limit?: number; } @@ -520,9 +518,9 @@ class ActionEval { if (q) this.qr = new EntitySet(scope, q); else this.qr = new EntitySet(scope, undefined, [], []); this.entities = this.qr.entities; - let query = (this.action as ActionWithQuery).query; - if (query && this.entities.length == 0) - throw new ECSError(`query doesn't match any entities`, query); // TODO + //let query = (this.action as ActionWithQuery).query; + //TODO? if (query && this.entities.length == 0) + //throw new ECSError(`query doesn't match any entities`, query); // TODO } begin() { let state = this.scope.state = Object.assign({}, this.scope.state); @@ -569,7 +567,8 @@ class ActionEval { const tag_re = /\{\{(.+?)\}\}/g; const label_re = /@(\w+)\b/g; - if (this.entities.length == 0 && this.action.select == 'if') + const allowEmpty = ['if','foreach','join']; + if (this.entities.length == 0 && allowEmpty.includes(this.action.select)) return ''; let action = this.action; @@ -581,10 +580,11 @@ class ActionEval { // TODO: detect cycles // TODO: "source"? // TODO: what if only 1 item? + // TODO: what if join is subset of items? if (action.select == 'join' && this.jr) { let jentities = this.jr.entities; - if (jentities.length == 0) - throw new ECSError(`join query doesn't match any entities`, (action as ActionWithJoin).join); // TODO + if (jentities.length == 0) return ''; + // TODO? throw new ECSError(`join query doesn't match any entities`, (action as ActionWithJoin).join); // TODO let joinfield = this.getJoinField(action, this.qr.atypes, this.jr.atypes); // TODO: what if only 1 item? // TODO: should be able to access fields via Y reg @@ -801,6 +801,7 @@ export class EntityScope implements SourceLocated { childScopes: EntityScope[] = []; systems: System[] = []; entities: Entity[] = []; + fieldtypes: { [name: string]: 'init' | 'const' } = {}; bss = new DataSegment(); rodata = new DataSegment(); code = new CodeSegment(); @@ -1017,16 +1018,15 @@ export class EntityScope implements SourceLocated { setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) { let c = this.em.singleComponentWithFieldName([{ etype: e.etype, cmatch: [component] }], fieldName, e); e.consts[mksymbol(component, fieldName)] = value; - if (this.em.symbols[mksymbol(component, fieldName)] == 'init') - throw new ECSError(`Can't mix const and init values for a component field`, e); - this.em.symbols[mksymbol(component, fieldName)] = 'const'; + this.fieldtypes[mksymbol(component, fieldName)] = 'const'; } setInitValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) { let c = this.em.singleComponentWithFieldName([{ etype: e.etype, cmatch: [component] }], fieldName, e); e.inits[mkscopesymbol(this, component, fieldName)] = value; - if (this.em.symbols[mksymbol(component, fieldName)] == 'const') - throw new ECSError(`Can't mix const and init values for a component field`, e); - this.em.symbols[mksymbol(component, fieldName)] = 'init'; + this.fieldtypes[mksymbol(component, fieldName)] = 'init'; + } + isConstOrInit(component: ComponentType, fieldName: string) : 'const' | 'init' { + return this.fieldtypes[mksymbol(component, fieldName)]; } generateCodeForEvent(event: string): string { // find systems that respond to event @@ -1128,7 +1128,6 @@ export class EntityManager { components: { [name: string]: ComponentType } = {}; systems: { [name: string]: System } = {}; topScopes: { [name: string]: EntityScope } = {}; - symbols: { [name: string]: 'init' | 'const' } = {}; event2systems: { [event: string]: System[] } = {}; name2cfpairs: { [cfname: string]: ComponentFieldPair[] } = {}; mainPath: string = ''; diff --git a/src/worker/tools/cc65.ts b/src/worker/tools/cc65.ts index 77b40837..d90bbba4 100644 --- a/src/worker/tools/cc65.ts +++ b/src/worker/tools/cc65.ts @@ -27,12 +27,14 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) { var segMatch = /[.]segment\s+"(\w+)"/i; var lines = []; var linenum = 0; + let curpath = ''; // TODO: only does .c functions, not all .s files for (var line of code.split(re_crlf)) { var dbgm = dbgLineMatch.exec(line); if (dbgm && dbgm[1]) { var dbgtype = dbgm[4]; offset = parseInt(dbgm[1], 16); + curpath = dbgm[5]; if (dbgtype == 'func') { var funcm = funcLineMatch.exec(dbgm[6]); if (funcm) { @@ -45,9 +47,9 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) { } } if (dbg && dbgm && dbgtype == 'line') { - //console.log(dbgm[6], offset, segofs); + //console.log(dbgm[5], dbgm[6], offset, segofs); lines.push({ - // TODO: sourcefile + path: dbgm[5], line: parseInt(dbgm[6]), offset: offset + segofs, insns: null @@ -65,6 +67,7 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) { linenum--; } else if (!dbg) { lines.push({ + path: curpath, line: linenum, offset: offset + segofs, insns: insns, @@ -219,6 +222,7 @@ export function linkLD65(step: BuildStep): BuildStepResult { var asmlines = []; // TODO: parseCA65Listing(lstout, symbolmap, params, false); var srclines = parseCA65Listing(lstout, symbolmap, params, true); putWorkFile(fn, lstout); + // TODO: multiple source files // TODO: you have to get rid of all source lines to get asm listing listings[fn] = { asmlines: srclines.length ? asmlines : null,