1mod cursor;
2mod expressions;
3mod format;
4mod lexer;
5mod lint;
6mod statements;
7mod symbols;
8
9use std::collections::{HashMap, HashSet};
10
11use rt_format::{NoNamedArguments, ParsedFormat};
12
13use crate::ValueType;
14use crate::builtins::{
15 BuiltinFunction, builtin_namespace_hint, default_host_callable, is_builtin_namespace,
16 resolve_builtin_namespace_call,
17};
18use crate::compiler::source_map::{SourceId, Span};
19
20use self::lexer::{Lexer, ParserFormatArg, Token, TokenKind, is_ident_continue, is_ident_start};
21use self::symbols::is_virtual_host_namespace_spec;
22use super::{
23 ParseError, ReplLocalBinding, STDLIB_PRINT_ARITY, STDLIB_PRINT_NAME,
24 ir::{
25 AssignmentKind, ClosureExpr, Expr, FunctionDecl, FunctionImpl, FunctionParam, LocalSlot,
26 MatchPattern, MatchTypePattern, Stmt, StructDecl, TypeSchema,
27 },
28};
29
30pub trait ParserDialect {
31 fn is_import_keyword(&self, _ident: &str) -> bool {
32 false
33 }
34
35 fn is_from_keyword(&self, _ident: &str) -> bool {
36 false
37 }
38
39 fn is_fn_alias_keyword(&self, _ident: &str) -> bool {
40 false
41 }
42
43 fn is_let_alias_keyword(&self, _ident: &str) -> bool {
44 false
45 }
46
47 fn allow_import_stmt(&self) -> bool {
48 false
49 }
50
51 fn allow_return_stmt(&self) -> bool {
52 false
53 }
54
55 fn allow_require_declaration(&self) -> bool {
56 false
57 }
58
59 fn allow_typeof_operator(&self) -> bool {
60 false
61 }
62
63 fn allow_arrow_closure(&self) -> bool {
64 false
65 }
66
67 fn allow_dotted_call(&self) -> bool {
68 false
69 }
70
71 fn allow_namespace_path_separator(&self) -> bool {
72 true
73 }
74
75 fn allow_let_mut_binding(&self) -> bool {
76 false
77 }
78
79 fn allow_macro_calls(&self) -> bool {
80 false
81 }
82
83 fn allow_plus_equal_operator(&self) -> bool {
84 false
85 }
86
87 fn allow_increment_operator(&self) -> bool {
88 false
89 }
90
91 fn allow_parenthesized_for_loop(&self) -> bool {
92 false
93 }
94
95 fn allow_for_in_loop(&self) -> bool {
96 false
97 }
98}
99
100pub(super) fn lint_trailing_function_return_semicolons(
101 source: &str,
102 source_id: SourceId,
103 dialect: &'static dyn ParserDialect,
104) -> Result<Vec<ParseError>, ParseError> {
105 lint::lint_trailing_function_return_semicolons(source, source_id, dialect)
106}
107
108pub(super) fn format_source(
109 source: &str,
110 dialect: &'static dyn ParserDialect,
111) -> Result<String, ParseError> {
112 format::format_source(source, dialect)
113}
114
115pub(super) struct Parser {
116 tokens: Vec<Token>,
117 pos: usize,
118 locals: HashMap<String, LocalSlot>,
119 named_local_bindings: Vec<(String, LocalSlot)>,
120 next_local: LocalSlot,
121 functions: HashMap<String, FunctionDecl>,
122 function_list: Vec<FunctionDecl>,
123 function_impls: HashMap<u16, FunctionImpl>,
124 next_function: u16,
125 closure_scopes: Vec<HashMap<String, LocalSlot>>,
126 closure_capture_contexts: Vec<ClosureCaptureContext>,
127 struct_schemas: HashMap<String, StructDecl>,
128 schema_reference_sites: Vec<(String, usize, usize, Span)>,
129 active_type_params: Vec<HashSet<String>>,
130 unknown_type_spans: Vec<Span>,
131 allow_implicit_externs: bool,
132 allow_implicit_semicolons: bool,
133 enforce_mutable_bindings: bool,
134 dialect: &'static dyn ParserDialect,
135 loop_depth: usize,
136 function_body_depth: usize,
137 host_namespace_aliases: HashMap<String, String>,
138 direct_host_call_aliases: HashMap<String, String>,
139 direct_host_wildcard_imports: HashSet<String>,
140 mutable_locals: Vec<bool>,
141 borrowed_map_iter_locals: Vec<LocalSlot>,
142 local_schemas: HashMap<LocalSlot, TypeSchema>,
143}
144
145struct ClosureCaptureContext {
146 by_name: HashMap<String, LocalSlot>,
147 capture_copies: Vec<(LocalSlot, LocalSlot)>,
148}
149
150impl Parser {
151 pub(super) fn new(
152 source: &str,
153 source_id: SourceId,
154 allow_implicit_externs: bool,
155 allow_implicit_semicolons: bool,
156 enforce_mutable_bindings: bool,
157 dialect: &'static dyn ParserDialect,
158 ) -> Result<Self, ParseError> {
159 let mut lexer = Lexer::new(source, source_id, dialect);
160 let mut tokens = Vec::new();
161 loop {
162 let token = lexer.next_token()?;
163 let is_eof = matches!(token.kind, TokenKind::Eof);
164 tokens.push(token);
165 if is_eof {
166 break;
167 }
168 }
169 Ok(Self {
170 tokens,
171 pos: 0,
172 locals: HashMap::new(),
173 named_local_bindings: Vec::new(),
174 next_local: 0,
175 functions: HashMap::new(),
176 function_list: Vec::new(),
177 function_impls: HashMap::new(),
178 next_function: 0,
179 closure_scopes: Vec::new(),
180 closure_capture_contexts: Vec::new(),
181 struct_schemas: HashMap::new(),
182 schema_reference_sites: Vec::new(),
183 active_type_params: Vec::new(),
184 unknown_type_spans: Vec::new(),
185 allow_implicit_externs,
186 allow_implicit_semicolons,
187 enforce_mutable_bindings,
188 dialect,
189 loop_depth: 0,
190 function_body_depth: 0,
191 host_namespace_aliases: HashMap::new(),
192 direct_host_call_aliases: HashMap::new(),
193 direct_host_wildcard_imports: HashSet::new(),
194 mutable_locals: Vec::new(),
195 borrowed_map_iter_locals: Vec::new(),
196 local_schemas: HashMap::new(),
197 })
198 }
199
200 pub(super) fn new_with_predeclared_locals(
201 source: &str,
202 source_id: SourceId,
203 allow_implicit_externs: bool,
204 allow_implicit_semicolons: bool,
205 enforce_mutable_bindings: bool,
206 dialect: &'static dyn ParserDialect,
207 predeclared_locals: &[ReplLocalBinding],
208 ) -> Result<Self, ParseError> {
209 let mut parser = Self::new(
210 source,
211 source_id,
212 allow_implicit_externs,
213 allow_implicit_semicolons,
214 enforce_mutable_bindings,
215 dialect,
216 )?;
217 for binding in predeclared_locals {
218 parser.predeclare_local(binding)?;
219 }
220 Ok(parser)
221 }
222
223 pub(super) fn parse_program(&mut self) -> Result<Vec<Stmt>, ParseError> {
224 let mut stmts = Vec::new();
225 while !self.check(&TokenKind::Eof) {
226 stmts.push(self.parse_stmt()?);
227 }
228 self.validate_schema_reference_sites()?;
229 Ok(stmts)
230 }
231
232 pub(super) fn local_count(&self) -> usize {
233 self.next_local as usize
234 }
235
236 pub(super) fn function_decls(&self) -> Vec<FunctionDecl> {
237 self.function_list.clone()
238 }
239
240 pub(super) fn function_impls(&self) -> HashMap<u16, FunctionImpl> {
241 self.function_impls.clone()
242 }
243
244 pub(super) fn local_bindings(&self) -> Vec<(String, LocalSlot)> {
245 let mut locals = self.named_local_bindings.clone();
246 locals.sort_by_key(|(_, index)| *index);
247 locals
248 }
249
250 pub(super) fn local_bindings_with_mutability(&self) -> Vec<ReplLocalBinding> {
251 let mut locals = self
252 .locals
253 .iter()
254 .map(|(name, index)| ReplLocalBinding {
255 name: name.clone(),
256 mutable: self.is_local_slot_mutable(*index),
257 schema: None,
258 optional: false,
259 })
260 .collect::<Vec<_>>();
261 locals.sort_by_key(|binding| self.locals.get(&binding.name).copied().unwrap_or(0));
262 locals
263 }
264
265 pub(super) fn struct_schemas(&self) -> HashMap<String, StructDecl> {
266 self.struct_schemas.clone()
267 }
268
269 pub(super) fn unknown_type_spans(&self) -> Vec<Span> {
270 self.unknown_type_spans.clone()
271 }
272
273 fn validate_schema_reference_sites(&self) -> Result<(), ParseError> {
274 for (name, arg_count, line, span) in &self.schema_reference_sites {
275 let Some(decl) = self.struct_schemas.get(name) else {
276 return Err(ParseError {
277 span: Some(*span),
278 code: None,
279 line: *line,
280 message: format!("unknown struct schema '{name}'"),
281 });
282 };
283 if decl.type_params.len() != *arg_count {
284 return Err(ParseError {
285 span: Some(*span),
286 code: None,
287 line: *line,
288 message: format!(
289 "struct schema '{name}' expects {} type arguments, got {}",
290 decl.type_params.len(),
291 arg_count
292 ),
293 });
294 }
295 if self.struct_schemas.contains_key(name) {
296 continue;
297 }
298 }
299 Ok(())
300 }
301
302 fn push_active_type_params(&mut self, params: &[String]) {
303 self.active_type_params
304 .push(params.iter().cloned().collect::<HashSet<_>>());
305 }
306
307 fn pop_active_type_params(&mut self) {
308 self.active_type_params.pop();
309 }
310
311 fn is_active_type_param(&self, name: &str) -> bool {
312 self.active_type_params
313 .iter()
314 .rev()
315 .any(|params| params.contains(name))
316 }
317
318 fn parse_type_params(
319 &mut self,
320 owner: &str,
321 owner_name: &str,
322 ) -> Result<Vec<String>, ParseError> {
323 if !self.check(&TokenKind::Less) {
324 return Ok(Vec::new());
325 }
326
327 self.expect(&TokenKind::Less, "expected '<' before type parameters")?;
328 let mut params = Vec::new();
329 let mut seen = HashSet::new();
330 loop {
331 let param = self.expect_ident("expected type parameter name")?;
332 if !seen.insert(param.clone()) {
333 return Err(ParseError {
334 span: Some(self.current_span()),
335 code: None,
336 line: self.current_line(),
337 message: format!(
338 "duplicate type parameter '{param}' in {owner} '{owner_name}'"
339 ),
340 });
341 }
342 params.push(param);
343 if self.match_kind(&TokenKind::Comma) {
344 continue;
345 }
346 break;
347 }
348 self.expect(&TokenKind::Greater, "expected '>' after type parameters")?;
349 Ok(params)
350 }
351
352 fn parse_turbofish_type_args(&mut self) -> Result<Vec<TypeSchema>, ParseError> {
353 if !self.check_path_separator() || !self.check_kind_at(self.pos + 2, &TokenKind::Less) {
354 return Ok(Vec::new());
355 }
356
357 self.match_path_separator();
358 self.expect(&TokenKind::Less, "expected '<' after '::' in turbofish")?;
359 let mut type_args = Vec::new();
360 loop {
361 type_args.push(self.parse_declared_type_schema()?);
362 if self.match_kind(&TokenKind::Comma) {
363 continue;
364 }
365 break;
366 }
367 self.expect(&TokenKind::Greater, "expected '>' after type arguments")?;
368 Ok(type_args)
369 }
370
371 fn function_param_names(params: &[FunctionParam]) -> Vec<String> {
372 params.iter().map(|param| param.name.clone()).collect()
373 }
374}