/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "Lexer.h"
#include "Nodes.h"
#include "ParserArena.h"
+#include "ParserError.h"
#include "ParserTokens.h"
#include "SourceProvider.h"
+#include "SourceProviderCache.h"
#include "SourceProviderCacheItem.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
class FunctionBodyNode;
class FunctionParameters;
class Identifier;
-class JSGlobalData;
+class VM;
class ProgramNode;
class SourceCode;
-class UString;
-
-#define fail() do { if (!m_error) updateErrorMessage(); return 0; } while (0)
-#define failWithToken(tok) do { if (!m_error) updateErrorMessage(tok); return 0; } while (0)
-#define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0)
-#define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0)
-#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
-#define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0)
-#define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0)
-#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
-#define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0)
-#define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0)
-#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
-#define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0)
-#define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
-#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
-#define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0)
-#define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
-#define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0)
-#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0)
-#define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0)
-#define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0)
-
- // Macros to make the more common TreeBuilder types a little less verbose
+
+// Macros to make the more common TreeBuilder types a little less verbose
#define TreeStatement typename TreeBuilder::Statement
#define TreeExpression typename TreeBuilder::Expression
#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
#define TreeFunctionBody typename TreeBuilder::FunctionBody
#define TreeProperty typename TreeBuilder::Property
#define TreePropertyList typename TreeBuilder::PropertyList
+#define TreeDeconstructionPattern typename TreeBuilder::DeconstructionPattern
COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+enum FunctionParseMode { FunctionMode, GetterMode, SetterMode };
+enum DeconstructionKind {
+ DeconstructToVariables,
+ DeconstructToParameters,
+ DeconstructToExpressions
+};
template <typename T> inline bool isEvalNode() { return false; }
template <> inline bool isEvalNode<EvalNode>() { return true; }
-struct DepthManager {
- DepthManager(int* depth)
- : m_originalDepth(*depth)
- , m_depth(depth)
- {
- }
-
- ~DepthManager()
- {
- *m_depth = m_originalDepth;
- }
-
-private:
- int m_originalDepth;
- int* m_depth;
-};
-
struct ScopeLabelInfo {
ScopeLabelInfo(StringImpl* ident, bool isLoop)
: m_ident(ident)
};
struct Scope {
- Scope(const JSGlobalData* globalData, bool isFunction, bool strictMode)
- : m_globalData(globalData)
+ Scope(const VM* vm, bool isFunction, bool strictMode)
+ : m_vm(vm)
, m_shadowsArguments(false)
, m_usesEval(false)
, m_needsFullActivation(false)
}
Scope(const Scope& rhs)
- : m_globalData(rhs.m_globalData)
+ : m_vm(rhs.m_vm)
, m_shadowsArguments(rhs.m_shadowsArguments)
, m_usesEval(rhs.m_usesEval)
, m_needsFullActivation(rhs.m_needsFullActivation)
bool isFunction() { return m_isFunction; }
bool isFunctionBoundary() { return m_isFunctionBoundary; }
+ void declareCallee(const Identifier* ident)
+ {
+ m_declaredVariables.add(ident->string().impl());
+ }
+
bool declareVariable(const Identifier* ident)
{
- bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+ bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
- m_declaredVariables.add(ident->ustring().impl());
+ m_declaredVariables.add(ident->string().impl());
return isValidStrictMode;
}
+ bool hasDeclaredVariable(const Identifier& ident)
+ {
+ return m_declaredVariables.contains(ident.impl());
+ }
+
+ bool hasDeclaredParameter(const Identifier& ident)
+ {
+ return m_declaredParameters.contains(ident.impl()) || m_declaredVariables.contains(ident.impl());
+ }
+
void declareWrite(const Identifier* ident)
{
ASSERT(m_strictMode);
bool declareParameter(const Identifier* ident)
{
- bool isArguments = m_globalData->propertyNames->arguments == *ident;
- bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).isNewEntry && m_globalData->propertyNames->eval != *ident && !isArguments;
+ bool isArguments = m_vm->propertyNames->arguments == *ident;
+ bool isValidStrictMode = m_declaredVariables.add(ident->string().impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ m_declaredParameters.add(ident->string().impl());
+
if (isArguments)
m_shadowsArguments = true;
return isValidStrictMode;
}
+
+ enum BindingResult {
+ BindingFailed,
+ StrictBindingFailed,
+ BindingSucceeded
+ };
+ BindingResult declareBoundParameter(const Identifier* ident)
+ {
+ bool isArguments = m_vm->propertyNames->arguments == *ident;
+ bool newEntry = m_declaredVariables.add(ident->string().impl()).isNewEntry;
+ bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+
+ if (isArguments)
+ m_shadowsArguments = true;
+ if (!newEntry)
+ return BindingFailed;
+ return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
+ }
+
+ void getUsedVariables(IdentifierSet& usedVariables)
+ {
+ usedVariables.swap(m_usedVariables);
+ }
void useVariable(const Identifier* ident, bool isEval)
{
m_usesEval |= isEval;
- m_usedVariables.add(ident->ustring().impl());
+ m_usedVariables.add(ident->string().impl());
}
void setNeedsFullActivation() { m_needsFullActivation = true; }
return true;
}
- void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
- {
- IdentifierSet::iterator end = m_writtenVariables.end();
- for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
- if (!m_declaredVariables.contains(*ptr))
- writtenVariables.add(*ptr);
- }
- }
-
- void getCapturedVariables(IdentifierSet& capturedVariables)
+ void getCapturedVariables(IdentifierSet& capturedVariables, bool& modifiedParameter)
{
if (m_needsFullActivation || m_usesEval) {
+ modifiedParameter = true;
capturedVariables.swap(m_declaredVariables);
return;
}
continue;
capturedVariables.add(*ptr);
}
+ modifiedParameter = false;
+ if (m_declaredParameters.size()) {
+ IdentifierSet::iterator end = m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (!m_declaredParameters.contains(*ptr))
+ continue;
+ modifiedParameter = true;
+ break;
+ }
+ }
}
void setStrictMode() { m_strictMode = true; }
bool strictMode() const { return m_strictMode; }
bool isValidStrictMode() const { return m_isValidStrictMode; }
bool shadowsArguments() const { return m_shadowsArguments; }
- void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
+ void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl>>& vector)
{
IdentifierSet::iterator end = capturedVariables.end();
for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
continue;
vector.append(*it);
}
- vector.shrinkToFit();
}
- void saveFunctionInfo(SourceProviderCacheItem* info)
+ void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters)
{
ASSERT(m_isFunction);
- info->usesEval = m_usesEval;
- info->strictMode = m_strictMode;
- info->needsFullActivation = m_needsFullActivation;
- copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
- copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
+ parameters.usesEval = m_usesEval;
+ parameters.strictMode = m_strictMode;
+ parameters.needsFullActivation = m_needsFullActivation;
+ copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables);
+ copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables);
}
- void restoreFunctionInfo(const SourceProviderCacheItem* info)
+ void restoreFromSourceProviderCache(const SourceProviderCacheItem* info)
{
ASSERT(m_isFunction);
m_usesEval = info->usesEval;
m_strictMode = info->strictMode;
m_needsFullActivation = info->needsFullActivation;
- unsigned size = info->usedVariables.size();
- for (unsigned i = 0; i < size; ++i)
- m_usedVariables.add(info->usedVariables[i]);
- size = info->writtenVariables.size();
- for (unsigned i = 0; i < size; ++i)
- m_writtenVariables.add(info->writtenVariables[i]);
+ for (unsigned i = 0; i < info->usedVariablesCount; ++i)
+ m_usedVariables.add(info->usedVariables()[i]);
+ for (unsigned i = 0; i < info->writtenVariablesCount; ++i)
+ m_writtenVariables.add(info->writtenVariables()[i]);
}
private:
- const JSGlobalData* m_globalData;
+ const VM* m_vm;
bool m_shadowsArguments : 1;
bool m_usesEval : 1;
bool m_needsFullActivation : 1;
typedef Vector<ScopeLabelInfo, 2> LabelStack;
OwnPtr<LabelStack> m_labels;
+ IdentifierSet m_declaredParameters;
IdentifierSet m_declaredVariables;
IdentifierSet m_usedVariables;
IdentifierSet m_closedVariables;
WTF_MAKE_FAST_ALLOCATED;
public:
- Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode);
+ Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode);
~Parser();
template <class ParsedNode>
- PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, JSObject**);
+ PassRefPtr<ParsedNode> parse(ParserError&, bool needReparsingAdjustment);
+
+ JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
+ Vector<RefPtr<StringImpl>>&& closedVariables() { return WTF::move(m_closedVariables); }
private:
struct AllowInOverride {
isStrict = m_scopeStack.last().strictMode();
isFunction = m_scopeStack.last().isFunction();
}
- m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
+ m_scopeStack.append(Scope(m_vm, isFunction, isStrict));
return currentScope();
}
return m_scopeStack[i].declareVariable(ident);
}
+ NEVER_INLINE bool hasDeclaredVariable(const Identifier& ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsNewDecls()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].hasDeclaredVariable(ident);
+ }
+
+ NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsNewDecls()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].hasDeclaredParameter(ident);
+ }
+
void declareWrite(const Identifier* ident)
{
- if (!m_syntaxAlreadyValidated)
+ if (!m_syntaxAlreadyValidated || strictMode())
m_scopeStack.last().declareWrite(ident);
}
}
Parser();
- UString parseInner();
+ String parseInner();
void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
- ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures,
- int, int, IdentifierSet&);
+ ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures, int, IdentifierSet&, const Vector<RefPtr<StringImpl>>&&);
// Used to determine type of error to report.
bool isFunctionBodyNode(ScopeNode*) { return false; }
bool isFunctionBodyNode(FunctionBodyNode*) { return true; }
-
ALWAYS_INLINE void next(unsigned lexerFlags = 0)
{
- m_lastLine = m_token.m_info.line;
- m_lastTokenEnd = m_token.m_info.endOffset;
- m_lexer->setLastLineNumber(m_lastLine);
- m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexerFlags, strictMode());
+ int lastLine = m_token.m_location.line;
+ int lastTokenEnd = m_token.m_location.endOffset;
+ int lastTokenLineStart = m_token.m_location.lineStartOffset;
+ m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+ m_lexer->setLastLineNumber(lastLine);
+ m_token.m_type = m_lexer->lex(&m_token, lexerFlags, strictMode());
}
ALWAYS_INLINE void nextExpectIdentifier(unsigned lexerFlags = 0)
{
- m_lastLine = m_token.m_info.line;
- m_lastTokenEnd = m_token.m_info.endOffset;
- m_lexer->setLastLineNumber(m_lastLine);
- m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_info, lexerFlags, strictMode());
+ int lastLine = m_token.m_location.line;
+ int lastTokenEnd = m_token.m_location.endOffset;
+ int lastTokenLineStart = m_token.m_location.lineStartOffset;
+ m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+ m_lexer->setLastLineNumber(lastLine);
+ m_token.m_type = m_lexer->lexExpectIdentifier(&m_token, lexerFlags, strictMode());
}
ALWAYS_INLINE bool nextTokenIsColon()
next(flags);
return result;
}
-
- ALWAYS_INLINE UString getToken() {
+
+ void printUnexpectedTokenText(WTF::PrintStream&);
+ ALWAYS_INLINE String getToken() {
SourceProvider* sourceProvider = m_source->provider();
- return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl());
+ return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset);
}
ALWAYS_INLINE bool match(JSTokenType expected)
return m_token.m_type == expected;
}
- ALWAYS_INLINE int tokenStart()
+ ALWAYS_INLINE bool isofToken()
{
- return m_token.m_info.startOffset;
+ return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of;
}
- ALWAYS_INLINE int tokenLine()
+ ALWAYS_INLINE unsigned tokenStart()
{
- return m_token.m_info.line;
+ return m_token.m_location.startOffset;
}
- ALWAYS_INLINE int tokenEnd()
+ ALWAYS_INLINE const JSTextPosition& tokenStartPosition()
{
- return m_token.m_info.endOffset;
+ return m_token.m_startPosition;
}
-
- const char* getTokenName(JSTokenType tok)
+
+ ALWAYS_INLINE int tokenLine()
{
- switch (tok) {
- case NULLTOKEN:
- return "null";
- case TRUETOKEN:
- return "true";
- case FALSETOKEN:
- return "false";
- case BREAK:
- return "break";
- case CASE:
- return "case";
- case DEFAULT:
- return "default";
- case FOR:
- return "for";
- case NEW:
- return "new";
- case VAR:
- return "var";
- case CONSTTOKEN:
- return "const";
- case CONTINUE:
- return "continue";
- case FUNCTION:
- return "function";
- case IF:
- return "if";
- case THISTOKEN:
- return "this";
- case DO:
- return "do";
- case WHILE:
- return "while";
- case SWITCH:
- return "switch";
- case WITH:
- return "with";
- case THROW:
- return "throw";
- case TRY:
- return "try";
- case CATCH:
- return "catch";
- case FINALLY:
- return "finally";
- case DEBUGGER:
- return "debugger";
- case ELSE:
- return "else";
- case OPENBRACE:
- return "{";
- case CLOSEBRACE:
- return "}";
- case OPENPAREN:
- return "(";
- case CLOSEPAREN:
- return ")";
- case OPENBRACKET:
- return "[";
- case CLOSEBRACKET:
- return "]";
- case COMMA:
- return ",";
- case QUESTION:
- return "?";
- case SEMICOLON:
- return ";";
- case COLON:
- return ":";
- case DOT:
- return ".";
- case EQUAL:
- return "=";
- case PLUSEQUAL:
- return "+=";
- case MINUSEQUAL:
- return "-=";
- case MULTEQUAL:
- return "*=";
- case DIVEQUAL:
- return "/=";
- case LSHIFTEQUAL:
- return "<<=";
- case RSHIFTEQUAL:
- return ">>=";
- case URSHIFTEQUAL:
- return ">>>=";
- case ANDEQUAL:
- return "&=";
- case MODEQUAL:
- return "%=";
- case XOREQUAL:
- return "^=";
- case OREQUAL:
- return "|=";
- case AUTOPLUSPLUS:
- case PLUSPLUS:
- return "++";
- case AUTOMINUSMINUS:
- case MINUSMINUS:
- return "--";
- case EXCLAMATION:
- return "!";
- case TILDE:
- return "~";
- case TYPEOF:
- return "typeof";
- case VOIDTOKEN:
- return "void";
- case DELETETOKEN:
- return "delete";
- case OR:
- return "||";
- case AND:
- return "&&";
- case BITOR:
- return "|";
- case BITXOR:
- return "^";
- case BITAND:
- return "&";
- case EQEQ:
- return "==";
- case NE:
- return "!=";
- case STREQ:
- return "===";
- case STRNEQ:
- return "!==";
- case LT:
- return "<";
- case GT:
- return ">";
- case LE:
- return "<=";
- case GE:
- return ">=";
- case INSTANCEOF:
- return "instanceof";
- case INTOKEN:
- return "in";
- case LSHIFT:
- return "<<";
- case RSHIFT:
- return ">>";
- case URSHIFT:
- return ">>>";
- case PLUS:
- return "+";
- case MINUS:
- return "-";
- case TIMES:
- return "*";
- case DIVIDE:
- return "/";
- case MOD:
- return "%";
- case RETURN:
- case RESERVED_IF_STRICT:
- case RESERVED:
- case NUMBER:
- case IDENT:
- case STRING:
- case ERRORTOK:
- case EOFTOK:
- return 0;
- case LastUntaggedToken:
- break;
- }
- ASSERT_NOT_REACHED();
- return "internal error";
+ return m_token.m_location.line;
}
- ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken)
+ ALWAYS_INLINE int tokenColumn()
{
- String errorMessage;
- switch (expectedToken) {
- case RESERVED_IF_STRICT:
- errorMessage = "Use of reserved word '";
- errorMessage += getToken().impl();
- errorMessage += "' in strict mode";
- m_errorMessage = errorMessage.impl();
- return;
- case RESERVED:
- errorMessage = "Use of reserved word '";
- errorMessage += getToken().impl();
- errorMessage += "'";
- m_errorMessage = errorMessage.impl();
- return;
- case NUMBER:
- errorMessage = "Unexpected number '";
- errorMessage += getToken().impl();
- errorMessage += "'";
- m_errorMessage = errorMessage.impl();
- return;
- case IDENT:
- errorMessage = "Expected an identifier but found '";
- errorMessage += getToken().impl();
- errorMessage += "' instead";
- m_errorMessage = errorMessage.impl();
- return;
- case STRING:
- errorMessage = "Unexpected string ";
- errorMessage += getToken().impl();
- m_errorMessage = errorMessage.impl();
- return;
- case ERRORTOK:
- errorMessage = "Unrecognized token '";
- errorMessage += getToken().impl();
- errorMessage += "'";
- m_errorMessage = errorMessage.impl();
- return;
- case EOFTOK:
- m_errorMessage = "Unexpected EOF";
- return;
- case RETURN:
- m_errorMessage = "Return statements are only valid inside functions";
- return;
- default:
- ASSERT_NOT_REACHED();
- m_errorMessage = "internal error";
- return;
- }
+ return tokenStart() - tokenLineStart();
+ }
+
+ ALWAYS_INLINE const JSTextPosition& tokenEndPosition()
+ {
+ return m_token.m_endPosition;
}
- NEVER_INLINE void updateErrorMessage()
+ ALWAYS_INLINE unsigned tokenLineStart()
{
- m_error = true;
- const char* name = getTokenName(m_token.m_type);
- if (!name)
- updateErrorMessageSpecialCase(m_token.m_type);
- else
- m_errorMessage = UString(String::format("Unexpected token '%s'", name).impl());
+ return m_token.m_location.lineStartOffset;
}
- NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken)
+ ALWAYS_INLINE const JSTokenLocation& tokenLocation()
{
- m_error = true;
- const char* name = getTokenName(expectedToken);
- if (name)
- m_errorMessage = UString(String::format("Expected token '%s'", name).impl());
- else {
- if (!getTokenName(m_token.m_type))
- updateErrorMessageSpecialCase(m_token.m_type);
- else
- updateErrorMessageSpecialCase(expectedToken);
- }
+ return m_token.m_location;
}
+
+ void setErrorMessage(String msg)
+ {
+ m_errorMessage = msg;
+ }
+
+ NEVER_INLINE void logError(bool);
+ template <typename A> NEVER_INLINE void logError(bool, const A&);
+ template <typename A, typename B> NEVER_INLINE void logError(bool, const A&, const B&);
+ template <typename A, typename B, typename C> NEVER_INLINE void logError(bool, const A&, const B&, const C&);
+ template <typename A, typename B, typename C, typename D> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&);
+ template <typename A, typename B, typename C, typename D, typename E> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&);
+ template <typename A, typename B, typename C, typename D, typename E, typename F> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&);
+ template <typename A, typename B, typename C, typename D, typename E, typename F, typename G> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&, const G&);
- NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg)
+ NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, String name, const char* afterMsg)
{
- m_error = true;
- String prefix(beforeMsg);
- String postfix(afterMsg);
- prefix += " '";
- prefix += name.impl();
- prefix += "' ";
- prefix += postfix;
- m_errorMessage = prefix.impl();
+ m_errorMessage = makeString(beforeMsg, " '", name, "' ", afterMsg);
}
- NEVER_INLINE void updateErrorMessage(const char* msg)
- {
- m_error = true;
- m_errorMessage = UString(msg);
+ NEVER_INLINE void updateErrorMessage(const char* msg)
+ {
+ ASSERT(msg);
+ m_errorMessage = String(msg);
+ ASSERT(!m_errorMessage.isNull());
}
void startLoop() { currentScope()->startLoop(); }
bool strictMode() { return currentScope()->strictMode(); }
bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
bool breakIsValid()
{
ScopeRef current = currentScope();
return result;
}
- template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
- template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&);
template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
- template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
- template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
- template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+ enum SpreadMode { AllowSpread, DontAllowSpread };
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode);
+ template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
- template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
- template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
- template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
+ template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+
+ template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, DeconstructionKind, const Identifier&, int depth);
+ template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, DeconstructionKind, int depth = 0);
+ template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn);
ALWAYS_INLINE int isBinaryOperator(JSTokenType);
bool allowAutomaticSemicolon();
bool canRecurse()
{
- return m_stack.recursionCheck();
+ return m_vm->isSafeToRecurse();
}
- int lastTokenEnd() const
+ const JSTextPosition& lastTokenEndPosition() const
{
- return m_lastTokenEnd;
+ return m_lastTokenEndPosition;
}
- mutable const JSGlobalData* m_globalData;
+ bool hasError() const
+ {
+ return !m_errorMessage.isNull();
+ }
+
+ struct SavePoint {
+ int startOffset;
+ unsigned oldLineStartOffset;
+ unsigned oldLastLineNumber;
+ unsigned oldLineNumber;
+ };
+
+ ALWAYS_INLINE SavePoint createSavePoint()
+ {
+ ASSERT(!hasError());
+ SavePoint result;
+ result.startOffset = m_token.m_location.startOffset;
+ result.oldLineStartOffset = m_token.m_location.lineStartOffset;
+ result.oldLastLineNumber = m_lexer->lastLineNumber();
+ result.oldLineNumber = m_lexer->lineNumber();
+ return result;
+ }
+
+ ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint)
+ {
+ m_errorMessage = String();
+ m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset);
+ next();
+ m_lexer->setLastLineNumber(savePoint.oldLastLineNumber);
+ m_lexer->setLineNumber(savePoint.oldLineNumber);
+ }
+
+ struct ParserState {
+ int assignmentCount;
+ int nonLHSCount;
+ int nonTrivialExpressionCount;
+ };
+
+ ALWAYS_INLINE ParserState saveState()
+ {
+ ParserState result;
+ result.assignmentCount = m_assignmentCount;
+ result.nonLHSCount = m_nonLHSCount;
+ result.nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ return result;
+ }
+
+ ALWAYS_INLINE void restoreState(const ParserState& state)
+ {
+ m_assignmentCount = state.assignmentCount;
+ m_nonLHSCount = state.nonLHSCount;
+ m_nonTrivialExpressionCount = state.nonTrivialExpressionCount;
+
+ }
+
+
+ VM* m_vm;
const SourceCode* m_source;
ParserArena* m_arena;
OwnPtr<LexerType> m_lexer;
- StackBounds m_stack;
- bool m_error;
- UString m_errorMessage;
+ bool m_hasStackOverflow;
+ String m_errorMessage;
JSToken m_token;
bool m_allowsIn;
- int m_lastLine;
- int m_lastTokenEnd;
+ JSTextPosition m_lastTokenEndPosition;
int m_assignmentCount;
int m_nonLHSCount;
bool m_syntaxAlreadyValidated;
int m_statementDepth;
int m_nonTrivialExpressionCount;
const Identifier* m_lastIdentifier;
- SourceProviderCache* m_functionCache;
+ const Identifier* m_lastFunctionName;
+ RefPtr<SourceProviderCache> m_functionCache;
SourceElements* m_sourceElements;
+ bool m_parsingBuiltin;
ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
IdentifierSet m_capturedVariables;
+ Vector<RefPtr<StringImpl>> m_closedVariables;
CodeFeatures m_features;
int m_numConstants;
};
};
+
template <typename LexerType>
template <class ParsedNode>
-PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)
+PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error, bool needReparsingAdjustment)
{
- ASSERT(lexicalGlobalObject);
- ASSERT(exception && !*exception);
int errLine;
- UString errMsg;
+ String errMsg;
- if (ParsedNode::scopeIsFunction)
+ if (ParsedNode::scopeIsFunction && needReparsingAdjustment)
m_lexer->setIsReparsing();
m_sourceElements = 0;
errLine = -1;
- errMsg = UString();
+ errMsg = String();
+
+ JSTokenLocation startLocation(tokenLocation());
+ ASSERT(m_source->startColumn() > 0);
+ unsigned startColumn = m_source->startColumn() - 1;
- UString parseError = parseInner();
+ String parseError = parseInner();
int lineNumber = m_lexer->lineNumber();
bool lexError = m_lexer->sawError();
- UString lexErrorMessage = lexError ? m_lexer->getErrorMessage() : UString();
+ String lexErrorMessage = lexError ? m_lexer->getErrorMessage() : String();
ASSERT(lexErrorMessage.isNull() != lexError);
m_lexer->clear();
RefPtr<ParsedNode> result;
if (m_sourceElements) {
- result = ParsedNode::create(&lexicalGlobalObject->globalData(),
- m_lexer->lastLineNumber(),
+ JSTokenLocation endLocation;
+ endLocation.line = m_lexer->lineNumber();
+ endLocation.lineStartOffset = m_lexer->currentLineStartOffset();
+ endLocation.startOffset = m_lexer->currentOffset();
+ unsigned endColumn = endLocation.startOffset - endLocation.lineStartOffset;
+ result = ParsedNode::create(m_vm,
+ startLocation,
+ endLocation,
+ startColumn,
+ endColumn,
m_sourceElements,
m_varDeclarations ? &m_varDeclarations->data : 0,
m_funcDeclarations ? &m_funcDeclarations->data : 0,
*m_source,
m_features,
m_numConstants);
- result->setLoc(m_source->firstLine(), m_lastLine);
- } else if (lexicalGlobalObject) {
+ result->setLoc(m_source->firstLine(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset());
+ } else {
// We can never see a syntax error when reparsing a function, since we should have
// reported the error when parsing the containing program or eval code. So if we're
// parsing a function body node, we assume that what actually happened here is that
// we ran out of stack while parsing. If we see an error while parsing eval or program
// code we assume that it was a syntax error since running out of stack is much less
// likely, and we are currently unable to distinguish between the two cases.
- if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
- *exception = createStackOverflowError(lexicalGlobalObject);
- else if (isEvalNode<ParsedNode>())
- *exception = createSyntaxError(lexicalGlobalObject, errMsg);
- else
- *exception = addErrorInfo(lexicalGlobalObject->globalExec(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, *m_source);
+ if (isFunctionBodyNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow)
+ error = ParserError(ParserError::StackOverflow, ParserError::SyntaxErrorNone, m_token);
+ else {
+ ParserError::SyntaxErrorType errorType = ParserError::SyntaxErrorIrrecoverable;
+ if (m_token.m_type == EOFTOK)
+ errorType = ParserError::SyntaxErrorRecoverable;
+ else if (m_token.m_type & UnterminatedErrorTokenFlag)
+ errorType = ParserError::SyntaxErrorUnterminatedLiteral;
+
+ if (isEvalNode<ParsedNode>())
+ error = ParserError(ParserError::EvalError, errorType, m_token, errMsg, errLine);
+ else
+ error = ParserError(ParserError::SyntaxError, errorType, m_token, errMsg, errLine);
+ }
}
- if (debugger && !ParsedNode::scopeIsFunction)
- debugger->sourceParsed(debuggerExecState, m_source->provider(), errLine, errMsg);
-
m_arena->reset();
return result.release();
}
template <class ParsedNode>
-PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
+PassRefPtr<ParsedNode> parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ParserError& error, JSTextPosition* positionBeforeLastNewline = 0, bool needReparsingAdjustment = false)
{
SamplingRegion samplingRegion("Parsing");
- ASSERT(source.provider()->data());
-
- if (source.provider()->data()->is8Bit()) {
- Parser< Lexer<LChar> > parser(globalData, source, parameters, strictness, parserMode);
- return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+ ASSERT(!source.provider()->source().isNull());
+ if (source.provider()->source().is8Bit()) {
+ Parser<Lexer<LChar>> parser(vm, source, parameters, name, strictness, parserMode);
+ RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error, needReparsingAdjustment);
+ if (positionBeforeLastNewline)
+ *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+ if (strictness == JSParseBuiltin) {
+ if (!result)
+ WTF::dataLog("Error compiling builtin: ", error.m_message, "\n");
+ RELEASE_ASSERT(result);
+ result->setClosedVariables(parser.closedVariables());
+ }
+ return result.release();
}
- Parser< Lexer<UChar> > parser(globalData, source, parameters, strictness, parserMode);
- return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+ Parser<Lexer<UChar>> parser(vm, source, parameters, name, strictness, parserMode);
+ RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error, needReparsingAdjustment);
+ if (positionBeforeLastNewline)
+ *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+ return result.release();
}
-} // namespace
+} // namespace
#endif