mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-13 06:29:57 +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 { SourceLocated, SourceLocation } from "../workertypes";
|
||||
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 {
|
||||
Ellipsis = 'ellipsis',
|
||||
@ -349,10 +349,9 @@ export class ECSCompiler extends Tokenizer {
|
||||
tempbytes = this.parseIntegerConstant();
|
||||
}
|
||||
let system: System = { name, tempbytes, actions: [] };
|
||||
let context: ActionContext = { scope: null, system };
|
||||
let text = this.parseCode(context);
|
||||
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);
|
||||
return system;
|
||||
}
|
||||
@ -384,13 +383,11 @@ export class ECSCompiler extends Tokenizer {
|
||||
if (this.ifToken('fit')) {
|
||||
fitbytes = this.parseIntegerConstant();
|
||||
}
|
||||
let context: ActionContext = { scope: null, system };
|
||||
// parse --- code ---
|
||||
let text = this.parseCode(context);
|
||||
let direction = undefined;
|
||||
if (modifiers['asc']) direction = 'asc';
|
||||
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;
|
||||
return action as ActionWithJoin;
|
||||
}
|
||||
@ -441,7 +438,7 @@ export class ECSCompiler extends Tokenizer {
|
||||
return this.parseList(this.parseEventName, ",");
|
||||
}
|
||||
|
||||
parseCode(context: ActionContext): string { // TODOActionNode[] {
|
||||
parseCode(): string { // TODOActionNode[] {
|
||||
// TODO: add $loc
|
||||
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||
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);
|
||||
code = lines.join('\n');
|
||||
|
||||
let acomp = new ECSActionCompiler(context);
|
||||
let nodes = acomp.parseFile(code, this.path);
|
||||
//let acomp = new ECSActionCompiler(context);
|
||||
//let nodes = acomp.parseFile(code, this.path);
|
||||
// TODO: return nodes
|
||||
return code;
|
||||
}
|
||||
@ -694,8 +691,8 @@ export class ECSCompiler extends Tokenizer {
|
||||
}
|
||||
var opfn = getOperator(op.str).f;
|
||||
// use logical operators instead of bitwise?
|
||||
if (op.str == 'AND') opfn = 'land';
|
||||
if (op.str == 'OR') opfn = 'lor';
|
||||
if (op.str == 'and') opfn = 'land';
|
||||
if (op.str == 'or') opfn = 'lor';
|
||||
var valtype = this.exprTypeForOp(opfn, left, right, op);
|
||||
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 };
|
||||
return { valtype, value };
|
||||
case TokenType.Ident:
|
||||
if (tok.str == 'NOT') {
|
||||
if (tok.str == 'not') {
|
||||
let expr = this.parsePrimary();
|
||||
let valtype : IntType = { dtype: 'int', lo: 0, hi: 1 };
|
||||
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.`);
|
||||
let atypes = this.em.archetypesMatching({ include: [component] })
|
||||
let entities = this.currentScope.entitiesMatching(atypes);
|
||||
return { entities, field } as EntitySetField;
|
||||
return { entities, field } as EntityFieldOp;
|
||||
}
|
||||
// entity.field
|
||||
if (this.ifToken('.')) {
|
||||
@ -764,7 +761,7 @@ export class ECSCompiler extends Tokenizer {
|
||||
let field = component.fields.find(f => f.name == ftok.str);
|
||||
if (!field) throw this.compileError(`There is no "${ftok.str}" field in this entity.`);
|
||||
let entities = [entity];
|
||||
return { entities, field } as EntitySetField;
|
||||
return { entities, field } as EntityFieldOp;
|
||||
}
|
||||
let args : Expr[] = [];
|
||||
if (this.ifToken('(')) {
|
||||
@ -796,6 +793,22 @@ export class ECSCompiler extends Tokenizer {
|
||||
parseExprList(): Expr[] {
|
||||
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];
|
||||
|
||||
// TODO?
|
||||
export interface ActionContext {
|
||||
system: System
|
||||
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 {
|
||||
select: SelectType;
|
||||
event: string;
|
||||
text: string;
|
||||
expr: Statement;
|
||||
critical?: boolean;
|
||||
fitbytes?: number;
|
||||
}
|
||||
@ -204,18 +195,17 @@ export interface ForwardRef extends SourceLocated {
|
||||
token: Token
|
||||
}
|
||||
|
||||
export type LExpr = IndOp | EntitySetField;
|
||||
export type ExprTypes = BinOp | UnOp | Literal | ForwardRef | LExpr;
|
||||
export type Expr = ExprTypes; // & SourceLocated;
|
||||
export type LExpr = IndOp | EntityFieldOp;
|
||||
export type Statement = InlineCode | BlockExpr;
|
||||
export type Expr = BinOp | UnOp | Literal | ForwardRef | LExpr | Statement;
|
||||
export type Opcode = string;
|
||||
export type Value = DataValue;
|
||||
|
||||
export interface ExprBase extends SourceLocated {
|
||||
valtype: DataType;
|
||||
}
|
||||
|
||||
export interface Literal extends ExprBase {
|
||||
value: Value;
|
||||
value: DataValue;
|
||||
}
|
||||
|
||||
export interface LiteralInt extends Literal {
|
||||
@ -239,11 +229,34 @@ export interface IndOp extends ExprBase {
|
||||
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[];
|
||||
field: DataField;
|
||||
}
|
||||
|
||||
export interface EntityContextOp extends ExprBase {
|
||||
entities: Entity[];
|
||||
}
|
||||
|
||||
export interface InlineCode extends ExprBase {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export function isLiteral(arg: Expr): arg is Literal {
|
||||
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 {
|
||||
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
|
||||
@ -796,7 +815,7 @@ class ActionEval {
|
||||
return code;
|
||||
}
|
||||
private getCodeAndProps(action: Action) {
|
||||
let code = action.text;
|
||||
let code = this.exprToCode(action.expr);
|
||||
let props: { [name: string]: string } = {};
|
||||
if (action.select != 'once') {
|
||||
// TODO: detect cycles
|
||||
@ -1125,6 +1144,15 @@ class ActionEval {
|
||||
if (code.split('\n ').length >= 4) return true; // TODO: :^/
|
||||
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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user