Crate egglang

Source
Expand description

A Rust implementation of the Egg Programming Language

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

Docs | Repo | Samples

§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

Modules§

error
Error and Result types
evaluator
Evaluates an expression into a Value
expression
Expression and Value types
operators
Traits for defining functions in Rust callable in Egg, as well as several builtin functions
parser
Parser for Egg scripts
prelude
Easy access to the crate’s most important types and functions
scope
Contains the Scope struct, which stores variables and allows for creation of local scopes