From 780ada70348c179f076635e338dd8fd492fb4e95 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Tue, 26 Apr 2022 12:40:42 -0400 Subject: [PATCH] Gen IR for types, incl. functional types --- sample-initial.amo | 2 +- src/ir/evaluation.rs | 42 ++++++++++++++++++++++++++++++++++++++- src/ir/expr.rs | 14 +++++++++++-- src/ir/mod.rs | 32 ++++++++++------------------- src/ir/types.rs | 13 +++++------- src/ir/value.rs | 15 +++++++++++++- src/main.rs | 7 ++++--- src/parser/declaration.rs | 5 +++-- src/parser/infix.rs | 28 +++++++++++++++++++++++--- src/parser/program.rs | 2 +- 10 files changed, 116 insertions(+), 44 deletions(-) diff --git a/sample-initial.amo b/sample-initial.amo index a8e3a18..84bd2e4 100644 --- a/sample-initial.amo +++ b/sample-initial.amo @@ -1,4 +1,4 @@ -cool_number: Into +cool_number: Int cool_number = 1312 main: Int diff --git a/src/ir/evaluation.rs b/src/ir/evaluation.rs index a09de46..d7ca99f 100644 --- a/src/ir/evaluation.rs +++ b/src/ir/evaluation.rs @@ -1,11 +1,16 @@ use std::{collections::{HashMap, LinkedList}, mem::Discriminant}; -use super::{Identifier, value::Value, expr::Operation, types::Type}; +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 @@ -53,3 +58,38 @@ pub enum EvaluateError { } 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")) +} diff --git a/src/ir/expr.rs b/src/ir/expr.rs index 3e7f2e6..68e0033 100644 --- a/src/ir/expr.rs +++ b/src/ir/expr.rs @@ -1,7 +1,7 @@ use core::fmt; use std::{collections::{LinkedList, HashSet}, mem::{self, discriminant}, borrow::Cow, ops::FromResidual, convert::Infallible}; -use super::{value::Value, pattern::Pattern, Identifier, evaluation::{ValueBindings, self, EvaluateError}}; +use super::{value::Value, pattern::Pattern, Identifier, evaluation::{ValueBindings, self, EvaluateError}, types::{PrimitiveType, Type}}; #[derive(Debug, Clone)] pub struct Expr { @@ -182,7 +182,17 @@ impl Expr { } } Operation::VariantUnion => todo!(), - Operation::FunctionType => todo!(), + Operation::FunctionType => { + if let [a, b] = arguments[..] { + if let (Value::Type(a), Value::Type(b)) = (a, b) { + ExprEvalResult::Succeeded(Value::Type(Type::Function(Box::new(a.clone()), Box::new(b.clone())))) + } else { + ExprEvalResult::Failed(EvaluateError::TypeMismatch(discriminant(b), discriminant(&Value::Type(Type::Primitive(PrimitiveType::Int))))) + } + } else { + ExprEvalResult::Failed(EvaluateError::ArgumentCountMismatch(Operation::FunctionType, arguments.len(), 2)) + } + }, Operation::NoOp => { // Look up the value, if it's a zero-arg function, evaluate it let apparent_value = diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e007e04..7be8789 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -41,6 +41,11 @@ impl Identifier { pub fn set_name(self, new_name: String) -> Identifier { Identifier(new_name, self.1, self.2) } + + pub fn identifier_Int() -> Identifier { + Identifier::main() + .subid_with_name("Int".to_string(), 0) + } } impl fmt::Display for Identifier { @@ -85,7 +90,7 @@ pub fn is_prime(x: usize, known_primes: &[usize]) -> bool { #[derive(Debug)] pub struct Declaration { pub identifier: Identifier, - pub value_type: Type, + pub value_type: Value, pub value: Value, } @@ -100,33 +105,16 @@ impl fmt::Display for Declaration { } } -pub fn hasty_evaluate(program: Vec) -> evaluation::Result { - let bindings = ValueBindings::default(); - let bindings = program.into_iter() - .fold(bindings, |bindings, declaration| - bindings.bind(&declaration.identifier, declaration.value) - ); - if let Some(main) = bindings.get_main() { - if let Value::Function(args, code) = main { - if args.is_empty() { - evaluate(code.clone(), bindings) - } else { - Err(EvaluateError::MainHasArgs) - } - } else { - Ok(main.clone()) - } - } else { - Err(EvaluateError::NoMain) - } -} - #[derive(Debug, Clone)] pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec); impl<'a> BindingScope<'a> { pub const ROOT: BindingScope<'static> = BindingScope(None, Vec::new()); + pub fn builtins() -> BindingScope<'static> { + BindingScope::ROOT.bind_single(Identifier::identifier_Int()) + } + pub fn bind(&self, idents: Vec) -> BindingScope { BindingScope(Some(self), idents) } diff --git a/src/ir/types.rs b/src/ir/types.rs index 94f3db3..7b1fbaf 100644 --- a/src/ir/types.rs +++ b/src/ir/types.rs @@ -2,7 +2,7 @@ use core::fmt; use super::Identifier; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Variant { pub name: Identifier, pub elements: Vec, @@ -21,10 +21,10 @@ impl fmt::Display for Variant { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum Type { UserDefined(Vec), - Function(Vec, Box), + Function(Box, Box), Primitive(PrimitiveType), } @@ -42,10 +42,7 @@ impl fmt::Display for Type { Self::Function(args, return_type) => write!(f, "{} -> {}", - args.into_iter() - .map(ToString::to_string) - .collect::>() - .join(" , "), + args, return_type ), Self::Primitive(p) => p.fmt(f), @@ -53,7 +50,7 @@ impl fmt::Display for Type { } } -#[derive(Debug)] +#[derive(Clone, Debug, Copy)] pub enum PrimitiveType { Int, Str, diff --git a/src/ir/value.rs b/src/ir/value.rs index 720fbee..4c67c6e 100644 --- a/src/ir/value.rs +++ b/src/ir/value.rs @@ -1,7 +1,7 @@ use core::fmt; use std::{collections::LinkedList, mem::discriminant}; -use super::{expr::Expr, Identifier, evaluation::EvaluateError}; +use super::{expr::{Expr, evaluate}, Identifier, evaluation::{EvaluateError, ValueBindings, self}, types::Type}; #[derive(Clone, Debug)] pub enum Value { @@ -9,6 +9,18 @@ pub enum Value { String(String), Function(Vec, LinkedList), Structural(Identifier, Vec), + Type(Type), +} + +impl Value { + /// Converts a zero-arg function into its result + pub fn simplify(self, bindings: &ValueBindings) -> evaluation::Result { + match self { + Value::Function(args, value) if args.is_empty() => + evaluate(value, bindings.nested_scope()), + other => Ok(other), + } + } } impl fmt::Display for Value { @@ -27,6 +39,7 @@ impl fmt::Display for Value { .collect::(), ), Self::Structural(_, _) => todo!(), + Self::Type(typ) => typ.fmt(f), } } } diff --git a/src/main.rs b/src/main.rs index bcd7c96..a7a2cc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use std::{fs::File, io::Read, collections::LinkedList, process::exit}; use logos::Logos; use parser::{program::Program, Parsable, WrappedLexer}; -use crate::ir::{hasty_evaluate, evaluation::EvaluateError}; +use crate::ir::evaluation::{EvaluateError, display_program}; mod token; mod parser; @@ -45,9 +45,10 @@ fn main() -> std::io::Result<()> { .map(|decl| format!("\n\n{decl}\n\n")) .collect::(), ); - match hasty_evaluate(program) { + + match display_program(program) { Ok(value) => - println!("Evaluated successfully! Got: {value}"), + println!("Evaluated successfully! Got:\n{value}"), Err(EvaluateError::UndefinedValue(v)) => println!("Hit an error: {v} is undefined"), Err(EvaluateError::EvaluatingZeroLengthExpr) => diff --git a/src/parser/declaration.rs b/src/parser/declaration.rs index 3279f56..de6ca12 100644 --- a/src/parser/declaration.rs +++ b/src/parser/declaration.rs @@ -1,6 +1,6 @@ use std::mem::{Discriminant, discriminant}; -use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope, types::{Type, PrimitiveType}}}; +use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope}}; use super::{Parsable, WrappedLexer, ParseError, absorb_token_or_error, expr::Expr}; @@ -63,10 +63,11 @@ impl Declaration { let n_args = args.len() as u32; let local_binding = bindings.bind(args.clone()); let expression_dag = value.gen_ir(&local_binding, &own_id, n_args, false)?; + let type_dag = type_.gen_ir(&local_binding, &own_id, n_args + 1, true)?; Ok(Some( ir::Declaration { identifier: own_id, - value_type: Type::Primitive(PrimitiveType::Int), // TODO + value_type: ir::value::Value::Function(Vec::new(), type_dag), value: ir::value::Value::Function(args, expression_dag), } )) diff --git a/src/parser/infix.rs b/src/parser/infix.rs index ea1447f..bfa5d21 100644 --- a/src/parser/infix.rs +++ b/src/parser/infix.rs @@ -22,8 +22,12 @@ pub trait GenIR { ) -> ir::Result>; } +pub enum Direction { LeftToRight, RightToLeft } pub trait InfixOp { fn gen_ir(&self) -> Operation; + fn direction(&self) -> Direction { + Direction::LeftToRight + } } impl InfixOp for InfixRank1 { @@ -42,6 +46,12 @@ impl InfixOp for InfixRank2 { Self::Aro => Operation::FunctionType, } } + fn direction(&self) -> Direction { + match self { + Self::LAnd => Direction::LeftToRight, + Self::Aro => Direction::RightToLeft, + } + } } impl InfixOp for InfixRank3 { @@ -110,7 +120,19 @@ impl GenIR for (LinkedList, Vec<(Op, NextRan let (first_arg_exprs, mut ops) = self; if let Some((this_op, second_arg)) = ops.pop() { let this_ident = parent.subid_with_name(String::new(), index); - let second_arg_exprs = second_arg.gen_ir(bindings, parent, index + 1, type_context)?; + let direction = this_op.direction(); + let (second_arg_exprs, finish_result): + (_, Box) -> ir::Result>>) = + match direction { + Direction::LeftToRight => ( + second_arg.gen_ir(bindings, parent, index + 1, type_context)?, + Box::new(|all_exprs| (all_exprs, ops).gen_ir(bindings, parent, index + 2, type_context)), + ), + Direction::RightToLeft => ( + (second_arg, ops).gen_ir(bindings, parent, index + 1, type_context)?, + Box::new(|all_exprs| ir::Result::Ok(all_exprs)) + ), + }; let op = this_op.gen_ir(); let first_arg_ident = get_last_ident(&first_arg_exprs).ok_or(IrError::MissingExpression)?; let second_arg_ident = get_last_ident(&second_arg_exprs).ok_or(IrError::MissingExpression)?; @@ -125,14 +147,14 @@ impl GenIR for (LinkedList, Vec<(Op, NextRan }; let all_prior_exprs = join(first_arg_exprs, second_arg_exprs); let all_exprs = cons_ll(all_prior_exprs, new_expr); - (all_exprs, ops).gen_ir(bindings, parent, index + 2, type_context) + finish_result(all_exprs) } else { Ok(first_arg_exprs) } } } -//pub type Rank4Exp = (TightExpr, Vec); +//pub tsecond_arg.gen_ir(bindings, parent, index + 1, type_context)ype Rank4Exp = (TightExpr, Vec); impl GenIR for Rank7Exp { fn gen_ir( self, diff --git a/src/parser/program.rs b/src/parser/program.rs index 63fdc8e..9147761 100644 --- a/src/parser/program.rs +++ b/src/parser/program.rs @@ -39,7 +39,7 @@ impl Program { let root_scope = self.0.iter() .enumerate() .filter_map(|(i, decl)| decl.get_identifier(&Identifier::ROOT, i as u32)) - .fold(BindingScope::ROOT, |scope, ident| scope.bind_single(ident)); + .fold(BindingScope::builtins(), |scope, ident| scope.bind_single(ident)); println!("DEBUG {root_scope:?}"); self.0.into_iter() .enumerate()