Skip to main content

luaur_ast/methods/
parser_parse_interp_string.rs

1use crate::records::ast_array::AstArray;
2use crate::records::ast_expr::AstExpr;
3use crate::records::ast_expr_interp_string::AstExprInterpString;
4use crate::records::cst_expr_interp_string::CstExprInterpString;
5use crate::records::lexer::Lexer;
6use crate::records::location::Location;
7use crate::records::parser::Parser;
8use crate::records::position::Position;
9use core::ffi::c_char;
10use luaur_common::macros::luau_assert::LUAU_ASSERT;
11
12impl Parser {
13    pub fn parse_interp_string(&mut self) -> *mut AstExpr {
14        let mut strings = crate::records::temp_vector::TempVector::new(&mut self.scratch_string);
15        let mut source_strings =
16            crate::records::temp_vector::TempVector::new(&mut self.scratch_string_2);
17        let mut string_positions =
18            crate::records::temp_vector::TempVector::new(&mut self.scratch_position);
19        let mut expressions = crate::records::temp_vector::TempVector::new(&mut self.scratch_expr);
20
21        let start_location = self.lexer.current().location;
22        let mut end_location = start_location;
23
24        loop {
25            let current_lexeme = *self.lexer.current();
26            LUAU_ASSERT!(
27                current_lexeme.r#type == crate::records::lexeme::Type::InterpStringBegin
28                    || current_lexeme.r#type == crate::records::lexeme::Type::InterpStringMid
29                    || current_lexeme.r#type == crate::records::lexeme::Type::InterpStringEnd
30                    || current_lexeme.r#type == crate::records::lexeme::Type::InterpStringSimple
31            );
32
33            end_location = current_lexeme.location;
34
35            let length = current_lexeme.get_length() as usize;
36            let data_ptr = unsafe { current_lexeme.data.data } as *const c_char;
37            let bytes = unsafe { core::slice::from_raw_parts(data_ptr as *const u8, length) };
38
39            if self.options.store_cst_data {
40                let source_string = self.copy_bytes(bytes);
41                source_strings.push_back(source_string);
42                string_positions.push_back(current_lexeme.location.begin);
43            }
44
45            let mut data = bytes.to_vec();
46            if !Lexer::fixup_quoted_bytes(&mut data) {
47                self.next_lexeme();
48                return self.report_expr_error(
49                    Location::new(start_location.begin, end_location.end),
50                    AstArray {
51                        data: core::ptr::null_mut(),
52                        size: 0,
53                    },
54                    format_args!("Interpolated string literal contains malformed escape sequence"),
55                ) as *mut AstExpr;
56            }
57
58            let chars = self.copy_bytes(&data);
59            self.next_lexeme();
60            strings.push_back(chars);
61
62            if current_lexeme.r#type == crate::records::lexeme::Type::InterpStringEnd
63                || current_lexeme.r#type == crate::records::lexeme::Type::InterpStringSimple
64            {
65                break;
66            }
67
68            let mut error_while_checking = false;
69
70            match self.lexer.current().r#type {
71                crate::records::lexeme::Type::InterpStringMid
72                | crate::records::lexeme::Type::InterpStringEnd => {
73                    error_while_checking = true;
74                    self.next_lexeme();
75                    expressions.push_back(self.report_expr_error(
76                        end_location,
77                        AstArray {
78                            data: core::ptr::null_mut(),
79                            size: 0,
80                        },
81                        format_args!(
82                            "Malformed interpolated string, expected expression inside '{{}}'"
83                        ),
84                    ) as *mut AstExpr);
85                }
86                crate::records::lexeme::Type::BrokenString => {
87                    error_while_checking = true;
88                    self.next_lexeme();
89                    expressions.push_back(self.report_expr_error(
90                        end_location,
91                        AstArray {
92                            data: core::ptr::null_mut(),
93                            size: 0,
94                        },
95                        format_args!("Malformed interpolated string; did you forget to add a '`'?"),
96                    ) as *mut AstExpr);
97                }
98                _ => {
99                    expressions.push_back(self.parse_expr_i32(0));
100                }
101            }
102
103            if error_while_checking {
104                break;
105            }
106
107            match self.lexer.current().r#type {
108                crate::records::lexeme::Type::InterpStringBegin
109                | crate::records::lexeme::Type::InterpStringMid
110                | crate::records::lexeme::Type::InterpStringEnd => {}
111                crate::records::lexeme::Type::BrokenInterpDoubleBrace => {
112                    self.next_lexeme();
113                    return self.report_expr_error(
114                        end_location,
115                        AstArray {
116                            data: core::ptr::null_mut(),
117                            size: 0,
118                        },
119                        format_args!("Double braces are not permitted within interpolated strings; did you mean '\\{{'?"),
120                    ) as *mut AstExpr;
121                }
122                crate::records::lexeme::Type::BrokenString | crate::records::lexeme::Type::Eof => {
123                    if self.lexer.current().r#type == crate::records::lexeme::Type::BrokenString {
124                        self.next_lexeme();
125                    }
126                    let strings_array = self.copy_temp_vector_t(&strings);
127                    let expressions_array = self.copy_temp_vector_t(&expressions);
128                    let node = unsafe {
129                        (*self.allocator).alloc(AstExprInterpString::new(
130                            Location::new(start_location.begin, self.lexer.previous_location().end),
131                            strings_array,
132                            expressions_array,
133                        ))
134                    };
135
136                    if self.options.store_cst_data {
137                        let source_strings_array = self.copy_temp_vector_t(&source_strings);
138                        let string_positions_array = self.copy_temp_vector_t(&string_positions);
139                        let cst_node = unsafe {
140                            (*self.allocator).alloc(CstExprInterpString::new(
141                                source_strings_array,
142                                string_positions_array,
143                            ))
144                        };
145                        self.cst_node_map.try_insert(
146                            node as *mut crate::records::ast_node::AstNode,
147                            cst_node as *mut crate::records::cst_node::CstNode,
148                        );
149                    }
150
151                    if let Some(top) = self.lexer.peek_brace_stack_top() {
152                        if top == crate::enums::brace_type::BraceType::InterpolatedString {
153                            self.report_location_c_char_item(
154                                *self.lexer.previous_location(),
155                                format_args!(
156                                    "Malformed interpolated string; did you forget to add a '}}'?"
157                                ),
158                            );
159                        }
160                    } else {
161                        self.report_location_c_char_item(
162                            *self.lexer.previous_location(),
163                            format_args!(
164                                "Malformed interpolated string; did you forget to add a '`'?"
165                            ),
166                        );
167                    }
168
169                    return node as *mut AstExpr;
170                }
171                _ => {
172                    return self.report_expr_error(
173                        end_location,
174                        AstArray {
175                            data: core::ptr::null_mut(),
176                            size: 0,
177                        },
178                        format_args!(
179                            "Malformed interpolated string, got {}",
180                            self.lexer.current().to_string()
181                        ),
182                    ) as *mut AstExpr;
183                }
184            }
185        }
186
187        let strings_array = self.copy_temp_vector_t(&strings);
188        let expressions_array = self.copy_temp_vector_t(&expressions);
189        let node = unsafe {
190            (*self.allocator).alloc(AstExprInterpString::new(
191                Location::new(start_location.begin, end_location.end),
192                strings_array,
193                expressions_array,
194            ))
195        };
196
197        if self.options.store_cst_data {
198            let source_strings_array = self.copy_temp_vector_t(&source_strings);
199            let string_positions_array = self.copy_temp_vector_t(&string_positions);
200            let cst_node = unsafe {
201                (*self.allocator).alloc(CstExprInterpString::new(
202                    source_strings_array,
203                    string_positions_array,
204                ))
205            };
206            self.cst_node_map.try_insert(
207                node as *mut crate::records::ast_node::AstNode,
208                cst_node as *mut crate::records::cst_node::CstNode,
209            );
210        }
211
212        node as *mut AstExpr
213    }
214}