rue_compiler/compile/item/
function.rs1use log::debug;
2use rue_ast::{AstFunctionItem, AstNode};
3use rue_diagnostic::DiagnosticKind;
4use rue_hir::{Declaration, FunctionKind, FunctionSymbol, ParameterSymbol, Symbol, SymbolId};
5use rue_types::{FunctionType, Type};
6
7use crate::{
8 Compiler, CompletionContext, SyntaxItem, SyntaxItemKind, compile_block,
9 compile_generic_parameters, compile_type, create_binding,
10};
11
12pub fn declare_function(ctx: &mut Compiler, function: &AstFunctionItem) -> SymbolId {
13 ctx.syntax_map_mut().add_item(SyntaxItem::new(
14 SyntaxItemKind::CompletionContext(CompletionContext::Item),
15 function.syntax().text_range(),
16 ));
17
18 let symbol = ctx.alloc_symbol(Symbol::Unresolved);
19
20 if function.test().is_some() {
21 ctx.add_test(symbol);
22 }
23
24 ctx.push_declaration(Declaration::Symbol(symbol));
25
26 let scope = ctx.alloc_child_scope();
27
28 let vars = if let Some(generic_parameters) = function.generic_parameters() {
29 compile_generic_parameters(ctx, scope, &generic_parameters)
30 } else {
31 vec![]
32 };
33
34 let range = function.syntax().text_range();
35 ctx.push_scope(scope, range.start());
36
37 let return_type = if let Some(return_type) = function.return_type() {
38 compile_type(ctx, &return_type)
39 } else {
40 ctx.builtins().nil.ty
41 };
42
43 let mut parameters = Vec::new();
44 let mut param_types = Vec::new();
45 let mut nil_terminated = true;
46
47 let len = function.parameters().count();
48
49 for (i, parameter) in function.parameters().enumerate() {
50 let is_spread = if let Some(spread) = parameter.spread() {
51 if i == len - 1 {
52 true
53 } else {
54 ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
55 false
56 }
57 } else {
58 false
59 };
60
61 if is_spread {
62 nil_terminated = false;
63 }
64
65 let symbol = ctx.alloc_symbol(Symbol::Unresolved);
66
67 ctx.push_declaration(Declaration::Symbol(symbol));
68
69 let ty = if let Some(ty) = parameter.ty() {
70 compile_type(ctx, &ty)
71 } else {
72 debug!("Unresolved function parameter type");
73 ctx.builtins().unresolved.ty
74 };
75
76 *ctx.symbol_mut(symbol) = Symbol::Parameter(ParameterSymbol { name: None, ty });
77
78 param_types.push(ty);
79 parameters.push(symbol);
80
81 ctx.pop_declaration();
82 }
83
84 ctx.pop_scope(range.end());
85
86 let body = ctx.builtins().unresolved.hir;
87
88 let ty = ctx.alloc_type(Type::Function(FunctionType {
89 params: param_types,
90 nil_terminated,
91 ret: return_type,
92 }));
93
94 *ctx.symbol_mut(symbol) = Symbol::Function(FunctionSymbol {
95 name: function.name(),
96 ty,
97 scope,
98 vars,
99 parameters,
100 nil_terminated,
101 return_type,
102 body,
103 kind: if function.inline().is_some() {
104 FunctionKind::Inline
105 } else if function.extern_kw().is_some() {
106 FunctionKind::Sequential
107 } else {
108 FunctionKind::BinaryTree
109 },
110 });
111
112 if let Some(name) = function.name() {
113 if ctx.last_scope().symbol(name.text()).is_some() {
114 ctx.diagnostic(
115 &name,
116 DiagnosticKind::DuplicateSymbol(name.text().to_string()),
117 );
118 } else {
119 ctx.last_scope_mut().insert_symbol(
120 name.text().to_string(),
121 symbol,
122 function.export().is_some(),
123 );
124 }
125
126 ctx.declaration_span(Declaration::Symbol(symbol), name.text_range());
127 }
128
129 ctx.pop_declaration();
130
131 symbol
132}
133
134pub fn compile_function(ctx: &mut Compiler, function: &AstFunctionItem, symbol: SymbolId) {
135 ctx.push_declaration(Declaration::Symbol(symbol));
136
137 let Symbol::Function(FunctionSymbol {
138 scope,
139 parameters,
140 return_type,
141 ..
142 }) = ctx.symbol(symbol).clone()
143 else {
144 unreachable!();
145 };
146
147 let range = function.syntax().text_range();
148 ctx.push_scope(scope, range.start());
149
150 for (i, parameter) in function.parameters().enumerate() {
151 let symbol = parameters[i];
152
153 ctx.push_declaration(Declaration::Symbol(symbol));
154
155 if let Some(binding) = parameter.binding() {
156 create_binding(ctx, symbol, &binding);
157 }
158
159 ctx.pop_declaration();
160 }
161
162 let resolved_body = if let Some(body) = function.body() {
163 let value = compile_block(
164 ctx,
165 &body,
166 true,
167 Some(return_type),
168 function.return_type().is_some(),
169 );
170 ctx.assign_type(body.syntax(), value.ty, return_type);
171 value
172 } else {
173 debug!("Unresolved function body");
174 ctx.builtins().unresolved.clone()
175 };
176
177 ctx.pop_scope(range.end());
178
179 let Symbol::Function(FunctionSymbol { body, .. }) = ctx.symbol_mut(symbol) else {
180 unreachable!();
181 };
182
183 *body = resolved_body.hir;
184
185 ctx.pop_declaration();
186}