• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
17 #define ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
18 
19 #include <algorithm>
20 #include <iterator>
21 #include <regex>
22 #include <string>
23 #include <unordered_set>
24 
25 #include "ast_verifier/checkContext.h"
26 
27 #include "ir/astNode.h"
28 #include "ir/statements/blockStatement.h"
29 #include "lexer/token/sourceLocation.h"
30 #include "parser/program/program.h"
31 #include "util/ustring.h"
32 #include "utils/arena_containers.h"
33 #include "varbinder/variable.h"
34 
35 namespace ark::es2panda::compiler::ast_verifier {
36 
37 using InvariantCheck = std::function<CheckResult(CheckContext &ctx, const ir::AstNode *)>;
38 using Invariants = std::map<std::string, InvariantCheck>;
39 
40 using InvariantNameSet = std::set<std::string>;
41 
42 class VerificationContext final {
43 public:
IntroduceNewInvariants(util::StringView phaseName)44     void IntroduceNewInvariants(util::StringView phaseName)
45     {
46         if (phaseName == "ScopesInitPhase") {
47             accumulatedChecks_.insert("NodeHasParentForAll");
48             accumulatedChecks_.insert("NodeHasSourceRangeForAll");
49             accumulatedChecks_.insert("EveryChildHasValidParentForAll");
50             accumulatedChecks_.insert("EveryChildInParentRangeForAll");
51             accumulatedChecks_.insert("VariableHasScopeForAll");
52         }
53         if (phaseName == "CheckerPhase") {
54             accumulatedChecks_.insert("NodeHasTypeForAll");
55             accumulatedChecks_.insert("IdentifierHasVariableForAll");
56             accumulatedChecks_.insert("ReferenceTypeAnnotationIsNullForAll");
57             accumulatedChecks_.insert("ArithmeticOperationValidForAll");
58             accumulatedChecks_.insert("SequenceExpressionHasLastTypeForAll");
59             accumulatedChecks_.insert("CheckInfiniteLoopForAll");
60             accumulatedChecks_.insert("ForLoopCorrectlyInitializedForAll");
61             accumulatedChecks_.insert("VariableHasEnclosingScopeForAll");
62             accumulatedChecks_.insert("ModifierAccessValidForAll");
63             accumulatedChecks_.insert("ImportExportAccessValid");
64             accumulatedChecks_.insert("VariableNameIdentifierNameSameForAll");
65         }
66     }
67 
AccumulatedChecks()68     const InvariantNameSet &AccumulatedChecks() const
69     {
70         return accumulatedChecks_;
71     }
72 
73 private:
74     InvariantNameSet accumulatedChecks_ {};
75 };
76 
77 /*
78  * ASTVerifier used for checking various invariants that should hold during AST transformation in lowerings
79  * For all available checks lookup the constructor
80  */
81 class ASTVerifier final {
82 public:
83     NO_COPY_SEMANTIC(ASTVerifier);
84     NO_MOVE_SEMANTIC(ASTVerifier);
85 
86     explicit ASTVerifier(ArenaAllocator *allocator);
87     ~ASTVerifier() = default;
88 
89     /**
90      * @brief Run all existing invariants on some ast node (and consequently it's children)
91      * @param ast AstNode which will be analyzed
92      * @return Messages report of analysis
93      */
94     Messages VerifyFull(const ir::AstNode *ast);
95 
96     /**
97      * @brief Run some particular invariants on some ast node
98      * @note invariants must be supplied as strings to invariant_set, additionally invariant
99      * name can be suffixed by `ForAll` string to include recursive analysis of provided node
100      * I.e. 'HasParent' invariant can be named 'HasParentRecursive' to traverse all child nodes as well
101      * @param ast AstNode which will be analyzed
102      * @param invariantSet Set of invariants to check
103      * @return Messages report of analysis
104      */
105     Messages Verify(const ir::AstNode *ast, const InvariantNameSet &invariantSet);
106 
107 private:
108     static constexpr const char *RECURSIVE_SUFFIX = "ForAll";
109 
RecursiveInvariant(const InvariantCheck & func)110     static InvariantCheck RecursiveInvariant(const InvariantCheck &func)
111     {
112         return [func](CheckContext &ctx, const ir::AstNode *ast) -> CheckResult {
113             std::function<void(const ir::AstNode *)> aux;
114             auto finalDecision = CheckDecision::CORRECT;
115             aux = [&ctx, func, &aux, &finalDecision](const ir::AstNode *child) -> void {
116                 const auto [decision, action] = func(ctx, child);
117                 if (decision == CheckDecision::INCORRECT) {
118                     finalDecision = CheckDecision::INCORRECT;
119                 }
120                 if (action == CheckAction::SKIP_SUBTREE) {
121                     return;
122                 }
123                 child->Iterate(aux);
124             };
125             aux(ast);
126             return {finalDecision, CheckAction::CONTINUE};
127         };
128     }
129 
130     template <typename T>
AddInvariant(ArenaAllocator * allocator,const std::string & name)131     void AddInvariant(ArenaAllocator *allocator, const std::string &name)
132     {
133         auto check = *allocator->New<T>(*allocator);
134         invariantsChecks_[name] = check;
135         invariantsNames_.insert(name);
136         invariantsChecks_[name + RECURSIVE_SUFFIX] = RecursiveInvariant(check);
137         invariantsNames_.insert(name + RECURSIVE_SUFFIX);
138     }
139 
140     Invariants invariantsChecks_;
141     InvariantNameSet invariantsNames_;
142 };
143 
144 }  // namespace ark::es2panda::compiler::ast_verifier
145 
146 #endif  // ES2PANDA_COMPILER_CORE_ASTVERIFIER_H
147