start: line+ # one line is either a rule optionally followed by an inline comment, # or a full-line comment line: rule (COMMENT)? -> line | COMMENT -> comment rule: ACTION OPERATION? ("IF" bool_expr)? | "DEFAULT" ":" ACTION -> default_rule ACTION: "ALLOW" | "DENY" OPERATION: "ANY" | "PROCESSING" | "EXPLORATION" FIELD: "FILE.SIZE" | "FILE.NAME" | "FILE.MODIFIED_AT" | "FILE.PATH" | "FILE.CREATED_AT" | "DIRECTORY.PATH" | "DIRECTORY.NAME" | "DIRECTORY.MODIFIED_AT" | "DIRECTORY.CREATED_AT" | "SHARE.NAME" | "SHARE.DESCRIPTION" | "SHARE.TYPE" | "DEPTH" OPERATOR: "MATCHES" | "IN" | ">=" | "<=" | "==" | ">" | "<" | "STARTSWITH" | "ENDSWITH" | "CONTAINS" ?bool_expr: or_expr ?or_expr: and_expr | or_expr "OR" and_expr -> or_ ?and_expr: not_expr | and_expr "AND" not_expr -> and_ ?not_expr: xor_expr | "NOT" not_expr -> not_ ?xor_expr: atom | xor_expr "XOR" atom -> xor ?atom: condition | "(" bool_expr ")" condition: FIELD OPERATOR value value: STRING | REGEX | NUMBER | list list: "[" [STRING ("," STRING)*] "]" REGEX: "REGEX" "(" STRING ")" # accept both single-quoted and double-quoted strings STRING: /"([^"\\]|\\.)*"/ | /'([^'\\]|\\.)*'/ NUMBER: /[0-9]+/ %import common.WS %ignore WS // ignore spaces/tabs # keep comments as tokens so we can parse comment lines and inline comments COMMENT: /#[^\n]*/