Skip to main content

luaur_ast/methods/
parser_parse_function_body.rs

1use 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}