egglang

Crates.ioegglang
lib.rsegglang
version0.3.3
sourcesrc
created_at2022-11-15 21:52:40.849839
updated_at2024-09-19 13:13:24.074518
descriptionThe Egg Programming Language From Eloquent JavaScript, but in Rust
homepage
repositoryhttps://github.com/sokorototo/egglang
max_upload_size
id715971
size63,376
Newton Toto (sokorototo)

documentation

https://docs.rs/egglang

README

A Rust implementation of the Egg Programming Language

Crate Version on Crates.io docs.rs
GitHub GitHub issues

Docs | Repo

egg is a toy Programming Language from the book Eloquent Javascript by Marijn Haverbeke, Chapter 12. The Book was pivotal to my early Programming journey. I moved to Rust some time back and in a fit of nostalgia I decided to rewrite egg in Rust.

✨ Features

  • Extensive and Modular standard library; Core, Objects, StringTools, Console and Functions

  • Effective Scope Chain: Local Variables and Global Variables work as expected.

  • User-Defined Functions: Create functions in Egg using the fn keyword.

  • Higher Order Functions: Pass functions as values to other functions or to built-in Operators.

  • Extensible: Create your own builtin functions by implementing the Operator trait.

  • no_std: Only depends on alloc. Enabling the std feature adds the Print, PrintLine, ReadLine and Sleep builtins.

🏋️‍♂️ Examples

To start executing a script, we need to first parse it, create a Scope and assemble a map of builtin functions it can access:
use egglang::prelude::*;

// Create the default Scope, with necessary constants set
let mut scope = Scope::default();

// Create a minimal set of operators
let mut operators = operators::empty();
operators::minimal(&mut operators);

// Parse a Script into a list of expressions
let script = "sum(12.5, 12.5, 25)";
let expressions = parse(script).unwrap();

// Evaluate the expression
let expression = &expressions[0]; // the call to `sum`
let result = evaluate(expression, &mut scope, &operators).unwrap();

assert_eq!(result, 50f32.into());
We can also define custom built-in functions by implementing Operator on a type:
use egglang::prelude::*;
use std::collections::BTreeMap;

// Create the default Scope, with necessary constants set
let mut scope = Scope::default();

// Insert base operators, and add console functions; Adds println
let mut operators = operators::empty();
operators::minimal(&mut operators);
operators::console(&mut operators);

// Define a `random(...)` builtin
struct Random;

impl Operator for Random {
    	fn evaluate(&self, _: &[Expression], _: &mut Scope, _: &BTreeMap<&str, Box<dyn Operator>>) -> EggResult<Value> {
    		// totally random value ;)
    		Ok(0.15.into())
    }
}

// Insert `random(...)` into Operators map
operators.insert("random", Box::new(Random));

// Parse a Script into a list of expressions
let script = r#"
define(iterations, random(0, 120))
repeat(iterations, println("oi oi oi oi oi"))
"#;
let expressions = parse(script).unwrap();

// Evaluate the expressions; define -> repeat -> ...
for expression in expressions {
  let _ = evaluate(&expression, &mut scope, &operators).unwrap();
}

Example Egg scripts can be found in the scripts directory;

Credit: u/Penguin-warrior-3105

Commit count: 138

cargo fmt