Skip to content

Commit 2c9842a

Browse files
committed
feat(ast): allow differing function implementations
`FunctionDeclaration` has an `implementation` property, which is an enum of different implementation sources. Currently only `Body` (existing behaviour where the implementation is within a set of curly brackets) and `None` (basic support for `extern` functions) are supported.
1 parent c890597 commit 2c9842a

9 files changed

Lines changed: 145 additions & 5 deletions

src/ir/ast.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,17 @@ mod function {
115115
#[derive(Clone, Debug)]
116116
pub struct FunctionDeclaration {
117117
pub signature: FunctionSignature,
118-
pub body: BlockId,
118+
pub implementation: FunctionImplementation,
119+
}
120+
121+
/// The implementation of a function.
122+
#[derive(Clone, Debug)]
123+
pub enum FunctionImplementation {
124+
/// No implementation has been provided for the function, although one may be added by a
125+
/// later stage.
126+
None,
127+
/// Implementation exists within the provided [`Block`].
128+
Body(BlockId),
119129
}
120130

121131
#[derive(Clone, Debug)]

src/main.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,5 +499,19 @@ mod test {
499499
10
500500
);
501501
}
502+
503+
#[test]
504+
#[should_panic(expected = "cannot generate HIR for function without implementation")]
505+
fn extern_function_no_implementation() {
506+
run(r#"extern fn something() -> bool;
507+
508+
fn main() -> u8 {
509+
if something() {
510+
3
511+
} else {
512+
7
513+
}
514+
}"#);
515+
}
502516
}
503517
}

src/passes/ast_gen.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl<'ctx, 'cst> Pass<'ctx, 'cst> for AstGen<'ctx> {
2828
ast_gen.lower_trait_implementation(trait_implementation);
2929
}
3030
cst::Item::ExternalFunction(external_function) => {
31-
todo!();
31+
ast_gen.lower_external_function(external_function);
3232
}
3333
}
3434
}
@@ -48,7 +48,7 @@ impl<'ctx> AstGen<'ctx> {
4848
fn lower_function(&mut self, function: &cst::FunctionDeclaration) -> FunctionId {
4949
let function_declaration = FunctionDeclaration {
5050
signature: self.lower_function_signature(&function.signature),
51-
body: self.lower_block(&function.body),
51+
implementation: FunctionImplementation::Body(self.lower_block(&function.body)),
5252
};
5353
self.ast.function_declarations.insert(function_declaration)
5454
}
@@ -59,6 +59,16 @@ impl<'ctx> AstGen<'ctx> {
5959
id
6060
}
6161

62+
fn lower_external_function(&mut self, external_function: &cst::ExternalFunction) -> FunctionId {
63+
let signature = self.lower_function_signature(&external_function.signature);
64+
let id = self.ast.function_declarations.insert(FunctionDeclaration {
65+
signature,
66+
implementation: FunctionImplementation::None,
67+
});
68+
self.ast.item_functions.push(id);
69+
id
70+
}
71+
6272
fn lower_function_signature(
6373
&mut self,
6474
signature: &cst::FunctionSignature,
@@ -411,4 +421,21 @@ mod test {
411421
pass.lower_trait_implementation(&parse(source));
412422
assert_debug_snapshot!(name, pass.ast.trait_implementations[0], source);
413423
}
424+
425+
#[rstest]
426+
#[case("external_function_simple", "extern fn some_function();")]
427+
#[case(
428+
"external_function_parameters",
429+
"extern fn some_function(parameter: u8);"
430+
)]
431+
#[case("external_function_return", "extern fn some_function() -> bool;")]
432+
#[case(
433+
"external_function_full",
434+
"extern fn some_function(parameter: u8) -> bool;"
435+
)]
436+
fn external_function(#[case] name: &str, mut ctx: Ctx, #[case] source: &'static str) {
437+
let mut pass = AstGen::new(&mut ctx);
438+
let id = pass.lower_external_function(&parse(source));
439+
assert_debug_snapshot!(name, pass.ast[id], source);
440+
}
414441
}

src/passes/hir_gen.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,14 @@ impl<'ctx, 'ast> HirGen<'ctx, 'ast> {
190190
};
191191

192192
// Lower the body of the function.
193-
let entry = self.lower_block(ctx, &self.ast[function.body], function_scope)?;
193+
let entry = match &function.implementation {
194+
ast::FunctionImplementation::Body(body) => {
195+
self.lower_block(ctx, &self.ast[*body], function_scope)?
196+
}
197+
ast::FunctionImplementation::None => {
198+
panic!("cannot generate HIR for function without implementation")
199+
}
200+
};
194201

195202
Ok(self.hir.functions.insert(Function {
196203
binding,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
source: src/passes/ast_gen.rs
3+
expression: "extern fn some_function(parameter: u8) -> bool;"
4+
---
5+
FunctionDeclaration {
6+
signature: FunctionSignature {
7+
name: StringId(
8+
0,
9+
),
10+
parameters: [
11+
FunctionParameter {
12+
name: StringId(
13+
1,
14+
),
15+
ty: AstTypeId(
16+
0,
17+
),
18+
},
19+
],
20+
return_ty: Some(
21+
AstTypeId(
22+
1,
23+
),
24+
),
25+
},
26+
implementation: None,
27+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
source: src/passes/ast_gen.rs
3+
expression: "extern fn some_function(parameter: u8);"
4+
---
5+
FunctionDeclaration {
6+
signature: FunctionSignature {
7+
name: StringId(
8+
0,
9+
),
10+
parameters: [
11+
FunctionParameter {
12+
name: StringId(
13+
1,
14+
),
15+
ty: AstTypeId(
16+
0,
17+
),
18+
},
19+
],
20+
return_ty: None,
21+
},
22+
implementation: None,
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
source: src/passes/ast_gen.rs
3+
expression: extern fn some_function() -> bool;
4+
---
5+
FunctionDeclaration {
6+
signature: FunctionSignature {
7+
name: StringId(
8+
0,
9+
),
10+
parameters: [],
11+
return_ty: Some(
12+
AstTypeId(
13+
0,
14+
),
15+
),
16+
},
17+
implementation: None,
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
source: src/passes/ast_gen.rs
3+
expression: extern fn some_function();
4+
---
5+
FunctionDeclaration {
6+
signature: FunctionSignature {
7+
name: StringId(
8+
0,
9+
),
10+
parameters: [],
11+
return_ty: None,
12+
},
13+
implementation: None,
14+
}

src/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ mod test {
351351
parameters: Vec::new(),
352352
return_ty: None,
353353
},
354-
body: block_id,
354+
implementation: ast::FunctionImplementation::Body(block_id),
355355
});
356356
// Add function as top level function.
357357
ast.item_functions.push(function_id);

0 commit comments

Comments
 (0)