1use rimu_ast::{SpannedBlock, SpannedExpression};
2use rimu_meta::{SourceId, Span};
3
4mod compiler;
5mod error;
6mod lexer;
7mod token;
8
9pub use crate::error::Error;
10pub(crate) use compiler::{compile_block, compile_expression};
11pub(crate) use lexer::{tokenize_block, tokenize_expression};
12pub(crate) use token::{SpannedToken, Token};
13
14pub fn parse_expression(code: &str, source: SourceId) -> (Option<SpannedExpression>, Vec<Error>) {
15 let mut errors = Vec::new();
16
17 let len = code.chars().count();
18 let eoi = Span::new(source.clone(), len, len);
19
20 let (tokens, lex_errors) = tokenize_expression(code, source.clone());
21 errors.append(&mut lex_errors.into_iter().map(Error::Lexer).collect());
22
23 let Some(tokens) = tokens else {
24 return (None, errors);
25 };
26
27 let (output, compile_errors) = compile_expression(tokens, eoi);
28 errors.append(&mut compile_errors.into_iter().map(Error::Compiler).collect());
29
30 (output, errors)
31}
32
33pub fn parse_block(code: &str, source: SourceId) -> (Option<SpannedBlock>, Vec<Error>) {
34 let mut errors = Vec::new();
35
36 let len = code.chars().count();
37 let eoi = Span::new(source.clone(), len, len);
38
39 let (tokens, lex_errors) = tokenize_block(code, source.clone());
40 errors.append(&mut lex_errors.into_iter().map(Error::Lexer).collect());
41
42 let Some(tokens) = tokens else {
43 return (None, errors);
44 };
45
46 let (output, compile_errors) = compile_block(tokens, eoi);
47 errors.append(&mut compile_errors.into_iter().map(Error::Compiler).collect());
48
49 (output, errors)
50}
51
52#[cfg(test)]
53mod tests {
54 use std::ops::Range;
55
56 use pretty_assertions::assert_eq;
57 use rimu_ast::{BinaryOperator, Block, Expression, SpannedBlock, SpannedExpression};
58 use rimu_meta::{SourceId, Span, Spanned};
59
60 use crate::{parse_block, parse_expression, Error};
61
62 fn span(range: Range<usize>) -> Span {
63 Span::new(SourceId::empty(), range.start, range.end)
64 }
65
66 fn test_block(code: &str) -> (Option<SpannedBlock>, Vec<Error>) {
67 parse_block(code, SourceId::empty())
68 }
69
70 fn test_expression(code: &str) -> (Option<SpannedExpression>, Vec<Error>) {
71 parse_expression(code, SourceId::empty())
72 }
73
74 #[test]
75 fn expr_arithmetic() {
76 let (actual_expr, errors) = test_expression("x + y * (z / w)");
77
78 let expected_expr = Some(Spanned::new(
79 Expression::Binary {
80 left: Box::new(Spanned::new(Expression::Identifier("x".into()), span(0..1))),
81 right: Box::new(Spanned::new(
82 Expression::Binary {
83 left: Box::new(Spanned::new(
84 Expression::Identifier("y".into()),
85 span(4..5),
86 )),
87 right: Box::new(Spanned::new(
88 Expression::Binary {
89 left: Box::new(Spanned::new(
90 Expression::Identifier("z".into()),
91 span(9..10),
92 )),
93 right: Box::new(Spanned::new(
94 Expression::Identifier("w".into()),
95 span(13..14),
96 )),
97 operator: BinaryOperator::Divide,
98 },
99 span(8..15),
100 )),
101 operator: BinaryOperator::Multiply,
102 },
103 span(4..15),
104 )),
105 operator: BinaryOperator::Add,
106 },
107 span(0..15),
108 ));
109
110 assert_eq!(actual_expr, expected_expr);
111 assert_eq!(errors.len(), 0);
112 }
113
114 #[test]
115 fn block_misc() {
116 let (actual_block, errors) = test_block(
117 "
118a:
119 b:
120 - c + d
121 - e: f
122 g: h
123",
124 );
125
126 let expected_block = Some(Spanned::new(
127 Block::Object(vec![(
128 Spanned::new("a".into(), span(1..2)),
129 Spanned::new(
130 Block::Object(vec![
131 (
132 Spanned::new("b".into(), span(6..7)),
133 Spanned::new(
134 Block::List(vec![
135 Spanned::new(
136 Block::Expression(Expression::Binary {
137 left: Box::new(Spanned::new(
138 Expression::Identifier("c".into()),
139 span(15..16),
140 )),
141 right: Box::new(Spanned::new(
142 Expression::Identifier("d".into()),
143 span(19..20),
144 )),
145 operator: BinaryOperator::Add,
146 }),
147 span(15..20),
148 ),
149 Spanned::new(
150 Block::Object(vec![(
151 Spanned::new("e".into(), span(27..28)),
152 Spanned::new(
153 Block::Expression(Expression::Identifier(
154 "f".into(),
155 )),
156 span(30..31),
157 ),
158 )]),
159 span(27..32),
160 ),
161 ]),
162 span(13..34),
163 ),
164 ),
165 (
166 Spanned::new("g".into(), span(34..35)),
167 Spanned::new(
168 Block::Expression(Expression::Identifier("h".into())),
169 span(37..38),
170 ),
171 ),
172 ]),
173 span(6..39),
174 ),
175 )]),
176 span(1..39),
177 ));
178
179 assert_eq!(actual_block, expected_block);
180 assert_eq!(errors.len(), 0);
181 }
182}