diff --git a/peg-macros/grammar.rs b/peg-macros/grammar.rs index f7debea..0ea43e8 100644 --- a/peg-macros/grammar.rs +++ b/peg-macros/grammar.rs @@ -1388,7 +1388,7 @@ pub mod peg { ::peg::RuleResult::Failed => break, } }; - let __step_res = match __parse_rust_type( + let __step_res = match __parse_rust_ty_param_bound( __input, __state, __err_state, @@ -1456,19 +1456,24 @@ pub mod peg { ::peg::RuleResult::Failed => break, } }; - let __step_res = match __parse_rust_type( - __input, - __state, - __err_state, - __pos, - ) { - ::peg::RuleResult::Matched(pos, _) => { - ::peg::RuleResult::Matched(pos, ()) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - }; + let __step_res = + match __parse_rust_ty_param_bound( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched( + pos, + _, + ) => ::peg::RuleResult::Matched( + pos, + (), + ), + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Failed + } + }; match __step_res { ::peg::RuleResult::Matched( __newpos, @@ -2036,45 +2041,24 @@ pub mod peg { ::peg::RuleResult::Matched(__pos, __value) } ::peg::RuleResult::Failed => { - let __seq_res = - match match ::peg::ParseLiteral::parse_string_literal( - __input, __pos, "for", - ) { - ::peg::RuleResult::Matched(__pos, __val) => { - let __seq_res = match __parse_rust_ty_params( - __input, - __state, - __err_state, - __pos, - ) { - ::peg::RuleResult::Matched(pos, _) => { - ::peg::RuleResult::Matched(pos, ()) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - }; - match __seq_res { - ::peg::RuleResult::Matched(__pos, _) => { - ::peg::RuleResult::Matched(__pos, ()) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - } - } - ::peg::RuleResult::Failed => { - __err_state.mark_failure(__pos, "\"for\""); - ::peg::RuleResult::Failed - } - } { - ::peg::RuleResult::Matched(__newpos, _) => { - ::peg::RuleResult::Matched(__newpos, ()) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Matched(__pos, ()) - } - }; + let __seq_res = match match __parse_rust_for_lifetimes( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } { + ::peg::RuleResult::Matched(__newpos, _) => { + ::peg::RuleResult::Matched(__newpos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Matched(__pos, ()) + } + }; match __seq_res { ::peg::RuleResult::Matched(__pos, _) => { let __seq_res = match __parse_rust_type( @@ -2112,10 +2096,7 @@ pub mod peg { let __sep_res = match :: peg :: ParseLiteral :: parse_string_literal (__input , __pos , "+") { :: peg :: RuleResult :: Matched (__pos , __val) => { :: peg :: RuleResult :: Matched (__pos , __val) } :: peg :: RuleResult :: Failed => { __err_state . mark_failure (__pos , "\"+\"") ; :: peg :: RuleResult :: Failed } } ; match __sep_res { :: peg :: RuleResult :: Matched (__newpos , _) => { __newpos } , :: peg :: RuleResult :: Failed => break , } }; - let __step_res = { - let __choice_res = match __parse_LIFETIME (__input , __state , __err_state , __pos) { :: peg :: RuleResult :: Matched (pos , _) => :: peg :: RuleResult :: Matched (pos , ()) , :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } ; - match __choice_res { :: peg :: RuleResult :: Matched (__pos , __value) => :: peg :: RuleResult :: Matched (__pos , __value) , :: peg :: RuleResult :: Failed => { let __seq_res = match match :: peg :: ParseLiteral :: parse_string_literal (__input , __pos , "?") { :: peg :: RuleResult :: Matched (__pos , __val) => { :: peg :: RuleResult :: Matched (__pos , __val) } :: peg :: RuleResult :: Failed => { __err_state . mark_failure (__pos , "\"?\"") ; :: peg :: RuleResult :: Failed } } { :: peg :: RuleResult :: Matched (__newpos , _) => { :: peg :: RuleResult :: Matched (__newpos , ()) } , :: peg :: RuleResult :: Failed => { :: peg :: RuleResult :: Matched (__pos , ()) } , } ; match __seq_res { :: peg :: RuleResult :: Matched (__pos , _) => { { let __seq_res = match __parse_rust_ty_path (__input , __state , __err_state , __pos) { :: peg :: RuleResult :: Matched (pos , _) => :: peg :: RuleResult :: Matched (pos , ()) , :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } ; match __seq_res { :: peg :: RuleResult :: Matched (__pos , _) => { :: peg :: RuleResult :: Matched (__pos , ()) } :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } } } :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } } } - }; + let __step_res = match __parse_rust_ty_param_bound (__input , __state , __err_state , __pos) { :: peg :: RuleResult :: Matched (pos , _) => :: peg :: RuleResult :: Matched (pos , ()) , :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } ; match __step_res { :: peg :: RuleResult :: Matched (__newpos , __value) => { __repeat_pos = __newpos ; __repeat_value . push (__value) ; } , :: peg :: RuleResult :: Failed => { break ; } } } if __repeat_value.len() >= 1 { @@ -2347,52 +2328,17 @@ pub mod peg { ::peg::RuleResult::Failed => break, } }; - let __step_res = { - let __choice_res = match __parse_LIFETIME( - __input, - __state, - __err_state, - __pos, - ) { - ::peg::RuleResult::Matched(pos, _) => { - ::peg::RuleResult::Matched(pos, ()) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - }; - match __choice_res { - ::peg::RuleResult::Matched(__pos, __value) => { - ::peg::RuleResult::Matched(__pos, __value) - } - ::peg::RuleResult::Failed => { - let __seq_res = match match :: peg :: ParseLiteral :: parse_string_literal (__input , __pos , "?") { :: peg :: RuleResult :: Matched (__pos , __val) => { :: peg :: RuleResult :: Matched (__pos , __val) } :: peg :: RuleResult :: Failed => { __err_state . mark_failure (__pos , "\"?\"") ; :: peg :: RuleResult :: Failed } } { :: peg :: RuleResult :: Matched (__newpos , _) => { :: peg :: RuleResult :: Matched (__newpos , ()) } , :: peg :: RuleResult :: Failed => { :: peg :: RuleResult :: Matched (__pos , ()) } , } ; - match __seq_res { - ::peg::RuleResult::Matched( - __pos, - _, - ) => { - let __seq_res = match __parse_rust_ty_path (__input , __state , __err_state , __pos) { :: peg :: RuleResult :: Matched (pos , _) => :: peg :: RuleResult :: Matched (pos , ()) , :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } ; - match __seq_res { - ::peg::RuleResult::Matched( - __pos, - _, - ) => { - ::peg::RuleResult::Matched( - __pos, - (), - ) - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - } - } - ::peg::RuleResult::Failed => { - ::peg::RuleResult::Failed - } - } - } + let __step_res = match __parse_rust_ty_param_bound( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Failed } }; match __step_res { @@ -2441,6 +2387,194 @@ pub mod peg { } } } + fn __parse_rust_for_lifetimes<'input>( + __input: &'input Input, + __state: &mut ParseState<'input>, + __err_state: &mut ::peg::error::ErrorState, + __pos: usize, + ) -> ::peg::RuleResult<()> { + #![allow(non_snake_case, unused, clippy::redundant_closure_call)] + match ::peg::ParseLiteral::parse_string_literal(__input, __pos, "for") { + ::peg::RuleResult::Matched(__pos, __val) => { + let __seq_res = match __parse_rust_ty_params(__input, __state, __err_state, __pos) { + ::peg::RuleResult::Matched(pos, _) => ::peg::RuleResult::Matched(pos, ()), + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => ::peg::RuleResult::Matched(__pos, ()), + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } + } + ::peg::RuleResult::Failed => { + __err_state.mark_failure(__pos, "\"for\""); + ::peg::RuleResult::Failed + } + } + } + fn __parse_rust_ty_param_bound<'input>( + __input: &'input Input, + __state: &mut ParseState<'input>, + __err_state: &mut ::peg::error::ErrorState, + __pos: usize, + ) -> ::peg::RuleResult<()> { + #![allow(non_snake_case, unused, clippy::redundant_closure_call)] + { + let __choice_res = match __parse_LIFETIME(__input, __state, __err_state, __pos) { + ::peg::RuleResult::Matched(pos, _) => ::peg::RuleResult::Matched(pos, ()), + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + }; + match __choice_res { + ::peg::RuleResult::Matched(__pos, __value) => { + ::peg::RuleResult::Matched(__pos, __value) + } + ::peg::RuleResult::Failed => { + let __choice_res = { + let __seq_res = match match ::peg::ParseLiteral::parse_string_literal( + __input, __pos, "?", + ) { + ::peg::RuleResult::Matched(__pos, __val) => { + ::peg::RuleResult::Matched(__pos, __val) + } + ::peg::RuleResult::Failed => { + __err_state.mark_failure(__pos, "\"?\""); + ::peg::RuleResult::Failed + } + } { + ::peg::RuleResult::Matched(__newpos, _) => { + ::peg::RuleResult::Matched(__newpos, ()) + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Matched(__pos, ()), + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => { + let __seq_res = match match __parse_rust_for_lifetimes( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } { + ::peg::RuleResult::Matched(__newpos, _) => { + ::peg::RuleResult::Matched(__newpos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Matched(__pos, ()) + } + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => { + let __seq_res = match __parse_rust_ty_path( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => { + ::peg::RuleResult::Matched(__pos, ()) + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } + }; + match __choice_res { + ::peg::RuleResult::Matched(__pos, __value) => { + ::peg::RuleResult::Matched(__pos, __value) + } + ::peg::RuleResult::Failed => { + match ::peg::ParseLiteral::parse_string_literal(__input, __pos, "(") { + ::peg::RuleResult::Matched(__pos, __val) => { + let __seq_res = + match match ::peg::ParseLiteral::parse_string_literal( + __input, __pos, "?", + ) { + ::peg::RuleResult::Matched(__pos, __val) => { + ::peg::RuleResult::Matched(__pos, __val) + } + ::peg::RuleResult::Failed => { + __err_state.mark_failure(__pos, "\"?\""); + ::peg::RuleResult::Failed + } + } { + ::peg::RuleResult::Matched(__newpos, _) => { + ::peg::RuleResult::Matched(__newpos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Matched(__pos, ()) + } + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => { + let __seq_res = match match __parse_rust_for_lifetimes( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Failed + } + } { + ::peg::RuleResult::Matched(__newpos, _) => { + ::peg::RuleResult::Matched(__newpos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Matched(__pos, ()) + } + }; + match __seq_res { + ::peg::RuleResult::Matched(__pos, _) => { + let __seq_res = match __parse_rust_ty_path( + __input, + __state, + __err_state, + __pos, + ) { + ::peg::RuleResult::Matched(pos, _) => { + ::peg::RuleResult::Matched(pos, ()) + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Failed + } + }; + match __seq_res { :: peg :: RuleResult :: Matched (__pos , _) => { match :: peg :: ParseLiteral :: parse_string_literal (__input , __pos , ")") { :: peg :: RuleResult :: Matched (__pos , __val) => { :: peg :: RuleResult :: Matched (__pos , ()) } :: peg :: RuleResult :: Failed => { __err_state . mark_failure (__pos , "\")\"") ; :: peg :: RuleResult :: Failed } } } :: peg :: RuleResult :: Failed => :: peg :: RuleResult :: Failed , } + } + ::peg::RuleResult::Failed => { + ::peg::RuleResult::Failed + } + } + } + ::peg::RuleResult::Failed => ::peg::RuleResult::Failed, + } + } + ::peg::RuleResult::Failed => { + __err_state.mark_failure(__pos, "\"(\""); + ::peg::RuleResult::Failed + } + } + } + } + } + } + } + } fn __parse_expression<'input>( __input: &'input Input, __state: &mut ParseState<'input>, diff --git a/peg-macros/grammar.rustpeg b/peg-macros/grammar.rustpeg index 7fdafdb..a534d04 100644 --- a/peg-macros/grammar.rustpeg +++ b/peg-macros/grammar.rustpeg @@ -59,8 +59,8 @@ rule rust_path() rule rust_type() = BRACKET_GROUP() / "&" LIFETIME()? "mut"? rust_type() - / "dyn" rust_type() ++ "+" - / "impl" rust_type() ++ "+" + / "dyn" rust_ty_param_bound() ++ "+" + / "impl" rust_ty_param_bound() ++ "+" / "(" (rust_type() ++ "," ","?)? ")" / ("<" rust_type() ("as" rust_ty_path())? ">")? rust_ty_path() @@ -73,12 +73,20 @@ rule rust_ty_params() -> Vec rule rust_where_clause() = "where" ( LIFETIME() (":" LIFETIME() ++ "+")? - / ("for" rust_ty_params())? rust_type() ":" (LIFETIME() / "?"? rust_ty_path()) ++ "+" + / rust_for_lifetimes()? rust_type() ":" rust_ty_param_bound() ++ "+" ) ** "," ","? rule rust_generic_param() = LIFETIME() (":" LIFETIME() ++ "+")? - / IDENT() (":"(LIFETIME() / "?"? rust_ty_path()) ++ "+")? + / IDENT() (":" rust_ty_param_bound() ++ "+")? + +rule rust_for_lifetimes() + = "for" rust_ty_params() + +rule rust_ty_param_bound() + = LIFETIME() + / "?"? rust_for_lifetimes()? rust_ty_path() + / "(" "?"? rust_for_lifetimes()? rust_ty_path() ")" rule expression() -> SpannedExpr = choice() diff --git a/tests/run-pass/assembly_ast_dyn_type_param_bounds.rs b/tests/run-pass/assembly_ast_dyn_type_param_bounds.rs new file mode 100644 index 0000000..8116666 --- /dev/null +++ b/tests/run-pass/assembly_ast_dyn_type_param_bounds.rs @@ -0,0 +1,122 @@ +extern crate peg; +use peg::parser; + +// C++ in Rust +trait Operation<'a>: std::fmt::Debug {} +trait Operand<'a>: std::fmt::Debug + AsDynOperand<'a> {} +trait Location<'a>: Operand<'a> {} +impl<'a, T: ?Sized + Location<'a>> Operand<'a> for T {} + +// Thanks to quinedot for their comprehensive write-up on dyn Traits. +// https://quinedot.github.io/rust-learning/dyn-trait-combining.html#manual-supertrait-upcasting +trait AsDynOperand<'a> { + fn as_dyn_operand(self: Box) -> Box + 'a>; +} + +impl<'a, T: /* Sized + */ Operand<'a> + 'a> AsDynOperand<'a> for T { + fn as_dyn_operand(self: Box) -> Box + 'a> { + self + } +} + + + +#[derive(Debug)] +pub struct Program<'a>(Vec + 'a>>); + +#[derive(Debug)] +struct Add<'a> { + result: Box + 'a>, + lhs: Box + 'a>, + rhs: Box + 'a>, +} +impl<'a> Operation<'a> for Add<'a> {} + +#[derive(Debug)] +struct Sub<'a> { + result: Box + 'a>, + lhs: Box + 'a>, + rhs: Box + 'a>, +} +impl<'a> Operation<'a> for Sub<'a> {} + +#[derive(Debug)] +struct Register<'a>(&'a str); +impl<'a> Location<'a> for Register<'a> {} + +#[derive(Debug)] +struct Global<'a>(&'a str); +impl<'a> Location<'a> for Global<'a> {} + +#[derive(Debug)] +struct Literal(i32); +impl<'a> Operand<'a> for Literal {} + +parser!{ +grammar assembly() for str { + pub rule program() -> Program<'input> + = op:operation() ** "\n" { Program(op) } + + rule _ = [' ']* + + rule operation() -> Box + 'input> + = a:add() {a} / s:sub() {s} + + rule add() -> Box> + = result:location() _ "=" _ "add" _ lhs:operand() _ rhs:operand() { Box::new(Add{ result, lhs, rhs }) } + + rule sub() -> Box> + = result:location() _ "=" _ "sub" _ lhs:operand() _ rhs:operand() { Box::new(Sub{ result, lhs, rhs }) } + + rule location() -> Box + 'input> + = r:register() {r} / g:global() {g} + + rule register() -> Box> + = "%" _ id:identifier() { Box::new(Register(id)) } + + rule global() -> Box> + = "@" _ id:identifier() { Box::new(Global(id)) } + + rule identifier() -> &'input str + = $(['a'..='z' | 'A'..='Z']+) + + rule operand() -> Box + 'input> + = l:location() {l.as_dyn_operand()} / l:literal() {Box::new(l)} + + rule literal() -> Literal + = n:$(['0'..='9']+) {? + let n = n.parse::().map_err(|_| "invalid int literal")?; + Ok(Literal(n)) + } + +}} + +fn main() { + let parsed = assembly::program("%apple = add 1 @g +@b = add 2 %a +%c = sub 82 @b +@dog = sub @b 12").unwrap(); + let expected = Program(vec![ + Box::new(Add{ + result: Box::new(Register("apple")), + lhs: Box::new(Literal(1)), + rhs: Box::new(Global("g")) + }), + Box::new(Add{ + result: Box::new(Global("b")), + lhs: Box::new(Literal(2)), + rhs: Box::new(Register("a")) + }), + Box::new(Sub{ + result: Box::new(Register("c")), + lhs: Box::new(Literal(82)), + rhs: Box::new(Global("b")) + }), + Box::new(Sub{ + result: Box::new(Global("dog")), + lhs: Box::new(Global("b")), + rhs: Box::new(Literal(12)) + }), + ]); + assert_eq!(format!("{parsed:?}"), format!("{expected:?}")); +}