зеркало из https://github.com/mozilla/pjs.git
844 строки
31 KiB
C++
844 строки
31 KiB
C++
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
//
|
|
// The contents of this file are subject to the Netscape 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/NPL/
|
|
//
|
|
// Software distributed under the License is distributed on an "AS
|
|
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
|
// 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 Netscape are
|
|
// Copyright (C) 1998 Netscape Communications Corporation. All
|
|
// Rights Reserved.
|
|
|
|
#ifndef parser_h
|
|
#define parser_h
|
|
|
|
#include "utilities.h"
|
|
#include <vector>
|
|
|
|
namespace JavaScript {
|
|
|
|
class StringAtom;
|
|
class World;
|
|
|
|
//
|
|
// Reader
|
|
//
|
|
|
|
// A Reader reads Unicode characters from a source string.
|
|
// Calling get() yields all of the characters in sequence. One character may be read
|
|
// past the end of the source; that character appears as a null.
|
|
class Reader {
|
|
const char16 *begin; // Beginning of source text
|
|
const char16 *p; // Position in source text
|
|
const char16 *end; // End of source text; *end is a null character
|
|
public:
|
|
const String source; // Source text
|
|
const String sourceLocation; // Description of location from which the source text came
|
|
private:
|
|
const uint32 initialLineNum; // One-based number of current line
|
|
std::vector<const char16 *> linePositions; // Array of line starts recorded by beginLine()
|
|
|
|
String *recordString; // String, if any, into which recordChar() records characters; not owned by the Reader
|
|
const char16 *recordBase; // Position of last beginRecording() call
|
|
const char16 *recordPos; // Position of last recordChar() call; nil if a discrepancy occurred
|
|
public:
|
|
|
|
Reader(const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
|
|
private:
|
|
Reader(const Reader&); // No copy constructor
|
|
void operator=(const Reader&); // No assignment operator
|
|
public:
|
|
|
|
char16 get() {ASSERT(p <= end); return *p++;}
|
|
char16 peek() {ASSERT(p <= end); return *p;}
|
|
void unget(uint32 n = 1) {ASSERT(p >= begin + n); p -= n;}
|
|
uint32 getPos() const {return static_cast<uint32>(p - begin);}
|
|
void setPos(uint32 pos) {ASSERT(pos <= getPos()); p = begin + pos;}
|
|
|
|
bool eof() const {ASSERT(p <= end); return p == end;}
|
|
bool peekEof(char16 ch) const {ASSERT(p <= end && *p == ch); return !ch && p == end;} // Faster version. ch is the result of a peek
|
|
bool pastEof() const {return p == end+1;}
|
|
bool getEof(char16 ch) const {ASSERT(p[-1] == ch); return !ch && p == end+1;} // Faster version. ch is the result of a get
|
|
|
|
void beginLine();
|
|
uint32 posToLineNum(uint32 pos) const;
|
|
uint32 getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const;
|
|
|
|
void beginRecording(String &recordString);
|
|
void recordChar(char16 ch);
|
|
String &endRecording();
|
|
|
|
void error(Exception::Kind kind, const String &message, uint32 pos);
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Lexer
|
|
//
|
|
|
|
class Token {
|
|
static const char *const kindNames[];
|
|
public:
|
|
enum Kind { // Keep synchronized with kindNames table
|
|
// Special
|
|
end, // End of token stream
|
|
|
|
number, // Number
|
|
string, // String
|
|
unit, // Unit after number
|
|
regExp, // Regular expression
|
|
|
|
// Punctuators
|
|
openParenthesis, // (
|
|
closeParenthesis, // )
|
|
openBracket, // [
|
|
closeBracket, // ]
|
|
openBrace, // {
|
|
closeBrace, // }
|
|
|
|
comma, // ,
|
|
semicolon, // ;
|
|
dot, // .
|
|
doubleDot, // ..
|
|
tripleDot, // ...
|
|
arrow, // ->
|
|
colon, // :
|
|
doubleColon, // ::
|
|
pound, // #
|
|
at, // @
|
|
|
|
increment, // ++
|
|
decrement, // --
|
|
|
|
complement, // ~
|
|
logicalNot, // !
|
|
|
|
times, // *
|
|
divide, // /
|
|
modulo, // %
|
|
plus, // +
|
|
minus, // -
|
|
leftShift, // <<
|
|
rightShift, // >>
|
|
logicalRightShift, // >>>
|
|
logicalAnd, // &&
|
|
logicalXor, // ^^
|
|
logicalOr, // ||
|
|
bitwiseAnd, // & // These must be at constant offsets from logicalAnd ... logicalOr
|
|
bitwiseXor, // ^
|
|
bitwiseOr, // |
|
|
|
|
assignment, // =
|
|
timesEquals, // *= // These must be at constant offsets from times ... bitwiseOr
|
|
divideEquals, // /=
|
|
moduloEquals, // %=
|
|
plusEquals, // +=
|
|
minusEquals, // -=
|
|
leftShiftEquals, // <<=
|
|
rightShiftEquals, // >>=
|
|
logicalRightShiftEquals, // >>>=
|
|
logicalAndEquals, // &&=
|
|
logicalXorEquals, // ^^=
|
|
logicalOrEquals, // ||=
|
|
bitwiseAndEquals, // &=
|
|
bitwiseXorEquals, // ^=
|
|
bitwiseOrEquals, // |=
|
|
|
|
equal, // ==
|
|
notEqual, // !=
|
|
lessThan, // <
|
|
lessThanOrEqual, // <=
|
|
greaterThan, // > // >, >= must be at constant offsets from <, <=
|
|
greaterThanOrEqual, // >=
|
|
identical, // ===
|
|
notIdentical, // !==
|
|
|
|
question, // ?
|
|
|
|
// Reserved words
|
|
Abstract, // abstract
|
|
Break, // break
|
|
Case, // case
|
|
Catch, // catch
|
|
Class, // class
|
|
Const, // const
|
|
Continue, // continue
|
|
Debugger, // debugger
|
|
Default, // default
|
|
Delete, // delete
|
|
Do, // do
|
|
Else, // else
|
|
Enum, // enum
|
|
Eval, // eval
|
|
Export, // export
|
|
Extends, // extends
|
|
False, // false
|
|
Final, // final
|
|
Finally, // finally
|
|
For, // for
|
|
Function, // function
|
|
Goto, // goto
|
|
If, // if
|
|
Implements, // implements
|
|
Import, // import
|
|
In, // in
|
|
Instanceof, // instanceof
|
|
Native, // native
|
|
New, // new
|
|
Null, // null
|
|
Package, // package
|
|
Private, // private
|
|
Protected, // protected
|
|
Public, // public
|
|
Return, // return
|
|
Static, // static
|
|
Super, // super
|
|
Switch, // switch
|
|
Synchronized, // synchronized
|
|
This, // this
|
|
Throw, // throw
|
|
Throws, // throws
|
|
Transient, // transient
|
|
True, // true
|
|
Try, // try
|
|
Typeof, // typeof
|
|
Var, // var
|
|
Volatile, // volatile
|
|
While, // while
|
|
With, // with
|
|
|
|
// Non-reserved words
|
|
Box, // box
|
|
Constructor, // constructor
|
|
Field, // field
|
|
Get, // get
|
|
Language, // language
|
|
Local, // local
|
|
Method, // method
|
|
Override, // override
|
|
Set, // set
|
|
Version, // version
|
|
|
|
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
|
|
|
|
KindsEnd, // End of token kinds
|
|
KeywordsBegin = Abstract, // Beginning of range of special identifier tokens
|
|
KeywordsEnd = identifier, // End of range of special identifier tokens
|
|
NonReservedBegin = Box, // Beginning of range of non-reserved words
|
|
NonReservedEnd = identifier,// End of range of non-reserved words
|
|
KindsWithCharsBegin = number,// Beginning of range of tokens for which the chars field (below) is valid
|
|
KindsWithCharsEnd = regExp+1// End of range of tokens for which the chars field (below) is valid
|
|
};
|
|
|
|
#define CASE_TOKEN_NONRESERVED \
|
|
Token::Box: \
|
|
case Token::Constructor: \
|
|
case Token::Field: \
|
|
case Token::Get: \
|
|
case Token::Language: \
|
|
case Token::Local: \
|
|
case Token::Method: \
|
|
case Token::Override: \
|
|
case Token::Set: \
|
|
case Token::Version: \
|
|
case Token::identifier
|
|
|
|
private:
|
|
#ifdef DEBUG
|
|
bool valid; // True if this token has been initialized
|
|
#endif
|
|
Kind kind; // The token's kind
|
|
bool lineBreak; // True if line break precedes this token
|
|
uint32 pos; // Source position of this token
|
|
const StringAtom *id; // The token's characters; non-nil for identifiers, keywords, and regular expressions only
|
|
String chars; // The token's characters; valid for strings, units, numbers, and regular expression flags only
|
|
float64 value; // The token's value (numbers only)
|
|
|
|
#ifdef DEBUG
|
|
Token(): valid(false) {}
|
|
#endif
|
|
|
|
public:
|
|
static void initKeywords(World &world);
|
|
static bool isIdentifierKind(Kind kind) {ASSERT(NonReservedEnd == identifier && KindsEnd == identifier+1); return kind >= NonReservedBegin;}
|
|
static bool isSpecialKind(Kind kind) {return kind <= regExp || kind == identifier;}
|
|
static const char *kindName(Kind kind) {ASSERT(uint(kind) < KindsEnd); return kindNames[kind];}
|
|
|
|
Kind getKind() const {ASSERT(valid); return kind;}
|
|
bool hasKind(Kind k) const {ASSERT(valid); return kind == k;}
|
|
bool getLineBreak() const {ASSERT(valid); return lineBreak;}
|
|
uint32 getPos() const {ASSERT(valid); return pos;}
|
|
const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;}
|
|
const String &getChars() const {ASSERT(valid && kind >= KindsWithCharsBegin && kind < KindsWithCharsEnd); return chars;}
|
|
float64 getValue() const {ASSERT(valid && kind == number); return value;}
|
|
|
|
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
|
|
void print(Formatter &f, bool debug = false) const;
|
|
|
|
friend class Lexer;
|
|
};
|
|
|
|
|
|
class Lexer {
|
|
enum {tokenLookahead = 2}; // Number of tokens that can be simultaneously live
|
|
#ifdef DEBUG
|
|
enum {tokenGuard = 10}; // Number of invalid tokens added to circular token buffer to catch references to old tokens
|
|
#else
|
|
enum {tokenGuard = 0}; // Number of invalid tokens added to circular token buffer to catch references to old tokens
|
|
#endif
|
|
enum {tokenBufferSize = tokenLookahead + tokenGuard}; // Token lookahead buffer size
|
|
|
|
Token tokens[tokenBufferSize]; // Circular buffer of recently read or lookahead tokens
|
|
Token *nextToken; // Address of next Token in the circular buffer to be returned by get()
|
|
int nTokensFwd; // Net number of Tokens on which unget() has been called; these Tokens are ahead of nextToken
|
|
#ifdef DEBUG
|
|
int nTokensBack; // Number of Tokens on which unget() can be called; these Tokens are beind nextToken
|
|
bool savedPreferRegExp[tokenBufferSize]; // Circular buffer of saved values of preferRegExp to get() calls
|
|
#endif
|
|
bool lexingUnit; // True if lexing a unit identifier immediately following a number
|
|
public:
|
|
World &world;
|
|
Reader reader;
|
|
|
|
Lexer(World &world, const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
|
|
|
|
const Token &get(bool preferRegExp);
|
|
const Token *eat(bool preferRegExp, Token::Kind kind);
|
|
const Token &peek(bool preferRegExp);
|
|
void redesignate(bool preferRegExp);
|
|
void unget();
|
|
uint32 getPos() const;
|
|
|
|
private:
|
|
void syntaxError(const char *message, uint backUp = 1);
|
|
char16 getChar();
|
|
char16 internalGetChar(char16 ch);
|
|
char16 peekChar();
|
|
char16 internalPeekChar(char16 ch);
|
|
bool testChar(char16 ch);
|
|
|
|
char16 lexEscape(bool unicodeOnly);
|
|
bool lexIdentifier(String &s, bool allowLeadingDigit);
|
|
bool lexNumeral();
|
|
void lexString(String &s, char16 separator);
|
|
void lexRegExp();
|
|
void lexToken(bool preferRegExp);
|
|
};
|
|
|
|
#ifndef DEBUG
|
|
inline void Lexer::redesignate(bool) {}
|
|
#endif
|
|
|
|
// Return the position of the first character of the next token, which must have been peeked.
|
|
inline uint32 Lexer::getPos() const
|
|
{
|
|
ASSERT(nTokensFwd);
|
|
return nextToken->getPos();
|
|
}
|
|
|
|
|
|
//
|
|
// Language Selectors
|
|
//
|
|
|
|
class Language {
|
|
enum {
|
|
minorVersion = 0, // Single BCD digit representing the minor JavaScript version
|
|
minorVersionBits = 4,
|
|
majorVersion = 4, // Single BCD digit representing the major JavaScript version
|
|
majorVersionBits = 4,
|
|
strictSemantics = 8, // True when strict semantics are in use
|
|
strictSyntax = 9, // True when strict syntax is in use
|
|
unknown = 31 // True when language is unknown
|
|
};
|
|
uint32 flags; // Bitmap of flags at locations as above
|
|
};
|
|
|
|
//
|
|
// 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 {
|
|
uint32 pos; // Position of this statement or expression
|
|
|
|
explicit ParseNode(uint32 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 FunctionName {
|
|
enum Prefix {
|
|
normal, // No prefix
|
|
Get, // get
|
|
Set, // set
|
|
New // new
|
|
};
|
|
|
|
Prefix prefix; // The name's prefix, if any
|
|
const StringAtom *name; // The name; nil if omitted
|
|
|
|
FunctionName(): prefix(normal), name(0) {}
|
|
};
|
|
|
|
struct ExprNode;
|
|
struct StmtNode;
|
|
|
|
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
|
|
|
|
VariableBinding(uint32 pos): ParseNode(pos), next(0), name(0), type(0), initializer(0) {}
|
|
};
|
|
|
|
struct FunctionDefinition: FunctionName {
|
|
VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any
|
|
VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none
|
|
VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none
|
|
ExprNode *resultType; // Result type expression or nil if not provided
|
|
StmtNode *body; // Body; nil if none
|
|
};
|
|
|
|
|
|
struct ExprNode: ParseNode {
|
|
enum Kind { // Actual class Operands
|
|
identifier, // IdentifierExprNode <name>
|
|
number, // NumberExprNode <value>
|
|
string, // StringExprNode <str>
|
|
regExp, // RegExpExprNode /<regExp>/<flags>
|
|
Null, // ExprNode null
|
|
True, // ExprNode true
|
|
False, // ExprNode false
|
|
This, // ExprNode this
|
|
Super, // ExprNode super
|
|
|
|
parentheses, // UnaryExprNode (<op>)
|
|
numUnit, // NumUnitExprNode <num> "<str>" or <num><str>
|
|
exprUnit, // ExprUnitExprNode (<op>) "<str>"
|
|
qualifiedIdentifier, // OpIdentifierExprNode <op> :: <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 qualifiedIdentifier
|
|
dotParen, // BinaryExprNode <op1> .( <op2> )
|
|
at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> )
|
|
|
|
Delete, // UnaryExprNode delete <op>
|
|
Typeof, // UnaryExprNode typeof <op>
|
|
Eval, // UnaryExprNode eval <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>
|
|
|
|
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>
|
|
In, // BinaryExprNode <op1> in <op2>
|
|
Instanceof, // BinaryExprNode <op1> instanceof <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
|
|
};
|
|
|
|
private:
|
|
Kind kind; // The node's kind
|
|
public:
|
|
|
|
ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {}
|
|
|
|
Kind getKind() const {return kind;}
|
|
bool hasKind(Kind k) const {return kind == k;}
|
|
|
|
static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualifiedIdentifier;}
|
|
};
|
|
|
|
struct IdentifierExprNode: ExprNode {
|
|
const StringAtom &name; // The identifier
|
|
|
|
IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name):
|
|
ExprNode(pos, kind), name(name) {}
|
|
};
|
|
|
|
struct OpIdentifierExprNode: IdentifierExprNode {
|
|
ExprNode *op; // The namespace expression or indexed expression; non-nil only
|
|
|
|
OpIdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name, ExprNode *op):
|
|
IdentifierExprNode(pos, kind, name), op(op) {ASSERT(op);}
|
|
};
|
|
|
|
struct NumberExprNode: ExprNode {
|
|
float64 value; // The number's value
|
|
|
|
NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {}
|
|
};
|
|
|
|
struct StringExprNode: ExprNode {
|
|
String &str; // The string
|
|
|
|
StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {}
|
|
};
|
|
|
|
struct RegExpExprNode: ExprNode {
|
|
const StringAtom ®Exp; // The regular expression's contents
|
|
String &flags; // The regular expression's flags
|
|
|
|
RegExpExprNode(uint32 pos, Kind kind, const StringAtom ®Exp, String &flags):
|
|
ExprNode(pos, kind), regExp(regExp), flags(flags) {}
|
|
};
|
|
|
|
struct NumUnitExprNode: StringExprNode { // str is the unit string
|
|
String &numStr; // The number's source string
|
|
float64 num; // The number's value
|
|
|
|
NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr):
|
|
StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {}
|
|
};
|
|
|
|
struct ExprUnitExprNode: StringExprNode { // str is the unit string
|
|
ExprNode *op; // The expression to which the unit is applied; non-nil only
|
|
|
|
ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr):
|
|
StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);}
|
|
};
|
|
|
|
struct FunctionExprNode: ExprNode {
|
|
FunctionDefinition function; // Function definition
|
|
|
|
FunctionExprNode(uint32 pos, Kind kind): ExprNode(pos, kind) {}
|
|
};
|
|
|
|
struct ExprList: ArenaObject {
|
|
ExprList *next; // Next expression in linked list
|
|
ExprNode *expr; // Attribute expression; non-nil only
|
|
|
|
explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);}
|
|
};
|
|
|
|
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(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {}
|
|
};
|
|
|
|
struct InvokeExprNode: PairListExprNode {
|
|
ExprNode *op; // The called function, called constructor, or indexed object; non-nil only
|
|
|
|
InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs):
|
|
PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);}
|
|
};
|
|
|
|
struct UnaryExprNode: ExprNode {
|
|
ExprNode *op; // The unary operator's operand; non-nil only
|
|
|
|
UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);}
|
|
};
|
|
|
|
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(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2):
|
|
ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);}
|
|
};
|
|
|
|
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(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3):
|
|
ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);}
|
|
};
|
|
|
|
|
|
|
|
struct StmtNode: ParseNode {
|
|
enum Kind { // Actual class Operands
|
|
empty, // StmtNode ;
|
|
expression, // ExprStmtNode <expr> ;
|
|
block, // BlockStmtNode <attributes> { <statements> }
|
|
label, // LabelStmtNode <label> : <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>
|
|
ForExprIn, // ForExprInStmtNode for ( <varExpr> in <container> ) <stmt>
|
|
ForConstIn, // ForVarInStmtNode for ( const <binding> in <container> ) <stmt>
|
|
ForVarIn, // ForVarInStmtNode for ( var <binding> in <container> ) <stmt>
|
|
Case, // ExprStmtNode case <expr> : or default : // Only occurs directly inside a Switch
|
|
Break, // GoStmtNode break ; or break <label> ;
|
|
Continue, // GoStmtNode continue ; or continue <label> ;
|
|
Return, // ExprStmtNode return ; or return <expr> ;
|
|
Throw, // ExprStmtNode throw <expr> ;
|
|
Try, // TryStmtNode try <stmt> <catches> <finally>
|
|
Const, // VariableStmtNode <attributes> const <bindings> ;
|
|
Var, // VariableStmtNode <attributes> var <bindings> ;
|
|
Function, // FunctionStmtNode <attributes> function <function>
|
|
Class, // ClassStmtNode <attributes> class <name> extends <superclasses> <body>
|
|
Language // LanguageStmtNode language <language> ;
|
|
};
|
|
|
|
Kind kind; // The node's kind
|
|
StmtNode *next; // Next statement in a linked list of statements in this block
|
|
|
|
StmtNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind), next(0) {}
|
|
};
|
|
|
|
struct ExprStmtNode: StmtNode {
|
|
ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements.
|
|
|
|
ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {}
|
|
};
|
|
|
|
struct AttributeStmtNode: StmtNode {
|
|
ExprList *attributes; // Linked list of block or definition's attributes
|
|
|
|
AttributeStmtNode(uint32 pos, Kind kind, ExprList *attributes): StmtNode(pos, kind), attributes(attributes) {}
|
|
};
|
|
|
|
struct BlockStmtNode: AttributeStmtNode {
|
|
StmtNode *statements; // Linked list of block's statements
|
|
|
|
BlockStmtNode(uint32 pos, Kind kind, ExprList *attributes): AttributeStmtNode(pos, kind, attributes) {}
|
|
};
|
|
|
|
struct LabelStmtNode: StmtNode {
|
|
const StringAtom &label; // The label
|
|
StmtNode *stmt; // Labeled statement; non-nil only
|
|
|
|
LabelStmtNode(uint32 pos, Kind kind, const StringAtom &label, StmtNode *stmt):
|
|
StmtNode(pos, kind), label(label), stmt(stmt) {ASSERT(stmt);}
|
|
};
|
|
|
|
struct UnaryStmtNode: ExprStmtNode {
|
|
StmtNode *stmt; // First substatement; non-nil only
|
|
|
|
UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt):
|
|
ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);}
|
|
};
|
|
|
|
struct BinaryStmtNode: UnaryStmtNode {
|
|
StmtNode *stmt2; // Second substatement; non-nil only
|
|
|
|
BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2):
|
|
UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);}
|
|
};
|
|
|
|
struct ForStmtNode: StmtNode {
|
|
StmtNode *initializer; // First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const.
|
|
ExprNode *expr2; // Second item in parentheses; nil if not provided
|
|
ExprNode *expr3; // Third item in parentheses; nil if not provided
|
|
StmtNode *stmt; // Substatement; non-nil only
|
|
|
|
ForStmtNode(uint32 pos, Kind kind, StmtNode *stmt):
|
|
StmtNode(pos, kind), stmt(stmt) {ASSERT(stmt);}
|
|
};
|
|
|
|
struct ForInStmtNode: StmtNode {
|
|
ExprNode *container; // Subexpression after 'in'; non-nil only
|
|
StmtNode *stmt; // Substatement; non-nil only
|
|
|
|
ForInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt):
|
|
StmtNode(pos, kind), container(container), stmt(stmt) {ASSERT(container && stmt);}
|
|
};
|
|
|
|
struct ForExprInStmtNode: ForInStmtNode {
|
|
ExprNode *varExpr; // Subexpression before 'in'; non-nil only
|
|
|
|
ForExprInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, ExprNode *varExpr):
|
|
ForInStmtNode(pos, kind, container, stmt), varExpr(varExpr) {ASSERT(varExpr);}
|
|
};
|
|
|
|
struct ForVarInStmtNode: ForInStmtNode {
|
|
VariableBinding *binding; // Var or const binding before 'in'; non-nil only
|
|
|
|
ForVarInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, VariableBinding *binding):
|
|
ForInStmtNode(pos, kind, container, stmt), binding(binding) {ASSERT(binding);}
|
|
};
|
|
|
|
struct SwitchStmtNode: ExprStmtNode {
|
|
StmtNode *statements; // Linked list of switch block's statements, which may include Case and Default statements
|
|
|
|
SwitchStmtNode(uint32 pos, Kind kind, ExprNode *expr):
|
|
ExprStmtNode(pos, kind, expr) {}
|
|
};
|
|
|
|
struct GoStmtNode: StmtNode {
|
|
const StringAtom *label; // The label; nil if none
|
|
|
|
GoStmtNode(uint32 pos, Kind kind, const StringAtom *label): StmtNode(pos, kind), label(label) {}
|
|
};
|
|
|
|
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
|
|
StmtNode *stmt; // The catch clause's body; non-nil only
|
|
|
|
CatchClause(uint32 pos, const StringAtom &name, ExprNode *type, StmtNode *stmt):
|
|
ParseNode(pos), next(0), name(name), type(type), 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(uint32 pos, Kind kind, StmtNode *stmt, CatchClause *catches, StmtNode *finally):
|
|
StmtNode(pos, kind), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);}
|
|
};
|
|
|
|
struct VariableStmtNode: AttributeStmtNode {
|
|
VariableBinding *bindings; // Linked list of variable bindings
|
|
|
|
VariableStmtNode(uint32 pos, Kind kind, ExprList *attributes): AttributeStmtNode(pos, kind, attributes) {}
|
|
};
|
|
|
|
struct FunctionStmtNode: AttributeStmtNode {
|
|
FunctionDefinition function; // Function definition
|
|
|
|
FunctionStmtNode(uint32 pos, Kind kind, ExprList *attributes): AttributeStmtNode(pos, kind, attributes) {}
|
|
};
|
|
|
|
struct ClassStmtNode: AttributeStmtNode {
|
|
const StringAtom &name; // The class's name
|
|
ExprList *superclasses; // Linked list of superclass expressions
|
|
StmtNode *body; // The class's body; non-nil only
|
|
|
|
ClassStmtNode(uint32 pos, Kind kind, ExprList *attributes, const StringAtom &name, ExprList *superclasses,
|
|
StmtNode *body):
|
|
AttributeStmtNode(pos, kind, attributes), name(name), superclasses(superclasses), body(body) {ASSERT(body);}
|
|
};
|
|
|
|
struct LanguageStmtNode: StmtNode {
|
|
JavaScript::Language language; // The selected language
|
|
|
|
LanguageStmtNode(uint32 pos, Kind kind, JavaScript::Language language):
|
|
StmtNode(pos, kind), language(language) {}
|
|
};
|
|
|
|
|
|
class Parser {
|
|
public:
|
|
Lexer lexer;
|
|
Arena &arena;
|
|
|
|
Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
|
|
|
|
private:
|
|
Reader &getReader() {return lexer.reader;}
|
|
World &getWorld() {return lexer.world;}
|
|
|
|
void syntaxError(const char *message, uint backUp = 1);
|
|
void syntaxError(const String &message, uint backUp = 1);
|
|
const Token &require(bool preferRegExp, Token::Kind kind);
|
|
String ©TokenChars(const Token &t);
|
|
|
|
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers);
|
|
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers);
|
|
IdentifierExprNode *parseQualifiedIdentifier(const Token &t);
|
|
PairListExprNode *parseArrayLiteral(const Token &initialToken);
|
|
PairListExprNode *parseObjectLiteral(const Token &initialToken);
|
|
ExprNode *parsePrimaryExpression();
|
|
BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind);
|
|
InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind);
|
|
public:
|
|
ExprNode *parsePostfixExpression(bool newExpression = false);
|
|
ExprNode *parseNonAssignmentExpression(bool noIn);
|
|
ExprNode *parseAssignmentExpression(bool noIn);
|
|
ExprNode *parseExpression(bool noIn);
|
|
};
|
|
}
|
|
#endif
|