runmat_parser/parser/
mod.rs1mod assignment;
2mod classdef;
3mod command;
4mod cursor;
5mod expr;
6mod stmt;
7
8use runmat_lexer::Token;
9
10use crate::{ParserOptions, Program, Stmt, SyntaxError};
11
12#[derive(Clone)]
13struct TokenInfo {
14 token: Token,
15 lexeme: String,
16 position: usize,
17 end: usize,
18}
19
20struct Parser {
21 tokens: Vec<TokenInfo>,
22 pos: usize,
23 input: String,
24 options: ParserOptions,
25 in_matrix_expr: bool,
26}
27
28pub fn parse(input: &str) -> Result<Program, SyntaxError> {
29 parse_with_options(input, ParserOptions::default())
30}
31
32pub fn parse_with_options(input: &str, options: ParserOptions) -> Result<Program, SyntaxError> {
33 use runmat_lexer::tokenize_detailed;
34
35 let toks = tokenize_detailed(input);
36 let mut tokens = Vec::new();
37 let mut skip_newlines = false;
38
39 for t in toks {
40 if matches!(t.token, Token::Error) {
41 return Err(SyntaxError {
42 message: format!("Invalid token: '{}'", t.lexeme),
43 position: t.start,
44 found_token: Some(t.lexeme),
45 expected: None,
46 });
47 }
48 if matches!(t.token, Token::Ellipsis | Token::Section) {
50 skip_newlines = matches!(t.token, Token::Ellipsis);
54 continue;
55 }
56 if skip_newlines && matches!(t.token, Token::Newline) {
57 continue;
58 }
59 skip_newlines = false;
60 tokens.push(TokenInfo {
61 token: t.token,
62 lexeme: t.lexeme,
63 position: t.start,
64 end: t.end,
65 });
66 }
67
68 let mut parser = Parser {
69 tokens,
70 pos: 0,
71 input: input.to_string(),
72 options,
73 in_matrix_expr: false,
74 };
75 parser.parse_program()
76}
77
78impl Parser {
79 fn parse_program(&mut self) -> Result<Program, SyntaxError> {
80 let mut body = Vec::new();
81 while self.pos < self.tokens.len() {
82 if self.consume(&Token::Semicolon)
83 || self.consume(&Token::Comma)
84 || self.consume(&Token::Newline)
85 {
86 continue;
87 }
88 body.push(self.parse_stmt_with_semicolon()?);
89 }
90 Ok(Program { body })
91 }
92
93 fn finalize_stmt(&self, stmt: Stmt, is_semicolon_terminated: bool) -> Stmt {
94 match stmt {
95 Stmt::ExprStmt(expr, _, span) => Stmt::ExprStmt(expr, is_semicolon_terminated, span),
96 Stmt::Assign(name, expr, _, span) => {
97 Stmt::Assign(name, expr, is_semicolon_terminated, span)
98 }
99 Stmt::MultiAssign(names, expr, _, span) => {
100 Stmt::MultiAssign(names, expr, is_semicolon_terminated, span)
101 }
102 Stmt::AssignLValue(lv, expr, _, span) => {
103 Stmt::AssignLValue(lv, expr, is_semicolon_terminated, span)
104 }
105 other => other,
106 }
107 }
108}