use std::collections::HashMap; use std::rc::Rc; use crate::builtin::Builtin; use crate::symbol_table::{DefId, SymbolTable}; //TODO most of these Clone impls only exist to support function application, because the //tree-walking evaluator moves the reduced IR members. /// The reduced intermediate representation consists of a list of function definitions, and a block /// of entrypoint statements. In a repl or script context this can be an arbitrary list of /// statements, in an executable context will likely just be a pointer to the main() function. #[derive(Debug)] pub struct ReducedIR { pub functions: HashMap, pub entrypoint: Vec, } impl ReducedIR { pub fn debug(&self, symbol_table: &SymbolTable) { println!("Reduced IR:"); println!("Functions:"); println!("-----------"); for (id, callable) in self.functions.iter() { let name = &symbol_table.lookup_symbol_by_def(id).unwrap().local_name; println!("{}({}) -> {:?}", id, name, callable); } println!(""); println!("Entrypoint:"); println!("-----------"); for stmt in self.entrypoint.iter() { println!("{:?}", stmt); } println!("-----------"); } } #[derive(Debug, Clone)] pub enum Statement { Expression(Expression), Binding { id: DefId, constant: bool, expr: Expression }, } #[derive(Debug, Clone)] pub enum Expression { Literal(Literal), Tuple(Vec), Lookup { id: DefId, //TODO eventually not everything that can be looked up will have a DefId kind: Lookup, }, Assign { lval: DefId, rval: Box, }, Callable(Function), Call { f: Box, args: Vec }, ReductionError(String), } impl Expression { pub fn unit() -> Self { Expression::Tuple(vec![]) } } #[derive(Debug)] pub struct FunctionDefinition { pub body: Vec } #[derive(Debug, Clone)] pub enum Function { Builtin(Builtin), UserDefined(DefId), Lambda { arity: u8, body: Vec } } #[derive(Debug, Clone)] pub enum Lookup { LocalVar, GlobalVar, Function, Param(u8), } #[derive(Debug, Clone)] pub enum Literal { Nat(u64), Int(i64), Float(f64), Bool(bool), StringLit(Rc), }