Add builtins
parent
e84b351daa
commit
bcee1cf160
|
@ -14,6 +14,9 @@
|
||||||
- [x] integers
|
- [x] integers
|
||||||
- [ ] floating point numbers
|
- [ ] floating point numbers
|
||||||
- [ ] text
|
- [ ] text
|
||||||
|
- [ ] items
|
||||||
|
- [x] function definitions
|
||||||
|
- [ ] type definitions
|
||||||
- [ ] functions
|
- [ ] functions
|
||||||
- [x] lambdas / closures
|
- [x] lambdas / closures
|
||||||
- [ ] generic functions
|
- [ ] generic functions
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,8 @@ use std::path::Path;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
||||||
use mul::cli::{Command, USAGE};
|
use mul::cli::{Command, USAGE};
|
||||||
use mul::phase::evaluate::Interpreter;
|
use mul::evaluate::Interpreter;
|
||||||
use mul::phase::parse::{parse_interactive_entry, parse_program};
|
use mul::parse::{parse_interactive_entry, parse_program};
|
||||||
use mul::syntax::Program;
|
use mul::syntax::Program;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
@ -23,8 +23,7 @@ fn main() -> Result<()> {
|
||||||
Command::Run { path } => {
|
Command::Run { path } => {
|
||||||
let program = parse(path.as_path())?;
|
let program = parse(path.as_path())?;
|
||||||
let mut interpreter = Interpreter::new();
|
let mut interpreter = Interpreter::new();
|
||||||
let value = interpreter.run(&program)?;
|
let _result = interpreter.run(&program)?;
|
||||||
println!("{value:#?}");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Command::Repl => repl(),
|
Command::Repl => repl(),
|
||||||
|
@ -64,7 +63,7 @@ fn repl() -> Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let value = interpreter.evaluate_interactive_entry(&parsed)?;
|
let value = interpreter.evaluate_interactive_entry(&parsed)?;
|
||||||
println!("{value:?}");
|
println!("{value}");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ pub enum Expression {
|
||||||
},
|
},
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A sequence of bindings with a final result.
|
/// A sequence of bindings with a final result.
|
||||||
|
|
Loading…
Reference in New Issue