mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-09-27 08:54:48 +00:00
ecs: block statement expr
This commit is contained in:
parent
05965397fd
commit
fc79cf9b0f
@ -2,7 +2,7 @@
|
|||||||
import { mergeLocs, Token, Tokenizer, TokenType } from "../tokenizer";
|
import { mergeLocs, Token, Tokenizer, TokenType } from "../tokenizer";
|
||||||
import { SourceLocated, SourceLocation } from "../workertypes";
|
import { SourceLocated, SourceLocation } from "../workertypes";
|
||||||
import { newDecoder } from "./decoder";
|
import { newDecoder } from "./decoder";
|
||||||
import { Action, ActionContext, ActionNode, ActionWithJoin, ArrayType, CodeLiteralNode, CodePlaceholderNode, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System, SystemInstance, SystemInstanceParameters, ComponentFieldPair, Expr, ExprBase, ForwardRef, isLiteral, EntitySetField, LExpr } from "./ecs";
|
import { Action, ActionContext, ActionNode, ActionWithJoin, ArrayType, CodeLiteralNode, CodePlaceholderNode, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System, SystemInstance, SystemInstanceParameters, ComponentFieldPair, Expr, ExprBase, ForwardRef, isLiteral, EntityFieldOp, LExpr, Statement } from "./ecs";
|
||||||
|
|
||||||
export enum ECSTokenType {
|
export enum ECSTokenType {
|
||||||
Ellipsis = 'ellipsis',
|
Ellipsis = 'ellipsis',
|
||||||
@ -349,10 +349,9 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
tempbytes = this.parseIntegerConstant();
|
tempbytes = this.parseIntegerConstant();
|
||||||
}
|
}
|
||||||
let system: System = { name, tempbytes, actions: [] };
|
let system: System = { name, tempbytes, actions: [] };
|
||||||
let context: ActionContext = { scope: null, system };
|
|
||||||
let text = this.parseCode(context);
|
|
||||||
let select: SelectType = 'once';
|
let select: SelectType = 'once';
|
||||||
let action: Action = { text, event: name, select };
|
let expr = this.parseBlockStatement();
|
||||||
|
let action: Action = { expr, event: name, select };
|
||||||
system.actions.push(action);
|
system.actions.push(action);
|
||||||
return system;
|
return system;
|
||||||
}
|
}
|
||||||
@ -384,13 +383,11 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
if (this.ifToken('fit')) {
|
if (this.ifToken('fit')) {
|
||||||
fitbytes = this.parseIntegerConstant();
|
fitbytes = this.parseIntegerConstant();
|
||||||
}
|
}
|
||||||
let context: ActionContext = { scope: null, system };
|
|
||||||
// parse --- code ---
|
|
||||||
let text = this.parseCode(context);
|
|
||||||
let direction = undefined;
|
let direction = undefined;
|
||||||
if (modifiers['asc']) direction = 'asc';
|
if (modifiers['asc']) direction = 'asc';
|
||||||
else if (modifiers['desc']) direction = 'desc';
|
else if (modifiers['desc']) direction = 'desc';
|
||||||
let action = { text, event, query, join, select, direction, fitbytes };
|
let expr = this.parseBlockStatement();
|
||||||
|
let action = { expr, event, query, join, select, direction, fitbytes };
|
||||||
if (modifiers['critical']) (action as ActionWithJoin).critical = true;
|
if (modifiers['critical']) (action as ActionWithJoin).critical = true;
|
||||||
return action as ActionWithJoin;
|
return action as ActionWithJoin;
|
||||||
}
|
}
|
||||||
@ -441,7 +438,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
return this.parseList(this.parseEventName, ",");
|
return this.parseList(this.parseEventName, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
parseCode(context: ActionContext): string { // TODOActionNode[] {
|
parseCode(): string { // TODOActionNode[] {
|
||||||
// TODO: add $loc
|
// TODO: add $loc
|
||||||
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||||
let code = tok.str.substring(3, tok.str.length - 3);
|
let code = tok.str.substring(3, tok.str.length - 3);
|
||||||
@ -450,8 +447,8 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
if (this.includeDebugInfo) this.addDebugInfo(lines, tok.$loc.line);
|
if (this.includeDebugInfo) this.addDebugInfo(lines, tok.$loc.line);
|
||||||
code = lines.join('\n');
|
code = lines.join('\n');
|
||||||
|
|
||||||
let acomp = new ECSActionCompiler(context);
|
//let acomp = new ECSActionCompiler(context);
|
||||||
let nodes = acomp.parseFile(code, this.path);
|
//let nodes = acomp.parseFile(code, this.path);
|
||||||
// TODO: return nodes
|
// TODO: return nodes
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@ -694,8 +691,8 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
}
|
}
|
||||||
var opfn = getOperator(op.str).f;
|
var opfn = getOperator(op.str).f;
|
||||||
// use logical operators instead of bitwise?
|
// use logical operators instead of bitwise?
|
||||||
if (op.str == 'AND') opfn = 'land';
|
if (op.str == 'and') opfn = 'land';
|
||||||
if (op.str == 'OR') opfn = 'lor';
|
if (op.str == 'or') opfn = 'lor';
|
||||||
var valtype = this.exprTypeForOp(opfn, left, right, op);
|
var valtype = this.exprTypeForOp(opfn, left, right, op);
|
||||||
left = { valtype:valtype, op:opfn, left: left, right: right };
|
left = { valtype:valtype, op:opfn, left: left, right: right };
|
||||||
}
|
}
|
||||||
@ -710,7 +707,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let valtype : IntType = { dtype: 'int', lo: value, hi: value };
|
let valtype : IntType = { dtype: 'int', lo: value, hi: value };
|
||||||
return { valtype, value };
|
return { valtype, value };
|
||||||
case TokenType.Ident:
|
case TokenType.Ident:
|
||||||
if (tok.str == 'NOT') {
|
if (tok.str == 'not') {
|
||||||
let expr = this.parsePrimary();
|
let expr = this.parsePrimary();
|
||||||
let valtype : IntType = { dtype: 'int', lo: 0, hi: 1 };
|
let valtype : IntType = { dtype: 'int', lo: 0, hi: 1 };
|
||||||
return { valtype, op: 'lnot', expr: expr };
|
return { valtype, op: 'lnot', expr: expr };
|
||||||
@ -752,7 +749,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
if (!this.currentScope) throw this.compileError(`This operation only works inside of a scope.`);
|
if (!this.currentScope) throw this.compileError(`This operation only works inside of a scope.`);
|
||||||
let atypes = this.em.archetypesMatching({ include: [component] })
|
let atypes = this.em.archetypesMatching({ include: [component] })
|
||||||
let entities = this.currentScope.entitiesMatching(atypes);
|
let entities = this.currentScope.entitiesMatching(atypes);
|
||||||
return { entities, field } as EntitySetField;
|
return { entities, field } as EntityFieldOp;
|
||||||
}
|
}
|
||||||
// entity.field
|
// entity.field
|
||||||
if (this.ifToken('.')) {
|
if (this.ifToken('.')) {
|
||||||
@ -764,7 +761,7 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
let field = component.fields.find(f => f.name == ftok.str);
|
let field = component.fields.find(f => f.name == ftok.str);
|
||||||
if (!field) throw this.compileError(`There is no "${ftok.str}" field in this entity.`);
|
if (!field) throw this.compileError(`There is no "${ftok.str}" field in this entity.`);
|
||||||
let entities = [entity];
|
let entities = [entity];
|
||||||
return { entities, field } as EntitySetField;
|
return { entities, field } as EntityFieldOp;
|
||||||
}
|
}
|
||||||
let args : Expr[] = [];
|
let args : Expr[] = [];
|
||||||
if (this.ifToken('(')) {
|
if (this.ifToken('(')) {
|
||||||
@ -796,6 +793,22 @@ export class ECSCompiler extends Tokenizer {
|
|||||||
parseExprList(): Expr[] {
|
parseExprList(): Expr[] {
|
||||||
return this.parseList(this.parseExpr, ',');
|
return this.parseList(this.parseExpr, ',');
|
||||||
}
|
}
|
||||||
|
parseBlockStatement(): Statement {
|
||||||
|
let valtype : IntType = { dtype:'int', lo:0, hi: 0 }
|
||||||
|
if (this.peekToken().type == ECSTokenType.CodeFragment) {
|
||||||
|
return { valtype, code: this.parseCode() };
|
||||||
|
}
|
||||||
|
let cmd = this.expectTokens(['end','begin']);
|
||||||
|
if (cmd.str == 'begin') {
|
||||||
|
let stmts = [];
|
||||||
|
while (this.peekToken().str != 'end') {
|
||||||
|
stmts.push(this.parseBlockStatement());
|
||||||
|
}
|
||||||
|
this.expectToken('end');
|
||||||
|
return { valtype, stmts };
|
||||||
|
}
|
||||||
|
throw this.internalError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -78,6 +78,7 @@ export const SELECT_TYPE = ['once', 'foreach', 'join', 'with', 'if', 'select', '
|
|||||||
|
|
||||||
export type SelectType = typeof SELECT_TYPE[number];
|
export type SelectType = typeof SELECT_TYPE[number];
|
||||||
|
|
||||||
|
// TODO?
|
||||||
export interface ActionContext {
|
export interface ActionContext {
|
||||||
system: System
|
system: System
|
||||||
scope: EntityScope | null
|
scope: EntityScope | null
|
||||||
@ -112,20 +113,10 @@ export class CodePlaceholderNode extends ActionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class QueryNode extends ActionNode {
|
|
||||||
}
|
|
||||||
|
|
||||||
class WrapperNode extends ActionNode {
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoopNode extends ActionNode {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface ActionBase extends SourceLocated {
|
export interface ActionBase extends SourceLocated {
|
||||||
select: SelectType;
|
select: SelectType;
|
||||||
event: string;
|
event: string;
|
||||||
text: string;
|
expr: Statement;
|
||||||
critical?: boolean;
|
critical?: boolean;
|
||||||
fitbytes?: number;
|
fitbytes?: number;
|
||||||
}
|
}
|
||||||
@ -204,18 +195,17 @@ export interface ForwardRef extends SourceLocated {
|
|||||||
token: Token
|
token: Token
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LExpr = IndOp | EntitySetField;
|
export type LExpr = IndOp | EntityFieldOp;
|
||||||
export type ExprTypes = BinOp | UnOp | Literal | ForwardRef | LExpr;
|
export type Statement = InlineCode | BlockExpr;
|
||||||
export type Expr = ExprTypes; // & SourceLocated;
|
export type Expr = BinOp | UnOp | Literal | ForwardRef | LExpr | Statement;
|
||||||
export type Opcode = string;
|
export type Opcode = string;
|
||||||
export type Value = DataValue;
|
|
||||||
|
|
||||||
export interface ExprBase extends SourceLocated {
|
export interface ExprBase extends SourceLocated {
|
||||||
valtype: DataType;
|
valtype: DataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Literal extends ExprBase {
|
export interface Literal extends ExprBase {
|
||||||
value: Value;
|
value: DataValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LiteralInt extends Literal {
|
export interface LiteralInt extends Literal {
|
||||||
@ -239,11 +229,34 @@ export interface IndOp extends ExprBase {
|
|||||||
args: Expr[];
|
args: Expr[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntitySetField extends ExprBase {
|
export interface CondOp extends ExprBase {
|
||||||
|
cond: Expr;
|
||||||
|
iftrue?: Expr;
|
||||||
|
iffalse?: Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlockExpr extends ExprBase {
|
||||||
|
loop?: boolean;
|
||||||
|
stmts: Expr[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BranchOp extends ExprBase {
|
||||||
|
branch: BlockExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityFieldOp extends ExprBase {
|
||||||
entities: Entity[];
|
entities: Entity[];
|
||||||
field: DataField;
|
field: DataField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EntityContextOp extends ExprBase {
|
||||||
|
entities: Entity[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InlineCode extends ExprBase {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
export function isLiteral(arg: Expr): arg is Literal {
|
export function isLiteral(arg: Expr): arg is Literal {
|
||||||
return (arg as any).value != null;
|
return (arg as any).value != null;
|
||||||
}
|
}
|
||||||
@ -259,6 +272,12 @@ export function isBinOp(arg: Expr): arg is BinOp {
|
|||||||
export function isUnOp(arg: Expr): arg is UnOp {
|
export function isUnOp(arg: Expr): arg is UnOp {
|
||||||
return (arg as any).op != null && (arg as any).expr != null;
|
return (arg as any).op != null && (arg as any).expr != null;
|
||||||
}
|
}
|
||||||
|
export function isBlockStmt(arg: Expr): arg is BlockExpr {
|
||||||
|
return (arg as any).stmts != null;
|
||||||
|
}
|
||||||
|
export function isInlineCode(arg: Expr): arg is InlineCode {
|
||||||
|
return (arg as any).code != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// DIALECT
|
/// DIALECT
|
||||||
@ -796,7 +815,7 @@ class ActionEval {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
private getCodeAndProps(action: Action) {
|
private getCodeAndProps(action: Action) {
|
||||||
let code = action.text;
|
let code = this.exprToCode(action.expr);
|
||||||
let props: { [name: string]: string } = {};
|
let props: { [name: string]: string } = {};
|
||||||
if (action.select != 'once') {
|
if (action.select != 'once') {
|
||||||
// TODO: detect cycles
|
// TODO: detect cycles
|
||||||
@ -1125,6 +1144,15 @@ class ActionEval {
|
|||||||
if (code.split('\n ').length >= 4) return true; // TODO: :^/
|
if (code.split('\n ').length >= 4) return true; // TODO: :^/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
exprToCode(expr: Expr) : string {
|
||||||
|
if (isBlockStmt(expr)) {
|
||||||
|
return expr.stmts.map(node => this.exprToCode(node)).join('\n');
|
||||||
|
}
|
||||||
|
if (isInlineCode(expr)) {
|
||||||
|
return expr.code;
|
||||||
|
}
|
||||||
|
throw new ECSError(`cannot convert expression to code`, expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EventCodeStats {
|
class EventCodeStats {
|
||||||
|
Loading…
Reference in New Issue
Block a user