| // 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/interpreter/src/server.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <memory> |
| #include <string_view> |
| |
| #include "lib/async-loop/default.h" |
| #include "lib/fidl-async/cpp/bind.h" |
| #include "lib/svc/dir.h" |
| #include "src/developer/shell/common/ast_builder.h" |
| #include "src/developer/shell/interpreter/src/expressions.h" |
| #include "src/developer/shell/interpreter/src/instructions.h" |
| #include "src/developer/shell/interpreter/src/schema.h" |
| #include "src/developer/shell/interpreter/src/types.h" |
| #include "zircon/process.h" |
| #include "zircon/processargs.h" |
| #include "zircon/status.h" |
| |
| namespace shell { |
| namespace interpreter { |
| namespace server { |
| |
| inline std::string_view GetView(const ::fidl::StringView& view) { |
| return std::string_view(view.data(), view.size()); |
| } |
| |
| std::unique_ptr<Type> GetType(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, |
| const fuchsia_shell::wire::ShellType& shell_type) { |
| if (shell_type.is_undef()) { |
| return std::make_unique<TypeUndefined>(); |
| } |
| if (shell_type.is_builtin_type()) { |
| using fuchsia_shell::wire::BuiltinType; |
| switch (shell_type.builtin_type()) { |
| case BuiltinType::kBool: |
| return std::make_unique<TypeBool>(); |
| case BuiltinType::kChar: |
| return std::make_unique<TypeChar>(); |
| case BuiltinType::kString: |
| return std::make_unique<TypeString>(); |
| case BuiltinType::kInt8: |
| return std::make_unique<TypeInt8>(); |
| case BuiltinType::kUint8: |
| return std::make_unique<TypeUint8>(); |
| case BuiltinType::kInt16: |
| return std::make_unique<TypeInt16>(); |
| case BuiltinType::kUint16: |
| return std::make_unique<TypeUint16>(); |
| case BuiltinType::kInt32: |
| return std::make_unique<TypeInt32>(); |
| case BuiltinType::kUint32: |
| return std::make_unique<TypeUint32>(); |
| case BuiltinType::kInt64: |
| return std::make_unique<TypeInt64>(); |
| case BuiltinType::kUint64: |
| return std::make_unique<TypeUint64>(); |
| case BuiltinType::kInteger: |
| return std::make_unique<TypeInteger>(); |
| case BuiltinType::kFloat32: |
| return std::make_unique<TypeFloat32>(); |
| case BuiltinType::kFloat64: |
| return std::make_unique<TypeFloat64>(); |
| default: |
| break; |
| } |
| } |
| if (shell_type.is_object_schema()) { |
| NodeId node_id(shell_type.object_schema().file_id, shell_type.object_schema().node_id); |
| std::shared_ptr<ObjectSchema> schema_node = |
| context->execution_context()->GetObjectSchema(node_id); |
| if (schema_node == nullptr) { |
| context->execution_context()->EmitError(NodeId(node_file_id, node_node_id), |
| "Type not found for object"); |
| return std::make_unique<TypeUndefined>(); |
| } |
| return ObjectSchema::GetType(schema_node); |
| } |
| context->execution_context()->EmitError(NodeId(node_file_id, node_node_id), "Bad type."); |
| return std::make_unique<TypeUndefined>(); |
| } |
| |
| class SerializeHelper { |
| public: |
| SerializeHelper() = default; |
| |
| fidl::VectorView<fuchsia_shell::wire::Node> nodes() { return builder_.NodesAsVectorView(); } |
| |
| struct TypeAndValue { |
| shell::console::AstBuilder::NodeId value_id; |
| fuchsia_shell::wire::ShellType type; |
| }; |
| |
| TypeAndValue Set(const Value& value) { |
| TypeAndValue id; |
| using fuchsia_shell::wire::BuiltinType; |
| switch (value.type()) { |
| case ValueType::kUndef: { |
| id.value_id.file_id = -1; |
| id.value_id.node_id = -1; |
| id.type = builder_.TypeUndef(); |
| break; |
| } |
| case ValueType::kInt8: |
| id.value_id = builder_.AddIntegerLiteral(value.GetInt8()); |
| id.type = GetBuiltin(BuiltinType::kInt8); |
| break; |
| case ValueType::kUint8: |
| id.value_id = builder_.AddIntegerLiteral(value.GetUint8()); |
| id.type = GetBuiltin(BuiltinType::kUint8); |
| break; |
| case ValueType::kInt16: |
| id.value_id = builder_.AddIntegerLiteral(value.GetInt16()); |
| id.type = GetBuiltin(BuiltinType::kInt16); |
| break; |
| case ValueType::kUint16: |
| id.value_id = builder_.AddIntegerLiteral(value.GetUint16()); |
| id.type = GetBuiltin(BuiltinType::kUint16); |
| break; |
| case ValueType::kInt32: |
| id.value_id = builder_.AddIntegerLiteral(value.GetInt32()); |
| id.type = GetBuiltin(BuiltinType::kInt32); |
| break; |
| case ValueType::kUint32: |
| id.value_id = builder_.AddIntegerLiteral(value.GetUint32()); |
| id.type = GetBuiltin(BuiltinType::kUint32); |
| break; |
| case ValueType::kInt64: |
| id.value_id = builder_.AddIntegerLiteral(value.GetInt64()); |
| id.type = GetBuiltin(BuiltinType::kInt64); |
| break; |
| case ValueType::kUint64: |
| id.value_id = builder_.AddIntegerLiteral(value.GetUint64()); |
| id.type = GetBuiltin(BuiltinType::kUint64); |
| break; |
| // Float ? |
| case ValueType::kString: |
| id.value_id = builder_.AddStringLiteral(value.GetString()->value()); |
| id.type = GetBuiltin(BuiltinType::kString); |
| break; |
| case ValueType::kObject: { |
| builder_.OpenObject(); |
| Object* object = value.GetObject(); |
| const std::shared_ptr<ObjectSchema> schema = object->schema(); |
| for (auto& field : schema->fields()) { |
| auto value = object->GetField(field.get()); |
| auto expression_id = Set(*value); |
| builder_.AddField(field->name(), expression_id.value_id, std::move(expression_id.type)); |
| } |
| shell::console::AstBuilder::NodePair value_type = builder_.CloseObject(); |
| id.value_id = value_type.value_node; |
| id.type = builder_.TypeObject(value_type.schema_node); |
| break; |
| } |
| } |
| return id; |
| } |
| |
| fuchsia_shell::wire::ShellType GetBuiltin(fuchsia_shell::wire::BuiltinType type) { |
| return builder_.TypeBuiltin(type); |
| } |
| |
| private: |
| shell::console::AstBuilder builder_; |
| }; |
| |
| // - ServerInterpreterContext ---------------------------------------------------------------------- |
| |
| std::unique_ptr<Expression> ServerInterpreterContext::GetExpression(const NodeId& node_id) { |
| auto result = expressions_.find(node_id); |
| if (result == expressions_.end()) { |
| return nullptr; |
| } |
| auto returned_value = std::move(result->second); |
| FX_DCHECK(returned_value != nullptr); |
| expressions_.erase(result); |
| return returned_value; |
| } |
| |
| // Retrieves the field corresponding to the given node id. |
| std::unique_ptr<ObjectDeclarationField> ServerInterpreterContext::GetObjectField( |
| const NodeId& node_id) { |
| auto result = fields_.find(node_id); |
| if (result == fields_.end()) { |
| return nullptr; |
| } |
| auto returned_value = std::move(result->second); |
| FX_DCHECK(returned_value != nullptr); |
| return returned_value; |
| } |
| |
| // Retrieves the schema of the field definition for the given node id. |
| std::shared_ptr<ObjectFieldSchema> ServerInterpreterContext::GetObjectFieldSchema( |
| const NodeId& node_id) { |
| auto result = object_field_schemas_.find(node_id); |
| if (result == object_field_schemas_.end()) { |
| return nullptr; |
| } |
| FX_DCHECK(result->second != nullptr); |
| return result->second; |
| } |
| |
| // - ServerInterpreter ----------------------------------------------------------------------------- |
| |
| void ServerInterpreter::EmitError(ExecutionContext* context, std::string error_message) { |
| auto result = |
| service_->OnError((context == nullptr) ? 0 : context->id(), std::move(error_message)); |
| ZX_ASSERT(result.ok()); |
| if (context != nullptr) { |
| context->set_has_errors(); |
| } |
| } |
| |
| void ServerInterpreter::EmitError(ExecutionContext* context, NodeId node_id, |
| std::string error_message) { |
| FX_DCHECK(context != nullptr); |
| fidl::Arena allocator; |
| fidl::VectorView<fuchsia_shell::wire::Location> locations(allocator, 1); |
| |
| locations[0].Allocate(allocator); |
| fuchsia_shell::wire::NodeId fidl_node_id{.file_id = node_id.file_id, .node_id = node_id.node_id}; |
| locations[0].set_node_id(allocator, std::move(fidl_node_id)); |
| |
| auto result = service_->OnError(context->id(), std::move(locations), std::move(error_message)); |
| ZX_ASSERT(result.ok()); |
| context->set_has_errors(); |
| } |
| |
| void ServerInterpreter::DumpDone(ExecutionContext* context) { |
| FX_DCHECK(context != nullptr); |
| auto result = service_->OnDumpDone(context->id()); |
| ZX_ASSERT(result.ok()); |
| } |
| |
| void ServerInterpreter::ContextDone(ExecutionContext* context) { |
| FX_DCHECK(context != nullptr); |
| auto result = service_->OnExecutionDone(context->id(), fuchsia_shell::wire::ExecuteResult::kOk); |
| ZX_ASSERT(result.ok()); |
| } |
| |
| void ServerInterpreter::ContextDoneWithAnalysisError(ExecutionContext* context) { |
| FX_DCHECK(context != nullptr); |
| auto result = |
| service_->OnExecutionDone(context->id(), fuchsia_shell::wire::ExecuteResult::kAnalysisError); |
| ZX_ASSERT(result.ok()); |
| } |
| |
| void ServerInterpreter::ContextDoneWithExecutionError(ExecutionContext* context) { |
| FX_DCHECK(context != nullptr); |
| auto result = |
| service_->OnExecutionDone(context->id(), fuchsia_shell::wire::ExecuteResult::kExecutionError); |
| ZX_ASSERT(result.ok()); |
| } |
| |
| void ServerInterpreter::TextResult(ExecutionContext* context, std::string_view text) { |
| constexpr size_t kMaxResultSize = 65400; |
| size_t offset = 0; |
| while (text.size() - offset > kMaxResultSize) { |
| auto result = |
| service_->OnTextResult(context->id(), std::string(text.data() + offset, kMaxResultSize), |
| /*partial_result=*/true); |
| ZX_ASSERT(result.ok()); |
| offset += kMaxResultSize; |
| } |
| auto result = |
| service_->OnTextResult(context->id(), std::string(text.data() + offset, text.size() - offset), |
| /*partial_result=*/false); |
| ZX_ASSERT(result.ok()); |
| } |
| |
| void ServerInterpreter::Result(ExecutionContext* context, const Value& result) { |
| SerializeHelper helper; |
| helper.Set(result); |
| auto call_result = service_->OnResult(context->id(), helper.nodes(), false); |
| ZX_ASSERT(call_result.ok()); |
| } |
| |
| void ServerInterpreter::CreateServerContext(ExecutionContext* context) { |
| FX_DCHECK(contexts_.find(context->id()) == contexts_.end()); |
| contexts_.emplace(context->id(), std::make_unique<ServerInterpreterContext>(context)); |
| } |
| |
| void ServerInterpreter::AddExpression(ServerInterpreterContext* context, |
| std::unique_ptr<Expression> expression, bool root_node) { |
| if (root_node) { |
| EmitError(context->execution_context(), |
| "Node " + expression->StringId() + " can't be a root node."); |
| return; |
| } |
| context->AddExpression(std::move(expression)); |
| } |
| |
| void ServerInterpreter::AddInstruction(ServerInterpreterContext* context, |
| std::unique_ptr<Instruction> instruction, bool root_node) { |
| if (root_node) { |
| context->execution_context()->AddPendingInstruction(std::move(instruction)); |
| } else { |
| context->AddInstruction(std::move(instruction)); |
| } |
| } |
| |
| void ServerInterpreter::AddObjectSchema(ServerInterpreterContext* context, |
| std::shared_ptr<ObjectSchema> definition, bool root_node) { |
| if (root_node) { |
| EmitError(context->execution_context(), |
| "Node " + definition->StringId() + ": classes not implemented."); |
| } else { |
| context->execution_context()->AddObjectSchema(definition); |
| } |
| } |
| |
| void ServerInterpreter::AddObjectFieldSchema(ServerInterpreterContext* context, |
| std::shared_ptr<ObjectFieldSchema> definition, |
| bool root_node) { |
| if (root_node) { |
| EmitError(context->execution_context(), |
| "Node " + definition->StringId() + " can't be a root node."); |
| return; |
| } |
| context->AddObjectFieldSchema(definition); |
| } |
| |
| void ServerInterpreter::AddObjectField(ServerInterpreterContext* context, |
| std::unique_ptr<ObjectDeclarationField> definition, |
| bool root_node) { |
| if (root_node) { |
| EmitError(context->execution_context(), |
| "Node " + definition->StringId() + " can't be a root node."); |
| return; |
| } |
| context->AddObjectField(std::move(definition)); |
| } |
| |
| std::unique_ptr<Expression> ServerInterpreter::GetNullableExpression( |
| ServerInterpreterContext* context, const NodeId& node_id) { |
| if (node_id.node_id == 0) { |
| return nullptr; |
| } |
| auto result = context->GetExpression(node_id); |
| if (result == nullptr) { |
| EmitError(context->execution_context(), "Can't find node " + node_id.StringId()); |
| return nullptr; |
| } |
| return result; |
| } |
| |
| std::unique_ptr<Expression> ServerInterpreter::GetExpression(ServerInterpreterContext* context, |
| const NodeId& container_id, |
| const std::string& member, |
| const NodeId& node_id) { |
| if (node_id.node_id == 0) { |
| EmitError(context->execution_context(), container_id, member + " can't be null."); |
| return nullptr; |
| } |
| auto result = context->GetExpression(node_id); |
| if (result == nullptr) { |
| EmitError(context->execution_context(), container_id, |
| "Can't find node " + node_id.StringId() + " for " + member + "."); |
| return nullptr; |
| } |
| return result; |
| } |
| |
| std::shared_ptr<ObjectFieldSchema> ServerInterpreter::GetObjectFieldSchema( |
| ServerInterpreterContext* context, const NodeId& node_id) { |
| if (node_id.node_id == 0) { |
| return nullptr; |
| } |
| auto result = context->GetObjectFieldSchema(node_id); |
| if (result == nullptr) { |
| EmitError(context->execution_context(), "Can't find node " + node_id.StringId()); |
| return nullptr; |
| } |
| return result; |
| } |
| |
| // - connect --------------------------------------------------------------------------------------- |
| |
| void connect(void* untyped_context, const char* service_name, zx_handle_t service_request) { |
| auto server = static_cast<Server*>(untyped_context); |
| zx::channel sr(service_request); |
| fidl::ServerEnd<fuchsia_shell::Shell> sr_end(std::move(sr)); |
| server->IncomingConnection(std::move(sr_end)); |
| } |
| |
| // - Service --------------------------------------------------------------------------------------- |
| |
| Service::~Service() { |
| // If this |Service| object is destroyed before the |Server|, |
| // unregister it from the server. |
| if (server_) { |
| server_->ForgetService(this); |
| } |
| } |
| |
| void Service::OnServerShutdown() { |
| server_ = nullptr; |
| binding_.value().Unbind(); |
| } |
| |
| void Service::CreateExecutionContext(CreateExecutionContextRequestView request, |
| CreateExecutionContextCompleter::Sync& completer) { |
| auto context = interpreter_->AddContext(request->context_id); |
| if (context != nullptr) { |
| interpreter_->CreateServerContext(context); |
| } |
| } |
| |
| void Service::AddNodes(AddNodesRequestView request, AddNodesCompleter::Sync& _completer) { |
| auto context = interpreter_->GetServerContext(request->context_id); |
| if (context == nullptr) { |
| interpreter_->EmitError( |
| nullptr, "Execution context " + std::to_string(request->context_id) + " not defined."); |
| } else { |
| for (const auto& node : request->nodes) { |
| if (node.node.is_integer_literal()) { |
| AddIntegerLiteral(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.integer_literal(), node.root_node); |
| } else if (node.node.is_variable_definition()) { |
| AddVariableDefinition(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.variable_definition(), node.root_node); |
| } else if (node.node.is_object_schema()) { |
| AddObjectSchema(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.object_schema(), node.root_node); |
| } else if (node.node.is_field_schema()) { |
| AddObjectSchemaField(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.field_schema(), node.root_node); |
| } else if (node.node.is_object()) { |
| AddObject(context, node.node_id.file_id, node.node_id.node_id, node.node.object(), |
| node.root_node); |
| } else if (node.node.is_object_field()) { |
| AddObjectField(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.object_field(), node.root_node); |
| } else if (node.node.is_string_literal()) { |
| AddStringLiteral(context, node.node_id.file_id, node.node_id.node_id, |
| node.node.string_literal(), node.root_node); |
| } else if (node.node.is_variable()) { |
| AddVariable(context, node.node_id.file_id, node.node_id.node_id, node.node.variable(), |
| node.root_node); |
| } else if (node.node.is_emit_result()) { |
| AddEmitResult(context, node.node_id.file_id, node.node_id.node_id, node.node.emit_result(), |
| node.root_node); |
| } else if (node.node.is_assignment()) { |
| AddAssignment(context, node.node_id.file_id, node.node_id.node_id, node.node.assignment(), |
| node.root_node); |
| } else if (node.node.is_addition()) { |
| AddAddition(context, node.node_id.file_id, node.node_id.node_id, node.node.addition(), |
| node.root_node); |
| } else { |
| interpreter_->EmitError(context->execution_context(), |
| "Can't create node " + std::to_string(node.node_id.file_id) + ":" + |
| std::to_string(node.node_id.node_id) + " (unknown type)."); |
| } |
| } |
| } |
| } |
| |
| void Service::DumpExecutionContext(DumpExecutionContextRequestView request, |
| ExecuteExecutionContextCompleter::Sync& completer) { |
| auto context = interpreter_->GetServerContext(request->context_id); |
| if (context == nullptr) { |
| interpreter_->EmitError( |
| nullptr, "Execution context " + std::to_string(request->context_id) + " not defined."); |
| } else { |
| context->execution_context()->Dump(); |
| } |
| } |
| |
| void Service::ExecuteExecutionContext(ExecuteExecutionContextRequestView request, |
| ExecuteExecutionContextCompleter::Sync& completer) { |
| auto context = interpreter_->GetServerContext(request->context_id); |
| if (context == nullptr) { |
| interpreter_->EmitError( |
| nullptr, "Execution context " + std::to_string(request->context_id) + " not defined."); |
| } else { |
| if (context->PendingNodes()) { |
| interpreter_->EmitError( |
| context->execution_context(), |
| "Pending AST nodes for execution context " + std::to_string(request->context_id) + "."); |
| } |
| context->execution_context()->Execute(); |
| interpreter_->EraseServerContext(request->context_id); |
| } |
| } |
| |
| void Service::Shutdown(ShutdownRequestView request, ShutdownCompleter::Sync& completer) { |
| // Shutdown the interpreter. If we have some memory leaks, this will generate errors. |
| std::vector<std::string> errors; |
| interpreter_->Shutdown(&errors); |
| // Send the potential errors to the caller. |
| std::vector<fidl::StringView> error_view; |
| for (const auto& error : errors) { |
| error_view.emplace_back(fidl::StringView::FromExternal(error)); |
| } |
| completer.Reply(fidl::VectorView<fidl::StringView>::FromExternal(error_view)); |
| // Closes the handle which means that if the client sends a request |
| // after the shutdown, it will receive a ZX_ERR_PEER_CLOSED. |
| // This will also schedule the destruction of this |Service|. |
| binding().Unbind(); |
| } |
| |
| void Service::AddIntegerLiteral(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, |
| const fuchsia_shell::wire::IntegerLiteral& node, bool root_node) { |
| if (node.absolute_value.count() > 1) { |
| interpreter_->EmitError(context->execution_context(), |
| "Infinite precision integers not supported for node " + |
| std::to_string(node_file_id) + ":" + std::to_string(node_node_id)); |
| return; |
| } |
| uint64_t absolute_value = 0; |
| if (node.absolute_value.count() > 0) { |
| absolute_value = node.absolute_value[0]; |
| } |
| bool negative = node.negative && (absolute_value > 0); |
| auto result = std::make_unique<IntegerLiteral>(interpreter(), node_file_id, node_node_id, |
| absolute_value, negative); |
| interpreter_->AddExpression(context, std::move(result), root_node); |
| } |
| |
| void Service::AddObjectSchema(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, |
| const fuchsia_shell::wire::ObjectSchemaDefinition& node, |
| bool root_node) { |
| std::vector<std::shared_ptr<ObjectFieldSchema>> fields; |
| for (auto& field : node.fields) { |
| fields.push_back( |
| interpreter_->GetObjectFieldSchema(context, NodeId(field.file_id, field.node_id))); |
| } |
| auto definition = |
| std::make_shared<ObjectSchema>(interpreter(), node_file_id, node_node_id, std::move(fields)); |
| interpreter_->AddObjectSchema(context, definition, root_node); |
| } |
| |
| void Service::AddObjectSchemaField( |
| ServerInterpreterContext* context, uint64_t node_file_id, uint64_t node_node_id, |
| const fuchsia_shell::wire::ObjectFieldSchemaDefinition& field_type, bool root_node) { |
| auto definition = std::make_shared<ObjectFieldSchema>( |
| interpreter(), node_file_id, node_node_id, field_type.name.data(), |
| GetType(context, node_file_id, node_node_id, field_type.type)); |
| interpreter_->AddObjectFieldSchema(context, definition, root_node); |
| } |
| |
| void Service::AddObject(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const fuchsia_shell::wire::ObjectDefinition& node, |
| bool root_node) { |
| NodeId schema_node_id(node.object_schema.file_id, node.object_schema.node_id); |
| |
| std::shared_ptr<ObjectSchema> object_schema = |
| context->execution_context()->GetObjectSchema(schema_node_id); |
| if (object_schema == nullptr) { |
| interpreter_->EmitError(context->execution_context(), "Schema of object variable not defined"); |
| return; |
| } |
| |
| std::vector<std::unique_ptr<ObjectDeclarationField>> fields; |
| fields.reserve(node.fields.count()); |
| |
| for (auto& field : node.fields) { |
| NodeId field_id(field.file_id, field.node_id); |
| std::unique_ptr<ObjectDeclarationField> field_node = context->GetObjectField(field_id); |
| fields.emplace_back(std::move(field_node)); |
| } |
| |
| auto definition = std::make_unique<ObjectDeclaration>(interpreter(), node_file_id, node_node_id, |
| object_schema, std::move(fields)); |
| interpreter_->AddExpression(context, std::move(definition), root_node); |
| } |
| |
| void Service::AddObjectField(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, |
| const fuchsia_shell::wire::ObjectFieldDefinition& node, |
| bool root_node) { |
| NodeId schema_id(node.object_field_schema.file_id, node.object_field_schema.node_id); |
| std::shared_ptr<ObjectFieldSchema> field_schema = |
| interpreter_->GetObjectFieldSchema(context, schema_id); |
| NodeId value_id(node.value.file_id, node.value.node_id); |
| std::unique_ptr<Expression> value = interpreter_->GetExpression( |
| context, NodeId(node_file_id, node_node_id), "expression", value_id); |
| auto definition = std::make_unique<ObjectDeclarationField>( |
| interpreter(), node_file_id, node_node_id, field_schema, std::move(value)); |
| interpreter_->AddObjectField(context, std::move(definition), root_node); |
| } |
| |
| void Service::AddVariableDefinition(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, |
| const fuchsia_shell::wire::VariableDefinition& node, |
| bool root_node) { |
| std::unique_ptr<Expression> initial_value = interpreter_->GetNullableExpression( |
| context, NodeId(node.initial_value.file_id, node.initial_value.node_id)); |
| std::unique_ptr<Type> type = GetType(context, node_file_id, node_node_id, node.type); |
| if (type->IsUndefined()) { |
| interpreter_->EmitError(context->execution_context(), NodeId(node_file_id, node_node_id), |
| "Type not defined."); |
| return; |
| } |
| auto result = std::make_unique<VariableDefinition>(interpreter(), node_file_id, node_node_id, |
| GetView(node.name), std::move(type), |
| node.mutable_value, std::move(initial_value)); |
| interpreter_->AddInstruction(context, std::move(result), root_node); |
| } |
| |
| void Service::AddStringLiteral(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const ::fidl::StringView& node, |
| bool root_node) { |
| auto result = std::make_unique<StringLiteral>(interpreter(), node_file_id, node_node_id, |
| std::string_view(node.data(), node.size())); |
| interpreter_->AddExpression(context, std::move(result), root_node); |
| } |
| |
| void Service::AddVariable(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const fidl::StringView& name, bool root_node) { |
| auto result = std::make_unique<ExpressionVariable>(interpreter(), node_file_id, node_node_id, |
| std::string(name.data(), name.size())); |
| interpreter_->AddExpression(context, std::move(result), root_node); |
| } |
| |
| void Service::AddEmitResult(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const fuchsia_shell::wire::NodeId& node, |
| bool root_node) { |
| std::unique_ptr<Expression> expression = |
| interpreter_->GetExpression(context, NodeId(node_file_id, node_node_id), "expression", |
| NodeId(node.file_id, node.node_id)); |
| auto result = std::make_unique<EmitResult>(interpreter(), node_file_id, node_node_id, |
| std::move(expression)); |
| interpreter_->AddInstruction(context, std::move(result), root_node); |
| } |
| |
| void Service::AddAssignment(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const fuchsia_shell::wire::Assignment& node, |
| bool root_node) { |
| std::unique_ptr<Expression> destination = |
| interpreter_->GetExpression(context, NodeId(node_file_id, node_node_id), "destination", |
| NodeId(node.destination.file_id, node.destination.node_id)); |
| std::unique_ptr<Expression> source = |
| interpreter_->GetExpression(context, NodeId(node_file_id, node_node_id), "source", |
| NodeId(node.source.file_id, node.source.node_id)); |
| auto result = std::make_unique<Assignment>(interpreter(), node_file_id, node_node_id, |
| std::move(destination), std::move(source)); |
| interpreter_->AddInstruction(context, std::move(result), root_node); |
| } |
| |
| void Service::AddAddition(ServerInterpreterContext* context, uint64_t node_file_id, |
| uint64_t node_node_id, const fuchsia_shell::wire::Addition& node, |
| bool root_node) { |
| std::unique_ptr<Expression> left = |
| interpreter_->GetExpression(context, NodeId(node_file_id, node_node_id), "left", |
| NodeId(node.left.file_id, node.left.node_id)); |
| std::unique_ptr<Expression> right = |
| interpreter_->GetExpression(context, NodeId(node_file_id, node_node_id), "right", |
| NodeId(node.right.file_id, node.right.node_id)); |
| auto result = std::make_unique<Addition>(interpreter(), node_file_id, node_node_id, |
| node.with_exceptions, std::move(left), std::move(right)); |
| interpreter_->AddExpression(context, std::move(result), root_node); |
| } |
| |
| // - Server ---------------------------------------------------------------------------------------- |
| |
| Server::Server(async::Loop* loop) : loop_(loop) {} |
| |
| bool Server::Listen() { |
| zx_handle_t directory_request = zx_take_startup_handle(PA_DIRECTORY_REQUEST); |
| if (directory_request == ZX_HANDLE_INVALID) { |
| FX_LOGS(ERROR) << "error: directory_request was ZX_HANDLE_INVALID"; |
| return false; |
| } |
| |
| svc_dir_t* dir = nullptr; |
| zx_status_t status = svc_dir_create(loop()->dispatcher(), directory_request, &dir); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "error: svc_dir_create failed: " << status << " (" |
| << zx_status_get_string(status) << ")"; |
| return false; |
| } |
| |
| status = svc_dir_add_service(dir, "svc", "fuchsia.shell.Shell", this, connect); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "error: svc_dir_add_service failed: " << status << " (" |
| << zx_status_get_string(status) << ")" << std::endl; |
| return false; |
| } |
| return true; |
| } |
| |
| zx_status_t Server::IncomingConnection(fidl::ServerEnd<fuchsia_shell::Shell> service_request) { |
| auto service = std::make_unique<Service>(this); |
| auto* service_ptr = service.get(); |
| auto binding = |
| fidl::BindServer(loop()->dispatcher(), std::move(service_request), std::move(service)); |
| // Register the connection. |
| service_ptr->set_binding(std::move(binding)); |
| services_.emplace_back(service_ptr); |
| return ZX_OK; |
| } |
| |
| Server::~Server() { |
| for (auto& service : services_) { |
| service->OnServerShutdown(); |
| } |
| } |
| |
| } // namespace server |
| } // namespace interpreter |
| } // namespace shell |