Skip to main content

vm/compiler/parser/
mod.rs

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}