ParseContext-inl.h (6077B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_ParseContext_inl_h 8 #define frontend_ParseContext_inl_h 9 10 #include "frontend/ParseContext.h" 11 12 #include "frontend/Parser.h" 13 14 namespace js { 15 namespace frontend { 16 17 template <> 18 inline bool ParseContext::Statement::is<ParseContext::LabelStatement>() const { 19 return kind_ == StatementKind::Label; 20 } 21 22 template <> 23 inline bool ParseContext::Statement::is<ParseContext::ClassStatement>() const { 24 return kind_ == StatementKind::Class; 25 } 26 27 template <typename T> 28 inline T& ParseContext::Statement::as() { 29 MOZ_ASSERT(is<T>()); 30 return static_cast<T&>(*this); 31 } 32 33 inline ParseContext::Scope::BindingIter ParseContext::Scope::bindings( 34 ParseContext* pc) { 35 // In function scopes with parameter expressions, function special names 36 // (like '.this') are declared as vars in the function scope, despite its 37 // not being the var scope. 38 return BindingIter(*this, pc->varScope_ == this || 39 pc->functionScope_.ptrOr(nullptr) == this); 40 } 41 42 inline ParseContext::Scope::Scope(ParserBase* parser) 43 : Nestable<Scope>(&parser->pc_->innermostScope_), 44 declared_(parser->fc_->nameCollectionPool()), 45 possibleAnnexBFunctionBoxes_(parser->fc_->nameCollectionPool()), 46 id_(parser->usedNames_.nextScopeId()) {} 47 48 inline ParseContext::Scope::Scope(FrontendContext* fc, ParseContext* pc, 49 UsedNameTracker& usedNames) 50 : Nestable<Scope>(&pc->innermostScope_), 51 declared_(fc->nameCollectionPool()), 52 possibleAnnexBFunctionBoxes_(fc->nameCollectionPool()), 53 id_(usedNames.nextScopeId()) {} 54 55 inline ParseContext::VarScope::VarScope(ParserBase* parser) : Scope(parser) { 56 useAsVarScope(parser->pc_); 57 } 58 59 inline ParseContext::VarScope::VarScope(FrontendContext* fc, ParseContext* pc, 60 UsedNameTracker& usedNames) 61 : Scope(fc, pc, usedNames) { 62 useAsVarScope(pc); 63 } 64 65 inline JS::Result<Ok, ParseContext::BreakStatementError> 66 ParseContext::checkBreakStatement(TaggedParserAtomIndex label) { 67 // Labeled 'break' statements target the nearest labeled statements (could 68 // be any kind) with the same label. Unlabeled 'break' statements target 69 // the innermost loop or switch statement. 70 if (label) { 71 auto hasSameLabel = [&label](ParseContext::LabelStatement* stmt) { 72 MOZ_ASSERT(stmt); 73 return stmt->label() == label; 74 }; 75 76 if (!findInnermostStatement<ParseContext::LabelStatement>(hasSameLabel)) { 77 return mozilla::Err(ParseContext::BreakStatementError::LabelNotFound); 78 } 79 80 } else { 81 auto isBreakTarget = [](ParseContext::Statement* stmt) { 82 return StatementKindIsUnlabeledBreakTarget(stmt->kind()); 83 }; 84 85 if (!findInnermostStatement(isBreakTarget)) { 86 return mozilla::Err(ParseContext::BreakStatementError::ToughBreak); 87 } 88 } 89 90 return Ok(); 91 } 92 93 inline JS::Result<Ok, ParseContext::ContinueStatementError> 94 ParseContext::checkContinueStatement(TaggedParserAtomIndex label) { 95 // Labeled 'continue' statements target the nearest labeled loop 96 // statements with the same label. Unlabeled 'continue' statements target 97 // the innermost loop statement. 98 auto isLoop = [](ParseContext::Statement* stmt) { 99 MOZ_ASSERT(stmt); 100 return StatementKindIsLoop(stmt->kind()); 101 }; 102 103 if (!label) { 104 // Unlabeled statement: we target the innermost loop, so make sure that 105 // there is an innermost loop. 106 if (!findInnermostStatement(isLoop)) { 107 return mozilla::Err(ParseContext::ContinueStatementError::NotInALoop); 108 } 109 return Ok(); 110 } 111 112 // Labeled statement: targest the nearest labeled loop with the same label. 113 ParseContext::Statement* stmt = innermostStatement(); 114 bool foundLoop = false; // True if we have encountered at least one loop. 115 116 for (;;) { 117 stmt = ParseContext::Statement::findNearest(stmt, isLoop); 118 if (!stmt) { 119 return foundLoop 120 ? mozilla::Err( 121 ParseContext::ContinueStatementError::LabelNotFound) 122 : mozilla::Err( 123 ParseContext::ContinueStatementError::NotInALoop); 124 } 125 126 foundLoop = true; 127 128 // Is it labeled by our label? 129 stmt = stmt->enclosing(); 130 while (stmt && stmt->is<ParseContext::LabelStatement>()) { 131 if (stmt->as<ParseContext::LabelStatement>().label() == label) { 132 return Ok(); 133 } 134 135 stmt = stmt->enclosing(); 136 } 137 } 138 } 139 140 template <typename DeclaredNamePtrT> 141 inline void RedeclareVar(DeclaredNamePtrT ptr, DeclarationKind kind) { 142 #ifdef DEBUG 143 DeclarationKind declaredKind = ptr->value()->kind(); 144 MOZ_ASSERT(DeclarationKindIsVar(declaredKind)); 145 #endif 146 147 // Any vars that are redeclared as body-level functions must 148 // be recorded as body-level functions. 149 // 150 // In the case of global and eval scripts, GlobalDeclaration- 151 // Instantiation [1] and EvalDeclarationInstantiation [2] 152 // check for the declarability of global var and function 153 // bindings via CanDeclareVar [3] and CanDeclareGlobal- 154 // Function [4]. CanDeclareGlobalFunction is strictly more 155 // restrictive than CanDeclareGlobalVar, so record the more 156 // restrictive kind. These semantics are implemented in 157 // CheckCanDeclareGlobalBinding. 158 // 159 // VarForAnnexBLexicalFunction declarations are declared when 160 // the var scope exits. It is not possible for a var to be 161 // previously declared as VarForAnnexBLexicalFunction and 162 // checked for redeclaration. 163 // 164 // [1] ES 15.1.11 165 // [2] ES 18.2.1.3 166 // [3] ES 8.1.1.4.15 167 // [4] ES 8.1.1.4.16 168 if (kind == DeclarationKind::BodyLevelFunction) { 169 MOZ_ASSERT(declaredKind != DeclarationKind::VarForAnnexBLexicalFunction); 170 ptr->value()->alterKind(kind); 171 } 172 } 173 174 } // namespace frontend 175 } // namespace js 176 177 #endif // frontend_ParseContext_inl_h