From 90a3c40ac3cf2b76777a26833a7a2298dbf280f0 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sun, 20 Apr 2025 14:11:03 -0500 Subject: [PATCH] Work on object access and number literal grammar; basic parser testing. --- src/parser/deimos.pest | 25 +++++++++++++----- src/parser/mod.rs | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index cf15168..3fc0dc5 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -67,25 +67,38 @@ Statement = { VariableDeclaration | CallExpression | AssignmentExpression } VariableDeclaration = { "let" ~ Mutable? ~ Identifier ~ TypeAnnotation? ~ ( "=" ~ Expression )? } // Expressions -Expression = { CallExpression | AssignmentExpression | Literal | FullyQualifiedName } +Expression = { CallExpression | AssignmentExpression | Literal | ObjectAccess } ExpressionList = { Expression ~ ( "," ~ Expression )* } // Calls -CallExpression = { FullyQualifiedName ~ GenericArguments ~ CallArguments } +CallExpression = { ObjectAccess ~ GenericArguments? ~ CallArguments } CallArguments = { ( "(" ~ ExpressionList? ~")") | ExpressionList } // Assignment -AssignmentExpression = { FullyQualifiedName ~ "=" ~ Expression } +AssignmentExpression = { ObjectAccess ~ "=" ~ Expression } + +// Object +ObjectAccess = { FullyQualifiedName ~ ( "." ~ Identifier )* } // Literals Literal = { NumberLiteral | StringLiteral | BooleanLiteral | NullLiteral } -NumberLiteral = { IntLiteral } -IntLiteral = { '0'..'9'+ } -LongLiteral = { '0'..'9'+ ~ "L" } +NumberLiteral = { LongLiteral | IntLiteral } + +IntLiteral = { NumberBase } +LongLiteral = ${ NumberBase ~ "L" } + +NumberBase = { DecimalBase | BinaryBase | HexadecimalBase } + +DecimalBase = @{ DecimalStartDigit ~ Digit* } +BinaryBase = @{ "0b" ~ Digit* } +DecimalStartDigit = { '1'..'9' } +Digit = { '0'..'9'+ } +HexadecimalBase = @{ "0x" ~ HexadecimalDigit+ } +HexadecimalDigit = { '0'..'9' | 'a'..'f' } StringLiteral = ${ "\"" ~ StringInner ~ "\"" } StringInner = @{ StringChar* } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2669896..3f8af4b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3,3 +3,62 @@ 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 pest::iterators::Pair; + use pest::Parser; + + macro_rules! match_inner_rules { + ($pair:expr; $rule:path; $handle_last:expr) => {{ + if let $rule = $pair.as_rule() { + $handle_last($pair); + } else { + panic!( + "Expected {} but found {:?}", + stringify!($rule), + $pair.as_rule() + ) + } + }}; + ($pair:expr; $head_rule:path $(, $tail_rules:path )* ; $handle_last:expr) => {{ + if let $head_rule = $pair.as_rule() { + let inner = $pair.into_inner().next().unwrap(); + match_inner_rules!( + inner; + $( $tail_rules ),*; + $handle_last + ); + } else { + panic!( + "Expected {} but found {:?}", + stringify!($head_rule), + $pair.as_rule() + ) + } + }}; + } + + fn parse(rule: Rule, input: &str) -> Pair { + let pair = DeimosParser::parse(rule, input).unwrap().next().unwrap(); + dbg!(&pair); + pair + } + + #[test] + fn hex_int() { + let pair = parse(Rule::IntLiteral, "0x1234abcd"); + match_inner_rules!(pair; Rule::IntLiteral, Rule::NumberBase, Rule::HexadecimalBase; |hexadecimal_base: Pair| { + assert_eq!(hexadecimal_base.as_str(), "0x1234abcd") + }); + } + + #[test] + fn hex_long() { + let pair = parse(Rule::LongLiteral, "0x123456789abcdefL"); + match_inner_rules!(pair; Rule::LongLiteral, Rule::NumberBase, Rule::HexadecimalBase; |hexadecimal_base: Pair| { + assert_eq!(hexadecimal_base.as_str(), "0x123456789abcdef") + }) + } +}