Skip to content

Conversation

@AdamEther
Copy link

@AdamEther AdamEther commented May 30, 2025

Summary

This PR introduces step13_maroon_json, a Rust implementation of a stack-based virtual machine that executes JSON bytecode. The VM provides a portable, language-agnostic bytecode format for executing computational tasks with state management, timing control, and output capabilities.

What's New

  • JSON Bytecode VM: A complete stack machine implementation that executes JSON-formatted bytecode
  • Expression Evaluation: Support for arithmetic operations (mul, sub) and comparisons (le)
  • State Machine Architecture: Explicit state transitions with local variable management
  • Async Execution: Leverages Tokio for non-blocking sleep operations
  • Variable Interpolation: Dynamic text output with variable substitution

Technical Details

The VM implements a stack-based execution model with three core data types:

  • State entries for control flow
  • Retrn entries for function return addresses
  • Value entries for computational data

Supported operations:

  • push_stack - Push entries onto the execution stack
  • write - Output text with variable interpolation
  • sleep - Async delay with expression-based duration
  • conditional - Branching based on expression evaluation
  • return - Return computed values to caller
  • done - Terminate execution

Example

Running factorial(5) produces timed output showing the recursive execution:
0ms: f(5)
250ms: f(4)
450ms: f(3)
600ms: f(2)
700ms: f(1)
750ms: 5!=120

Architecture Benefits

  1. Portability: JSON bytecode can be generated and executed by any language
  2. Debuggability: Stack state and execution flow are explicit and inspectable
  3. Extensibility: New operations and expression types can be easily added
  4. Performance: Rust implementation with async/await for efficient execution

Files Added

  • step13_maroon_json/code/src/main.rs - VM implementation
  • step13_maroon_json/code/Cargo.toml - Rust dependencies
  • step13_maroon_json/README.md - Documentation
  • step13_maroon_json/run.sh - Execution script

Testing

cd step13_maroon_json && ./run.sh

This executes the factorial example from factorial_bytecode.json and demonstrates the VM's capabilities.

@AdamEther
Copy link
Author

@dkorolev please re-review it.

struct MaroonVM {
program: Program,
stack: Vec<StackEntry>,
local_vars: HashMap<String, u64>,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heap?

}

impl MaroonVM {
fn new(program: Program) -> Self {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need the initial state, and perhaps its arguments? So that the invalid states are not representable?


fn evaluate_expression(&self, expr: &Expression) -> u64 {
match expr {
Expression::Var { var } => *self.local_vars.get(var).unwrap_or(&0),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just .unwrap(), this _or(&0) doesn't look safe to me.

}

fn evaluate_stack_value(&self, value: &StackValue) -> u64 {
match value {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There got to be some visitor pattern for this in Rust, natively — no?

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());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me confused. Needs a comment or pls make it more self-descriptive, it's write-only as of now.

.context("Entry point function not found")?;

// Initialize stack with entry state
self.local_vars.insert("n".to_string(), initial_arg);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also making too many assumptions — just a u64, called "n". Need to find a way to do it cleaner, although the code most definitely LGTM.



// Update local variables based on state
if current_state_name.contains("PostRecursiveCall") && local_values.len() >= 2 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely a bug

let mut continue_to_next_iteration = false;
for op in &state_def.operations {
match &op.op_type[..] {
"push_stack" => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid this. Parse the JSON into a strongly typed object first pls.

let mut pushed_stack = false;
for exec_op in ops_to_execute {
match &exec_op.op_type[..] {
"return" => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This inner part looks redundant to me.

Copy link
Owner

@dkorolev dkorolev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

For this to be self-contained, perhaps present it as a command-line tool, which gets three inputs: path to the .json with the code, path to the .json with the "call spec", and the name of the function to execute?

Overall I'd say it's good to merge! And let's stop abusing the rust-experiments repo, it's about time =)

@AdamEther
Copy link
Author

Thanks for your time and looking into it!

For this to be self-contained, perhaps present it as a command-line tool, which gets three inputs: path to the .json with the code, path to the .json with the "call spec", and the name of the function to execute?

Sounds right to me.

Overall I'd say it's good to merge! And let's stop abusing the rust-experiments repo, it's about time =)

Noted with thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants