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:
parent
d9b8b8b7d3
commit
b28a4b5be4
@ -17,7 +17,7 @@
|
||||
var keywords1, keywords2;
|
||||
|
||||
var directives_list = [
|
||||
'component', 'system', 'entity', 'scope', 'end',
|
||||
'end', 'component', 'system', 'entity', 'scope', 'using',
|
||||
'const', 'init', 'locals',
|
||||
'on', 'do', 'emit', 'limit',
|
||||
'once', 'foreach', 'source', 'join'
|
||||
|
@ -255,7 +255,10 @@ export class ECSCompiler extends Tokenizer {
|
||||
let scope = this.em.newScope(name, this.currentScope || undefined);
|
||||
this.currentScope = scope;
|
||||
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') {
|
||||
this.annotate(() => this.parseEntity());
|
||||
}
|
||||
@ -267,6 +270,13 @@ export class ECSCompiler extends Tokenizer {
|
||||
return scope;
|
||||
}
|
||||
|
||||
parseScopeUsing() {
|
||||
let syslist = this.parseList(this.parseSystemRef, ',');
|
||||
for (let sys of syslist) {
|
||||
this.currentScope?.systems.push(sys);
|
||||
}
|
||||
}
|
||||
|
||||
parseEntity() : Entity {
|
||||
if (!this.currentScope) { this.internalError(); throw new Error(); }
|
||||
let name = '';
|
||||
@ -319,12 +329,15 @@ export class ECSCompiler extends Tokenizer {
|
||||
return eref;
|
||||
}
|
||||
|
||||
parseSystemRef() : System {
|
||||
let name = this.expectIdent().str;
|
||||
let sys = this.em.getSystemByName(name);
|
||||
if (!sys) this.compileError(`I couldn't find a system named "${name}".`, this.lasttoken.$loc);
|
||||
return sys;
|
||||
}
|
||||
|
||||
exportToFile(src: SourceFileExport) {
|
||||
for (let scope of Object.values(this.em.scopes)) {
|
||||
scope.analyzeEntities();
|
||||
scope.generateCode();
|
||||
scope.dump(src);
|
||||
}
|
||||
this.em.exportToFile(src);
|
||||
}
|
||||
|
||||
export() {
|
||||
|
@ -230,6 +230,7 @@ export class Dialect_CA65 {
|
||||
`
|
||||
readonly HEADER = `
|
||||
.include "vcs-ca65.h"
|
||||
.code
|
||||
`
|
||||
readonly FOOTER = `
|
||||
.segment "VECTORS"
|
||||
@ -237,7 +238,7 @@ VecNMI: .word Start
|
||||
VecReset: .word Start
|
||||
VecBRK: .word Start
|
||||
`
|
||||
readonly TEMPLATE_INIT = `
|
||||
readonly TEMPLATE_INIT_MAIN = `
|
||||
Start:
|
||||
CLEAN_START
|
||||
`
|
||||
@ -502,6 +503,7 @@ class ActionEval {
|
||||
case 'source':
|
||||
if (!state.x) throw new ECSError('expected index register', this.action);
|
||||
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);
|
||||
let indofs = int.entities[0].id - state.x.entities[0].id;
|
||||
state.xofs += indofs;
|
||||
@ -705,6 +707,7 @@ class ActionEval {
|
||||
export class EntityScope implements SourceLocated {
|
||||
$loc: SourceLocation;
|
||||
childScopes: EntityScope[] = [];
|
||||
systems: System[] = [];
|
||||
entities: Entity[] = [];
|
||||
bss = new DataSegment();
|
||||
rodata = new DataSegment();
|
||||
@ -909,6 +912,7 @@ export class EntityScope implements SourceLocated {
|
||||
code = code.replace('{{%dest}}', segment.getOriginSymbol());
|
||||
return code;
|
||||
}
|
||||
// TODO: check type/range of value
|
||||
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;
|
||||
@ -935,6 +939,7 @@ export class EntityScope implements SourceLocated {
|
||||
let s = this.dialect.code();
|
||||
//s += `\n; event ${event}\n`;
|
||||
let emitcode: { [event: string]: string } = {};
|
||||
systems = systems.filter(s => this.systems.includes(s));
|
||||
for (let sys of systems) {
|
||||
// TODO: does this work if multiple actions?
|
||||
// TODO: should 'emits' be on action?
|
||||
@ -984,7 +989,10 @@ export class EntityScope implements SourceLocated {
|
||||
}
|
||||
generateCode() {
|
||||
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);
|
||||
this.code.addCodeFragment(initcode);
|
||||
let start = this.generateCodeForEvent('start');
|
||||
@ -995,7 +1003,6 @@ export class EntityScope implements SourceLocated {
|
||||
}
|
||||
}
|
||||
dump(file: SourceFileExport) {
|
||||
file.text(this.dialect.HEADER); // TODO
|
||||
file.segment(`${this.name}_DATA`, 'bss');
|
||||
if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes);
|
||||
this.bss.dump(file);
|
||||
@ -1003,7 +1010,6 @@ export class EntityScope implements SourceLocated {
|
||||
this.rodata.dump(file);
|
||||
//file.segment(`${this.name}_CODE`, 'code');
|
||||
this.code.dump(file);
|
||||
file.text(this.dialect.FOOTER); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,8 +1019,8 @@ export class EntityManager {
|
||||
systems: { [name: string]: System } = {};
|
||||
scopes: { [name: string]: EntityScope } = {};
|
||||
symbols: { [name: string]: 'init' | 'const' } = {};
|
||||
event2systems: { [name: string]: System[] } = {};
|
||||
name2cfpairs: { [name: string]: ComponentFieldPair[] } = {};
|
||||
event2systems: { [event: string]: System[] } = {};
|
||||
name2cfpairs: { [cfname: string]: ComponentFieldPair[] } = {};
|
||||
|
||||
constructor(public readonly dialect: Dialect_CA65) {
|
||||
}
|
||||
@ -1089,6 +1095,9 @@ export class EntityManager {
|
||||
getComponentByName(name: string): ComponentType {
|
||||
return this.components[name];
|
||||
}
|
||||
getSystemByName(name: string): System {
|
||||
return this.systems[name];
|
||||
}
|
||||
singleComponentWithFieldName(atypes: ArchetypeMatch[], fieldName: string, where: SourceLocated) {
|
||||
let components = this.componentsWithFieldName(atypes, fieldName);
|
||||
// TODO: use name2cfpairs?
|
||||
@ -1106,4 +1115,13 @@ export class EntityManager {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,8 @@ export class Tokenizer {
|
||||
let s: string = m[i + 1];
|
||||
if (s != null) {
|
||||
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];
|
||||
// add token to list
|
||||
switch (rule.type) {
|
||||
|
Loading…
Reference in New Issue
Block a user