|  | // Copyright 2021 The Tint Authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "src/program.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "src/demangler.h" | 
|  | #include "src/resolver/resolver.h" | 
|  | #include "src/semantic/expression.h" | 
|  |  | 
|  | namespace tint { | 
|  |  | 
|  | Program::Program() = default; | 
|  |  | 
|  | Program::Program(Program&& program) | 
|  | : id_(std::move(program.id_)), | 
|  | types_(std::move(program.types_)), | 
|  | ast_nodes_(std::move(program.ast_nodes_)), | 
|  | sem_nodes_(std::move(program.sem_nodes_)), | 
|  | ast_(std::move(program.ast_)), | 
|  | sem_(std::move(program.sem_)), | 
|  | symbols_(std::move(program.symbols_)), | 
|  | diagnostics_(std::move(program.diagnostics_)), | 
|  | is_valid_(program.is_valid_) { | 
|  | program.AssertNotMoved(); | 
|  | program.moved_ = true; | 
|  | } | 
|  |  | 
|  | Program::Program(ProgramBuilder&& builder) { | 
|  | id_ = builder.ID(); | 
|  |  | 
|  | is_valid_ = builder.IsValid(); | 
|  | if (builder.ResolveOnBuild() && builder.IsValid()) { | 
|  | resolver::Resolver resolver(&builder); | 
|  | if (!resolver.Resolve()) { | 
|  | diagnostics_.add_error(resolver.error()); | 
|  | is_valid_ = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // The above must be called *before* the calls to std::move() below | 
|  | types_ = std::move(builder.Types()); | 
|  | ast_nodes_ = std::move(builder.ASTNodes()); | 
|  | sem_nodes_ = std::move(builder.SemNodes()); | 
|  | ast_ = &builder.AST();  // ast::Module is actually a heap allocation. | 
|  | sem_ = std::move(builder.Sem()); | 
|  | symbols_ = std::move(builder.Symbols()); | 
|  | diagnostics_.add(std::move(builder.Diagnostics())); | 
|  | builder.MarkAsMoved(); | 
|  |  | 
|  | if (!is_valid_ && !diagnostics_.contains_errors()) { | 
|  | // If the builder claims to be invalid, then we really should have an error | 
|  | // message generated. If we find a situation where the program is not valid | 
|  | // and there are no errors reported, add one here. | 
|  | diagnostics_.add_error("invalid program generated"); | 
|  | } | 
|  | } | 
|  |  | 
|  | Program::~Program() = default; | 
|  |  | 
|  | Program& Program::operator=(Program&& program) { | 
|  | program.AssertNotMoved(); | 
|  | program.moved_ = true; | 
|  | id_ = std::move(program.id_); | 
|  | types_ = std::move(program.types_); | 
|  | ast_nodes_ = std::move(program.ast_nodes_); | 
|  | sem_nodes_ = std::move(program.sem_nodes_); | 
|  | ast_ = std::move(program.ast_); | 
|  | sem_ = std::move(program.sem_); | 
|  | symbols_ = std::move(program.symbols_); | 
|  | diagnostics_ = std::move(program.diagnostics_); | 
|  | is_valid_ = program.is_valid_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | Program Program::Clone() const { | 
|  | AssertNotMoved(); | 
|  | return Program(CloneAsBuilder()); | 
|  | } | 
|  |  | 
|  | ProgramBuilder Program::CloneAsBuilder() const { | 
|  | AssertNotMoved(); | 
|  | ProgramBuilder out; | 
|  | CloneContext(&out, this).Clone(); | 
|  | return out; | 
|  | } | 
|  |  | 
|  | bool Program::IsValid() const { | 
|  | AssertNotMoved(); | 
|  | return is_valid_; | 
|  | } | 
|  |  | 
|  | type::Type* Program::TypeOf(const ast::Expression* expr) const { | 
|  | auto* sem = Sem().Get(expr); | 
|  | return sem ? sem->Type() : nullptr; | 
|  | } | 
|  |  | 
|  | std::string Program::to_str(bool demangle) const { | 
|  | AssertNotMoved(); | 
|  | auto str = ast_->to_str(Sem()); | 
|  | if (demangle) { | 
|  | str = Demangler().Demangle(Symbols(), str); | 
|  | } | 
|  | return str; | 
|  | } | 
|  |  | 
|  | std::string Program::str(const ast::Node* node) const { | 
|  | return Demangler().Demangle(Symbols(), node->str(Sem())); | 
|  | } | 
|  |  | 
|  | void Program::AssertNotMoved() const { | 
|  | TINT_ASSERT(!moved_); | 
|  | } | 
|  |  | 
|  | }  // namespace tint |