tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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