//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #ifndef _AST_H_ #define _AST_H_ class ExprEvalState; class Namespace; class SimObject; class SimGroup; class CodeStream; /// Enable this #define if you are seeing the message "precompile size mismatch" in the console. /// This will help track down which node type is causing the error. It could be /// due to incorrect compiler optimization. //#define DEBUG_AST_NODES enum TypeReq { TypeReqNone, TypeReqUInt, TypeReqFloat, TypeReqString }; enum ExprNodeName { NameExprNode, NameFloatNode, NameIntNode, NameVarNode }; /// Representation of a node for the scripting language parser. /// /// When the scripting language is evaluated, it is turned from a string representation, /// into a parse tree, thence into byte code, which is ultimately interpreted by the VM. /// /// This is the base class for the nodes in the parse tree. There are a great many subclasses, /// each representing a different language construct. struct StmtNode { StmtNode* next; ///< Next entry in parse tree. StmtNode(); virtual ~StmtNode() {} /// @name next Accessors /// @{ /// void append(StmtNode* next); StmtNode* getNext() const { return next; } /// @} /// @name Debug Info /// @{ StringTableEntry dbgFileName; ///< Name of file this node is associated with. S32 dbgLineNumber; ///< Line number this node is associated with. #ifdef DEBUG_AST_NODES virtual String dbgStmtType() const = 0; #endif /// @} /// @name Breaking /// @{ void addBreakLine(CodeStream& codeStream); /// @} /// @name Compilation /// @{ virtual U32 compileStmt(CodeStream& codeStream, U32 ip) = 0; virtual void setPackage(StringTableEntry packageName); /// @} }; /// Helper macro #ifndef DEBUG_AST_NODES # define DBG_STMT_TYPE(s) virtual const char* dbgStmtType() const { return "#s"; } #else # define DBG_STMT_TYPE(s) #endif struct BreakStmtNode : StmtNode { static BreakStmtNode* alloc(S32 lineNumber); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(BreakStmtNode); }; struct ContinueStmtNode : StmtNode { static ContinueStmtNode* alloc(S32 lineNumber); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(ContinueStmtNode); }; /// A mathematical expression. struct ExprNode : StmtNode { ExprNode* optimizedNode; U32 compileStmt(CodeStream& codeStream, U32 ip); virtual U32 compile(CodeStream& codeStream, U32 ip, TypeReq type) = 0; virtual TypeReq getPreferredType() = 0; virtual ExprNodeName getExprNodeNameEnum() const { return NameExprNode; } }; struct ReturnStmtNode : StmtNode { ExprNode* expr; static ReturnStmtNode* alloc(S32 lineNumber, ExprNode* expr); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(ReturnStmtNode); }; struct IfStmtNode : StmtNode { ExprNode* testExpr; StmtNode* ifBlock, * elseBlock; U32 endifOffset; U32 elseOffset; bool integer; bool propagate; static IfStmtNode* alloc(S32 lineNumber, ExprNode* testExpr, StmtNode* ifBlock, StmtNode* elseBlock, bool propagateThrough); void propagateSwitchExpr(ExprNode* left, bool string); ExprNode* getSwitchOR(ExprNode* left, ExprNode* list, bool string); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(IfStmtNode); }; struct LoopStmtNode : StmtNode { ExprNode* testExpr; ExprNode* initExpr; ExprNode* endLoopExpr; StmtNode* loopBlock; bool isDoLoop; U32 breakOffset; U32 continueOffset; U32 loopBlockStartOffset; bool integer; static LoopStmtNode* alloc(S32 lineNumber, ExprNode* testExpr, ExprNode* initExpr, ExprNode* endLoopExpr, StmtNode* loopBlock, bool isDoLoop); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(LoopStmtNode); }; /// A "foreach" statement. struct IterStmtNode : StmtNode { /// Local variable name to use for the container element. StringTableEntry varName; /// Expression evaluating to a SimSet object. ExprNode* containerExpr; /// The statement body. StmtNode* body; /// If true, this is a 'foreach$'. bool isStringIter; /// Bytecode size of body statement. Set by precompileStmt. U32 bodySize; static IterStmtNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter); U32 compileStmt(CodeStream& codeStream, U32 ip); }; /// A binary mathematical expression (ie, left op right). struct BinaryExprNode : ExprNode { S32 op; ExprNode* left; ExprNode* right; }; struct FloatBinaryExprNode : BinaryExprNode { static FloatBinaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); bool optimize(); TypeReq getPreferredType(); DBG_STMT_TYPE(FloatBinaryExprNode); }; struct ConditionalExprNode : ExprNode { ExprNode* testExpr; ExprNode* trueExpr; ExprNode* falseExpr; bool integer; static ConditionalExprNode* alloc(S32 lineNumber, ExprNode* testExpr, ExprNode* trueExpr, ExprNode* falseExpr); virtual U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); virtual TypeReq getPreferredType(); DBG_STMT_TYPE(ConditionalExprNode); }; struct IntBinaryExprNode : BinaryExprNode { TypeReq subType; U32 operand; static IntBinaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right); void getSubTypeOperand(); bool optimize(); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(IntBinaryExprNode); }; struct StreqExprNode : BinaryExprNode { bool eq; static StreqExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right, bool eq); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StreqExprNode); }; struct StrcatExprNode : BinaryExprNode { S32 appendChar; static StrcatExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right, S32 appendChar); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StrcatExprNode); }; struct CommaCatExprNode : BinaryExprNode { static CommaCatExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(CommaCatExprNode); }; struct IntUnaryExprNode : ExprNode { S32 op; ExprNode* expr; bool integer; static IntUnaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* expr); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(IntUnaryExprNode); }; struct FloatUnaryExprNode : ExprNode { S32 op; ExprNode* expr; static FloatUnaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* expr); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(FloatUnaryExprNode); }; struct VarNode : ExprNode { StringTableEntry varName; ExprNode* arrayIndex; static VarNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); virtual ExprNodeName getExprNodeNameEnum() const { return NameVarNode; } DBG_STMT_TYPE(VarNode); }; struct IntNode : ExprNode { S32 value; U32 index; // if it's converted to float/string static IntNode* alloc(S32 lineNumber, S32 value); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); virtual ExprNodeName getExprNodeNameEnum() const { return NameIntNode; } DBG_STMT_TYPE(IntNode); }; struct FloatNode : ExprNode { F64 value; U32 index; static FloatNode* alloc(S32 lineNumber, F64 value); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); virtual ExprNodeName getExprNodeNameEnum() const { return NameFloatNode; } DBG_STMT_TYPE(FloatNode); }; struct StrConstNode : ExprNode { char* str; F64 fVal; U32 index; bool tag; bool doc; // Specifies that this string is a documentation block. static StrConstNode* alloc(S32 lineNumber, const char* str, bool tag, bool doc = false); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StrConstNode); }; struct ConstantNode : ExprNode { StringTableEntry value; F64 fVal; U32 index; static ConstantNode* alloc(S32 lineNumber, StringTableEntry value); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(ConstantNode); }; struct AssignExprNode : ExprNode { StringTableEntry varName; ExprNode* expr; ExprNode* arrayIndex; TypeReq subType; static AssignExprNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssignExprNode); }; struct AssignDecl { S32 lineNumber; S32 token; ExprNode* expr; bool integer; }; struct AssignOpExprNode : ExprNode { StringTableEntry varName; ExprNode* expr; ExprNode* arrayIndex; S32 op; U32 operand; TypeReq subType; static AssignOpExprNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr, S32 op); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssignOpExprNode); }; struct TTagSetStmtNode : StmtNode { StringTableEntry tag; ExprNode* valueExpr; ExprNode* stringExpr; static TTagSetStmtNode* alloc(S32 lineNumber, StringTableEntry tag, ExprNode* valueExpr, ExprNode* stringExpr); U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(TTagSetStmtNode); }; struct TTagDerefNode : ExprNode { ExprNode* expr; static TTagDerefNode* alloc(S32 lineNumber, ExprNode* expr); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(TTagDerefNode); }; struct TTagExprNode : ExprNode { StringTableEntry tag; static TTagExprNode* alloc(S32 lineNumber, StringTableEntry tag); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(TTagExprNode); }; struct FuncCallExprNode : ExprNode { StringTableEntry funcName; StringTableEntry nameSpace; ExprNode* args; U32 callType; enum { FunctionCall, StaticCall, MethodCall, ParentCall }; static FuncCallExprNode* alloc(S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode* args, bool dot); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(FuncCallExprNode); }; struct AssertCallExprNode : ExprNode { ExprNode* testExpr; const char* message; U32 messageIndex; static AssertCallExprNode* alloc(S32 lineNumber, ExprNode* testExpr, const char* message); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssertCallExprNode); }; struct SlotDecl { S32 lineNumber; ExprNode* object; StringTableEntry slotName; ExprNode* array; }; struct SlotAccessNode : ExprNode { ExprNode* objectExpr, * arrayExpr; StringTableEntry slotName; static SlotAccessNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAccessNode); }; struct InternalSlotDecl { S32 lineNumber; ExprNode* object; ExprNode* slotExpr; bool recurse; }; struct InternalSlotAccessNode : ExprNode { ExprNode* objectExpr, * slotExpr; bool recurse; static InternalSlotAccessNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* slotExpr, bool recurse); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(InternalSlotAccessNode); }; struct SlotAssignNode : ExprNode { ExprNode* objectExpr, * arrayExpr; StringTableEntry slotName; ExprNode* valueExpr; U32 typeID; static SlotAssignNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName, ExprNode* valueExpr, U32 typeID = -1); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAssignNode); }; struct SlotAssignOpNode : ExprNode { ExprNode* objectExpr, * arrayExpr; StringTableEntry slotName; S32 op; ExprNode* valueExpr; U32 operand; TypeReq subType; static SlotAssignOpNode* alloc(S32 lineNumber, ExprNode* objectExpr, StringTableEntry slotName, ExprNode* arrayExpr, S32 op, ExprNode* valueExpr); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAssignOpNode); }; struct ObjectDeclNode : ExprNode { ExprNode* classNameExpr; StringTableEntry parentObject; ExprNode* objectNameExpr; ExprNode* argList; SlotAssignNode* slotDecls; ObjectDeclNode* subObjects; bool isDatablock; U32 failOffset; bool isClassNameInternal; bool isSingleton; static ObjectDeclNode* alloc(S32 lineNumber, ExprNode* classNameExpr, ExprNode* objectNameExpr, ExprNode* argList, StringTableEntry parentObject, SlotAssignNode* slotDecls, ObjectDeclNode* subObjects, bool isDatablock, bool classNameInternal, bool isSingleton); U32 precompileSubObject(bool); U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); U32 compileSubObject(CodeStream& codeStream, U32 ip, bool); TypeReq getPreferredType(); DBG_STMT_TYPE(ObjectDeclNode); }; struct ObjectBlockDecl { SlotAssignNode* slots; ObjectDeclNode* decls; }; struct FunctionDeclStmtNode : StmtNode { StringTableEntry fnName; VarNode* args; StmtNode* stmts; StringTableEntry nameSpace; StringTableEntry package; U32 endOffset; U32 argc; static FunctionDeclStmtNode* alloc(S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode* args, StmtNode* stmts); U32 compileStmt(CodeStream& codeStream, U32 ip); void setPackage(StringTableEntry packageName); DBG_STMT_TYPE(FunctionDeclStmtNode); }; extern StmtNode* gStatementList; extern ExprEvalState gEvalState; #endif