luaur_ast/methods/
parser_parse_function_body.rs1use crate::records::ast_array::AstArray;
2use crate::records::ast_attr::AstAttr;
3use crate::records::ast_expr_function::AstExprFunction;
4use crate::records::ast_local::AstLocal;
5use crate::records::ast_name::AstName;
6use crate::records::lexeme::Lexeme;
7use crate::records::name::Name;
8use crate::records::parser::Parser;
9
10use crate::records::ast_generic_type::AstGenericType;
11use crate::records::ast_generic_type_pack::AstGenericTypePack;
12use crate::records::ast_node::AstNode;
13use crate::records::ast_stat_block::AstStatBlock;
14use crate::records::ast_type::AstType;
15use crate::records::ast_type_pack::AstTypePack;
16use crate::records::binding::Binding;
17use crate::records::cst_expr_function::CstExprFunction;
18use crate::records::cst_node::CstNode;
19use crate::records::function::Function;
20use crate::records::lexeme::Type;
21use crate::records::location::Location;
22use crate::records::match_lexeme::MatchLexeme;
23use crate::records::position::Position;
24use crate::records::temp_vector::TempVector;
25
26impl Parser {
27 pub fn parse_function_body(
28 &mut self,
29 hasself: bool,
30 match_function: &Lexeme,
31 debugname: &AstName,
32 local_name: Option<&Name>,
33 attributes: &AstArray<*mut AstAttr>,
34 is_const: bool,
35 ) -> (*mut AstExprFunction, *mut AstLocal) {
36 let mut start = match_function.location;
37 if attributes.size > 0 {
38 start = unsafe { (**attributes.data).base.location };
39 }
40
41 let cst_node = if self.options.store_cst_data {
42 unsafe { (*self.allocator).alloc(CstExprFunction::new()) }
43 } else {
44 core::ptr::null_mut()
45 };
46
47 let (generics, generic_packs) = if !cst_node.is_null() {
48 let mut local_comma_positions = TempVector::new(&mut self.scratch_position);
49 let res = self.parse_generic_type_list(
50 false,
51 unsafe { Some(&mut (*cst_node).open_generics_position) },
52 Some(&mut local_comma_positions),
53 unsafe { Some(&mut (*cst_node).close_generics_position) },
54 );
55 unsafe {
56 (*cst_node).generics_comma_positions =
57 self.copy_temp_vector_t(&local_comma_positions);
58 }
59 res
60 } else {
61 self.parse_generic_type_list(false, None, None, None)
62 };
63
64 let match_paren = MatchLexeme::new(self.lexer.current());
65 self.expect_and_consume_char('(', "function");
66
67 self.match_recovery_stop_on_token[')' as usize] += 1;
68
69 let mut args = TempVector::new(&mut self.scratch_binding);
70
71 let mut vararg = false;
72 let mut vararg_location = Location::default();
73 let mut vararg_annotation: *mut AstTypePack = core::ptr::null_mut();
74
75 if self.lexer.current().r#type != Type(')' as i32) {
76 if !cst_node.is_null() {
77 let res = self.parse_binding_list(
78 &mut args,
79 true,
80 unsafe { &mut (*cst_node).args_comma_positions },
81 core::ptr::null_mut(),
82 unsafe { &mut (*cst_node).vararg_annotation_colon_position },
83 false,
84 );
85 vararg = res.0;
86 vararg_location = res.1;
87 vararg_annotation = res.2;
88 } else {
89 let res = self.parse_binding_list(
90 &mut args,
91 true,
92 core::ptr::null_mut(),
93 core::ptr::null_mut(),
94 core::ptr::null_mut(),
95 false,
96 );
97 vararg = res.0;
98 vararg_location = res.1;
99 vararg_annotation = res.2;
100 }
101 }
102
103 let mut arg_location: Option<Location> = None;
104 if match_paren.type_ == Type('(' as i32) && self.lexer.current().r#type == Type(')' as i32)
105 {
106 arg_location = Some(Location::new(
107 match_paren.position,
108 self.lexer.current().location.end,
109 ));
110 }
111
112 self.expect_match_and_consume(')', &match_paren, true);
113
114 self.match_recovery_stop_on_token[')' as usize] -= 1;
115
116 let typelist = self.parse_optional_return_type(if !cst_node.is_null() {
117 unsafe { Some(&mut (*cst_node).return_specifier_position) }
118 } else {
119 None
120 });
121 let mut fun_local: *mut AstLocal = core::ptr::null_mut();
122 if let Some(local_name) = local_name {
123 let binding = if luaur_common::FFlag::LuauConst2.get() {
124 Binding::new(
125 *local_name,
126 core::ptr::null_mut(),
127 Position::new(0, 0),
128 is_const,
129 )
130 } else {
131 Binding::new(
132 *local_name,
133 core::ptr::null_mut(),
134 Position::missing(),
135 false,
136 )
137 };
138 fun_local = self.push_local(&binding);
139 }
140
141 let locals_begin = self.save_locals();
142
143 let mut fun = Function::new();
144 fun.vararg = vararg;
145
146 self.function_stack.push(fun);
147
148 let (self_, vars) = self.prepare_function_arguments(&start, hasself, &args);
149
150 let body = self.parse_block();
151
152 self.function_stack.pop();
153
154 self.restore_locals(locals_begin);
155
156 let end = self.lexer.current().location;
157
158 let has_end =
159 self.expect_match_end_and_consume(Type::ReservedEnd, &MatchLexeme::new(match_function));
160 unsafe {
161 (*body).has_end = has_end;
162 }
163
164 let node = unsafe {
165 (*self.allocator).alloc(AstExprFunction::new(
166 Location::new(start.begin, end.end),
167 *attributes,
168 generics,
169 generic_packs,
170 self_,
171 vars,
172 vararg,
173 vararg_location,
174 body,
175 self.function_stack.len(),
176 *debugname,
177 typelist,
178 vararg_annotation,
179 arg_location,
180 ))
181 };
182
183 if self.options.store_cst_data {
184 unsafe {
185 (*cst_node).function_keyword_position = match_function.location.begin;
186 (*cst_node).args_annotation_colon_positions =
187 self.extract_annotation_colon_positions(&args);
188 }
189 self.cst_node_map
190 .try_insert(node as *mut AstNode, cst_node as *mut CstNode);
191 }
192
193 (node, fun_local)
194 }
195}