Gen IR for types, incl. functional types
This commit is contained in:
parent
1895364870
commit
780ada7034
|
@ -1,4 +1,4 @@
|
||||||
cool_number: Into
|
cool_number: Int
|
||||||
cool_number = 1312
|
cool_number = 1312
|
||||||
|
|
||||||
main: Int
|
main: Int
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
use std::{collections::{HashMap, LinkedList}, mem::Discriminant};
|
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)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct ValueBindings<'a>(Option<&'a ValueBindings<'a>>, HashMap<u128, Value>);
|
pub struct ValueBindings<'a>(Option<&'a ValueBindings<'a>>, HashMap<u128, Value>);
|
||||||
|
|
||||||
impl<'a> ValueBindings<'a> {
|
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 {
|
pub fn bind(mut self, ident: &Identifier, value: Value) -> Self {
|
||||||
self.1.insert(ident.1 as u128, value);
|
self.1.insert(ident.1 as u128, value);
|
||||||
self
|
self
|
||||||
|
@ -53,3 +58,38 @@ pub enum EvaluateError {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result = std::result::Result<Value, EvaluateError>;
|
pub type Result = std::result::Result<Value, EvaluateError>;
|
||||||
|
|
||||||
|
pub fn display_program(program: Vec<Declaration>) -> std::result::Result<String, EvaluateError> {
|
||||||
|
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::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
format!(
|
||||||
|
"{0} has type {1}\n{0} has the value {2}\n",
|
||||||
|
decl.identifier,
|
||||||
|
decl.value_type.simplify(&bindings)?,
|
||||||
|
other,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<std::result::Result<Vec<_>, _>>()
|
||||||
|
.map(|lines| lines.join("\n"))
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{collections::{LinkedList, HashSet}, mem::{self, discriminant}, borrow::Cow, ops::FromResidual, convert::Infallible};
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Expr {
|
pub struct Expr {
|
||||||
|
@ -182,7 +182,17 @@ impl Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::VariantUnion => todo!(),
|
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 => {
|
Operation::NoOp => {
|
||||||
// Look up the value, if it's a zero-arg function, evaluate it
|
// Look up the value, if it's a zero-arg function, evaluate it
|
||||||
let apparent_value =
|
let apparent_value =
|
||||||
|
|
|
@ -41,6 +41,11 @@ impl Identifier {
|
||||||
pub fn set_name(self, new_name: String) -> Identifier {
|
pub fn set_name(self, new_name: String) -> Identifier {
|
||||||
Identifier(new_name, self.1, self.2)
|
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 {
|
impl fmt::Display for Identifier {
|
||||||
|
@ -85,7 +90,7 @@ pub fn is_prime(x: usize, known_primes: &[usize]) -> bool {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Declaration {
|
pub struct Declaration {
|
||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
pub value_type: Type,
|
pub value_type: Value,
|
||||||
pub value: Value,
|
pub value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,33 +105,16 @@ impl fmt::Display for Declaration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasty_evaluate(program: Vec<Declaration>) -> 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec<Identifier>);
|
pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec<Identifier>);
|
||||||
|
|
||||||
impl<'a> BindingScope<'a> {
|
impl<'a> BindingScope<'a> {
|
||||||
pub const ROOT: BindingScope<'static> = BindingScope(None, Vec::new());
|
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<Identifier>) -> BindingScope {
|
pub fn bind(&self, idents: Vec<Identifier>) -> BindingScope {
|
||||||
BindingScope(Some(self), idents)
|
BindingScope(Some(self), idents)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use core::fmt;
|
||||||
|
|
||||||
use super::Identifier;
|
use super::Identifier;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
pub elements: Vec<Type>,
|
pub elements: Vec<Type>,
|
||||||
|
@ -21,10 +21,10 @@ impl fmt::Display for Variant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
UserDefined(Vec<Variant>),
|
UserDefined(Vec<Variant>),
|
||||||
Function(Vec<Type>, Box<Type>),
|
Function(Box<Type>, Box<Type>),
|
||||||
Primitive(PrimitiveType),
|
Primitive(PrimitiveType),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +42,7 @@ impl fmt::Display for Type {
|
||||||
Self::Function(args, return_type) =>
|
Self::Function(args, return_type) =>
|
||||||
write!(f,
|
write!(f,
|
||||||
"{} -> {}",
|
"{} -> {}",
|
||||||
args.into_iter()
|
args,
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" , "),
|
|
||||||
return_type
|
return_type
|
||||||
),
|
),
|
||||||
Self::Primitive(p) => p.fmt(f),
|
Self::Primitive(p) => p.fmt(f),
|
||||||
|
@ -53,7 +50,7 @@ impl fmt::Display for Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
pub enum PrimitiveType {
|
pub enum PrimitiveType {
|
||||||
Int,
|
Int,
|
||||||
Str,
|
Str,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{collections::LinkedList, mem::discriminant};
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
@ -9,6 +9,18 @@ pub enum Value {
|
||||||
String(String),
|
String(String),
|
||||||
Function(Vec<Identifier>, LinkedList<Expr>),
|
Function(Vec<Identifier>, LinkedList<Expr>),
|
||||||
Structural(Identifier, Vec<Value>),
|
Structural(Identifier, Vec<Value>),
|
||||||
|
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 {
|
impl fmt::Display for Value {
|
||||||
|
@ -27,6 +39,7 @@ impl fmt::Display for Value {
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
),
|
),
|
||||||
Self::Structural(_, _) => todo!(),
|
Self::Structural(_, _) => todo!(),
|
||||||
|
Self::Type(typ) => typ.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{fs::File, io::Read, collections::LinkedList, process::exit};
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
use parser::{program::Program, Parsable, WrappedLexer};
|
use parser::{program::Program, Parsable, WrappedLexer};
|
||||||
|
|
||||||
use crate::ir::{hasty_evaluate, evaluation::EvaluateError};
|
use crate::ir::evaluation::{EvaluateError, display_program};
|
||||||
|
|
||||||
mod token;
|
mod token;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
@ -45,9 +45,10 @@ fn main() -> std::io::Result<()> {
|
||||||
.map(|decl| format!("\n\n{decl}\n\n"))
|
.map(|decl| format!("\n\n{decl}\n\n"))
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
);
|
);
|
||||||
match hasty_evaluate(program) {
|
|
||||||
|
match display_program(program) {
|
||||||
Ok(value) =>
|
Ok(value) =>
|
||||||
println!("Evaluated successfully! Got: {value}"),
|
println!("Evaluated successfully! Got:\n{value}"),
|
||||||
Err(EvaluateError::UndefinedValue(v)) =>
|
Err(EvaluateError::UndefinedValue(v)) =>
|
||||||
println!("Hit an error: {v} is undefined"),
|
println!("Hit an error: {v} is undefined"),
|
||||||
Err(EvaluateError::EvaluatingZeroLengthExpr) =>
|
Err(EvaluateError::EvaluatingZeroLengthExpr) =>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::mem::{Discriminant, discriminant};
|
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};
|
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 n_args = args.len() as u32;
|
||||||
let local_binding = bindings.bind(args.clone());
|
let local_binding = bindings.bind(args.clone());
|
||||||
let expression_dag = value.gen_ir(&local_binding, &own_id, n_args, false)?;
|
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(
|
Ok(Some(
|
||||||
ir::Declaration {
|
ir::Declaration {
|
||||||
identifier: own_id,
|
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),
|
value: ir::value::Value::Function(args, expression_dag),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
|
@ -22,8 +22,12 @@ pub trait GenIR {
|
||||||
) -> ir::Result<LinkedList<ir::expr::Expr>>;
|
) -> ir::Result<LinkedList<ir::expr::Expr>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Direction { LeftToRight, RightToLeft }
|
||||||
pub trait InfixOp {
|
pub trait InfixOp {
|
||||||
fn gen_ir(&self) -> Operation;
|
fn gen_ir(&self) -> Operation;
|
||||||
|
fn direction(&self) -> Direction {
|
||||||
|
Direction::LeftToRight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InfixOp for InfixRank1 {
|
impl InfixOp for InfixRank1 {
|
||||||
|
@ -42,6 +46,12 @@ impl InfixOp for InfixRank2 {
|
||||||
Self::Aro => Operation::FunctionType,
|
Self::Aro => Operation::FunctionType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn direction(&self) -> Direction {
|
||||||
|
match self {
|
||||||
|
Self::LAnd => Direction::LeftToRight,
|
||||||
|
Self::Aro => Direction::RightToLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InfixOp for InfixRank3 {
|
impl InfixOp for InfixRank3 {
|
||||||
|
@ -110,7 +120,19 @@ impl<NextRank: GenIR, Op: InfixOp> GenIR for (LinkedList<Expr>, Vec<(Op, NextRan
|
||||||
let (first_arg_exprs, mut ops) = self;
|
let (first_arg_exprs, mut ops) = self;
|
||||||
if let Some((this_op, second_arg)) = ops.pop() {
|
if let Some((this_op, second_arg)) = ops.pop() {
|
||||||
let this_ident = parent.subid_with_name(String::new(), index);
|
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<dyn FnOnce(LinkedList<ir::expr::Expr>) -> ir::Result<LinkedList<ir::expr::Expr>>>) =
|
||||||
|
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 op = this_op.gen_ir();
|
||||||
let first_arg_ident = get_last_ident(&first_arg_exprs).ok_or(IrError::MissingExpression)?;
|
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)?;
|
let second_arg_ident = get_last_ident(&second_arg_exprs).ok_or(IrError::MissingExpression)?;
|
||||||
|
@ -125,14 +147,14 @@ impl<NextRank: GenIR, Op: InfixOp> GenIR for (LinkedList<Expr>, Vec<(Op, NextRan
|
||||||
};
|
};
|
||||||
let all_prior_exprs = join(first_arg_exprs, second_arg_exprs);
|
let all_prior_exprs = join(first_arg_exprs, second_arg_exprs);
|
||||||
let all_exprs = cons_ll(all_prior_exprs, new_expr);
|
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 {
|
} else {
|
||||||
Ok(first_arg_exprs)
|
Ok(first_arg_exprs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub type Rank4Exp = (TightExpr, Vec<Rank5Exp>);
|
//pub tsecond_arg.gen_ir(bindings, parent, index + 1, type_context)ype Rank4Exp = (TightExpr, Vec<Rank5Exp>);
|
||||||
impl GenIR for Rank7Exp {
|
impl GenIR for Rank7Exp {
|
||||||
fn gen_ir(
|
fn gen_ir(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl Program {
|
||||||
let root_scope = self.0.iter()
|
let root_scope = self.0.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, decl)| decl.get_identifier(&Identifier::ROOT, i as u32))
|
.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:?}");
|
println!("DEBUG {root_scope:?}");
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
Loading…
Reference in New Issue