/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #ifndef LINGODEC_AST_H #define LINGODEC_AST_H #include "common/array.h" #include "common/ptr.h" #include "common/str.h" #include "common/util.h" #include "./enums.h" namespace LingoDec { struct CaseLabelNode; struct Handler; struct LoopNode; struct Node; struct RepeatWithInStmtNode; /* Datum */ struct Datum { DatumType type; int i = -1; double f = 0.0f; Common::String s; Common::Array> l; Datum() { type = kDatumVoid; } Datum(int val) { type = kDatumInt; i = val; } Datum(double val) { type = kDatumFloat; f = val; } Datum(DatumType t, Common::String val) { type = t; s = val; } Datum(DatumType t, Common::Array> val) { type = t; l = val; } int toInt(); }; class NodeVisitor; /* Node */ struct Node { NodeType type; bool isExpression; bool isStatement; bool isLabel; bool isLoop; Node *parent; uint32 _startOffset; uint32 _endOffset; Node(NodeType t, uint32 offset) : type(t), isExpression(false), isStatement(false), isLabel(false), isLoop(false), parent(nullptr), _startOffset(offset), _endOffset(offset) {} virtual ~Node() {} virtual void accept(NodeVisitor& visitor) const = 0; virtual Common::SharedPtr getValue(); Node *ancestorStatement(); LoopNode *ancestorLoop(); virtual bool hasSpaces(bool dot); }; /* ExprNode */ struct ExprNode : Node { ExprNode(NodeType t, uint32 offset) : Node(t, offset) { isExpression = true; } }; /* StmtNode */ struct StmtNode : Node { StmtNode(NodeType t, uint32 offset) : Node(t, offset) { isStatement = true; } }; /* LabelNode */ struct LabelNode : Node { LabelNode(NodeType t, uint32 offset) : Node(t, offset) { isLabel = true; } }; /* LoopNode */ struct LoopNode : StmtNode { uint32 startIndex; LoopNode(NodeType t, uint32 startIndex_, uint32 offset) : StmtNode(t, offset), startIndex(startIndex_) { isLoop = true; } }; /* ErrorNode */ struct ErrorNode : ExprNode { explicit ErrorNode(uint32 offset) : ExprNode(kErrorNode, offset) {} bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* CommentNode */ struct CommentNode : Node { Common::String text; CommentNode(uint32 offset, Common::String t) : Node(kCommentNode, offset), text(t) {} void accept(NodeVisitor &visitor) const override; }; /* LiteralNode */ struct LiteralNode : ExprNode { Common::SharedPtr value; LiteralNode(uint32 offset, Common::SharedPtr d) : ExprNode(kLiteralNode, offset) { value = Common::move(d); } Common::SharedPtr getValue() override; bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* BlockNode */ struct BlockNode : Node { Common::Array> children; // for use during translation: uint32 endPos; CaseLabelNode *currentCaseLabel = nullptr; explicit BlockNode(uint32 offset) : Node(kBlockNode, offset), endPos(Common::String::npos) {} void addChild(Common::SharedPtr child); void accept(NodeVisitor &visitor) const override; }; /* HandlerNode */ struct HandlerNode : Node { Handler *handler; Common::SharedPtr block; HandlerNode(uint32 offset, Handler *h) : Node(kHandlerNode, offset), handler(h) { block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* ExitStmtNode */ struct ExitStmtNode : StmtNode { explicit ExitStmtNode(uint32 offset) : StmtNode(kExitStmtNode, offset) {} void accept(NodeVisitor &visitor) const override; }; /* InverseOpNode */ struct InverseOpNode : ExprNode { Common::SharedPtr operand; InverseOpNode(uint32 offset, Common::SharedPtr o) : ExprNode(kInverseOpNode, offset) { operand = Common::move(o); operand->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* NotOpNode */ struct NotOpNode : ExprNode { Common::SharedPtr operand; NotOpNode(uint32 offset, Common::SharedPtr o) : ExprNode(kNotOpNode, offset) { operand = Common::move(o); operand->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* BinaryOpNode */ struct BinaryOpNode : ExprNode { OpCode opcode; Common::SharedPtr left; Common::SharedPtr right; BinaryOpNode(uint32 offset, OpCode op, Common::SharedPtr a, Common::SharedPtr b) : ExprNode(kBinaryOpNode, offset), opcode(op) { left = Common::move(a); left->parent = this; right = Common::move(b); right->parent = this; } virtual unsigned int getPrecedence() const; void accept(NodeVisitor &visitor) const override; }; /* ChunkExprNode */ struct ChunkExprNode : ExprNode { ChunkExprType type; Common::SharedPtr first; Common::SharedPtr last; Common::SharedPtr string; ChunkExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr a, Common::SharedPtr b, Common::SharedPtr s) : ExprNode(kChunkExprNode, offset), type(t) { first = Common::move(a); first->parent = this; last = Common::move(b); last->parent = this; string = Common::move(s); string->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* ChunkHiliteStmtNode */ struct ChunkHiliteStmtNode : StmtNode { Common::SharedPtr chunk; ChunkHiliteStmtNode(uint32 offset, Common::SharedPtr c) : StmtNode(kChunkHiliteStmtNode, offset) { chunk = Common::move(c); chunk->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* ChunkDeleteStmtNode */ struct ChunkDeleteStmtNode : StmtNode { Common::SharedPtr chunk; ChunkDeleteStmtNode(uint32 offset, Common::SharedPtr c) : StmtNode(kChunkDeleteStmtNode, offset) { chunk = Common::move(c); chunk->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* SpriteIntersectsExprNode */ struct SpriteIntersectsExprNode : ExprNode { Common::SharedPtr firstSprite; Common::SharedPtr secondSprite; SpriteIntersectsExprNode(uint32 offset, Common::SharedPtr a, Common::SharedPtr b) : ExprNode(kSpriteIntersectsExprNode, offset) { firstSprite = Common::move(a); firstSprite->parent = this; secondSprite = Common::move(b); secondSprite->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* SpriteWithinExprNode */ struct SpriteWithinExprNode : ExprNode { Common::SharedPtr firstSprite; Common::SharedPtr secondSprite; SpriteWithinExprNode(uint32 offset, Common::SharedPtr a, Common::SharedPtr b) : ExprNode(kSpriteWithinExprNode, offset) { firstSprite = Common::move(a); firstSprite->parent = this; secondSprite = Common::move(b); secondSprite->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* MemberExprNode */ struct MemberExprNode : ExprNode { Common::String type; Common::SharedPtr memberID; Common::SharedPtr castID; MemberExprNode(uint32 offset, Common::String type_, Common::SharedPtr memberID_, Common::SharedPtr castID_) : ExprNode(kMemberExprNode, offset), type(type_) { this->memberID = Common::move(memberID_); this->memberID->parent = this; if (castID_) { this->castID = Common::move(castID_); this->castID->parent = this; } } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* VarNode */ struct VarNode : ExprNode { Common::String varName; VarNode(uint32 offset, Common::String v) : ExprNode(kVarNode, offset), varName(v) {} bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* AssignmentStmtNode */ struct AssignmentStmtNode : StmtNode { Common::SharedPtr variable; Common::SharedPtr value; bool forceVerbose; AssignmentStmtNode(uint32 offset, Common::SharedPtr var, Common::SharedPtr val, bool forceVerbose_ = false) : StmtNode(kAssignmentStmtNode, offset), forceVerbose(forceVerbose_) { variable = Common::move(var); variable->parent = this; value = Common::move(val); value->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* IfStmtNode */ struct IfStmtNode : StmtNode { bool hasElse; Common::SharedPtr condition; Common::SharedPtr block1; Common::SharedPtr block2; IfStmtNode(uint32 offset, Common::SharedPtr c) : StmtNode(kIfStmtNode, offset), hasElse(false) { condition = Common::move(c); condition->parent = this; block1 = Common::SharedPtr(new BlockNode(offset)); block1->parent = this; block2 = Common::SharedPtr(new BlockNode(offset)); block2->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* RepeatWhileStmtNode */ struct RepeatWhileStmtNode : LoopNode { Common::SharedPtr condition; Common::SharedPtr block; RepeatWhileStmtNode(uint32 startIndex_, Common::SharedPtr c, uint32 offset) : LoopNode(kRepeatWhileStmtNode, startIndex_, offset) { condition = Common::move(c); condition->parent = this; block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* RepeatWithInStmtNode */ struct RepeatWithInStmtNode : LoopNode { Common::String varName; Common::SharedPtr list; Common::SharedPtr block; RepeatWithInStmtNode(uint32 startIndex_, Common::String v, Common::SharedPtr l, uint32 offset) : LoopNode(kRepeatWithInStmtNode, startIndex_, offset) { varName = v; list = Common::move(l); list->parent = this; block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* RepeatWithToStmtNode */ struct RepeatWithToStmtNode : LoopNode { Common::String varName; Common::SharedPtr start; bool up; Common::SharedPtr end; Common::SharedPtr block; RepeatWithToStmtNode(uint32 startIndex_, Common::String v, Common::SharedPtr s, bool _up, Common::SharedPtr e, uint32 offset) : LoopNode(kRepeatWithToStmtNode, startIndex_, offset), up(_up) { varName = v; start = Common::move(s); start->parent = this; end = Common::move(e); end->parent = this; block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* CaseLabelNode */ struct CaseLabelNode : LabelNode { Common::SharedPtr value; CaseExpect expect; Common::SharedPtr nextOr; Common::SharedPtr nextLabel; Common::SharedPtr block; CaseLabelNode(uint32 offset, Common::SharedPtr v, CaseExpect e) : LabelNode(kCaseLabelNode, offset), expect(e) { value = Common::move(v); value->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* OtherwiseNode */ struct OtherwiseNode : LabelNode { Common::SharedPtr block; explicit OtherwiseNode(uint32 offset) : LabelNode(kOtherwiseNode, offset) { block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* EndCaseNode */ struct EndCaseNode : LabelNode { explicit EndCaseNode(uint32 offset) : LabelNode(kEndCaseNode, offset) {} void accept(NodeVisitor &visitor) const override; }; /* CaseStmtNode */ struct CaseStmtNode : StmtNode { Common::SharedPtr value; Common::SharedPtr firstLabel; Common::SharedPtr otherwise; // for use during translation: int32 endPos = -1; int32 potentialOtherwisePos = -1; CaseStmtNode(uint32 offset, Common::SharedPtr v) : StmtNode(kCaseStmtNode, offset) { value = Common::move(v); value->parent = this; } void addOtherwise(uint32 offset); void accept(NodeVisitor &visitor) const override; }; /* TellStmtNode */ struct TellStmtNode : StmtNode { Common::SharedPtr window; Common::SharedPtr block; TellStmtNode(uint32 offset, Common::SharedPtr w) : StmtNode(kTellStmtNode, offset) { window = Common::move(w); window->parent = this; block = Common::SharedPtr(new BlockNode(offset)); block->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* SoundCmdStmtNode */ struct SoundCmdStmtNode : StmtNode { Common::String cmd; Common::SharedPtr argList; SoundCmdStmtNode(uint32 offset, Common::String c, Common::SharedPtr a) : StmtNode(kSoundCmdStmtNode, offset) { cmd = c; argList = Common::move(a); argList->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* PlayCmdStmtNode */ struct PlayCmdStmtNode : StmtNode { Common::SharedPtr argList; PlayCmdStmtNode(uint32 offset, Common::SharedPtr a) : StmtNode(kPlayCmdStmtNode, offset) { argList = Common::move(a); argList->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* CallNode */ struct CallNode : Node { Common::String name; Common::SharedPtr argList; CallNode(uint32 offset, Common::String n, Common::SharedPtr a) : Node(kCallNode, offset) { name = n; argList = Common::move(a); argList->parent = this; if (argList->getValue()->type == kDatumArgListNoRet) isStatement = true; else isExpression = true; } bool noParens() const; bool isMemberExpr() const; bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* ObjCallNode */ struct ObjCallNode : Node { Common::String name; Common::SharedPtr argList; ObjCallNode(uint32 offset, Common::String n, Common::SharedPtr a) : Node(kObjCallNode, offset) { name = n; argList = Common::move(a); argList->parent = this; if (argList->getValue()->type == kDatumArgListNoRet) isStatement = true; else isExpression = true; } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* ObjCallV4Node */ struct ObjCallV4Node : Node { Common::SharedPtr obj; Common::SharedPtr argList; ObjCallV4Node(uint32 offset, Common::SharedPtr o, Common::SharedPtr a) : Node(kObjCallV4Node, offset) { obj = o; argList = Common::move(a); argList->parent = this; if (argList->getValue()->type == kDatumArgListNoRet) isStatement = true; else isExpression = true; } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* TheExprNode */ struct TheExprNode : ExprNode { Common::String prop; TheExprNode(uint32 offset, Common::String p) : ExprNode(kTheExprNode, offset), prop(p) {} void accept(NodeVisitor &visitor) const override; }; /* LastStringChunkExprNode */ struct LastStringChunkExprNode : ExprNode { ChunkExprType type; Common::SharedPtr obj; LastStringChunkExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr o) : ExprNode(kLastStringChunkExprNode, offset), type(t) { obj = Common::move(o); obj->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* StringChunkCountExprNode */ struct StringChunkCountExprNode : ExprNode { ChunkExprType type; Common::SharedPtr obj; StringChunkCountExprNode(uint32 offset, ChunkExprType t, Common::SharedPtr o) : ExprNode(kStringChunkCountExprNode, offset), type(t) { obj = Common::move(o); obj->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* MenuPropExprNode */ struct MenuPropExprNode : ExprNode { Common::SharedPtr menuID; unsigned int prop; MenuPropExprNode(uint32 offset, Common::SharedPtr m, unsigned int p) : ExprNode(kMenuPropExprNode, offset), prop(p) { menuID = Common::move(m); menuID->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* MenuItemPropExprNode */ struct MenuItemPropExprNode : ExprNode { Common::SharedPtr menuID; Common::SharedPtr itemID; unsigned int prop; MenuItemPropExprNode(uint32 offset, Common::SharedPtr m, Common::SharedPtr i, unsigned int p) : ExprNode(kMenuItemPropExprNode, offset), prop(p) { menuID = Common::move(m); menuID->parent = this; itemID = Common::move(i); itemID->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* SoundPropExprNode */ struct SoundPropExprNode : ExprNode { Common::SharedPtr soundID; unsigned int prop; SoundPropExprNode(uint32 offset, Common::SharedPtr s, unsigned int p) : ExprNode(kSoundPropExprNode, offset), prop(p) { soundID = Common::move(s); soundID->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* SpritePropExprNode */ struct SpritePropExprNode : ExprNode { Common::SharedPtr spriteID; unsigned int prop; SpritePropExprNode(uint32 offset, Common::SharedPtr s, unsigned int p) : ExprNode(kSpritePropExprNode, offset), prop(p) { spriteID = Common::move(s); spriteID->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* ThePropExprNode */ struct ThePropExprNode : ExprNode { Common::SharedPtr obj; Common::String prop; ThePropExprNode(uint32 offset, Common::SharedPtr o, Common::String p) : ExprNode(kThePropExprNode, offset), prop(p) { obj = Common::move(o); obj->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* ObjPropExprNode */ struct ObjPropExprNode : ExprNode { Common::SharedPtr obj; Common::String prop; ObjPropExprNode(uint32 offset, Common::SharedPtr o, Common::String p) : ExprNode(kObjPropExprNode, offset), prop(p) { obj = Common::move(o); obj->parent = this; } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* ObjBracketExprNode */ struct ObjBracketExprNode : ExprNode { Common::SharedPtr obj; Common::SharedPtr prop; ObjBracketExprNode(uint32 offset, Common::SharedPtr o, Common::SharedPtr p) : ExprNode(kObjBracketExprNode, offset) { obj = Common::move(o); obj->parent = this; prop = Common::move(p); prop->parent = this; } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* ObjPropIndexExprNode */ struct ObjPropIndexExprNode : ExprNode { Common::SharedPtr obj; Common::String prop; Common::SharedPtr index; Common::SharedPtr index2; ObjPropIndexExprNode(uint32 offset, Common::SharedPtr o, Common::String p, Common::SharedPtr i, Common::SharedPtr i2) : ExprNode(kObjPropIndexExprNode, offset), prop(p) { obj = Common::move(o); obj->parent = this; index = Common::move(i); index->parent = this; if (i2) { index2 = Common::move(i2); index2->parent = this; } } bool hasSpaces(bool dot) override; void accept(NodeVisitor &visitor) const override; }; /* ExitRepeatStmtNode */ struct ExitRepeatStmtNode : StmtNode { explicit ExitRepeatStmtNode(uint32 offset) : StmtNode(kExitRepeatStmtNode, offset) {} void accept(NodeVisitor &visitor) const override; }; /* NextRepeatStmtNode */ struct NextRepeatStmtNode : StmtNode { explicit NextRepeatStmtNode(uint32 offset) : StmtNode(kNextRepeatStmtNode, offset) {} void accept(NodeVisitor &visitor) const override; }; /* PutStmtNode */ struct PutStmtNode : StmtNode { PutType type; Common::SharedPtr variable; Common::SharedPtr value; PutStmtNode(uint32 offset, PutType t, Common::SharedPtr var, Common::SharedPtr val) : StmtNode(kPutStmtNode, offset), type(t) { variable = Common::move(var); variable->parent = this; value = Common::move(val); value->parent = this; } void accept(NodeVisitor &visitor) const override; }; /* WhenStmtNode */ struct WhenStmtNode : StmtNode { int event; Common::String script; WhenStmtNode(uint32 offset, int e, Common::String s) : StmtNode(kWhenStmtNode, offset), event(e), script(s) {} void accept(NodeVisitor &visitor) const override; }; /* NewObjNode */ struct NewObjNode : ExprNode { Common::String objType; Common::SharedPtr objArgs; NewObjNode(uint32 offset, Common::String o, Common::SharedPtr args) : ExprNode(kNewObjNode, offset), objType(o), objArgs(args) {} void accept(NodeVisitor &visitor) const override; }; class NodeVisitor { public: virtual ~NodeVisitor() {} virtual void visit(const HandlerNode &node) { defaultVisit(node); } virtual void visit(const ErrorNode &node) { defaultVisit(node); } virtual void visit(const CommentNode &node) { defaultVisit(node); } virtual void visit(const NewObjNode &node) { defaultVisit(node); } virtual void visit(const LiteralNode &node) { defaultVisit(node); } virtual void visit(const IfStmtNode &node) { defaultVisit(node); } virtual void visit(const EndCaseNode &node) { defaultVisit(node); } virtual void visit(const ObjCallNode &node) { defaultVisit(node); } virtual void visit(const PutStmtNode &node) { defaultVisit(node); } virtual void visit(const TheExprNode &node) { defaultVisit(node); } virtual void visit(const BinaryOpNode &node) { defaultVisit(node); } virtual void visit(const CaseStmtNode &node) { defaultVisit(node); } virtual void visit(const ExitStmtNode &node) { defaultVisit(node); } virtual void visit(const TellStmtNode &node) { defaultVisit(node); } virtual void visit(const WhenStmtNode &node) { defaultVisit(node); } virtual void visit(const CaseLabelNode &node) { defaultVisit(node); } virtual void visit(const ChunkExprNode &node) { defaultVisit(node); } virtual void visit(const InverseOpNode &node) { defaultVisit(node); } virtual void visit(const ObjCallV4Node &node) { defaultVisit(node); } virtual void visit(const OtherwiseNode &node) { defaultVisit(node); } virtual void visit(const MemberExprNode &node) { defaultVisit(node); } virtual void visit(const ObjPropExprNode &node) { defaultVisit(node); } virtual void visit(const PlayCmdStmtNode &node) { defaultVisit(node); } virtual void visit(const ThePropExprNode &node) { defaultVisit(node); } virtual void visit(const MenuPropExprNode &node) { defaultVisit(node); } virtual void visit(const SoundCmdStmtNode &node) { defaultVisit(node); } virtual void visit(const SoundPropExprNode &node) { defaultVisit(node); } virtual void visit(const AssignmentStmtNode &node) { defaultVisit(node); } virtual void visit(const ExitRepeatStmtNode &node) { defaultVisit(node); } virtual void visit(const NextRepeatStmtNode &node) { defaultVisit(node); } virtual void visit(const ObjBracketExprNode &node) { defaultVisit(node); } virtual void visit(const SpritePropExprNode &node) { defaultVisit(node); } virtual void visit(const ChunkDeleteStmtNode &node) { defaultVisit(node); } virtual void visit(const ChunkHiliteStmtNode &node) { defaultVisit(node); } virtual void visit(const RepeatWhileStmtNode &node) { defaultVisit(node); } virtual void visit(const MenuItemPropExprNode &node) { defaultVisit(node); } virtual void visit(const ObjPropIndexExprNode &node) { defaultVisit(node); } virtual void visit(const RepeatWithInStmtNode &node) { defaultVisit(node); } virtual void visit(const RepeatWithToStmtNode &node) { defaultVisit(node); } virtual void visit(const SpriteWithinExprNode &node) { defaultVisit(node); } virtual void visit(const LastStringChunkExprNode &node) { defaultVisit(node); } virtual void visit(const SpriteIntersectsExprNode &node) { defaultVisit(node); } virtual void visit(const StringChunkCountExprNode &node) { defaultVisit(node); } virtual void visit(const VarNode &node) { defaultVisit(node); } virtual void visit(const CallNode &node) { defaultVisit(node); } virtual void visit(const BlockNode &node) { defaultVisit(node); } virtual void visit(const NotOpNode &node) { defaultVisit(node); } virtual void defaultVisit(const Node &) {} }; /* AST */ struct AST { Common::SharedPtr root; BlockNode *currentBlock; AST(uint32 offset, Handler *handler){ root = Common::SharedPtr(new HandlerNode(offset, handler)); currentBlock = root->block.get(); } void addStatement(Common::SharedPtr statement); void enterBlock(BlockNode *block); void exitBlock(); }; } // namespace LingoDec #endif // LINGODEC_AST_H