Reorganize

main
mat ess 2023-07-24 12:22:57 -04:00
parent 501dfff220
commit e84b351daa
5 changed files with 59 additions and 17 deletions

View File

@ -1,13 +1,15 @@
use std::collections::HashMap;
use std::{collections::HashMap, fmt::Display};
use thiserror::Error;
use crate::builtins::{self, Builtin};
use crate::syntax::{Block, Expression, InteractiveEntry, Item, Name, Program};
pub type Dictionary<T> = HashMap<Name, T>;
#[derive(Debug, Clone)]
pub enum Value {
Builtin(Builtin),
Closure {
environment: Dictionary<Value>,
parameters: Vec<Name>,
@ -15,6 +17,19 @@ pub enum Value {
},
Boolean(bool),
Integer(i64),
Unit,
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Builtin(b) => write!(f, "<builtin:{b:?}>"),
Value::Closure { parameters, .. } => write!(f, "<closure({})>", parameters.join(", ")),
Value::Boolean(b) => write!(f, "{b}"),
Value::Integer(i) => write!(f, "{i}"),
Value::Unit => write!(f, "()"),
}
}
}
#[derive(Debug, Error)]
@ -27,9 +42,11 @@ pub enum Error {
ArgumentsMismatch(usize, usize),
#[error("No function called main to run")]
MissingMainFunction,
#[error("Problem with builtin call: {0}")]
BuiltinError(#[from] builtins::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Interpreter {
@ -39,7 +56,7 @@ pub struct Interpreter {
impl Interpreter {
pub fn new() -> Self {
Interpreter {
environment: Dictionary::new(),
environment: Builtin::dictionary(),
}
}
@ -52,7 +69,7 @@ impl Interpreter {
self.interpret_item(item)?;
}
if let Some(main) = self.environment.get("main").cloned() {
self.call_closure(&main, &vec![])
self.apply_call(&main, &vec![])
} else {
Err(Error::MissingMainFunction)
}
@ -101,14 +118,15 @@ impl Interpreter {
}),
Expression::Call { callee, arguments } => {
let callee = self.evaluate(callee.as_ref())?;
self.call_closure(&callee, arguments)
self.apply_call(&callee, arguments)
}
Expression::Boolean(b) => Ok(Value::Boolean(*b)),
Expression::Integer(i) => Ok(Value::Integer(*i)),
Expression::Unit => Ok(Value::Unit),
}
}
fn call_closure(&mut self, callee: &Value, arguments: &Vec<Expression>) -> Result<Value> {
fn apply_call(&mut self, callee: &Value, arguments: &Vec<Expression>) -> Result<Value> {
match callee {
Value::Closure {
environment,
@ -121,10 +139,27 @@ impl Interpreter {
let mut nested = Interpreter::nested(environment.clone());
for (name, argument) in parameters.iter().zip(arguments) {
// we don't want arguments to refer to each other, so use the parent interpreter
nested.bind(name.clone(), argument)?;
self.bind_nested(name.clone(), argument, &mut nested)?;
}
nested.evaluate(result)
}
Value::Builtin(b) => {
if arguments.len() < b.min_parameters() {
return Err(Error::ArgumentsMismatch(
b.min_parameters(),
arguments.len(),
));
} else if let Some(max) = b.max_parameters() {
if arguments.len() > max {
return Err(Error::ArgumentsMismatch(max, arguments.len()));
}
}
let arguments = arguments
.iter()
.map(|term| self.evaluate(term))
.collect::<Result<Vec<_>>>()?;
b.call(arguments).map_err(Error::BuiltinError)
}
_ => Err(Error::NotAFunction),
}
}
@ -142,6 +177,17 @@ impl Interpreter {
self.environment.insert(name, value.clone());
Ok(value)
}
fn bind_nested(
&mut self,
name: Name,
term: &Expression,
nested: &mut Interpreter,
) -> Result<Value> {
let value = self.evaluate(term)?;
nested.environment.insert(name, value.clone());
Ok(value)
}
}
impl Default for Interpreter {

View File

@ -1,3 +1,5 @@
pub mod builtins;
pub mod cli;
pub mod phase;
pub mod evaluate;
pub mod parse;
pub mod syntax;

View File

@ -2,9 +2,9 @@ use lalrpop_util::{lalrpop_mod, lexer::Token, ParseError};
use crate::syntax::{InteractiveEntry, Program};
lalrpop_mod!(parser, "/phase/parse/parser.rs");
lalrpop_mod!(parser, "/parse/parser.rs");
pub type Result<'input, T> = std::result::Result<T, ParseError<usize, Token<'input>, &'static str>>;
type Result<'input, T> = std::result::Result<T, ParseError<usize, Token<'input>, &'static str>>;
pub fn parse_program(input: &str) -> Result<Program> {
parser::ProgramParser::new().parse(input)

View File

@ -41,6 +41,7 @@ Atom: Expression = {
Integer => Expression::Integer(<>),
Boolean => Expression::Boolean(<>),
"(" <Expression> ")",
"(" ")" => Expression::Unit,
};
BlockBinding = <Binding> ";";

View File

@ -1,7 +0,0 @@
pub mod parse;
// |
// |
// syntax
// |
// v
pub mod evaluate;