1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-26 10:49:17 +00:00

ecs: using, fixed tokenizer start/end column

This commit is contained in:
Steven Hugg 2022-02-02 16:32:04 -06:00
parent d9b8b8b7d3
commit b28a4b5be4
4 changed files with 46 additions and 14 deletions

View File

@ -17,7 +17,7 @@
var keywords1, keywords2; var keywords1, keywords2;
var directives_list = [ var directives_list = [
'component', 'system', 'entity', 'scope', 'end', 'end', 'component', 'system', 'entity', 'scope', 'using',
'const', 'init', 'locals', 'const', 'init', 'locals',
'on', 'do', 'emit', 'limit', 'on', 'do', 'emit', 'limit',
'once', 'foreach', 'source', 'join' 'once', 'foreach', 'source', 'join'

View File

@ -255,7 +255,10 @@ export class ECSCompiler extends Tokenizer {
let scope = this.em.newScope(name, this.currentScope || undefined); let scope = this.em.newScope(name, this.currentScope || undefined);
this.currentScope = scope; this.currentScope = scope;
let cmd; let cmd;
while ((cmd = this.expectTokens(['entity', 'comment', 'end']).str) != 'end') { while ((cmd = this.expectTokens(['using', 'entity', 'comment', 'end']).str) != 'end') {
if (cmd == 'using') {
this.parseScopeUsing();
}
if (cmd == 'entity') { if (cmd == 'entity') {
this.annotate(() => this.parseEntity()); this.annotate(() => this.parseEntity());
} }
@ -267,6 +270,13 @@ export class ECSCompiler extends Tokenizer {
return scope; return scope;
} }
parseScopeUsing() {
let syslist = this.parseList(this.parseSystemRef, ',');
for (let sys of syslist) {
this.currentScope?.systems.push(sys);
}
}
parseEntity() : Entity { parseEntity() : Entity {
if (!this.currentScope) { this.internalError(); throw new Error(); } if (!this.currentScope) { this.internalError(); throw new Error(); }
let name = ''; let name = '';
@ -319,12 +329,15 @@ export class ECSCompiler extends Tokenizer {
return eref; return eref;
} }
exportToFile(src: SourceFileExport) { parseSystemRef() : System {
for (let scope of Object.values(this.em.scopes)) { let name = this.expectIdent().str;
scope.analyzeEntities(); let sys = this.em.getSystemByName(name);
scope.generateCode(); if (!sys) this.compileError(`I couldn't find a system named "${name}".`, this.lasttoken.$loc);
scope.dump(src); return sys;
} }
exportToFile(src: SourceFileExport) {
this.em.exportToFile(src);
} }
export() { export() {

View File

@ -230,6 +230,7 @@ export class Dialect_CA65 {
` `
readonly HEADER = ` readonly HEADER = `
.include "vcs-ca65.h" .include "vcs-ca65.h"
.code
` `
readonly FOOTER = ` readonly FOOTER = `
.segment "VECTORS" .segment "VECTORS"
@ -237,7 +238,7 @@ VecNMI: .word Start
VecReset: .word Start VecReset: .word Start
VecBRK: .word Start VecBRK: .word Start
` `
readonly TEMPLATE_INIT = ` readonly TEMPLATE_INIT_MAIN = `
Start: Start:
CLEAN_START CLEAN_START
` `
@ -502,6 +503,7 @@ class ActionEval {
case 'source': case 'source':
if (!state.x) throw new ECSError('expected index register', this.action); if (!state.x) throw new ECSError('expected index register', this.action);
let int = state.x.intersection(this.qr); let int = state.x.intersection(this.qr);
// TODO: what if we filter 0 entities?
if (int.entities.length == 0) throw new ECSError('queries do not intersect', this.action); if (int.entities.length == 0) throw new ECSError('queries do not intersect', this.action);
let indofs = int.entities[0].id - state.x.entities[0].id; let indofs = int.entities[0].id - state.x.entities[0].id;
state.xofs += indofs; state.xofs += indofs;
@ -705,6 +707,7 @@ class ActionEval {
export class EntityScope implements SourceLocated { export class EntityScope implements SourceLocated {
$loc: SourceLocation; $loc: SourceLocation;
childScopes: EntityScope[] = []; childScopes: EntityScope[] = [];
systems: System[] = [];
entities: Entity[] = []; entities: Entity[] = [];
bss = new DataSegment(); bss = new DataSegment();
rodata = new DataSegment(); rodata = new DataSegment();
@ -909,6 +912,7 @@ export class EntityScope implements SourceLocated {
code = code.replace('{{%dest}}', segment.getOriginSymbol()); code = code.replace('{{%dest}}', segment.getOriginSymbol());
return code; return code;
} }
// TODO: check type/range of value
setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) { setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
let c = this.em.singleComponentWithFieldName([{ etype: e.etype, cmatch: [component] }], fieldName, e); let c = this.em.singleComponentWithFieldName([{ etype: e.etype, cmatch: [component] }], fieldName, e);
e.consts[mksymbol(component, fieldName)] = value; e.consts[mksymbol(component, fieldName)] = value;
@ -935,6 +939,7 @@ export class EntityScope implements SourceLocated {
let s = this.dialect.code(); let s = this.dialect.code();
//s += `\n; event ${event}\n`; //s += `\n; event ${event}\n`;
let emitcode: { [event: string]: string } = {}; let emitcode: { [event: string]: string } = {};
systems = systems.filter(s => this.systems.includes(s));
for (let sys of systems) { for (let sys of systems) {
// TODO: does this work if multiple actions? // TODO: does this work if multiple actions?
// TODO: should 'emits' be on action? // TODO: should 'emits' be on action?
@ -984,7 +989,10 @@ export class EntityScope implements SourceLocated {
} }
generateCode() { generateCode() {
this.tempOffset = this.maxTempBytes = 0; this.tempOffset = this.maxTempBytes = 0;
this.code.addCodeFragment(this.dialect.TEMPLATE_INIT); // TODO: main scope?
if (this.name.toLowerCase() == 'main') {
this.code.addCodeFragment(this.dialect.TEMPLATE_INIT_MAIN);
}
let initcode = this.allocateInitData(this.bss); let initcode = this.allocateInitData(this.bss);
this.code.addCodeFragment(initcode); this.code.addCodeFragment(initcode);
let start = this.generateCodeForEvent('start'); let start = this.generateCodeForEvent('start');
@ -995,7 +1003,6 @@ export class EntityScope implements SourceLocated {
} }
} }
dump(file: SourceFileExport) { dump(file: SourceFileExport) {
file.text(this.dialect.HEADER); // TODO
file.segment(`${this.name}_DATA`, 'bss'); file.segment(`${this.name}_DATA`, 'bss');
if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes); if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes);
this.bss.dump(file); this.bss.dump(file);
@ -1003,7 +1010,6 @@ export class EntityScope implements SourceLocated {
this.rodata.dump(file); this.rodata.dump(file);
//file.segment(`${this.name}_CODE`, 'code'); //file.segment(`${this.name}_CODE`, 'code');
this.code.dump(file); this.code.dump(file);
file.text(this.dialect.FOOTER); // TODO
} }
} }
@ -1013,8 +1019,8 @@ export class EntityManager {
systems: { [name: string]: System } = {}; systems: { [name: string]: System } = {};
scopes: { [name: string]: EntityScope } = {}; scopes: { [name: string]: EntityScope } = {};
symbols: { [name: string]: 'init' | 'const' } = {}; symbols: { [name: string]: 'init' | 'const' } = {};
event2systems: { [name: string]: System[] } = {}; event2systems: { [event: string]: System[] } = {};
name2cfpairs: { [name: string]: ComponentFieldPair[] } = {}; name2cfpairs: { [cfname: string]: ComponentFieldPair[] } = {};
constructor(public readonly dialect: Dialect_CA65) { constructor(public readonly dialect: Dialect_CA65) {
} }
@ -1089,6 +1095,9 @@ export class EntityManager {
getComponentByName(name: string): ComponentType { getComponentByName(name: string): ComponentType {
return this.components[name]; return this.components[name];
} }
getSystemByName(name: string): System {
return this.systems[name];
}
singleComponentWithFieldName(atypes: ArchetypeMatch[], fieldName: string, where: SourceLocated) { singleComponentWithFieldName(atypes: ArchetypeMatch[], fieldName: string, where: SourceLocated) {
let components = this.componentsWithFieldName(atypes, fieldName); let components = this.componentsWithFieldName(atypes, fieldName);
// TODO: use name2cfpairs? // TODO: use name2cfpairs?
@ -1106,4 +1115,13 @@ export class EntityManager {
systems: this.systems systems: this.systems
}) })
} }
exportToFile(file: SourceFileExport) {
file.text(this.dialect.HEADER); // TODO
for (let scope of Object.values(this.scopes)) {
scope.analyzeEntities();
scope.generateCode();
scope.dump(file);
}
file.text(this.dialect.FOOTER); // TODO
}
} }

View File

@ -110,7 +110,8 @@ export class Tokenizer {
let s: string = m[i + 1]; let s: string = m[i + 1];
if (s != null) { if (s != null) {
found = true; found = true;
let loc = { path: this.path, line: this.lineno, start: m.index, end: m.index + s.length }; let col = m.index - (this.lineindex[this.lineno-1] || -1) - 1;
let loc = { path: this.path, line: this.lineno, start: col, end: col + s.length };
let rule = rules[i]; let rule = rules[i];
// add token to list // add token to list
switch (rule.type) { switch (rule.type) {