rue_compiler/compile/item/
function.rs1use log::debug;
2use rue_ast::{AstFunctionItem, AstNode};
3use rue_diagnostic::DiagnosticKind;
4use rue_hir::{FunctionSymbol, ParameterSymbol, Scope, Symbol, SymbolId};
5use rue_types::{FunctionType, Type};
6
7use crate::{Compiler, compile_block, compile_generic_parameters, compile_type};
8
9pub fn declare_function(ctx: &mut Compiler, function: &AstFunctionItem) -> SymbolId {
10 let scope = ctx.alloc_scope(Scope::new());
11
12 let vars = if let Some(generic_parameters) = function.generic_parameters() {
13 compile_generic_parameters(ctx, scope, &generic_parameters)
14 } else {
15 vec![]
16 };
17
18 ctx.push_scope(scope);
19
20 let return_type = if let Some(return_type) = function.return_type() {
21 compile_type(ctx, &return_type)
22 } else {
23 debug!("Unresolved function return type");
24 ctx.builtins().unresolved.ty
25 };
26
27 let mut parameters = Vec::new();
28 let mut param_types = Vec::new();
29 let mut nil_terminated = true;
30
31 let len = function.parameters().count();
32
33 for (i, parameter) in function.parameters().enumerate() {
34 let is_spread = if let Some(spread) = parameter.spread() {
35 if i == len - 1 {
36 true
37 } else {
38 ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
39 false
40 }
41 } else {
42 false
43 };
44
45 if is_spread {
46 nil_terminated = false;
47 }
48
49 let ty = if let Some(ty) = parameter.ty() {
50 compile_type(ctx, &ty)
51 } else {
52 debug!("Unresolved function parameter type");
53 ctx.builtins().unresolved.ty
54 };
55
56 let symbol = ctx.alloc_symbol(Symbol::Parameter(ParameterSymbol {
57 name: parameter.name(),
58 ty,
59 }));
60
61 if let Some(name) = parameter.name() {
62 if ctx.scope(scope).symbol(name.text()).is_some() {
63 ctx.diagnostic(
64 &name,
65 DiagnosticKind::DuplicateSymbol(name.text().to_string()),
66 );
67 }
68
69 ctx.scope_mut(scope)
70 .insert_symbol(name.text().to_string(), symbol, false);
71 }
72
73 param_types.push(ty);
74 parameters.push(symbol);
75 }
76
77 ctx.pop_scope();
78
79 let body = ctx.builtins().unresolved.hir;
80
81 let ty = ctx.alloc_type(Type::Function(FunctionType {
82 params: param_types,
83 nil_terminated,
84 ret: return_type,
85 }));
86
87 let symbol = ctx.alloc_symbol(Symbol::Function(FunctionSymbol {
88 name: function.name(),
89 ty,
90 scope,
91 vars,
92 parameters,
93 nil_terminated,
94 return_type,
95 body,
96 inline: function.inline().is_some(),
97 }));
98
99 if let Some(name) = function.name() {
100 if ctx.last_scope().symbol(name.text()).is_some() {
101 ctx.diagnostic(
102 &name,
103 DiagnosticKind::DuplicateSymbol(name.text().to_string()),
104 );
105 }
106
107 ctx.last_scope_mut().insert_symbol(
108 name.text().to_string(),
109 symbol,
110 function.export().is_some(),
111 );
112 }
113
114 symbol
115}
116
117pub fn compile_function(ctx: &mut Compiler, function: &AstFunctionItem, symbol: SymbolId) {
118 let (scope, return_type) = if let Symbol::Function(FunctionSymbol {
119 scope, return_type, ..
120 }) = ctx.symbol(symbol)
121 {
122 (*scope, *return_type)
123 } else {
124 unreachable!();
125 };
126
127 ctx.push_scope(scope);
128
129 let resolved_body = if let Some(body) = function.body() {
130 let index = ctx.mapping_checkpoint();
131 let value = compile_block(ctx, &body, true, Some(return_type));
132 ctx.assign_type(body.syntax(), value.ty, return_type);
133 ctx.revert_mappings(index);
134 value
135 } else {
136 debug!("Unresolved function body");
137 ctx.builtins().unresolved.clone()
138 };
139
140 ctx.pop_scope();
141
142 let Symbol::Function(FunctionSymbol { body, .. }) = ctx.symbol_mut(symbol) else {
143 unreachable!();
144 };
145
146 *body = resolved_body.hir;
147}