From 83238f30f1e990f2f5ceb26f63effa19be43654f Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Wed, 2 Feb 2022 17:03:22 -0600 Subject: [PATCH] ecs: scoping, start labels, subscopes (need unions for data) --- src/common/ecs/compiler.ts | 5 ++++- src/common/ecs/ecs.ts | 39 ++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/common/ecs/compiler.ts b/src/common/ecs/compiler.ts index 7d530730..33061c3f 100644 --- a/src/common/ecs/compiler.ts +++ b/src/common/ecs/compiler.ts @@ -255,13 +255,16 @@ export class ECSCompiler extends Tokenizer { let scope = this.em.newScope(name, this.currentScope || undefined); this.currentScope = scope; let cmd; - while ((cmd = this.expectTokens(['using', 'entity', 'comment', 'end']).str) != 'end') { + while ((cmd = this.expectTokens(['using', 'entity', 'scope', 'comment', 'end']).str) != 'end') { if (cmd == 'using') { this.parseScopeUsing(); } if (cmd == 'entity') { this.annotate(() => this.parseEntity()); } + if (cmd == 'scope') { + this.annotate(() => this.parseScope()); + } if (cmd == 'comment') { this.expectTokenTypes([ECSTokenType.CodeFragment]); } diff --git a/src/common/ecs/ecs.ts b/src/common/ecs/ecs.ts index f90d16f8..461c86aa 100644 --- a/src/common/ecs/ecs.ts +++ b/src/common/ecs/ecs.ts @@ -56,6 +56,7 @@ crazy idea -- full expansion, then relooper */ +import { throws } from "assert"; import { SourceLocated, SourceLocation } from "../workertypes"; export class ECSError extends Error { @@ -230,16 +231,19 @@ export class Dialect_CA65 { ` readonly HEADER = ` .include "vcs-ca65.h" +.define PAL 0 .code ` readonly FOOTER = ` .segment "VECTORS" -VecNMI: .word Start -VecReset: .word Start -VecBRK: .word Start +VecNMI: .word Main::__NMI +VecReset: .word Main::__Reset +VecBRK: .word Main::__BRK ` readonly TEMPLATE_INIT_MAIN = ` -Start: +__NMI: +__Reset: +__BRK: CLEAN_START ` @@ -313,6 +317,14 @@ export class SourceFileExport { debug_line(path: string, line: number) { this.lines.push(` .dbg line, "${path}", ${line}`); } + startScope(name: string) { + this.lines.push(` .scope ${name}`) + } + endScope(name: string) { + this.lines.push(` .endscope`) + this.lines.push(`${name}__Start = ${name}::__Start`) + // TODO: scope__start = scope::start + } toString() { return this.lines.join('\n'); } @@ -1003,13 +1015,22 @@ export class EntityScope implements SourceLocated { } } dump(file: SourceFileExport) { + this.analyzeEntities(); + this.generateCode(); + file.startScope(this.name); file.segment(`${this.name}_DATA`, 'bss'); if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes); this.bss.dump(file); file.segment(`${this.name}_RODATA`, 'rodata'); this.rodata.dump(file); //file.segment(`${this.name}_CODE`, 'code'); + file.label('__Start'); this.code.dump(file); + for (let subscope of this.childScopes) { + // TODO: overlay child BSS segments + subscope.dump(file); + } + file.endScope(this.name); } } @@ -1017,7 +1038,7 @@ export class EntityManager { archetypes: { [key: string]: EntityArchetype } = {}; components: { [name: string]: ComponentType } = {}; systems: { [name: string]: System } = {}; - scopes: { [name: string]: EntityScope } = {}; + topScopes: { [name: string]: EntityScope } = {}; symbols: { [name: string]: 'init' | 'const' } = {}; event2systems: { [event: string]: System[] } = {}; name2cfpairs: { [cfname: string]: ComponentFieldPair[] } = {}; @@ -1026,8 +1047,8 @@ export class EntityManager { } newScope(name: string, parent?: EntityScope) { let scope = new EntityScope(this, this.dialect, name, parent); - if (this.scopes[name]) throw new ECSError(`scope ${name} already defined`); - this.scopes[name] = scope; + if (this.topScopes[name]) throw new ECSError(`scope ${name} already defined`); + if (!parent) this.topScopes[name] = scope; return scope; } defineComponent(ctype: ComponentType) { @@ -1117,9 +1138,7 @@ export class EntityManager { } exportToFile(file: SourceFileExport) { file.text(this.dialect.HEADER); // TODO - for (let scope of Object.values(this.scopes)) { - scope.analyzeEntities(); - scope.generateCode(); + for (let scope of Object.values(this.topScopes)) { scope.dump(file); } file.text(this.dialect.FOOTER); // TODO