1// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_PARSING_FUNC_NAME_INFERRER_H_
6#define V8_PARSING_FUNC_NAME_INFERRER_H_
7
8#include <vector>
9
10#include "src/base/macros.h"
11#include "src/base/pointer-with-payload.h"
12
13namespace v8 {
14
15namespace internal {
16class AstRawString;
17}
18
19namespace base {
20template <>
21struct PointerWithPayloadTraits<v8::internal::AstRawString> {
22  static constexpr int kAvailableBits = 2;
23};
24}  // namespace base
25
26namespace internal {
27
28class AstConsString;
29class AstValueFactory;
30class FunctionLiteral;
31
32enum class InferName { kYes, kNo };
33
34// FuncNameInferrer is a stateful class that is used to perform name
35// inference for anonymous functions during static analysis of source code.
36// Inference is performed in cases when an anonymous function is assigned
37// to a variable or a property (see test-func-name-inference.cc for examples.)
38//
39// The basic idea is that during parsing of LHSs of certain expressions
40// (assignments, declarations, object literals) we collect name strings,
41// and during parsing of the RHS, a function literal can be collected. After
42// parsing the RHS we can infer a name for function literals that do not have
43// a name.
44class FuncNameInferrer {
45 public:
46  explicit FuncNameInferrer(AstValueFactory* ast_value_factory);
47
48  FuncNameInferrer(const FuncNameInferrer&) = delete;
49  FuncNameInferrer& operator=(const FuncNameInferrer&) = delete;
50
51  // To enter function name inference state, put a FuncNameInferrer::State
52  // on the stack.
53  class State {
54   public:
55    explicit State(FuncNameInferrer* fni)
56        : fni_(fni), top_(fni->names_stack_.size()) {
57      ++fni_->scope_depth_;
58    }
59    ~State() {
60      DCHECK(fni_->IsOpen());
61      fni_->names_stack_.resize(top_);
62      --fni_->scope_depth_;
63    }
64    State(const State&) = delete;
65    State& operator=(const State&) = delete;
66
67   private:
68    FuncNameInferrer* fni_;
69    size_t top_;
70  };
71
72  // Returns whether we have entered name collection state.
73  bool IsOpen() const { return scope_depth_ > 0; }
74
75  // Pushes an enclosing the name of enclosing function onto names stack.
76  void PushEnclosingName(const AstRawString* name);
77
78  // Pushes an encountered name onto names stack when in collection state.
79  void PushLiteralName(const AstRawString* name);
80
81  void PushVariableName(const AstRawString* name);
82
83  // Adds a function to infer name for.
84  void AddFunction(FunctionLiteral* func_to_infer) {
85    if (IsOpen()) {
86      funcs_to_infer_.push_back(func_to_infer);
87    }
88  }
89
90  void RemoveLastFunction() {
91    if (IsOpen() && !funcs_to_infer_.empty()) funcs_to_infer_.pop_back();
92  }
93
94  void RemoveAsyncKeywordFromEnd();
95
96  // Infers a function name and leaves names collection state.
97  void Infer() {
98    DCHECK(IsOpen());
99    if (!funcs_to_infer_.empty()) InferFunctionsNames();
100  }
101
102 private:
103  enum NameType : uint8_t {
104    kEnclosingConstructorName,
105    kLiteralName,
106    kVariableName
107  };
108  struct Name {
109    // Needed for names_stack_.resize()
110    Name() { UNREACHABLE(); }
111    Name(const AstRawString* name, NameType type)
112        : name_and_type_(name, type) {}
113
114    base::PointerWithPayload<const AstRawString, NameType, 2> name_and_type_;
115    inline const AstRawString* name() const {
116      return name_and_type_.GetPointer();
117    }
118    inline NameType type() const { return name_and_type_.GetPayload(); }
119  };
120
121  // Constructs a full name in dotted notation from gathered names.
122  AstConsString* MakeNameFromStack();
123
124  // Performs name inferring for added functions.
125  void InferFunctionsNames();
126
127  AstValueFactory* ast_value_factory_;
128  std::vector<Name> names_stack_;
129  std::vector<FunctionLiteral*> funcs_to_infer_;
130  size_t scope_depth_ = 0;
131};
132
133
134}  // namespace internal
135}  // namespace v8
136
137#endif  // V8_PARSING_FUNC_NAME_INFERRER_H_
138