Function arguments
This commit is contained in:
parent
98354eb44f
commit
5a50faeacf
6 changed files with 173 additions and 46 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
104
src/ast/llvm.rs
104
src/ast/llvm.rs
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
35
src/utils.rs
35
src/utils.rs
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue