mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-26 10:49:17 +00:00
ecs: {{%props}}, ecs errors w/ $loc
This commit is contained in:
parent
249d4735eb
commit
c54b6a1150
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import { Tokenizer, TokenType } from "../tokenizer";
|
import { Tokenizer, TokenType } from "../tokenizer";
|
||||||
|
import { SourceLocated } from "../workertypes";
|
||||||
import { Action, ArrayType, ComponentType, DataField, DataType, DataValue, Dialect_CA65, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SourceFileExport, System } from "./ecs";
|
import { Action, ArrayType, ComponentType, DataField, DataType, DataValue, Dialect_CA65, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SourceFileExport, System } from "./ecs";
|
||||||
|
|
||||||
export enum ECSTokenType {
|
export enum ECSTokenType {
|
||||||
@ -18,7 +19,6 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
super();
|
super();
|
||||||
//this.includeEOL = true;
|
//this.includeEOL = true;
|
||||||
this.setTokenRules([
|
this.setTokenRules([
|
||||||
{ type: TokenType.Ident, regex: /[A-Za-z_][A-Za-z0-9_]*/ },
|
|
||||||
{ type: TokenType.CodeFragment, regex: /---/ },
|
{ type: TokenType.CodeFragment, regex: /---/ },
|
||||||
{ type: ECSTokenType.Ellipsis, regex: /\.\./ },
|
{ type: ECSTokenType.Ellipsis, regex: /\.\./ },
|
||||||
{ type: ECSTokenType.Operator, regex: /[#=,:(){}\[\]]/ },
|
{ type: ECSTokenType.Operator, regex: /[#=,:(){}\[\]]/ },
|
||||||
@ -26,15 +26,23 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
{ type: ECSTokenType.Integer, regex: /[-]?0x[A-Fa-f0-9]+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?0x[A-Fa-f0-9]+/ },
|
||||||
{ type: ECSTokenType.Integer, regex: /[-]?\$[A-Fa-f0-9]+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?\$[A-Fa-f0-9]+/ },
|
||||||
{ type: ECSTokenType.Integer, regex: /[-]?\d+/ },
|
{ type: ECSTokenType.Integer, regex: /[-]?\d+/ },
|
||||||
|
{ type: TokenType.Ident, regex: /[A-Za-z_][A-Za-z0-9_]*/ },
|
||||||
{ type: TokenType.Ignore, regex: /\s+/ },
|
{ type: TokenType.Ignore, regex: /\s+/ },
|
||||||
]);
|
]);
|
||||||
this.errorOnCatchAll = true;
|
this.errorOnCatchAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
annotate<T extends SourceLocated>(fn: () => T) {
|
||||||
|
let tok = this.peekToken();
|
||||||
|
let obj = fn();
|
||||||
|
if (obj) (obj as SourceLocated).$loc = tok.$loc;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
parseFile(text: string, path: string) {
|
parseFile(text: string, path: string) {
|
||||||
this.tokenizeFile(text, path);
|
this.tokenizeFile(text, path);
|
||||||
while (!this.isEOF()) {
|
while (!this.isEOF()) {
|
||||||
this.parseTopLevel();
|
this.annotate(() => this.parseTopLevel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,9 +145,10 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let actions: Action[] = [];
|
let actions: Action[] = [];
|
||||||
let system: System = { name, actions };
|
let system: System = { name, actions };
|
||||||
let cmd;
|
let cmd;
|
||||||
while ((cmd = this.consumeToken().str) != 'end') {
|
while ((cmd = this.expectTokens(['on','locals','end']).str) != 'end') {
|
||||||
if (cmd == 'on') {
|
if (cmd == 'on') {
|
||||||
actions.push(this.parseAction());
|
let action = this.annotate(() => this.parseAction());
|
||||||
|
actions.push(action);
|
||||||
} else if (cmd == 'locals') {
|
} else if (cmd == 'locals') {
|
||||||
system.tempbytes = this.expectInteger();
|
system.tempbytes = this.expectInteger();
|
||||||
} else {
|
} else {
|
||||||
@ -150,6 +159,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseAction(): Action {
|
parseAction(): Action {
|
||||||
|
// TODO: unused events?
|
||||||
let event = this.expectIdent().str;
|
let event = this.expectIdent().str;
|
||||||
this.expectToken('do');
|
this.expectToken('do');
|
||||||
let select = this.expectTokens(['once', 'foreach', 'source', 'join']).str as SelectType; // TODO: type check?
|
let select = this.expectTokens(['once', 'foreach', 'source', 'join']).str as SelectType; // TODO: type check?
|
||||||
@ -159,6 +169,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let limit;
|
let limit;
|
||||||
if (this.peekToken().str == 'limit') {
|
if (this.peekToken().str == 'limit') {
|
||||||
this.consumeToken();
|
this.consumeToken();
|
||||||
|
if (!['foreach', 'join'].includes(select)) this.compileError(`A "${select}" query can't include a limit.`);
|
||||||
limit = this.expectInteger();
|
limit = this.expectInteger();
|
||||||
}
|
}
|
||||||
if (this.peekToken().str == 'emit') {
|
if (this.peekToken().str == 'emit') {
|
||||||
@ -205,11 +216,12 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let scope = this.em.newScope(name, this.currentScope);
|
let scope = this.em.newScope(name, this.currentScope);
|
||||||
this.currentScope = scope;
|
this.currentScope = scope;
|
||||||
let cmd;
|
let cmd;
|
||||||
while ((cmd = this.consumeToken().str) != 'end') {
|
while ((cmd = this.expectTokens(['entity', 'comment', 'end']).str) != 'end') {
|
||||||
if (cmd == 'entity') {
|
if (cmd == 'entity') {
|
||||||
this.parseEntity();
|
this.annotate(() => this.parseEntity());
|
||||||
} else {
|
}
|
||||||
this.compileError(`Unexpected scope keyword: ${cmd}`);
|
if (cmd == 'comment') {
|
||||||
|
this.expectTokenTypes([TokenType.CodeFragment]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.currentScope = scope.parent;
|
this.currentScope = scope.parent;
|
||||||
@ -225,22 +237,18 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let e = this.currentScope.newEntity(etype);
|
let e = this.currentScope.newEntity(etype);
|
||||||
e.name = name;
|
e.name = name;
|
||||||
let cmd;
|
let cmd;
|
||||||
while ((cmd = this.consumeToken().str) != 'end') {
|
while ((cmd = this.expectTokens(['const', 'init', 'end']).str) != 'end') {
|
||||||
// TODO: check data types
|
// TODO: check data types
|
||||||
if (cmd == 'const' || cmd == 'init') {
|
let name = this.expectIdent().str;
|
||||||
let name = this.expectIdent().str;
|
let comps = this.em.componentsWithFieldName([{etype: e.etype, cmatch:e.etype.components}], name);
|
||||||
let comps = this.em.componentsWithFieldName([{etype: e.etype, cmatch:e.etype.components}], name);
|
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
||||||
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
||||||
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
let field = comps[0].fields.find(f => f.name == name);
|
||||||
let field = comps[0].fields.find(f => f.name == name);
|
if (!field) this.internalError();
|
||||||
if (!field) this.internalError();
|
this.expectToken('=');
|
||||||
this.expectToken('=');
|
let value = this.parseDataValue(field);
|
||||||
let value = this.parseDataValue(field);
|
if (cmd == 'const') this.currentScope.setConstValue(e, comps[0], name, value);
|
||||||
if (cmd == 'const') this.currentScope.setConstValue(e, comps[0], name, value);
|
if (cmd == 'init') this.currentScope.setInitValue(e, comps[0], name, value);
|
||||||
if (cmd == 'init') this.currentScope.setInitValue(e, comps[0], name, value);
|
|
||||||
} else {
|
|
||||||
this.compileError(`Unexpected scope keyword: ${cmd}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ function mkscopesymbol(s: EntityScope, c: ComponentType, fieldName: string) {
|
|||||||
return s.name + '_' + c.name + '_' + fieldName;
|
return s.name + '_' + c.name + '_' + fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Entity {
|
export interface Entity extends SourceLocated {
|
||||||
id: number;
|
id: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
etype: EntityArchetype;
|
etype: EntityArchetype;
|
||||||
@ -71,7 +71,7 @@ export interface EntityArchetype {
|
|||||||
components: ComponentType[];
|
components: ComponentType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentType {
|
export interface ComponentType extends SourceLocated {
|
||||||
name: string;
|
name: string;
|
||||||
fields: DataField[];
|
fields: DataField[];
|
||||||
optional?: boolean;
|
optional?: boolean;
|
||||||
@ -84,13 +84,13 @@ export interface Query {
|
|||||||
updates?: string[];
|
updates?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface System {
|
export interface System extends SourceLocated {
|
||||||
name: string;
|
name: string;
|
||||||
actions: Action[];
|
actions: Action[];
|
||||||
tempbytes?: number;
|
tempbytes?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Action {
|
export interface Action extends SourceLocated {
|
||||||
text: string;
|
text: string;
|
||||||
event: string;
|
event: string;
|
||||||
select: SelectType
|
select: SelectType
|
||||||
@ -158,26 +158,28 @@ export class Dialect_CA65 {
|
|||||||
readonly ASM_ITERATE_EACH = `
|
readonly ASM_ITERATE_EACH = `
|
||||||
ldx #0
|
ldx #0
|
||||||
@__each:
|
@__each:
|
||||||
{{code}}
|
{{%code}}
|
||||||
inx
|
inx
|
||||||
cpx #{{ecount}}
|
cpx #{{%ecount}}
|
||||||
bne @__each
|
bne @__each
|
||||||
|
@__exit:
|
||||||
`;
|
`;
|
||||||
|
|
||||||
readonly ASM_ITERATE_JOIN = `
|
readonly ASM_ITERATE_JOIN = `
|
||||||
ldy #0
|
ldy #0
|
||||||
@__each:
|
@__each:
|
||||||
ldx {{joinfield}},y
|
ldx {{%joinfield}},y
|
||||||
{{code}}
|
{{%code}}
|
||||||
iny
|
iny
|
||||||
cpy #{{ecount}}
|
cpy #{{%ecount}}
|
||||||
bne @__each
|
bne @__each
|
||||||
|
@__exit:
|
||||||
`;
|
`;
|
||||||
|
|
||||||
readonly INIT_FROM_ARRAY = `
|
readonly INIT_FROM_ARRAY = `
|
||||||
ldy #{{nbytes}}
|
ldy #{{%nbytes}}
|
||||||
: lda {{src}}-1,y
|
: lda {{%src}}-1,y
|
||||||
sta {{dest}}-1,y
|
sta {{%dest}}-1,y
|
||||||
dey
|
dey
|
||||||
bne :-
|
bne :-
|
||||||
`
|
`
|
||||||
@ -337,7 +339,8 @@ function getPackedFieldSize(f: DataType, constValue?: DataValue): number {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EntityScope {
|
export class EntityScope implements SourceLocated {
|
||||||
|
$loc: SourceLocation;
|
||||||
childScopes: EntityScope[] = [];
|
childScopes: EntityScope[] = [];
|
||||||
entities: Entity[] = [];
|
entities: Entity[] = [];
|
||||||
bss = new Segment();
|
bss = new Segment();
|
||||||
@ -430,10 +433,11 @@ export class EntityScope {
|
|||||||
hasComponent(ctype: ComponentType) {
|
hasComponent(ctype: ComponentType) {
|
||||||
return this.componentsInScope.has(ctype.name);
|
return this.componentsInScope.has(ctype.name);
|
||||||
}
|
}
|
||||||
getJoinField(atypes: ArchetypeMatch[], jtypes: ArchetypeMatch[]) : ComponentFieldPair {
|
getJoinField(action: Action, atypes: ArchetypeMatch[], jtypes: ArchetypeMatch[]) : ComponentFieldPair {
|
||||||
let refs = Array.from(this.iterateArchetypeFields(atypes, (c,f) => f.dtype == 'ref'));
|
let refs = Array.from(this.iterateArchetypeFields(atypes, (c,f) => f.dtype == 'ref'));
|
||||||
if (refs.length == 0) throw new ECSError(`cannot find join fields`);
|
// TODO: better error message
|
||||||
if (refs.length > 1) throw new ECSError(`cannot join multiple fields`);
|
if (refs.length == 0) throw new ECSError(`cannot find join fields`, action);
|
||||||
|
if (refs.length > 1) throw new ECSError(`cannot join multiple fields`, action);
|
||||||
// TODO: check to make sure join works
|
// TODO: check to make sure join works
|
||||||
return refs[0]; // TODO
|
return refs[0]; // TODO
|
||||||
/* TODO
|
/* TODO
|
||||||
@ -546,23 +550,23 @@ export class EntityScope {
|
|||||||
let bufofs = this.rodata.allocateInitData(bufsym, initbytes);
|
let bufofs = this.rodata.allocateInitData(bufsym, initbytes);
|
||||||
let code = this.dialect.INIT_FROM_ARRAY;
|
let code = this.dialect.INIT_FROM_ARRAY;
|
||||||
//TODO: function to repalce from dict?
|
//TODO: function to repalce from dict?
|
||||||
code = code.replace('{{nbytes}}', initbytes.length.toString())
|
code = code.replace('{{%nbytes}}', initbytes.length.toString())
|
||||||
code = code.replace('{{src}}', bufsym);
|
code = code.replace('{{%src}}', bufsym);
|
||||||
code = code.replace('{{dest}}', segment.getOriginSymbol());
|
code = code.replace('{{%dest}}', segment.getOriginSymbol());
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
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, "setConstValue");
|
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setConstValue");
|
||||||
e.consts[mksymbol(component, fieldName)] = value;
|
e.consts[mksymbol(component, fieldName)] = value;
|
||||||
if (this.em.symbols[mksymbol(component, fieldName)] == 'init')
|
if (this.em.symbols[mksymbol(component, fieldName)] == 'init')
|
||||||
throw new ECSError(`Can't mix const and init values for a component field`);
|
throw new ECSError(`Can't mix const and init values for a component field`, e);
|
||||||
this.em.symbols[mksymbol(component, fieldName)] = 'const';
|
this.em.symbols[mksymbol(component, fieldName)] = 'const';
|
||||||
}
|
}
|
||||||
setInitValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
|
setInitValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
|
||||||
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setInitValue");
|
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setInitValue");
|
||||||
e.inits[mkscopesymbol(this, component, fieldName)] = value;
|
e.inits[mkscopesymbol(this, component, fieldName)] = value;
|
||||||
if (this.em.symbols[mksymbol(component, fieldName)] == 'const')
|
if (this.em.symbols[mksymbol(component, fieldName)] == 'const')
|
||||||
throw new ECSError(`Can't mix const and init values for a component field`);
|
throw new ECSError(`Can't mix const and init values for a component field`, e);
|
||||||
this.em.symbols[mksymbol(component, fieldName)] = 'init';
|
this.em.symbols[mksymbol(component, fieldName)] = 'init';
|
||||||
}
|
}
|
||||||
generateCodeForEvent(event: string): string {
|
generateCodeForEvent(event: string): string {
|
||||||
@ -611,29 +615,43 @@ export class EntityScope {
|
|||||||
}
|
}
|
||||||
replaceCode(code: string, sys: System, action: Action): string {
|
replaceCode(code: string, sys: System, action: Action): string {
|
||||||
const tag_re = /\{\{(.+?)\}\}/g;
|
const tag_re = /\{\{(.+?)\}\}/g;
|
||||||
|
const label_re = /@(\w+)\b/g;
|
||||||
|
|
||||||
let label = `${sys.name}__${action.event}`;
|
let label = `${sys.name}__${action.event}`;
|
||||||
let atypes = this.em.archetypesMatching(action.query);
|
let atypes = this.em.archetypesMatching(action.query);
|
||||||
let entities = this.entitiesMatching(atypes);
|
let entities = this.entitiesMatching(atypes);
|
||||||
|
if (entities.length == 0) throw new ECSError(`action ${label} doesn't match any entities`, action); // TODO
|
||||||
// TODO: detect cycles
|
// TODO: detect cycles
|
||||||
// TODO: "source"?
|
// TODO: "source"?
|
||||||
// TODO: what if only 1 item?
|
// TODO: what if only 1 item?
|
||||||
|
let props : {[name: string] : string} = {};
|
||||||
if (action.select == 'foreach') {
|
if (action.select == 'foreach') {
|
||||||
code = this.wrapCodeInLoop(code, action, entities);
|
code = this.wrapCodeInLoop(code, action, entities);
|
||||||
}
|
}
|
||||||
if (action.select == 'join' && action.join) {
|
if (action.select == 'join' && action.join) {
|
||||||
let jtypes = this.em.archetypesMatching(action.join);
|
let jtypes = this.em.archetypesMatching(action.join);
|
||||||
let jentities = this.entitiesMatching(jtypes);
|
let jentities = this.entitiesMatching(jtypes);
|
||||||
let joinfield = this.getJoinField(atypes, jtypes);
|
let joinfield = this.getJoinField(action, atypes, jtypes);
|
||||||
// TODO: what if only 1 item?
|
// TODO: what if only 1 item?
|
||||||
|
// TODO: should be able to access fields via Y reg
|
||||||
code = this.wrapCodeInLoop(code, action, entities, joinfield);
|
code = this.wrapCodeInLoop(code, action, entities, joinfield);
|
||||||
atypes = jtypes;
|
atypes = jtypes;
|
||||||
entities = jentities;
|
entities = jentities;
|
||||||
|
props['%joinfield'] = this.dialect.fieldsymbol(joinfield.c, joinfield.f, 0);
|
||||||
}
|
}
|
||||||
if (entities.length == 0) throw new ECSError(`action ${label} doesn't match any entities`);
|
props['%efullcount'] = entities.length.toString();
|
||||||
|
if (action.limit) {
|
||||||
|
entities = entities.slice(0, action.limit);
|
||||||
|
}
|
||||||
|
if (entities.length == 0) throw new ECSError(`action ${label} doesn't match any entities`); // TODO
|
||||||
|
// define properties
|
||||||
|
props['%elo'] = entities[0].id.toString();
|
||||||
|
props['%ehi'] = entities[entities.length - 1].id.toString();
|
||||||
|
props['%ecount'] = entities.length.toString();
|
||||||
// replace @labels
|
// replace @labels
|
||||||
code = code.replace(/@(\w+)\b/g, (s: string, a: string) => `${label}__${a}`);
|
code = code.replace(label_re, (s: string, a: string) => `${label}__${a}`);
|
||||||
// replace {{...}} tags
|
// replace {{...}} tags
|
||||||
return code.replace(tag_re, (entire, group: string) => {
|
code = code.replace(tag_re, (entire, group: string) => {
|
||||||
let cmd = group.charAt(0);
|
let cmd = group.charAt(0);
|
||||||
let rest = group.substring(1);
|
let rest = group.substring(1);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@ -642,7 +660,7 @@ export class EntityScope {
|
|||||||
case '.': // auto label
|
case '.': // auto label
|
||||||
case '@': // auto label
|
case '@': // auto label
|
||||||
return `${label}_${rest}`;
|
return `${label}_${rest}`;
|
||||||
case '$': // temp byte
|
case '$': // temp byte (TODO: check to make sure not overflowing)
|
||||||
return `TEMP+${this.tempOffset}+${rest}`;
|
return `TEMP+${this.tempOffset}+${rest}`;
|
||||||
case '=':
|
case '=':
|
||||||
// TODO?
|
// TODO?
|
||||||
@ -653,9 +671,12 @@ export class EntityScope {
|
|||||||
case '^': // subroutine reference
|
case '^': // subroutine reference
|
||||||
return this.includeSubroutine(rest);
|
return this.includeSubroutine(rest);
|
||||||
default:
|
default:
|
||||||
throw new ECSError(`unrecognized command ${cmd} in ${entire}`);
|
let value = props[group];
|
||||||
|
if (value) return value;
|
||||||
|
else throw new ECSError(`unrecognized command {{${group}}} in ${entire}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
includeSubroutine(symbol: string): string {
|
includeSubroutine(symbol: string): string {
|
||||||
this.subroutines.add(symbol);
|
this.subroutines.add(symbol);
|
||||||
@ -667,16 +688,7 @@ export class EntityScope {
|
|||||||
// TODO: what if 0 or 1 entitites?
|
// TODO: what if 0 or 1 entitites?
|
||||||
let s = this.dialect.ASM_ITERATE_EACH;
|
let s = this.dialect.ASM_ITERATE_EACH;
|
||||||
if (joinfield) s = this.dialect.ASM_ITERATE_JOIN;
|
if (joinfield) s = this.dialect.ASM_ITERATE_JOIN;
|
||||||
if (action.limit) {
|
s = s.replace('{{%code}}', code);
|
||||||
ents = ents.slice(0, action.limit);
|
|
||||||
}
|
|
||||||
s = s.replace('{{elo}}', () => ents[0].id.toString());
|
|
||||||
s = s.replace('{{ehi}}', () => ents[ents.length - 1].id.toString());
|
|
||||||
s = s.replace('{{ecount}}', () => ents.length.toString());
|
|
||||||
s = s.replace('{{code}}', code);
|
|
||||||
if (joinfield) {
|
|
||||||
s = s.replace('{{joinfield}}', () => this.dialect.fieldsymbol(joinfield.c, joinfield.f, 0));
|
|
||||||
}
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
generateCodeForField(sys: System, action: Action,
|
generateCodeForField(sys: System, action: Action,
|
||||||
|
@ -101,9 +101,10 @@ export class Tokenizer {
|
|||||||
// add token to list
|
// add token to list
|
||||||
switch (rule.type) {
|
switch (rule.type) {
|
||||||
case TokenType.CodeFragment:
|
case TokenType.CodeFragment:
|
||||||
if (this.codeFragment) {
|
// TODO: empty code fragment doesn't work
|
||||||
|
if (this.codeFragment != null) {
|
||||||
let codeLoc = mergeLocs(this.codeFragmentStart, loc);
|
let codeLoc = mergeLocs(this.codeFragmentStart, loc);
|
||||||
this._pushToken({ str: this.codeFragment, type: rule.type, $loc: codeLoc }); //TODO: merge start/end
|
this._pushToken({ str: this.codeFragment, type: rule.type, $loc: codeLoc });
|
||||||
this.codeFragmentStart = null;
|
this.codeFragmentStart = null;
|
||||||
this.codeFragment = null;
|
this.codeFragment = null;
|
||||||
} else {
|
} else {
|
||||||
@ -121,6 +122,7 @@ export class Tokenizer {
|
|||||||
if (this.codeFragment == null) {
|
if (this.codeFragment == null) {
|
||||||
this._pushToken({ str: s, type: rule.type, $loc: loc });
|
this._pushToken({ str: s, type: rule.type, $loc: loc });
|
||||||
}
|
}
|
||||||
|
case TokenType.Comment:
|
||||||
case TokenType.Ignore:
|
case TokenType.Ignore:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ECSCompiler } from "../../common/ecs/compiler";
|
import { ECSCompiler } from "../../common/ecs/compiler";
|
||||||
|
import { ECSError } from "../../common/ecs/ecs";
|
||||||
import { CompileError } from "../../common/tokenizer";
|
import { CompileError } from "../../common/tokenizer";
|
||||||
import { CodeListingMap } from "../../common/workertypes";
|
import { CodeListingMap } from "../../common/workertypes";
|
||||||
import { BuildStep, BuildStepResult, gatherFiles, getWorkFileAsString, putWorkFile, staleFiles } from "../workermain";
|
import { BuildStep, BuildStepResult, gatherFiles, getWorkFileAsString, putWorkFile, staleFiles } from "../workermain";
|
||||||
@ -11,17 +12,20 @@ export function assembleECS(step: BuildStep): BuildStepResult {
|
|||||||
let code = getWorkFileAsString(step.path);
|
let code = getWorkFileAsString(step.path);
|
||||||
try {
|
try {
|
||||||
compiler.parseFile(code, step.path);
|
compiler.parseFile(code, step.path);
|
||||||
|
let outtext = compiler.export().toString();
|
||||||
|
putWorkFile(destpath, outtext);
|
||||||
|
var listings: CodeListingMap = {};
|
||||||
|
listings[destpath] = {lines:[], text:outtext} // TODO
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof CompileError) {
|
if (e instanceof ECSError) {
|
||||||
|
compiler.addError(e.message, e.$loc);
|
||||||
|
return { errors: compiler.errors };
|
||||||
|
} else if (e instanceof CompileError) {
|
||||||
return { errors: compiler.errors };
|
return { errors: compiler.errors };
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let outtext = compiler.export().toString();
|
|
||||||
putWorkFile(destpath, outtext);
|
|
||||||
var listings: CodeListingMap = {};
|
|
||||||
listings[destpath] = {lines:[], text:outtext} // TODO
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
nexttool: "ca65",
|
nexttool: "ca65",
|
||||||
|
Loading…
Reference in New Issue
Block a user