Initial function prototype (no arguments yet)
This commit is contained in:
parent
15d1d627fd
commit
98354eb44f
5 changed files with 127 additions and 62 deletions
46
Cargo.lock
generated
46
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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<_>>>()?;
|
||||
|
||||
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)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<()> = {
|
||||
|
|
Loading…
Reference in a new issue