| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/shell/console/ast_builder.h" |
| |
| #include <algorithm> |
| |
| namespace shell::console { |
| |
| using NodeId = AstBuilder::NodeId; |
| |
| NodeId AstBuilder::AddNode(llcpp::fuchsia::shell::Node&& node, bool is_root) { |
| llcpp::fuchsia::shell::NodeDefinition definition; |
| definition.node = std::move(node); |
| definition.root_node = is_root; |
| llcpp::fuchsia::shell::NodeId id; |
| id.file_id = file_id_; |
| id.node_id = ++next_id_; |
| definition.node_id = std::move(id); |
| nodes_.push_back(std::move(definition)); |
| return id; |
| } |
| |
| fidl::VectorView<llcpp::fuchsia::shell::Node> AstBuilder::NodesAsVectorView() { |
| struct { |
| bool operator()(const llcpp::fuchsia::shell::NodeDefinition& a, |
| const llcpp::fuchsia::shell::NodeDefinition& b) const { |
| return a.node_id.node_id < b.node_id.node_id; |
| } |
| } cmp; |
| std::sort(nodes_.begin(), nodes_.end(), cmp); |
| for (auto& node_def : nodes_) { |
| raw_nodes_.push_back(std::move(node_def.node)); |
| } |
| nodes_.clear(); |
| return fidl::unowned_vec(raw_nodes_); |
| } |
| |
| AstBuilder& AstBuilder::operator=(AstBuilder&& other) { |
| this->next_id_ = other.next_id_; |
| this->bufs_ = std::move(other.bufs_); |
| other.bufs_.clear(); |
| this->nodes_ = std::move(other.nodes_); |
| return *this; |
| } |
| |
| AstBuilder::AstBuilder(AstBuilder&& other) { |
| this->next_id_ = other.next_id_; |
| this->bufs_ = std::move(other.bufs_); |
| other.bufs_.clear(); |
| this->nodes_ = std::move(other.nodes_); |
| } |
| |
| void AstBuilder::SetRoot(NodeId node_id) { |
| for (size_t i = 0; i < nodes_.size(); i++) { |
| if (nodes_[i].node_id.node_id == node_id.node_id && |
| nodes_[i].node_id.file_id == node_id.file_id) { |
| nodes_[i].root_node = true; |
| return; |
| } |
| } |
| } |
| |
| NodeId AstBuilder::AddVariableDeclaration(const std::string& identifier, |
| llcpp::fuchsia::shell::ShellType&& type, NodeId node_id, |
| bool is_const, bool is_root) { |
| auto def = ManageNew<llcpp::fuchsia::shell::VariableDefinition>(); |
| char* name_buf = ManageCopyOf(identifier.c_str(), identifier.size()); |
| def->name.set_data(fidl::unowned_ptr(name_buf)); |
| def->name.set_size(identifier.size()); |
| def->type = std::move(type); |
| def->mutable_value = !is_const; |
| def->initial_value = node_id; |
| auto node = llcpp::fuchsia::shell::Node::WithVariableDefinition(fidl::unowned_ptr(def)); |
| return AddNode(std::move(node), is_root); |
| } |
| |
| NodeId AstBuilder::AddVariableFromDef(NodeId node_id) { |
| auto managed_node = ManagedNodeId(node_id); |
| auto node = llcpp::fuchsia::shell::Node::WithVariable(fidl::unowned_ptr(managed_node)); |
| return AddNode(std::move(node)); |
| } |
| |
| NodeId AstBuilder::AddIntegerLiteral(uint64_t i, bool is_negative) { |
| auto literal = ManageNew<llcpp::fuchsia::shell::IntegerLiteral>(); |
| |
| uint64_t* managed_val = ManageCopyOf(&i); |
| |
| literal->absolute_value = ::fidl::VectorView(fidl::unowned_ptr(managed_val), 1); |
| literal->negative = is_negative; |
| auto node = llcpp::fuchsia::shell::Node::WithIntegerLiteral(fidl::unowned_ptr(literal)); |
| return AddNode(std::move(node)); |
| } |
| |
| NodeId AstBuilder::AddIntegerLiteral(int64_t i) { |
| auto literal = ManageNew<llcpp::fuchsia::shell::IntegerLiteral>(); |
| |
| uint64_t val; |
| if (i == LLONG_MIN) { |
| val = static_cast<uint64_t>(LLONG_MAX) + 1; |
| } else { |
| val = llabs(i); |
| } |
| uint64_t* managed_val = ManageCopyOf(&val); |
| |
| literal->absolute_value = ::fidl::VectorView(fidl::unowned_ptr(managed_val), 1); |
| literal->negative = (i < 0); |
| auto node = llcpp::fuchsia::shell::Node::WithIntegerLiteral(fidl::unowned_ptr(literal)); |
| return AddNode(std::move(node)); |
| } |
| |
| NodeId AstBuilder::AddStringLiteral(const std::string& s) { |
| auto literal = ManageNew<fidl::StringView>(); |
| |
| char* managed_val = ManageCopyOf(s.data(), s.size()); |
| literal->set_data(fidl::unowned_ptr(managed_val)); |
| literal->set_size(s.size()); |
| auto node = llcpp::fuchsia::shell::Node::WithStringLiteral(fidl::unowned_ptr(literal)); |
| return AddNode(std::move(node)); |
| } |
| |
| NodeId AstBuilder::AddAddition(bool with_exceptions, NodeId left_id, NodeId right_id) { |
| auto addition = ManageNew<llcpp::fuchsia::shell::Addition>(); |
| addition->left = std::move(left_id); |
| addition->right = std::move(right_id); |
| addition->with_exceptions = with_exceptions; |
| |
| auto node = llcpp::fuchsia::shell::Node::WithAddition(fidl::unowned_ptr(addition)); |
| |
| return AddNode(std::move(node), /*root_node=*/false); |
| } |
| |
| void AstBuilder::OpenObject() { object_stack_.emplace_back(); } |
| |
| AstBuilder::NodePair AstBuilder::CloseObject() { |
| auto object_schema = ManageNew<llcpp::fuchsia::shell::ObjectSchemaDefinition>(); |
| auto object = ManageNew<llcpp::fuchsia::shell::ObjectDefinition>(); |
| |
| // Create a vector of nodes for the fields. |
| std::vector<FidlNodeIdPair>& fields = object_stack_.back(); |
| auto schema_mem = ManageNewArray<llcpp::fuchsia::shell::NodeId>(fields.size()); |
| auto value_mem = ManageNewArray<llcpp::fuchsia::shell::NodeId>(fields.size()); |
| for (size_t i = 0; i < fields.size(); i++) { |
| schema_mem[i] = std::move(fields[i].schema_id); |
| value_mem[i] = std::move(fields[i].value_id); |
| } |
| |
| object_schema->fields = ::fidl::VectorView<llcpp::fuchsia::shell::NodeId>( |
| fidl::unowned_ptr(schema_mem), fields.size()); |
| auto schema_node = |
| llcpp::fuchsia::shell::Node::WithObjectSchema(fidl::unowned_ptr(object_schema)); |
| NodeId schema_node_id = AddNode(std::move(schema_node), true); |
| |
| object->fields = ::fidl::VectorView<llcpp::fuchsia::shell::NodeId>(fidl::unowned_ptr(value_mem), |
| fields.size()); |
| auto value_node = llcpp::fuchsia::shell::Node::WithObject(fidl::unowned_ptr(object)); |
| NodeId value_node_id = AddNode(std::move(value_node)); |
| |
| object->object_schema = schema_node_id; |
| |
| object_stack_.pop_back(); |
| NodePair result; |
| result.schema_node = schema_node_id; |
| result.value_node = value_node_id; |
| return result; |
| } |
| |
| AstBuilder::NodePair AstBuilder::AddField(const std::string& key, NodeId expression_node_id, |
| llcpp::fuchsia::shell::ShellType&& type) { |
| NodePair result; |
| |
| // Create the type. |
| auto field_schema = ManageNew<llcpp::fuchsia::shell::ObjectFieldSchemaDefinition>(); |
| char* name_buf = ManageCopyOf(key.c_str(), key.size()); |
| field_schema->name.set_data(fidl::unowned_ptr(name_buf)); |
| field_schema->name.set_size(key.size()); |
| field_schema->type = std::move(type); |
| auto node = llcpp::fuchsia::shell::Node::WithFieldSchema(fidl::unowned_ptr(field_schema)); |
| llcpp::fuchsia::shell::NodeId type_id; |
| result.schema_node = type_id = AddNode(std::move(node)); |
| |
| // Create the object |
| auto field = ManageNew<llcpp::fuchsia::shell::ObjectFieldDefinition>(); |
| field->object_field_schema.file_id = file_id_; |
| field->object_field_schema.node_id = type_id.node_id; |
| field->value = expression_node_id; |
| llcpp::fuchsia::shell::NodeId value_id; |
| auto value_node = llcpp::fuchsia::shell::Node::WithObjectField(fidl::unowned_ptr(field)); |
| result.value_node = value_id = AddNode(std::move(value_node)); |
| |
| std::vector<FidlNodeIdPair>& fields = object_stack_.back(); |
| fields.emplace_back(std::move(type_id), std::move(value_id)); |
| |
| return result; |
| } |
| |
| } // namespace shell::console |