/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the JavaScript 2 Prototype. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef parser_h___ #define parser_h___ #include "world.h" #include "utilities.h" #include "reader.h" #include "lexer.h" #include #ifdef DIKDIK #include "property.h" #endif namespace JavaScript { #ifdef DIKDIK // forward declarations to classes in the back-end namespace JS2Runtime { class JSFunction; class JSType; class JSObject; class Attribute; } #endif #ifdef EPIMETHEUS namespace MetaData { class Context; class JS2Object; class JS2Class; class Member; class InstanceMember; class Multiname; class BlockFrame; class FunctionInstance; typedef uint32 LabelID; } #endif // // Pragmas // namespace Pragma { enum Flags { // Bitmap of pragma flags // Only one of js1, js12, es4, or js2 will be set js1 = 1<<0, // JS 1.x and ECMAScript 1, 2, or 3 js12 = 1<<1, // JS 1.2 es4 = 1<<2, // ECMAScript 4 js2 = 1<<3, // ECMAScript 4 with JS 2.0 extensions js1or12 = js1|js12, es4orjs2 = es4|js2, languageMask = js1|js12|es4|js2, strict = 1<<4 // Strict mode; can only be set when js2 or es4 is set }; inline Flags setLanguage(Flags flags, Flags language) {return static_cast(flags & ~languageMask | language);} inline bool lineBreaksSignificant(Flags flags) {return (flags & strict) == 0;} } // // Parser // // The structures below are generally allocated inside an arena. The // structures' destructors may never be called, so these structures should not // hold onto any data that needs to be destroyed explicitly. Strings are // allocated via newArenaString. struct ParseNode: ArenaObject { size_t pos; // Position of this statement or expression explicit ParseNode(size_t pos): pos(pos) {} }; // A helper template for creating linked lists of ParseNode subtypes. N should // be derived from a ParseNode and should have an instance variable called // of type N* and that is initialized to nil when an N instance is // created. template class NodeQueue { public: N *first; // Head of queue private: N **last; // Next link of last element of queue public: NodeQueue(): first(0), last(&first) {} private: NodeQueue(const NodeQueue&); // No copy constructor void operator=(const NodeQueue&); // No assignment operator public: void operator+=(N *elt) {ASSERT(elt && !elt->next); *last = elt; last = &elt->next;} }; struct ExprNode; struct AttributeStmtNode; struct BlockStmtNode; struct VariableBinding: ParseNode { VariableBinding *next; // Next binding in a linked list of variable or parameter bindings const StringAtom *name; // The variable's name; // nil if omitted, which currently can only happen for ... parameters ExprNode *type; // Type expression or nil if not provided ExprNode *initializer; // Initial value expression or nil if not provided bool constant; // true for const variables and parameters #ifdef DIKDIK JS2Runtime::Property *prop; // the sematics/codegen passes stuff their data in here. JS2Runtime::JSObject *scope; // ditto #endif #ifdef EPIMETHEUS MetaData::Member *member; // the associated definition, [used to resolve eventual type] MetaData::InstanceMember *overridden; // overridden member... [used for resolving override legality] MetaData::Multiname *mn; // ...and name constructed by the semantics phase. [used for emitting initialization sequence] #endif VariableBinding(size_t pos, const StringAtom *name, ExprNode *type, ExprNode *initializer, bool constant): ParseNode(pos), next(0), name(name), type(type), initializer(initializer), constant(constant) {} void print(PrettyPrinter &f, bool printConst) const; }; struct ExprNode: ParseNode { // Keep synchronized with kindNames enum Kind { // Actual class Operands none, // Beginning of isPostfix() identifier, // IdentifierExprNode Null, // ExprNode null boolean, // BooleanExprNode number, // NumberExprNode string, // StringExprNode regExp, // RegExpExprNode // This, // ExprNode this parentheses, // UnaryExprNode () numUnit, // NumUnitExprNode "" or exprUnit, // ExprUnitExprNode () "" or qualify, // QualifyExprNode :: objectLiteral, // PairListExprNode {:, :, ..., :} arrayLiteral, // PairListExprNode [, , ..., ] functionLiteral, // FunctionExprNode function call, // InvokeExprNode (:, :, ..., :) New, // InvokeExprNode new (:, :, ..., :) index, // InvokeExprNode [:, :, ..., :] dot, // BinaryExprNode . ( must be identifier or qualify) dotParen, // BinaryExprNode .( ) // End of isPostfix() superExpr, // SuperExprNode super or super() superStmt, // InvokeExprNode super(:, :, ..., :) // A superStmt will only appear at the top level of an expression StmtNode. Delete, // UnaryExprNode delete Void, // UnaryExprNode void Typeof, // UnaryExprNode typeof preIncrement, // UnaryExprNode ++ preDecrement, // UnaryExprNode -- postIncrement, // UnaryExprNode ++ postDecrement, // UnaryExprNode -- plus, // UnaryExprNode + minus, // UnaryExprNode - complement, // UnaryExprNode ~ logicalNot, // UnaryExprNode ! juxtapose, // BinaryExprNode (used to combine attributes) add, // BinaryExprNode + subtract, // BinaryExprNode - multiply, // BinaryExprNode * divide, // BinaryExprNode / modulo, // BinaryExprNode % leftShift, // BinaryExprNode << rightShift, // BinaryExprNode >> logicalRightShift, // BinaryExprNode >>> bitwiseAnd, // BinaryExprNode & bitwiseXor, // BinaryExprNode ^ bitwiseOr, // BinaryExprNode | logicalAnd, // BinaryExprNode && logicalXor, // BinaryExprNode ^^ logicalOr, // BinaryExprNode || equal, // BinaryExprNode == notEqual, // BinaryExprNode != lessThan, // BinaryExprNode < lessThanOrEqual, // BinaryExprNode <= greaterThan, // BinaryExprNode > greaterThanOrEqual, // BinaryExprNode >= identical, // BinaryExprNode === notIdentical, // BinaryExprNode !== As, // BinaryExprNode as In, // BinaryExprNode in Instanceof, // BinaryExprNode instanceof Is, // BinaryExprNode is assignment, // BinaryExprNode = addEquals, // BinaryExprNode += subtractEquals, // BinaryExprNode -= multiplyEquals, // BinaryExprNode *= divideEquals, // BinaryExprNode /= moduloEquals, // BinaryExprNode %= leftShiftEquals, // BinaryExprNode <<= rightShiftEquals, // BinaryExprNode >>= logicalRightShiftEquals, // BinaryExprNode >>>= bitwiseAndEquals, // BinaryExprNode &= bitwiseXorEquals, // BinaryExprNode ^= bitwiseOrEquals, // BinaryExprNode |= logicalAndEquals, // BinaryExprNode &&= logicalXorEquals, // BinaryExprNode ^^= logicalOrEquals, // BinaryExprNode ||= conditional, // TernaryExprNode ? : comma, // BinaryExprNode , (Comma expressions only) kindsEnd }; private: Kind kind; // The node's kind static const char *const kindNames[kindsEnd]; public: ExprNode(size_t pos, Kind kind): ParseNode(pos), kind(kind) {} Kind getKind() const {return kind;} bool hasKind(Kind k) const {return kind == k;} static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];} bool isPostfix() const {return kind >= identifier && kind <= dotParen;} virtual void print(PrettyPrinter &f) const; friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} }; // Print e onto f. inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) { ASSERT(e); e->print(f); return f; } struct FunctionName { enum Prefix { // Keep synchronized with functionPrefixNames normal, // No prefix Get, // get Set, // set op // The function name is a string (used for operator overrides) }; Prefix prefix; // The name's prefix, if any const StringAtom *name; // The interned name; nil if omitted FunctionName(): prefix(normal), name(0) {} void print(PrettyPrinter &f) const; }; struct FunctionDefinition: FunctionName { // The parameters linked list includes all kinds of parameters. optParameters, restParameter, and namedParameters // are pointers into the interior of the linked list. If any kind is empty, then that kind's pointer is equal to // the following kind's pointer, so, for example, if there is no rest parameter then restParameter == namedParameters. // A pointer is nil only if its kind and all subsequent kinds are empty. VariableBinding *parameters; // Linked list of all parameters, including optional, rest, and named parameters VariableBinding *optParameters; // Pointer to first optional parameter inside parameters list VariableBinding *restParameter; // Pointer to rest parameter inside parameters list VariableBinding *namedParameters;// Pointer to first named parameter inside parameters list bool restIsNamed; // True if the rest parameter has the 'named' attribute ExprNode *resultType; // Result type expression or nil if not provided BlockStmtNode *body; // Body; nil if none void print(PrettyPrinter &f, const AttributeStmtNode *attributes, bool noSemi) const; #ifdef EPIMETHEUS MetaData::FunctionInstance *fn; // Runtime data, bytecode, parameters etc. #endif }; struct IdentifierExprNode: ExprNode { const StringAtom &name; // The identifier IdentifierExprNode(size_t pos, Kind kind, const StringAtom &name): ExprNode(pos, kind), name(name) {} explicit IdentifierExprNode(const Token &t): ExprNode(t.getPos(), identifier), name(t.getIdentifier()) {} void print(PrettyPrinter &f) const; }; struct QualifyExprNode: IdentifierExprNode { ExprNode *qualifier; // The qualifier expression; non-nil only QualifyExprNode(size_t pos, ExprNode *qualifier, const StringAtom &name): IdentifierExprNode(pos, qualify, name), qualifier(qualifier) {ASSERT(qualifier);} void print(PrettyPrinter &f) const; }; struct BooleanExprNode: ExprNode { bool value; // The boolean's value BooleanExprNode(size_t pos, bool value): ExprNode(pos, boolean), value(value) {} void print(PrettyPrinter &f) const; }; struct NumberExprNode: ExprNode { float64 value; // The number's value NumberExprNode(size_t pos, float64 value): ExprNode(pos, number), value(value) {} explicit NumberExprNode(const Token &t): ExprNode(t.getPos(), number), value(t.getValue()) {} void print(PrettyPrinter &f) const; }; struct StringExprNode: ExprNode { String &str; // The string StringExprNode(size_t pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {} void print(PrettyPrinter &f) const; }; struct RegExpExprNode: ExprNode { const StringAtom &re; // The regular expression's contents String &flags; // The regular expression's flags RegExpExprNode(size_t pos, Kind kind, const StringAtom &re, String &flags): ExprNode(pos, kind), re(re), flags(flags) {} void print(PrettyPrinter &f) const; }; struct NumUnitExprNode: StringExprNode { // str is the unit string String &numStr; // The number's source string float64 num; // The number's value NumUnitExprNode(size_t pos, Kind kind, String &numStr, float64 num, String &unitStr): StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} void print(PrettyPrinter &f) const; }; struct ExprUnitExprNode: StringExprNode { // str is the unit string ExprNode *op; // The expression to which the unit is applied; non-nil only ExprUnitExprNode(size_t pos, Kind kind, ExprNode *op, String &unitStr): StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} void print(PrettyPrinter &f) const; }; struct FunctionExprNode: ExprNode { FunctionDefinition function; // Function definition explicit FunctionExprNode(size_t pos): ExprNode(pos, functionLiteral) {} void print(PrettyPrinter &f) const; }; struct ExprPairList: ArenaObject { ExprPairList *next; // Next pair in linked list ExprNode *field; // Field expression or nil if not provided ExprNode *value; // Value expression or nil if not provided explicit ExprPairList(ExprNode *field = 0, ExprNode *value = 0): next(0), field(field), value(value) {} }; struct PairListExprNode: ExprNode { ExprPairList *pairs; // Linked list of pairs PairListExprNode(size_t pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {} void print(PrettyPrinter &f) const; }; struct InvokeExprNode: PairListExprNode { ExprNode *op; // The called function, called constructor, or indexed object; nil only for superStmt #ifdef DIKDIK bool isSuperInvoke; // used by backend to handle super constructor call in a constructor #endif InvokeExprNode(size_t pos, Kind kind, ExprNode *op, ExprPairList *pairs): PairListExprNode(pos, kind, pairs), op(op) #ifdef DIKDIK , isSuperInvoke(false) #endif {ASSERT(op || kind == superStmt);} void print(PrettyPrinter &f) const; }; struct SuperExprNode: ExprNode { ExprNode *op; // The operand or nil if none SuperExprNode(size_t pos, ExprNode *op): ExprNode(pos, superExpr), op(op) {} void print(PrettyPrinter &f) const; }; struct UnaryExprNode: ExprNode { ExprNode *op; // The unary operator's operand; non-nil only UnaryExprNode(size_t pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);} void print(PrettyPrinter &f) const; }; struct BinaryExprNode: ExprNode { ExprNode *op1; // The binary operator's first operand; non-nil only ExprNode *op2; // The binary operator's second operand; non-nil only BinaryExprNode(size_t pos, Kind kind, ExprNode *op1, ExprNode *op2): ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} void print(PrettyPrinter &f) const; }; struct TernaryExprNode: ExprNode { ExprNode *op1; // The ternary operator's first operand; non-nil only ExprNode *op2; // The ternary operator's second operand; non-nil only ExprNode *op3; // The ternary operator's third operand; non-nil only TernaryExprNode(size_t pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3): ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);} void print(PrettyPrinter &f) const; }; struct StmtNode: ParseNode { enum Kind { // Actual class Operands empty, // StmtNode ; expression, // ExprStmtNode ; block, // BlockStmtNode { } group, // BlockStmtNode { } label, // LabelStmtNode : If, // UnaryStmtNode if ( ) IfElse, // BinaryStmtNode if ( ) else Switch, // SwitchStmtNode switch ( ) While, // UnaryStmtNode while ( ) DoWhile, // UnaryStmtNode do while ( ) With, // UnaryStmtNode with ( ) For, // ForStmtNode for ( ; ; ) ForIn, // ForStmtNode for ( in ) Case, // ExprStmtNode case : or default : (Only occurs directly inside a Switch) Break, // GoStmtNode break ; or break ; Continue, // GoStmtNode continue ; or continue ; Return, // ExprStmtNode return ; or return ; Throw, // ExprStmtNode throw ; Try, // TryStmtNode try Export, // ExportStmtNode export ; Const, // VariableStmtNode const ; Var, // VariableStmtNode var ; Function, // FunctionStmtNode function Class, // ClassStmtNode class extends Namespace, // NamespaceStmtNode namespace Use, // UseStmtNode use namespace ; Import, // ImportStmtNode import ; Package, // PackageStmtNode package Pragma, // PragmaStmtNode pragma ; Include, // IncludeStmtNode include "name" ; Debugger // DebuggerStmtNode debugger ; }; private: Kind kind; // The node's kind public: StmtNode *next; // Next statement in a linked list of statements in this block StmtNode(size_t pos, Kind kind): ParseNode(pos), kind(kind), next(0) {} Kind getKind() const {return kind;} bool hasKind(Kind k) const {return kind == k;} static void printStatements(PrettyPrinter &f, const StmtNode *statements); static void printBlockStatements(PrettyPrinter &f, const StmtNode *statements, bool loose); static void printSemi(PrettyPrinter &f, bool noSemi); void printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation = 0) const; virtual void print(PrettyPrinter &f, bool noSemi) const; }; struct ExprStmtNode: StmtNode { ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements. #ifdef DIKDIK uint32 label; // Used for case statements' code generation #endif #ifdef EPIMETHEUS MetaData::LabelID labelID; // Used for case statements' code generation #endif ExprStmtNode(size_t pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct DebuggerStmtNode: StmtNode { DebuggerStmtNode(size_t pos, Kind kind): StmtNode(pos, kind) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct AttributeStmtNode: StmtNode { ExprNode *attributes; // Directive's attributes; nil if none #ifdef DIKDIK JS2Runtime::Attribute *attributeValue; // used by backend #endif AttributeStmtNode(size_t pos, Kind kind, ExprNode *attributes): StmtNode(pos, kind), attributes(attributes) {} void printAttributes(PrettyPrinter &f) const; }; struct BlockStmtNode: AttributeStmtNode { StmtNode *statements; // Linked list of block's or group's statements BlockStmtNode(size_t pos, Kind kind, ExprNode *attributes, StmtNode *statements): AttributeStmtNode(pos, kind, attributes), statements(statements) {} void print(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::BlockFrame *compileFrame; // Used by backend, it's the plural frame for the // declarations contained in the block. #endif }; struct LabelStmtNode: StmtNode { const StringAtom &name; // The label StmtNode *stmt; // Labeled statement; non-nil only LabelStmtNode(size_t pos, const StringAtom &name, StmtNode *stmt): StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);} void print(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::LabelID labelID; #endif }; struct UnaryStmtNode: ExprStmtNode { StmtNode *stmt; // First substatement; non-nil only UnaryStmtNode(size_t pos, Kind kind, ExprNode *expr, StmtNode *stmt): ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);} void print(PrettyPrinter &f, bool noSemi) const; virtual void printContents(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::LabelID breakLabelID; MetaData::LabelID continueLabelID; MetaData::BlockFrame *compileFrame; #endif }; struct BinaryStmtNode: UnaryStmtNode { StmtNode *stmt2; // Second substatement; non-nil only BinaryStmtNode(size_t pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2): UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);} void printContents(PrettyPrinter &f, bool noSemi) const; }; struct ForStmtNode: StmtNode { StmtNode *initializer; // For: First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const. // ForIn: Expression or declaration before 'in'; either an expression, // or a Var or a Const with exactly one binding. ExprNode *expr2; // For: Second item in parentheses; nil if not provided // ForIn: Subexpression after 'in'; non-nil only ExprNode *expr3; // For: Third item in parentheses; nil if not provided // ForIn: nil StmtNode *stmt; // Substatement; non-nil only ForStmtNode(size_t pos, Kind kind, StmtNode *initializer, ExprNode *expr2, ExprNode *expr3, StmtNode *stmt): StmtNode(pos, kind), initializer(initializer), expr2(expr2), expr3(expr3), stmt(stmt) {ASSERT(stmt);} void print(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::LabelID breakLabelID; MetaData::LabelID continueLabelID; #endif }; struct SwitchStmtNode: ExprStmtNode { StmtNode *statements; // Linked list of switch block's statements, which may include Case and Default statements SwitchStmtNode(size_t pos, ExprNode *expr, StmtNode *statements): ExprStmtNode(pos, Switch, expr), statements(statements) {} void print(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::LabelID breakLabelID; #endif }; struct GoStmtNode: StmtNode { const StringAtom *name; // The label; nil if none GoStmtNode(size_t pos, Kind kind, const StringAtom *name): StmtNode(pos, kind), name(name) {} void print(PrettyPrinter &f, bool noSemi) const; #ifdef EPIMETHEUS MetaData::LabelID tgtID; #endif }; struct CatchClause: ParseNode { CatchClause *next; // Next catch clause in a linked list of catch clauses const StringAtom &name; // The name of the variable that will hold the exception ExprNode *type; // Type expression or nil if not provided bool constant; // true for const variables StmtNode *stmt; // The catch clause's body; non-nil only #ifdef DIKDIK JS2Runtime::Property *prop; // the sematics/codegen passes stuff their data in here. #endif CatchClause(size_t pos, const StringAtom &name, ExprNode *type, bool constant, StmtNode *stmt): ParseNode(pos), next(0), name(name), type(type), constant(constant), stmt(stmt) {ASSERT(stmt);} }; struct TryStmtNode: StmtNode { StmtNode *stmt; // Substatement being tried; usually a block; non-nil only CatchClause *catches; // Linked list of catch blocks; may be nil StmtNode *finally; // Finally block or nil if none TryStmtNode(size_t pos, StmtNode *stmt, CatchClause *catches, StmtNode *finally): StmtNode(pos, Try), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);} void print(PrettyPrinter &f, bool noSemi) const; }; struct ExportBinding: ParseNode { ExportBinding *next; // Next binding in a linked list of export bindings FunctionName name; // The exported variable's name; name.name is non-nil only FunctionName initializer; // The original variable's name; same as name if omitted ExportBinding(size_t pos): ParseNode(pos), next(0) {} void print(PrettyPrinter &f) const; }; struct ExportStmtNode: AttributeStmtNode { ExportBinding *bindings; // Linked list of export bindings; non-nil only ExportStmtNode(size_t pos, ExprNode *attributes, ExportBinding *bindings): AttributeStmtNode(pos, Export, attributes), bindings(bindings) {ASSERT(bindings);} void print(PrettyPrinter &f, bool noSemi) const; }; struct VariableStmtNode: AttributeStmtNode { VariableBinding *bindings; // Linked list of variable bindings; non-nil only VariableStmtNode(size_t pos, Kind kind, ExprNode *attributes, VariableBinding *bindings): AttributeStmtNode(pos, kind, attributes), bindings(bindings) {ASSERT(bindings);} void print(PrettyPrinter &f, bool noSemi) const; }; struct FunctionStmtNode: AttributeStmtNode { FunctionDefinition function; // Function definition #ifdef DIKDIK JS2Runtime::JSFunction *mFunction; // used by backend #endif FunctionStmtNode(size_t pos, Kind kind, ExprNode *attributes): AttributeStmtNode(pos, kind, attributes) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct NamespaceStmtNode: AttributeStmtNode { const StringAtom &name; // The namespace's or class's name NamespaceStmtNode(size_t pos, Kind kind, ExprNode *attributes, const StringAtom &name): AttributeStmtNode(pos, kind, attributes), name(name) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct ClassStmtNode: NamespaceStmtNode { ExprNode *superclass; // Superclass expression (classes only); nil if omitted BlockStmtNode *body; // The class's body; nil if omitted #ifdef DIKDIK JS2Runtime::JSType *mType; // used by backend #endif #ifdef EPIMETHEUS MetaData::JS2Class *c; // Runtime metadata structure #endif ClassStmtNode(size_t pos, ExprNode *attributes, const StringAtom &name, ExprNode *superclass, BlockStmtNode *body): NamespaceStmtNode(pos, Class, attributes, name), superclass(superclass), body(body) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct IdentifierList: ArenaObject { IdentifierList *next; // Next identifier in linked list const StringAtom &name; // The identifier explicit IdentifierList(const StringAtom &name): next(0), name(name) {} void printList(PrettyPrinter &f, char separator) const; }; struct ExprList: ArenaObject { ExprList *next; // Next expression in linked list ExprNode *expr; // Expression; non-nil only explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);} void printList(PrettyPrinter &f) const; }; struct UseStmtNode: AttributeStmtNode { ExprList *namespaces; // Linked list of namespace expressions; may be nil in an import statement IdentifierList *includeExclude; // Linked list of include/exclude identifiers bool exclude; // If true, includeExclude lists excluded identifiers; if false, included identifiers UseStmtNode(size_t pos, Kind kind, ExprNode *attributes, ExprList *namespaces): AttributeStmtNode(pos, kind, attributes), namespaces(namespaces) {} protected: void printNamespaces(PrettyPrinter &f) const; void printIncludeExclude(PrettyPrinter &f) const; public: void print(PrettyPrinter &f, bool noSemi) const; }; struct ImportStmtNode: UseStmtNode { const StringAtom *varName; // The package variable's name; nil if omitted // Either packageIdList or packageString may be nil, but not both IdentifierList *packageIdList; // The package name as a list of identifiers String *packageString; // The package name as a string ImportStmtNode(size_t pos, ExprNode *attributes, const StringAtom *varName, IdentifierList *packageIdList, String *packageString, ExprList *namespaces): UseStmtNode(pos, Import, attributes, namespaces), varName(varName), packageIdList(packageIdList), packageString(packageString) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct PackageStmtNode: StmtNode { IdentifierList *packageIdList; // The package name as a list of identifiers; may be nil BlockStmtNode *body; // The package's body; non-nil only #ifdef DIKDIK JS2Runtime::JSObject *scope; // the sematics/codegen passes stuff their data in here. #endif PackageStmtNode(size_t pos, IdentifierList *packageIdList, BlockStmtNode *body): StmtNode(pos, Package), packageIdList(packageIdList), body(body) {ASSERT(body);} void print(PrettyPrinter &f, bool noSemi) const; }; struct PragmaStmtNode: StmtNode { Pragma::Flags flags; // The new set of flags to use until the next PragmaStmtNode or the end of this scope PragmaStmtNode(size_t pos, Pragma::Flags flags): StmtNode(pos, Pragma), flags(flags) {} void print(PrettyPrinter &f, bool noSemi) const; }; struct IncludeStmtNode: StmtNode { String &name; // The file name IncludeStmtNode(size_t pos, String &name): StmtNode(pos, Include), name(name) {} void print(PrettyPrinter &f, bool noSemi) const; }; class Parser { public: Lexer lexer; Arena &arena; Pragma::Flags &flags; // The flags currently guiding the parser; saved and restored on entering nested scopes Parser(World &world, Arena &arena, Pragma::Flags &flags, const String &source, const String &sourceLocation, uint32 initialLineNum = 1); private: Reader &getReader() {return lexer.reader;} World &getWorld() {return lexer.world;} public: void syntaxError(const char *message, uint backUp = 1); void syntaxError(const String &message, uint backUp = 1); const Token &require(bool preferRegExp, Token::Kind kind); private: String ©TokenChars(const Token &t); bool lineBreakBefore(const Token &t) const {return Pragma::lineBreaksSignificant(flags) && t.getLineBreak();} bool lineBreakBefore() {return Pragma::lineBreaksSignificant(flags) && lexer.peek(true).getLineBreak();} enum SuperState { ssNone, // No super operator ssExpr, // super or super(expr) ssStmt // super or super(expr) or super(arguments) }; enum Precedence { pNone, // End tag pExpression, // ListExpression pAssignment, // AssignmentExpression pConditional, // ConditionalExpression pLogicalOr, // LogicalOrExpression pLogicalXor, // LogicalXorExpression pLogicalAnd, // LogicalAndExpression pBitwiseOr, // BitwiseOrExpression pBitwiseXor, // BitwiseXorExpression pBitwiseAnd, // BitwiseAndExpression pEquality, // EqualityExpression pRelational, // RelationalExpression pShift, // ShiftExpression pAdditive, // AdditiveExpression pMultiplicative, // MultiplicativeExpression pUnary, // UnaryExpression pPostfix // PostfixExpression }; struct BinaryOperatorInfo { ExprNode::Kind kind; // The kind of BinaryExprNode the operator should generate; // ExprNode::none if not a binary operator Precedence precedenceLeft; // Operators in this operator's left subexpression with precedenceLeft or higher are reduced Precedence precedenceRight; // This operator's precedence bool superLeft; // True if the left operand can be a SuperExpression }; static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd]; struct StackedSubexpression; ExprNode *makeIdentifierExpression(const Token &t) const; const StringAtom &ensureIdentifier(const Token &t); const StringAtom &parseIdentifier(); IdentifierList *parseIdentifierList(Token::Kind separator); ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp); ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool noComma, bool &foundQualifiers, bool preferRegExp); ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp); PairListExprNode *parseArrayLiteral(const Token &initialToken); PairListExprNode *parseObjectLiteral(const Token &initialToken); ExprNode *parseUnitSuffixes(ExprNode *e); ExprNode *parseSuper(size_t pos, SuperState superState); public: FunctionExprNode *parseFunctionExpression(size_t pos); private: ExprNode *parsePrimaryExpression(SuperState superState); ExprNode *parseMember(ExprNode *target, const Token &tOperator, bool preferRegExp); InvokeExprNode *parseInvoke(ExprNode *target, size_t pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind); ExprNode *parsePostfixOperator(ExprNode *e, bool newExpression, bool attribute); ExprNode *parsePostfixExpression(SuperState superState, bool newExpression); void ensurePostfix(const ExprNode *e); ExprNode *parseUnaryExpression(SuperState superState); ExprNode *parseGeneralExpression(bool allowSuperStmt, bool noIn, bool noAssignment, bool noComma); public: ExprNode *parseListExpression(bool noIn) {return parseGeneralExpression(false, noIn, false, false);} ExprNode *parseAssignmentExpression(bool noIn) {return parseGeneralExpression(false, noIn, false, true);} ExprNode *parseNonAssignmentExpression(bool noIn) {return parseGeneralExpression(false, noIn, true, true);} private: ExprNode *parseAttribute(const Token &t); ExprNode *parseAttributes(size_t pos, ExprNode *attribute); static bool expressionIsAttribute(const ExprNode *e); ExprNode *parseParenthesizedListExpression(); ExprList *parseParenthesizedExpressionList(bool optional); ExprNode *parseTypeExpression(bool noIn=false); ExprNode *parseTypeBinding(Token::Kind kind, bool noIn); bool doubleColonFollows(); VariableBinding *parseVariableBinding(size_t pos, bool noIn, bool noType, bool noInitializer, bool noAttributes, bool constant); VariableBinding *parseParameter(bool rest, bool &named); void parseFunctionName(FunctionName &fn); void parseFunctionSignature(FunctionDefinition &fd); ExportBinding *parseExportBinding(); StmtNode *parseBlockContents(bool substatement, bool inSwitch); BlockStmtNode *parseBody(bool *semicolonWanted); void parseIncludeExclude(UseStmtNode &s); ImportStmtNode *parseImport(size_t pos, ExprNode *attributes); UseStmtNode *parseUseDirective(size_t pos, ExprNode *attributes); void parseClosingSemicolon(); bool parseBooleanPragma(const ExprList *arguments, bool &value, bool ignoreErrors); bool parseNumericPragma(const ExprList *arguments, float64 &value, bool ignoreErrors); StmtNode *parseUse(size_t pos, ExprNode *attributes, bool &semicolonWanted); StmtNode *parseAnnotatableDirective(size_t pos, ExprNode *attributes, const Token &t, bool noIn, bool substatement, bool &semicolonWanted); ForStmtNode *parseFor(size_t pos, bool &semicolonWanted); TryStmtNode *parseTry(size_t pos); PackageStmtNode *parsePackage(size_t pos); StmtNode *parseDirective(bool substatement, bool inSwitch, bool &semicolonWanted); StmtNode *parseSubstatement(bool &semicolonWanted); public: StmtNode *parseFullDirective(bool substatement, bool inSwitch); StmtNode *parseProgram(); }; } #endif /* parser_h___ */