Reorganize
parent
501dfff220
commit
e84b351daa
|
@ -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 {
|
|
@ -1,3 +1,5 @@
|
|||
pub mod builtins;
|
||||
pub mod cli;
|
||||
pub mod phase;
|
||||
pub mod evaluate;
|
||||
pub mod parse;
|
||||
pub mod syntax;
|
||||
|
|
|
@ -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)
|
|
@ -41,6 +41,7 @@ Atom: Expression = {
|
|||
Integer => Expression::Integer(<>),
|
||||
Boolean => Expression::Boolean(<>),
|
||||
"(" <Expression> ")",
|
||||
"(" ")" => Expression::Unit,
|
||||
};
|
||||
|
||||
BlockBinding = <Binding> ";";
|
|
@ -1,7 +0,0 @@
|
|||
pub mod parse;
|
||||
// |
|
||||
// |
|
||||
// syntax
|
||||
// |
|
||||
// v
|
||||
pub mod evaluate;
|
Loading…
Reference in New Issue