Added expression parsing and printing code

This commit is contained in:
waldemar%netscape.com 2000-05-12 03:26:24 +00:00
parent f240e58708
commit 66582beffd
4 changed files with 1784 additions and 428 deletions

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ namespace JavaScript {
const char16 *p; // Position in source text const char16 *p; // Position in source text
const char16 *end; // End of source text; *end is a null character const char16 *end; // End of source text; *end is a null character
public: public:
String source; // Source text const String source; // Source text
const String sourceLocation; // Description of location from which the source text came const String sourceLocation; // Description of location from which the source text came
private: private:
const uint32 initialLineNum; // One-based number of current line const uint32 initialLineNum; // One-based number of current line
@ -85,10 +85,13 @@ namespace JavaScript {
// Lexer // Lexer
// //
void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote);
void quoteString(Formatter &f, const String &s, char16 quote);
class Token { class Token {
static const char *const kindNames[];
public: public:
enum Kind { // Keep synchronized with kindNames table enum Kind { // Keep synchronized with kindNames and tokenBinaryOperatorInfos tables
// Special // Special
end, // End of token stream end, // End of token stream
@ -217,42 +220,42 @@ namespace JavaScript {
With, // with With, // with
// Non-reserved words // Non-reserved words
Box, // box Attribute, // attribute
Constructor, // constructor Constructor, // constructor
Field, // field
Get, // get Get, // get
Language, // language Language, // language
Local, // local Local, // local
Method, // method Namespace, // namespace
Override, // override Override, // override
Set, // set Set, // set
Version, // version Use, // use
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code) identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
KindsEnd, // End of token kinds kindsEnd, // End of token kinds
KeywordsBegin = Abstract, // Beginning of range of special identifier tokens keywordsBegin = Abstract, // Beginning of range of special identifier tokens
KeywordsEnd = identifier, // End of range of special identifier tokens keywordsEnd = identifier, // End of range of special identifier tokens
NonReservedBegin = Box, // Beginning of range of non-reserved words nonreservedBegin = Attribute,// Beginning of range of non-reserved words
NonReservedEnd = identifier,// End 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 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 kindsWithCharsEnd = regExp+1// End of range of tokens for which the chars field (below) is valid
}; };
#define CASE_TOKEN_NONRESERVED \ #define CASE_TOKEN_NONRESERVED \
Token::Box: \ Token::Attribute: \
case Token::Constructor: \ case Token::Constructor: \
case Token::Field: \
case Token::Get: \ case Token::Get: \
case Token::Language: \ case Token::Language: \
case Token::Local: \ case Token::Local: \
case Token::Method: \ case Token::Namespace: \
case Token::Override: \ case Token::Override: \
case Token::Set: \ case Token::Set: \
case Token::Version: \ case Token::Use: \
case Token::identifier case Token::identifier
private: private:
static const char *const kindNames[kindsEnd];
#ifdef DEBUG #ifdef DEBUG
bool valid; // True if this token has been initialized bool valid; // True if this token has been initialized
#endif #endif
@ -269,16 +272,16 @@ namespace JavaScript {
public: public:
static void initKeywords(World &world); static void initKeywords(World &world);
static bool isIdentifierKind(Kind kind) {ASSERT(NonReservedEnd == identifier && KindsEnd == identifier+1); return kind >= NonReservedBegin;} 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 bool isSpecialKind(Kind kind) {return kind <= regExp || kind == identifier;}
static const char *kindName(Kind kind) {ASSERT(uint(kind) < KindsEnd); return kindNames[kind];} static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
Kind getKind() const {ASSERT(valid); return kind;} Kind getKind() const {ASSERT(valid); return kind;}
bool hasKind(Kind k) const {ASSERT(valid); return kind == k;} bool hasKind(Kind k) const {ASSERT(valid); return kind == k;}
bool getLineBreak() const {ASSERT(valid); return lineBreak;} bool getLineBreak() const {ASSERT(valid); return lineBreak;}
uint32 getPos() const {ASSERT(valid); return pos;} uint32 getPos() const {ASSERT(valid); return pos;}
const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;} const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;}
const String &getChars() const {ASSERT(valid && kind >= KindsWithCharsBegin && kind < KindsWithCharsEnd); return chars;} const String &getChars() const {ASSERT(valid && kind >= kindsWithCharsBegin && kind < kindsWithCharsEnd); return chars;}
float64 getValue() const {ASSERT(valid && kind == number); return value;} float64 getValue() const {ASSERT(valid && kind == number); return value;}
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
@ -434,7 +437,8 @@ namespace JavaScript {
struct ExprNode: ParseNode { struct ExprNode: ParseNode {
enum Kind { // Actual class Operands enum Kind { // Actual class Operands // Keep synchronized with kindNames
none,
identifier, // IdentifierExprNode <name> identifier, // IdentifierExprNode <name>
number, // NumberExprNode <value> number, // NumberExprNode <value>
string, // StringExprNode <str> string, // StringExprNode <str>
@ -444,12 +448,15 @@ namespace JavaScript {
False, // ExprNode false False, // ExprNode false
This, // ExprNode this This, // ExprNode this
Super, // ExprNode super Super, // ExprNode super
Public, // ExprNode public
Package, // ExprNode package
Private, // ExprNode private
parentheses, // UnaryExprNode (<op>) parentheses, // UnaryExprNode (<op>)
numUnit, // NumUnitExprNode <num> "<str>" or <num><str> numUnit, // NumUnitExprNode <num> "<str>" or <num><str>
exprUnit, // ExprUnitExprNode (<op>) "<str>" exprUnit, // ExprUnitExprNode (<op>) "<str>"
qualifiedIdentifier, // OpIdentifierExprNode <op> :: <name> qualify, // BinaryExprNode <op1> :: <op2> (right-associative: a::b::c represented as a::(b::c))
objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>} objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>}
arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>] arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>]
functionLiteral, // FunctionExprNode function <function> functionLiteral, // FunctionExprNode function <function>
@ -458,11 +465,11 @@ namespace JavaScript {
New, // InvokeExprNode new <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>] index, // InvokeExprNode <op>[<field>:<value>, <field>:<value>, ..., <field>:<value>]
dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualifiedIdentifier dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualify
dotParen, // BinaryExprNode <op1> .( <op2> ) dotParen, // BinaryExprNode <op1> .( <op2> )
at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> ) at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> )
Delete, // UnaryExprNode delete <op> Delete, // UnaryExprNode delete <op> // Begin of isUnaryKind()
Typeof, // UnaryExprNode typeof <op> Typeof, // UnaryExprNode typeof <op>
Eval, // UnaryExprNode eval <op> Eval, // UnaryExprNode eval <op>
preIncrement, // UnaryExprNode ++ <op> preIncrement, // UnaryExprNode ++ <op>
@ -472,7 +479,7 @@ namespace JavaScript {
plus, // UnaryExprNode + <op> plus, // UnaryExprNode + <op>
minus, // UnaryExprNode - <op> minus, // UnaryExprNode - <op>
complement, // UnaryExprNode ~ <op> complement, // UnaryExprNode ~ <op>
logicalNot, // UnaryExprNode ! <op> logicalNot, // UnaryExprNode ! <op> // End of isUnaryKind()
add, // BinaryExprNode <op1> + <op2> add, // BinaryExprNode <op1> + <op2>
subtract, // BinaryExprNode <op1> - <op2> subtract, // BinaryExprNode <op1> - <op2>
@ -500,7 +507,7 @@ namespace JavaScript {
In, // BinaryExprNode <op1> in <op2> In, // BinaryExprNode <op1> in <op2>
Instanceof, // BinaryExprNode <op1> instanceof <op2> Instanceof, // BinaryExprNode <op1> instanceof <op2>
assignment, // BinaryExprNode <op1> = <op2> assignment, // BinaryExprNode <op1> = <op2> // Begin of isAssigningKind()
addEquals, // BinaryExprNode <op1> += <op2> addEquals, // BinaryExprNode <op1> += <op2>
subtractEquals, // BinaryExprNode <op1> -= <op2> subtractEquals, // BinaryExprNode <op1> -= <op2>
multiplyEquals, // BinaryExprNode <op1> *= <op2> multiplyEquals, // BinaryExprNode <op1> *= <op2>
@ -514,14 +521,17 @@ namespace JavaScript {
bitwiseOrEquals, // BinaryExprNode <op1> |= <op2> bitwiseOrEquals, // BinaryExprNode <op1> |= <op2>
logicalAndEquals, // BinaryExprNode <op1> &&= <op2> logicalAndEquals, // BinaryExprNode <op1> &&= <op2>
logicalXorEquals, // BinaryExprNode <op1> ^^= <op2> logicalXorEquals, // BinaryExprNode <op1> ^^= <op2>
logicalOrEquals, // BinaryExprNode <op1> ||= <op2> logicalOrEquals, // BinaryExprNode <op1> ||= <op2> // End of isAssigningKind()
conditional, // TernaryExprNode <op1> ? <op2> : <op3> conditional, // TernaryExprNode <op1> ? <op2> : <op3>
comma // BinaryExprNode <op1> , <op2> // Comma expressions only comma, // BinaryExprNode <op1> , <op2> // Comma expressions only
kindsEnd
}; };
private: private:
Kind kind; // The node's kind Kind kind; // The node's kind
static const char *const kindNames[kindsEnd];
public: public:
ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {}
@ -529,33 +539,41 @@ namespace JavaScript {
Kind getKind() const {return kind;} Kind getKind() const {return kind;}
bool hasKind(Kind k) const {return kind == k;} bool hasKind(Kind k) const {return kind == k;}
static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualifiedIdentifier;} static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualify;}
static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;}
static bool isUnaryKind(Kind kind) {return kind >= Delete && kind <= logicalNot;}
static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
virtual void print(PrettyPrinter &f) const;
}; };
// Print e onto f.
inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) {ASSERT(e); e->print(f); return f;}
struct IdentifierExprNode: ExprNode { struct IdentifierExprNode: ExprNode {
const StringAtom &name; // The identifier const StringAtom &name; // The identifier
IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name): IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name):
ExprNode(pos, kind), name(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): void print(PrettyPrinter &f) const;
IdentifierExprNode(pos, kind, name), op(op) {ASSERT(op);}
}; };
struct NumberExprNode: ExprNode { struct NumberExprNode: ExprNode {
float64 value; // The number's value float64 value; // The number's value
NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {} NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {}
void print(PrettyPrinter &f) const;
}; };
struct StringExprNode: ExprNode { struct StringExprNode: ExprNode {
String &str; // The string String &str; // The string
StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {} StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {}
void print(PrettyPrinter &f) const;
}; };
struct RegExpExprNode: ExprNode { struct RegExpExprNode: ExprNode {
@ -564,6 +582,8 @@ namespace JavaScript {
RegExpExprNode(uint32 pos, Kind kind, const StringAtom &regExp, String &flags): RegExpExprNode(uint32 pos, Kind kind, const StringAtom &regExp, String &flags):
ExprNode(pos, kind), regExp(regExp), flags(flags) {} ExprNode(pos, kind), regExp(regExp), flags(flags) {}
void print(PrettyPrinter &f) const;
}; };
struct NumUnitExprNode: StringExprNode { // str is the unit string struct NumUnitExprNode: StringExprNode { // str is the unit string
@ -572,6 +592,8 @@ namespace JavaScript {
NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr): NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr):
StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {}
void print(PrettyPrinter &f) const;
}; };
struct ExprUnitExprNode: StringExprNode { // str is the unit string struct ExprUnitExprNode: StringExprNode { // str is the unit string
@ -579,12 +601,16 @@ namespace JavaScript {
ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr): ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr):
StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct FunctionExprNode: ExprNode { struct FunctionExprNode: ExprNode {
FunctionDefinition function; // Function definition FunctionDefinition function; // Function definition
FunctionExprNode(uint32 pos, Kind kind): ExprNode(pos, kind) {} FunctionExprNode(uint32 pos, Kind kind): ExprNode(pos, kind) {}
void print(PrettyPrinter &f) const;
}; };
struct ExprList: ArenaObject { struct ExprList: ArenaObject {
@ -606,6 +632,8 @@ namespace JavaScript {
ExprPairList *pairs; // Linked list of pairs ExprPairList *pairs; // Linked list of pairs
PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {} PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {}
void print(PrettyPrinter &f) const;
}; };
struct InvokeExprNode: PairListExprNode { struct InvokeExprNode: PairListExprNode {
@ -613,12 +641,16 @@ namespace JavaScript {
InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs):
PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);} PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct UnaryExprNode: ExprNode { struct UnaryExprNode: ExprNode {
ExprNode *op; // The unary operator's operand; non-nil only ExprNode *op; // The unary operator's operand; non-nil only
UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);} UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct BinaryExprNode: ExprNode { struct BinaryExprNode: ExprNode {
@ -627,6 +659,8 @@ namespace JavaScript {
BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2): BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2):
ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);}
void print(PrettyPrinter &f) const;
}; };
struct TernaryExprNode: ExprNode { struct TernaryExprNode: ExprNode {
@ -636,6 +670,8 @@ namespace JavaScript {
TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3): TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3):
ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);} ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);}
void print(PrettyPrinter &f) const;
}; };
@ -827,17 +863,47 @@ namespace JavaScript {
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers); ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers);
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers); ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers);
IdentifierExprNode *parseQualifiedIdentifier(const Token &t); ExprNode *parseQualifiedIdentifier(const Token &t);
PairListExprNode *parseArrayLiteral(const Token &initialToken); PairListExprNode *parseArrayLiteral(const Token &initialToken);
PairListExprNode *parseObjectLiteral(const Token &initialToken); PairListExprNode *parseObjectLiteral(const Token &initialToken);
ExprNode *parsePrimaryExpression(); ExprNode *parsePrimaryExpression();
BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind); 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); InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind);
public:
ExprNode *parsePostfixExpression(bool newExpression = false); ExprNode *parsePostfixExpression(bool newExpression = false);
ExprNode *parseNonAssignmentExpression(bool noIn); ExprNode *parseUnaryExpression();
ExprNode *parseAssignmentExpression(bool noIn);
ExprNode *parseExpression(bool noIn); enum Precedence {
pNone, // End tag
pExpression, // Expression
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
};
static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd];
struct StackedSubexpression;
public:
ExprNode *parseExpression(bool noIn, bool noAssignment = false, bool noComma = false);
ExprNode *parseNonAssignmentExpression(bool noIn) {return parseExpression(noIn, true, true);}
ExprNode *parseAssignmentExpression(bool noIn) {return parseExpression(noIn, false, true);}
}; };
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ namespace JavaScript {
const char16 *p; // Position in source text const char16 *p; // Position in source text
const char16 *end; // End of source text; *end is a null character const char16 *end; // End of source text; *end is a null character
public: public:
String source; // Source text const String source; // Source text
const String sourceLocation; // Description of location from which the source text came const String sourceLocation; // Description of location from which the source text came
private: private:
const uint32 initialLineNum; // One-based number of current line const uint32 initialLineNum; // One-based number of current line
@ -85,10 +85,13 @@ namespace JavaScript {
// Lexer // Lexer
// //
void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote);
void quoteString(Formatter &f, const String &s, char16 quote);
class Token { class Token {
static const char *const kindNames[];
public: public:
enum Kind { // Keep synchronized with kindNames table enum Kind { // Keep synchronized with kindNames and tokenBinaryOperatorInfos tables
// Special // Special
end, // End of token stream end, // End of token stream
@ -217,42 +220,42 @@ namespace JavaScript {
With, // with With, // with
// Non-reserved words // Non-reserved words
Box, // box Attribute, // attribute
Constructor, // constructor Constructor, // constructor
Field, // field
Get, // get Get, // get
Language, // language Language, // language
Local, // local Local, // local
Method, // method Namespace, // namespace
Override, // override Override, // override
Set, // set Set, // set
Version, // version Use, // use
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code) identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
KindsEnd, // End of token kinds kindsEnd, // End of token kinds
KeywordsBegin = Abstract, // Beginning of range of special identifier tokens keywordsBegin = Abstract, // Beginning of range of special identifier tokens
KeywordsEnd = identifier, // End of range of special identifier tokens keywordsEnd = identifier, // End of range of special identifier tokens
NonReservedBegin = Box, // Beginning of range of non-reserved words nonreservedBegin = Attribute,// Beginning of range of non-reserved words
NonReservedEnd = identifier,// End 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 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 kindsWithCharsEnd = regExp+1// End of range of tokens for which the chars field (below) is valid
}; };
#define CASE_TOKEN_NONRESERVED \ #define CASE_TOKEN_NONRESERVED \
Token::Box: \ Token::Attribute: \
case Token::Constructor: \ case Token::Constructor: \
case Token::Field: \
case Token::Get: \ case Token::Get: \
case Token::Language: \ case Token::Language: \
case Token::Local: \ case Token::Local: \
case Token::Method: \ case Token::Namespace: \
case Token::Override: \ case Token::Override: \
case Token::Set: \ case Token::Set: \
case Token::Version: \ case Token::Use: \
case Token::identifier case Token::identifier
private: private:
static const char *const kindNames[kindsEnd];
#ifdef DEBUG #ifdef DEBUG
bool valid; // True if this token has been initialized bool valid; // True if this token has been initialized
#endif #endif
@ -269,16 +272,16 @@ namespace JavaScript {
public: public:
static void initKeywords(World &world); static void initKeywords(World &world);
static bool isIdentifierKind(Kind kind) {ASSERT(NonReservedEnd == identifier && KindsEnd == identifier+1); return kind >= NonReservedBegin;} 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 bool isSpecialKind(Kind kind) {return kind <= regExp || kind == identifier;}
static const char *kindName(Kind kind) {ASSERT(uint(kind) < KindsEnd); return kindNames[kind];} static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
Kind getKind() const {ASSERT(valid); return kind;} Kind getKind() const {ASSERT(valid); return kind;}
bool hasKind(Kind k) const {ASSERT(valid); return kind == k;} bool hasKind(Kind k) const {ASSERT(valid); return kind == k;}
bool getLineBreak() const {ASSERT(valid); return lineBreak;} bool getLineBreak() const {ASSERT(valid); return lineBreak;}
uint32 getPos() const {ASSERT(valid); return pos;} uint32 getPos() const {ASSERT(valid); return pos;}
const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;} const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;}
const String &getChars() const {ASSERT(valid && kind >= KindsWithCharsBegin && kind < KindsWithCharsEnd); return chars;} const String &getChars() const {ASSERT(valid && kind >= kindsWithCharsBegin && kind < kindsWithCharsEnd); return chars;}
float64 getValue() const {ASSERT(valid && kind == number); return value;} float64 getValue() const {ASSERT(valid && kind == number); return value;}
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
@ -434,7 +437,8 @@ namespace JavaScript {
struct ExprNode: ParseNode { struct ExprNode: ParseNode {
enum Kind { // Actual class Operands enum Kind { // Actual class Operands // Keep synchronized with kindNames
none,
identifier, // IdentifierExprNode <name> identifier, // IdentifierExprNode <name>
number, // NumberExprNode <value> number, // NumberExprNode <value>
string, // StringExprNode <str> string, // StringExprNode <str>
@ -444,12 +448,15 @@ namespace JavaScript {
False, // ExprNode false False, // ExprNode false
This, // ExprNode this This, // ExprNode this
Super, // ExprNode super Super, // ExprNode super
Public, // ExprNode public
Package, // ExprNode package
Private, // ExprNode private
parentheses, // UnaryExprNode (<op>) parentheses, // UnaryExprNode (<op>)
numUnit, // NumUnitExprNode <num> "<str>" or <num><str> numUnit, // NumUnitExprNode <num> "<str>" or <num><str>
exprUnit, // ExprUnitExprNode (<op>) "<str>" exprUnit, // ExprUnitExprNode (<op>) "<str>"
qualifiedIdentifier, // OpIdentifierExprNode <op> :: <name> qualify, // BinaryExprNode <op1> :: <op2> (right-associative: a::b::c represented as a::(b::c))
objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>} objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>}
arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>] arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>]
functionLiteral, // FunctionExprNode function <function> functionLiteral, // FunctionExprNode function <function>
@ -458,11 +465,11 @@ namespace JavaScript {
New, // InvokeExprNode new <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>] index, // InvokeExprNode <op>[<field>:<value>, <field>:<value>, ..., <field>:<value>]
dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualifiedIdentifier dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualify
dotParen, // BinaryExprNode <op1> .( <op2> ) dotParen, // BinaryExprNode <op1> .( <op2> )
at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> ) at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> )
Delete, // UnaryExprNode delete <op> Delete, // UnaryExprNode delete <op> // Begin of isUnaryKind()
Typeof, // UnaryExprNode typeof <op> Typeof, // UnaryExprNode typeof <op>
Eval, // UnaryExprNode eval <op> Eval, // UnaryExprNode eval <op>
preIncrement, // UnaryExprNode ++ <op> preIncrement, // UnaryExprNode ++ <op>
@ -472,7 +479,7 @@ namespace JavaScript {
plus, // UnaryExprNode + <op> plus, // UnaryExprNode + <op>
minus, // UnaryExprNode - <op> minus, // UnaryExprNode - <op>
complement, // UnaryExprNode ~ <op> complement, // UnaryExprNode ~ <op>
logicalNot, // UnaryExprNode ! <op> logicalNot, // UnaryExprNode ! <op> // End of isUnaryKind()
add, // BinaryExprNode <op1> + <op2> add, // BinaryExprNode <op1> + <op2>
subtract, // BinaryExprNode <op1> - <op2> subtract, // BinaryExprNode <op1> - <op2>
@ -500,7 +507,7 @@ namespace JavaScript {
In, // BinaryExprNode <op1> in <op2> In, // BinaryExprNode <op1> in <op2>
Instanceof, // BinaryExprNode <op1> instanceof <op2> Instanceof, // BinaryExprNode <op1> instanceof <op2>
assignment, // BinaryExprNode <op1> = <op2> assignment, // BinaryExprNode <op1> = <op2> // Begin of isAssigningKind()
addEquals, // BinaryExprNode <op1> += <op2> addEquals, // BinaryExprNode <op1> += <op2>
subtractEquals, // BinaryExprNode <op1> -= <op2> subtractEquals, // BinaryExprNode <op1> -= <op2>
multiplyEquals, // BinaryExprNode <op1> *= <op2> multiplyEquals, // BinaryExprNode <op1> *= <op2>
@ -514,14 +521,17 @@ namespace JavaScript {
bitwiseOrEquals, // BinaryExprNode <op1> |= <op2> bitwiseOrEquals, // BinaryExprNode <op1> |= <op2>
logicalAndEquals, // BinaryExprNode <op1> &&= <op2> logicalAndEquals, // BinaryExprNode <op1> &&= <op2>
logicalXorEquals, // BinaryExprNode <op1> ^^= <op2> logicalXorEquals, // BinaryExprNode <op1> ^^= <op2>
logicalOrEquals, // BinaryExprNode <op1> ||= <op2> logicalOrEquals, // BinaryExprNode <op1> ||= <op2> // End of isAssigningKind()
conditional, // TernaryExprNode <op1> ? <op2> : <op3> conditional, // TernaryExprNode <op1> ? <op2> : <op3>
comma // BinaryExprNode <op1> , <op2> // Comma expressions only comma, // BinaryExprNode <op1> , <op2> // Comma expressions only
kindsEnd
}; };
private: private:
Kind kind; // The node's kind Kind kind; // The node's kind
static const char *const kindNames[kindsEnd];
public: public:
ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {}
@ -529,33 +539,41 @@ namespace JavaScript {
Kind getKind() const {return kind;} Kind getKind() const {return kind;}
bool hasKind(Kind k) const {return kind == k;} bool hasKind(Kind k) const {return kind == k;}
static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualifiedIdentifier;} static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualify;}
static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;}
static bool isUnaryKind(Kind kind) {return kind >= Delete && kind <= logicalNot;}
static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
virtual void print(PrettyPrinter &f) const;
}; };
// Print e onto f.
inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) {ASSERT(e); e->print(f); return f;}
struct IdentifierExprNode: ExprNode { struct IdentifierExprNode: ExprNode {
const StringAtom &name; // The identifier const StringAtom &name; // The identifier
IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name): IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name):
ExprNode(pos, kind), name(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): void print(PrettyPrinter &f) const;
IdentifierExprNode(pos, kind, name), op(op) {ASSERT(op);}
}; };
struct NumberExprNode: ExprNode { struct NumberExprNode: ExprNode {
float64 value; // The number's value float64 value; // The number's value
NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {} NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {}
void print(PrettyPrinter &f) const;
}; };
struct StringExprNode: ExprNode { struct StringExprNode: ExprNode {
String &str; // The string String &str; // The string
StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {} StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {}
void print(PrettyPrinter &f) const;
}; };
struct RegExpExprNode: ExprNode { struct RegExpExprNode: ExprNode {
@ -564,6 +582,8 @@ namespace JavaScript {
RegExpExprNode(uint32 pos, Kind kind, const StringAtom &regExp, String &flags): RegExpExprNode(uint32 pos, Kind kind, const StringAtom &regExp, String &flags):
ExprNode(pos, kind), regExp(regExp), flags(flags) {} ExprNode(pos, kind), regExp(regExp), flags(flags) {}
void print(PrettyPrinter &f) const;
}; };
struct NumUnitExprNode: StringExprNode { // str is the unit string struct NumUnitExprNode: StringExprNode { // str is the unit string
@ -572,6 +592,8 @@ namespace JavaScript {
NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr): NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr):
StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {}
void print(PrettyPrinter &f) const;
}; };
struct ExprUnitExprNode: StringExprNode { // str is the unit string struct ExprUnitExprNode: StringExprNode { // str is the unit string
@ -579,12 +601,16 @@ namespace JavaScript {
ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr): ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr):
StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct FunctionExprNode: ExprNode { struct FunctionExprNode: ExprNode {
FunctionDefinition function; // Function definition FunctionDefinition function; // Function definition
FunctionExprNode(uint32 pos, Kind kind): ExprNode(pos, kind) {} FunctionExprNode(uint32 pos, Kind kind): ExprNode(pos, kind) {}
void print(PrettyPrinter &f) const;
}; };
struct ExprList: ArenaObject { struct ExprList: ArenaObject {
@ -606,6 +632,8 @@ namespace JavaScript {
ExprPairList *pairs; // Linked list of pairs ExprPairList *pairs; // Linked list of pairs
PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {} PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {}
void print(PrettyPrinter &f) const;
}; };
struct InvokeExprNode: PairListExprNode { struct InvokeExprNode: PairListExprNode {
@ -613,12 +641,16 @@ namespace JavaScript {
InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs):
PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);} PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct UnaryExprNode: ExprNode { struct UnaryExprNode: ExprNode {
ExprNode *op; // The unary operator's operand; non-nil only ExprNode *op; // The unary operator's operand; non-nil only
UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);} UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);}
void print(PrettyPrinter &f) const;
}; };
struct BinaryExprNode: ExprNode { struct BinaryExprNode: ExprNode {
@ -627,6 +659,8 @@ namespace JavaScript {
BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2): BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2):
ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);}
void print(PrettyPrinter &f) const;
}; };
struct TernaryExprNode: ExprNode { struct TernaryExprNode: ExprNode {
@ -636,6 +670,8 @@ namespace JavaScript {
TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3): TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3):
ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);} ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);}
void print(PrettyPrinter &f) const;
}; };
@ -827,17 +863,47 @@ namespace JavaScript {
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers); ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers);
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers); ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers);
IdentifierExprNode *parseQualifiedIdentifier(const Token &t); ExprNode *parseQualifiedIdentifier(const Token &t);
PairListExprNode *parseArrayLiteral(const Token &initialToken); PairListExprNode *parseArrayLiteral(const Token &initialToken);
PairListExprNode *parseObjectLiteral(const Token &initialToken); PairListExprNode *parseObjectLiteral(const Token &initialToken);
ExprNode *parsePrimaryExpression(); ExprNode *parsePrimaryExpression();
BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind); 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); InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind);
public:
ExprNode *parsePostfixExpression(bool newExpression = false); ExprNode *parsePostfixExpression(bool newExpression = false);
ExprNode *parseNonAssignmentExpression(bool noIn); ExprNode *parseUnaryExpression();
ExprNode *parseAssignmentExpression(bool noIn);
ExprNode *parseExpression(bool noIn); enum Precedence {
pNone, // End tag
pExpression, // Expression
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
};
static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd];
struct StackedSubexpression;
public:
ExprNode *parseExpression(bool noIn, bool noAssignment = false, bool noComma = false);
ExprNode *parseNonAssignmentExpression(bool noIn) {return parseExpression(noIn, true, true);}
ExprNode *parseAssignmentExpression(bool noIn) {return parseExpression(noIn, false, true);}
}; };
} }
#endif #endif