Initial function prototype (no arguments yet)

This commit is contained in:
Michael Zhang 2022-04-28 10:46:35 -05:00
parent 15d1d627fd
commit 98354eb44f
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
5 changed files with 127 additions and 62 deletions

46
Cargo.lock generated
View file

@ -13,9 +13,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
[[package]] [[package]]
name = "ascii-canvas" name = "ascii-canvas"
@ -78,16 +78,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.1.8" version = "3.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_derive", "clap_derive",
"clap_lex",
"indexmap", "indexmap",
"lazy_static", "lazy_static",
"os_str_bytes",
"strsim", "strsim",
"termcolor", "termcolor",
"textwrap", "textwrap",
@ -106,6 +106,15 @@ dependencies = [
"syn", "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]] [[package]]
name = "crunchy" name = "crunchy"
version = "0.2.2" version = "0.2.2"
@ -216,7 +225,7 @@ dependencies = [
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.1.0" 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 = [ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
@ -229,7 +238,7 @@ dependencies = [
[[package]] [[package]]
name = "inkwell_internals" name = "inkwell_internals"
version = "0.5.0" 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 = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -285,15 +294,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.121" version = "0.2.124"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "120.2.3" version = "120.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce76f8393b7a607a906087666db398d872db739622e644e58552c198ccdfdf45" checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
@ -344,9 +353,6 @@ name = "os_str_bytes"
version = "6.0.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@ -437,18 +443,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -553,9 +559,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.90" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -6,7 +6,10 @@ use inkwell::{
context::Context, context::Context,
module::Module, module::Module,
types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType},
values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, BasicMetadataValueEnum}, values::{
BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue,
PointerValue,
},
IntPredicate, IntPredicate,
}; };
@ -81,10 +84,9 @@ impl Expr<Type> {
ty: func_ty, ty: func_ty,
kind: EnvValueKind::Func(func_ptr), kind: EnvValueKind::Func(func_ptr),
}) => { }) => {
fn DUMB_CONVERT(a: BasicValueEnum) -> BasicMetadataValueEnum { fn DUMB_CONVERT(a: BasicValueEnum) -> BasicMetadataValueEnum {
use BasicValueEnum as A;
use BasicMetadataValueEnum as B; use BasicMetadataValueEnum as B;
use BasicValueEnum as A;
match a { match a {
A::ArrayValue(a) => B::ArrayValue(a), A::ArrayValue(a) => B::ArrayValue(a),
A::IntValue(a) => B::IntValue(a), A::IntValue(a) => B::IntValue(a),
@ -97,15 +99,16 @@ impl Expr<Type> {
let args_llvm = args let args_llvm = args
.iter() .iter()
.map(|arg| { .map(|arg| arg.into_llvm(context, builder, env).map(DUMB_CONVERT))
arg.into_llvm(context, builder, env).map(DUMB_CONVERT)
})
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
let call_site =
builder.build_call(*func_ptr, args_llvm.as_slice(), ""); 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:?}"), _ => bail!("No function with name {func:?}"),
}, },
} }
@ -277,19 +280,39 @@ pub fn convert(
let module = context.create_module(&file_name); let module = context.create_module(&file_name);
let builder = context.create_builder(); let builder = context.create_builder();
let mut env = Env::default();
for func in program.iter().filter_map(|decl| match decl { for func in program.iter().filter_map(|decl| match decl {
Decl::Func(v) => Some(v), Decl::Func(v) => Some(v),
_ => None, _ => None,
}) { }) {
let return_ty = func.return_ty.into_llvm_basic_type(context); let return_ty = func.return_ty.into_llvm_basic_type(context);
let llvm_func_ty = fn_type_basic(return_ty, &[], false); let llvm_func_ty = fn_type_basic(return_ty, &[], false);
let llvm_func = module.add_function(&func.name, llvm_func_ty, None); 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"); let entry_block = context.append_basic_block(llvm_func, "entry");
builder.position_at_end(entry_block); builder.position_at_end(entry_block);
let env = Env::default();
convert_stmts(&context, &module, &llvm_func, &builder, &env, &func.stmts)?; convert_stmts(&context, &module, &llvm_func, &builder, &env, &func.stmts)?;
} }

View file

@ -11,6 +11,7 @@ pub struct Func<T> {
pub name: String, pub name: String,
pub return_ty: Type, pub return_ty: Type,
pub stmts: Vec<Stmt<T>>, pub stmts: Vec<Stmt<T>>,
pub ty: T,
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::{
collections::{HashMap, HashSet},
mem,
};
use anyhow::Result; use anyhow::Result;
@ -73,7 +76,7 @@ impl Op {
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
struct Constraint(Type_, Type_); struct Constraint(Type_, Type_);
#[derive(Default)] #[derive(Debug, Default)]
struct Env { struct Env {
parent: Option<Box<Env>>, parent: Option<Box<Env>>,
local_type_map: HashMap<String, Type_>, local_type_map: HashMap<String, Type_>,
@ -145,7 +148,7 @@ impl<'a> AnnotationContext<'a> {
fn annotate_stmts( fn annotate_stmts(
ctx: &mut AnnotationContext, ctx: &mut AnnotationContext,
stmts: impl AsRef<[Stmt<()>]>, stmts: impl AsRef<[Stmt<()>]>,
) -> Vec<Stmt<Type_>> { ) -> Result<Vec<Stmt<Type_>>> {
let stmts = stmts.as_ref(); let stmts = stmts.as_ref();
let mut new_stmts = Vec::new(); let mut new_stmts = Vec::new();
ctx.push_scope(); ctx.push_scope();
@ -153,14 +156,16 @@ fn annotate_stmts(
for stmt in stmts.iter() { for stmt in stmts.iter() {
match stmt { match stmt {
Stmt::Return(ret_val) => { Stmt::Return(ret_val) => {
let new_stmt = let new_stmt = match ret_val {
Stmt::Return(ret_val.as_ref().map(|expr| annotate_expr(ctx, expr))); Some(v) => Some(annotate_expr(ctx, v)?),
new_stmts.push(new_stmt); None => None,
};
new_stmts.push(Stmt::Return(new_stmt));
} }
Stmt::Let(name, ty, body) => { Stmt::Let(name, ty, body) => {
let new_stmt = 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 { let ty = match ty {
Some(v) => Type_::from_type(v.clone()), Some(v) => Type_::from_type(v.clone()),
None => ctx.type_var(), None => ctx.type_var(),
@ -170,18 +175,21 @@ fn annotate_stmts(
} }
Stmt::IfElse(if_else) => { 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); new_stmts.push(new_stmt);
} }
} }
} }
ctx.pop_scope(); ctx.pop_scope();
new_stmts Ok(new_stmts)
} }
fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr<Type_> { fn annotate_expr(
match &expr.kind { ctx: &mut AnnotationContext,
expr: &Expr<()>,
) -> Result<Expr<Type_>> {
Ok(match &expr.kind {
ExprKind::Int(n) => Expr { ExprKind::Int(n) => Expr {
kind: ExprKind::Int(*n), kind: ExprKind::Int(*n),
ty: Type_::Int, ty: Type_::Int,
@ -199,8 +207,8 @@ fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr<Type_> {
} }
ExprKind::BinOp(left, op, right) => { ExprKind::BinOp(left, op, right) => {
let left = annotate_expr(ctx, left); let left = annotate_expr(ctx, left)?;
let right = annotate_expr(ctx, right); let right = annotate_expr(ctx, right)?;
let output = ctx.type_var(); let output = ctx.type_var();
op.constraints(ctx, &left.ty, &right.ty, &output); op.constraints(ctx, &left.ty, &right.ty, &output);
@ -211,63 +219,84 @@ fn annotate_expr(ctx: &mut AnnotationContext, expr: &Expr<()>) -> Expr<Type_> {
} }
} }
ExprKind::Call(func, args) => { ExprKind::Call(func_name, args) => {
let mut args_annot = Vec::new(); let mut args_annot = Vec::new();
let ret_ty = ctx.type_var(); 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 { for arg in args {
let arg_annot = annotate_expr(ctx, arg); let arg_annot = annotate_expr(ctx, arg)?;
args_annot.push(arg_annot); args_annot.push(arg_annot);
} }
Expr { Expr {
kind: ExprKind::Call(func.to_string(), args_annot), kind: ExprKind::Call(func_name.to_string(), args_annot),
ty: ret_ty, ty: ret_ty,
} }
} }
} })
} }
fn annotate_if_else( fn annotate_if_else(
ctx: &mut AnnotationContext, ctx: &mut AnnotationContext,
if_else: &IfElse<()>, if_else: &IfElse<()>,
) -> IfElse<Type_> { ) -> Result<IfElse<Type_>> {
let converted_cond = annotate_expr(ctx, &if_else.cond); let converted_cond = annotate_expr(ctx, &if_else.cond)?;
let converted_body = annotate_stmts(ctx, &if_else.body); let converted_body = annotate_stmts(ctx, &if_else.body)?;
let else_clause = match &if_else.else_clause { let else_clause = match &if_else.else_clause {
Some(ElseClause::If(if_else2)) => { 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(stmts)) => {
Some(ElseClause::Body(annotate_stmts(ctx, &stmts))) Some(ElseClause::Body(annotate_stmts(ctx, &stmts)?))
} }
None => None, None => None,
}; };
IfElse { Ok(IfElse {
cond: converted_cond, cond: converted_cond,
body: converted_body, body: converted_body,
else_clause, else_clause,
} })
} }
fn collect_info(func: &Func<()>) -> (Func<Type_>, HashSet<Constraint>) { fn collect_info(
env: Env,
func: &Func<()>,
) -> Result<(Func<Type_>, HashSet<Constraint>, Env)> {
let mut constraints = HashSet::new(); let mut constraints = HashSet::new();
let mut ctx = AnnotationContext { let mut ctx = AnnotationContext {
counter: 0, counter: 0,
constraints: &mut constraints, 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 { let func = Func {
name: func.name.clone(), name: func.name.clone(),
return_ty: func.return_ty.clone(), return_ty: func.return_ty.clone(),
stmts: new_stmts, 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<usize, Type_>; type Assignments = HashMap<usize, Type_>;
@ -420,28 +449,34 @@ fn substitute_in_func(
name: func.name, name: func.name,
return_ty: func.return_ty, return_ty: func.return_ty,
stmts: substitute_in_stmts(assignments, func.stmts)?, stmts: substitute_in_stmts(assignments, func.stmts)?,
ty: func.ty.convert(assignments)?,
}) })
} }
pub fn convert(ast: Vec<Decl<()>>) -> Result<Vec<Decl<Type>>> { pub fn convert(ast: Vec<Decl<()>>) -> Result<Vec<Decl<Type>>> {
// First pass, gather all of the type signatures in the top level // 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() { for decl in ast.iter() {
match decl { match decl {
super::Decl::Func(func) => { super::Decl::Func(func) => {
let name = func.name.clone(); let name = func.name.clone();
let ty = Type::Func(Vec::new(), Box::new(func.return_ty.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 // Now, type-check each function separately
let mut new_decl = Vec::new(); let mut new_decl = Vec::new();
let mut env = top_level_env;
for decl in ast.iter() { for decl in ast.iter() {
match decl { match decl {
Decl::Func(func) => { 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!("func: {:?}", decorated_func);
println!("constraints: {:?}", constraints); println!("constraints: {:?}", constraints);

View file

@ -10,7 +10,7 @@ Decl: Decl<()> = {
Func: Func<()> = { Func: Func<()> = {
"fn" <name:Ident> "(" ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" => "fn" <name:Ident> "(" ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" =>
Func { name, return_ty, stmts }, Func { name, return_ty, stmts, ty: (), },
}; };
Stmt: Stmt<()> = { Stmt: Stmt<()> = {