/src/hermes/include/hermes/AST/SemValidate.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #ifndef HERMES_AST_SEMVALIDATE_H |
9 | | #define HERMES_AST_SEMVALIDATE_H |
10 | | |
11 | | #include "hermes/AST/Context.h" |
12 | | #include "hermes/AST/ESTree.h" |
13 | | #include "hermes/FrontEndDefs/JavaScriptDeclKind.h" |
14 | | #include "hermes/Support/SourceErrorManager.h" |
15 | | |
16 | | #include <deque> |
17 | | |
18 | | namespace hermes { |
19 | | namespace sem { |
20 | | |
21 | | /// Semantic information for a function declaration, expression, method, etc. |
22 | | class FunctionInfo { |
23 | | public: |
24 | | struct VarDecl { |
25 | | using Kind = JavaScriptDeclKind; |
26 | | |
27 | | Kind kind; |
28 | | ESTree::IdentifierNode *identifier; |
29 | | |
30 | | /// If false, this VarDecl does not need a default undefined/empty |
31 | | /// initialization. These are useful for VarDecls for functions. |
32 | | bool needsInitializer; |
33 | | |
34 | | /// Constructs a VarDecl with the given kind \p k and name \p id. The |
35 | | /// created VarDecl needsInitializer. |
36 | | VarDecl(Kind k, ESTree::IdentifierNode *id) |
37 | 23.1k | : kind(k), identifier(id), needsInitializer(true) {} |
38 | | |
39 | | /// Named-constructor for creating VarDecls that don't require initializers. |
40 | | static VarDecl withoutInitializer( |
41 | | Kind k, |
42 | 0 | ESTree::IdentifierNode *identifier) { |
43 | 0 | VarDecl v{k, identifier}; |
44 | 0 | v.needsInitializer = false; |
45 | 0 | return v; |
46 | 0 | } |
47 | | }; |
48 | | |
49 | | using BlockDecls = llvh::SmallVector<VarDecl, 4>; |
50 | | |
51 | | /// Parameter names. |
52 | | BlockDecls paramNames{}; |
53 | | |
54 | | /// This function's "var" declarations. |
55 | | BlockDecls varScoped; |
56 | | |
57 | | /// Map from AST Node to its lexical (let/const) declarations. |
58 | | llvh::DenseMap<ESTree::Node *, std::unique_ptr<BlockDecls>> lexicallyScoped{}; |
59 | | |
60 | | using BlockClosures = llvh::SmallVector<ESTree::FunctionDeclarationNode *, 2>; |
61 | | /// Map from AST Node to the functions defined in it. |
62 | | llvh::DenseMap<ESTree::Node *, std::unique_ptr<BlockClosures>> closures{}; |
63 | | |
64 | | /// A list of imports that need to be hoisted and materialized before we |
65 | | /// can generate the rest of the function. |
66 | | /// Any line of the file may use the imported values. |
67 | | llvh::SmallVector<ESTree::ImportDeclarationNode *, 2> imports{}; |
68 | | |
69 | | /// Whether this function references the "arguments" identifier. This is a |
70 | | /// conservative approximation of whether it tries to access the "arguments" |
71 | | /// object. Why "conservative"? Because in non-strict mode it is possible to |
72 | | /// declare a variable called "arguments" and then access it. |
73 | | /// In the future, when we start resolving variables in the validator, we will |
74 | | /// be able to be completely accurate, but for now this is good enough. |
75 | | bool usesArguments = false; |
76 | | |
77 | | /// Whether this function contains arrow functions. |
78 | | bool containsArrowFunctions = false; |
79 | | |
80 | | /// This is a logical or of the \c usesArguments flags of all contained |
81 | | /// arrow functions. This will be used as a conservative estimate of |
82 | | /// whether a non-arrow function needs to eagerly create and capture its |
83 | | /// Arguments object. |
84 | | bool containsArrowFunctionsUsingArguments = false; |
85 | | |
86 | | /// Number of labels allocated so far. We use this counter to assign |
87 | | /// consecutive index values to labels. |
88 | | unsigned labelCount = 0; |
89 | | |
90 | | /// Indicates whether this function has been hoisted. |
91 | | bool hoisted{}; |
92 | | |
93 | | /// Allocate a new label and return its index. |
94 | 66.5k | unsigned allocateLabel() { |
95 | 66.5k | return labelCount++; |
96 | 66.5k | } |
97 | | }; |
98 | | |
99 | | /// Identifier and label tables, populated by the semantic validator. They need |
100 | | /// to be stored separately from the AST because they have destructors, while |
101 | | /// the AST is stored in a pool. |
102 | | class SemContext { |
103 | | public: |
104 | | /// Create a new instance of \c FunctionInfo. |
105 | 23.2k | FunctionInfo *createFunction() { |
106 | 23.2k | functions_.emplace_back(); |
107 | 23.2k | return &functions_.back(); |
108 | 23.2k | } |
109 | | |
110 | | private: |
111 | | std::deque<FunctionInfo> functions_{}; |
112 | | }; |
113 | | |
114 | | /// Perform semantic validation of the entire AST, starting from the specified |
115 | | /// root, which should be ProgramNode. |
116 | | bool validateAST(Context &astContext, SemContext &semCtx, ESTree::NodePtr root); |
117 | | |
118 | | /// Perform semantic validation of the entire AST, without preparing the AST for |
119 | | /// compilation. This will not error on features we can parse but not compile, |
120 | | /// transform the AST, or perform compilation specific validation. |
121 | | bool validateASTForParser( |
122 | | Context &astContext, |
123 | | SemContext &semCtx, |
124 | | ESTree::NodePtr root); |
125 | | |
126 | | /// Perform semantic validation of an individual function in the given context |
127 | | /// \param function must be a function node |
128 | | /// \param strict specifies parent strictness. |
129 | | bool validateFunctionAST( |
130 | | Context &astContext, |
131 | | SemContext &semCtx, |
132 | | ESTree::NodePtr function, |
133 | | bool strict); |
134 | | |
135 | | } // namespace sem |
136 | | } // namespace hermes |
137 | | |
138 | | #endif // HERMES_AST_SEMVALIDATE_H |