1use crate::parser::common::{
6 compound_identifier, condition_value, many_until_eof, map_err, skip_ws, using_list, ws,
7 BindParserError, CompoundIdentifier, Include, NomSpan, Span, Value,
8};
9use nom::branch::alt;
10use nom::bytes::complete::tag;
11use nom::combinator::{opt, value};
12use nom::multi::{many1, separated_list1};
13use nom::sequence::{delimited, preceded, terminated};
14use nom::{IResult, Parser};
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct Ast<'a> {
18 pub using: Vec<Include>,
19 pub statements: StatementBlock<'a>,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub enum ConditionOp {
24 Equals,
25 NotEquals,
26}
27
28#[derive(Debug, Clone, PartialEq)]
29pub struct Condition<'a> {
30 pub span: Span<'a>,
31 pub lhs: CompoundIdentifier,
32 pub op: ConditionOp,
33 pub rhs: Value,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub enum Statement<'a> {
38 ConditionStatement {
39 span: Span<'a>,
40 condition: Condition<'a>,
41 },
42 Accept {
43 span: Span<'a>,
44 identifier: CompoundIdentifier,
45 values: Vec<Value>,
46 },
47 If {
48 span: Span<'a>,
49 blocks: Vec<(Condition<'a>, StatementBlock<'a>)>,
50 else_block: StatementBlock<'a>,
51 },
52 False {
53 span: Span<'a>,
54 },
55 True {
56 span: Span<'a>,
57 },
58}
59
60pub type StatementBlock<'a> = Vec<Statement<'a>>;
61
62impl<'a> Statement<'a> {
63 pub fn get_span(&'a self) -> &'a Span<'a> {
64 match self {
65 Statement::ConditionStatement { span, .. } => span,
66 Statement::Accept { span, .. } => span,
67 Statement::If { span, .. } => span,
68 Statement::False { span } => span,
69 Statement::True { span } => span,
70 }
71 }
72}
73
74impl<'a> TryFrom<&'a str> for Ast<'a> {
76 type Error = BindParserError;
77
78 fn try_from(input: &'a str) -> Result<Self, Self::Error> {
79 match rules(NomSpan::new(input)) {
80 Ok((_, ast)) => Ok(ast),
81 Err(nom::Err::Error(e)) => Err(e),
82 Err(nom::Err::Failure(e)) => Err(e),
83 Err(nom::Err::Incomplete(_)) => {
84 unreachable!("Parser should never generate Incomplete errors")
85 }
86 }
87 }
88}
89
90fn condition_op(input: NomSpan) -> IResult<NomSpan, ConditionOp, BindParserError> {
91 let equals = value(ConditionOp::Equals, tag("=="));
92 let not_equals = value(ConditionOp::NotEquals, tag("!="));
93 map_err(alt((equals, not_equals)), BindParserError::ConditionOp).parse(input)
94}
95
96fn condition(input: NomSpan) -> IResult<NomSpan, Condition, BindParserError> {
97 let from = skip_ws(input)?;
98 let (input, lhs) = ws(compound_identifier).parse(from)?;
99 let (input, op) = ws(condition_op).parse(input)?;
100 let (to, rhs) = ws(condition_value).parse(input)?;
101
102 let span = Span::from_to(&from, &to);
103 Ok((to, Condition { span, lhs, op, rhs }))
104}
105
106fn condition_statement(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
107 let from = skip_ws(input)?;
108 let terminator = ws(map_err(tag(";"), BindParserError::Semicolon));
109 let (to, condition) = terminated(condition, terminator).parse(from)?;
110
111 let span = Span::from_to(&from, &to);
112 Ok((to, Statement::ConditionStatement { span, condition }))
113}
114
115fn keyword_if(input: NomSpan) -> IResult<NomSpan, NomSpan, BindParserError> {
116 ws(map_err(tag("if"), BindParserError::IfKeyword)).parse(input)
117}
118
119fn keyword_else(input: NomSpan) -> IResult<NomSpan, NomSpan, BindParserError> {
120 ws(map_err(tag("else"), BindParserError::ElseKeyword)).parse(input)
121}
122
123fn if_statement(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
124 let from = skip_ws(input)?;
125
126 let if_block = (preceded(keyword_if, condition), statement_block);
127 let mut if_blocks = separated_list1(keyword_else, if_block);
128
129 let mut else_block = preceded(keyword_else, statement_block);
130
131 let (input, blocks) = if_blocks.parse(from)?;
132 let (to, else_block) = else_block.parse(input)?;
133
134 let span = Span::from_to(&from, &to);
135 Ok((to, Statement::If { span, blocks, else_block }))
136}
137
138pub fn statement_block(input: NomSpan) -> IResult<NomSpan, Vec<Statement>, BindParserError> {
139 let block_start = ws(map_err(tag("{"), BindParserError::IfBlockStart));
140 let block_end = ws(map_err(tag("}"), BindParserError::IfBlockEnd));
141 delimited(block_start, many1(ws(statement)), block_end).parse(input)
142}
143
144fn keyword_accept(input: NomSpan) -> IResult<NomSpan, NomSpan, BindParserError> {
145 ws(map_err(tag("accept"), BindParserError::AcceptKeyword)).parse(input)
146}
147
148fn accept(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
149 let from = skip_ws(input)?;
150
151 let list_start = ws(map_err(tag("{"), BindParserError::ListStart));
152 let list_end = ws(map_err(tag("}"), BindParserError::ListEnd));
153 let separator = || ws(map_err(tag(","), BindParserError::ListSeparator));
154
155 let values = separated_list1(separator(), ws(condition_value));
156 let values = terminated(values, opt(separator()));
158 let value_list = delimited(list_start, values, list_end);
159
160 let (to, (identifier, values)) =
161 preceded(keyword_accept, (ws(compound_identifier), value_list)).parse(from)?;
162
163 let span = Span::from_to(&from, &to);
164 Ok((to, Statement::Accept { span, identifier, values }))
165}
166
167fn keyword_false(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
168 let from = skip_ws(input)?;
169 let keyword = ws(map_err(tag("false"), BindParserError::FalseKeyword));
170 let terminator = ws(map_err(tag(";"), BindParserError::Semicolon));
171 let (to, _) = terminated(keyword, terminator).parse(from)?;
172
173 let span = Span::from_to(&from, &to);
174 Ok((to, Statement::False { span }))
175}
176
177fn keyword_true(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
178 let from = skip_ws(input)?;
179 let keyword = ws(map_err(tag("true"), BindParserError::TrueKeyword));
180 let terminator = ws(map_err(tag(";"), BindParserError::Semicolon));
181 let (to, _) = terminated(keyword, terminator).parse(from)?;
182
183 let span = Span::from_to(&from, &to);
184 Ok((to, Statement::True { span }))
185}
186
187fn statement(input: NomSpan) -> IResult<NomSpan, Statement, BindParserError> {
188 alt((condition_statement, if_statement, accept, keyword_false, keyword_true)).parse(input)
189}
190
191fn rules(input: NomSpan) -> IResult<NomSpan, Ast, BindParserError> {
192 let (input, using) = ws(using_list).parse(input)?;
193 let (input, statements) = many_until_eof(ws(statement)).parse(input)?;
194 if statements.is_empty() {
195 return Err(nom::Err::Error(BindParserError::NoStatements(input.to_string())));
196 }
197 Ok((input, Ast { using, statements }))
198}
199
200#[cfg(test)]
201mod test {
202 use super::*;
203 use crate::make_identifier;
204 use crate::parser::common::test::check_result;
205
206 mod condition_ops {
207 use super::*;
208
209 #[test]
210 fn equality() {
211 check_result(condition_op(NomSpan::new("==")), "", ConditionOp::Equals);
212 }
213
214 #[test]
215 fn inequality() {
216 check_result(condition_op(NomSpan::new("!=")), "", ConditionOp::NotEquals);
217 }
218
219 #[test]
220 fn invalid() {
221 assert_eq!(
222 condition_op(NomSpan::new(">=")),
223 Err(nom::Err::Error(BindParserError::ConditionOp(">=".to_string())))
224 );
225 }
226
227 #[test]
228 fn empty() {
229 assert_eq!(
230 condition_op(NomSpan::new("")),
231 Err(nom::Err::Error(BindParserError::ConditionOp("".to_string())))
232 );
233 }
234 }
235
236 mod conditions {
237 use super::*;
238
239 #[test]
240 fn equality_condition() {
241 check_result(
242 condition(NomSpan::new("abc == true")),
243 "",
244 Condition {
245 span: Span { offset: 0, line: 1, fragment: "abc == true" },
246 lhs: make_identifier!["abc"],
247 op: ConditionOp::Equals,
248 rhs: Value::BoolLiteral(true),
249 },
250 );
251 }
252
253 #[test]
254 fn empty() {
255 assert_eq!(
256 condition(NomSpan::new("")),
257 Err(nom::Err::Error(BindParserError::Identifier("".to_string())))
258 );
259 }
260
261 #[test]
262 fn span() {
263 check_result(
266 condition(NomSpan::new(" \n\t\r\nabc \n\t\r\n== \n\t\r\ntrue \n\t\r\n")),
267 " \n\t\r\n",
268 Condition {
269 span: Span { offset: 5, line: 3, fragment: "abc \n\t\r\n== \n\t\r\ntrue" },
270 lhs: make_identifier!["abc"],
271 op: ConditionOp::Equals,
272 rhs: Value::BoolLiteral(true),
273 },
274 );
275 }
276 }
277
278 mod if_statements {
279 use super::*;
280
281 #[test]
282 fn simple() {
283 check_result(
284 if_statement(NomSpan::new("if a == b { c == 1; } else { d == 2; }")),
285 "",
286 Statement::If {
287 span: Span {
288 offset: 0,
289 line: 1,
290 fragment: "if a == b { c == 1; } else { d == 2; }",
291 },
292 blocks: vec![(
293 Condition {
294 span: Span { offset: 3, line: 1, fragment: "a == b" },
295 lhs: make_identifier!["a"],
296 op: ConditionOp::Equals,
297 rhs: Value::Identifier(make_identifier!["b"]),
298 },
299 vec![Statement::ConditionStatement {
300 span: Span { offset: 12, line: 1, fragment: "c == 1;" },
301 condition: Condition {
302 span: Span { offset: 12, line: 1, fragment: "c == 1" },
303 lhs: make_identifier!["c"],
304 op: ConditionOp::Equals,
305 rhs: Value::NumericLiteral(1),
306 },
307 }],
308 )],
309 else_block: vec![Statement::ConditionStatement {
310 span: Span { offset: 29, line: 1, fragment: "d == 2;" },
311 condition: Condition {
312 span: Span { offset: 29, line: 1, fragment: "d == 2" },
313 lhs: make_identifier!["d"],
314 op: ConditionOp::Equals,
315 rhs: Value::NumericLiteral(2),
316 },
317 }],
318 },
319 );
320 }
321
322 #[test]
323 fn else_if() {
324 check_result(
325 if_statement(NomSpan::new(
326 "if a == b { c == 1; } else if e == 3 { d == 2; } else { f != 4; }",
327 )),
328 "",
329 Statement::If {
330 span: Span {
331 offset: 0,
332 line: 1,
333 fragment:
334 "if a == b { c == 1; } else if e == 3 { d == 2; } else { f != 4; }",
335 },
336 blocks: vec![
337 (
338 Condition {
339 span: Span { offset: 3, line: 1, fragment: "a == b" },
340 lhs: make_identifier!["a"],
341 op: ConditionOp::Equals,
342 rhs: Value::Identifier(make_identifier!["b"]),
343 },
344 vec![Statement::ConditionStatement {
345 span: Span { offset: 12, line: 1, fragment: "c == 1;" },
346 condition: Condition {
347 span: Span { offset: 12, line: 1, fragment: "c == 1" },
348 lhs: make_identifier!["c"],
349 op: ConditionOp::Equals,
350 rhs: Value::NumericLiteral(1),
351 },
352 }],
353 ),
354 (
355 Condition {
356 span: Span { offset: 30, line: 1, fragment: "e == 3" },
357 lhs: make_identifier!["e"],
358 op: ConditionOp::Equals,
359 rhs: Value::NumericLiteral(3),
360 },
361 vec![Statement::ConditionStatement {
362 span: Span { offset: 39, line: 1, fragment: "d == 2;" },
363 condition: Condition {
364 span: Span { offset: 39, line: 1, fragment: "d == 2" },
365 lhs: make_identifier!["d"],
366 op: ConditionOp::Equals,
367 rhs: Value::NumericLiteral(2),
368 },
369 }],
370 ),
371 ],
372 else_block: vec![Statement::ConditionStatement {
373 span: Span { offset: 56, line: 1, fragment: "f != 4;" },
374 condition: Condition {
375 span: Span { offset: 56, line: 1, fragment: "f != 4" },
376 lhs: make_identifier!["f"],
377 op: ConditionOp::NotEquals,
378 rhs: Value::NumericLiteral(4),
379 },
380 }],
381 },
382 );
383 }
384
385 #[test]
386 fn nested() {
387 check_result(
388 if_statement(NomSpan::new(
389 "if a == 1 { if b == 2 { c != 3; } else { c == 3; } } else { d == 2; }",
390 )),
391 "",
392 Statement::If {
393 span: Span {
394 offset: 0,
395 line: 1,
396 fragment:
397 "if a == 1 { if b == 2 { c != 3; } else { c == 3; } } else { d == 2; }",
398 },
399 blocks: vec![(
400 Condition {
401 span: Span { offset: 3, line: 1, fragment: "a == 1" },
402 lhs: make_identifier!["a"],
403 op: ConditionOp::Equals,
404 rhs: Value::NumericLiteral(1),
405 },
406 vec![Statement::If {
407 span: Span {
408 offset: 12,
409 line: 1,
410 fragment: "if b == 2 { c != 3; } else { c == 3; }",
411 },
412 blocks: vec![(
413 Condition {
414 span: Span { offset: 15, line: 1, fragment: "b == 2" },
415 lhs: make_identifier!["b"],
416 op: ConditionOp::Equals,
417 rhs: Value::NumericLiteral(2),
418 },
419 vec![Statement::ConditionStatement {
420 span: Span { offset: 24, line: 1, fragment: "c != 3;" },
421 condition: Condition {
422 span: Span { offset: 24, line: 1, fragment: "c != 3" },
423 lhs: make_identifier!["c"],
424 op: ConditionOp::NotEquals,
425 rhs: Value::NumericLiteral(3),
426 },
427 }],
428 )],
429 else_block: vec![Statement::ConditionStatement {
430 span: Span { offset: 41, line: 1, fragment: "c == 3;" },
431 condition: Condition {
432 span: Span { offset: 41, line: 1, fragment: "c == 3" },
433 lhs: make_identifier!["c"],
434 op: ConditionOp::Equals,
435 rhs: Value::NumericLiteral(3),
436 },
437 }],
438 }],
439 )],
440 else_block: vec![Statement::ConditionStatement {
441 span: Span { offset: 60, line: 1, fragment: "d == 2;" },
442 condition: Condition {
443 span: Span { offset: 60, line: 1, fragment: "d == 2" },
444 lhs: make_identifier!["d"],
445 op: ConditionOp::Equals,
446 rhs: Value::NumericLiteral(2),
447 },
448 }],
449 },
450 );
451 }
452
453 #[test]
454 fn invalid() {
455 assert_eq!(
457 if_statement(NomSpan::new("a == b { c == 1; }")),
458 Err(nom::Err::Error(BindParserError::IfKeyword("a == b { c == 1; }".to_string())))
459 );
460
461 assert_eq!(
463 if_statement(NomSpan::new("if { c == 1; }")),
464 Err(nom::Err::Error(BindParserError::Identifier("{ c == 1; }".to_string())))
465 );
466
467 assert_eq!(
469 if_statement(NomSpan::new("if a == b { c == 1; }")),
470 Err(nom::Err::Error(BindParserError::ElseKeyword("".to_string())))
471 );
472 assert_eq!(
473 if_statement(NomSpan::new("if a == b { c == 1; } else if e == 3 { d == 2; }")),
474 Err(nom::Err::Error(BindParserError::ElseKeyword("".to_string())))
475 );
476
477 assert_eq!(
479 if_statement(NomSpan::new("if a == b c == 1; }")),
480 Err(nom::Err::Error(BindParserError::IfBlockStart("c == 1; }".to_string())))
481 );
482 assert_eq!(
483 if_statement(NomSpan::new("if a == b { c == 1;")),
484 Err(nom::Err::Error(BindParserError::IfBlockEnd("".to_string())))
485 );
486
487 assert!(if_statement(NomSpan::new("if a == b { } else { c == 1; }")).is_err());
491 assert!(if_statement(NomSpan::new("if a == b { c == 1; } else { }")).is_err());
492 }
493
494 #[test]
495 fn empty() {
496 assert_eq!(
497 if_statement(NomSpan::new("")),
498 Err(nom::Err::Error(BindParserError::IfKeyword("".to_string())))
499 );
500 }
501 }
502
503 mod accepts {
504 use super::*;
505
506 #[test]
507 fn simple() {
508 check_result(
509 accept(NomSpan::new("accept a { 1 }")),
510 "",
511 Statement::Accept {
512 span: Span { offset: 0, line: 1, fragment: "accept a { 1 }" },
513 identifier: make_identifier!["a"],
514 values: vec![Value::NumericLiteral(1)],
515 },
516 );
517 }
518
519 #[test]
520 fn multiple_values() {
521 check_result(
522 accept(NomSpan::new("accept a { 1, 2 }")),
523 "",
524 Statement::Accept {
525 span: Span { offset: 0, line: 1, fragment: "accept a { 1, 2 }" },
526 identifier: make_identifier!["a"],
527 values: vec![Value::NumericLiteral(1), Value::NumericLiteral(2)],
528 },
529 );
530 }
531
532 #[test]
533 fn trailing_comma() {
534 check_result(
535 accept(NomSpan::new("accept a { 1, 2, }")),
536 "",
537 Statement::Accept {
538 span: Span { offset: 0, line: 1, fragment: "accept a { 1, 2, }" },
539 identifier: make_identifier!["a"],
540 values: vec![Value::NumericLiteral(1), Value::NumericLiteral(2)],
541 },
542 );
543 }
544
545 #[test]
546 fn invalid() {
547 assert_eq!(
549 accept(NomSpan::new("a { 1 }")),
550 Err(nom::Err::Error(BindParserError::AcceptKeyword("a { 1 }".to_string())))
551 );
552
553 assert_eq!(
555 accept(NomSpan::new("accept { 1 }")),
556 Err(nom::Err::Error(BindParserError::Identifier("{ 1 }".to_string())))
557 );
558
559 assert_eq!(
561 accept(NomSpan::new("accept a { }")),
562 Err(nom::Err::Error(BindParserError::ConditionValue("}".to_string())))
563 );
564
565 assert_eq!(
567 accept(NomSpan::new("accept a 1 }")),
568 Err(nom::Err::Error(BindParserError::ListStart("1 }".to_string())))
569 );
570 assert_eq!(
571 accept(NomSpan::new("accept a { 1")),
572 Err(nom::Err::Error(BindParserError::ListEnd("".to_string())))
573 );
574 }
575
576 #[test]
577 fn empty() {
578 assert_eq!(
579 accept(NomSpan::new("")),
580 Err(nom::Err::Error(BindParserError::AcceptKeyword("".to_string())))
581 );
582 }
583
584 #[test]
585 fn span() {
586 check_result(
588 accept(NomSpan::new(" \n\t\r\naccept a \n\t\r\n{ 1 } \n\t\r\n")),
589 " \n\t\r\n",
590 Statement::Accept {
591 span: Span { offset: 5, line: 3, fragment: "accept a \n\t\r\n{ 1 }" },
592 identifier: make_identifier!["a"],
593 values: vec![Value::NumericLiteral(1)],
594 },
595 );
596 }
597 }
598
599 mod false_statement {
600 use super::*;
601
602 #[test]
603 fn simple() {
604 check_result(
605 keyword_false(NomSpan::new("false;")),
606 "",
607 Statement::False { span: Span { offset: 0, line: 1, fragment: "false;" } },
608 );
609 }
610
611 #[test]
612 fn invalid() {
613 assert_eq!(
615 keyword_false(NomSpan::new("a;")),
616 Err(nom::Err::Error(BindParserError::FalseKeyword("a;".to_string())))
617 );
618 assert_eq!(
619 keyword_false(NomSpan::new(";")),
620 Err(nom::Err::Error(BindParserError::FalseKeyword(";".to_string())))
621 );
622
623 assert_eq!(
625 keyword_false(NomSpan::new("false")),
626 Err(nom::Err::Error(BindParserError::Semicolon("".to_string())))
627 );
628 }
629
630 #[test]
631 fn empty() {
632 assert_eq!(
633 keyword_false(NomSpan::new("")),
634 Err(nom::Err::Error(BindParserError::FalseKeyword("".to_string())))
635 );
636 }
637
638 #[test]
639 fn span() {
640 check_result(
642 keyword_false(NomSpan::new(" \n\t\r\nfalse; \n\t\r\n")),
643 " \n\t\r\n",
644 Statement::False { span: Span { offset: 5, line: 3, fragment: "false;" } },
645 );
646 }
647 }
648
649 mod true_statement {
650 use super::*;
651
652 #[test]
653 fn simple() {
654 check_result(
655 keyword_true(NomSpan::new("true;")),
656 "",
657 Statement::True { span: Span { offset: 0, line: 1, fragment: "true;" } },
658 );
659 }
660
661 #[test]
662 fn invalid() {
663 assert_eq!(
665 keyword_true(NomSpan::new("p;")),
666 Err(nom::Err::Error(BindParserError::TrueKeyword("p;".to_string())))
667 );
668 assert_eq!(
669 keyword_true(NomSpan::new(";")),
670 Err(nom::Err::Error(BindParserError::TrueKeyword(";".to_string())))
671 );
672
673 assert_eq!(
675 keyword_true(NomSpan::new("true")),
676 Err(nom::Err::Error(BindParserError::Semicolon("".to_string())))
677 );
678 }
679
680 #[test]
681 fn empty() {
682 assert_eq!(
683 keyword_true(NomSpan::new("")),
684 Err(nom::Err::Error(BindParserError::TrueKeyword("".to_string())))
685 );
686 }
687
688 #[test]
689 fn span() {
690 check_result(
692 keyword_true(NomSpan::new(" \n\t\r\ntrue; \n\t\r\n")),
693 " \n\t\r\n",
694 Statement::True { span: Span { offset: 5, line: 3, fragment: "true;" } },
695 );
696 }
697 }
698
699 mod rules {
700 use super::*;
701
702 #[test]
703 fn simple() {
704 check_result(
705 rules(NomSpan::new("using a; x == 1;")),
706 "",
707 Ast {
708 using: vec![Include { name: make_identifier!["a"], alias: None }],
709 statements: vec![Statement::ConditionStatement {
710 span: Span { offset: 9, line: 1, fragment: "x == 1;" },
711 condition: Condition {
712 span: Span { offset: 9, line: 1, fragment: "x == 1" },
713 lhs: make_identifier!["x"],
714 op: ConditionOp::Equals,
715 rhs: Value::NumericLiteral(1),
716 },
717 }],
718 },
719 );
720 }
721
722 #[test]
723 fn empty() {
724 assert_eq!(
725 rules(NomSpan::new("")),
726 Err(nom::Err::Error(BindParserError::NoStatements("".to_string())))
727 );
728 }
729
730 #[test]
731 fn requires_statement() {
732 assert_eq!(
734 rules(NomSpan::new("using a;")),
735 Err(nom::Err::Error(BindParserError::NoStatements("".to_string())))
736 );
737 }
738
739 #[test]
740 fn using_list_optional() {
741 check_result(
742 rules(NomSpan::new("x == 1;")),
743 "",
744 Ast {
745 using: vec![],
746 statements: vec![Statement::ConditionStatement {
747 span: Span { offset: 0, line: 1, fragment: "x == 1;" },
748 condition: Condition {
749 span: Span { offset: 0, line: 1, fragment: "x == 1" },
750 lhs: make_identifier!["x"],
751 op: ConditionOp::Equals,
752 rhs: Value::NumericLiteral(1),
753 },
754 }],
755 },
756 );
757 }
758
759 #[test]
760 fn requires_semicolons() {
761 assert_eq!(
763 rules(NomSpan::new("x == 1")),
764 Err(nom::Err::Error(BindParserError::TrueKeyword("x == 1".to_string())))
765 );
766 }
767
768 #[test]
769 fn multiple_statements() {
770 check_result(
771 rules(NomSpan::new(
772 "x == 1; accept y { true } false; if z == 2 { a != 3; } else { a == 3; }",
773 )),
774 "",
775 Ast {
776 using: vec![],
777 statements: vec![
778 Statement::ConditionStatement {
779 span: Span { offset: 0, line: 1, fragment: "x == 1;" },
780 condition: Condition {
781 span: Span { offset: 0, line: 1, fragment: "x == 1" },
782 lhs: make_identifier!["x"],
783 op: ConditionOp::Equals,
784 rhs: Value::NumericLiteral(1),
785 },
786 },
787 Statement::Accept {
788 span: Span { offset: 8, line: 1, fragment: "accept y { true }" },
789 identifier: make_identifier!["y"],
790 values: vec![Value::BoolLiteral(true)],
791 },
792 Statement::False { span: Span { offset: 26, line: 1, fragment: "false;" } },
793 Statement::If {
794 span: Span {
795 offset: 33,
796 line: 1,
797 fragment: "if z == 2 { a != 3; } else { a == 3; }",
798 },
799 blocks: vec![(
800 Condition {
801 span: Span { offset: 36, line: 1, fragment: "z == 2" },
802 lhs: make_identifier!["z"],
803 op: ConditionOp::Equals,
804 rhs: Value::NumericLiteral(2),
805 },
806 vec![Statement::ConditionStatement {
807 span: Span { offset: 45, line: 1, fragment: "a != 3;" },
808 condition: Condition {
809 span: Span { offset: 45, line: 1, fragment: "a != 3" },
810 lhs: make_identifier!["a"],
811 op: ConditionOp::NotEquals,
812 rhs: Value::NumericLiteral(3),
813 },
814 }],
815 )],
816 else_block: vec![Statement::ConditionStatement {
817 span: Span { offset: 62, line: 1, fragment: "a == 3;" },
818 condition: Condition {
819 span: Span { offset: 62, line: 1, fragment: "a == 3" },
820 lhs: make_identifier!["a"],
821 op: ConditionOp::Equals,
822 rhs: Value::NumericLiteral(3),
823 },
824 }],
825 },
826 ],
827 },
828 );
829 }
830 }
831}