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 "src/handles.h"
9 #include "src/zone.h"
10 
11 namespace v8 {
12 namespace internal {
13 
14 class AstRawString;
15 class AstString;
16 class AstValueFactory;
17 class FunctionLiteral;
18 
19 // FuncNameInferrer is a stateful class that is used to perform name
20 // inference for anonymous functions during static analysis of source code.
21 // Inference is performed in cases when an anonymous function is assigned
22 // to a variable or a property (see test-func-name-inference.cc for examples.)
23 //
24 // The basic idea is that during parsing of LHSs of certain expressions
25 // (assignments, declarations, object literals) we collect name strings,
26 // and during parsing of the RHS, a function literal can be collected. After
27 // parsing the RHS we can infer a name for function literals that do not have
28 // a name.
29 class FuncNameInferrer : public ZoneObject {
30  public:
31   FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone);
32 
33   // To enter function name inference state, put a FuncNameInferrer::State
34   // on the stack.
35   class State {
36    public:
State(FuncNameInferrer * fni)37     explicit State(FuncNameInferrer* fni) : fni_(fni) {
38       if (fni_ != nullptr) fni_->Enter();
39     }
~State()40     ~State() {
41       if (fni_ != nullptr) fni_->Leave();
42     }
43 
44    private:
45     FuncNameInferrer* fni_;
46 
47     DISALLOW_COPY_AND_ASSIGN(State);
48   };
49 
50   // Returns whether we have entered name collection state.
IsOpen()51   bool IsOpen() const { return !entries_stack_.is_empty(); }
52 
53   // Pushes an enclosing the name of enclosing function onto names stack.
54   void PushEnclosingName(const AstRawString* name);
55 
56   // Pushes an encountered name onto names stack when in collection state.
57   void PushLiteralName(const AstRawString* name);
58 
59   void PushVariableName(const AstRawString* name);
60 
61   // Adds a function to infer name for.
AddFunction(FunctionLiteral * func_to_infer)62   void AddFunction(FunctionLiteral* func_to_infer) {
63     if (IsOpen()) {
64       funcs_to_infer_.Add(func_to_infer, zone());
65     }
66   }
67 
RemoveLastFunction()68   void RemoveLastFunction() {
69     if (IsOpen() && !funcs_to_infer_.is_empty()) {
70       funcs_to_infer_.RemoveLast();
71     }
72   }
73 
74   // Infers a function name and leaves names collection state.
Infer()75   void Infer() {
76     DCHECK(IsOpen());
77     if (!funcs_to_infer_.is_empty()) {
78       InferFunctionsNames();
79     }
80   }
81 
82  private:
83   enum NameType {
84     kEnclosingConstructorName,
85     kLiteralName,
86     kVariableName
87   };
88   struct Name {
NameName89     Name(const AstRawString* name, NameType type) : name(name), type(type) {}
90     const AstRawString* name;
91     NameType type;
92   };
93 
Enter()94   void Enter() { entries_stack_.Add(names_stack_.length(), zone()); }
95 
Leave()96   void Leave() {
97     DCHECK(IsOpen());
98     names_stack_.Rewind(entries_stack_.RemoveLast());
99     if (entries_stack_.is_empty()) funcs_to_infer_.Clear();
100   }
101 
zone()102   Zone* zone() const { return zone_; }
103 
104   // Constructs a full name in dotted notation from gathered names.
105   const AstString* MakeNameFromStack();
106 
107   // A helper function for MakeNameFromStack.
108   const AstString* MakeNameFromStackHelper(int pos,
109                                                const AstString* prev);
110 
111   // Performs name inferring for added functions.
112   void InferFunctionsNames();
113 
114   AstValueFactory* ast_value_factory_;
115   ZoneList<int> entries_stack_;
116   ZoneList<Name> names_stack_;
117   ZoneList<FunctionLiteral*> funcs_to_infer_;
118   Zone* zone_;
119 
120   DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
121 };
122 
123 
124 }  // namespace internal
125 }  // namespace v8
126 
127 #endif  // V8_PARSING_FUNC_NAME_INFERRER_H_
128