module otya.smilebasic.node; import otya.smilebasic.type; import otya.smilebasic.token; import std.container; enum NodeType { Node, Expression, Constant, BinaryOperator, Variable, CallFunction, VoidExpression, UnaryOperator, IndexExpressions, Statements, FunctionBody, Assign, CallFunctionStatement, Print, Label, Goto, If, For, Gosub, Return, End, Break, Continue, Var, DefineVariable, DefineArray, ArrayAssign, DefineFunction, While, Inc, Data, Read, Restore, On, Input, RepeatUntil, Option, Swap, AssignRef, VarRef, XOn, XOff, Exec, Use, Linput, CallSprite, CallBG, } abstract class Node { NodeType type; //式は複数行に渡って描けないのでStatementに置くべき SourceLocation location; } abstract class Expression : Node { } class Constant : Expression { TokenValue value; this(TokenValue v, SourceLocation loc) { super.location = loc; this.type = NodeType.Constant; this.value = v; } } class BinaryOperator : Expression { Expression item1; TokenType operator; Expression item2; this(BinaryOperator bop, SourceLocation loc) { super.location = loc; this.type = NodeType.BinaryOperator; this.item1 = bop.item1; this.operator = bop.operator; this.item2 = bop.item2; } this(Expression i1, SourceLocation loc) { super.location = loc; this.type = NodeType.BinaryOperator; this.item1 = i1; } this(Expression i1, TokenType o, Expression i2, SourceLocation loc) { super.location = loc; this.type = NodeType.BinaryOperator; this.item1 = i1; this.operator = o; this.item2 = i2; } } class UnaryOperator : Expression { TokenType operator; Expression item; this(TokenType o, Expression i, SourceLocation loc) { super.location = loc; this.type = NodeType.UnaryOperator; this.operator = o; this.item = i; } } class Variable : Expression { wstring name; this(wstring n, SourceLocation loc) { super.location = loc; this.type = NodeType.Variable; this.name = n; } } class CallFunction : Expression { wstring name; Expression[] args; this(wstring n, SourceLocation loc) { super.location = loc; this.type = NodeType.CallFunction; this.name = n; args = new Expression[0]; } void addArg(Expression arg) { args ~= arg; } } class VoidExpression : Expression { this(SourceLocation loc) { super.location = loc; this.type = NodeType.VoidExpression; } } abstract class Statement : Node { static Statement NOP = null; } class Statements : Statement { Statement[] statements; this(SourceLocation loc) { super.location = loc; this.type = NodeType.Statements; statements = new Statement[0]; } void addStatement(Statement statement) { statements ~= statement; } } enum PrintArgumentType { Expression,//exp Line, Tab,//, } /* *;は基本無視 */ struct PrintArgument { PrintArgumentType type; Expression expression; this(PrintArgumentType type) { this.type = type; this.expression = null; } this(PrintArgumentType type, Expression expression) { this.type = type; this.expression = expression; } } /* *PRINTは関数ではないしmkIIと違って必ず:がいる *関数と違ってFUNC(,,,)のような記述はエラー *と言っても3.2で上の記述もエラーになりうる */ class Print : Statement { PrintArgument[] args; this(SourceLocation loc) { super.location = loc; this.type = NodeType.Print; args = new PrintArgument[0]; } void addArgument(Expression expression) { args ~= PrintArgument(PrintArgumentType.Expression, expression); } void addTab() { args ~= PrintArgument(PrintArgumentType.Tab); } void addLine() { args ~= PrintArgument(PrintArgumentType.Line); } } class Assign : Statement { wstring name; Expression expression; this(wstring name, Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Assign; this.name = name; this.expression = expr; } } class AssignRef : Statement { Expression left; Expression expression; this(Expression left, Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.AssignRef; this.left = left; this.expression = expr; } } class Label : Statement { wstring label; this(wstring name, SourceLocation loc) { super.location = loc; this.type = NodeType.Label; this.label = name; } } class Goto : Statement { wstring label; this(wstring name, SourceLocation loc) { super.location = loc; this.type = NodeType.Goto; this.label = name; } Expression labelexpr; this(Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Goto; this.labelexpr = expr; } } class If : Statement { import std.typecons; Expression condition; Statements then; Statements else_; Tuple!(Statements, Expression)[] elseif; this(Expression condition, Statements t, Statements e, Tuple!(Statements, Expression)[] elif, SourceLocation loc) { super.location = loc; this.type = NodeType.If; this.condition = condition; this.then = t; this.else_ = e; this.elseif = elif; } bool hasElse() { return !(else_ is null) && else_.statements.length != 0; } bool hasElseif() { return !(elseif is null) && elseif.length != 0; } } class For : Statement { Assign initExpression; Expression toExpression; Expression stepExpression; Statements statements; this(Assign assign, Expression toExpression, Expression stepExpression, Statements statements, SourceLocation loc) { super.location = loc; this.type = NodeType.For; this.initExpression = assign; this.toExpression = toExpression; this.stepExpression = stepExpression; this.statements = statements; } this(Assign assign, Expression toExpression, Statements statements, SourceLocation loc) { super.location = loc; this.type = NodeType.For; this.initExpression = assign; this.toExpression = toExpression; this.stepExpression = null; this.statements = statements; } } class Gosub : Statement { wstring label; this(wstring name, SourceLocation loc) { super.location = loc; this.type = NodeType.Gosub; this.label = name; } Expression labelexpr; this(Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Gosub; this.labelexpr = expr; } } class Return : Statement { Expression expression; this(Expression expression, SourceLocation loc) { super.location = loc; this.type = NodeType.Return; this.expression = expression; } } class End : Statement { this(SourceLocation loc) { super.location = loc; this.type = NodeType.End; } } class Break : Statement { this(SourceLocation loc) { super.location = loc; this.type = NodeType.Break; } } class Continue : Statement { this(SourceLocation loc) { super.location = loc; this.type = NodeType.Continue; } } class Var : Statement { Statement[] define; this(SourceLocation loc) { super.location = loc; this.type = NodeType.Var; this.define = new Statement[0]; } void addDefineVar(DefineVariable dv) { this.define ~= dv; } void addDefineArray(DefineArray da) { this.define ~= da; } } class DefineVariable : Statement { wstring name; Expression expression; this(wstring name, Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.DefineVariable; this.name = name; this.expression = expr; } } class DefineArray : Statement { wstring name; IndexExpressions dim; this(wstring name, IndexExpressions dim, SourceLocation loc) { super.location = loc; this.type = NodeType.DefineArray; this.name = name; this.dim = dim; } } class IndexExpressions : Expression { Expression[] expressions; this(SourceLocation loc) { super.location = loc; this.type = NodeType.IndexExpressions; this.expressions = new Expression[0]; } void addExpression(Expression expr) { this.expressions ~= expr; } } class ArrayAssign : Statement { wstring name; IndexExpressions indexExpression; Expression assignExpression; this(wstring name, IndexExpressions expr, Expression assign, SourceLocation loc) { super.location = loc; this.type = NodeType.ArrayAssign; this.name = name; this.indexExpression = expr; this.assignExpression = assign; } } class DefineFunction : Statement { wstring[] arguments; wstring[] outArguments; wstring name; Statements functionBody; bool returnExpr; bool isCommon; this(wstring name, bool returnExpr, bool isCommon, SourceLocation loc) { super.location = loc; this.type = NodeType.DefineFunction; this.name = name; this.returnExpr = returnExpr; this.isCommon = isCommon; } this(wstring name, bool isCommon, SourceLocation loc) { super.location = loc; this.type = NodeType.DefineFunction; this.name = name; this.returnExpr = false; this.isCommon = isCommon; } void addArgument(wstring name) { this.arguments ~= name; } void addOutArgument(wstring name) { this.outArguments ~= name; } } class CallFunctionStatement : Statement { wstring name; Expression[] args; Expression[] outVariable; this(wstring n, SourceLocation loc) { super.location = loc; this.type = NodeType.CallFunctionStatement; this.name = n; args = new Expression[0]; } void addArg(Expression arg) { args ~= arg; } void addOut(Expression var) { outVariable ~= var; } } class While : Statement { Expression condExpression; Statements statements; this(Expression condExpression, Statements statements, SourceLocation loc) { super.location = loc; this.type = NodeType.While; this.condExpression = condExpression; this.statements = statements; } } class Inc : Statement { Expression name; Expression expression; this(Expression name, Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Inc; this.name = name; this.expression = expr; } } class Data : Statement { TokenValue[] data; this(SourceLocation loc) { super.location = loc; this.type = NodeType.Data; this.data = new TokenValue[0]; } void addData(TokenValue v) { data ~= v; } } class Read : Statement { Expression[] variables; this(SourceLocation loc) { super.location = loc; this.type = NodeType.Read; } void addVariable(Expression lvalue) { variables ~= lvalue; } } class Restore : Statement { Expression label; this(Expression label, SourceLocation loc) { super.location = loc; this.label = label; this.type = NodeType.Restore; } } class On : Statement { Expression condition; bool isGosub; wstring[] labels; this(Expression expr, bool isgosub, SourceLocation loc) { super.location = loc; this.condition = expr; this.isGosub = isgosub; this.labels = new wstring[0]; this.type = NodeType.On; } void addLabel(wstring label) { this.labels ~= label; } } class Input : Statement { Expression message; bool question; Expression[] variables; this(Expression message, bool question, SourceLocation loc) { super.location = loc; this.message = message; this.question = question; this.variables = new Expression[0]; this.type = NodeType.Input; } void addVariable(Expression lvalue) { variables ~= lvalue; } } class RepeatUntil : Statement { Expression condExpression; Statements statements; this(Expression condExpression, Statements statements, SourceLocation loc) { super.location = loc; this.type = NodeType.RepeatUntil; this.condExpression = condExpression; this.statements = statements; } } class Option : Statement { wstring argument; this(wstring arg, SourceLocation loc) { super.location = loc; this.type = NodeType.Option; argument = arg; } } class Swap : Statement { Expression item1; Expression item2; this(Expression item1, Expression item2, SourceLocation loc) { super.location = loc; this.type = NodeType.Swap; this.item1 = item1; this.item2 = item2; } } class VarRef : Expression { Expression expression; this(Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.VarRef; this.expression = expr; } } class XOn : Statement { wstring func; this(wstring func, SourceLocation loc) { super.location = loc; this.type = NodeType.XOn; this.func = func; } } class XOff : Statement { wstring func; this(wstring func, SourceLocation loc) { super.location = loc; this.type = NodeType.XOff; this.func = func; } } class Exec : Statement { Expression expression; this(Expression e, SourceLocation loc) { super.location = loc; expression = e; this.type = NodeType.Exec; } } class Use : Statement { Expression expression; this(Expression e, SourceLocation loc) { super.location = loc; expression = e; this.type = NodeType.Use; } } class Linput : Statement { bool hasGuide; Expression guide; Expression expression; this(Expression guide, Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Linput; this.hasGuide = true; this.guide = guide; this.expression = expr; } this(Expression expr, SourceLocation loc) { super.location = loc; this.type = NodeType.Linput; this.hasGuide = false; this.expression = expr; } } class CallSprite : Statement { this(SourceLocation loc) { super.location = loc; this.type = NodeType.CallSprite; } } class CallBG : Statement { this(SourceLocation loc) { super.location = loc; this.type = NodeType.CallBG; } }