Mozilla/mozilla/js2/src/parser.h
gerv%gerv.net 912583b021 Bug 236613: change to MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@155485 18797224-902f-48f8-a5cc-f745e15eee43
2004-04-25 15:37:13 +00:00

944 lines
43 KiB
C++

/* -*- 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 <vector>
#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>(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
// <next> of type N* and that is initialized to nil when an N instance is
// created.
template<class N> 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 <name>
Null, // ExprNode null
boolean, // BooleanExprNode <value>
number, // NumberExprNode <value>
string, // StringExprNode <str>
regExp, // RegExpExprNode /<re>/<flags>
This, // ExprNode this
parentheses, // UnaryExprNode (<op>)
numUnit, // NumUnitExprNode <num> "<str>" or <num><str>
exprUnit, // ExprUnitExprNode (<op>) "<str>" or <op><str>
qualify, // QualifyExprNode <qualifier> :: <name>
objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>}
arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>]
functionLiteral, // FunctionExprNode function <function>
call, // InvokeExprNode <op>(<field>:<value>, <field>:<value>, ..., <field>:<value>)
New, // InvokeExprNode new <op>(<field>:<value>, <field>:<value>, ..., <field>:<value>)
index, // InvokeExprNode <op>[<field>:<value>, <field>:<value>, ..., <field>:<value>]
dot, // BinaryExprNode <op1> . <op2> (<op2> must be identifier or qualify)
dotParen, // BinaryExprNode <op1> .( <op2> )
// End of isPostfix()
superExpr, // SuperExprNode super or super(<op>)
superStmt, // InvokeExprNode super(<field>:<value>, <field>:<value>, ..., <field>:<value>)
// A superStmt will only appear at the top level of an expression StmtNode.
Delete, // UnaryExprNode delete <op>
Void, // UnaryExprNode void <op>
Typeof, // UnaryExprNode typeof <op>
preIncrement, // UnaryExprNode ++ <op>
preDecrement, // UnaryExprNode -- <op>
postIncrement, // UnaryExprNode <op> ++
postDecrement, // UnaryExprNode <op> --
plus, // UnaryExprNode + <op>
minus, // UnaryExprNode - <op>
complement, // UnaryExprNode ~ <op>
logicalNot, // UnaryExprNode ! <op>
juxtapose, // BinaryExprNode <op1> <op2> (used to combine attributes)
add, // BinaryExprNode <op1> + <op2>
subtract, // BinaryExprNode <op1> - <op2>
multiply, // BinaryExprNode <op1> * <op2>
divide, // BinaryExprNode <op1> / <op2>
modulo, // BinaryExprNode <op1> % <op2>
leftShift, // BinaryExprNode <op1> << <op2>
rightShift, // BinaryExprNode <op1> >> <op2>
logicalRightShift, // BinaryExprNode <op1> >>> <op2>
bitwiseAnd, // BinaryExprNode <op1> & <op2>
bitwiseXor, // BinaryExprNode <op1> ^ <op2>
bitwiseOr, // BinaryExprNode <op1> | <op2>
logicalAnd, // BinaryExprNode <op1> && <op2>
logicalXor, // BinaryExprNode <op1> ^^ <op2>
logicalOr, // BinaryExprNode <op1> || <op2>
equal, // BinaryExprNode <op1> == <op2>
notEqual, // BinaryExprNode <op1> != <op2>
lessThan, // BinaryExprNode <op1> < <op2>
lessThanOrEqual, // BinaryExprNode <op1> <= <op2>
greaterThan, // BinaryExprNode <op1> > <op2>
greaterThanOrEqual, // BinaryExprNode <op1> >= <op2>
identical, // BinaryExprNode <op1> === <op2>
notIdentical, // BinaryExprNode <op1> !== <op2>
As, // BinaryExprNode <op1> as <op2>
In, // BinaryExprNode <op1> in <op2>
Instanceof, // BinaryExprNode <op1> instanceof <op2>
Is, // BinaryExprNode <op1> is <op2>
assignment, // BinaryExprNode <op1> = <op2>
addEquals, // BinaryExprNode <op1> += <op2>
subtractEquals, // BinaryExprNode <op1> -= <op2>
multiplyEquals, // BinaryExprNode <op1> *= <op2>
divideEquals, // BinaryExprNode <op1> /= <op2>
moduloEquals, // BinaryExprNode <op1> %= <op2>
leftShiftEquals, // BinaryExprNode <op1> <<= <op2>
rightShiftEquals, // BinaryExprNode <op1> >>= <op2>
logicalRightShiftEquals, // BinaryExprNode <op1> >>>= <op2>
bitwiseAndEquals, // BinaryExprNode <op1> &= <op2>
bitwiseXorEquals, // BinaryExprNode <op1> ^= <op2>
bitwiseOrEquals, // BinaryExprNode <op1> |= <op2>
logicalAndEquals, // BinaryExprNode <op1> &&= <op2>
logicalXorEquals, // BinaryExprNode <op1> ^^= <op2>
logicalOrEquals, // BinaryExprNode <op1> ||= <op2>
conditional, // TernaryExprNode <op1> ? <op2> : <op3>
comma, // BinaryExprNode <op1> , <op2> (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 <expr> ;
block, // BlockStmtNode { <statements> }
group, // BlockStmtNode <attributes> { <statements> }
label, // LabelStmtNode <name> : <stmt>
If, // UnaryStmtNode if ( <expr> ) <stmt>
IfElse, // BinaryStmtNode if ( <expr> ) <stmt> else <stmt2>
Switch, // SwitchStmtNode switch ( <expr> ) <statements>
While, // UnaryStmtNode while ( <expr> ) <stmt>
DoWhile, // UnaryStmtNode do <stmt> while ( <expr> )
With, // UnaryStmtNode with ( <expr> ) <stmt>
For, // ForStmtNode for ( <initializer> ; <expr2> ; <expr3> ) <stmt>
ForIn, // ForStmtNode for ( <initializer> in <expr2> ) <stmt>
Case, // ExprStmtNode case <expr> : or default : (Only occurs directly inside a Switch)
Break, // GoStmtNode break ; or break <name> ;
Continue, // GoStmtNode continue ; or continue <name>;
Return, // ExprStmtNode return ; or return <expr> ;
Throw, // ExprStmtNode throw <expr> ;
Try, // TryStmtNode try <stmt> <catches> <finally>
Export, // ExportStmtNode <attributes> export <bindings> ;
Const, // VariableStmtNode <attributes> const <bindings> ;
Var, // VariableStmtNode <attributes> var <bindings> ;
Function, // FunctionStmtNode <attributes> function <function>
Class, // ClassStmtNode <attributes> class <name> extends <superclass> <body>
Namespace, // NamespaceStmtNode <attributes> namespace <name>
Use, // UseStmtNode use namespace <exprs> ;
Import, // ImportStmtNode import <bindings> ;
Package, // PackageStmtNode package <packageName> <body>
Pragma, // PragmaStmtNode pragma <flags> ;
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 &copyTokenChars(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___ */