From 9e311d41d3ddca3b430166f0093890d3c5ccfd01 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Jun 2015 07:26:38 -0400 Subject: [PATCH] Conditional alternatives. --- src/grammar/parse_tree.rs | 20 +++++++++++++++++++- src/normalize/mod.rs | 4 ++-- src/parser/mod.rs | 25 +++++++++++++++++++++++-- src/parser/test.rs | 11 +++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/grammar/parse_tree.rs b/src/grammar/parse_tree.rs index 8249d5e..0c732e9 100644 --- a/src/grammar/parse_tree.rs +++ b/src/grammar/parse_tree.rs @@ -49,7 +49,7 @@ grammar Type<'input, T> { // Example 2: conditional patterns Expr: Expr = { - ~Expr "(" ~Comma ")" => Expr::CallExpr(~~~); + ~Expr "(" ~Comma ")" => Expr::CallExpr(~~); ID if M !~ "NO_ID" => { }; @@ -92,10 +92,28 @@ pub struct NonterminalData { pub struct Alternative { pub expr: Vec, + // if C, only legal in macros + pub condition: Option, + // => { code } pub action: Option, } +#[derive(Clone, Debug)] +pub enum Condition { + // X == "Foo", equality + Equals(InternedString, InternedString), + + // X != "Foo", inequality + NotEquals(InternedString, InternedString), + + // X ~~ "Foo", regexp match + Match(InternedString, InternedString), + + // X !~ "Foo", regexp non-match + NotMatch(InternedString, InternedString), +} + #[derive(Clone, Debug)] pub enum Symbol { // ( ) etc diff --git a/src/normalize/mod.rs b/src/normalize/mod.rs index 79ea44f..47ebe94 100644 --- a/src/normalize/mod.rs +++ b/src/normalize/mod.rs @@ -20,8 +20,8 @@ pub fn normalize(input: &pt::Grammar) -> Result { // X = ...1 Vec_X ...2 // Comma_X: Vec<> = ...; // -// AFTER THIS POINT: No more macros or macro references, though type -// indirections may occur. +// AFTER THIS POINT: No more macros, macro references, or guarded +// alternatives, though type indirections may occur. // mod macro_expand; // Computes types where the user omitted them (or diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d5c45f5..05e538e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -67,13 +67,34 @@ rusty_peg! { ("{" "}" ";") => a; ALTERNATIVE: Alternative = - ( ";") => Alternative { + ( ";") => Alternative { expr: s, + condition: c, action: a }; + IF_COND: Condition = + ("if" ) => c; + ACTION: String = ("=>" ) => b; + // Conditions + + COND: Condition = + (EQUALS_COND / NOT_EQUALS_COND / MATCH_COND / NOT_MATCH_COND); + + EQUALS_COND: Condition = + ( "==" ) => Condition::Equals(a, b); + + NOT_EQUALS_COND: Condition = + ( "!=" ) => Condition::NotEquals(a, b); + + MATCH_COND: Condition = + ( "~~" ) => Condition::Match(a, b); + + NOT_MATCH_COND: Condition = + ( "!~" ) => Condition::NotMatch(a, b); + // Symbols SYMBOL: Symbol = @@ -148,7 +169,7 @@ rusty_peg! { () => intern(i); ID_RE: &'input str = - regex(r"[a-zA-Z_][a-zA-Z0-9_]*"); + regex(r"[a-zA-Z_][a-zA-Z0-9_]*") - ["if"]; LIFETIME: InternedString = () => intern(i); diff --git a/src/parser/test.rs b/src/parser/test.rs index 794719d..078c66c 100644 --- a/src/parser/test.rs +++ b/src/parser/test.rs @@ -82,3 +82,14 @@ fn macro_nt() { .unwrap(); } +#[test] +fn cond_nt() { + super::parse_nonterminal( + "Foo = { + X if E == \"Bar\"; + X if E ~~ \"Bar\"; + X if E != \"Bar\"; + X if E !~ \"Bar\"; + };").unwrap(); +} +