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]]
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",

View file

@ -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<Type> {
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<Type> {
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::<Result<Vec<_>>>()?;
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)?;
}

View file

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

View file

@ -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<Box<Env>>,
local_type_map: HashMap<String, Type_>,
@ -145,7 +148,7 @@ impl<'a> AnnotationContext<'a> {
fn annotate_stmts(
ctx: &mut AnnotationContext,
stmts: impl AsRef<[Stmt<()>]>,
) -> Vec<Stmt<Type_>> {
) -> Result<Vec<Stmt<Type_>>> {
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<Type_> {
match &expr.kind {
fn annotate_expr(
ctx: &mut AnnotationContext,
expr: &Expr<()>,
) -> Result<Expr<Type_>> {
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<Type_> {
}
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<Type_> {
}
}
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<Type_> {
let converted_cond = annotate_expr(ctx, &if_else.cond);
let converted_body = annotate_stmts(ctx, &if_else.body);
) -> Result<IfElse<Type_>> {
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<Type_>, HashSet<Constraint>) {
fn collect_info(
env: Env,
func: &Func<()>,
) -> Result<(Func<Type_>, HashSet<Constraint>, 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<usize, Type_>;
@ -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<Decl<()>>) -> Result<Vec<Decl<Type>>> {
// 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);

View file

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