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 parsed_function_decls: HashSet<u16>,
125 next_function: u16,
126 closure_scopes: Vec<HashMap<String, LocalSlot>>,
127 closure_capture_contexts: Vec<ClosureCaptureContext>,
128 struct_schemas: HashMap<String, StructDecl>,
129 schema_reference_sites: Vec<(String, usize, usize, Span)>,
130 active_type_params: Vec<HashSet<String>>,
131 unknown_type_spans: Vec<Span>,
132 allow_implicit_externs: bool,
133 allow_implicit_semicolons: bool,
134 enforce_mutable_bindings: bool,
135 dialect: &'static dyn ParserDialect,
136 loop_depth: usize,
137 function_body_depth: usize,
138 host_namespace_aliases: HashMap<String, String>,
139 direct_host_call_aliases: HashMap<String, String>,
140 direct_host_wildcard_imports: HashSet<String>,
141 mutable_locals: Vec<bool>,
142 borrowed_map_iter_locals: Vec<LocalSlot>,
143 local_schemas: HashMap<LocalSlot, TypeSchema>,
144}
145
146struct ClosureCaptureContext {
147 by_name: HashMap<String, LocalSlot>,
148 capture_copies: Vec<(LocalSlot, LocalSlot)>,
149}
150
151impl Parser {
152 pub(super) fn new(
153 source: &str,
154 source_id: SourceId,
155 allow_implicit_externs: bool,
156 allow_implicit_semicolons: bool,
157 enforce_mutable_bindings: bool,
158 dialect: &'static dyn ParserDialect,
159 ) -> Result<Self, ParseError> {
160 let mut lexer = Lexer::new(source, source_id, dialect);
161 let mut tokens = Vec::new();
162 loop {
163 let token = lexer.next_token()?;
164 let is_eof = matches!(token.kind, TokenKind::Eof);
165 tokens.push(token);
166 if is_eof {
167 break;
168 }
169 }
170 Ok(Self {
171 tokens,
172 pos: 0,
173 locals: HashMap::new(),
174 named_local_bindings: Vec::new(),
175 next_local: 0,
176 functions: HashMap::new(),
177 function_list: Vec::new(),
178 function_impls: HashMap::new(),
179 parsed_function_decls: HashSet::new(),
180 next_function: 0,
181 closure_scopes: Vec::new(),
182 closure_capture_contexts: Vec::new(),
183 struct_schemas: HashMap::new(),
184 schema_reference_sites: Vec::new(),
185 active_type_params: Vec::new(),
186 unknown_type_spans: Vec::new(),
187 allow_implicit_externs,
188 allow_implicit_semicolons,
189 enforce_mutable_bindings,
190 dialect,
191 loop_depth: 0,
192 function_body_depth: 0,
193 host_namespace_aliases: HashMap::new(),
194 direct_host_call_aliases: HashMap::new(),
195 direct_host_wildcard_imports: HashSet::new(),
196 mutable_locals: Vec::new(),
197 borrowed_map_iter_locals: Vec::new(),
198 local_schemas: HashMap::new(),
199 })
200 }
201
202 pub(super) fn new_with_predeclared_locals(
203 source: &str,
204 source_id: SourceId,
205 allow_implicit_externs: bool,
206 allow_implicit_semicolons: bool,
207 enforce_mutable_bindings: bool,
208 dialect: &'static dyn ParserDialect,
209 predeclared_locals: &[ReplLocalBinding],
210 ) -> Result<Self, ParseError> {
211 let mut parser = Self::new(
212 source,
213 source_id,
214 allow_implicit_externs,
215 allow_implicit_semicolons,
216 enforce_mutable_bindings,
217 dialect,
218 )?;
219 for binding in predeclared_locals {
220 parser.predeclare_local(binding)?;
221 }
222 Ok(parser)
223 }
224
225 pub(super) fn parse_program(&mut self) -> Result<Vec<Stmt>, ParseError> {
226 self.predeclare_functions()?;
227 let mut stmts = Vec::new();
228 while !self.check(&TokenKind::Eof) {
229 stmts.push(self.parse_stmt()?);
230 }
231 self.validate_schema_reference_sites()?;
232 Ok(stmts)
233 }
234
235 fn predeclare_functions(&mut self) -> Result<(), ParseError> {
236 let mut index = 0usize;
237 while index < self.tokens.len() {
238 match &self.tokens[index].kind {
239 TokenKind::Fn => {
240 let line = self.tokens[index].line;
241 let Some(Token {
242 kind: TokenKind::Ident(name),
243 ..
244 }) = self.tokens.get(index + 1)
245 else {
246 index += 1;
247 continue;
248 };
249 let name = name.clone();
250 let exported =
251 index > 0 && matches!(self.tokens[index - 1].kind, TokenKind::Pub);
252 let mut cursor = index + 2;
253 let mut type_params = Vec::new();
254 if self
255 .tokens
256 .get(cursor)
257 .is_some_and(|token| matches!(token.kind, TokenKind::Less))
258 {
259 cursor += 1;
260 while let Some(token) = self.tokens.get(cursor) {
261 match &token.kind {
262 TokenKind::Ident(param) => type_params.push(param.clone()),
263 TokenKind::Greater => {
264 cursor += 1;
265 break;
266 }
267 _ => {}
268 }
269 cursor += 1;
270 }
271 }
272 if !self
273 .tokens
274 .get(cursor)
275 .is_some_and(|token| matches!(token.kind, TokenKind::LParen))
276 {
277 index += 1;
278 continue;
279 }
280 cursor += 1;
281 let mut arity = 0usize;
282 let mut angle_depth = 0usize;
283 let mut paren_depth = 1usize;
284 let mut has_param = false;
285 while let Some(token) = self.tokens.get(cursor) {
286 match token.kind {
287 TokenKind::LParen => paren_depth += 1,
288 TokenKind::RParen if paren_depth == 1 && angle_depth == 0 => {
289 if has_param {
290 arity += 1;
291 }
292 break;
293 }
294 TokenKind::RParen => paren_depth = paren_depth.saturating_sub(1),
295 TokenKind::Less => angle_depth += 1,
296 TokenKind::Greater => angle_depth = angle_depth.saturating_sub(1),
297 TokenKind::Comma if paren_depth == 1 && angle_depth == 0 => {
298 if has_param {
299 arity += 1;
300 has_param = false;
301 }
302 }
303 _ if paren_depth == 1 && angle_depth == 0 => has_param = true,
304 _ => {}
305 }
306 cursor += 1;
307 }
308 if self.functions.contains_key(&name) {
309 return Err(ParseError {
310 span: None,
311 code: None,
312 line,
313 message: format!("duplicate function '{name}'"),
314 });
315 }
316 let arity = u8::try_from(arity).map_err(|_| ParseError {
317 span: None,
318 code: None,
319 line,
320 message: "function arity too large".to_string(),
321 })?;
322 let function_index = self.next_function;
323 self.next_function = self.next_function.checked_add(1).ok_or(ParseError {
324 span: None,
325 code: None,
326 line,
327 message: "function index overflow".to_string(),
328 })?;
329 let decl = FunctionDecl {
330 name: name.clone(),
331 arity,
332 index: function_index,
333 args: vec![String::new(); usize::from(arity)],
334 arg_schemas: vec![None; usize::from(arity)],
335 return_schema: None,
336 type_params,
337 exported,
338 return_type: ValueType::Unknown,
339 };
340 self.functions.insert(name, decl.clone());
341 self.function_list.push(decl);
342 index = cursor;
343 }
344 _ => index += 1,
345 }
346 }
347 Ok(())
348 }
349
350 pub(super) fn local_count(&self) -> usize {
351 self.next_local as usize
352 }
353
354 pub(super) fn function_decls(&self) -> Vec<FunctionDecl> {
355 self.function_list.clone()
356 }
357
358 pub(super) fn function_impls(&self) -> HashMap<u16, FunctionImpl> {
359 self.function_impls.clone()
360 }
361
362 pub(super) fn local_bindings(&self) -> Vec<(String, LocalSlot)> {
363 let mut locals = self.named_local_bindings.clone();
364 locals.sort_by_key(|(_, index)| *index);
365 locals
366 }
367
368 pub(super) fn local_bindings_with_mutability(&self) -> Vec<ReplLocalBinding> {
369 let mut locals = self
370 .locals
371 .iter()
372 .map(|(name, index)| ReplLocalBinding {
373 name: name.clone(),
374 mutable: self.is_local_slot_mutable(*index),
375 schema: None,
376 optional: false,
377 })
378 .collect::<Vec<_>>();
379 locals.sort_by_key(|binding| self.locals.get(&binding.name).copied().unwrap_or(0));
380 locals
381 }
382
383 pub(super) fn struct_schemas(&self) -> HashMap<String, StructDecl> {
384 self.struct_schemas.clone()
385 }
386
387 pub(super) fn unknown_type_spans(&self) -> Vec<Span> {
388 self.unknown_type_spans.clone()
389 }
390
391 fn validate_schema_reference_sites(&self) -> Result<(), ParseError> {
392 for (name, arg_count, line, span) in &self.schema_reference_sites {
393 let Some(decl) = self.struct_schemas.get(name) else {
394 return Err(ParseError {
395 span: Some(*span),
396 code: None,
397 line: *line,
398 message: format!("unknown struct schema '{name}'"),
399 });
400 };
401 if decl.type_params.len() != *arg_count {
402 return Err(ParseError {
403 span: Some(*span),
404 code: None,
405 line: *line,
406 message: format!(
407 "struct schema '{name}' expects {} type arguments, got {}",
408 decl.type_params.len(),
409 arg_count
410 ),
411 });
412 }
413 if self.struct_schemas.contains_key(name) {
414 continue;
415 }
416 }
417 Ok(())
418 }
419
420 fn push_active_type_params(&mut self, params: &[String]) {
421 self.active_type_params
422 .push(params.iter().cloned().collect::<HashSet<_>>());
423 }
424
425 fn pop_active_type_params(&mut self) {
426 self.active_type_params.pop();
427 }
428
429 fn is_active_type_param(&self, name: &str) -> bool {
430 self.active_type_params
431 .iter()
432 .rev()
433 .any(|params| params.contains(name))
434 }
435
436 fn parse_type_params(
437 &mut self,
438 owner: &str,
439 owner_name: &str,
440 ) -> Result<Vec<String>, ParseError> {
441 if !self.check(&TokenKind::Less) {
442 return Ok(Vec::new());
443 }
444
445 self.expect(&TokenKind::Less, "expected '<' before type parameters")?;
446 let mut params = Vec::new();
447 let mut seen = HashSet::new();
448 loop {
449 let param = self.expect_ident("expected type parameter name")?;
450 if !seen.insert(param.clone()) {
451 return Err(ParseError {
452 span: Some(self.current_span()),
453 code: None,
454 line: self.current_line(),
455 message: format!(
456 "duplicate type parameter '{param}' in {owner} '{owner_name}'"
457 ),
458 });
459 }
460 params.push(param);
461 if self.match_kind(&TokenKind::Comma) {
462 continue;
463 }
464 break;
465 }
466 self.expect(&TokenKind::Greater, "expected '>' after type parameters")?;
467 Ok(params)
468 }
469
470 fn parse_turbofish_type_args(&mut self) -> Result<Vec<TypeSchema>, ParseError> {
471 if !self.check_path_separator() || !self.check_kind_at(self.pos + 2, &TokenKind::Less) {
472 return Ok(Vec::new());
473 }
474
475 self.match_path_separator();
476 self.expect(&TokenKind::Less, "expected '<' after '::' in turbofish")?;
477 let mut type_args = Vec::new();
478 loop {
479 type_args.push(self.parse_declared_type_schema()?);
480 if self.match_kind(&TokenKind::Comma) {
481 continue;
482 }
483 break;
484 }
485 self.expect(&TokenKind::Greater, "expected '>' after type arguments")?;
486 Ok(type_args)
487 }
488
489 fn function_param_names(params: &[FunctionParam]) -> Vec<String> {
490 params.iter().map(|param| param.name.clone()).collect()
491 }
492}