Skip to content

Commit 8d82c33

Browse files
committed
Add Call statements [TC missing]
1 parent af1b3ab commit 8d82c33

File tree

8 files changed

+164
-94
lines changed

8 files changed

+164
-94
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn foo() {
2+
bar();
3+
return;
4+
}
5+
6+
fn bar() -> int {
7+
return 0;
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn foo() {
2+
let x = bar();
3+
return;
4+
}
5+
6+
fn bar() {
7+
return;
8+
}

src/ai.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ fn env_from_cfg(cfg: &IntraProcCFG) -> Environment {
149149
.collect::<Vec<_>>();
150150
free_vars.sort();
151151
free_vars.push(RETURN_VAR.to_string());
152-
// println!("{:?}", free_vars);
153152
Environment::new(free_vars)
154153
}
155154

@@ -310,6 +309,12 @@ fn handle_irnode<M: Manager>(
310309
// TODO: handle arrays in AI
311310
None
312311
}
312+
IRCall(name, args) => {
313+
// Can ignore calls for now, but they can change state, namely when we pass arrays, which are by-reference
314+
// TODO: Also need to handle special functions like analyze!
315+
316+
None
317+
}
313318
IRReturn(Some(e)) => {
314319
// TODO: Handle return better. How?
315320
// TODO: make this not panic if retty not int. need to track return type of analyzed function

src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub enum Stmt {
187187
Return(Option<WithLoc<Expr>>),
188188
Decl(WithLoc<Var>, WithLoc<Expr>),
189189
Assn(WithLoc<LocExpr>, WithLoc<Expr>),
190+
Call(WithLoc<String>, WithLoc<Vec<WithLoc<Expr>>>),
190191
IfElse {
191192
cond: WithLoc<Expr>,
192193
if_branch: WithLoc<Block>,
@@ -220,6 +221,9 @@ impl Display for Stmt {
220221
Return(None) => f.write_str(&format!("return")),
221222
Decl(v, e) => f.write_str(&format!("let {} = {}", v, e)),
222223
Assn(v, e) => f.write_str(&format!("{} = {}", v, e)),
224+
Call(name, args) => {
225+
f.write_str(&format!("{}({})", name, sep_string_display(args, ", ")))
226+
}
223227
IfElse {
224228
cond,
225229
if_branch,

src/compiler.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use inkwell::context::Context;
66
use inkwell::module::Module;
77
use inkwell::passes::PassManager;
88
use inkwell::types::{AnyType, BasicMetadataTypeEnum, BasicTypeEnum};
9-
use inkwell::values::{InstructionOpcode, BasicValue, BasicMetadataValueEnum, FloatValue, IntValue, FunctionValue, PointerValue, BasicValueEnum, AnyValue, AnyValueEnum};
9+
use inkwell::values::{InstructionOpcode, BasicValue, BasicMetadataValueEnum, FloatValue, IntValue, FunctionValue, PointerValue, BasicValueEnum, AnyValue, AnyValueEnum, CallSiteValue};
1010
use inkwell::{OptimizationLevel, FloatPredicate, IntPredicate, AddressSpace};
1111
use inkwell::targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine};
1212
use crate::ast::{BinOpcode, Block, Expr, FuncDef, LocExpr, Program, Stmt, Type, UnOpcode, Var, WithLoc};
@@ -85,6 +85,13 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
8585
alloc_array_default_res.try_as_basic_value().left().unwrap().into_pointer_value()
8686
}
8787

88+
fn compile_call(&mut self, name: &WithLoc<String>, args: &WithLoc<Vec<WithLoc<Expr>>>) -> CallSiteValue<'ctx> {
89+
let args = args.iter().map(|e| self.compile_exp(e).into()).collect::<Vec<_>>();
90+
let func = self.functions.get(name.as_str()).unwrap();
91+
let call_res = self.builder.build_call(*func, &args[..], name.as_str());
92+
call_res
93+
}
94+
8895
fn compile_loc_exp(&mut self, lexp: &WithLoc<LocExpr>) -> PointerValue<'ctx> {
8996
match &lexp.elem {
9097
LocExpr::Var(v) => {
@@ -190,9 +197,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
190197
}
191198
}
192199
Expr::Call(name, args) => {
193-
let args = args.iter().map(|e| self.compile_exp(e).into()).collect::<Vec<_>>();
194-
let func = self.functions.get(name.as_str()).unwrap();
195-
let call_res = self.builder.build_call(*func, &args[..], name.as_str());
200+
let call_res = self.compile_call(name, args);
196201
// if we typecheck correctly and do not allow void functions to be in expression calls, then this will always work
197202
call_res.try_as_basic_value().unwrap_left().into()
198203
}
@@ -267,6 +272,10 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
267272
let ptr = self.compile_loc_exp(le);
268273
self.builder.build_store(ptr, val.into_int_value());
269274
},
275+
Stmt::Call(name, args) => {
276+
let call_res = self.compile_call(name, args);
277+
278+
}
270279
Stmt::IfElse { cond, if_branch, else_branch } => {
271280
let cond = self.compile_exp(cond).into_int_value();
272281
let cond = self.builder.build_int_truncate(cond, self.context.bool_type(), "cond_cast");

src/ir.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub enum IRNode {
2828
IRSkip,
2929
IRDecl(Var, Expr),
3030
IRAssn(LocExpr, Expr),
31+
IRCall(String, Vec<Expr>),
3132
IRReturn(Option<Expr>),
3233

3334
IRCBranch(Expr),
@@ -47,10 +48,17 @@ impl IRNode {
4748
fv.extend(le.free_vars());
4849
fv
4950
}
51+
IRCall(_, es) => {
52+
let mut fv = HashSet::new();
53+
for e in es {
54+
fv.extend(e.free_vars());
55+
}
56+
fv
57+
}
5058
IRReturn(Some(e)) => e.free_vars(),
5159
IRReturn(None) => HashSet::new(),
5260
IRCBranch(e) => e.free_vars(),
53-
_ => HashSet::new(),
61+
IRUnreachable | IRTestcase | IRSkip | IRBranch => HashSet::new(),
5462
}
5563
}
5664
}
@@ -63,6 +71,9 @@ impl Display for IRNode {
6371
IRSkip => f.write_str("skip"),
6472
IRDecl(v, e) => f.write_str(&format!("let {} = {}", v, e)),
6573
IRAssn(v, e) => f.write_str(&format!("{} = {}", v, e)),
74+
IRCall(name, args) => {
75+
f.write_str(&format!("{}({})", name, sep_string_display(args, ", ")))
76+
}
6677
IRReturn(Some(e)) => f.write_str(&format!("return {}", e)),
6778
IRReturn(None) => f.write_str(&format!("return")),
6879
IRCBranch(e) => f.write_str(&format!("<cbranch> {}", e)),
@@ -136,6 +147,13 @@ impl IntraProcCFG {
136147
}
137148
prev_nodes = vec![(added, Fallthrough)];
138149
}
150+
Stmt::Call(ref f, ref args) => {
151+
let added = self.graph.add_node(IRCall(f.elem.clone(), args.iter().map(|arg| arg.elem.clone()).collect()));
152+
for (prev_node, connect_prev) in &prev_nodes {
153+
self.graph.add_edge(*prev_node, added, *connect_prev);
154+
}
155+
prev_nodes = vec![(added, Fallthrough)];
156+
}
139157
Stmt::IfElse {
140158
ref cond,
141159
ref if_branch,

src/progge.lalrpop

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ pub Stmt: Stmt = {
121121
<le:LocExprL> "=" <e:ExprL> => {
122122
Stmt::Assn(le, e)
123123
},
124+
<c:CallExpr_> => Stmt::Call(c.0, c.1),
124125
}
125126

126127
LocExprL = WithLoc<LocExpr>;
@@ -170,7 +171,7 @@ LeafExpr: Expr = {
170171
Int => Expr::IntLit(<>),
171172
"true" => Expr::BoolLit(true),
172173
"false" => Expr::BoolLit(false),
173-
<n:NameL> "(" <args:WithLoc<Comma<ExprL>>> ")" => Expr::Call(n, args),
174+
<c:CallExpr_> => Expr::Call(c.0, c.1),
174175
"[" <elems:WithLoc<Comma<ExprL>>> "]" => Expr::Array(elems),
175176
"[" <default:ExprL> ";" <size:ExprL> "]" => Expr::DefaultArray { default_value: Box::new(default), size: Box::new(size) },
176177
<arr:LeafExprL> "[" <idx:ExprL> "]" => Expr::Index(Box::new(arr), Box::new(idx)),
@@ -191,6 +192,11 @@ LeafExpr: Expr = {
191192

192193
}
193194

195+
//CallExprL = WithLoc<CallExpr>;
196+
CallExpr_: (WithLoc<String>, WithLoc<Vec<WithLoc<Expr>>>) = {
197+
<n:NameL> "(" <args:WithLoc<Comma<ExprL>>> ")" => (n, args),
198+
}
199+
194200
BExpr0OpL = WithLoc<BExpr0Op>;
195201
BExpr0Op: BinOpcode = {
196202
"||" => BinOpcode::Or,

src/tc.rs

Lines changed: 99 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,11 @@ impl TypeChecker {
753753
}
754754

755755
}
756+
Stmt::Call(name, args) => {
757+
// TODO: typecheck that this is unit
758+
let retty = self.tc_call(name, args);
759+
None
760+
}
756761
Stmt::IfElse {
757762
cond,
758763
if_branch,
@@ -906,93 +911,8 @@ impl TypeChecker {
906911
}
907912
}
908913
Expr::Call(name, args) => {
909-
// TODO: Typecheck that function exists
910-
let (_, params, retty) = &self.f_ty_ctx[name.as_str()];
911-
let retty = (**retty).clone();
912-
913-
let params_len = params.len();
914-
let args_len = args.len();
915-
916-
if params_len != args_len {
917-
let [color_name, color1, color2] = colors();
918-
919-
Report::build(ariadne::ReportKind::Error, &self.src_file, exp.loc.start)
920-
.with_message::<&str>("argument count mismatch")
921-
.with_label(
922-
Label::new(
923-
(&self.src_file, args.loc.start..args.loc.end)
924-
)
925-
.with_message(
926-
format!("call to function {} with {} arguments", name.as_str().fg(color_name), args_len.to_string().fg(color1))
927-
)
928-
.with_color(color1)
929-
)
930-
.with_label(
931-
Label::new(
932-
(&self.src_file, params.loc.start..params.loc.end)
933-
)
934-
.with_message(
935-
format!("function {} has {} parameters", name.as_str().fg(color_name), params_len.to_string().fg(color2))
936-
)
937-
.with_color(color2)
938-
)
939-
.with_note(
940-
format!("function calls must provide the same number of arguments as the function expects")
941-
)
942-
.finish()
943-
.print((&self.src_file, Source::from(self.src_content.clone())))
944-
.unwrap();
945-
946-
self.errors.add(
947-
format!("argument count mismatch for call to `{}`: {} args given but function expects {}", name, args_len, params_len),
948-
exp.loc,
949-
);
950-
}
951-
952-
// let param_tys = params.iter().map(|p| p.1.clone()).collect::<Vec<_>>();
953-
954-
params.elem.clone().into_iter().zip(args.iter_mut()).for_each(|((param_v, param_t), arg)| {
955-
let arg_t = self.tc_exp(arg);
956-
957-
if arg_t != *param_t {
958-
let [a, b] = colors();
959-
960-
self.report("argument type mismatch", arg.loc.start)
961-
.with_label(
962-
Label::new(
963-
(&self.src_file, arg.loc.start..arg.loc.end)
964-
)
965-
.with_message(
966-
format!("this expression has type {}", arg_t.to_string().fg(a))
967-
)
968-
.with_color(a)
969-
)
970-
.with_label(
971-
Label::new(
972-
(&self.src_file, param_v.loc.start..param_t.loc.end)
973-
)
974-
.with_message(
975-
format!("this parameter has type {}", param_t.elem.to_string().fg(b))
976-
)
977-
.with_color(b)
978-
)
979-
.with_note(
980-
format!(
981-
"the types of {} and respective {} must match in a call expression",
982-
"arguments".fg(a),
983-
"parameters".fg(b)
984-
)
985-
)
986-
.finish()
987-
.print((&self.src_file, Source::from(self.src_content.clone())))
988-
.unwrap();
989-
990-
self.errors.add(
991-
format!("argument type mismatch for call to `{}`: expected type `{}` got type `{}`", name, param_t, arg_t),
992-
arg.loc,
993-
);
994-
}
995-
});
914+
let retty = self.tc_call(name, args);
915+
// TODO: Typecheck this is non-unit
996916

997917
retty
998918
}
@@ -1305,6 +1225,98 @@ impl TypeChecker {
13051225
exp.set_type_loc(&t);
13061226
t
13071227
}
1228+
1229+
pub fn tc_call(&mut self, name: &mut WithLoc<String>, args: &mut WithLoc<Vec<WithLoc<Expr>>>) -> Type {
1230+
// TODO: Typecheck that function exists
1231+
let (_, params, retty) = &self.f_ty_ctx[name.as_str()];
1232+
let retty = (**retty).clone();
1233+
1234+
let params_len = params.len();
1235+
let args_len = args.len();
1236+
1237+
if params_len != args_len {
1238+
let [color_name, color1, color2] = colors();
1239+
1240+
Report::build(ariadne::ReportKind::Error, &self.src_file, args.loc.start)
1241+
.with_message::<&str>("argument count mismatch")
1242+
.with_label(
1243+
Label::new(
1244+
(&self.src_file, args.loc.start..args.loc.end)
1245+
)
1246+
.with_message(
1247+
format!("call to function {} with {} arguments", name.as_str().fg(color_name), args_len.to_string().fg(color1))
1248+
)
1249+
.with_color(color1)
1250+
)
1251+
.with_label(
1252+
Label::new(
1253+
(&self.src_file, params.loc.start..params.loc.end)
1254+
)
1255+
.with_message(
1256+
format!("function {} has {} parameters", name.as_str().fg(color_name), params_len.to_string().fg(color2))
1257+
)
1258+
.with_color(color2)
1259+
)
1260+
.with_note(
1261+
format!("function calls must provide the same number of arguments as the function expects")
1262+
)
1263+
.finish()
1264+
.print((&self.src_file, Source::from(self.src_content.clone())))
1265+
.unwrap();
1266+
1267+
self.errors.add(
1268+
format!("argument count mismatch for call to `{}`: {} args given but function expects {}", name, args_len, params_len),
1269+
args.loc,
1270+
);
1271+
}
1272+
1273+
// let param_tys = params.iter().map(|p| p.1.clone()).collect::<Vec<_>>();
1274+
1275+
params.elem.clone().into_iter().zip(args.iter_mut()).for_each(|((param_v, param_t), arg)| {
1276+
let arg_t = self.tc_exp(arg);
1277+
1278+
if arg_t != *param_t {
1279+
let [a, b] = colors();
1280+
1281+
self.report("argument type mismatch", arg.loc.start)
1282+
.with_label(
1283+
Label::new(
1284+
(&self.src_file, arg.loc.start..arg.loc.end)
1285+
)
1286+
.with_message(
1287+
format!("this expression has type {}", arg_t.to_string().fg(a))
1288+
)
1289+
.with_color(a)
1290+
)
1291+
.with_label(
1292+
Label::new(
1293+
(&self.src_file, param_v.loc.start..param_t.loc.end)
1294+
)
1295+
.with_message(
1296+
format!("this parameter has type {}", param_t.elem.to_string().fg(b))
1297+
)
1298+
.with_color(b)
1299+
)
1300+
.with_note(
1301+
format!(
1302+
"the types of {} and respective {} must match in a call expression",
1303+
"arguments".fg(a),
1304+
"parameters".fg(b)
1305+
)
1306+
)
1307+
.finish()
1308+
.print((&self.src_file, Source::from(self.src_content.clone())))
1309+
.unwrap();
1310+
1311+
self.errors.add(
1312+
format!("argument type mismatch for call to `{}`: expected type `{}` got type `{}`", name, param_t, arg_t),
1313+
arg.loc,
1314+
);
1315+
}
1316+
});
1317+
1318+
retty
1319+
}
13081320
}
13091321

13101322
// Helper to generate a bunch of colors

0 commit comments

Comments
 (0)