use std::{collections::{HashMap, LinkedList}, mem::Discriminant}; use super::{Identifier, value::Value, expr::Operation, types::{Type, PrimitiveType}, Declaration}; #[derive(Debug, Default, Clone)] pub struct ValueBindings<'a>(Option<&'a ValueBindings<'a>>, HashMap); impl<'a> ValueBindings<'a> { pub fn builtins() -> Self { Self::default() .bind(&Identifier::identifier_Int(), Value::Type(Type::Primitive(PrimitiveType::Int))) } pub fn bind(mut self, ident: &Identifier, value: Value) -> Self { self.1.insert(ident.1 as u128, value); self } pub fn bind_all(mut self, other: LinkedList<(&Identifier, &Value)>) -> Self{ self.1.extend( other.into_iter() .map(|(ident, val)| (ident.1 as u128, val.clone())) ); self } pub fn bind_all_owned(mut self, other: LinkedList<(Identifier, Value)>) -> Self{ self.1.extend( other.into_iter() .map(|(ident, val)| (ident.1 as u128, val)) ); self } pub fn lookup(&self, ident: &Identifier) -> Option<&Value> { self.1.get(&(ident.1 as u128)) .or_else(|| self.0.and_then(|binding| binding.lookup(ident))) } pub fn nested_scope(&'a self) -> ValueBindings<'a> { ValueBindings(Some(self), HashMap::new()) } pub fn get_main(&self) -> Option<&Value> { self.1.get(&3).or_else(|| self.0.and_then(ValueBindings::get_main)) } } pub enum EvaluateError { UndefinedValue(Identifier), EvaluatingZeroLengthExpr, ArgumentCountMismatch(Operation, usize, usize), FunctionArgumentCountMismatch(usize, usize), TypeMismatch(Discriminant, Discriminant), NoMain, MainHasArgs, IncompleteConditional, } pub type Result = std::result::Result; pub fn display_program(program: Vec) -> std::result::Result { let bindings = ValueBindings::builtins(); let bindings = program.iter() .fold(bindings, |bindings, declaration| bindings.bind(&declaration.identifier, declaration.value.clone()) ); program.into_iter() .map(|decl| { Ok(match decl.value.simplify(&bindings)? { Value::Function(args, val) => { format!( "{0} has type {1}\n{0} takes the arguments: {2}\n", decl.identifier, decl.value_type.simplify(&bindings)?, args.into_iter() .map(|arg| arg.to_string()) .collect::>() .join(", "), ) } other => { format!( "{0} has type {1}\n{0} has the value {2}\n", decl.identifier, decl.value_type.simplify(&bindings)?, other, ) } }) }) .collect::, _>>() .map(|lines| lines.join("\n")) }