jia_parse/jia_lang/parser/
expr.rs1use super::Parser;
9use crate::error::ParseError;
10use crate::jia_lang::ast::{ArithOp, Expr};
11use crate::jia_lang::lexer::TokenKind;
12
13#[derive(Clone, Copy)]
14enum UnaryExprFn {
15 StartOf,
16 EndOf,
17 DurationOf,
18 PresentOf,
19}
20
21impl UnaryExprFn {
22 fn from_name(name: &str) -> Option<Self> {
23 match name {
24 "start_of" => Some(Self::StartOf),
25 "end_of" => Some(Self::EndOf),
26 "duration_of" => Some(Self::DurationOf),
27 "present_of" => Some(Self::PresentOf),
28 _ => None,
29 }
30 }
31
32 fn apply(self, arg: String) -> Expr {
33 match self {
34 Self::StartOf => Expr::StartOf(arg),
35 Self::EndOf => Expr::EndOf(arg),
36 Self::DurationOf => Expr::DurationOf(arg),
37 Self::PresentOf => Expr::PresentOf(arg),
38 }
39 }
40}
41
42impl<'a> Parser<'a> {
43 pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
45 self.parse_additive()
46 }
47
48 fn parse_additive(&mut self) -> Result<Expr, ParseError> {
50 let mut left = self.parse_multiplicative()?;
51 loop {
52 let op = match self.peek_kind() {
53 Some(TokenKind::Plus) => ArithOp::Add,
54 Some(TokenKind::Minus) => ArithOp::Sub,
55 _ => break,
56 };
57 self.advance();
58 let right = self.parse_multiplicative()?;
59 left = Expr::BinaryOp {
60 op,
61 left: Box::new(left),
62 right: Box::new(right),
63 };
64 }
65 Ok(left)
66 }
67
68 fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
70 let mut left = self.parse_atom()?;
71 loop {
72 let op = match self.peek_kind() {
73 Some(TokenKind::Star) => ArithOp::Mul,
74 Some(TokenKind::Slash) => ArithOp::Div,
75 _ => break,
76 };
77 self.advance();
78 let right = self.parse_atom()?;
79 left = Expr::BinaryOp {
80 op,
81 left: Box::new(left),
82 right: Box::new(right),
83 };
84 }
85 Ok(left)
86 }
87
88 fn parse_atom(&mut self) -> Result<Expr, ParseError> {
90 match self.peek_kind() {
91 Some(TokenKind::Number(n)) => {
92 self.advance();
93 Ok(Expr::Number(n))
94 }
95 Some(TokenKind::Float(f)) => {
96 self.advance();
97 Ok(Expr::Float(f))
98 }
99 Some(TokenKind::Minus) => {
100 self.advance();
101 let inner = self.parse_atom()?;
102 Ok(Expr::Negate(Box::new(inner)))
103 }
104 Some(TokenKind::LParen) => {
105 self.advance();
106 let expr = self.parse_expr()?;
107 self.expect_token(TokenKind::RParen)?;
108 Ok(expr)
109 }
110 Some(TokenKind::Ident(name)) => {
111 let name = name.clone();
113 if let Some(function) = UnaryExprFn::from_name(&name) {
114 self.advance();
115 self.expect_token(TokenKind::LParen)?;
116 let arg = self.expect_ident()?;
117 self.expect_token(TokenKind::RParen)?;
118 Ok(function.apply(arg))
119 } else {
120 self.advance();
121 Ok(Expr::Var(name))
122 }
123 }
124 _ => {
125 let span = self.current_span();
126 Err(ParseError::new("expected expression", span))
127 }
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use crate::jia_lang::ast::{ArithOp, Expr};
135 use crate::jia_lang::lexer::tokenize;
136 use crate::jia_lang::parser::Parser;
137
138 fn parse_expr(input: &str) -> Expr {
139 let tokens = tokenize(input).unwrap();
140 let mut parser = Parser::new(&tokens);
141 parser.parse_expr().unwrap()
142 }
143
144 #[test]
145 fn test_number() {
146 assert_eq!(parse_expr("42"), Expr::Number(42));
147 }
148
149 #[test]
150 fn test_variable() {
151 assert_eq!(parse_expr("makespan"), Expr::Var("makespan".to_string()));
152 }
153
154 #[test]
155 fn test_start_of() {
156 assert_eq!(
157 parse_expr("start_of(task_a)"),
158 Expr::StartOf("task_a".to_string())
159 );
160 }
161
162 #[test]
163 fn test_end_of() {
164 assert_eq!(
165 parse_expr("end_of(task_b)"),
166 Expr::EndOf("task_b".to_string())
167 );
168 }
169
170 #[test]
171 fn test_duration_of() {
172 assert_eq!(
173 parse_expr("duration_of(task_a)"),
174 Expr::DurationOf("task_a".to_string())
175 );
176 }
177
178 #[test]
179 fn test_addition() {
180 assert_eq!(
181 parse_expr("end_of(a) + 5"),
182 Expr::BinaryOp {
183 op: ArithOp::Add,
184 left: Box::new(Expr::EndOf("a".to_string())),
185 right: Box::new(Expr::Number(5)),
186 }
187 );
188 }
189
190 #[test]
191 fn test_precedence_mul_before_add() {
192 let expr = parse_expr("1 + 2 * 3");
194 assert_eq!(
195 expr,
196 Expr::BinaryOp {
197 op: ArithOp::Add,
198 left: Box::new(Expr::Number(1)),
199 right: Box::new(Expr::BinaryOp {
200 op: ArithOp::Mul,
201 left: Box::new(Expr::Number(2)),
202 right: Box::new(Expr::Number(3)),
203 }),
204 }
205 );
206 }
207
208 #[test]
209 fn test_parenthesized() {
210 let expr = parse_expr("(1 + 2) * 3");
211 assert_eq!(
212 expr,
213 Expr::BinaryOp {
214 op: ArithOp::Mul,
215 left: Box::new(Expr::BinaryOp {
216 op: ArithOp::Add,
217 left: Box::new(Expr::Number(1)),
218 right: Box::new(Expr::Number(2)),
219 }),
220 right: Box::new(Expr::Number(3)),
221 }
222 );
223 }
224
225 #[test]
226 fn test_negation() {
227 assert_eq!(parse_expr("-5"), Expr::Negate(Box::new(Expr::Number(5))));
228 }
229
230 #[test]
231 fn test_present_of_and_expression_error() {
232 assert_eq!(
233 parse_expr("present_of(task_a)"),
234 Expr::PresentOf("task_a".to_string())
235 );
236
237 let tokens = tokenize(")").unwrap();
238 let mut parser = Parser::new(&tokens);
239 assert!(parser.parse_expr().is_err());
240 }
241}