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
38 for t in toks {
39 if matches!(t.token, Token::Error) {
40 return Err(SyntaxError {
41 message: format!("Invalid token: '{}'", t.lexeme),
42 position: t.start,
43 found_token: Some(t.lexeme),
44 expected: None,
45 });
46 }
47 if matches!(t.token, Token::Ellipsis | Token::Section) {
49 continue;
50 }
51 tokens.push(TokenInfo {
52 token: t.token,
53 lexeme: t.lexeme,
54 position: t.start,
55 end: t.end,
56 });
57 }
58
59 let mut parser = Parser {
60 tokens,
61 pos: 0,
62 input: input.to_string(),
63 options,
64 in_matrix_expr: false,
65 };
66 parser.parse_program()
67}
68
69impl Parser {
70 fn parse_program(&mut self) -> Result<Program, SyntaxError> {
71 let mut body = Vec::new();
72 while self.pos < self.tokens.len() {
73 if self.consume(&Token::Semicolon)
74 || self.consume(&Token::Comma)
75 || self.consume(&Token::Newline)
76 {
77 continue;
78 }
79 body.push(self.parse_stmt_with_semicolon()?);
80 }
81 Ok(Program { body })
82 }
83
84 fn finalize_stmt(&self, stmt: Stmt, is_semicolon_terminated: bool) -> Stmt {
85 match stmt {
86 Stmt::ExprStmt(expr, _, span) => Stmt::ExprStmt(expr, is_semicolon_terminated, span),
87 Stmt::Assign(name, expr, _, span) => {
88 Stmt::Assign(name, expr, is_semicolon_terminated, span)
89 }
90 Stmt::MultiAssign(names, expr, _, span) => {
91 Stmt::MultiAssign(names, expr, is_semicolon_terminated, span)
92 }
93 Stmt::AssignLValue(lv, expr, _, span) => {
94 Stmt::AssignLValue(lv, expr, is_semicolon_terminated, span)
95 }
96 other => other,
97 }
98 }
99}