]>
Commit | Line | Data |
---|---|---|
b37bf2e1 | 1 | /* |
b37bf2e1 A |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
93a37866 | 4 | * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. |
b37bf2e1 A |
5 | * |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Library General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public License | |
17 | * along with this library; see the file COPYING.LIB. If not, write to | |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 | * Boston, MA 02110-1301, USA. | |
20 | * | |
21 | */ | |
22 | ||
23 | #ifndef Parser_h | |
24 | #define Parser_h | |
25 | ||
9dae56ea | 26 | #include "Debugger.h" |
14957cd0 | 27 | #include "ExceptionHelpers.h" |
f9bf01c6 A |
28 | #include "Executable.h" |
29 | #include "JSGlobalObject.h" | |
30 | #include "Lexer.h" | |
9dae56ea | 31 | #include "Nodes.h" |
f9bf01c6 | 32 | #include "ParserArena.h" |
93a37866 | 33 | #include "ParserError.h" |
ed1e77d3 | 34 | #include "ParserFunctionInfo.h" |
6fe7ccc8 | 35 | #include "ParserTokens.h" |
ba379fdc | 36 | #include "SourceProvider.h" |
93a37866 | 37 | #include "SourceProviderCache.h" |
6fe7ccc8 | 38 | #include "SourceProviderCacheItem.h" |
b37bf2e1 A |
39 | #include <wtf/Forward.h> |
40 | #include <wtf/Noncopyable.h> | |
b37bf2e1 | 41 | #include <wtf/RefPtr.h> |
6fe7ccc8 A |
42 | namespace JSC { |
43 | struct Scope; | |
44 | } | |
45 | ||
46 | namespace WTF { | |
47 | template <> struct VectorTraits<JSC::Scope> : SimpleClassVectorTraits { | |
48 | static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0. | |
49 | }; | |
50 | } | |
b37bf2e1 | 51 | |
9dae56ea | 52 | namespace JSC { |
b37bf2e1 | 53 | |
6fe7ccc8 A |
54 | class ExecState; |
55 | class FunctionBodyNode; | |
56 | class FunctionParameters; | |
57 | class Identifier; | |
93a37866 | 58 | class VM; |
6fe7ccc8 A |
59 | class ProgramNode; |
60 | class SourceCode; | |
93a37866 A |
61 | |
62 | // Macros to make the more common TreeBuilder types a little less verbose | |
6fe7ccc8 A |
63 | #define TreeStatement typename TreeBuilder::Statement |
64 | #define TreeExpression typename TreeBuilder::Expression | |
65 | #define TreeFormalParameterList typename TreeBuilder::FormalParameterList | |
66 | #define TreeSourceElements typename TreeBuilder::SourceElements | |
67 | #define TreeClause typename TreeBuilder::Clause | |
68 | #define TreeClauseList typename TreeBuilder::ClauseList | |
69 | #define TreeConstDeclList typename TreeBuilder::ConstDeclList | |
70 | #define TreeArguments typename TreeBuilder::Arguments | |
71 | #define TreeArgumentsList typename TreeBuilder::ArgumentsList | |
72 | #define TreeFunctionBody typename TreeBuilder::FunctionBody | |
ed1e77d3 A |
73 | #if ENABLE(ES6_CLASS_SYNTAX) |
74 | #define TreeClassExpression typename TreeBuilder::ClassExpression | |
75 | #endif | |
6fe7ccc8 A |
76 | #define TreeProperty typename TreeBuilder::Property |
77 | #define TreePropertyList typename TreeBuilder::PropertyList | |
ed1e77d3 | 78 | #define TreeDestructuringPattern typename TreeBuilder::DestructuringPattern |
6fe7ccc8 A |
79 | |
80 | COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens); | |
81 | ||
82 | enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode }; | |
ed1e77d3 A |
83 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
84 | enum FunctionParseType { StandardFunctionParseType, ArrowFunctionParseType }; | |
85 | #else | |
86 | enum FunctionParseType { StandardFunctionParseType}; | |
87 | #endif | |
6fe7ccc8 | 88 | enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; |
ed1e77d3 A |
89 | enum FunctionParseMode { |
90 | FunctionMode, | |
91 | GetterMode, | |
92 | SetterMode, | |
93 | MethodMode, | |
94 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
95 | ArrowFunctionMode | |
96 | #endif | |
97 | }; | |
98 | enum DestructuringKind { | |
99 | DestructureToVariables, | |
100 | DestructureToParameters, | |
101 | DestructureToExpressions | |
81345200 | 102 | }; |
6fe7ccc8 A |
103 | |
104 | template <typename T> inline bool isEvalNode() { return false; } | |
105 | template <> inline bool isEvalNode<EvalNode>() { return true; } | |
106 | ||
6fe7ccc8 | 107 | struct ScopeLabelInfo { |
ed1e77d3 A |
108 | UniquedStringImpl* uid; |
109 | bool isLoop; | |
6fe7ccc8 A |
110 | }; |
111 | ||
112 | struct Scope { | |
93a37866 A |
113 | Scope(const VM* vm, bool isFunction, bool strictMode) |
114 | : m_vm(vm) | |
6fe7ccc8 A |
115 | , m_shadowsArguments(false) |
116 | , m_usesEval(false) | |
117 | , m_needsFullActivation(false) | |
ed1e77d3 A |
118 | , m_hasDirectSuper(false) |
119 | , m_needsSuperBinding(false) | |
6fe7ccc8 A |
120 | , m_allowsNewDecls(true) |
121 | , m_strictMode(strictMode) | |
122 | , m_isFunction(isFunction) | |
123 | , m_isFunctionBoundary(false) | |
124 | , m_isValidStrictMode(true) | |
125 | , m_loopDepth(0) | |
126 | , m_switchDepth(0) | |
127 | { | |
128 | } | |
129 | ||
130 | Scope(const Scope& rhs) | |
93a37866 | 131 | : m_vm(rhs.m_vm) |
6fe7ccc8 A |
132 | , m_shadowsArguments(rhs.m_shadowsArguments) |
133 | , m_usesEval(rhs.m_usesEval) | |
134 | , m_needsFullActivation(rhs.m_needsFullActivation) | |
ed1e77d3 A |
135 | , m_hasDirectSuper(rhs.m_hasDirectSuper) |
136 | , m_needsSuperBinding(rhs.m_needsSuperBinding) | |
6fe7ccc8 A |
137 | , m_allowsNewDecls(rhs.m_allowsNewDecls) |
138 | , m_strictMode(rhs.m_strictMode) | |
139 | , m_isFunction(rhs.m_isFunction) | |
140 | , m_isFunctionBoundary(rhs.m_isFunctionBoundary) | |
141 | , m_isValidStrictMode(rhs.m_isValidStrictMode) | |
142 | , m_loopDepth(rhs.m_loopDepth) | |
143 | , m_switchDepth(rhs.m_switchDepth) | |
144 | { | |
145 | if (rhs.m_labels) { | |
ed1e77d3 | 146 | m_labels = std::make_unique<LabelStack>(); |
6fe7ccc8 A |
147 | |
148 | typedef LabelStack::const_iterator iterator; | |
149 | iterator end = rhs.m_labels->end(); | |
150 | for (iterator it = rhs.m_labels->begin(); it != end; ++it) | |
ed1e77d3 | 151 | m_labels->append(ScopeLabelInfo { it->uid, it->isLoop }); |
6fe7ccc8 A |
152 | } |
153 | } | |
154 | ||
155 | void startSwitch() { m_switchDepth++; } | |
156 | void endSwitch() { m_switchDepth--; } | |
157 | void startLoop() { m_loopDepth++; } | |
158 | void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; } | |
159 | bool inLoop() { return !!m_loopDepth; } | |
160 | bool breakIsValid() { return m_loopDepth || m_switchDepth; } | |
161 | bool continueIsValid() { return m_loopDepth; } | |
162 | ||
163 | void pushLabel(const Identifier* label, bool isLoop) | |
164 | { | |
165 | if (!m_labels) | |
ed1e77d3 A |
166 | m_labels = std::make_unique<LabelStack>(); |
167 | m_labels->append(ScopeLabelInfo { label->impl(), isLoop }); | |
6fe7ccc8 A |
168 | } |
169 | ||
170 | void popLabel() | |
171 | { | |
172 | ASSERT(m_labels); | |
173 | ASSERT(m_labels->size()); | |
174 | m_labels->removeLast(); | |
175 | } | |
176 | ||
177 | ScopeLabelInfo* getLabel(const Identifier* label) | |
178 | { | |
179 | if (!m_labels) | |
180 | return 0; | |
181 | for (int i = m_labels->size(); i > 0; i--) { | |
ed1e77d3 | 182 | if (m_labels->at(i - 1).uid == label->impl()) |
6fe7ccc8 A |
183 | return &m_labels->at(i - 1); |
184 | } | |
185 | return 0; | |
186 | } | |
187 | ||
188 | void setIsFunction() | |
189 | { | |
190 | m_isFunction = true; | |
191 | m_isFunctionBoundary = true; | |
192 | } | |
193 | bool isFunction() { return m_isFunction; } | |
194 | bool isFunctionBoundary() { return m_isFunctionBoundary; } | |
195 | ||
93a37866 A |
196 | void declareCallee(const Identifier* ident) |
197 | { | |
ed1e77d3 | 198 | m_declaredVariables.add(ident->impl()); |
93a37866 A |
199 | } |
200 | ||
6fe7ccc8 A |
201 | bool declareVariable(const Identifier* ident) |
202 | { | |
93a37866 | 203 | bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident; |
6fe7ccc8 | 204 | m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; |
ed1e77d3 | 205 | m_declaredVariables.add(ident->impl()); |
6fe7ccc8 A |
206 | return isValidStrictMode; |
207 | } | |
208 | ||
81345200 A |
209 | bool hasDeclaredVariable(const Identifier& ident) |
210 | { | |
211 | return m_declaredVariables.contains(ident.impl()); | |
212 | } | |
213 | ||
214 | bool hasDeclaredParameter(const Identifier& ident) | |
215 | { | |
216 | return m_declaredParameters.contains(ident.impl()) || m_declaredVariables.contains(ident.impl()); | |
217 | } | |
218 | ||
6fe7ccc8 A |
219 | void declareWrite(const Identifier* ident) |
220 | { | |
221 | ASSERT(m_strictMode); | |
222 | m_writtenVariables.add(ident->impl()); | |
223 | } | |
224 | ||
225 | void preventNewDecls() { m_allowsNewDecls = false; } | |
226 | bool allowsNewDecls() const { return m_allowsNewDecls; } | |
227 | ||
228 | bool declareParameter(const Identifier* ident) | |
229 | { | |
93a37866 | 230 | bool isArguments = m_vm->propertyNames->arguments == *ident; |
ed1e77d3 | 231 | bool isValidStrictMode = m_declaredVariables.add(ident->impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments; |
6fe7ccc8 | 232 | m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; |
ed1e77d3 | 233 | m_declaredParameters.add(ident->impl()); |
81345200 | 234 | |
6fe7ccc8 A |
235 | if (isArguments) |
236 | m_shadowsArguments = true; | |
237 | return isValidStrictMode; | |
238 | } | |
81345200 A |
239 | |
240 | enum BindingResult { | |
241 | BindingFailed, | |
242 | StrictBindingFailed, | |
243 | BindingSucceeded | |
244 | }; | |
245 | BindingResult declareBoundParameter(const Identifier* ident) | |
246 | { | |
247 | bool isArguments = m_vm->propertyNames->arguments == *ident; | |
ed1e77d3 | 248 | bool newEntry = m_declaredVariables.add(ident->impl()).isNewEntry; |
81345200 A |
249 | bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments; |
250 | m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; | |
251 | ||
252 | if (isArguments) | |
253 | m_shadowsArguments = true; | |
254 | if (!newEntry) | |
255 | return BindingFailed; | |
256 | return isValidStrictMode ? BindingSucceeded : StrictBindingFailed; | |
257 | } | |
258 | ||
259 | void getUsedVariables(IdentifierSet& usedVariables) | |
260 | { | |
261 | usedVariables.swap(m_usedVariables); | |
262 | } | |
6fe7ccc8 A |
263 | |
264 | void useVariable(const Identifier* ident, bool isEval) | |
265 | { | |
266 | m_usesEval |= isEval; | |
ed1e77d3 | 267 | m_usedVariables.add(ident->impl()); |
6fe7ccc8 | 268 | } |
b37bf2e1 | 269 | |
6fe7ccc8 | 270 | void setNeedsFullActivation() { m_needsFullActivation = true; } |
b37bf2e1 | 271 | |
ed1e77d3 A |
272 | #if ENABLE(ES6_CLASS_SYNTAX) |
273 | bool hasDirectSuper() { return m_hasDirectSuper; } | |
274 | #else | |
275 | bool hasDirectSuper() { return false; } | |
276 | #endif | |
277 | void setHasDirectSuper() { m_hasDirectSuper = true; } | |
278 | ||
279 | #if ENABLE(ES6_CLASS_SYNTAX) | |
280 | bool needsSuperBinding() { return m_needsSuperBinding; } | |
281 | #else | |
282 | bool needsSuperBinding() { return false; } | |
283 | #endif | |
284 | void setNeedsSuperBinding() { m_needsSuperBinding = true; } | |
285 | ||
6fe7ccc8 A |
286 | bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) |
287 | { | |
288 | if (nestedScope->m_usesEval) | |
289 | m_usesEval = true; | |
290 | IdentifierSet::iterator end = nestedScope->m_usedVariables.end(); | |
291 | for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) { | |
292 | if (nestedScope->m_declaredVariables.contains(*ptr)) | |
293 | continue; | |
294 | m_usedVariables.add(*ptr); | |
295 | if (shouldTrackClosedVariables) | |
296 | m_closedVariables.add(*ptr); | |
297 | } | |
298 | if (nestedScope->m_writtenVariables.size()) { | |
299 | IdentifierSet::iterator end = nestedScope->m_writtenVariables.end(); | |
300 | for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) { | |
301 | if (nestedScope->m_declaredVariables.contains(*ptr)) | |
302 | continue; | |
303 | m_writtenVariables.add(*ptr); | |
304 | } | |
305 | } | |
306 | ||
307 | return true; | |
308 | } | |
309 | ||
ed1e77d3 | 310 | void getCapturedVariables(IdentifierSet& capturedVariables, bool& modifiedParameter, bool& modifiedArguments) |
6fe7ccc8 A |
311 | { |
312 | if (m_needsFullActivation || m_usesEval) { | |
81345200 | 313 | modifiedParameter = true; |
ed1e77d3 | 314 | capturedVariables = m_declaredVariables; |
6fe7ccc8 A |
315 | return; |
316 | } | |
317 | for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) { | |
318 | if (!m_declaredVariables.contains(*ptr)) | |
319 | continue; | |
320 | capturedVariables.add(*ptr); | |
321 | } | |
81345200 | 322 | modifiedParameter = false; |
ed1e77d3 A |
323 | if (shadowsArguments()) |
324 | modifiedArguments = true; | |
81345200 A |
325 | if (m_declaredParameters.size()) { |
326 | IdentifierSet::iterator end = m_writtenVariables.end(); | |
327 | for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) { | |
ed1e77d3 A |
328 | if (*ptr == m_vm->propertyNames->arguments.impl()) |
329 | modifiedArguments = true; | |
81345200 A |
330 | if (!m_declaredParameters.contains(*ptr)) |
331 | continue; | |
332 | modifiedParameter = true; | |
333 | break; | |
334 | } | |
335 | } | |
6fe7ccc8 A |
336 | } |
337 | void setStrictMode() { m_strictMode = true; } | |
338 | bool strictMode() const { return m_strictMode; } | |
339 | bool isValidStrictMode() const { return m_isValidStrictMode; } | |
340 | bool shadowsArguments() const { return m_shadowsArguments; } | |
341 | ||
ed1e77d3 | 342 | void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<UniquedStringImpl>>& vector) |
6fe7ccc8 A |
343 | { |
344 | IdentifierSet::iterator end = capturedVariables.end(); | |
345 | for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) { | |
346 | if (m_declaredVariables.contains(*it)) | |
347 | continue; | |
348 | vector.append(*it); | |
349 | } | |
6fe7ccc8 A |
350 | } |
351 | ||
93a37866 | 352 | void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters) |
6fe7ccc8 A |
353 | { |
354 | ASSERT(m_isFunction); | |
93a37866 A |
355 | parameters.usesEval = m_usesEval; |
356 | parameters.strictMode = m_strictMode; | |
357 | parameters.needsFullActivation = m_needsFullActivation; | |
358 | copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables); | |
359 | copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables); | |
6fe7ccc8 A |
360 | } |
361 | ||
93a37866 | 362 | void restoreFromSourceProviderCache(const SourceProviderCacheItem* info) |
6fe7ccc8 A |
363 | { |
364 | ASSERT(m_isFunction); | |
365 | m_usesEval = info->usesEval; | |
366 | m_strictMode = info->strictMode; | |
367 | m_needsFullActivation = info->needsFullActivation; | |
93a37866 A |
368 | for (unsigned i = 0; i < info->usedVariablesCount; ++i) |
369 | m_usedVariables.add(info->usedVariables()[i]); | |
370 | for (unsigned i = 0; i < info->writtenVariablesCount; ++i) | |
371 | m_writtenVariables.add(info->writtenVariables()[i]); | |
6fe7ccc8 A |
372 | } |
373 | ||
374 | private: | |
93a37866 | 375 | const VM* m_vm; |
6fe7ccc8 A |
376 | bool m_shadowsArguments : 1; |
377 | bool m_usesEval : 1; | |
378 | bool m_needsFullActivation : 1; | |
ed1e77d3 A |
379 | bool m_hasDirectSuper : 1; |
380 | bool m_needsSuperBinding : 1; | |
6fe7ccc8 A |
381 | bool m_allowsNewDecls : 1; |
382 | bool m_strictMode : 1; | |
383 | bool m_isFunction : 1; | |
384 | bool m_isFunctionBoundary : 1; | |
385 | bool m_isValidStrictMode : 1; | |
386 | int m_loopDepth; | |
387 | int m_switchDepth; | |
388 | ||
389 | typedef Vector<ScopeLabelInfo, 2> LabelStack; | |
ed1e77d3 | 390 | std::unique_ptr<LabelStack> m_labels; |
81345200 | 391 | IdentifierSet m_declaredParameters; |
6fe7ccc8 A |
392 | IdentifierSet m_declaredVariables; |
393 | IdentifierSet m_usedVariables; | |
394 | IdentifierSet m_closedVariables; | |
395 | IdentifierSet m_writtenVariables; | |
396 | }; | |
397 | ||
398 | typedef Vector<Scope, 10> ScopeStack; | |
b37bf2e1 | 399 | |
6fe7ccc8 A |
400 | struct ScopeRef { |
401 | ScopeRef(ScopeStack* scopeStack, unsigned index) | |
402 | : m_scopeStack(scopeStack) | |
403 | , m_index(index) | |
404 | { | |
405 | } | |
406 | Scope* operator->() { return &m_scopeStack->at(m_index); } | |
407 | unsigned index() const { return m_index; } | |
408 | ||
409 | bool hasContainingScope() | |
410 | { | |
411 | return m_index && !m_scopeStack->at(m_index).isFunctionBoundary(); | |
412 | } | |
413 | ||
414 | ScopeRef containingScope() | |
415 | { | |
416 | ASSERT(hasContainingScope()); | |
417 | return ScopeRef(m_scopeStack, m_index - 1); | |
418 | } | |
419 | ||
420 | private: | |
421 | ScopeStack* m_scopeStack; | |
422 | unsigned m_index; | |
423 | }; | |
ba379fdc | 424 | |
6fe7ccc8 A |
425 | template <typename LexerType> |
426 | class Parser { | |
427 | WTF_MAKE_NONCOPYABLE(Parser); | |
428 | WTF_MAKE_FAST_ALLOCATED; | |
b5422865 | 429 | |
6fe7ccc8 | 430 | public: |
ed1e77d3 A |
431 | Parser( |
432 | VM*, const SourceCode&, FunctionParameters*, const Identifier&, | |
433 | JSParserBuiltinMode, JSParserStrictMode, JSParserCodeType, | |
434 | ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded); | |
6fe7ccc8 A |
435 | ~Parser(); |
436 | ||
437 | template <class ParsedNode> | |
ed1e77d3 | 438 | std::unique_ptr<ParsedNode> parse(ParserError&); |
81345200 A |
439 | |
440 | JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); } | |
ed1e77d3 A |
441 | JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); } |
442 | Vector<RefPtr<UniquedStringImpl>>&& closedVariables() { return WTF::move(m_closedVariables); } | |
6fe7ccc8 A |
443 | |
444 | private: | |
445 | struct AllowInOverride { | |
446 | AllowInOverride(Parser* parser) | |
447 | : m_parser(parser) | |
448 | , m_oldAllowsIn(parser->m_allowsIn) | |
449 | { | |
450 | parser->m_allowsIn = true; | |
451 | } | |
452 | ~AllowInOverride() | |
453 | { | |
454 | m_parser->m_allowsIn = m_oldAllowsIn; | |
455 | } | |
456 | Parser* m_parser; | |
457 | bool m_oldAllowsIn; | |
458 | }; | |
459 | ||
460 | struct AutoPopScopeRef : public ScopeRef { | |
461 | AutoPopScopeRef(Parser* parser, ScopeRef scope) | |
462 | : ScopeRef(scope) | |
463 | , m_parser(parser) | |
464 | { | |
465 | } | |
466 | ||
467 | ~AutoPopScopeRef() | |
468 | { | |
469 | if (m_parser) | |
470 | m_parser->popScope(*this, false); | |
471 | } | |
472 | ||
473 | void setPopped() | |
474 | { | |
475 | m_parser = 0; | |
476 | } | |
477 | ||
b37bf2e1 | 478 | private: |
6fe7ccc8 | 479 | Parser* m_parser; |
b37bf2e1 | 480 | }; |
b37bf2e1 | 481 | |
6fe7ccc8 A |
482 | ScopeRef currentScope() |
483 | { | |
484 | return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1); | |
485 | } | |
486 | ||
487 | ScopeRef pushScope() | |
488 | { | |
489 | bool isFunction = false; | |
490 | bool isStrict = false; | |
491 | if (!m_scopeStack.isEmpty()) { | |
492 | isStrict = m_scopeStack.last().strictMode(); | |
493 | isFunction = m_scopeStack.last().isFunction(); | |
494 | } | |
93a37866 | 495 | m_scopeStack.append(Scope(m_vm, isFunction, isStrict)); |
6fe7ccc8 A |
496 | return currentScope(); |
497 | } | |
498 | ||
499 | bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables) | |
500 | { | |
501 | ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1); | |
502 | ASSERT(m_scopeStack.size() > 1); | |
503 | bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); | |
504 | m_scopeStack.removeLast(); | |
505 | return result; | |
506 | } | |
507 | ||
508 | bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables) | |
509 | { | |
510 | return popScopeInternal(scope, shouldTrackClosedVariables); | |
511 | } | |
512 | ||
513 | bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables) | |
514 | { | |
515 | scope.setPopped(); | |
516 | return popScopeInternal(scope, shouldTrackClosedVariables); | |
517 | } | |
518 | ||
519 | bool declareVariable(const Identifier* ident) | |
520 | { | |
521 | unsigned i = m_scopeStack.size() - 1; | |
522 | ASSERT(i < m_scopeStack.size()); | |
523 | while (!m_scopeStack[i].allowsNewDecls()) { | |
524 | i--; | |
525 | ASSERT(i < m_scopeStack.size()); | |
526 | } | |
527 | return m_scopeStack[i].declareVariable(ident); | |
528 | } | |
529 | ||
81345200 A |
530 | NEVER_INLINE bool hasDeclaredVariable(const Identifier& ident) |
531 | { | |
532 | unsigned i = m_scopeStack.size() - 1; | |
533 | ASSERT(i < m_scopeStack.size()); | |
534 | while (!m_scopeStack[i].allowsNewDecls()) { | |
535 | i--; | |
536 | ASSERT(i < m_scopeStack.size()); | |
537 | } | |
538 | return m_scopeStack[i].hasDeclaredVariable(ident); | |
539 | } | |
540 | ||
541 | NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident) | |
542 | { | |
543 | unsigned i = m_scopeStack.size() - 1; | |
544 | ASSERT(i < m_scopeStack.size()); | |
545 | while (!m_scopeStack[i].allowsNewDecls()) { | |
546 | i--; | |
547 | ASSERT(i < m_scopeStack.size()); | |
548 | } | |
549 | return m_scopeStack[i].hasDeclaredParameter(ident); | |
550 | } | |
551 | ||
6fe7ccc8 A |
552 | void declareWrite(const Identifier* ident) |
553 | { | |
81345200 | 554 | if (!m_syntaxAlreadyValidated || strictMode()) |
6fe7ccc8 A |
555 | m_scopeStack.last().declareWrite(ident); |
556 | } | |
557 | ||
558 | ScopeStack m_scopeStack; | |
559 | ||
560 | const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos) | |
561 | { | |
562 | return m_functionCache ? m_functionCache->get(openBracePos) : 0; | |
563 | } | |
564 | ||
565 | Parser(); | |
93a37866 | 566 | String parseInner(); |
6fe7ccc8 | 567 | |
ed1e77d3 A |
568 | void didFinishParsing(SourceElements*, DeclarationStacks::VarStack&, |
569 | DeclarationStacks::FunctionStack&, CodeFeatures, int, IdentifierSet&, const Vector<RefPtr<UniquedStringImpl>>&&); | |
6fe7ccc8 A |
570 | |
571 | // Used to determine type of error to report. | |
572 | bool isFunctionBodyNode(ScopeNode*) { return false; } | |
573 | bool isFunctionBodyNode(FunctionBodyNode*) { return true; } | |
574 | ||
6fe7ccc8 A |
575 | ALWAYS_INLINE void next(unsigned lexerFlags = 0) |
576 | { | |
81345200 A |
577 | int lastLine = m_token.m_location.line; |
578 | int lastTokenEnd = m_token.m_location.endOffset; | |
579 | int lastTokenLineStart = m_token.m_location.lineStartOffset; | |
580 | m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart); | |
581 | m_lexer->setLastLineNumber(lastLine); | |
582 | m_token.m_type = m_lexer->lex(&m_token, lexerFlags, strictMode()); | |
6fe7ccc8 A |
583 | } |
584 | ||
585 | ALWAYS_INLINE void nextExpectIdentifier(unsigned lexerFlags = 0) | |
586 | { | |
81345200 A |
587 | int lastLine = m_token.m_location.line; |
588 | int lastTokenEnd = m_token.m_location.endOffset; | |
589 | int lastTokenLineStart = m_token.m_location.lineStartOffset; | |
590 | m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart); | |
591 | m_lexer->setLastLineNumber(lastLine); | |
592 | m_token.m_type = m_lexer->lexExpectIdentifier(&m_token, lexerFlags, strictMode()); | |
6fe7ccc8 A |
593 | } |
594 | ||
595 | ALWAYS_INLINE bool nextTokenIsColon() | |
596 | { | |
597 | return m_lexer->nextTokenIsColon(); | |
598 | } | |
599 | ||
600 | ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0) | |
601 | { | |
602 | bool result = m_token.m_type == expected; | |
603 | if (result) | |
604 | next(flags); | |
605 | return result; | |
606 | } | |
81345200 A |
607 | |
608 | void printUnexpectedTokenText(WTF::PrintStream&); | |
93a37866 | 609 | ALWAYS_INLINE String getToken() { |
6fe7ccc8 | 610 | SourceProvider* sourceProvider = m_source->provider(); |
81345200 | 611 | return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset); |
6fe7ccc8 A |
612 | } |
613 | ||
614 | ALWAYS_INLINE bool match(JSTokenType expected) | |
615 | { | |
616 | return m_token.m_type == expected; | |
617 | } | |
618 | ||
81345200 A |
619 | ALWAYS_INLINE bool isofToken() |
620 | { | |
621 | return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of; | |
622 | } | |
623 | ||
ed1e77d3 A |
624 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
625 | ALWAYS_INLINE bool isEndOfArrowFunction() | |
626 | { | |
627 | return match(SEMICOLON) || match(COMMA) || match(CLOSEPAREN) || match(CLOSEBRACE) || match(CLOSEBRACKET) || match(EOFTOK) || m_lexer->prevTerminator(); | |
628 | } | |
629 | ||
630 | ALWAYS_INLINE bool isArrowFunctionParamters() | |
631 | { | |
632 | bool isArrowFunction = false; | |
633 | ||
634 | if (match(EOFTOK)) | |
635 | return isArrowFunction; | |
636 | ||
637 | SavePoint saveArrowFunctionPoint = createSavePoint(); | |
638 | ||
639 | if (consume(OPENPAREN)) { | |
640 | bool isArrowFunctionParamters = true; | |
641 | ||
642 | while (consume(IDENT)) { | |
643 | if (consume(COMMA)) { | |
644 | if (!match(IDENT)) { | |
645 | isArrowFunctionParamters = false; | |
646 | break; | |
647 | } | |
648 | } else | |
649 | break; | |
650 | } | |
651 | ||
652 | if (isArrowFunctionParamters) { | |
653 | if (consume(CLOSEPAREN) && match(ARROWFUNCTION)) | |
654 | isArrowFunction = true; | |
655 | } | |
656 | } else if (consume(IDENT) && match(ARROWFUNCTION)) | |
657 | isArrowFunction = true; | |
658 | ||
659 | restoreSavePoint(saveArrowFunctionPoint); | |
660 | ||
661 | return isArrowFunction; | |
662 | } | |
663 | #endif | |
664 | ||
93a37866 | 665 | ALWAYS_INLINE unsigned tokenStart() |
6fe7ccc8 | 666 | { |
93a37866 | 667 | return m_token.m_location.startOffset; |
6fe7ccc8 A |
668 | } |
669 | ||
81345200 A |
670 | ALWAYS_INLINE const JSTextPosition& tokenStartPosition() |
671 | { | |
672 | return m_token.m_startPosition; | |
673 | } | |
674 | ||
6fe7ccc8 A |
675 | ALWAYS_INLINE int tokenLine() |
676 | { | |
93a37866 A |
677 | return m_token.m_location.line; |
678 | } | |
679 | ||
680 | ALWAYS_INLINE int tokenColumn() | |
681 | { | |
682 | return tokenStart() - tokenLineStart(); | |
683 | } | |
684 | ||
81345200 | 685 | ALWAYS_INLINE const JSTextPosition& tokenEndPosition() |
93a37866 | 686 | { |
81345200 | 687 | return m_token.m_endPosition; |
6fe7ccc8 A |
688 | } |
689 | ||
93a37866 | 690 | ALWAYS_INLINE unsigned tokenLineStart() |
6fe7ccc8 | 691 | { |
93a37866 | 692 | return m_token.m_location.lineStartOffset; |
6fe7ccc8 A |
693 | } |
694 | ||
93a37866 A |
695 | ALWAYS_INLINE const JSTokenLocation& tokenLocation() |
696 | { | |
697 | return m_token.m_location; | |
698 | } | |
699 | ||
ed1e77d3 | 700 | void setErrorMessage(const String& message) |
6fe7ccc8 | 701 | { |
ed1e77d3 | 702 | m_errorMessage = message; |
6fe7ccc8 A |
703 | } |
704 | ||
81345200 A |
705 | NEVER_INLINE void logError(bool); |
706 | template <typename A> NEVER_INLINE void logError(bool, const A&); | |
707 | template <typename A, typename B> NEVER_INLINE void logError(bool, const A&, const B&); | |
708 | template <typename A, typename B, typename C> NEVER_INLINE void logError(bool, const A&, const B&, const C&); | |
709 | template <typename A, typename B, typename C, typename D> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&); | |
710 | 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&); | |
711 | 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&); | |
712 | 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&); | |
6fe7ccc8 | 713 | |
ed1e77d3 | 714 | NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMessage, const String& name, const char* afterMessage) |
6fe7ccc8 | 715 | { |
ed1e77d3 | 716 | m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage); |
6fe7ccc8 A |
717 | } |
718 | ||
93a37866 A |
719 | NEVER_INLINE void updateErrorMessage(const char* msg) |
720 | { | |
721 | ASSERT(msg); | |
722 | m_errorMessage = String(msg); | |
723 | ASSERT(!m_errorMessage.isNull()); | |
6fe7ccc8 A |
724 | } |
725 | ||
726 | void startLoop() { currentScope()->startLoop(); } | |
727 | void endLoop() { currentScope()->endLoop(); } | |
728 | void startSwitch() { currentScope()->startSwitch(); } | |
729 | void endSwitch() { currentScope()->endSwitch(); } | |
730 | void setStrictMode() { currentScope()->setStrictMode(); } | |
731 | bool strictMode() { return currentScope()->strictMode(); } | |
732 | bool isValidStrictMode() { return currentScope()->isValidStrictMode(); } | |
733 | bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } | |
81345200 | 734 | Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); } |
6fe7ccc8 A |
735 | bool breakIsValid() |
736 | { | |
737 | ScopeRef current = currentScope(); | |
738 | while (!current->breakIsValid()) { | |
739 | if (!current.hasContainingScope()) | |
740 | return false; | |
741 | current = current.containingScope(); | |
742 | } | |
743 | return true; | |
744 | } | |
745 | bool continueIsValid() | |
746 | { | |
747 | ScopeRef current = currentScope(); | |
748 | while (!current->continueIsValid()) { | |
749 | if (!current.hasContainingScope()) | |
750 | return false; | |
751 | current = current.containingScope(); | |
752 | } | |
753 | return true; | |
754 | } | |
755 | void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); } | |
756 | void popLabel() { currentScope()->popLabel(); } | |
757 | ScopeLabelInfo* getLabel(const Identifier* label) | |
758 | { | |
759 | ScopeRef current = currentScope(); | |
760 | ScopeLabelInfo* result = 0; | |
761 | while (!(result = current->getLabel(label))) { | |
762 | if (!current.hasContainingScope()) | |
763 | return 0; | |
764 | current = current.containingScope(); | |
765 | } | |
766 | return result; | |
767 | } | |
ed1e77d3 A |
768 | |
769 | template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode, FunctionParseType); | |
770 | template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength); | |
6fe7ccc8 | 771 | template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0); |
ed1e77d3 A |
772 | #if ENABLE(ES6_CLASS_SYNTAX) |
773 | template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&); | |
774 | #endif | |
6fe7ccc8 A |
775 | template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&); |
776 | template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&); | |
777 | template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&); | |
778 | template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&); | |
779 | template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&); | |
780 | template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&); | |
781 | template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&); | |
782 | template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&); | |
783 | template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&); | |
784 | template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&); | |
785 | template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&); | |
786 | template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&); | |
787 | template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&); | |
788 | template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&); | |
789 | template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&); | |
790 | template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&); | |
791 | template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&); | |
792 | template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&); | |
793 | template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&); | |
81345200 | 794 | template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&); |
6fe7ccc8 A |
795 | template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&); |
796 | template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&); | |
797 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&); | |
798 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&); | |
799 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&); | |
800 | template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&); | |
801 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&); | |
802 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&); | |
803 | template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&); | |
81345200 A |
804 | template <class TreeBuilder> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&); |
805 | enum SpreadMode { AllowSpread, DontAllowSpread }; | |
806 | template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode); | |
807 | template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict); | |
ed1e77d3 A |
808 | template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName); |
809 | template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded); | |
810 | template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionParseType); | |
6fe7ccc8 | 811 | template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&); |
ed1e77d3 A |
812 | enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext }; |
813 | template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext); | |
81345200 A |
814 | template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&); |
815 | ||
ed1e77d3 A |
816 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
817 | template <class TreeBuilder> TreeStatement parseArrowFunctionSingleExpressionBody(TreeBuilder&, FunctionParseType); | |
818 | template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&); | |
819 | #endif | |
820 | ||
821 | template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken); | |
822 | template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, int depth = 0); | |
823 | template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&); | |
824 | template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&); | |
825 | ||
826 | template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionParseType); | |
827 | ||
828 | template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, FunctionParseMode, ParserFunctionInfo<TreeBuilder>&); | |
829 | ||
830 | #if ENABLE(ES6_CLASS_SYNTAX) | |
831 | template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&); | |
832 | #endif | |
833 | ||
834 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) | |
835 | template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail); | |
836 | template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode); | |
837 | #endif | |
838 | ||
839 | template <class TreeBuilder> ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&); | |
840 | ||
6fe7ccc8 A |
841 | ALWAYS_INLINE int isBinaryOperator(JSTokenType); |
842 | bool allowAutomaticSemicolon(); | |
843 | ||
844 | bool autoSemiColon() | |
845 | { | |
846 | if (m_token.m_type == SEMICOLON) { | |
847 | next(); | |
848 | return true; | |
b37bf2e1 | 849 | } |
6fe7ccc8 A |
850 | return allowAutomaticSemicolon(); |
851 | } | |
852 | ||
ed1e77d3 A |
853 | |
854 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
855 | void setEndOfStatement() | |
856 | { | |
857 | m_lexer->setTokenPosition(&m_token); | |
858 | } | |
859 | #endif | |
860 | ||
6fe7ccc8 A |
861 | bool canRecurse() |
862 | { | |
81345200 | 863 | return m_vm->isSafeToRecurse(); |
6fe7ccc8 A |
864 | } |
865 | ||
81345200 | 866 | const JSTextPosition& lastTokenEndPosition() const |
6fe7ccc8 | 867 | { |
81345200 | 868 | return m_lastTokenEndPosition; |
6fe7ccc8 A |
869 | } |
870 | ||
81345200 | 871 | bool hasError() const |
93a37866 | 872 | { |
81345200 | 873 | return !m_errorMessage.isNull(); |
93a37866 A |
874 | } |
875 | ||
81345200 A |
876 | struct SavePoint { |
877 | int startOffset; | |
878 | unsigned oldLineStartOffset; | |
879 | unsigned oldLastLineNumber; | |
880 | unsigned oldLineNumber; | |
881 | }; | |
882 | ||
883 | ALWAYS_INLINE SavePoint createSavePoint() | |
884 | { | |
885 | ASSERT(!hasError()); | |
886 | SavePoint result; | |
887 | result.startOffset = m_token.m_location.startOffset; | |
888 | result.oldLineStartOffset = m_token.m_location.lineStartOffset; | |
889 | result.oldLastLineNumber = m_lexer->lastLineNumber(); | |
890 | result.oldLineNumber = m_lexer->lineNumber(); | |
891 | return result; | |
892 | } | |
893 | ||
894 | ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint) | |
93a37866 | 895 | { |
81345200 A |
896 | m_errorMessage = String(); |
897 | m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset); | |
898 | next(); | |
899 | m_lexer->setLastLineNumber(savePoint.oldLastLineNumber); | |
900 | m_lexer->setLineNumber(savePoint.oldLineNumber); | |
93a37866 A |
901 | } |
902 | ||
81345200 A |
903 | struct ParserState { |
904 | int assignmentCount; | |
905 | int nonLHSCount; | |
906 | int nonTrivialExpressionCount; | |
907 | }; | |
908 | ||
909 | ALWAYS_INLINE ParserState saveState() | |
93a37866 | 910 | { |
81345200 A |
911 | ParserState result; |
912 | result.assignmentCount = m_assignmentCount; | |
913 | result.nonLHSCount = m_nonLHSCount; | |
914 | result.nonTrivialExpressionCount = m_nonTrivialExpressionCount; | |
915 | return result; | |
93a37866 | 916 | } |
81345200 A |
917 | |
918 | ALWAYS_INLINE void restoreState(const ParserState& state) | |
919 | { | |
920 | m_assignmentCount = state.assignmentCount; | |
921 | m_nonLHSCount = state.nonLHSCount; | |
922 | m_nonTrivialExpressionCount = state.nonTrivialExpressionCount; | |
923 | ||
924 | } | |
925 | ||
93a37866 A |
926 | |
927 | VM* m_vm; | |
6fe7ccc8 | 928 | const SourceCode* m_source; |
ed1e77d3 A |
929 | ParserArena m_parserArena; |
930 | std::unique_ptr<LexerType> m_lexer; | |
6fe7ccc8 | 931 | |
93a37866 A |
932 | bool m_hasStackOverflow; |
933 | String m_errorMessage; | |
6fe7ccc8 A |
934 | JSToken m_token; |
935 | bool m_allowsIn; | |
81345200 | 936 | JSTextPosition m_lastTokenEndPosition; |
6fe7ccc8 A |
937 | int m_assignmentCount; |
938 | int m_nonLHSCount; | |
939 | bool m_syntaxAlreadyValidated; | |
940 | int m_statementDepth; | |
941 | int m_nonTrivialExpressionCount; | |
942 | const Identifier* m_lastIdentifier; | |
81345200 | 943 | const Identifier* m_lastFunctionName; |
93a37866 | 944 | RefPtr<SourceProviderCache> m_functionCache; |
6fe7ccc8 | 945 | SourceElements* m_sourceElements; |
81345200 | 946 | bool m_parsingBuiltin; |
ed1e77d3 A |
947 | ConstructorKind m_defaultConstructorKind; |
948 | ThisTDZMode m_thisTDZMode; | |
949 | DeclarationStacks::VarStack m_varDeclarations; | |
950 | DeclarationStacks::FunctionStack m_funcDeclarations; | |
6fe7ccc8 | 951 | IdentifierSet m_capturedVariables; |
ed1e77d3 | 952 | Vector<RefPtr<UniquedStringImpl>> m_closedVariables; |
6fe7ccc8 A |
953 | CodeFeatures m_features; |
954 | int m_numConstants; | |
955 | ||
956 | struct DepthManager { | |
957 | DepthManager(int* depth) | |
958 | : m_originalDepth(*depth) | |
959 | , m_depth(depth) | |
960 | { | |
961 | } | |
962 | ||
963 | ~DepthManager() | |
964 | { | |
965 | *m_depth = m_originalDepth; | |
966 | } | |
967 | ||
968 | private: | |
969 | int m_originalDepth; | |
970 | int* m_depth; | |
971 | }; | |
972 | }; | |
973 | ||
93a37866 | 974 | |
6fe7ccc8 A |
975 | template <typename LexerType> |
976 | template <class ParsedNode> | |
ed1e77d3 | 977 | std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error) |
6fe7ccc8 | 978 | { |
6fe7ccc8 | 979 | int errLine; |
93a37866 | 980 | String errMsg; |
6fe7ccc8 | 981 | |
ed1e77d3 | 982 | if (ParsedNode::scopeIsFunction) |
6fe7ccc8 A |
983 | m_lexer->setIsReparsing(); |
984 | ||
985 | m_sourceElements = 0; | |
b5422865 | 986 | |
6fe7ccc8 | 987 | errLine = -1; |
93a37866 A |
988 | errMsg = String(); |
989 | ||
990 | JSTokenLocation startLocation(tokenLocation()); | |
81345200 A |
991 | ASSERT(m_source->startColumn() > 0); |
992 | unsigned startColumn = m_source->startColumn() - 1; | |
ba379fdc | 993 | |
93a37866 | 994 | String parseError = parseInner(); |
6fe7ccc8 A |
995 | |
996 | int lineNumber = m_lexer->lineNumber(); | |
997 | bool lexError = m_lexer->sawError(); | |
93a37866 | 998 | String lexErrorMessage = lexError ? m_lexer->getErrorMessage() : String(); |
6fe7ccc8 A |
999 | ASSERT(lexErrorMessage.isNull() != lexError); |
1000 | m_lexer->clear(); | |
1001 | ||
1002 | if (!parseError.isNull() || lexError) { | |
1003 | errLine = lineNumber; | |
1004 | errMsg = !lexErrorMessage.isNull() ? lexErrorMessage : parseError; | |
f9bf01c6 | 1005 | m_sourceElements = 0; |
6fe7ccc8 | 1006 | } |
9dae56ea | 1007 | |
ed1e77d3 | 1008 | std::unique_ptr<ParsedNode> result; |
6fe7ccc8 | 1009 | if (m_sourceElements) { |
93a37866 | 1010 | JSTokenLocation endLocation; |
81345200 | 1011 | endLocation.line = m_lexer->lineNumber(); |
93a37866 A |
1012 | endLocation.lineStartOffset = m_lexer->currentLineStartOffset(); |
1013 | endLocation.startOffset = m_lexer->currentOffset(); | |
81345200 | 1014 | unsigned endColumn = endLocation.startOffset - endLocation.lineStartOffset; |
ed1e77d3 | 1015 | result = std::make_unique<ParsedNode>(m_parserArena, |
93a37866 A |
1016 | startLocation, |
1017 | endLocation, | |
1018 | startColumn, | |
81345200 | 1019 | endColumn, |
6fe7ccc8 | 1020 | m_sourceElements, |
ed1e77d3 A |
1021 | m_varDeclarations, |
1022 | m_funcDeclarations, | |
6fe7ccc8 A |
1023 | m_capturedVariables, |
1024 | *m_source, | |
1025 | m_features, | |
1026 | m_numConstants); | |
81345200 | 1027 | result->setLoc(m_source->firstLine(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset()); |
ed1e77d3 | 1028 | result->setEndOffset(m_lexer->currentOffset()); |
93a37866 | 1029 | } else { |
6fe7ccc8 A |
1030 | // We can never see a syntax error when reparsing a function, since we should have |
1031 | // reported the error when parsing the containing program or eval code. So if we're | |
1032 | // parsing a function body node, we assume that what actually happened here is that | |
1033 | // we ran out of stack while parsing. If we see an error while parsing eval or program | |
1034 | // code we assume that it was a syntax error since running out of stack is much less | |
1035 | // likely, and we are currently unable to distinguish between the two cases. | |
93a37866 A |
1036 | if (isFunctionBodyNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow) |
1037 | error = ParserError(ParserError::StackOverflow, ParserError::SyntaxErrorNone, m_token); | |
1038 | else { | |
1039 | ParserError::SyntaxErrorType errorType = ParserError::SyntaxErrorIrrecoverable; | |
1040 | if (m_token.m_type == EOFTOK) | |
1041 | errorType = ParserError::SyntaxErrorRecoverable; | |
1042 | else if (m_token.m_type & UnterminatedErrorTokenFlag) | |
1043 | errorType = ParserError::SyntaxErrorUnterminatedLiteral; | |
1044 | ||
1045 | if (isEvalNode<ParsedNode>()) | |
1046 | error = ParserError(ParserError::EvalError, errorType, m_token, errMsg, errLine); | |
1047 | else | |
1048 | error = ParserError(ParserError::SyntaxError, errorType, m_token, errMsg, errLine); | |
1049 | } | |
b37bf2e1 A |
1050 | } |
1051 | ||
ed1e77d3 | 1052 | return result; |
6fe7ccc8 A |
1053 | } |
1054 | ||
1055 | template <class ParsedNode> | |
ed1e77d3 A |
1056 | std::unique_ptr<ParsedNode> parse( |
1057 | VM* vm, const SourceCode& source, FunctionParameters* parameters, | |
1058 | const Identifier& name, JSParserBuiltinMode builtinMode, | |
1059 | JSParserStrictMode strictMode, JSParserCodeType codeType, | |
1060 | ParserError& error, JSTextPosition* positionBeforeLastNewline = 0, | |
1061 | ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded) | |
6fe7ccc8 A |
1062 | { |
1063 | SamplingRegion samplingRegion("Parsing"); | |
1064 | ||
93a37866 A |
1065 | ASSERT(!source.provider()->source().isNull()); |
1066 | if (source.provider()->source().is8Bit()) { | |
ed1e77d3 A |
1067 | Parser<Lexer<LChar>> parser(vm, source, parameters, name, builtinMode, strictMode, codeType, defaultConstructorKind, thisTDZMode); |
1068 | std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error); | |
81345200 A |
1069 | if (positionBeforeLastNewline) |
1070 | *positionBeforeLastNewline = parser.positionBeforeLastNewline(); | |
ed1e77d3 | 1071 | if (builtinMode == JSParserBuiltinMode::Builtin) { |
81345200 | 1072 | if (!result) |
ed1e77d3 | 1073 | WTF::dataLog("Error compiling builtin: ", error.message(), "\n"); |
81345200 A |
1074 | RELEASE_ASSERT(result); |
1075 | result->setClosedVariables(parser.closedVariables()); | |
1076 | } | |
ed1e77d3 | 1077 | return result; |
6fe7ccc8 | 1078 | } |
ed1e77d3 A |
1079 | ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string"); |
1080 | Parser<Lexer<UChar>> parser(vm, source, parameters, name, builtinMode, strictMode, codeType, defaultConstructorKind, thisTDZMode); | |
1081 | std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error); | |
81345200 A |
1082 | if (positionBeforeLastNewline) |
1083 | *positionBeforeLastNewline = parser.positionBeforeLastNewline(); | |
ed1e77d3 | 1084 | return result; |
6fe7ccc8 | 1085 | } |
b37bf2e1 | 1086 | |
93a37866 | 1087 | } // namespace |
6fe7ccc8 | 1088 | #endif |