205 lines
4.4 KiB
Rust
205 lines
4.4 KiB
Rust
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}");
|
|
}
|
|
}
|