diff --git a/factorial_bytecode.json b/factorial_bytecode.json new file mode 100644 index 0000000..998d9fe --- /dev/null +++ b/factorial_bytecode.json @@ -0,0 +1,154 @@ +{ + "version": "1.0", + "functions": { + "factorial": { + "states": [ + { + "name": "FactorialEntry", + "local_vars": 1, + "operations": [ + { + "type": "push_stack", + "entries": [ + { + "Value": { + "FactorialInput": { + "var": "n" + } + } + }, + { + "Retrn": "FactorialDone" + }, + { + "Value": { + "FactorialArgument": { + "var": "n" + } + } + }, + { + "State": "FactorialRecursiveCall" + } + ] + } + ] + }, + { + "name": "FactorialRecursiveCall", + "local_vars": 1, + "operations": [ + { + "type": "write", + "text": "f({n})", + "next_state": "FactorialRecursionPostWrite" + } + ] + }, + { + "name": "FactorialRecursionPostWrite", + "local_vars": 1, + "operations": [ + { + "type": "sleep", + "ms": { + "mul": [ + { + "var": "n" + }, + { + "const": 50 + } + ] + }, + "next_state": "FactorialRecursionPostSleep" + } + ] + }, + { + "name": "FactorialRecursionPostSleep", + "local_vars": 1, + "operations": [ + { + "type": "conditional", + "condition": { + "le": [ + { + "var": "n" + }, + { + "const": 1 + } + ] + }, + "then": [ + { + "type": "return", + "value": { + "const": 1 + } + } + ], + "else": [ + { + "type": "push_stack", + "entries": [ + { + "Retrn": "FactorialRecursionPostRecursiveCall" + }, + { + "Value": { + "FactorialArgument": { + "sub": [ + { + "var": "n" + }, + { + "const": 1 + } + ] + } + } + }, + { + "State": "FactorialRecursiveCall" + } + ] + } + ] + } + ] + }, + { + "name": "FactorialRecursionPostRecursiveCall", + "local_vars": 2, + "operations": [ + { + "type": "return", + "value": { + "mul": [ + { + "var": "n" + }, + { + "var": "result" + } + ] + } + } + ] + }, + { + "name": "FactorialDone", + "local_vars": 2, + "operations": [ + { + "type": "done" + } + ] + } + ] + } + }, + "entry_point": "factorial" +} \ No newline at end of file diff --git a/maroon_bytecode_schema.json b/maroon_bytecode_schema.json new file mode 100644 index 0000000..7284dae --- /dev/null +++ b/maroon_bytecode_schema.json @@ -0,0 +1,243 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MaroonBytecode", + "description": "JSON bytecode format for Maroon stack machine", + "type": "object", + "required": ["version", "functions"], + "properties": { + "version": { + "type": "string", + "const": "1.0" + }, + "functions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Function" + } + }, + "entry_point": { + "type": "string", + "description": "Name of the entry function" + } + }, + "definitions": { + "Function": { + "type": "object", + "required": ["states"], + "properties": { + "states": { + "type": "array", + "items": { + "$ref": "#/definitions/State" + } + } + } + }, + "State": { + "type": "object", + "required": ["name", "local_vars", "operations"], + "properties": { + "name": { + "type": "string", + "description": "State name (e.g., FactorialEntry, FactorialRecursiveCall)" + }, + "local_vars": { + "type": "integer", + "minimum": 0, + "description": "Number of local variables on stack for this state" + }, + "operations": { + "type": "array", + "items": { + "$ref": "#/definitions/Operation" + } + } + } + }, + "Operation": { + "oneOf": [ + {"$ref": "#/definitions/PushStackOp"}, + {"$ref": "#/definitions/WriteOp"}, + {"$ref": "#/definitions/SleepOp"}, + {"$ref": "#/definitions/ReturnOp"}, + {"$ref": "#/definitions/ConditionalOp"}, + {"$ref": "#/definitions/DoneOp"} + ] + }, + "PushStackOp": { + "type": "object", + "required": ["type", "entries"], + "properties": { + "type": {"const": "push_stack"}, + "entries": { + "type": "array", + "items": {"$ref": "#/definitions/StackEntry"} + } + } + }, + "WriteOp": { + "type": "object", + "required": ["type", "text", "next_state"], + "properties": { + "type": {"const": "write"}, + "text": {"type": "string"}, + "next_state": {"type": "string"} + } + }, + "SleepOp": { + "type": "object", + "required": ["type", "ms", "next_state"], + "properties": { + "type": {"const": "sleep"}, + "ms": {"$ref": "#/definitions/Expression"}, + "next_state": {"type": "string"} + } + }, + "ReturnOp": { + "type": "object", + "required": ["type", "value"], + "properties": { + "type": {"const": "return"}, + "value": {"$ref": "#/definitions/Expression"} + } + }, + "ConditionalOp": { + "type": "object", + "required": ["type", "condition", "then", "else"], + "properties": { + "type": {"const": "conditional"}, + "condition": {"$ref": "#/definitions/Expression"}, + "then": { + "type": "array", + "items": {"$ref": "#/definitions/Operation"} + }, + "else": { + "type": "array", + "items": {"$ref": "#/definitions/Operation"} + } + } + }, + "DoneOp": { + "type": "object", + "required": ["type"], + "properties": { + "type": {"const": "done"} + } + }, + "StackEntry": { + "oneOf": [ + { + "type": "object", + "required": ["State"], + "properties": { + "State": {"type": "string"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["Retrn"], + "properties": { + "Retrn": {"type": "string"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["Value"], + "properties": { + "Value": {"$ref": "#/definitions/StackValue"} + }, + "additionalProperties": false + } + ] + }, + "StackValue": { + "oneOf": [ + { + "type": "object", + "required": ["FactorialInput"], + "properties": { + "FactorialInput": {"$ref": "#/definitions/Expression"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["FactorialArgument"], + "properties": { + "FactorialArgument": {"$ref": "#/definitions/Expression"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["FactorialReturnValue"], + "properties": { + "FactorialReturnValue": {"$ref": "#/definitions/Expression"} + }, + "additionalProperties": false + } + ] + }, + "Expression": { + "oneOf": [ + { + "type": "object", + "required": ["var"], + "properties": { + "var": {"type": "string"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["const"], + "properties": { + "const": {"type": "number"} + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["mul"], + "properties": { + "mul": { + "type": "array", + "items": {"$ref": "#/definitions/Expression"}, + "minItems": 2, + "maxItems": 2 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["sub"], + "properties": { + "sub": { + "type": "array", + "items": {"$ref": "#/definitions/Expression"}, + "minItems": 2, + "maxItems": 2 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["le"], + "properties": { + "le": { + "type": "array", + "items": {"$ref": "#/definitions/Expression"}, + "minItems": 2, + "maxItems": 2 + } + }, + "additionalProperties": false + } + ] + } + } +} \ No newline at end of file diff --git a/maroon_dsl_design.md b/maroon_dsl_design.md new file mode 100644 index 0000000..f620cdc --- /dev/null +++ b/maroon_dsl_design.md @@ -0,0 +1,203 @@ +# Maroon JSON Bytecode Design + +A stack machine architecture for executing computational tasks with state management, timing, and output capabilities. + +## JSON Bytecode Format + +The JSON bytecode directly represents stack machine operations: + +```json +{ + "version": "1.0", + "functions": { + "factorial": { + "states": [ + { + "name": "FactorialEntry", + "local_vars": 1, + "operations": [ + { + "type": "push_stack", + "entries": [ + {"Value": {"FactorialInput": {"var": "n"}}}, + {"Retrn": "FactorialDone"}, + {"Value": {"FactorialArgument": {"var": "n"}}}, + {"State": "FactorialRecursiveCall"} + ] + } + ] + }, + { + "name": "FactorialRecursiveCall", + "local_vars": 1, + "operations": [ + { + "type": "write", + "text": "f({n})", + "next_state": "FactorialRecursionPostWrite" + } + ] + }, + { + "name": "FactorialRecursionPostWrite", + "local_vars": 1, + "operations": [ + { + "type": "sleep", + "ms": {"mul": [{"var": "n"}, {"const": 50}]}, + "next_state": "FactorialRecursionPostSleep" + } + ] + }, + { + "name": "FactorialRecursionPostSleep", + "local_vars": 1, + "operations": [ + { + "type": "conditional", + "condition": {"le": [{"var": "n"}, {"const": 1}]}, + "then": [ + {"type": "return", "value": {"const": 1}} + ], + "else": [ + { + "type": "push_stack", + "entries": [ + {"Retrn": "FactorialRecursionPostRecursiveCall"}, + {"Value": {"FactorialArgument": {"sub": [{"var": "n"}, {"const": 1}]}}}, + {"State": "FactorialRecursiveCall"} + ] + } + ] + } + ] + }, + { + "name": "FactorialRecursionPostRecursiveCall", + "local_vars": 2, + "operations": [ + { + "type": "return", + "value": {"mul": [{"var": "n"}, {"var": "result"}]} + } + ] + }, + { + "name": "FactorialDone", + "local_vars": 2, + "operations": [ + { + "type": "done" + } + ] + } + ] + } + }, + "entry_point": "factorial" +} +``` + +## Stack Entry Types + +The stack machine uses three types of entries: + +```rust +enum StackEntry { + State(String), // Next state to execute + Retrn(String), // Return address + Value(StackValue), // Stack values +} + +enum StackValue { + FactorialInput(Expression), + FactorialArgument(Expression), + FactorialReturnValue(Expression), +} +``` + +## Stack Operations + +### Push Stack +```json +{ + "type": "push_stack", + "entries": [ + {"Value": {"FactorialArgument": {"var": "n"}}}, + {"State": "FactorialRecursiveCall"} + ] +} +``` + +### Write Operation +```json +{ + "type": "write", + "text": "f({n})", + "next_state": "FactorialRecursionPostWrite" +} +``` + +### Sleep Operation +```json +{ + "type": "sleep", + "ms": {"mul": [{"var": "n"}, {"const": 50}]}, + "next_state": "FactorialRecursionPostSleep" +} +``` + +### Conditional Operation +```json +{ + "type": "conditional", + "condition": {"le": [{"var": "n"}, {"const": 1}]}, + "then": [{"type": "return", "value": {"const": 1}}], + "else": [{"type": "push_stack", "entries": [...]}] +} +``` + +### Return Operation +```json +{ + "type": "return", + "value": {"mul": [{"var": "n"}, {"var": "result"}]} +} +``` + +## Expression Evaluation + +Expressions in JSON support arithmetic and comparison operations: + +```json +// Variable reference +{"var": "n"} + +// Constant +{"const": 1} + +// Arithmetic +{"mul": [{"var": "n"}, {"const": 50}]} +{"sub": [{"var": "n"}, {"const": 1}]} + +// Comparison +{"le": [{"var": "n"}, {"const": 1}]} +``` + +## VM Implementation + +The JSON bytecode is executed by the Rust VM implementation: + +**Rust VM** (`step13_maroon_json/`) - High-performance async execution with: +- Complete stack machine implementation +- Expression evaluation for arithmetic and comparisons +- Support for all bytecode operations +- Async/await for sleep operations + +## Benefits + +1. **Language-agnostic**: JSON bytecode can be executed by any language +2. **Debugging**: Stack state is explicit and inspectable +3. **Performance**: Optimized Rust implementation with async execution +4. **Extensibility**: New operations can be added to the bytecode format +5. **Portability**: JSON format works across platforms and architectures \ No newline at end of file diff --git a/maroon_dsl_summary.md b/maroon_dsl_summary.md new file mode 100644 index 0000000..d345d4d --- /dev/null +++ b/maroon_dsl_summary.md @@ -0,0 +1,68 @@ +# Maroon JSON VM Implementation Summary + +## Overview + +A stack machine implementation that executes JSON bytecode for computational tasks with state management, timing, and output capabilities. + +## Components + +### 1. **JSON Bytecode Format** (`maroon_dsl_design.md`) +- Stack-based execution model with states and operations +- Direct representation of stack machine operations in JSON +- Supports control flow, recursion, and timed execution + +### 2. **JSON Schema** (`maroon_bytecode_schema.json`) +- Formal JSON Schema that validates bytecode structure +- Defines stack entry types: + - `State` - Next state to execute + - `Retrn` - Return address for function calls + - `Value` - Stack values with typed expressions + +### 3. **Rust VM** (`step13_maroon_json/`) +- High-performance async executor for JSON bytecode +- Implements complete stack machine with local variables +- Supports operations: push_stack, write, sleep, conditional, return, done +- Expression evaluation for arithmetic and comparisons + +## Execution Model + +``` +JSON Bytecode → [Rust VM] → Output +``` + +## Stack Operations + +- **push_stack**: Push entries onto the execution stack +- **write**: Output text with variable interpolation +- **sleep**: Delay execution for specified milliseconds +- **conditional**: Branch based on expression evaluation +- **return**: Return value to caller +- **done**: Complete execution + +## Example Output + +Running factorial(5): +``` +0ms: f(5) +250ms: f(4) +450ms: f(3) +600ms: f(2) +700ms: f(1) +750ms: 5!=120 +``` + +## Key Benefits + +1. **Language-agnostic**: JSON bytecode can be executed by any language +2. **Debuggable**: Stack state and execution flow are explicit +3. **Performance**: Optimized Rust implementation with async execution +4. **Extensible**: Easy to add new operations or expression types +5. **Portability**: JSON format works across platforms and architectures + +## Testing + +Run the Rust VM implementation: +```bash +cd step13_maroon_json +./run.sh +``` \ No newline at end of file diff --git a/step13_maroon_json/README.md b/step13_maroon_json/README.md new file mode 100644 index 0000000..734cc85 --- /dev/null +++ b/step13_maroon_json/README.md @@ -0,0 +1,40 @@ +# Maroon JSON Executor + +This step implements a JSON bytecode executor for the Maroon stack machine. + +## Components + +1. **JSON Bytecode Format**: Executes the JSON format defined in `maroon_bytecode_schema.json` +2. **Stack Machine**: Implements the same stack-based execution model as the PR +3. **Expression Evaluation**: Supports arithmetic and comparison operations + +## Running + +```bash +# Build the executor +cd code +cargo build --release + +# Run factorial(5) from JSON bytecode +cargo run --release ../../factorial_bytecode.json 5 +``` + +## Stack Machine Operations + +- **push_stack**: Push entries onto the stack +- **write**: Output text with variable interpolation +- **sleep**: Delay execution +- **conditional**: Branch based on condition +- **return**: Return value to caller +- **done**: Complete execution + +## Example Output + +``` +0ms: f(5) +250ms: f(4) +450ms: f(3) +600ms: f(2) +700ms: f(1) +750ms: 5!=120 +``` \ No newline at end of file diff --git a/step13_maroon_json/code/Cargo.toml b/step13_maroon_json/code/Cargo.toml new file mode 100644 index 0000000..5788869 --- /dev/null +++ b/step13_maroon_json/code/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "maroon_json_executor" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1", features = ["full"] } +anyhow = "1.0" \ No newline at end of file diff --git a/step13_maroon_json/code/src/main.rs b/step13_maroon_json/code/src/main.rs new file mode 100644 index 0000000..2533be1 --- /dev/null +++ b/step13_maroon_json/code/src/main.rs @@ -0,0 +1,324 @@ +use anyhow::{Context, Result}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::env; +use std::fs; +use tokio::time::{sleep, Duration}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +enum StackEntry { + State { #[serde(rename = "State")] state: String }, + Retrn { #[serde(rename = "Retrn")] retrn: String }, + Value { #[serde(rename = "Value")] value: StackValue }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +enum StackValue { + FactorialInput { #[serde(rename = "FactorialInput")] input: Expression }, + FactorialArgument { #[serde(rename = "FactorialArgument")] arg: Expression }, + FactorialReturnValue { #[serde(rename = "FactorialReturnValue")] ret: Expression }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +enum Expression { + Var { var: String }, + Const { #[serde(rename = "const")] value: u64 }, + Mul { mul: Vec }, + Sub { sub: Vec }, + Le { le: Vec }, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Operation { + #[serde(rename = "type")] + op_type: String, + #[serde(flatten)] + data: OperationData, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum OperationData { + PushStack { entries: Vec }, + Write { text: String, next_state: String }, + Sleep { ms: Expression, next_state: String }, + Return { value: Expression }, + Conditional { condition: Expression, then: Vec, #[serde(rename = "else")] else_ops: Vec }, + Done {}, +} + +#[derive(Debug, Serialize, Deserialize)] +struct State { + name: String, + local_vars: usize, + operations: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Function { + states: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Program { + version: String, + functions: HashMap, + entry_point: String, +} + +#[derive(Debug)] +struct MaroonVM { + program: Program, + stack: Vec, + local_vars: HashMap, + current_time: u64, +} + +impl MaroonVM { + fn new(program: Program) -> Self { + Self { + program, + stack: Vec::new(), + local_vars: HashMap::new(), + current_time: 0, + } + } + + fn evaluate_expression(&self, expr: &Expression) -> u64 { + match expr { + Expression::Var { var } => *self.local_vars.get(var).unwrap_or(&0), + Expression::Const { value } => *value, + Expression::Mul { mul } => { + let a = self.evaluate_expression(&mul[0]); + let b = self.evaluate_expression(&mul[1]); + a * b + } + Expression::Sub { sub } => { + let a = self.evaluate_expression(&sub[0]); + let b = self.evaluate_expression(&sub[1]); + a - b + } + Expression::Le { le } => { + let a = self.evaluate_expression(&le[0]); + let b = self.evaluate_expression(&le[1]); + if a <= b { 1 } else { 0 } + } + } + } + + fn evaluate_stack_value(&self, value: &StackValue) -> u64 { + match value { + StackValue::FactorialInput { input } => self.evaluate_expression(input), + StackValue::FactorialArgument { arg } => self.evaluate_expression(arg), + StackValue::FactorialReturnValue { ret } => self.evaluate_expression(ret), + } + } + + fn interpolate_text(&self, text: &str) -> String { + let mut result = text.to_string(); + for (var, value) in &self.local_vars { + result = result.replace(&format!("{{{}}}", var), &value.to_string()); + } + result + } + + async fn execute(&mut self, initial_arg: u64) -> Result<()> { + let entry_func = self.program.functions.get(&self.program.entry_point) + .context("Entry point function not found")?; + + // Initialize stack with entry state + self.local_vars.insert("n".to_string(), initial_arg); + self.stack.push(StackEntry::Value { + value: StackValue::FactorialInput { input: Expression::Const { value: initial_arg } } + }); + self.stack.push(StackEntry::State { state: "FactorialEntry".to_string() }); + + while !self.stack.is_empty() { + // Pop current state + let current_entry = self.stack.pop().unwrap(); + let current_state_name = match current_entry { + StackEntry::State { state } => state, + _ => panic!("Expected state on top of stack, got {:?}", current_entry), + }; + + + // Find the state definition + let state_def = entry_func.states.iter() + .find(|s| s.name == current_state_name) + .context("State not found")?; + + // Pop local variables from stack + let mut local_values = Vec::new(); + for _ in 0..state_def.local_vars { + if let Some(StackEntry::Value { value }) = self.stack.pop() { + local_values.push(self.evaluate_stack_value(&value)); + } + } + + + // Update local variables based on state + if current_state_name.contains("PostRecursiveCall") && local_values.len() >= 2 { + // local_values[0] is the return value (result), local_values[1] is the saved n + self.local_vars.insert("result".to_string(), local_values[0]); + self.local_vars.insert("n".to_string(), local_values[1]); + } else if (current_state_name == "FactorialRecursiveCall" || + current_state_name.contains("Post") || + current_state_name.contains("Argument")) && !local_values.is_empty() { + self.local_vars.insert("n".to_string(), local_values[0]); + } + + + // Execute operations + let mut continue_to_next_iteration = false; + for op in &state_def.operations { + match &op.op_type[..] { + "push_stack" => { + if let OperationData::PushStack { entries } = &op.data { + for entry in entries { + self.stack.push(entry.clone()); + } + // After push_stack in states like FactorialEntry, we should continue + // to the next iteration of the main loop + continue_to_next_iteration = true; + break; + } + } + "write" => { + if let OperationData::Write { text, next_state } = &op.data { + let output = self.interpolate_text(text); + println!("{}ms: {}", self.current_time, output); + + // Push local vars back + for &val in local_values.iter().rev() { + self.stack.push(StackEntry::Value { + value: StackValue::FactorialArgument { arg: Expression::Const { value: val } } + }); + } + self.stack.push(StackEntry::State { state: next_state.clone() }); + break; // Exit the operations loop + } + } + "sleep" => { + if let OperationData::Sleep { ms, next_state } = &op.data { + let sleep_ms = self.evaluate_expression(ms); + sleep(Duration::from_millis(sleep_ms)).await; + self.current_time += sleep_ms; + + // Push local vars back + for &val in local_values.iter().rev() { + self.stack.push(StackEntry::Value { + value: StackValue::FactorialArgument { arg: Expression::Const { value: val } } + }); + } + self.stack.push(StackEntry::State { state: next_state.clone() }); + break; // Exit the operations loop + } + } + "conditional" => { + if let OperationData::Conditional { condition, then, else_ops } = &op.data { + let cond_value = self.evaluate_expression(condition); + let ops_to_execute = if cond_value != 0 { then } else { else_ops }; + + let mut pushed_stack = false; + for exec_op in ops_to_execute { + match &exec_op.op_type[..] { + "return" => { + if let OperationData::Return { value } = &exec_op.data { + let ret_value = self.evaluate_expression(value); + + // Pop return address + if let Some(StackEntry::Retrn { retrn }) = self.stack.pop() { + self.stack.push(StackEntry::Value { + value: StackValue::FactorialReturnValue { + ret: Expression::Const { value: ret_value } + } + }); + self.stack.push(StackEntry::State { state: retrn }); + } + } + } + "push_stack" => { + if let OperationData::PushStack { entries } = &exec_op.data { + // First push back the local values to preserve them + for &val in local_values.iter().rev() { + self.stack.push(StackEntry::Value { + value: StackValue::FactorialArgument { arg: Expression::Const { value: val } } + }); + } + // Then push the new entries + for entry in entries { + self.stack.push(entry.clone()); + } + pushed_stack = true; + } + } + _ => {} + } + } + + if pushed_stack { + continue_to_next_iteration = true; + break; + } + } + } + "return" => { + if let OperationData::Return { value } = &op.data { + let ret_value = self.evaluate_expression(value); + + // Pop return address + if let Some(StackEntry::Retrn { retrn }) = self.stack.pop() { + self.stack.push(StackEntry::Value { + value: StackValue::FactorialReturnValue { + ret: Expression::Const { value: ret_value } + } + }); + self.stack.push(StackEntry::State { state: retrn }); + } + } + } + "done" => { + if local_values.len() >= 2 { + println!("{}ms: {}!={}", self.current_time, initial_arg, local_values[0]); + } + return Ok(()); + } + _ => {} + } + } + + // If we set the flag to continue, skip to the next iteration + if continue_to_next_iteration { + continue; + } + } + + Ok(()) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let args: Vec = env::args().collect(); + if args.len() != 3 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } + + let bytecode_file = &args[1]; + let n: u64 = args[2].parse().context("Invalid number")?; + + let json_content = fs::read_to_string(bytecode_file) + .context("Failed to read bytecode file")?; + + let program: Program = serde_json::from_str(&json_content) + .context("Failed to parse bytecode")?; + + let mut vm = MaroonVM::new(program); + vm.execute(n).await?; + + Ok(()) +} \ No newline at end of file diff --git a/step13_maroon_json/factorial_bytecode.json b/step13_maroon_json/factorial_bytecode.json new file mode 100644 index 0000000..998d9fe --- /dev/null +++ b/step13_maroon_json/factorial_bytecode.json @@ -0,0 +1,154 @@ +{ + "version": "1.0", + "functions": { + "factorial": { + "states": [ + { + "name": "FactorialEntry", + "local_vars": 1, + "operations": [ + { + "type": "push_stack", + "entries": [ + { + "Value": { + "FactorialInput": { + "var": "n" + } + } + }, + { + "Retrn": "FactorialDone" + }, + { + "Value": { + "FactorialArgument": { + "var": "n" + } + } + }, + { + "State": "FactorialRecursiveCall" + } + ] + } + ] + }, + { + "name": "FactorialRecursiveCall", + "local_vars": 1, + "operations": [ + { + "type": "write", + "text": "f({n})", + "next_state": "FactorialRecursionPostWrite" + } + ] + }, + { + "name": "FactorialRecursionPostWrite", + "local_vars": 1, + "operations": [ + { + "type": "sleep", + "ms": { + "mul": [ + { + "var": "n" + }, + { + "const": 50 + } + ] + }, + "next_state": "FactorialRecursionPostSleep" + } + ] + }, + { + "name": "FactorialRecursionPostSleep", + "local_vars": 1, + "operations": [ + { + "type": "conditional", + "condition": { + "le": [ + { + "var": "n" + }, + { + "const": 1 + } + ] + }, + "then": [ + { + "type": "return", + "value": { + "const": 1 + } + } + ], + "else": [ + { + "type": "push_stack", + "entries": [ + { + "Retrn": "FactorialRecursionPostRecursiveCall" + }, + { + "Value": { + "FactorialArgument": { + "sub": [ + { + "var": "n" + }, + { + "const": 1 + } + ] + } + } + }, + { + "State": "FactorialRecursiveCall" + } + ] + } + ] + } + ] + }, + { + "name": "FactorialRecursionPostRecursiveCall", + "local_vars": 2, + "operations": [ + { + "type": "return", + "value": { + "mul": [ + { + "var": "n" + }, + { + "var": "result" + } + ] + } + } + ] + }, + { + "name": "FactorialDone", + "local_vars": 2, + "operations": [ + { + "type": "done" + } + ] + } + ] + } + }, + "entry_point": "factorial" +} \ No newline at end of file diff --git a/step13_maroon_json/run.sh b/step13_maroon_json/run.sh new file mode 100755 index 0000000..e90fe6f --- /dev/null +++ b/step13_maroon_json/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +echo "Building Maroon JSON executor..." +cd code +cargo build --release + +echo -e "\nCopying bytecode file..." +cp ../../../factorial_bytecode.json . + +echo -e "\nExecuting factorial(5) from JSON bytecode:" +cargo run --release factorial_bytecode.json 5 \ No newline at end of file