glop 0.2.5

Glue Language for OPerations
Documentation
use ast::*;

#[pub]
glop -> Glop
    = __ ms:matches __ { Glop{ matches: ms } }

matches -> Vec<Match>
    = m:match __ ms:matches { let mut ms = ms; ms.insert(0, m); ms }
    / m:match { vec![m] }

match -> Match
    = "when" __ "(" __ c:conditions __ ")" __ a:matchActions {?
		let acting_roles_set = acting_roles(&c);
		let acting_roles = acting_roles_set.iter().collect::<Vec<&String>>();
		if acting_roles.len() > 1 {
			Err("multiple acting roles in the same match is not supported")
		} else {
			let acting_role = if acting_roles.is_empty() {
				None
			} else {
				Some(acting_roles[0].to_string())
			};
			Ok(Match{
				conditions: c,
				actions: a,
				acting_role: acting_role,
			})
		}
    }

matchActions -> Vec<Action>
	= "{" __ a:actions __ "}" { a }
	/ v:$("#!" (!"!#" .)+) "!#" { vec![Action::Script(String::from(v))] }

conditions -> Vec<Condition>
    = c:condition __ "," __ cs:conditions { let mut cs = cs; cs.insert(0, c); cs }
    / c:condition { vec![c] }

condition -> Condition
    = k:identifier __ op:cmpop __ v:value { Condition::Cmp(k, op, v) }
    / unaryfunc

identifier -> Identifier
    = part:idpart "." rest:identifier { let mut rest = rest; rest.insert(0, part); rest }
    / part:idpart { vec![part] }

idpart -> String
    = v:$([a-z][a-z0-9_^.]+) { String::from(v) }

value -> String
    = v:$([A-Za-z0-9_]+) { String::from(v) }
    / "\"" v:$([^"]+) "\"" { String::from(v) }

unaryfunc -> Condition
    = "message" __ topic:identifier __ src_role:maybeSrcRole __ acting_role:maybeActingRole {
		Condition::Message{
			topic: topic.join("."),
			src_role: src_role,
			acting_role: acting_role,
		}
	}
    / "is_set" __ k:identifier { Condition::IsSet(k) }
    / "is_unset" __ k:identifier { Condition::IsUnset(k) }

maybeSrcRole -> Option<String>
	= "from" __ role:idpart { Some(role) }
	/ { None }

maybeActingRole -> Option<String>
	= "as" __ role:idpart { Some(role) }
	/ { None }

cmpop -> CmpOpcode
    = "==" { CmpOpcode::Equal }
    / "!=" { CmpOpcode::NotEqual }

actions -> Vec<Action>
    = n:action __ ns:actions { let mut ns = ns; ns.insert(0, n); ns }
    / n:action { vec![n] }
	/ { vec![] }

action -> Action
    = "var" __ "set" __ k:identifier __ v:value __ ";" { Action::SetVar(k, v) }
    / "var" __ "unset" __ k:identifier __ ";" { Action::UnsetVar(k) }
    / "script" __ v:$("#!" (!"!#" .)+) "!#" { Action::Script(String::from(v)) }
    / m:match { Action::Match(m) }

/* The following is borrowed from rust-peg's own grammar */

__ = (whitespace / eol / comment)*

/* Modeled after ECMA-262, 5th ed., 7.4. */
comment
  = singleLineComment
  / multiLineComment

singleLineComment
  = "//" (!eolChar .)*

multiLineComment
  = "/*" (!"*/" .)* "*/"

/* Modeled after ECMA-262, 5th ed., 7.3. */
eol
  = "\n"
  / "\r\n"
  / "\r"
  / "\u{2028}"
  / "\u{2029}"

eolChar
  = [\n\r\u{2028}\u{2029}]

/* Modeled after ECMA-262, 5th ed., 7.2. */
whitespace
  = [ \t\u{00A0}\u{FEFF}\u{1680}\u{180E}\u{2000}-\u{200A}\u{202F}\u{205F}\u{3000}] // \v\f removed