use pest_derive::Parser; #[derive(Parser)] #[grammar = "parser/deimos.pest"] pub struct DeimosParser; #[cfg(test)] mod deimos_parser_tests { use crate::parser::{DeimosParser, Rule}; use indoc::indoc; use pest::Parser; macro_rules! fail_rule { ($pair: expr; $rule:path) => {{ panic!( "Expected {} but found {:?}", stringify!($rule), $pair.as_rule() ) }}; } macro_rules! match_rule { ($pair:expr; $rule:path) => {{ if $rule != $pair.as_rule() { fail_rule!($pair; $rule); } }}; } fn parses_to(rule: Rule, input: &str) { let parse_result = DeimosParser::parse(rule, input); if let Err(e) = parse_result { panic!("Parsing failed.\n{}", e); } else { let mut pairs = parse_result.unwrap(); if input.trim() != pairs.as_str().trim() { panic!( "Parsing did not consume entire input. Consumed only:\n{}", pairs.as_str() ); } let first = pairs.next().unwrap(); match_rule!(first; rule) } } #[test] fn hex_int() { parses_to(Rule::IntLiteral, "0x1234abcd"); } #[test] fn hex_long() { parses_to(Rule::LongLiteral, "0x123456789abcdefL"); } #[test] fn suffix_expression_call_single_identifier() { parses_to(Rule::SuffixExpression, "foo()"); } #[test] fn simple_interface() { parses_to(Rule::CompilationUnit, "pub int Simple { fn foo() -> Void }"); } #[test] fn interface_with_op() { parses_to( Rule::CompilationUnit, "pub int Callable { op () () -> Void }", ); } #[test] fn interface_with_alias() { parses_to( Rule::CompilationUnit, indoc! {" pub int Callable { fn call() -> Void def op () () -> Void alias call } "}, ); } #[test] fn index_identifier() { parses_to(Rule::SuffixExpression, "foo[0]"); } #[test] fn chained_index_call_on_identifier() { parses_to(Rule::SuffixExpression, "foo[0]()"); } #[test] fn if_statement() { parses_to( Rule::IfStatement, indoc! {" if (foo == 42) { bar() }"}, ) } #[test] fn if_else_statement() { parses_to( Rule::IfElseStatement, indoc! {" if (foo == 42) { bar() } else { baz() }"}, ) } #[test] fn if_else_if_statement() { parses_to( Rule::IfElseStatement, indoc! {" if (foo == 42) { bar() } else if (foo == 16) { baz() }"}, ) } #[test] fn if_else_if_else_statement() { parses_to( Rule::IfElseStatement, indoc! {" if (foo == 42) { foo() } else if (foo == 16) { baz() } else { fizz() }"}, ) } #[test] fn while_statement() { parses_to(Rule::WhileStatement, "while (foo) { bar() }"); } #[test] fn for_statement() { parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }"); } #[test] fn if_statement_with_call_condition() { parses_to( Rule::IfStatement, indoc! {" if (foo()) { bar() } "}, ) } #[test] fn while_statement_with_call_condition() { parses_to(Rule::WhileStatement, "while (foo()) { bar(); }") } #[test] fn for_statement_with_call_iterator() { parses_to( Rule::ForStatement, indoc! {" for (foo in bar()) { baz(foo); } "}, ) } #[test] fn use_statement() { parses_to(Rule::UseStatement, "use std::core::println"); } #[test] fn use_star() { parses_to(Rule::UseStatement, "use std::core::*") } #[test] fn use_list() { parses_to(Rule::UseStatement, "use std::core::{print, println}"); } }