diff --git a/src/labels/labels.rs b/src/labels/labels.rs index 16d055e..19c3a9f 100644 --- a/src/labels/labels.rs +++ b/src/labels/labels.rs @@ -39,6 +39,100 @@ fn label_line() -> impl Rule { (":", Tag("label", label_name), eol) } +fn tile_kind() -> impl Rule { + (Opt((tile_color, ww)), tile_base_kind) +} + +fn tile_color() -> impl Rule { + ( + Alt(("blue", "green", "cyan", "red", "purple", "yellow", "white")), + Not('a'..='z'), + ) +} + +fn tile_base_kind() -> impl Rule { + let ac = ( + And('a'..='c'), + Alt(( + "ammo", + "bear", + "blinkwall", + "bomb", + "boulder", + "breakable", + "bullet", + "clockwise", + "counter", + )), + ); + let dk = ( + And('d'..='k'), + Alt(( + "door", + "duplicator", + "empty", + "energizer", + "fake", + "forest", + "gem", + "head", + "invisible", + "key", + )), + ); + let lr = ( + And('l'..='r'), + Alt(( + "line", "lion", "monitor", "normal", "object", "passage", "player", "pusher", + "ricochet", "ruffian", + )), + ); + let s = ( + And("s"), + Alt(( + "scroll", + "segment", + "shark", + "sliderew", + "sliderns", + "slime", + "solid", + "spinninggun", + "star", + )), + ); + let tz = ( + And('t'..='z'), + Alt(("tiger", "torch", "transporter", "water")), + ); + Alt((ac, dk, lr, s, tz)) +} + +fn condition() -> impl Rule { + let base = Alt(( + "alligned", + ("any", ww, tile_kind), + ("blocked", ww, direction), + "contact", + "energized", + )); + (star!("not", ww), base) +} + +fn direction() -> impl Rule { + let modifier = Alt(("cw", "ccw", "rndp", "opp")); + (star!(modifier, ww), base_direction, Not('a'..='z')) +} + +fn base_direction() -> impl Rule { + // Some directions are prefixes of others, which can break parsing. + // To prevent this, we roughly order the strings from longest to shortest. + let dynamic = Alt(("flow", "rndne", "rndns", "rnd", "seek")); + let long = Alt(("north", "south", "east", "west", "idle")); + let short = Alt(("n", "s", "e", "w", "i")); + (Alt((dynamic, long, short)), Not('a'..='z')) +} + fn label_name() -> impl Rule { let namespace = (plus!(word_char), "~"); ( @@ -98,6 +192,24 @@ mod test { parse_err(&label_name, "~foo"); } + #[test] + fn test_direction() { + parse(&direction, "n"); + parse(&direction, "north"); + parse(&direction, "rndp rndne"); + parse(&direction, "opp seek"); + parse(&direction, "cw cw cw flow"); + } + + #[test] + fn test_condition() { + parse(&condition, "alligned"); + parse(&condition, "blocked seek"); + parse(&condition, "not blocked rndp seek"); + parse(&condition, "any red lion"); + parse(&condition, "any bear"); + } + #[test] fn test_references() { let mut p = Parser::new("#send foo");