944 lines
43 KiB
C++
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 ©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___ */
|