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 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'
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
exportToFile(src: SourceFileExport) {
|
||||||
for (let scope of Object.values(this.em.scopes)) {
|
this.em.exportToFile(src);
|
||||||
scope.analyzeEntities();
|
|
||||||
scope.generateCode();
|
|
||||||
scope.dump(src);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user