Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 1 | // Copyright 2020 The Tint Authors. |
| 2 | // |
| 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 | |
Sarah Mashayekhi | 34f90a0 | 2020-11-06 17:31:15 +0000 | [diff] [blame] | 15 | #ifndef SRC_VALIDATOR_VALIDATOR_IMPL_H_ |
| 16 | #define SRC_VALIDATOR_VALIDATOR_IMPL_H_ |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 17 | |
| 18 | #include <string> |
David Neto | 20f4d1d | 2021-01-18 19:45:24 +0000 | [diff] [blame] | 19 | #include <unordered_set> |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 20 | |
Sarah Mashayekhi | 591fe91 | 2020-07-23 23:49:52 +0000 | [diff] [blame] | 21 | #include "src/ast/assignment_statement.h" |
Sarah Mashayekhi | 65f88d6 | 2020-08-06 21:24:14 +0000 | [diff] [blame] | 22 | #include "src/ast/identifier_expression.h" |
Ben Clayton | a6b9a8e | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 23 | #include "src/ast/module.h" |
Sarah Mashayekhi | b08e253 | 2020-08-17 15:46:07 +0000 | [diff] [blame] | 24 | #include "src/ast/return_statement.h" |
Ben Clayton | 1d8098a | 2020-11-30 23:30:58 +0000 | [diff] [blame] | 25 | #include "src/ast/switch_statement.h" |
Ben Clayton | 1d8098a | 2020-11-30 23:30:58 +0000 | [diff] [blame] | 26 | #include "src/ast/variable_decl_statement.h" |
Ben Clayton | c40f627 | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 27 | #include "src/program.h" |
Sarah Mashayekhi | b77399c | 2020-08-05 15:23:47 +0000 | [diff] [blame] | 28 | #include "src/scope_stack.h" |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 29 | |
| 30 | namespace tint { |
| 31 | |
Ben Clayton | c40f627 | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 32 | /// Determines if the program is complete and valid |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 33 | class ValidatorImpl { |
| 34 | public: |
| 35 | /// Constructor |
Ben Clayton | c40f627 | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 36 | /// @param program the program to validate |
| 37 | explicit ValidatorImpl(const Program* program); |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 38 | ~ValidatorImpl(); |
| 39 | |
| 40 | /// Runs the validator |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 41 | /// @returns true if the validation was successful |
dan sinclair | 795b6b5 | 2021-01-11 15:10:19 +0000 | [diff] [blame] | 42 | bool Validate(); |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 43 | |
Ben Clayton | a6b9a8e | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 44 | /// @returns the program being validated |
| 45 | const Program* program() { return program_; } |
| 46 | |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 47 | /// @returns the diagnostic messages |
| 48 | const diag::List& diagnostics() const { return diags_; } |
| 49 | /// @returns the diagnostic messages |
| 50 | diag::List& diagnostics() { return diags_; } |
| 51 | |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 52 | /// @returns error messages from the validator |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 53 | std::string error() { |
Ben Clayton | d221738 | 2021-01-11 21:09:22 +0000 | [diff] [blame] | 54 | diag::Formatter formatter{{false, false, false, false}}; |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 55 | return formatter.format(diags_); |
| 56 | } |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 57 | /// @returns true if an error was encountered |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 58 | bool has_error() const { return diags_.contains_errors(); } |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 59 | |
Ben Clayton | f8971ae | 2020-12-02 15:31:08 +0000 | [diff] [blame] | 60 | /// Appends an error at `src` with the code `code` and message `msg` |
Ben Clayton | f32a3c1 | 2020-11-26 17:49:22 +0000 | [diff] [blame] | 61 | /// @param src the source causing the error |
| 62 | /// @param code the validation error code |
| 63 | /// @param msg the error message |
| 64 | void add_error(const Source& src, const char* code, const std::string& msg); |
| 65 | |
Ben Clayton | f8971ae | 2020-12-02 15:31:08 +0000 | [diff] [blame] | 66 | /// Appends an error at `src` with the message `msg` |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 67 | /// @param src the source causing the error |
| 68 | /// @param msg the error message |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 69 | void add_error(const Source& src, const std::string& msg); |
| 70 | |
James Price | c0f3019 | 2021-02-09 23:22:32 +0000 | [diff] [blame] | 71 | /// Validates a global variable |
| 72 | /// @param var the global variable to check |
Sarah Mashayekhi | 4fb431c | 2020-08-25 15:04:53 +0000 | [diff] [blame] | 73 | /// @returns true if the validation was successful |
James Price | c0f3019 | 2021-02-09 23:22:32 +0000 | [diff] [blame] | 74 | bool ValidateGlobalVariable(const ast::Variable* var); |
Sarah Mashayekhi | 591fe91 | 2020-07-23 23:49:52 +0000 | [diff] [blame] | 75 | /// Validates a function |
| 76 | /// @param func the function to check |
| 77 | /// @returns true if the validation was successful |
Sarah Mashayekhi | a3f9778 | 2020-07-30 02:27:03 +0000 | [diff] [blame] | 78 | bool ValidateFunction(const ast::Function* func); |
dan sinclair | 4069f33 | 2020-07-27 15:25:00 +0000 | [diff] [blame] | 79 | /// Validates a block of statements |
| 80 | /// @param block the statements to check |
| 81 | /// @returns true if the validation was successful |
Sarah Mashayekhi | a3f9778 | 2020-07-30 02:27:03 +0000 | [diff] [blame] | 82 | bool ValidateStatements(const ast::BlockStatement* block); |
Sarah Mashayekhi | 591fe91 | 2020-07-23 23:49:52 +0000 | [diff] [blame] | 83 | /// Validates a statement |
| 84 | /// @param stmt the statement to check |
| 85 | /// @returns true if the validation was successful |
Sarah Mashayekhi | a3f9778 | 2020-07-30 02:27:03 +0000 | [diff] [blame] | 86 | bool ValidateStatement(const ast::Statement* stmt); |
Sarah Mashayekhi | 591fe91 | 2020-07-23 23:49:52 +0000 | [diff] [blame] | 87 | /// Validates an assignment |
Sarah Mashayekhi | e88f1c3 | 2020-08-07 14:34:34 +0000 | [diff] [blame] | 88 | /// @param assign the assignment to check |
Sarah Mashayekhi | 591fe91 | 2020-07-23 23:49:52 +0000 | [diff] [blame] | 89 | /// @returns true if the validation was successful |
Sarah Mashayekhi | e88f1c3 | 2020-08-07 14:34:34 +0000 | [diff] [blame] | 90 | bool ValidateAssign(const ast::AssignmentStatement* assign); |
David Neto | 71012dc | 2021-01-18 22:17:25 +0000 | [diff] [blame] | 91 | /// Validates a bad assignment to an identifier. Issues an error |
| 92 | /// and returns false if the left hand side is an identifier. |
| 93 | /// @param assign the assignment to check |
| 94 | /// @returns true if the LHS of theassignment is not an identifier expression |
| 95 | bool ValidateBadAssignmentToIdentifier( |
| 96 | const ast::AssignmentStatement* assign); |
Sarah Mashayekhi | 65f88d6 | 2020-08-06 21:24:14 +0000 | [diff] [blame] | 97 | /// Validates an expression |
| 98 | /// @param expr the expression to check |
Sarah Mashayekhi | 8db00df | 2020-08-20 17:00:09 +0000 | [diff] [blame] | 99 | /// @return true if the expression is valid |
Sarah Mashayekhi | 65f88d6 | 2020-08-06 21:24:14 +0000 | [diff] [blame] | 100 | bool ValidateExpression(const ast::Expression* expr); |
Ben Clayton | f8971ae | 2020-12-02 15:31:08 +0000 | [diff] [blame] | 101 | /// Validates declaration name uniqueness |
| 102 | /// @param decl is the new declaration to be added |
| 103 | /// @returns true if no previous declaration with the `decl` 's name |
Sarah Mashayekhi | d3107bd | 2020-08-11 20:44:06 +0000 | [diff] [blame] | 104 | /// exist in the variable stack |
| 105 | bool ValidateDeclStatement(const ast::VariableDeclStatement* decl); |
Sarah Mashayekhi | b08e253 | 2020-08-17 15:46:07 +0000 | [diff] [blame] | 106 | /// Validates return statement |
| 107 | /// @param ret the return statement to check |
| 108 | /// @returns true if function return type matches the return statement type |
| 109 | bool ValidateReturnStatement(const ast::ReturnStatement* ret); |
Sarah Mashayekhi | 8db00df | 2020-08-20 17:00:09 +0000 | [diff] [blame] | 110 | /// Validates function calls |
| 111 | /// @param expr the call to validate |
| 112 | /// @returns true if successful |
| 113 | bool ValidateCallExpr(const ast::CallExpression* expr); |
Sarah Mashayekhi | 2e9f1f5 | 2020-09-10 14:37:17 +0000 | [diff] [blame] | 114 | /// Validates switch statements |
| 115 | /// @param s the switch statement to check |
| 116 | /// @returns true if the valdiation was successful |
| 117 | bool ValidateSwitch(const ast::SwitchStatement* s); |
| 118 | /// Validates case statements |
| 119 | /// @param c the case statement to check |
| 120 | /// @returns true if the valdiation was successful |
| 121 | bool ValidateCase(const ast::CaseStatement* c); |
Sarah Mashayekhi | 3b04058 | 2020-11-11 14:21:05 +0000 | [diff] [blame] | 122 | /// Validates entry points |
| 123 | /// @param funcs the functions to check |
| 124 | /// @returns true if the valdiation was successful |
| 125 | bool ValidateEntryPoint(const ast::FunctionList& funcs); |
David Neto | 20f4d1d | 2021-01-18 19:45:24 +0000 | [diff] [blame] | 126 | /// Returns true if the given type is storable. This uses and |
| 127 | /// updates `storable_` and `not_storable_`. |
| 128 | /// @param type the given type |
| 129 | /// @returns true if the given type is storable. |
Ben Clayton | 207b5e2 | 2021-01-21 15:42:10 +0000 | [diff] [blame] | 130 | bool IsStorable(type::Type* type); |
David Neto | 20f4d1d | 2021-01-18 19:45:24 +0000 | [diff] [blame] | 131 | |
David Neto | 71012dc | 2021-01-18 22:17:25 +0000 | [diff] [blame] | 132 | /// Testing method to inserting a given variable into the current scope. |
Ben Clayton | 207b5e2 | 2021-01-21 15:42:10 +0000 | [diff] [blame] | 133 | /// @param var the variable to register |
David Neto | 71012dc | 2021-01-18 22:17:25 +0000 | [diff] [blame] | 134 | void RegisterVariableForTesting(ast::Variable* var) { |
| 135 | variable_stack_.set(var->symbol(), var); |
| 136 | } |
| 137 | |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 138 | private: |
Ben Clayton | c40f627 | 2021-01-26 16:57:10 +0000 | [diff] [blame] | 139 | const Program* program_; |
Ben Clayton | ba06db6 | 2020-11-26 16:50:02 +0000 | [diff] [blame] | 140 | diag::List diags_; |
James Price | c0f3019 | 2021-02-09 23:22:32 +0000 | [diff] [blame] | 141 | ScopeStack<const ast::Variable*> variable_stack_; |
Sarah Mashayekhi | b08e253 | 2020-08-17 15:46:07 +0000 | [diff] [blame] | 142 | ast::Function* current_function_ = nullptr; |
Sarah Mashayekhi | 462dd67 | 2020-03-04 20:51:29 +0000 | [diff] [blame] | 143 | }; |
| 144 | |
| 145 | } // namespace tint |
| 146 | |
Sarah Mashayekhi | 34f90a0 | 2020-11-06 17:31:15 +0000 | [diff] [blame] | 147 | #endif // SRC_VALIDATOR_VALIDATOR_IMPL_H_ |