Skip to content

Commit 70e19f5

Browse files
A4-Tackskevinmehall
authored andcommitted
Add no associative infix for precedence!{}
1 parent 830ba4f commit 70e19f5

File tree

3 files changed

+54
-11
lines changed

3 files changed

+54
-11
lines changed

peg-macros/translate.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -878,10 +878,11 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
878878
));
879879
}
880880
(&Expr::Marker(la), &Expr::Marker(ra)) if op.elements.len() >= 3 => {
881-
//infix
882-
let new_prec = match (la, ra) {
883-
(true, false) => prec + 1, // left associative
884-
(false, true) => prec, // right associative
881+
// infix
882+
let (assoc, new_prec) = match (la, ra) {
883+
(true, false) => (true, prec + 1), // left associative
884+
(false, true) => (true, prec), // right associative
885+
(false, false) => (false, prec + 1), // no associative
885886
_ => return report_error(op_span, "precedence rules must use `@` and `(@)` to indicate associativity".to_string())
886887
};
887888

@@ -891,7 +892,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
891892
if let ::peg::RuleResult::Matched(__pos, #r_arg) = __recurse(__pos, #new_prec, __state, __err_state) {
892893
let #l_arg = __infix_result;
893894
__infix_result = #action;
894-
::peg::RuleResult::Matched(__pos, ())
895+
::peg::RuleResult::Matched(__pos, #assoc)
895896
} else { ::peg::RuleResult::Failed }
896897
}
897898
})
@@ -906,7 +907,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
906907
quote_spanned! { op_span =>
907908
let #l_arg = __infix_result;
908909
__infix_result = #action;
909-
::peg::RuleResult::Matched(__pos, ())
910+
::peg::RuleResult::Matched(__pos, true)
910911
}
911912
},
912913
));
@@ -940,8 +941,8 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
940941
level_code.push(quote_spanned! { span =>
941942
if #prec >= __min_prec {
942943
#(
943-
if let ::peg::RuleResult::Matched(__pos, ()) = #post_rules {
944-
return (__infix_result, ::peg::RuleResult::Matched(__pos, ()));
944+
if let ::peg::RuleResult::Matched(__pos, __assoc) = #post_rules {
945+
return (__infix_result, ::peg::RuleResult::Matched(__pos, __assoc));
945946
}
946947
)*
947948
}
@@ -968,7 +969,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
968969
min_prec: i32,
969970
lpos: usize,
970971
prefix_atom: &dyn Fn(usize, &mut S, &mut ::peg::error::ErrorState, &dyn Fn(usize, i32, &mut S, &mut ::peg::error::ErrorState) -> ::peg::RuleResult<T>) -> ::peg::RuleResult<T>,
971-
level_code: &dyn Fn(usize, usize, i32, T, &mut S, &mut ::peg::error::ErrorState, &dyn Fn(usize, i32, &mut S, &mut ::peg::error::ErrorState) -> ::peg::RuleResult<T>) -> (T, ::peg::RuleResult<()>),
972+
level_code: &dyn Fn(usize, usize, i32, T, &mut S, &mut ::peg::error::ErrorState, &dyn Fn(usize, i32, &mut S, &mut ::peg::error::ErrorState) -> ::peg::RuleResult<T>) -> (T, ::peg::RuleResult<bool>),
972973
) -> ::peg::RuleResult<T> {
973974
let initial = {
974975
prefix_atom(lpos, state, err_state, &|pos, min_prec, state, err_state| {
@@ -993,9 +994,11 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
993994
);
994995
infix_result = val;
995996

996-
if let ::peg::RuleResult::Matched(pos, ()) = res {
997+
if let ::peg::RuleResult::Matched(pos, assoc) = res {
997998
repeat_pos = pos;
998-
continue;
999+
if assoc {
1000+
continue;
1001+
}
9991002
}
10001003

10011004
break;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
extern crate peg;
2+
3+
peg::parser!(grammar arithmetic() for str {
4+
pub(crate) rule no_assoc() = precedence! {
5+
@ "+" @ {}
6+
--
7+
@ "?" {}
8+
--
9+
"-" @ {}
10+
--
11+
"x" {}
12+
}
13+
});
14+
15+
#[test]
16+
fn main() {
17+
assert!(arithmetic::no_assoc("x+x").is_ok());
18+
assert!(arithmetic::no_assoc("-x").is_ok());
19+
assert!(arithmetic::no_assoc("x?").is_ok());
20+
21+
assert!(arithmetic::no_assoc("-x?").is_ok());
22+
assert!(arithmetic::no_assoc("x+-x").is_ok());
23+
assert!(arithmetic::no_assoc("-x+x").is_ok());
24+
assert!(arithmetic::no_assoc("-x+-x").is_ok());
25+
assert!(arithmetic::no_assoc("x+x?").is_ok());
26+
assert!(arithmetic::no_assoc("x?+x").is_ok());
27+
assert!(arithmetic::no_assoc("x?+x?").is_ok());
28+
assert!(arithmetic::no_assoc("x+-x?").is_ok());
29+
assert!(arithmetic::no_assoc("x?+-x?").is_ok());
30+
assert!(arithmetic::no_assoc("-x?+-x?").is_ok());
31+
32+
assert!(arithmetic::no_assoc("x+x+x").is_err());
33+
assert!(arithmetic::no_assoc("x?+x+x").is_err());
34+
assert!(arithmetic::no_assoc("-x+x+x").is_err());
35+
assert!(arithmetic::no_assoc("x+-x+x").is_err());
36+
assert!(arithmetic::no_assoc("x+x?+x").is_err());
37+
assert!(arithmetic::no_assoc("x+x?+-x").is_err());
38+
assert!(arithmetic::no_assoc("x+x?+x?").is_err());
39+
}

tests/pass/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod arithmetic_ast;
33
mod arithmetic_infix;
44
mod arithmetic_infix_ast;
55
mod arithmetic_infix_ast_span;
6+
mod arithmetic_no_associative;
67
mod arithmetic_with_left_recursion;
78
mod assembly_ast_dyn_type_param_bounds;
89
mod borrow_from_input;

0 commit comments

Comments
 (0)