| // 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. |
| type ExecuteResult = strict enum : 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. |
| type NodeId = struct { |
| /// The id of the file. |
| file_id uint64; |
| /// The id of the node for that file. |
| node_id uint64; |
| }; |
| |
| /// Defines a Location for an error. |
| type Location = table { |
| /// Defined for error relative to an AST node. For native methods, this is not defined. |
| 1: node_id NodeId; |
| }; |
| |
| /// Defines the builtin types. |
| type BuiltinType = strict enum : 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. |
| type ObjectFieldSchemaDefinition = struct { |
| /// The type of the field. |
| type ShellType; |
| /// The name of the field. |
| name string:MAX; |
| }; |
| |
| type ObjectSchemaDefinition = struct { |
| fields vector<NodeId>:MAX; |
| }; |
| |
| /// Defines a type used by the shell. |
| type ShellType = strict union { |
| /// Undefined type (can be used when the type can be inferred). |
| 1: undef bool; |
| /// A builtin type. |
| 2: builtin_type BuiltinType; |
| /// The NodeId corresponding to an object schema. |
| 3: object_schema NodeId; |
| }; |
| |
| /// Defines an integer value. |
| type IntegerLiteral = struct { |
| /// The absolute value of the value. The first value in the vector is the less significant 64 |
| /// bits. |
| absolute_value vector<uint64>:MAX; |
| /// If true, the value is negative (-absolute_value). |
| /// There is no negative zero. That means that, for zero, negative should be false. |
| negative bool; |
| }; |
| |
| type ObjectFieldDefinition = struct { |
| /// The schema of this field. |
| object_field_schema NodeId; |
| /// The nodeid containing the value of this field. |
| value NodeId; |
| }; |
| |
| /// Defines an object value. |
| type ObjectDefinition = struct { |
| /// A list of nodes of type ObjectFieldDefinition corresponding to the fields of this object. |
| fields vector<NodeId>:MAX; |
| // A node of type ObjectSchemaDefinition corresponding to the type of this object. |
| object_schema NodeId; |
| }; |
| |
| /// Defines a variable. |
| type VariableDefinition = struct { |
| /// The name of the variable. |
| name string:MAX; |
| /// The type of the variable. |
| type ShellType; |
| /// True if the variable can be modified afterward. |
| mutable_value bool; |
| /// The node which defines the initial value. |
| initial_value NodeId; |
| }; |
| |
| /// Defines an assignment. |
| type Assignment = struct { |
| /// The destination. It must be a L Value. |
| destination NodeId; |
| /// The source. It's an expression. |
| source NodeId; |
| }; |
| |
| /// Defines an addition. |
| type Addition = struct { |
| /// Throws an exception if we have an overflow or an underflow. |
| with_exceptions bool; |
| /// Left term. |
| left NodeId; |
| /// Right term. |
| right NodeId; |
| }; |
| |
| /// Defines a node (expression, instruction, ...). |
| type Node = strict union { |
| /// An integer value. |
| 1: integer_literal IntegerLiteral; |
| /// A variable. |
| 2: variable_definition VariableDefinition; |
| // A schema definition. |
| 3: object_schema ObjectSchemaDefinition; |
| // A field schema definition |
| 4: field_schema ObjectFieldSchemaDefinition; |
| // An object definition. |
| 5: object ObjectDefinition; |
| // A object field definition |
| 6: object_field ObjectFieldDefinition; |
| /// A string value. |
| 7: string_literal string:MAX; |
| /// The value of a previously defined variable. It refers to a previously created variable |
| /// definition using its name. |
| 8: variable string:MAX; |
| /// Emits a result. The value of the expression is sent back to the client using OnResult. |
| 9: emit_result NodeId; |
| /// 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. |
| type NodeDefinition = struct { |
| /// Id of the node. |
| node_id NodeId; |
| /// 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. |
| root_node bool; |
| }; |
| |
| /// 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(struct { |
| context_id uint64; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| nodes vector<NodeDefinition>:MAX; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| }); |
| |
| /// 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() -> (struct { |
| errors vector<string:MAX>:MAX; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| locations vector<Location>:MAX; |
| error_message string:MAX; |
| }); |
| |
| /// Signals that the shell has dumped all the pending instructions. |
| /// |
| /// - `context_id` the execution context id. |
| -> OnDumpDone(struct { |
| context_id uint64; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| result ExecuteResult; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| result string:MAX; |
| partial_result bool; |
| }); |
| |
| /// 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(struct { |
| context_id uint64; |
| nodes vector<Node>:MAX; |
| partial_result bool; |
| }); |
| }; |