blob: 7264ec499dcd9acab9ca16d076843d7b5a348fea [file] [log] [blame]
// 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.
library fuchsia.shell;
/// Result of a ExecutePendingInstructions.
enum ExecuteResult : uint32 {
/// Only used for fields. This will never be used by ExecutePedningInstructions.
UNDEF = 0;
/// Execution finished without error.
OK = 1;
/// Execution finished with errors during the execution.
EXECUTION_ERROR = 2;
/// Execution finished with errors during the semantic/analysis passes.
ANALYSIS_ERROR = 3;
};
/// Defines a unique identifier for an AST node.
struct NodeId {
/// The id of the file.
uint64 file_id;
/// The id of the node for that file.
uint64 node_id;
};
/// Defines a Location for an error.
table Location {
/// Defined for error relative to an AST node. For native methods, this is not defined.
1: NodeId node_id;
};
/// Defines the builtin types.
enum BuiltinType : uint32 {
/// A Boolean (true/false).
BOOL = 0;
/// An unicode character.
CHAR = 1;
/// A UTF8 string.
STRING = 2;
/// 8 bit signed integer.
INT8 = 3;
/// 8 bit unsigned integer.
UINT8 = 4;
/// 16 bit signed integer.
INT16 = 5;
/// 16 bit unsigned integer.
UINT16 = 6;
/// 32 bit signed integer.
INT32 = 7;
/// 32 bit unsigned integer.
UINT32 = 8;
/// 64 bit signed integer.
INT64 = 9;
/// 64 bit unsigned integer.
UINT64 = 10;
/// Infinite precision integer (signed).
INTEGER = 11;
/// 32 bit floating-point.
FLOAT32 = 12;
/// 64 bit floating-point.
FLOAT64 = 13;
};
/// A definition of a field of an object.
struct ObjectFieldSchemaDefinition {
/// The type of the field.
ShellType type;
/// The name of the field.
string:MAX name;
};
struct ObjectSchemaDefinition {
vector<NodeId>:MAX fields;
};
/// Defines a type used by the shell.
union ShellType {
/// Undefined type (can be used when the type can be inferred).
1: bool undef;
/// A builtin type.
2: BuiltinType builtin_type;
/// The NodeId corresponding to an object schema.
3: NodeId object_schema;
};
/// Defines an integer value.
struct IntegerLiteral {
/// The absolute value of the value. The first value in the vector is the less significant 64
/// bits.
vector<uint64>:MAX absolute_value;
/// If true, the value is negative (-absolute_value).
/// There is no negative zero. That means that, for zero, negative should be false.
bool negative;
};
struct ObjectFieldDefinition {
/// The schema of this field.
NodeId object_field_schema;
/// The nodeid containing the value of this field.
NodeId value;
};
/// Defines an object value.
struct ObjectDefinition {
/// A list of nodes of type ObjectFieldDefinition corresponding to the fields of this object.
vector<NodeId>:MAX fields;
// A node of type ObjectSchemaDefinition corresponding to the type of this object.
NodeId object_schema;
};
/// Defines a variable.
struct VariableDefinition {
/// The name of the variable.
string:MAX name;
/// The type of the variable.
ShellType type;
/// True if the variable can be modified afterward.
bool mutable_value;
/// The node which defines the initial value.
NodeId initial_value;
};
/// Defines an assignment.
struct Assignment {
/// The destination. It must be a L Value.
NodeId destination;
/// The source. It's an expression.
NodeId source;
};
/// Defines an addition.
struct Addition {
/// Throws an exception if we have an overflow or an underflow.
bool with_exceptions;
/// Left term.
NodeId left;
/// Right term.
NodeId right;
};
/// Defines a node (expression, instruction, ...).
union Node {
/// An integer value.
1: IntegerLiteral integer_literal;
/// A variable.
2: VariableDefinition variable_definition;
// A schema definition.
3: ObjectSchemaDefinition object_schema;
// A field schema definition
4: ObjectFieldSchemaDefinition field_schema;
// An object definition.
5: ObjectDefinition object;
// A object field definition
6: ObjectFieldDefinition object_field;
/// A string value.
7: string:MAX string_literal;
/// The value of a previously defined variable. It refers to a previously created variable
/// definition using its name.
8: string:MAX variable;
/// Emits a result. The value of the expression is sent back to the client using OnResult.
9: NodeId emit_result;
/// Assign an expression (L Value) with the computed value of another expression.
10: Assignment assignment;
/// An addition.
11: Addition addition;
};
/// Defines a node which has to be inserted in the AST. The node will stay pending until it is used
/// by another node.
struct NodeDefinition {
/// Id of the node.
NodeId node_id;
/// The node to be defined.
Node node;
/// If true, instruction nodes are added to the context's pending instructions and other nodes
/// are added to the interpreter AST.
///
/// For instructions, root_node true means that instructions have to be executed immediately
/// (in fact when ExecuteExecutionContext will be called).
///
/// For other nodes (namespaces, classes, functions, globals) root_node true means that the
/// node is directly attached to the AST root node. Root nodes stay alive across multiple
/// executions. They are available each time ExecuteExecutionContext is called even if they
/// have been defined before another call of ExecuteExecutionContext.
///
/// When root_node is false, the node is pending and must be used by another node before
/// ExecuteExecutionContext is called.
bool root_node;
};
/// Defines the protocol to communicate with a shell interpreter.
[Discoverable]
protocol Shell {
/// Creates an execution context. An execution context can be a very small chunk of code.
/// For example, with a command line interface for which the user types an instruction and
/// then hits enter, each instruction will be in it's own execution context. However, they all
/// share the same isolate which stores globals. Each global variable definition in an
/// execution context is created at the isolate level (and, therefore, accessible from other
/// execution context).
///
/// - `context_id` the id for the context. This id is provided by the client which must ensure
/// that the id is unique. A context_id can be reused as soon as OnExecutionDone is
/// received.
CreateExecutionContext(uint64 context_id);
/// Adds nodes to the AST. This message can be used several time to build an AST.
///
/// - `context_id` the id for the execution context. Instructions without a container are
/// added to the context's pending instructions. All other nodes without a container are
/// added to the interpreter AST.
/// - `nodes` all the node to be inserted. Children must be inserted before their container.
/// That means that you should do a depth first traversal of your graph to generate these
/// calls.
AddNodes(uint64 context_id, vector<NodeDefinition>:MAX nodes);
/// Dumps all the pending instructions. This generates an OnTextResult event for each pending
/// instruction with a brief description of that instruction.
/// When everything is dumped, OnDumpDone is called. Only the instructions successfully added
/// are dumped.
///
/// - `context_id` the id for the execution context previously created with
/// CreateExecutionContext.
DumpExecutionContext(uint64 context_id);
/// Executes all the pending instructions. This can generate one or several errors using
/// OnError.
/// When the execution is finished (all the pending instructions have been handled),
/// OnExecutionDone is called.
/// This will execute all the instructions added to the execution context is received.
/// It is illegal to add more instructions once this function has been called.
/// If you need to execute more instructions, you need to create another execution context.
///
/// - `context_id` the id for the execution context previously created with
/// CreateExecutionContext.
ExecuteExecutionContext(uint64 context_id);
/// Delete the current interpreter. The server will close the other side of the channel.
///
/// - `errors` all the errors found by the interpreter during the shutdown (it should be
/// empty).
Shutdown() -> (vector<string:MAX>:MAX errors);
/// Called each time the shell detects an error. This method can be called several times.
/// The execution is done (started with ExecuteExecutionContext) when OnExecutionDone is
/// received by the client.
///
/// - `context_id` when the error is generated by an execution context, the id of the context.
/// Zero otherwise.
/// - `locations`
/// For runtime errors, this is the stack frame (inner location first).
/// For semantic errors, this is the location of the error (only one item).
/// For global errors (not relative to a file), this is empty.
/// - `error_message` the text message for the error.
-> OnError(uint64 context_id, vector<Location>:MAX locations, string:MAX error_message);
/// Signals that the shell has dumped all the pending instructions.
///
/// - `context_id` the execution context id.
-> OnDumpDone(uint64 context_id);
/// Signals that the shell has handled all the pending instructions.
/// This will be called exactly once when the ExecutionContext is completely finished (the
/// execution starts when ExecuteExecutionContext is received).
/// Once this event is called, the execution context is destroyed.
///
/// - `context_id` the execution context id.
/// - `result` the result of the execution.
-> OnExecutionDone(uint64 context_id, ExecuteResult result);
/// Called when an execution context has a textual result. If the result is too big to fit
/// into one message, this event is called several times.
/// This method is temporary. We will define something more powerful later (streams like stdio,
/// typed results, ...).
/// This method can be called several times.
/// The execution is done (started with ExecuteExecutionContext) when OnExecutionDone is
/// received by the client.
///
/// - `context_id` the execution context id.
/// - `result` the text of the result.
/// - `partial_result` if true, the result is partial and at least one other event will be
/// called. All the results must be concatenated to reconstruct the original text.
-> OnTextResult(uint64 context_id, string:MAX result, bool partial_result);
/// Called when an execution context has a result (emit_result instruction). If the result is
/// too big to fit into one message, this event is called several times.
/// This event can be called several times for one context if several emit_result instructions
/// are used.
///
/// - `context_id` the execution context id.
/// - `nodes` the nodes of the result. The last node of OnResult for which partial_result is
/// false is the root node which defines the result (all the other nodes are children of
/// this node). All nodes are implicitly numbered starting at one for the first node in the
/// vector.
/// - `partial_result` if true, the result is partial and at least one other event will be
/// called. All the nodes must be used to reconstruct the original value.
-> OnResult(uint64 context_id, vector<Node>:MAX nodes, bool partial_result);
};