diff --git a/Cargo.lock b/Cargo.lock index 1b9201b..f29fee4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "ascii-canvas" @@ -78,16 +78,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.8" +version = "3.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" +checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", "lazy_static", - "os_str_bytes", "strsim", "termcolor", "textwrap", @@ -106,6 +106,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -216,7 +225,7 @@ dependencies = [ [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#36c3b106e61b1b45295a35f94023d93d9328c76f" +source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" dependencies = [ "either", "inkwell_internals", @@ -229,7 +238,7 @@ dependencies = [ [[package]] name = "inkwell_internals" version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#36c3b106e61b1b45295a35f94023d93d9328c76f" +source = "git+https://github.com/TheDan64/inkwell?branch=master#bff378bee02bcbb5bed35f47e9ed69e6642e9188" dependencies = [ "proc-macro2", "quote", @@ -285,15 +294,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" [[package]] name = "llvm-sys" -version = "120.2.3" +version = "120.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce76f8393b7a607a906087666db398d872db739622e644e58552c198ccdfdf45" +checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" dependencies = [ "cc", "lazy_static", @@ -344,9 +353,6 @@ name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] [[package]] name = "parking_lot" @@ -437,18 +443,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -553,9 +559,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", "quote", diff --git a/src/ast/llvm.rs b/src/ast/llvm.rs index ad9adc9..519026d 100644 --- a/src/ast/llvm.rs +++ b/src/ast/llvm.rs @@ -6,7 +6,10 @@ use inkwell::{ context::Context, module::Module, types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, - values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, BasicMetadataValueEnum}, + values::{ + BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, + PointerValue, + }, IntPredicate, }; @@ -81,10 +84,9 @@ impl Expr { ty: func_ty, kind: EnvValueKind::Func(func_ptr), }) => { - fn DUMB_CONVERT(a: BasicValueEnum) -> BasicMetadataValueEnum { - use BasicValueEnum as A; use BasicMetadataValueEnum as B; + use BasicValueEnum as A; match a { A::ArrayValue(a) => B::ArrayValue(a), A::IntValue(a) => B::IntValue(a), @@ -97,15 +99,16 @@ impl Expr { let args_llvm = args .iter() - .map(|arg| { - arg.into_llvm(context, builder, env).map(DUMB_CONVERT) - }) + .map(|arg| arg.into_llvm(context, builder, env).map(DUMB_CONVERT)) .collect::>>()?; - builder.build_call(*func_ptr, args_llvm.as_slice(), ""); + let call_site = + builder.build_call(*func_ptr, args_llvm.as_slice(), ""); - todo!() + let value = call_site.try_as_basic_value().unwrap_left(); + Ok(value) } + _ => bail!("No function with name {func:?}"), }, } @@ -277,19 +280,39 @@ pub fn convert( let module = context.create_module(&file_name); let builder = context.create_builder(); + let mut env = Env::default(); for func in program.iter().filter_map(|decl| match decl { Decl::Func(v) => Some(v), _ => None, }) { let return_ty = func.return_ty.into_llvm_basic_type(context); let llvm_func_ty = fn_type_basic(return_ty, &[], false); - let llvm_func = module.add_function(&func.name, llvm_func_ty, None); + + env.local_type_map.insert( + func.name.clone(), + EnvValue { + ty: &func.ty, + kind: EnvValueKind::Func(llvm_func), + }, + ); + } + + for func in program.iter().filter_map(|decl| match decl { + Decl::Func(v) => Some(v), + _ => None, + }) { + let llvm_func = match env.local_type_map.get(&func.name) { + Some(EnvValue { + kind: EnvValueKind::Func(func), + .. + }) => func.clone(), + _ => unreachable!(), + }; let entry_block = context.append_basic_block(llvm_func, "entry"); builder.position_at_end(entry_block); - let env = Env::default(); convert_stmts(&context, &module, &llvm_func, &builder, &env, &func.stmts)?; } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 218de19..1bef14d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -11,6 +11,7 @@ pub struct Func { pub name: String, pub return_ty: Type, pub stmts: Vec>, + pub ty: T, } #[derive(Debug)] diff --git a/src/ast/typed.rs b/src/ast/typed.rs index b76b3ab..2adf97e 100644 --- a/src/ast/typed.rs +++ b/src/ast/typed.rs @@ -1,4 +1,7 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + mem, +}; use anyhow::Result; @@ -73,7 +76,7 @@ impl Op { #[derive(Debug, Hash, Eq, PartialEq)] struct Constraint(Type_, Type_); -#[derive(Default)] +#[derive(Debug, Default)] struct Env { parent: Option>, local_type_map: HashMap, @@ -145,7 +148,7 @@ impl<'a> AnnotationContext<'a> { fn annotate_stmts( ctx: &mut AnnotationContext, stmts: impl AsRef<[Stmt<()>]>, -) -> Vec> { +) -> Result>> { let stmts = stmts.as_ref(); let mut new_stmts = Vec::new(); ctx.push_scope(); @@ -153,14 +156,16 @@ fn annotate_stmts( for stmt in stmts.iter() { match stmt { Stmt::Return(ret_val) => { - let new_stmt = - Stmt::Return(ret_val.as_ref().map(|expr| annotate_expr(ctx, expr))); - new_stmts.push(new_stmt); + let new_stmt = match ret_val { + Some(v) => Some(annotate_expr(ctx, v)?), + None => None, + }; + new_stmts.push(Stmt::Return(new_stmt)); } Stmt::Let(name, ty, body) => { let new_stmt = - Stmt::Let(name.clone(), ty.clone(), annotate_expr(ctx, body)); + Stmt::Let(name.clone(), ty.clone(), annotate_expr(ctx, body)?); let ty = match ty { Some(v) => Type_::from_type(v.clone()), None => ctx.type_var(), @@ -170,18 +175,21 @@ fn annotate_stmts( } Stmt::IfElse(if_else) => { - let new_stmt = Stmt::IfElse(annotate_if_else(ctx, &if_else)); + let new_stmt = Stmt::IfElse(annotate_if_else(ctx, &if_else)?); new_stmts.push(new_stmt); } } } ctx.pop_scope(); - new_stmts + Ok(new_stmts) } -fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr { - match &expr.kind { +fn annotate_expr( + ctx: &mut AnnotationContext, + expr: &Expr<()>, +) -> Result> { + Ok(match &expr.kind { ExprKind::Int(n) => Expr { kind: ExprKind::Int(*n), ty: Type_::Int, @@ -199,8 +207,8 @@ fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr { } ExprKind::BinOp(left, op, right) => { - let left = annotate_expr(ctx, left); - let right = annotate_expr(ctx, right); + let left = annotate_expr(ctx, left)?; + let right = annotate_expr(ctx, right)?; let output = ctx.type_var(); op.constraints(ctx, &left.ty, &right.ty, &output); @@ -211,63 +219,84 @@ fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr { } } - ExprKind::Call(func, args) => { + ExprKind::Call(func_name, args) => { let mut args_annot = Vec::new(); let ret_ty = ctx.type_var(); + let (func_args_ty, func_ret_ty) = + match ctx.current_env.as_ref().unwrap().lookup(func_name) { + Some(Type_::Func(args, ret)) => (args.clone(), *ret.clone()), + Some(_) => bail!("Not a function"), + None => bail!("Name not found"), + }; + + ctx.constrain(ret_ty.clone(), func_ret_ty); + for arg in args { - let arg_annot = annotate_expr(ctx, arg); + let arg_annot = annotate_expr(ctx, arg)?; args_annot.push(arg_annot); } Expr { - kind: ExprKind::Call(func.to_string(), args_annot), + kind: ExprKind::Call(func_name.to_string(), args_annot), ty: ret_ty, } } - } + }) } fn annotate_if_else( ctx: &mut AnnotationContext, if_else: &IfElse<()>, -) -> IfElse { - let converted_cond = annotate_expr(ctx, &if_else.cond); - let converted_body = annotate_stmts(ctx, &if_else.body); +) -> Result> { + let converted_cond = annotate_expr(ctx, &if_else.cond)?; + let converted_body = annotate_stmts(ctx, &if_else.body)?; let else_clause = match &if_else.else_clause { Some(ElseClause::If(if_else2)) => { - Some(ElseClause::If(Box::new(annotate_if_else(ctx, &if_else2)))) + Some(ElseClause::If(Box::new(annotate_if_else(ctx, &if_else2)?))) } Some(ElseClause::Body(stmts)) => { - Some(ElseClause::Body(annotate_stmts(ctx, &stmts))) + Some(ElseClause::Body(annotate_stmts(ctx, &stmts)?)) } None => None, }; - IfElse { + Ok(IfElse { cond: converted_cond, body: converted_body, else_clause, - } + }) } -fn collect_info(func: &Func<()>) -> (Func, HashSet) { +fn collect_info( + env: Env, + func: &Func<()>, +) -> Result<(Func, HashSet, Env)> { let mut constraints = HashSet::new(); let mut ctx = AnnotationContext { counter: 0, constraints: &mut constraints, - current_env: Some(Env::default()), + current_env: Some(env), }; - let new_stmts = annotate_stmts(&mut ctx, &func.stmts); + let new_stmts = annotate_stmts(&mut ctx, &func.stmts)?; + + // TODO: Args + let total_ty = Type_::Func( + Vec::new(), + Box::new(Type_::from_type(func.return_ty.clone())), + ); let func = Func { name: func.name.clone(), return_ty: func.return_ty.clone(), stmts: new_stmts, + ty: total_ty, }; - (func, constraints) + let env = ctx.current_env.unwrap(); + mem::drop(ctx.constraints); + Ok((func, constraints, env)) } type Assignments = HashMap; @@ -420,28 +449,34 @@ fn substitute_in_func( name: func.name, return_ty: func.return_ty, stmts: substitute_in_stmts(assignments, func.stmts)?, + ty: func.ty.convert(assignments)?, }) } pub fn convert(ast: Vec>) -> Result>> { // First pass, gather all of the type signatures in the top level - let mut top_level_signatures = HashMap::new(); + let mut top_level_env = Env::default(); for decl in ast.iter() { match decl { super::Decl::Func(func) => { let name = func.name.clone(); let ty = Type::Func(Vec::new(), Box::new(func.return_ty.clone())); - top_level_signatures.insert(name, ty); + top_level_env + .local_type_map + .insert(name, Type_::from_type(ty)); } } } // Now, type-check each function separately let mut new_decl = Vec::new(); + let mut env = top_level_env; for decl in ast.iter() { match decl { Decl::Func(func) => { - let (decorated_func, constraints) = collect_info(func); + println!("Processing func {:?}", func); + let (decorated_func, constraints, env2) = collect_info(env, func)?; + env = env2; println!("func: {:?}", decorated_func); println!("constraints: {:?}", constraints); diff --git a/src/parser.lalrpop b/src/parser.lalrpop index 3e9e6e0..25a86af 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -10,7 +10,7 @@ Decl: Decl<()> = { Func: Func<()> = { "fn" "(" ")" "->" "{" "}" => - Func { name, return_ty, stmts }, + Func { name, return_ty, stmts, ty: (), }, }; Stmt: Stmt<()> = {