Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

4621 lines (3922 sloc) 150.447 kB
/* -*- Mode: js; js-indent-level: 4; -*- */
/*
* LLJS port of esprima
Copyright (C) 2012 Stephen Crane <culda.rinon@gmail.com>
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*jslint bitwise:true plusplus:true */
/*global esprima:true, exports:true,
throwError: true, createLiteral: true, generateStatement: true,
parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
parseFunctionDeclaration: true, parseFunctionExpression: true,
parseFunctionSourceElements: true, parseVariableIdentifier: true,
parseLeftHandSideExpression: true,
parseStatement: true, parseSourceElement: true */
extern console;
extern RegExp, Error, String, parseInt, parseFloat, Array, Object, esprima, process, memory;
typedef dyn dyn_func();
typedef dyn dyn2dyn(dyn);
typedef dyn2dyn dyn2dyn2dyn(dyn);
typedef byte *malloc_ty(uint);
let malloc_ty malloc;
if (typeof process !== "undefined") {
malloc = (malloc_ty)(require('memory').malloc);
} else {
malloc = (malloc_ty)(memory.malloc);
}
struct StringT {
byte* start;
uint len;
}
// Node objects
// Programs
struct ProgramT {
u8 type;
StatementListT* body;
};
// Statements
union StatementU {
BlockStatementT* block;
ExpressionStatementT* expression;
IfStatementT* ifStatement;
LabeledStatementT* labeled;
BreakStatementT* breakStatement;
ContinueStatementT* continueStatement;
WithStatementT* withStatement;
SwitchStatementT* switchStatement;
ReturnStatementT* returnStatement;
ThrowStatementT* throwStatement;
TryStatementT* tryStatement;
WhileStatementT* whileStatement;
DoWhileStatementT* doWhile;
ForStatementT* forStatement;
ForInStatementT* forIn;
LetStatementT* letStatement;
DebuggerStatementT* debuggerStatement;
VariableDeclarationT* variableDeclaration;
FunctionDeclarationT* functionDeclaration;
};
struct StatementT {
u8 type;
StatementU c;
};
struct StatementListT {
StatementT* elem;
StatementListT* next;
};
typedef StatementT EmptyStatementT;
struct BlockStatementT {
StatementListT* body;
};
struct ExpressionStatementT {
u8 type;
ExpressionT* expression;
};
struct IfStatementT {
ExpressionT* test;
StatementT* consequent;
StatementT* alternate;
};
struct LabeledStatementT {
IdentifierT* label;
StatementT* body;
};
struct BreakStatementT {
IdentifierT* label;
};
struct ContinueStatementT {
IdentifierT* label;
};
struct WithStatementT {
ExpressionT* object;
StatementT* body;
};
struct SwitchStatementT {
ExpressionT* discriminant;
SwitchCaseListT* cases;
u8 lexical;
};
struct ReturnStatementT {
ExpressionT* argument;
};
struct ThrowStatementT {
ExpressionT* argument;
};
struct TryStatementT {
BlockStatementT* block;
CatchClauseListT* handlers;
BlockStatementT* finalizer;
};
struct WhileStatementT {
ExpressionT* test;
StatementT* body;
};
struct DoWhileStatementT {
StatementT* body;
ExpressionT* test;
};
union ForInitU {
VariableDeclarationT* variableDeclaration;
ExpressionT* expression;
};
struct ForStatementT {
u8 initType;
ForInitU* init;
ExpressionT* test;
ExpressionT* update;
StatementT* body;
};
struct ForInStatementT {
u8 leftType;
ForInitU* left;
ExpressionT* right;
StatementT* body;
u8 each;
};
struct LetStatementT {
LetHeadListT* head;
StatementT* body;
};
struct LetHeadListT {
LetHeadT* elem;
LetHeadListT* next;
};
struct LetHeadT {
PatternT* id;
ExpressionT* init;
};
typedef StatementT DebuggerStatementT;
// Declarations
union DeclarationU {
FunctionDeclarationT* functionDeclaration;
VariableDeclarationT* variableDeclaration;
}
struct DeclarationT {
u8 type;
DeclarationU c;
};
union BlockOrExpressionU {
BlockStatementT* block;
ExpressionT* expression;
};
struct MetaT {
u8 thunk;
u8 closed;
u8 generator;
u8 expression;
};
struct FunctionDeclarationT {
IdentifierT* id;
PatternListT* params;
u8 bodyType;
BlockOrExpressionU body;
ExpressionListT* defaults;
IdentifierT* rest;
u8 generator;
u8 expression;
MetaT meta;
};
const u8 VAR_KIND_VAR = 0;
const u8 VAR_KIND_LET = 1;
const u8 VAR_KIND_CONST = 2;
struct VariableDeclarationT {
VariableDeclaratorListT* declarations;
u8 kind;
};
struct VariableDeclaratorT {
PatternT* id;
ExpressionT* init;
};
struct VariableDeclaratorListT {
VariableDeclaratorT* elem;
VariableDeclaratorListT* next;
};
// Expressions
union ExpressionU {
ArrayExpressionT* array;
ObjectExpressionT* object;
FunctionExpressionT* functionExpression;
SequenceExpressionT* sequence;
UnaryExpressionT* unary;
BinaryExpressionT* binary;
AssignmentExpressionT* assignment;
UpdateExpressionT* update;
LogicalExpressionT* logical;
ConditionalExpressionT* conditional;
NewExpressionT* newExpression;
CallExpressionT* call;
MemberExpressionT* member;
// YieldExpressionT* yieldExpression;
IdentifierT* identifier;
LiteralT* literal;
};
struct ExpressionT {
u8 type;
ExpressionU c;
};
struct ExpressionListT {
ExpressionT* elem;
ExpressionListT* next;
};
typedef ExpressionT ThisExpressionT;
struct ArrayExpressionT {
ExpressionListT* elements;
};
struct ObjectExpressionT {
ObjectPropertiesListT* properties;
};
struct FunctionExpressionT {
IdentifierT* id;
PatternListT* params;
u8 bodyType;
BlockOrExpressionU body;
ExpressionListT* defaults;
IdentifierT* rest;
u8 generator;
u8 expression;
MetaT meta;
};
struct SequenceExpressionT {
ExpressionListT* expressions;
};
struct UnaryExpressionT {
u8 operator;
u8 prefix;
ExpressionT* argument;
};
struct BinaryExpressionT {
u8 operator;
ExpressionT* left;
ExpressionT* right;
};
struct AssignmentExpressionT {
u8 operator;
ExpressionT* left;
ExpressionT* right;
};
struct UpdateExpressionT {
u8 operator;
ExpressionT* argument;
u8 prefix;
};
struct LogicalExpressionT {
u8 operator;
ExpressionT* left;
ExpressionT* right;
};
struct ConditionalExpressionT {
ExpressionT* test;
ExpressionT* alternate;
ExpressionT* consequent;
};
struct NewExpressionT {
ExpressionT* callee;
ExpressionListT* arguments;
};
struct CallExpressionT {
ExpressionT* callee;
ExpressionListT* arguments;
};
union IdentifierOrExpressionU {
IdentifierT* identifier;
ExpressionT* expression;
};
struct MemberExpressionT {
ExpressionT* object;
u8 propertyType;
IdentifierOrExpressionU property;
u8 computed;
};
// struct YieldExpressionT {
// ExpressionT* argument;
// };
// struct ComprehensionExpressionT {
// ExpressionT* body;
// ComprehensionBlockListT* blocks;
// ExpressionT* filter;
// };
// struct GeneratorExpressionT {
// ExpressionT* body;
// ComprehensionBlockListT* blocks;
// ExpressionT* filter;
// };
// a couple other spidermonkey-specific expresssions go here
// Patterns
union PatternU {
ObjectPatternT* object;
ArrayPatternT* array;
ExpressionT* expression;
IdentifierT* identifier;
};
struct PatternT {
u8 type;
PatternU c;
};
struct PatternListT {
PatternT* elem;
PatternListT* next;
};
const u8 OBJECT_KIND_INIT = 0;
const u8 OBJECT_KIND_GET = 1;
const u8 OBJECT_KIND_SET = 2;
struct ObjectPatternT {
ObjectPropertiesListT* properties;
};
union LiteralOrIdentifierU {
LiteralT* literal;
IdentifierT* identifier;
};
struct LiteralOrIdentifierT {
u8 type;
LiteralOrIdentifierU c;
};
struct ObjectPropertiesT {
LiteralOrIdentifierT* key;
PatternT* value;
u8 kind;
}
struct ObjectPropertiesListT {
ObjectPropertiesT* elem;
ObjectPropertiesListT* next;
};
struct ArrayPatternT {
PatternListT* elements;
};
// Clauses
struct SwitchCaseT {
ExpressionT* test;
StatementListT* consequent;
};
struct SwitchCaseListT {
SwitchCaseT* elem;
SwitchCaseListT* next;
};
struct CatchClauseT {
PatternT* param;
ExpressionT* guard;
BlockStatementT* body;
};
struct CatchClauseListT {
CatchClauseT* elem;
CatchClauseListT* next;
};
// Miscellaneous
struct IdentifierT {
StringT* name;
};
struct LiteralT {
u8 type;
StringT* value;
StringT* raw;
};
struct AssignmentOperatorT {
u8 token;
};
typedef ExpressionT* ExpressionF();
typedef BlockStatementT* BlockStatementF();
typedef CallExpressionT* CallExpressionF(ExpressionT*);
typedef CatchClauseT* CatchClauseF();
typedef MemberExpressionT* MemberExpressionF(ExpressionT*);
typedef VariableDeclarationT* VariableDeclarationF_u8(u8);
typedef VariableDeclarationT* VariableDeclarationF();
typedef FunctionDeclarationT* FunctionDeclarationF();
typedef FunctionExpressionT* FunctionExpressionF();
typedef IdentifierT* IdentifierF();
typedef ObjectPropertiesT* ObjectPropertiesF();
typedef LiteralOrIdentifierT* LiteralOrIdentifierF();
typedef FunctionExpressionT* FunctionExpressionF_PatternListT_dyn(PatternListT*, dyn);
typedef StatementT* StatementF();
typedef SwitchCaseT* SwitchCaseF();
typedef VariableDeclaratorT* VariableDeclaratorF(u8);
typedef LiteralT* LiteralF(dyn);
typedef ProgramT* ProgramF(dyn);
struct SyntaxT {
u8 AssignmentExpression;
u8 ArrayExpression;
u8 BlockStatement;
u8 BinaryExpression;
u8 BreakStatement;
u8 CallExpression;
u8 CatchClause;
u8 ConditionalExpression;
u8 ContinueStatement;
u8 DoWhileStatement;
u8 DebuggerStatement;
u8 EmptyStatement;
u8 ExpressionStatement;
u8 ForStatement;
u8 ForInStatement;
u8 FunctionDeclaration;
u8 FunctionExpression;
u8 Identifier;
u8 IfStatement;
u8 Literal;
u8 LabeledStatement;
u8 LogicalExpression;
u8 MemberExpression;
u8 NewExpression;
u8 ObjectExpression;
u8 Program;
u8 Property;
u8 ReturnStatement;
u8 SequenceExpression;
u8 SwitchStatement;
u8 SwitchCase;
u8 ThisExpression;
u8 ThrowStatement;
u8 TryStatement;
u8 UnaryExpression;
u8 UpdateExpression;
u8 VariableDeclaration;
u8 VariableDeclarator;
u8 WhileStatement;
u8 WithStatement;
u8 Expression;
u8 LetStatement;
};
(function (exports) {
'use strict';
let Token,
TokenName,
SyntaxStrings,
PropertyKind,
Messages,
Regex,
source,
strict,
index,
lineNumber,
lineStart,
length,
buffer,
state,
extra;
Token = {
BooleanLiteral: 1,
EOF: 2,
Identifier: 3,
Keyword: 4,
NullLiteral: 5,
NumericLiteral: 6,
Punctuator: 7,
StringLiteral: 8
};
TokenName = {};
TokenName[Token.BooleanLiteral] = 'Boolean';
TokenName[Token.EOF] = '<end>';
TokenName[Token.Identifier] = 'Identifier';
TokenName[Token.Keyword] = 'Keyword';
TokenName[Token.NullLiteral] = 'Null';
TokenName[Token.NumericLiteral] = 'Numeric';
TokenName[Token.Punctuator] = 'Punctuator';
TokenName[Token.StringLiteral] = 'String';
SyntaxStrings = {
AssignmentExpression: 'AssignmentExpression',
ArrayExpression: 'ArrayExpression',
BlockStatement: 'BlockStatement',
BinaryExpression: 'BinaryExpression',
BreakStatement: 'BreakStatement',
CallExpression: 'CallExpression',
CatchClause: 'CatchClause',
ConditionalExpression: 'ConditionalExpression',
ContinueStatement: 'ContinueStatement',
DoWhileStatement: 'DoWhileStatement',
DebuggerStatement: 'DebuggerStatement',
EmptyStatement: 'EmptyStatement',
ExpressionStatement: 'ExpressionStatement',
ForStatement: 'ForStatement',
ForInStatement: 'ForInStatement',
FunctionDeclaration: 'FunctionDeclaration',
FunctionExpression: 'FunctionExpression',
Identifier: 'Identifier',
IfStatement: 'IfStatement',
Literal: 'Literal',
LabeledStatement: 'LabeledStatement',
LogicalExpression: 'LogicalExpression',
MemberExpression: 'MemberExpression',
NewExpression: 'NewExpression',
ObjectExpression: 'ObjectExpression',
Program: 'Program',
Property: 'Property',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SwitchStatement: 'SwitchStatement',
SwitchCase: 'SwitchCase',
ThisExpression: 'ThisExpression',
ThrowStatement: 'ThrowStatement',
TryStatement: 'TryStatement',
UnaryExpression: 'UnaryExpression',
UpdateExpression: 'UpdateExpression',
VariableDeclaration: 'VariableDeclaration',
VariableDeclarator: 'VariableDeclarator',
WhileStatement: 'WhileStatement',
WithStatement: 'WithStatement'
};
let SyntaxT* Syntax = new SyntaxT;
Syntax->AssignmentExpression = 0;
Syntax->ArrayExpression = 1;
Syntax->BlockStatement = 2;
Syntax->BinaryExpression = 3;
Syntax->BreakStatement = 4;
Syntax->CallExpression = 5;
Syntax->CatchClause = 6;
Syntax->ConditionalExpression = 7;
Syntax->ContinueStatement = 8;
Syntax->DoWhileStatement = 9;
Syntax->DebuggerStatement = 10;
Syntax->EmptyStatement = 11;
Syntax->ExpressionStatement = 12;
Syntax->ForStatement = 13;
Syntax->ForInStatement = 14;
Syntax->FunctionDeclaration = 15;
Syntax->FunctionExpression = 16;
Syntax->Identifier = 17;
Syntax->IfStatement = 18;
Syntax->Literal = 19;
Syntax->LabeledStatement = 20;
Syntax->LogicalExpression = 21;
Syntax->MemberExpression = 22;
Syntax->NewExpression = 23;
Syntax->ObjectExpression = 24;
Syntax->Program = 25;
Syntax->Property = 26;
Syntax->ReturnStatement = 27;
Syntax->SequenceExpression = 28;
Syntax->SwitchStatement = 29;
Syntax->SwitchCase = 30;
Syntax->ThisExpression = 31;
Syntax->ThrowStatement = 32;
Syntax->TryStatement = 33;
Syntax->UnaryExpression = 34;
Syntax->UpdateExpression = 35;
Syntax->VariableDeclaration = 36;
Syntax->VariableDeclarator = 37;
Syntax->WhileStatement = 38;
Syntax->WithStatement = 39;
Syntax->Expression = 40;
Syntax->LetStatement = 41;
PropertyKind = {
Data: 1,
Get: 2,
Set: 4
};
// Error messages should be identical to V8.
Messages = {
UnexpectedToken: 'Unexpected token %0',
UnexpectedNumber: 'Unexpected number',
UnexpectedString: 'Unexpected string',
UnexpectedIdentifier: 'Unexpected identifier',
UnexpectedReserved: 'Unexpected reserved word',
UnexpectedEOS: 'Unexpected end of input',
NewlineAfterThrow: 'Illegal newline after throw',
InvalidRegExp: 'Invalid regular expression',
UnterminatedRegExp: 'Invalid regular expression: missing /',
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
NoCatchOrFinally: 'Missing catch or finally after try',
UnknownLabel: 'Undefined label \'%0\'',
Redeclaration: '%0 \'%1\' has already been declared',
IllegalContinue: 'Illegal continue statement',
IllegalBreak: 'Illegal break statement',
IllegalReturn: 'Illegal return statement',
StrictModeWith: 'Strict mode code may not include a with statement',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
StrictReservedWord: 'Use of future reserved word in strict mode'
};
// See also tools/generate-unicode-regex.py.
Regex = {
NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
};
function ExpressionT* castExpression(obj, u8 fromType) {
let ExpressionT* expr = new ExpressionT;
expr->type = fromType;
switch (fromType) {
case Syntax->ArrayExpression:
expr->c.array = (ArrayExpressionT*)(obj);
break;
case Syntax->ObjectExpression:
expr->c.object = (ObjectExpressionT*)(obj);
break;
case Syntax->FunctionExpression:
expr->c.functionExpression = (FunctionExpressionT*)(obj);
break;
case Syntax->SequenceExpression:
expr->c.sequence = (SequenceExpressionT*)(obj);
break;
case Syntax->UnaryExpression:
expr->c.unary = (UnaryExpressionT*)(obj);
break;
case Syntax->BinaryExpression:
expr->c.binary = (BinaryExpressionT*)(obj);
break;
case Syntax->AssignmentExpression:
expr->c.assignment = (AssignmentExpressionT*)(obj);
break;
case Syntax->UpdateExpression:
expr->c.update = (UpdateExpressionT*)(obj);
break;
case Syntax->LogicalExpression:
expr->c.logical = (LogicalExpressionT*)(obj);
break;
case Syntax->ConditionalExpression:
expr->c.conditional = (ConditionalExpressionT*)(obj);
break;
case Syntax->NewExpression:
expr->c.newExpression = (NewExpressionT*)(obj);
break;
case Syntax->CallExpression:
expr->c.call = (CallExpressionT*)(obj);
break;
case Syntax->MemberExpression:
expr->c.member = (MemberExpressionT*)(obj);
break;
case Syntax->Identifier:
expr->c.identifier = (IdentifierT*)(obj);
break;
case Syntax->Literal:
expr->c.literal = (LiteralT*)(obj);
break;
default:
throw new Error('Unknown type to cast: ' + fromType);
}
return expr;
}
function PatternT* castPattern(obj, u8 fromType) {
let PatternT* pattern = new PatternT;
pattern->type = fromType;
switch (fromType) {
case Syntax->Expression:
pattern->c.expression = (ExpressionT*)(obj);
break;
case Syntax->Identifier:
pattern->c.identifier = (IdentifierT*)(obj);
break;
default:
throw new Error('Unknown type to cast: ' + fromType);
}
return pattern;
}
function StatementT* castStatement(obj, u8 fromType) {
let StatementT* statement = new StatementT;
statement->type = fromType;
switch (fromType) {
case Syntax->BlockStatement:
statement->c.block = (BlockStatementT*)(obj);
break;
case Syntax->ExpressionStatement:
statement->c.expression = (ExpressionStatementT*)(obj);
break;
case Syntax->IfStatement:
statement->c.ifStatement = (IfStatementT*)(obj);
break;
case Syntax->LabeledStatement:
statement->c.labeled = (LabeledStatementT*)(obj);
break;
case Syntax->BreakStatement:
statement->c.breakStatement = (BreakStatementT*)(obj);
break;
case Syntax->ContinueStatement:
statement->c.continueStatement = (ContinueStatementT*)(obj);
break;
case Syntax->WithStatement:
statement->c.withStatement = (WithStatementT*)(obj);
break;
case Syntax->SwitchStatement:
statement->c.switchStatement = (SwitchStatementT*)(obj);
break;
case Syntax->ReturnStatement:
statement->c.returnStatement = (ReturnStatementT*)(obj);
break;
case Syntax->ThrowStatement:
statement->c.throwStatement = (ThrowStatementT*)(obj);
break;
case Syntax->TryStatement:
statement->c.tryStatement = (TryStatementT*)(obj);
break;
case Syntax->WhileStatement:
statement->c.whileStatement = (WhileStatementT*)(obj);
break;
case Syntax->DoWhileStatement:
statement->c.doWhile = (DoWhileStatementT*)(obj);
break;
case Syntax->ForStatement:
statement->c.forStatement = (ForStatementT*)(obj);
break;
case Syntax->ForInStatement:
statement->c.forIn = (ForInStatementT*)(obj);
break;
case Syntax->LetStatement:
statement->c.letStatement = (LetStatementT*)(obj);
break;
case Syntax->DebuggerStatement:
statement->c.debuggerStatement = (DebuggerStatementT*)(obj);
break;
case Syntax->VariableDeclaration:
statement->c.variableDeclaration = (VariableDeclarationT*)(obj);
break;
case Syntax->FunctionDeclaration:
statement->c.functionDeclaration = (FunctionDeclarationT*)(obj);
break;
default:
throw new Error('Unknown type to cast: ' + fromType);
}
return statement;
}
function uint statementListLength(StatementListT* list) {
let uint l = 0;
let StatementListT* cur = list;
while (cur !== null) {
cur = cur->next;
l++;
}
return l-1;
}
function uint varDeclListLength(VariableDeclaratorListT* list) {
let uint l = 0;
let VariableDeclaratorListT* cur = list;
while (cur !== null) {
cur = cur->next;
l++;
}
return l-1;
}
function uint catchClauseListLength(CatchClauseListT* list) {
let uint l = 0;
let CatchClauseListT* cur = list;
while (cur !== null) {
cur = cur->next;
l++;
}
return l-1;
}
// let strByteCount = 0;
function StringT* convertStr(o) {
let StringT* newStr = new StringT;
if (!o) {
newStr->start = 0;
// strByteCount += 1;
return newStr;
}
let str = o.toString();
newStr->start = malloc((u32)(str.length+1));
let byte* cur = newStr->start;
for (let i=0, l=str.length; i<l; i++) {
*cur = (u8) (str.charCodeAt(i));
cur++;
}
*cur = 0;
// strByteCount += str.length+1;
return newStr;
}
function readStr(StringT* str) {
let varStr = '';
for (let byte* c=str->start; *c != 0; c++) {
varStr += String.fromCharCode(*c);
}
return varStr;
}
function u8 convertOperator(op) {
switch (op) {
case '.':
return 0;
case 'new':
return 1;
case '++':
return 2;
case '--':
return 3;
case '!':
return 4;
case '~':
return 5;
case '+':
return 6;
case '-':
return 7;
case 'typeof':
return 8;
case 'void':
return 9;
case 'delete':
return 10;
case '*':
return 11;
case '/':
return 12;
case '%':
return 13;
case '<<':
return 14;
case '>>':
return 15;
case '>>>':
return 16;
case '<':
return 17;
case '<=':
return 18;
case '>':
return 19;
case '>=':
return 20;
case 'in':
return 21;
case 'instanceof':
return 22;
case '==':
return 23;
case '!=':
return 24;
case '===':
return 25;
case '!==':
return 26;
case '&':
return 27;
case '^':
return 28;
case '|':
return 29;
case '&&':
return 30;
case '||':
return 31;
case '=':
return 32;
case '+=':
return 33;
case '-=':
return 34;
case '*=':
return 35;
case '/=':
return 36;
case '%=':
return 37;
case '<<=':
return 38;
case '>>=':
return 39;
case '>>>=':
return 40;
case '&=':
return 41;
case '^=':
return 42;
case '|=':
return 43;
case ',':
return 44;
default:
throw new Error('Unrecognized operator: ' + op);
}
}
function u8 convertVarKind(str) {
switch (str) {
case 'var':
return VAR_KIND_VAR;
case 'let':
return VAR_KIND_LET;
case 'const':
return VAR_KIND_CONST;
}
}
// Ensure the condition is true, otherwise throw an error.
// This is only to have a better contract semantic, i.e. another safety net
// to catch a logic error. The condition shall be fulfilled in normal case.
// Do NOT use this to enforce a certain condition on any user input.
function assert(condition, message) {
if (!condition) {
throw new Error('ASSERT: ' + message);
}
}
function sliceSource(from, to) {
return source.slice(from, to);
}
if (typeof 'esprima'[0] === 'undefined') {
sliceSource = function sliceArraySource(from, to) {
return source.slice(from, to).join('');
};
}
function isDecimalDigit(ch) {
return '0123456789'.indexOf(ch) >= 0;
}
function isHexDigit(ch) {
return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
}
function isOctalDigit(ch) {
return '01234567'.indexOf(ch) >= 0;
}
// 7.2 White Space
function isWhiteSpace(ch) {
return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
(ch === '\u000C') || (ch === '\u00A0') ||
(ch.charCodeAt(0) >= 0x1680 &&
'\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
}
// 7.3 Line Terminators
function isLineTerminator(ch) {
return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
}
// 7.6 Identifier Names and Identifiers
function isIdentifierStart(ch) {
return (ch === '$') || (ch === '_') || (ch === '\\') ||
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
}
function isIdentifierPart(ch) {
return (ch === '$') || (ch === '_') || (ch === '\\') ||
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
((ch >= '0') && (ch <= '9')) ||
((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
}
// 7.6.1.2 Future Reserved Words
function isFutureReservedWord(id) {
switch (id) {
// Future reserved words.
case 'class':
case 'enum':
case 'export':
case 'extends':
case 'import':
case 'super':
return true;
}
return false;
}
function isStrictModeReservedWord(id) {
switch (id) {
// Strict Mode reserved words.
case 'implements':
case 'interface':
case 'package':
case 'private':
case 'protected':
case 'public':
case 'static':
case 'yield':
case 'let':
return true;
}
return false;
}
function isRestrictedWord(id) {
return id === 'eval' || id === 'arguments';
}
// 7.6.1.1 Keywords
function isKeyword(id) {
let keyword = false;
switch (id.length) {
case 2:
keyword = (id === 'if') || (id === 'in') || (id === 'do');
break;
case 3:
keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
break;
case 4:
keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
break;
case 5:
keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
break;
case 6:
keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
break;
case 7:
keyword = (id === 'default') || (id === 'finally');
break;
case 8:
keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
break;
case 10:
keyword = (id === 'instanceof');
break;
}
if (keyword) {
return true;
}
switch (id) {
// Future reserved words.
// 'const' is specialized as Keyword in V8.
case 'const':
return true;
// For compatiblity to SpiderMonkey and ES.next
case 'yield':
case 'let':
return true;
}
if (strict && isStrictModeReservedWord(id)) {
return true;
}
return isFutureReservedWord(id);
}
// Return the next character and move forward.
function nextChar() {
return source[index++];
}
// 7.4 Comments
function skipComment() {
let ch, blockComment, lineComment;
blockComment = false;
lineComment = false;
while (index < length) {
ch = source[index];
if (lineComment) {
ch = nextChar();
if (isLineTerminator(ch)) {
lineComment = false;
if (ch === '\r' && source[index] === '\n') {
++index;
}
++lineNumber;
lineStart = index;
}
} else if (blockComment) {
if (isLineTerminator(ch)) {
if (ch === '\r' && source[index + 1] === '\n') {
++index;
}
++lineNumber;
++index;
lineStart = index;
if (index >= length) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
} else {
ch = nextChar();
if (index >= length) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
if (ch === '*') {
ch = source[index];
if (ch === '/') {
++index;
blockComment = false;
}
}
}
} else if (ch === '/') {
ch = source[index + 1];
if (ch === '/') {
index += 2;
lineComment = true;
} else if (ch === '*') {
index += 2;
blockComment = true;
if (index >= length) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
} else {
break;
}
} else if (isWhiteSpace(ch)) {
++index;
} else if (isLineTerminator(ch)) {
++index;
if (ch === '\r' && source[index] === '\n') {
++index;
}
++lineNumber;
lineStart = index;
} else {
break;
}
}
}
function scanHexEscape(prefix) {
let i, len, ch, code = 0;
len = (prefix === 'u') ? 4 : 2;
for (i = 0; i < len; ++i) {
if (index < length && isHexDigit(source[index])) {
ch = nextChar();
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
} else {
return '';
}
}
return String.fromCharCode(code);
}
function scanIdentifier() {
let ch, start, id, restore;
ch = source[index];
if (!isIdentifierStart(ch)) {
return;
}
start = index;
if (ch === '\\') {
++index;
if (source[index] !== 'u') {
return;
}
++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
if (ch === '\\' || !isIdentifierStart(ch)) {
return;
}
id = ch;
} else {
index = restore;
id = 'u';
}
} else {
id = nextChar();
}
while (index < length) {
ch = source[index];
if (!isIdentifierPart(ch)) {
break;
}
if (ch === '\\') {
++index;
if (source[index] !== 'u') {
return;
}
++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
if (ch === '\\' || !isIdentifierPart(ch)) {
return;
}
id += ch;
} else {
index = restore;
id += 'u';
}
} else {
id += nextChar();
}
}
// There is no keyword or literal with only one character.
// Thus, it must be an identifier.
if (id.length === 1) {
return {
type: Token.Identifier,
value: id,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (isKeyword(id)) {
return {
type: Token.Keyword,
value: id,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// 7.8.1 Null Literals
if (id === 'null') {
return {
type: Token.NullLiteral,
value: id,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// 7.8.2 Boolean Literals
if (id === 'true' || id === 'false') {
return {
type: Token.BooleanLiteral,
value: id,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
return {
type: Token.Identifier,
value: id,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// 7.7 Punctuators
function scanPunctuator() {
let start = index,
ch1 = source[index],
ch2,
ch3,
ch4;
// Check for most common single-character punctuators.
if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
++index;
return {
type: Token.Punctuator,
value: ch1,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
++index;
return {
type: Token.Punctuator,
value: ch1,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// Dot (.) can also start a floating-point number, hence the need
// to check the next character.
ch2 = source[index + 1];
if (ch1 === '.' && !isDecimalDigit(ch2)) {
return {
type: Token.Punctuator,
value: nextChar(),
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// Peek more characters.
ch3 = source[index + 2];
ch4 = source[index + 3];
// 4-character punctuator: >>>=
if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
if (ch4 === '=') {
index += 4;
return {
type: Token.Punctuator,
value: '>>>=',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
}
// 3-character punctuators: === !== >>> <<= >>=
if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
index += 3;
return {
type: Token.Punctuator,
value: '===',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
index += 3;
return {
type: Token.Punctuator,
value: '!==',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
index += 3;
return {
type: Token.Punctuator,
value: '>>>',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
index += 3;
return {
type: Token.Punctuator,
value: '<<=',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
index += 3;
return {
type: Token.Punctuator,
value: '>>=',
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// 2-character punctuators: <= >= == != ++ -- << >> && ||
// += -= *= %= &= |= ^= /=
if (ch2 === '=') {
if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
index += 2;
return {
type: Token.Punctuator,
value: ch1 + ch2,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
}
if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
if ('+-<>&|'.indexOf(ch2) >= 0) {
index += 2;
return {
type: Token.Punctuator,
value: ch1 + ch2,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
}
// The remaining 1-character punctuators.
if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
return {
type: Token.Punctuator,
value: nextChar(),
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
}
// 7.8.3 Numeric Literals
function scanNumericLiteral() {
let number, start, ch;
ch = source[index];
assert(isDecimalDigit(ch) || (ch === '.'),
'Numeric literal must start with a decimal digit or a decimal point');
start = index;
number = '';
if (ch !== '.') {
number = nextChar();
ch = source[index];
// Hex number starts with '0x'.
// Octal number starts with '0'.
if (number === '0') {
if (ch === 'x' || ch === 'X') {
number += nextChar();
while (index < length) {
ch = source[index];
if (!isHexDigit(ch)) {
break;
}
number += nextChar();
}
if (number.length <= 2) {
// only 0x
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
if (index < length) {
ch = source[index];
if (isIdentifierStart(ch)) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
return {
type: Token.NumericLiteral,
value: parseInt(number, 16),
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
} else if (isOctalDigit(ch)) {
number += nextChar();
while (index < length) {
ch = source[index];
if (!isOctalDigit(ch)) {
break;
}
number += nextChar();
}
if (index < length) {
ch = source[index];
if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
return {
type: Token.NumericLiteral,
value: parseInt(number, 8),
octal: true,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// decimal number starts with '0' such as '09' is illegal.
if (isDecimalDigit(ch)) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
while (index < length) {
ch = source[index];
if (!isDecimalDigit(ch)) {
break;
}
number += nextChar();
}
}
if (ch === '.') {
number += nextChar();
while (index < length) {
ch = source[index];
if (!isDecimalDigit(ch)) {
break;
}
number += nextChar();
}
}
if (ch === 'e' || ch === 'E') {
number += nextChar();
ch = source[index];
if (ch === '+' || ch === '-') {
number += nextChar();
}
ch = source[index];
if (isDecimalDigit(ch)) {
number += nextChar();
while (index < length) {
ch = source[index];
if (!isDecimalDigit(ch)) {
break;
}
number += nextChar();
}
} else {
ch = 'character ' + ch;
if (index >= length) {
ch = '<end>';
}
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
if (index < length) {
ch = source[index];
if (isIdentifierStart(ch)) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
return {
type: Token.NumericLiteral,
value: parseFloat(number),
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
// 7.8.4 String Literals
function scanStringLiteral() {
let str = '', quote, start, ch, code, unescaped, restore, octal = false;
quote = source[index];
assert((quote === '\'' || quote === '"'),
'String literal must starts with a quote');
start = index;
++index;
while (index < length) {
ch = nextChar();
if (ch === quote) {
quote = '';
break;
} else if (ch === '\\') {
ch = nextChar();
if (!isLineTerminator(ch)) {
switch (ch) {
case 'n':
str += '\n';
break;
case 'r':
str += '\r';
break;
case 't':
str += '\t';
break;
case 'u':
case 'x':
restore = index;
unescaped = scanHexEscape(ch);
if (unescaped) {
str += unescaped;
} else {
index = restore;
str += ch;
}
break;
case 'b':
str += '\b';
break;
case 'f':
str += '\f';
break;
case 'v':
str += '\v';
break;
default:
if (isOctalDigit(ch)) {
code = '01234567'.indexOf(ch);
// \0 is not octal escape sequence
if (code !== 0) {
octal = true;
}
if (index < length && isOctalDigit(source[index])) {
octal = true;
code = code * 8 + '01234567'.indexOf(nextChar());
// 3 digits are only allowed when string starts
// with 0, 1, 2, 3
if ('0123'.indexOf(ch) >= 0 &&
index < length &&
isOctalDigit(source[index])) {
code = code * 8 + '01234567'.indexOf(nextChar());
}
}
str += String.fromCharCode(code);
} else {
str += ch;
}
break;
}
} else {
++lineNumber;
if (ch === '\r' && source[index] === '\n') {
++index;
}
}
} else if (isLineTerminator(ch)) {
break;
} else {
str += ch;
}
}
if (quote !== '') {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
return {
type: Token.StringLiteral,
value: str,
octal: octal,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
};
}
function scanRegExp() {
let str = '', ch, start, pattern, flags, value, classMarker = false, restore;
buffer = null;
skipComment();
start = index;
ch = source[index];
assert(ch === '/', 'Regular expression literal must start with a slash');
str = nextChar();
while (index < length) {
ch = nextChar();
str += ch;
if (classMarker) {
if (ch === ']') {
classMarker = false;
}
} else {
if (ch === '\\') {
ch = nextChar();
// ECMA-262 7.8.5
if (isLineTerminator(ch)) {
throwError({}, Messages.UnterminatedRegExp);
}
str += ch;
} else if (ch === '/') {
break;
} else if (ch === '[') {
classMarker = true;
} else if (isLineTerminator(ch)) {
throwError({}, Messages.UnterminatedRegExp);
}
}
}
if (str.length === 1) {
throwError({}, Messages.UnterminatedRegExp);
}
// Exclude leading and trailing slash.
pattern = str.substr(1, str.length - 2);
flags = '';
while (index < length) {
ch = source[index];
if (!isIdentifierPart(ch)) {
break;
}
++index;
if (ch === '\\' && index < length) {
ch = source[index];
if (ch === 'u') {
++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
flags += ch;
str += '\\u';
for (; restore < index; ++restore) {
str += source[restore];
}
} else {
index = restore;
flags += 'u';
str += '\\u';
}
} else {
str += '\\';
}
} else {
flags += ch;
str += ch;
}
}
try {
value = new RegExp(pattern, flags);
} catch (e) {
throwError({}, Messages.InvalidRegExp);
}
return {
literal: str,
value: value,
range: [start, index]
};
}
function isIdentifierName(token) {
return token.type === Token.Identifier ||
token.type === Token.Keyword ||
token.type === Token.BooleanLiteral ||
token.type === Token.NullLiteral;
}
function advance() {
let ch, token;
skipComment();
if (index >= length) {
return {
type: Token.EOF,
lineNumber: lineNumber,
lineStart: lineStart,
range: [index, index]
};
}
token = scanPunctuator();
if (typeof token !== 'undefined') {
return token;
}
ch = source[index];
if (ch === '\'' || ch === '"') {
return scanStringLiteral();
}
if (ch === '.' || isDecimalDigit(ch)) {
return scanNumericLiteral();
}
token = scanIdentifier();
if (typeof token !== 'undefined') {
return token;
}
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
function lex() {
let token;
if (buffer) {
index = buffer.range[1];
lineNumber = buffer.lineNumber;
lineStart = buffer.lineStart;
token = buffer;
buffer = null;
return token;
}
buffer = null;
return advance();
}
function lookahead() {
let pos, line, start;
if (buffer !== null) {
return buffer;
}
pos = index;
line = lineNumber;
start = lineStart;
buffer = advance();
index = pos;
lineNumber = line;
lineStart = start;
return buffer;
}
// Return true if there is a line terminator before the next token.
function peekLineTerminator() {
let pos, line, start, found;
pos = index;
line = lineNumber;
start = lineStart;
skipComment();
found = lineNumber !== line;
index = pos;
lineNumber = line;
lineStart = start;
return found;
}
// Throw an exception
function throwError(token, messageFormat) {
let error,
args = Array.prototype.slice.call(arguments, 2),
msg = messageFormat.replace(
/%(\d)/g,
function (whole, index) {
return args[index] || '';
}
);
if (typeof token.lineNumber === 'number') {
error = new Error('Line ' + token.lineNumber + ': ' + msg);
error.index = token.range[0];
error.lineNumber = token.lineNumber;
error.column = token.range[0] - lineStart + 1;
} else {
error = new Error('Line ' + lineNumber + ': ' + msg);
error.index = index;
error.lineNumber = lineNumber;
error.column = index - lineStart + 1;
}
throw error;
}
function throwErrorTolerant() {
try {
throwError.apply(null, arguments);
} catch (e) {
if (extra.errors) {
extra.errors.push(e);
} else {
throw e;
}
}
}
// Throw an exception because of the token.
function throwUnexpected(token) {
if (token.type === Token.EOF) {
throwError(token, Messages.UnexpectedEOS);
}
if (token.type === Token.NumericLiteral) {
throwError(token, Messages.UnexpectedNumber);
}
if (token.type === Token.StringLiteral) {
throwError(token, Messages.UnexpectedString);
}
if (token.type === Token.Identifier) {
throwError(token, Messages.UnexpectedIdentifier);
}
if (token.type === Token.Keyword) {
if (isFutureReservedWord(token.value)) {
throwError(token, Messages.UnexpectedReserved);
} else if (strict && isStrictModeReservedWord(token.value)) {
throwError(token, Messages.StrictReservedWord);
}
throwError(token, Messages.UnexpectedToken, token.value);
}
// BooleanLiteral, NullLiteral, or Punctuator.
throwError(token, Messages.UnexpectedToken, token.value);
}
// Expect the next token to match the specified punctuator.
// If not, an exception will be thrown.
function expect(value) {
let token = lex();
if (token.type !== Token.Punctuator || token.value !== value) {
throwUnexpected(token);
}
}
// Expect the next token to match the specified keyword.
// If not, an exception will be thrown.
function expectKeyword(keyword) {
let token = lex();
if (token.type !== Token.Keyword || token.value !== keyword) {
throwUnexpected(token);
}
}
// Return true if the next token matches the specified punctuator.
function match(value) {
let token = lookahead();
return token.type === Token.Punctuator && token.value === value;
}
// Return true if the next token matches the specified keyword
function matchKeyword(keyword) {
let token = lookahead();
return token.type === Token.Keyword && token.value === keyword;
}
// Return true if the next token is an assignment operator
function matchAssign() {
let token = lookahead(),
op = token.value;
if (token.type !== Token.Punctuator) {
return false;
}
return op === '=' ||
op === '*=' ||
op === '/=' ||
op === '%=' ||
op === '+=' ||
op === '-=' ||
op === '<<=' ||
op === '>>=' ||
op === '>>>=' ||
op === '&=' ||
op === '^=' ||
op === '|=';
}
function consumeSemicolon() {
let token, line;
// Catch the very common case first.
if (source[index] === ';') {
lex();
return;
}
line = lineNumber;
skipComment();
if (lineNumber !== line) {
return;
}
if (match(';')) {
lex();
return;
}
token = lookahead();
if (token.type !== Token.EOF && !match('}')) {
throwUnexpected(token);
}
return;
}
// Return true if provided expression is LeftHandSideExpression
function isLeftHandSide(ExpressionT* expr) {
return expr->type === Syntax->Identifier || expr->type === Syntax->MemberExpression;
}
// 11.1.4 Array Initialiser
function ArrayExpressionT* parseArrayInitialiser() {
let ExpressionListT* elements = new ExpressionListT;
let ExpressionListT* cur = elements;
let undef;
expect('[');
while (!match(']')) {
if (match(',')) {
lex();
cur->next = new ExpressionListT;
cur = cur->next;
} else {
cur->elem = parseAssignmentExpression();
cur->next = new ExpressionListT;
cur = cur->next;
if (!match(']')) {
expect(',');
}
}
}
expect(']');
let ArrayExpressionT* expr = new ArrayExpressionT;
expr->elements = elements;
return expr;
}
// 11.1.5 Object Initialiser
function FunctionExpressionT* parsePropertyFunction(PatternListT* param, first) {
let previousStrict;
let BlockStatementT* body;
previousStrict = strict;
body = parseFunctionSourceElements();
if (first && strict && isRestrictedWord(readStr(param->elem->c.identifier->name))) {
throwError(first, Messages.StrictParamName);
}
strict = previousStrict;
let FunctionExpressionT* expr = new FunctionExpressionT;
expr->id = null;
expr->params = param;
expr->defaults = new ExpressionListT;
expr->bodyType = Syntax->BlockStatement;
expr->body.block = body;
expr->rest = null;
expr->generator = 0;
expr->expression = 0;
return expr;
}
function LiteralOrIdentifierT* parseObjectPropertyKey() {
let token = lex();
let LiteralOrIdentifierT* ret = new LiteralOrIdentifierT;
// Note: This function is called only from parseObjectProperty(), where
// EOF and Punctuator tokens are already filtered out.
if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
if (strict && token.octal) {
throwError(token, Messages.StrictOctalLiteral);
}
ret->type = Syntax->Literal;
ret->c.literal = createLiteral(token);
return ret;
}
ret->type = Syntax->Identifier;
ret->c.identifier = new IdentifierT;
ret->c.identifier->name = convertStr(token.value);
return ret;
}
function ObjectPropertiesT* parseObjectProperty() {
let token;
let ObjectPropertiesT* prop;
let PatternListT* param;
let LiteralOrIdentifierT* id;
let LiteralOrIdentifierT* key;
token = lookahead();
if (token.type === Token.Identifier) {
id = parseObjectPropertyKey();
// Property Assignment: Getter and Setter.
if (token.value === 'get' && !match(':')) {
key = parseObjectPropertyKey();
expect('(');
expect(')');
prop = new ObjectPropertiesT;
prop->key = key;
prop->value = castPattern(parsePropertyFunction(new PatternListT), Syntax->FunctionExpression);
prop->kind = OBJECT_KIND_GET;
return prop;
} else if (token.value === 'set' && !match(':')) {
key = parseObjectPropertyKey();
expect('(');
token = lookahead();
if (token.type !== Token.Identifier) {
throwUnexpected(lex());
}
param->elem = castPattern(parseVariableIdentifier(), Syntax->Identifier);
expect(')');
prop = new ObjectPropertiesT;
prop->key = key;
prop->value = castPattern(castExpression(parsePropertyFunction(param, token), Syntax->FunctionExpression), Syntax->Expression);
prop->kind = OBJECT_KIND_SET;
return prop;
} else {
expect(':');
prop = new ObjectPropertiesT;
prop->key = id;
prop->value = castPattern(parseAssignmentExpression(), Syntax->Expression);
prop->kind = OBJECT_KIND_INIT;
return prop;
}
} else if (token.type === Token.EOF || token.type === Token.Punctuator) {
throwUnexpected(token);
} else {
key = parseObjectPropertyKey();
expect(':');
prop = new ObjectPropertiesT;
prop->key = key;
prop->value = castPattern(parseAssignmentExpression(), Syntax->Expression);
prop->kind = OBJECT_KIND_INIT;
return prop;
}
}
function ObjectExpressionT* parseObjectInitialiser() {
let name, kind, map = {};
let ObjectExpressionT* expr = new ObjectExpressionT;
expr->properties = new ObjectPropertiesListT;
let ObjectPropertiesListT* curProp = expr->properties;
let ObjectPropertiesT* property;
expect('{');
while (!match('}')) {
property = parseObjectProperty();
if (property->key->type === Syntax->Identifier) {
name = property->key->c.identifier->name;
} else {
name = readStr(property->key->c.literal->value);
}
kind = (property->kind === OBJECT_KIND_INIT) ? PropertyKind.Data : (property->kind === OBJECT_KIND_GET) ? PropertyKind.Get : PropertyKind.Set;
if (Object.prototype.hasOwnProperty.call(map, name)) {
if (map[name] === PropertyKind.Data) {
if (strict && kind === PropertyKind.Data) {
throwErrorTolerant({}, Messages.StrictDuplicateProperty);
} else if (kind !== PropertyKind.Data) {
throwError({}, Messages.AccessorDataProperty);
}
} else {
if (kind === PropertyKind.Data) {
throwError({}, Messages.AccessorDataProperty);
} else if (map[name] & kind) {
throwError({}, Messages.AccessorGetSet);
}
}
map[name] |= kind;
} else {
map[name] = kind;
}
curProp->elem = property;
curProp->next = new ObjectPropertiesListT;
curProp = curProp->next;
if (!match('}')) {
expect(',');
}
}
expect('}');
return expr;
}
// 11.1 Primary Expressions
function ExpressionT* parsePrimaryExpression() {
let ExpressionT* expr = new ExpressionT;
let token = lookahead(),
type = token.type;
if (type === Token.Identifier) {
let IdentifierT* identifier = new IdentifierT;
identifier->name = convertStr(lex().value);
expr->type = Syntax->Identifier;
expr->c.identifier = identifier;
return expr;
}
if (type === Token.StringLiteral || type === Token.NumericLiteral) {
if (strict && token.octal) {
throwErrorTolerant(token, Messages.StrictOctalLiteral);
}
return castExpression(createLiteral(lex()), Syntax->Literal);
}
if (type === Token.Keyword) {
if (matchKeyword('this')) {
lex();
return new ThisExpressionT;
}
if (matchKeyword('function')) {
return castExpression(parseFunctionExpression(), Syntax->FunctionExpression);
}
}
if (type === Token.BooleanLiteral) {
lex();
token.value = (token.value === 'true');
return castExpression(createLiteral(token), Syntax->Literal);
}
if (type === Token.NullLiteral) {
lex();
token.value = null;
return castExpression(createLiteral(token), Syntax->Literal);
}
if (match('[')) {
return castExpression(parseArrayInitialiser(), Syntax->ArrayExpression);
}
if (match('{')) {
return castExpression(parseObjectInitialiser(), Syntax->ObjectExpression);
}
if (match('(')) {
lex();
state.lastParenthesized = expr = parseExpression();
expect(')');
return expr;
}
if (match('/') || match('/=')) {
return castExpression(createLiteral(scanRegExp()), Syntax->Literal);
}
throwUnexpected(lex());
}
// 11.2 Left-Hand-Side Expressions
function ExpressionListT* parseArguments() {
let ExpressionListT* args = new ExpressionListT;
let ExpressionListT* cur = args;
expect('(');
if (!match(')')) {
while (index < length) {
cur->elem = parseAssignmentExpression();
if (match(')')) {
break;
}
expect(',');
}
}
expect(')');
return args;
}
function IdentifierT* parseNonComputedProperty() {
let token = lex();
if (!isIdentifierName(token)) {
throwUnexpected(token);
}
let IdentifierT* identifier = new IdentifierT;
identifier->name = convertStr(token.value);
return identifier;
}
function MemberExpressionT* parseNonComputedMember(ExpressionT* object) {
let MemberExpressionT* member = new MemberExpressionT;
member->computed = 0;
member->object = object;
member->propertyType = Syntax->Identifier;
member->property.identifier = parseNonComputedProperty();
return member;
}
function MemberExpressionT* parseComputedMember(ExpressionT* object) {
let MemberExpressionT* expr
expect('[');
expr = new MemberExpressionT;
expr->computed = 1;
expr->object = object;
expr->propertyType = Syntax->Expression;
expr->property.expression = parseExpression();
expect(']');
return expr;
}
function CallExpressionT* parseCallMember(ExpressionT* object) {
let CallExpressionT* expr = new CallExpressionT;
expr->callee = object;
expr->arguments = parseArguments();
return expr;
}
function ExpressionT* parseNewExpression() {
expectKeyword('new');
let NewExpressionT* newExpr = new NewExpressionT;
newExpr->callee = parseLeftHandSideExpression();
if (match('(')) {
newExpr->arguments = parseArguments();
}
return castExpression(newExpr, Syntax->NewExpression);
}
function ExpressionT* parseLeftHandSideExpressionAllowCall() {
let ExpressionT* expr;
let useNew = matchKeyword('new');
expr = useNew ? parseNewExpression() : parsePrimaryExpression();
while (index < length) {
if (match('.')) {
lex();
expr = castExpression(parseNonComputedMember(expr), Syntax->MemberExpression);
} else if (match('[')) {
expr = castExpression(parseComputedMember(expr), Syntax->MemberExpression);
} else if (match('(')) {
expr = castExpression(parseCallMember(expr), Syntax->CallExpression);
} else {
break;
}
}
return expr;
}
function ExpressionT* parseLeftHandSideExpression() {
let useNew;
let ExpressionT* expr;
useNew = matchKeyword('new');
expr = useNew ? parseNewExpression() : parsePrimaryExpression();
while (index < length) {
if (match('.')) {
lex();
expr = castExpression(parseNonComputedMember(expr), Syntax->MemberExpression);
} else if (match('[')) {
expr = castExpression(parseComputedMember(expr), Syntax->MemberExpression);
} else {
break;
}
}
return expr;
}
// 11.3 Postfix Expressions
function ExpressionT* parsePostfixExpression() {
let ExpressionT* expr;
expr = parseLeftHandSideExpressionAllowCall();
if ((match('++') || match('--')) && !peekLineTerminator()) {
// 11.3.1, 11.3.2
if (strict && expr->type === Syntax->Identifier && isRestrictedWord(expr->c.identifier->name)) {
throwError({}, Messages.StrictLHSPostfix);
}
if (!isLeftHandSide(expr)) {
throwError({}, Messages.InvalidLHSInAssignment);
}
let UpdateExpressionT* newExpr = new UpdateExpressionT;
newExpr->operator = convertOperator(lex().value);
newExpr->argument = expr;
newExpr->prefix = 0;
expr = new ExpressionT;
expr->type = Syntax->UpdateExpression;
expr->c.update = newExpr;
}
return expr;
}
// 11.4 Unary Operators
function ExpressionT* parseUnaryExpression() {
let token;
let ExpressionT* expr;
if (match('++') || match('--')) {
token = lex();
expr = parseUnaryExpression();
// 11.4.4, 11.4.5
if (strict && expr->type === Syntax->Identifier && isRestrictedWord(expr->c.identifier->name)) {
throwError({}, Messages.StrictLHSPrefix);
}
if (!isLeftHandSide(expr)) {
throwError({}, Messages.InvalidLHSInAssignment);
}
let UpdateExpressionT* update = new UpdateExpressionT;
update->operator = convertOperator(token.value);
update->argument = expr;
update->prefix = 1;
expr = new ExpressionT;
expr->type = Syntax->UpdateExpression;
expr->c.update = update;
return expr;
}
if (match('+') || match('-') || match('~') || match('!')) {
let UnaryExpressionT* unary = new UnaryExpressionT;
unary->operator = convertOperator(lex().value);
unary->argument = parseUnaryExpression();
expr = new ExpressionT;
expr->type = Syntax->UnaryExpression;
expr->c.unary = unary;
return expr;
}
if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
let UnaryExpressionT* unary = new UnaryExpressionT;
unary->operator = convertOperator(lex().value);
unary->argument = parseUnaryExpression();
expr = new ExpressionT;
expr->type = Syntax->UnaryExpression;
expr->c.unary = unary;
if (strict && unary->operator === 'delete' && unary->argument->type === Syntax->Identifier) {
throwErrorTolerant({}, Messages.StrictDelete);
}
return expr;
}
return parsePostfixExpression();
}
// 11.5 Multiplicative Operators
function ExpressionT* parseMultiplicativeExpression() {
let ExpressionT* expr;
expr = parseUnaryExpression();
while (match('*') || match('/') || match('%')) {
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator(lex().value);
binary->left = expr;
binary->right = parseUnaryExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
// 11.6 Additive Operators
function ExpressionT* parseAdditiveExpression() {
let ExpressionT* expr;
expr = parseMultiplicativeExpression();
while (match('+') || match('-')) {
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator(lex().value);
binary->left = expr;
binary->right = parseMultiplicativeExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
// 11.7 Bitwise Shift Operators
function ExpressionT* parseShiftExpression() {
let ExpressionT* expr;
expr = parseAdditiveExpression();
while (match('<<') || match('>>') || match('>>>')) {
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator(lex().value);
binary->left = expr;
binary->right = parseAdditiveExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
// 11.8 Relational Operators
function ExpressionT* parseRelationalExpression() {
let previousAllowIn;
let ExpressionT* expr;
previousAllowIn = state.allowIn;
state.allowIn = true;
expr = parseShiftExpression();
while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator(lex().value);
binary->left = expr;
binary->right = parseShiftExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
state.allowIn = previousAllowIn;
return expr;
}
// 11.9 Equality Operators
function ExpressionT* parseEqualityExpression() {
let ExpressionT* expr;
expr = parseRelationalExpression();
while (match('==') || match('!=') || match('===') || match('!==')) {
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator(lex().value);
binary->left = expr;
binary->right = parseRelationalExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
// 11.10 Binary Bitwise Operators
function ExpressionT* parseBitwiseANDExpression() {
let ExpressionT* expr;
expr = parseEqualityExpression();
while (match('&')) {
lex();
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator('&');
binary->left = expr;
binary->right = parseEqualityExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
function ExpressionT* parseBitwiseXORExpression() {
let ExpressionT* expr;
expr = parseBitwiseANDExpression();
while (match('^')) {
lex();
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator('^');
binary->left = expr;
binary->right = parseBitwiseANDExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
function ExpressionT* parseBitwiseORExpression() {
let ExpressionT* expr;
expr = parseBitwiseXORExpression();
while (match('|')) {
lex();
let BinaryExpressionT* binary = new BinaryExpressionT;
binary->operator = convertOperator('|');
binary->left = expr;
binary->right = parseBitwiseXORExpression();
expr = new ExpressionT;
expr->type = Syntax->BinaryExpression;
expr->c.binary = binary;
}
return expr;
}
// 11.11 Binary Logical Operators
function ExpressionT* parseLogicalANDExpression() {
let ExpressionT* expr;
expr = parseBitwiseORExpression();
while (match('&&')) {
lex();
let LogicalExpressionT* logical = new LogicalExpressionT;
logical->operator = convertOperator('&&');
logical->left = expr;
logical->right = parseBitwiseORExpression();
expr = new ExpressionT;
expr->type = Syntax->LogicalExpression;
expr->c.logical = logical;
}
return expr;
}
function ExpressionT* parseLogicalORExpression() {
let ExpressionT* expr;
expr = parseLogicalANDExpression();
while (match('||')) {
lex();
let LogicalExpressionT* logical = new LogicalExpressionT;
logical->operator = convertOperator('||');
logical->left = expr;
logical->right = parseLogicalANDExpression();
expr = new ExpressionT;
expr->type = Syntax->LogicalExpression;
expr->c.logical = logical;
}
return expr;
}
// 11.12 Conditional Operator
function ExpressionT* parseConditionalExpression() {
let previousAllowIn;
let ExpressionT *expr, *consequent;
expr = parseLogicalORExpression();
if (match('?')) {
lex();
previousAllowIn = state.allowIn;
state.allowIn = true;
consequent = parseAssignmentExpression();
state.allowIn = previousAllowIn;
expect(':');
let ConditionalExpressionT* conditional = new ConditionalExpressionT;
conditional->test = expr;
conditional->consequent = consequent;
conditional->alternate = parseAssignmentExpression();
expr = new ExpressionT;
expr->type = Syntax->ConditionalExpression;
expr->c.conditional = conditional;
}
return expr;
}
// 11.13 Assignment Operators
function ExpressionT* parseAssignmentExpression() {
let ExpressionT* expr;
expr = parseConditionalExpression();
if (matchAssign()) {
// LeftHandSideExpression
if (!isLeftHandSide(expr)) {
throwError({}, Messages.InvalidLHSInAssignment);
}
// 11.13.1
if (strict && expr->type === Syntax->Identifier && isRestrictedWord(expr->c.identifier->name)) {
throwError({}, Messages.StrictLHSAssignment);
}
let AssignmentExpressionT* assignment = new AssignmentExpressionT;
assignment->operator = convertOperator(lex().value);
assignment->left = expr;
assignment->right = parseAssignmentExpression();
expr = castExpression(assignment, Syntax->AssignmentExpression);
}
return expr;
}
// 11.14 Comma Operator
function ExpressionT* parseExpression() {
let ExpressionT* expr;
expr = parseAssignmentExpression();
if (match(',')) {
let SequenceExpressionT* sequence = new SequenceExpressionT;
sequence->expressions = new ExpressionListT;
let ExpressionListT* cur = sequence->expressions;
cur->elem = expr;
while (index < length) {
if (!match(',')) {
break;
}
lex();
cur->next = new ExpressionListT;
cur = cur->next;
cur->elem = castExpression(parseAssignmentExpression(), Syntax->AssignmentExpression);
}
expr = new ExpressionT;
expr->type = Syntax->SequenceExpression;
expr->c.sequence = sequence;
}
return expr;
}
// 12.1 Block
function StatementListT* parseStatementList() {
let StatementListT* list = new StatementListT;
let StatementListT* cur = list;
let StatementT* statement;
while (index < length) {
if (match('}')) {
break;
}
statement = parseSourceElement();
if (statement === null) {
break;
}
cur->elem = statement;
cur->next = new StatementListT;
cur = cur->next;
}
return list;
}
function BlockStatementT* parseBlock() {
let StatementListT* block;
expect('{');
block = parseStatementList();
expect('}');
let BlockStatementT* blockSt = new BlockStatementT;
blockSt->body = block;
return blockSt;
}
// 12.2 Variable Statement
function IdentifierT* parseVariableIdentifier() {
let token = lex();
if (token.type !== Token.Identifier) {
throwUnexpected(token);
}
let IdentifierT* ident = new IdentifierT;
ident->name = convertStr(token.value);
return ident;
}
function VariableDeclaratorT* parseVariableDeclaration(u8 kind) {
let PatternT* init;
let IdentifierT* id;
id = parseVariableIdentifier();
// 12.2.1
if (strict && isRestrictedWord(id->name)) {
throwErrorTolerant({}, Messages.StrictVarName);
}
if (kind === 'const') {
expect('=');
init = castPattern(parseAssignmentExpression(), Syntax->Expression);
} else if (match('=')) {
lex();
init = castPattern(parseAssignmentExpression(), Syntax->Expression);
}
let VariableDeclaratorT* decl = new VariableDeclaratorT;
decl->id = castPattern(id, Syntax->Identifier);
decl->init = castExpression(init, Syntax->Identifier);
return decl;
}
function VariableDeclaratorListT* parseVariableDeclarationList(u8 kind) {
let VariableDeclaratorListT* list = new VariableDeclaratorListT;
let VariableDeclaratorListT* cur = list;
while (index < length) {
cur->elem = parseVariableDeclaration(kind);
cur->next = new VariableDeclaratorListT;
cur = cur->next;
if (!match(',')) {
break;
}
lex();
}
return list;
}
function VariableDeclarationT* parseVariableStatement() {
let VariableDeclaratorListT* declarations;
expectKeyword('var');
declarations = parseVariableDeclarationList(VAR_KIND_VAR);
consumeSemicolon();
let VariableDeclarationT* decl = new VariableDeclarationT;
decl->declarations = declarations;
decl->kind = VAR_KIND_VAR;
return decl;
}
// kind may be `const` or `let`
// Both are experimental and not in the specification yet.
// see http://wiki.ecmascript.org/doku.php?id=harmony:const
// and http://wiki.ecmascript.org/doku.php?id=harmony:let
function VariableDeclarationT* parseConstLetDeclaration(u8 kind) {
let VariableDeclaratorListT* declarations;
switch (kind) {
case VAR_KIND_VAR:
expectKeyword('var');
break;
case VAR_KIND_LET:
expectKeyword('var');
break;
case VAR_KIND_CONST:
expectKeyword('var');
break;
}
declarations = parseVariableDeclarationList(kind);
consumeSemicolon();
let VariableDeclarationT* decl = new VariableDeclarationT;
decl->declarations = declarations;
decl->kind = kind;
return decl;
}
// 12.3 Empty Statement
function EmptyStatementT* parseEmptyStatement() {
expect(';');
let EmptyStatementT* s = new EmptyStatementT;
s->type = Syntax->EmptyStatement;
return s;
}
// 12.4 Expression Statement
function ExpressionStatementT* parseExpressionStatement() {
let ExpressionT* expr;
expr = parseExpression();
consumeSemicolon();
let ExpressionStatementT* s = new ExpressionStatementT;
s->type = Syntax->ExpressionStatement;
s->expression = expr;
return s;
}
// 12.5 If statement
function IfStatementT* parseIfStatement() {
let ExpressionT* test;
let StatementT *consequent, *alternate;
expectKeyword('if');
expect('(');
test = parseExpression();
expect(')');
consequent = parseStatement();
if (matchKeyword('else')) {
lex();
alternate = parseStatement();
} else {
alternate = null;
}
let IfStatementT* st = new IfStatementT;
st->test = test;
st->consequent = consequent;
st->alternate = alternate;
return st;
}
// 12.6 Iteration Statements
function DoWhileStatementT* parseDoWhileStatement() {
let oldInIteration;
let StatementT* body;
let ExpressionT* test;
expectKeyword('do');
oldInIteration = state.inIteration;
state.inIteration = true;
body = parseStatement();
state.inIteration = oldInIteration;
expectKeyword('while');
expect('(');
test = parseExpression();
expect(')');
if (match(';')) {
lex();
}
let DoWhileStatementT* st = new DoWhileStatementT;
st->body = body;
st->test = test;
return st;
}
function WhileStatementT* parseWhileStatement() {
let oldInIteration;
let ExpressionT* test;
let StatementT* body;
expectKeyword('while');
expect('(');
test = parseExpression();
expect(')');
oldInIteration = state.inIteration;
state.inIteration = true;
body = parseStatement();
state.inIteration = oldInIteration;
let WhileStatementT* st = new WhileStatementT;
st->test = test;
st->body = body;
return st;
}
function VariableDeclarationT* parseForVariableDeclaration() {
let token = lex();
let VariableDeclarationT* decl = new VariableDeclarationT;
decl->declarations = parseVariableDeclarationList(VAR_KIND_VAR); // TODO - check kind
decl->kind = convertVarKind(token.value);
return decl;
}
function StatementT* parseForStatement() {
let oldInIteration;
let ForInitU *init, *left;
let ExpressionT *test, *update, *right;
let StatementT* body;
let u8 initType;
expectKeyword('for');
expect('(');
if (match(';')) {
lex();
} else {
if (matchKeyword('var') || matchKeyword('let')) {
state.allowIn = false;
initType = Syntax->VariableDeclaration;
init = new ForInitU;
init->variableDeclaration = parseForVariableDeclaration();
state.allowIn = true;
if (varDeclListLength(init->variableDeclaration->declarations) === 1 && matchKeyword('in')) {
lex();
left = init;
right = parseExpression();
init->variableDeclaration = null;
}
} else {
state.allowIn = false;
initType = Syntax->Expression;
init = new ForInitU;
init->expression = parseExpression();
state.allowIn = true;
if (matchKeyword('in')) {
// LeftHandSideExpression
if (!isLeftHandSide(init->expression)) {
throwError({}, Messages.InvalidLHSInForIn);
}
lex();
left = init;
right = parseExpression();
init->expression = null;
}
}
if (left === null) {
expect(';');
}
}
if (left === null) {
if (!match(';')) {
test = parseExpression();
}
expect(';');
if (!match(')')) {
update = parseExpression();
}
}
expect(')');
oldInIteration = state.inIteration;
state.inIteration = true;
body = parseStatement();
state.inIteration = oldInIteration;
if (left === null) {
let ForStatementT* st = new ForStatementT;
st->init = init;
st->test = test;
st->update = update;
st->body = body;
return castStatement(st, Syntax->ForStatement);
}
let ForInStatementT* st = new ForInStatementT;
st->left = left;
st->right = right;
st->body = body;
st->each = 0;
return castStatement(st, Syntax->ForInStatement);
}
// 12.7 The continue statement
function ContinueStatementT* parseContinueStatement() {
let token;
let IdentifierT* label;
let ContinueStatementT* st;
expectKeyword('continue');
// Optimize the most common form: 'continue;'.
if (source[index] === ';') {
lex();
if (!state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
return new ContinueStatementT;
}
if (peekLineTerminator()) {
if (!state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
return new ContinueStatementT;
}
token = lookahead();
if (token.type === Token.Identifier) {
label = parseVariableIdentifier();
if (!Object.prototype.hasOwnProperty.call(state.labelSet, readStr(label->name))) {
throwError({}, Messages.UnknownLabel, readStr(label->name));
}
}
consumeSemicolon();
if (label === null && !state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
st = new ContinueStatementT;
st->label = label;
return st;
}
// 12.8 The break statement
function BreakStatementT* parseBreakStatement() {
let token;
let BreakStatementT* st = new BreakStatementT;
let IdentifierT* label;
expectKeyword('break');
// Optimize the most common form: 'break;'.
if (source[index] === ';') {
lex();
if (!(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
return st;
}
if (peekLineTerminator()) {
if (!(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
return st;
}
token = lookahead();
if (token.type === Token.Identifier) {
label = parseVariableIdentifier();
if (!Object.prototype.hasOwnProperty.call(state.labelSet, readStr(label->name))) {
throwError({}, Messages.UnknownLabel, readStr(label->name));
}
}
consumeSemicolon();
if (label === null && !(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
st->label = label;
return st;
}
// 12.9 The return statement
function ReturnStatementT* parseReturnStatement() {
let token;
let ReturnStatementT* st;
let ExpressionT* argument;
expectKeyword('return');
if (!state.inFunctionBody) {
throwErrorTolerant({}, Messages.IllegalReturn);
}
// 'return' followed by a space and an identifier is very common.
if (source[index] === ' ') {
if (isIdentifierStart(source[index + 1])) {
argument = parseExpression();
consumeSemicolon();
st = new ReturnStatementT;
st->argument = argument
return st;
}
}
if (peekLineTerminator()) {
st = new ReturnStatementT;
return st;
}
if (!match(';')) {
token = lookahead();
if (!match('}') && token.type !== Token.EOF) {
argument = parseExpression();
}
}
consumeSemicolon();
st = new ReturnStatementT;
st->argument = argument
return st;
}
// 12.10 The with statement
function WithStatementT* parseWithStatement() {
let ExpressionT* object;
let StatementT* body;
if (strict) {
throwErrorTolerant({}, Messages.StrictModeWith);
}
expectKeyword('with');
expect('(');
object = parseExpression();
expect(')');
body = parseStatement();
let WithStatementT* st = new WithStatementT;
st->object = object;
st->body = body;
return st;
}
// 12.10 The swith statement
function SwitchCaseT* parseSwitchCase() {
let ExpressionT* test;
let StatementListT* consequent = new StatementListT;
let StatementListT* cur = consequent;
let StatementT* statement;
let clause, defaultFound;
if (matchKeyword('default')) {
lex();
test = null;
} else {
expectKeyword('case');
test = parseExpression();
}
expect(':');
while (index < length) {
if (match('}') || matchKeyword('default') || matchKeyword('case')) {
break;
}
statement = parseStatement();
if (statement === null) {
break;
}
cur->elem = statement;
cur->next = new StatementListT;
cur = cur->next;
}
let SwitchCaseT* s = new SwitchCaseT;
s->test = test;
s->consequent = consequent;
return s;
}
function SwitchStatementT* parseSwitchStatement() {
let oldInSwitch;
let SwitchStatementT* st;
let ExpressionT* discriminant;
let SwitchCaseListT* cases;
let defaultFound;
let SwitchCaseT* clause;
expectKeyword('switch');
expect('(');
discriminant = parseExpression();
expect(')');
expect('{');
if (match('}')) {
lex();
st = new SwitchStatementT;
st->discriminant = discriminant;
return st;
}
cases = new SwitchCaseListT;
let SwitchCaseListT* cur = cases;
oldInSwitch = state.inSwitch;
state.inSwitch = true;
defaultFound = false;
while (index < length) {
if (match('}')) {
break;
}
clause = parseSwitchCase();
if (clause->test === null) {
if (defaultFound) {
throwError({}, Messages.MultipleDefaultsInSwitch);
}
defaultFound = true;
}
cur->elem = clause;
cur->next = new SwitchCaseListT;
cur = cur->next;
}
state.inSwitch = oldInSwitch;
expect('}');
st = new SwitchStatementT;
st->discriminant = discriminant;
st->cases = cases;
return st;
}
// 12.13 The throw statement
function ThrowStatementT* parseThrowStatement() {
let ExpressionT* argument;
expectKeyword('throw');
if (peekLineTerminator()) {
throwError({}, Messages.NewlineAfterThrow);
}
argument = parseExpression();
consumeSemicolon();
let ThrowStatementT* st = new ThrowStatementT;
st->argument = argument;
return st;
}
// 12.14 The try statement
function CatchClauseT* parseCatchClause() {
let PatternT* param;
expectKeyword('catch');
expect('(');
if (!match(')')) {
param = castPattern(parseExpression(), Syntax->Expression);
// 12.14.1
if (strict && param->type === Syntax->Identifier && isRestrictedWord(readStr(param->c.identifier->name))) {
throwErrorTolerant({}, Messages.StrictCatchVariable);
}
}
expect(')');
let CatchClauseT* clause = new CatchClauseT;
clause->param = param;
clause->body = parseBlock();
return clause;
}
function TryStatementT* parseTryStatement() {
let BlockStatementT* block;
let CatchClauseListT* handlers = new CatchClauseListT;
let BlockStatementT* finalizer;
expectKeyword('try');
block = parseBlock();
let CatchClauseListT* cur = handlers;
if (matchKeyword('catch')) {
cur->elem = parseCatchClause();
cur->next = new CatchClauseListT;
cur = cur->next;
}
if (matchKeyword('finally')) {
lex();
finalizer = parseBlock();
}
if (catchClauseListLength(handlers) === 0 && !finalizer) {
throwError({}, Messages.NoCatchOrFinally);
}
let TryStatementT* st = new TryStatementT;
st->block = block;
st->handlers = handlers;
st->finalizer = finalizer;
return st;
}
// 12.15 The debugger statement
function DebuggerStatementT* parseDebuggerStatement() {
expectKeyword('debugger');
consumeSemicolon();
return new DebuggerStatementT;
}
// 12 Statements
function StatementT* parseStatement() {
let token = lookahead();
let StatementT* labeledBody;
let ExpressionT* expr;
if (token.type === Token.EOF) {
throwUnexpected(token);
}
if (token.type === Token.Punctuator) {
switch (token.value) {
case ';':
return parseEmptyStatement();
case '{':
return castStatement(parseBlock(), Syntax->BlockStatement);
case '(':
return castStatement(parseExpressionStatement(), Syntax->ExpressionStatement);
default:
break;
}
}
if (token.type === Token.Keyword) {
switch (token.value) {
case 'break':
return castStatement(parseBreakStatement(), Syntax->BreakStatement);
case 'continue':
return castStatement(parseContinueStatement(), Syntax->ContinueStatement);
case 'debugger':
return parseDebuggerStatement();
case 'do':
return castStatement(parseDoWhileStatement(), Syntax->DoWhileStatement);
case 'for':
return parseForStatement();
case 'function':
return castStatement(parseFunctionDeclaration(), Syntax->FunctionDeclaration);
case 'if':
return castStatement(parseIfStatement(), Syntax->IfStatement);
case 'return':
return castStatement(parseReturnStatement(), Syntax->ReturnStatement);
case 'switch':
return castStatement(parseSwitchStatement(), Syntax->SwitchStatement);
case 'throw':
return castStatement(parseThrowStatement(), Syntax->ThrowStatement);
case 'try':
return castStatement(parseTryStatement(), Syntax->TryStatement);
case 'var':
return castStatement(parseVariableStatement(), Syntax->VariableDeclaration);
case 'while':
return castStatement(parseWhileStatement(), Syntax->WhileStatement);
case 'with':
return castStatement(parseWithStatement(), Syntax->WithStatement);
default:
break;
}
}
expr = parseExpression();
// 12.12 Labelled Statements
if ((expr->type === Syntax->Identifier) && match(':')) {
lex();
let name = readStr(expr->c.identifier->name);
if (Object.prototype.hasOwnProperty.call(state.labelSet, name)) {
throwError({}, Messages.Redeclaration, 'Label', name);
}
state.labelSet[name] = true;
labeledBody = parseStatement();
delete state.labelSet[name];
let LabeledStatementT* st = new LabeledStatementT;
st->label = expr->c.identifier;
st->body = labeledBody;
return castStatement(st, Syntax->LabeledStatement);
}
consumeSemicolon();
let ExpressionStatementT* st = new ExpressionStatementT;
st->expression = expr;
return castStatement(st, Syntax->ExpressionStatement);
}
// 13 Function Definition
function BlockStatementT* parseFunctionSourceElements() {
let token, directive, firstRestricted,
oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
let StatementT* sourceElement;
let StatementListT* sourceElements = new StatementListT;
let StatementListT* cur = sourceElements;
expect('{');
while (index < length) {
token = lookahead();
if (token.type !== Token.StringLiteral) {
break;
}
cur->elem = parseSourceElement();
if (cur->elem->type === Syntax->ExpressionStatement && cur->elem->c.expression->type !== Syntax->Literal) {
// this is not directive
break;
}
cur->next = new StatementListT;
cur = cur->next;
directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
if (directive === 'use strict') {
strict = true;
if (firstRestricted) {
throwError(firstRestricted, Messages.StrictOctalLiteral);
}
} else {
if (!firstRestricted && token.octal) {
firstRestricted = token;
}
}
}
oldLabelSet = state.labelSet;
oldInIteration = state.inIteration;
oldInSwitch = state.inSwitch;
oldInFunctionBody = state.inFunctionBody;
state.labelSet = {};
state.inIteration = false;
state.inSwitch = false;
state.inFunctionBody = true;
while (index < length) {
if (match('}')) {
break;
}
sourceElement = parseSourceElement();
if (sourceElement === null) {
break;
}
cur->elem = sourceElement;
cur->next = new StatementListT;
cur = cur->next;
}
expect('}');
state.labelSet = oldLabelSet;
state.inIteration = oldInIteration;
state.inSwitch = oldInSwitch;
state.inFunctionBody = oldInFunctionBody;
let BlockStatementT* block = new BlockStatementT;
block->body = sourceElements;
return block;
}
function FunctionDeclarationT* parseFunctionDeclaration() {
let token, firstRestricted, message, previousStrict, paramSet;
let IdentifierT* id;
let PatternListT* params = new PatternListT;
let PatternListT* cur = params;
let IdentifierT* param;
let BlockStatementT* body;
expectKeyword('function');
token = lookahead();
id = parseVariableIdentifier();
if (strict) {
if (isRestrictedWord(token.value)) {
throwError(token, Messages.StrictFunctionName);
}
} else {
if (isRestrictedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictFunctionName;
} else if (isStrictModeReservedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictReservedWord;
}
}
expect('(');
if (!match(')')) {
paramSet = {};
while (index < length) {
token = lookahead();
param = parseVariableIdentifier();
if (strict) {
if (isRestrictedWord(token.value)) {
throwError(token, Messages.StrictParamName);
}
if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
throwError(token, Messages.StrictParamDupe);
}
} else if (!firstRestricted) {
if (isRestrictedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictParamName;
} else if (isStrictModeReservedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictReservedWord;
} else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
firstRestricted = token;
message = Messages.StrictParamDupe;
}
}
cur->elem = castPattern(param, Syntax->Identifier);
cur->next = new PatternListT;
cur = cur->next;
paramSet[readStr(param->name)] = true;
if (match(')')) {
break;
}
expect(',');
}
}
expect(')');
previousStrict = strict;
body = parseFunctionSourceElements();
if (strict && firstRestricted) {
throwError(firstRestricted, message);
}
strict = previousStrict;
let FunctionDeclarationT* decl = new FunctionDeclarationT;
decl->id = id;
decl->params = params;
decl->defaults = new ExpressionListT;
decl->bodyType = Syntax->BlockStatement;
decl->body.block = body;
decl->rest = null;
decl->generator = 0;
decl->expression = 0;
return decl;
}
function FunctionExpressionT* parseFunctionExpression() {
let token, firstRestricted, message, previousStrict, paramSet;
let IdentifierT* id;
let PatternListT* params = new PatternListT;
let PatternListT* cur = params;
let IdentifierT* param;
let BlockStatementT* body;
expectKeyword('function');
if (!match('(')) {
token = lookahead();
id = parseVariableIdentifier();
if (strict) {
if (isRestrictedWord(token.value)) {
throwError(token, Messages.StrictFunctionName);
}
} else {
if (isRestrictedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictFunctionName;
} else if (isStrictModeReservedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictReservedWord;
}
}
}
expect('(');
if (!match(')')) {
paramSet = {};
while (index < length) {
token = lookahead();
param = parseVariableIdentifier();
if (strict) {
if (isRestrictedWord(token.value)) {
throwError(token, Messages.StrictParamName);
}
if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
throwError(token, Messages.StrictParamDupe);
}
} else if (!firstRestricted) {
if (isRestrictedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictParamName;
} else if (isStrictModeReservedWord(token.value)) {
firstRestricted = token;
message = Messages.StrictReservedWord;
} else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
firstRestricted = token;
message = Messages.StrictParamDupe;
}
}
cur->elem = castPattern(param, Syntax->Identifier);
cur->next = new PatternListT;
cur = cur->next;
paramSet[readStr(param->name)] = true;
if (match(')')) {
break;
}
expect(',');
}
}
expect(')');
previousStrict = strict;
body = parseFunctionSourceElements();
if (strict && firstRestricted) {
throwError(firstRestricted, message);
}
strict = previousStrict;
let FunctionExpressionT* expr = new FunctionExpressionT;
expr->id = id;
expr->params = params;
expr->defaults = new ExpressionListT;
expr->bodyType = Syntax->BlockStatement;
expr->body.block = body;
expr->rest = null;
expr->generator = 0;
expr->expression = 0;
return expr;
}
// 14 Program
function StatementT* parseSourc