Add builtins

main
mat ess 2023-07-24 12:23:13 -04:00
parent e84b351daa
commit bcee1cf160
4 changed files with 140 additions and 5 deletions

View File

@ -14,6 +14,9 @@
- [x] integers
- [ ] floating point numbers
- [ ] text
- [ ] items
- [x] function definitions
- [ ] type definitions
- [ ] functions
- [x] lambdas / closures
- [ ] generic functions

132
src/builtins.rs Normal file
View File

@ -0,0 +1,132 @@
use std::fmt::Write;
use thiserror::Error;
use crate::evaluate::{Dictionary, Value};
#[derive(Debug, Copy, Clone)]
pub enum Builtin {
Print,
Add,
Sub,
Mul,
Div,
Equals,
GreaterThan,
LessThan,
}
#[derive(Debug, Error)]
pub enum Error {
#[error("Tried to {0} a non-integer: {1}")]
NonInteger(&'static str, Value),
}
type Result<T> = std::result::Result<T, Error>;
fn unwrap_int_value(op_name: &'static str) -> impl Fn(Value) -> Result<i64> {
move |value| match value {
Value::Integer(i) => Ok(i),
_ => Err(Error::NonInteger(op_name, value)),
}
}
macro_rules! int_op {
($arguments:expr, $op:tt, $op_name:expr) => {
Value::Integer(
$arguments
.into_iter()
.map(unwrap_int_value($op_name))
.reduce(|acc, v| Ok(acc? $op v?))
.unwrap()?,
)
};
}
macro_rules! int_cmp {
($arguments:expr, $op:tt) => {{
let mut arguments = $arguments;
let unwrap = unwrap_int_value("compare");
let y = unwrap(arguments.pop().unwrap())?;
let x = unwrap(arguments.pop().unwrap())?;
Value::Boolean(x $op y)
}};
}
impl Builtin {
pub fn dictionary() -> Dictionary<Value> {
[
("_print", Builtin::Print),
("_add", Builtin::Add),
("_sub", Builtin::Sub),
("_mul", Builtin::Mul),
("_div", Builtin::Div),
("_equals", Builtin::Equals),
("_greaterthan", Builtin::GreaterThan),
("_lessthan", Builtin::LessThan),
]
.map(|(name, builtin)| (name.to_string(), Value::Builtin(builtin)))
.into()
}
pub fn min_parameters(&self) -> usize {
match self {
Builtin::Print => 0,
Builtin::Add
| Builtin::Sub
| Builtin::Mul
| Builtin::Div
| Builtin::Equals
| Builtin::GreaterThan
| Builtin::LessThan => 2,
}
}
pub fn max_parameters(&self) -> Option<usize> {
match self {
Builtin::Print
| Builtin::Add
| Builtin::Sub
| Builtin::Mul
| Builtin::Div
| Builtin::Equals => None,
Builtin::GreaterThan | Builtin::LessThan => Some(2),
}
}
pub fn call(&self, arguments: Vec<Value>) -> Result<Value> {
let result = match self {
Builtin::Print => {
let mut output = String::new();
let mut arguments = arguments.into_iter().peekable();
while let Some(term) = arguments.next() {
if arguments.peek().is_some() {
write!(output, "{term} ").expect("Error during printing");
} else {
write!(output, "{term}").expect("Error during printing");
}
}
println!("{output}");
Value::Unit
}
Builtin::Add => int_op!(arguments, +, "add"),
Builtin::Sub => int_op!(arguments, -, "subtract"),
Builtin::Mul => int_op!(arguments, *, "multiply"),
Builtin::Div => int_op!(arguments, /, "divide"),
Builtin::Equals => {
let mut arguments = arguments;
let y = arguments.pop().unwrap();
let x = arguments.pop().unwrap();
let b = match (x, y) {
(Value::Integer(x), Value::Integer(y)) => x == y,
(Value::Boolean(x), Value::Boolean(y)) => x == y,
(Value::Unit, Value::Unit) => true,
_ => false,
};
Value::Boolean(b)
}
Builtin::GreaterThan => int_cmp!(arguments, >),
Builtin::LessThan => int_cmp!(arguments, <),
};
Ok(result)
}
}

View File

@ -5,8 +5,8 @@ use std::path::Path;
use anyhow::{anyhow, Context, Result};
use mul::cli::{Command, USAGE};
use mul::phase::evaluate::Interpreter;
use mul::phase::parse::{parse_interactive_entry, parse_program};
use mul::evaluate::Interpreter;
use mul::parse::{parse_interactive_entry, parse_program};
use mul::syntax::Program;
fn main() -> Result<()> {
@ -23,8 +23,7 @@ fn main() -> Result<()> {
Command::Run { path } => {
let program = parse(path.as_path())?;
let mut interpreter = Interpreter::new();
let value = interpreter.run(&program)?;
println!("{value:#?}");
let _result = interpreter.run(&program)?;
Ok(())
}
Command::Repl => repl(),
@ -64,7 +63,7 @@ fn repl() -> Result<()> {
}
};
let value = interpreter.evaluate_interactive_entry(&parsed)?;
println!("{value:?}");
println!("{value}");
}
Ok(())
}

View File

@ -46,6 +46,7 @@ pub enum Expression {
},
Boolean(bool),
Integer(i64),
Unit,
}
/// A sequence of bindings with a final result.