Function arguments

This commit is contained in:
Michael Zhang 2022-04-28 11:33:26 -05:00
parent 98354eb44f
commit 5a50faeacf
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
6 changed files with 173 additions and 46 deletions

View file

@ -1,7 +1,7 @@
fn compute() -> int { fn compute(x : int) -> int {
return 42; return 120 + x;
} }
fn main() -> int { fn main() -> int {
return compute(); return compute(3);
} }

View file

@ -7,12 +7,16 @@ use inkwell::{
module::Module, module::Module,
types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType},
values::{ values::{
BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue,
PointerValue, IntValue, PointerValue,
}, },
IntPredicate, IntPredicate,
}; };
use crate::utils::{
convert_type_to_metadata_type, convert_value_to_metadata_value,
};
use super::{Decl, ElseClause, Expr, ExprKind, IfElse, Op, Stmt, Type}; use super::{Decl, ElseClause, Expr, ExprKind, IfElse, Op, Stmt, Type};
impl Expr<Type> { impl Expr<Type> {
@ -26,17 +30,16 @@ impl Expr<Type> {
let bool_ty = context.bool_type(); let bool_ty = context.bool_type();
match &self.kind { match &self.kind {
ExprKind::Var(name) => { ExprKind::Var(name) => Ok(match env.lookup(&name) {
let value = match env.lookup(&name) { Some(v) => match v.kind {
Some(v) => match v.kind { EnvValueKind::Local(l) => l,
EnvValueKind::Local(l) => l, EnvValueKind::Func(f) => {
EnvValueKind::Func(f) => f.as_global_value().as_pointer_value(), let ptr = f.as_global_value().as_pointer_value();
}, builder.build_load(ptr, "")
None => bail!("Unbound name {name:?}"), }
}; },
None => bail!("Unbound name {name:?}"),
Ok(builder.build_load(value, "")) }),
}
ExprKind::Int(n) => { ExprKind::Int(n) => {
Ok(BasicValueEnum::IntValue(int_ty.const_int(*n as u64, false))) Ok(BasicValueEnum::IntValue(int_ty.const_int(*n as u64, false)))
@ -49,6 +52,16 @@ impl Expr<Type> {
} }
match op { match op {
Op::Plus => {
let left_val =
left.into_llvm(context, builder, env)?.into_int_value();
let right_val =
right.into_llvm(context, builder, env)?.into_int_value();
let result: IntValue =
builder.build_int_add(left_val, right_val, "");
Ok(BasicValueEnum::IntValue(result))
}
Op::LessThan => { Op::LessThan => {
let left_val = let left_val =
left.into_llvm(context, builder, env)?.into_int_value(); left.into_llvm(context, builder, env)?.into_int_value();
@ -84,23 +97,15 @@ 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 {
use BasicMetadataValueEnum as B;
use BasicValueEnum as A;
match a {
A::ArrayValue(a) => B::ArrayValue(a),
A::IntValue(a) => B::IntValue(a),
A::FloatValue(a) => B::FloatValue(a),
A::PointerValue(a) => B::PointerValue(a),
A::StructValue(a) => B::StructValue(a),
A::VectorValue(a) => B::VectorValue(a),
}
}
let args_llvm = args let args_llvm = args
.iter() .iter()
.map(|arg| arg.into_llvm(context, builder, env).map(DUMB_CONVERT)) .map(|arg| {
arg
.into_llvm(context, builder, env)
.map(convert_value_to_metadata_value)
})
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
println!("ARGS_LLVM: {args_llvm:?}");
let call_site = let call_site =
builder.build_call(*func_ptr, args_llvm.as_slice(), ""); builder.build_call(*func_ptr, args_llvm.as_slice(), "");
@ -143,17 +148,19 @@ fn fn_type_basic<'ctx>(
} }
} }
#[derive(Debug)]
enum EnvValueKind<'ctx> { enum EnvValueKind<'ctx> {
Func(FunctionValue<'ctx>), Func(FunctionValue<'ctx>),
Local(PointerValue<'ctx>), Local(BasicValueEnum<'ctx>),
} }
#[derive(Debug)]
struct EnvValue<'a, 'ctx> { struct EnvValue<'a, 'ctx> {
ty: &'a Type, ty: &'a Type,
kind: EnvValueKind<'ctx>, kind: EnvValueKind<'ctx>,
} }
#[derive(Default)] #[derive(Debug, Default)]
struct Env<'a, 'ctx> { struct Env<'a, 'ctx> {
parent: Option<&'a Env<'a, 'ctx>>, parent: Option<&'a Env<'a, 'ctx>>,
local_type_map: HashMap<String, EnvValue<'a, 'ctx>>, local_type_map: HashMap<String, EnvValue<'a, 'ctx>>,
@ -246,7 +253,7 @@ fn convert_stmts(
name.clone(), name.clone(),
EnvValue { EnvValue {
ty, ty,
kind: EnvValueKind::Local(alloca), kind: EnvValueKind::Local(alloca.as_basic_value_enum()),
}, },
); );
} }
@ -286,7 +293,14 @@ pub fn convert(
_ => 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 args_ty = func
.args
.iter()
.map(|arg| {
convert_type_to_metadata_type(arg.ty.into_llvm_basic_type(context))
})
.collect::<Vec<_>>();
let llvm_func_ty = fn_type_basic(return_ty, &args_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( env.local_type_map.insert(
@ -309,11 +323,37 @@ pub fn convert(
}) => func.clone(), }) => func.clone(),
_ => unreachable!(), _ => 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);
convert_stmts(&context, &module, &llvm_func, &builder, &env, &func.stmts)?; let mut scoped_env = Env {
parent: Some(&env),
local_type_map: HashMap::new(),
};
for (arg, param) in func.args.iter().zip(llvm_func.get_params().into_iter())
{
scoped_env.local_type_map.insert(
arg.name.clone(),
EnvValue {
ty: &arg.ty,
kind: EnvValueKind::Local(param),
},
);
}
println!("ARGS {:?}", func.args);
println!("ENV {:?}", scoped_env);
convert_stmts(
&context,
&module,
&llvm_func,
&builder,
&scoped_env,
&func.stmts,
)?;
} }
Ok(module) Ok(module)

View file

@ -9,11 +9,18 @@ pub enum Decl<T> {
#[derive(Debug)] #[derive(Debug)]
pub struct Func<T> { pub struct Func<T> {
pub name: String, pub name: String,
pub args: Vec<Arg>,
pub return_ty: Type, pub return_ty: Type,
pub stmts: Vec<Stmt<T>>, pub stmts: Vec<Stmt<T>>,
pub ty: T, pub ty: T,
} }
#[derive(Debug, Clone)]
pub struct Arg {
pub name: String,
pub ty: Type,
}
#[derive(Debug)] #[derive(Debug)]
pub enum Stmt<T> { pub enum Stmt<T> {
Let(String, Option<Type>, Expr<T>), Let(String, Option<Type>, Expr<T>),
@ -52,6 +59,7 @@ pub enum ExprKind<T> {
pub enum Op { pub enum Op {
LessThan, LessThan,
GreaterThan, GreaterThan,
Plus,
} }
impl Op { impl Op {

View file

@ -64,6 +64,11 @@ impl Op {
output: &Type_, output: &Type_,
) { ) {
match self { match self {
Op::Plus => {
ctx.constrain(left.clone(), Type_::Int);
ctx.constrain(right.clone(), Type_::Int);
ctx.constrain(output.clone(), Type_::Int);
}
Op::LessThan | Op::GreaterThan => { Op::LessThan | Op::GreaterThan => {
ctx.constrain(left.clone(), Type_::Int); ctx.constrain(left.clone(), Type_::Int);
ctx.constrain(right.clone(), Type_::Int); ctx.constrain(right.clone(), Type_::Int);
@ -230,10 +235,14 @@ fn annotate_expr(
None => bail!("Name not found"), None => bail!("Name not found"),
}; };
println!("ENV: {:?}", ctx.current_env);
println!("ANNOT CALL {:?} {:?} {:?}", func_name, args, func_args_ty);
ctx.constrain(ret_ty.clone(), func_ret_ty); ctx.constrain(ret_ty.clone(), func_ret_ty);
for arg in args { for (arg, expected_ty) in args.iter().zip(func_args_ty.iter()) {
let arg_annot = annotate_expr(ctx, arg)?; let arg_annot = annotate_expr(ctx, arg)?;
ctx.constrain(arg_annot.ty.clone(), expected_ty.clone());
args_annot.push(arg_annot); args_annot.push(arg_annot);
} }
@ -281,14 +290,18 @@ fn collect_info(
}; };
let new_stmts = annotate_stmts(&mut ctx, &func.stmts)?; let new_stmts = annotate_stmts(&mut ctx, &func.stmts)?;
// TODO: Args let args_ = func
let total_ty = Type_::Func( .args
Vec::new(), .iter()
Box::new(Type_::from_type(func.return_ty.clone())), .cloned()
); .map(|arg| Type_::from_type(arg.ty))
.collect();
let total_ty =
Type_::Func(args_, Box::new(Type_::from_type(func.return_ty.clone())));
let func = Func { let func = Func {
name: func.name.clone(), name: func.name.clone(),
args: func.args.clone(),
return_ty: func.return_ty.clone(), return_ty: func.return_ty.clone(),
stmts: new_stmts, stmts: new_stmts,
ty: total_ty, ty: total_ty,
@ -373,6 +386,7 @@ fn substitute_in_expr_kind(
ExprKind::BinOp(Box::new(left), op, Box::new(right)) ExprKind::BinOp(Box::new(left), op, Box::new(right))
} }
ExprKind::Call(func, args) => { ExprKind::Call(func, args) => {
println!("CALL {:?}", (&func, &args));
let args = args let args = args
.into_iter() .into_iter()
.map(|arg| substitute_in_expr(assignments, arg)) .map(|arg| substitute_in_expr(assignments, arg))
@ -447,6 +461,7 @@ fn substitute_in_func(
) -> Result<Func<Type>> { ) -> Result<Func<Type>> {
Ok(Func { Ok(Func {
name: func.name, name: func.name,
args: func.args,
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)?, ty: func.ty.convert(assignments)?,
@ -460,7 +475,8 @@ pub fn convert(ast: Vec<Decl<()>>) -> Result<Vec<Decl<Type>>> {
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 args_ty = func.args.iter().map(|arg| arg.ty.clone()).collect();
let ty = Type::Func(args_ty, Box::new(func.return_ty.clone()));
top_level_env top_level_env
.local_type_map .local_type_map
.insert(name, Type_::from_type(ty)); .insert(name, Type_::from_type(ty));
@ -474,9 +490,22 @@ pub fn convert(ast: Vec<Decl<()>>) -> Result<Vec<Decl<Type>>> {
for decl in ast.iter() { for decl in ast.iter() {
match decl { match decl {
Decl::Func(func) => { Decl::Func(func) => {
let mut scoped_env = Env {
parent: Some(Box::new(env)),
local_type_map: HashMap::new(),
};
for arg in func.args.iter() {
scoped_env
.local_type_map
.insert(arg.name.clone(), Type_::from_type(arg.ty.clone()));
}
println!("Processing func {:?}", func); println!("Processing func {:?}", func);
let (decorated_func, constraints, env2) = collect_info(env, func)?; let (decorated_func, constraints, env2) =
env = env2; collect_info(scoped_env, func)?;
env = *env2.parent.unwrap();
println!("func: {:?}", decorated_func); println!("func: {:?}", decorated_func);
println!("constraints: {:?}", constraints); println!("constraints: {:?}", constraints);

View file

@ -9,10 +9,14 @@ Decl: Decl<()> = {
}; };
Func: Func<()> = { Func: Func<()> = {
"fn" <name:Ident> "(" ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" => "fn" <name:Ident> "(" <args:Args> ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" =>
Func { name, return_ty, stmts, ty: (), }, Func { name, args, return_ty, stmts, ty: (), },
}; };
Args: Vec<Arg> = Punct<",", Arg>? => <>.unwrap_or_else(|| Vec::new());
Arg: Arg = <name:Ident> ":" <ty:Type> => Arg { name, ty };
Stmt: Stmt<()> = { Stmt: Stmt<()> = {
"let" <name:Ident> <ty:ColonType?> "=" <expr:Expr> ";" => "let" <name:Ident> <ty:ColonType?> "=" <expr:Expr> ";" =>
Stmt::Let(name, ty, expr), Stmt::Let(name, ty, expr),
@ -46,6 +50,13 @@ Expr: Expr<()> = {
<func:Ident> "(" <args:Punct<",", Expr>?> ")" => <func:Ident> "(" <args:Punct<",", Expr>?> ")" =>
Expr { kind: ExprKind::Call(func, args.unwrap_or_else(|| vec![])), ty: () }, Expr { kind: ExprKind::Call(func, args.unwrap_or_else(|| vec![])), ty: () },
#[precedence(level = "8")]
#[assoc(side = "left")]
<left:Expr> <op:AddOp> <right:Expr> => Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
ty: (),
},
#[precedence(level = "13")] #[precedence(level = "13")]
#[assoc(side = "none")] #[assoc(side = "none")]
<left:Expr> <op:CompareOp> <right:Expr> => Expr { <left:Expr> <op:CompareOp> <right:Expr> => Expr {
@ -54,6 +65,10 @@ Expr: Expr<()> = {
}, },
}; };
AddOp: Op = {
"+" => Op::Plus,
};
CompareOp: Op = { CompareOp: Op = {
"<" => Op::LessThan, "<" => Op::LessThan,
">" => Op::GreaterThan, ">" => Op::GreaterThan,

View file

@ -1 +1,36 @@
// TODO: put layered environment here? // TODO: put layered environment here?
use inkwell::{
types::{BasicMetadataTypeEnum, BasicTypeEnum},
values::{BasicMetadataValueEnum, BasicValueEnum},
};
pub fn convert_type_to_metadata_type(
a: BasicTypeEnum,
) -> BasicMetadataTypeEnum {
use BasicMetadataTypeEnum as B;
use BasicTypeEnum as A;
match a {
A::IntType(a) => B::IntType(a),
A::ArrayType(a) => B::ArrayType(a),
A::FloatType(a) => B::FloatType(a),
A::StructType(a) => B::StructType(a),
A::VectorType(a) => B::VectorType(a),
A::PointerType(a) => B::PointerType(a),
}
}
pub fn convert_value_to_metadata_value(
a: BasicValueEnum,
) -> BasicMetadataValueEnum {
use BasicMetadataValueEnum as B;
use BasicValueEnum as A;
match a {
A::ArrayValue(a) => B::ArrayValue(a),
A::IntValue(a) => B::IntValue(a),
A::FloatValue(a) => B::FloatValue(a),
A::PointerValue(a) => B::PointerValue(a),
A::StructValue(a) => B::StructValue(a),
A::VectorValue(a) => B::VectorValue(a),
}
}