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}
142
143struct ClosureCaptureContext {
144    by_name: HashMap<String, LocalSlot>,
145    capture_copies: Vec<(LocalSlot, LocalSlot)>,
146}
147
148impl Parser {
149    pub(super) fn new(
150        source: &str,
151        source_id: SourceId,
152        allow_implicit_externs: bool,
153        allow_implicit_semicolons: bool,
154        enforce_mutable_bindings: bool,
155        dialect: &'static dyn ParserDialect,
156    ) -> Result<Self, ParseError> {
157        let mut lexer = Lexer::new(source, source_id, dialect);
158        let mut tokens = Vec::new();
159        loop {
160            let token = lexer.next_token()?;
161            let is_eof = matches!(token.kind, TokenKind::Eof);
162            tokens.push(token);
163            if is_eof {
164                break;
165            }
166        }
167        Ok(Self {
168            tokens,
169            pos: 0,
170            locals: HashMap::new(),
171            named_local_bindings: Vec::new(),
172            next_local: 0,
173            functions: HashMap::new(),
174            function_list: Vec::new(),
175            function_impls: HashMap::new(),
176            next_function: 0,
177            closure_scopes: Vec::new(),
178            closure_capture_contexts: Vec::new(),
179            struct_schemas: HashMap::new(),
180            schema_reference_sites: Vec::new(),
181            active_type_params: Vec::new(),
182            unknown_type_spans: Vec::new(),
183            allow_implicit_externs,
184            allow_implicit_semicolons,
185            enforce_mutable_bindings,
186            dialect,
187            loop_depth: 0,
188            function_body_depth: 0,
189            host_namespace_aliases: HashMap::new(),
190            direct_host_call_aliases: HashMap::new(),
191            direct_host_wildcard_imports: HashSet::new(),
192            mutable_locals: Vec::new(),
193        })
194    }
195
196    pub(super) fn new_with_predeclared_locals(
197        source: &str,
198        source_id: SourceId,
199        allow_implicit_externs: bool,
200        allow_implicit_semicolons: bool,
201        enforce_mutable_bindings: bool,
202        dialect: &'static dyn ParserDialect,
203        predeclared_locals: &[ReplLocalBinding],
204    ) -> Result<Self, ParseError> {
205        let mut parser = Self::new(
206            source,
207            source_id,
208            allow_implicit_externs,
209            allow_implicit_semicolons,
210            enforce_mutable_bindings,
211            dialect,
212        )?;
213        for binding in predeclared_locals {
214            parser.predeclare_local(binding)?;
215        }
216        Ok(parser)
217    }
218
219    pub(super) fn parse_program(&mut self) -> Result<Vec<Stmt>, ParseError> {
220        let mut stmts = Vec::new();
221        while !self.check(&TokenKind::Eof) {
222            stmts.push(self.parse_stmt()?);
223        }
224        self.validate_schema_reference_sites()?;
225        Ok(stmts)
226    }
227
228    pub(super) fn local_count(&self) -> usize {
229        self.next_local as usize
230    }
231
232    pub(super) fn function_decls(&self) -> Vec<FunctionDecl> {
233        self.function_list.clone()
234    }
235
236    pub(super) fn function_impls(&self) -> HashMap<u16, FunctionImpl> {
237        self.function_impls.clone()
238    }
239
240    pub(super) fn local_bindings(&self) -> Vec<(String, LocalSlot)> {
241        let mut locals = self.named_local_bindings.clone();
242        locals.sort_by_key(|(_, index)| *index);
243        locals
244    }
245
246    pub(super) fn local_bindings_with_mutability(&self) -> Vec<ReplLocalBinding> {
247        let mut locals = self
248            .locals
249            .iter()
250            .map(|(name, index)| ReplLocalBinding {
251                name: name.clone(),
252                mutable: self.is_local_slot_mutable(*index),
253                schema: None,
254                optional: false,
255            })
256            .collect::<Vec<_>>();
257        locals.sort_by_key(|binding| self.locals.get(&binding.name).copied().unwrap_or(0));
258        locals
259    }
260
261    pub(super) fn struct_schemas(&self) -> HashMap<String, StructDecl> {
262        self.struct_schemas.clone()
263    }
264
265    pub(super) fn unknown_type_spans(&self) -> Vec<Span> {
266        self.unknown_type_spans.clone()
267    }
268
269    fn validate_schema_reference_sites(&self) -> Result<(), ParseError> {
270        for (name, arg_count, line, span) in &self.schema_reference_sites {
271            let Some(decl) = self.struct_schemas.get(name) else {
272                return Err(ParseError {
273                    span: Some(*span),
274                    code: None,
275                    line: *line,
276                    message: format!("unknown struct schema '{name}'"),
277                });
278            };
279            if decl.type_params.len() != *arg_count {
280                return Err(ParseError {
281                    span: Some(*span),
282                    code: None,
283                    line: *line,
284                    message: format!(
285                        "struct schema '{name}' expects {} type arguments, got {}",
286                        decl.type_params.len(),
287                        arg_count
288                    ),
289                });
290            }
291            if self.struct_schemas.contains_key(name) {
292                continue;
293            }
294        }
295        Ok(())
296    }
297
298    fn push_active_type_params(&mut self, params: &[String]) {
299        self.active_type_params
300            .push(params.iter().cloned().collect::<HashSet<_>>());
301    }
302
303    fn pop_active_type_params(&mut self) {
304        self.active_type_params.pop();
305    }
306
307    fn is_active_type_param(&self, name: &str) -> bool {
308        self.active_type_params
309            .iter()
310            .rev()
311            .any(|params| params.contains(name))
312    }
313
314    fn parse_type_params(
315        &mut self,
316        owner: &str,
317        owner_name: &str,
318    ) -> Result<Vec<String>, ParseError> {
319        if !self.check(&TokenKind::Less) {
320            return Ok(Vec::new());
321        }
322
323        self.expect(&TokenKind::Less, "expected '<' before type parameters")?;
324        let mut params = Vec::new();
325        let mut seen = HashSet::new();
326        loop {
327            let param = self.expect_ident("expected type parameter name")?;
328            if !seen.insert(param.clone()) {
329                return Err(ParseError {
330                    span: Some(self.current_span()),
331                    code: None,
332                    line: self.current_line(),
333                    message: format!(
334                        "duplicate type parameter '{param}' in {owner} '{owner_name}'"
335                    ),
336                });
337            }
338            params.push(param);
339            if self.match_kind(&TokenKind::Comma) {
340                continue;
341            }
342            break;
343        }
344        self.expect(&TokenKind::Greater, "expected '>' after type parameters")?;
345        Ok(params)
346    }
347
348    fn parse_turbofish_type_args(&mut self) -> Result<Vec<TypeSchema>, ParseError> {
349        if !self.check_path_separator() || !self.check_kind_at(self.pos + 2, &TokenKind::Less) {
350            return Ok(Vec::new());
351        }
352
353        self.match_path_separator();
354        self.expect(&TokenKind::Less, "expected '<' after '::' in turbofish")?;
355        let mut type_args = Vec::new();
356        loop {
357            type_args.push(self.parse_declared_type_schema()?);
358            if self.match_kind(&TokenKind::Comma) {
359                continue;
360            }
361            break;
362        }
363        self.expect(&TokenKind::Greater, "expected '>' after type arguments")?;
364        Ok(type_args)
365    }
366
367    fn function_param_names(params: &[FunctionParam]) -> Vec<String> {
368        params.iter().map(|param| param.name.clone()).collect()
369    }
370}