sourceafPegger::Rules.fan


** A collection of PEG rules, ready for use!
mixin Rules {
    
    ** Matches the given string. 
    ** 
    ** Example PEG notation:
    ** 
    **   "ChuckNorris"
    static Rule str(Str string, Bool ignoreCase := true) {
        StrRule(string, ignoreCase) // TODO: validate the str is not empty
    }
    
    ** Matches one or more characters up to (but not including) the given string.  
    ** 
    ** Example PEG notation:
    ** 
    **   (!"ChuckNorris" .)+
    static Rule strNot(Str string, Bool ignoreCase := true) {
        StrNotRule(string, ignoreCase)  // TODO: validate the str is not empty
    }
    
//  TODO: glob Rule - maybe they *only* match until the end of the line? (so we can first read until EOL) 
//  static Rule glob(Str regex) {
//      RuleTodo()
//  }
//
//  TODO: regex Rule
//  static Rule regex(Str regex) {
//      RuleTodo()
//  }
    
    ** Matches the given character.  
    ** 
    ** Example PEG notation:
    ** 
    **   "C"
    static Rule char(Int char) {
        CharRule(char.toChar.toCode) |Int peek->Bool| { char == peek }
    }

    ** Matches any character.  
    ** 
    ** PEG notation:
    ** 
    **   "."
    static Rule anyChar() {
        CharRule(".") |Int peek->Bool| { true }
    }

    ** Matches any character except the given one.  
    ** 
    ** Example PEG notation:
    ** 
    **   !"C" .
    static Rule anyCharNot(Int char) {
        CharRule("!${char.toChar.toCode} .") |Int peek->Bool| { char != peek }
    }

    ** Matches any character in the given list.  
    ** 
    ** Example PEG notation:
    ** 
    **   [ChukNoris]
    static Rule anyCharOf(Int[] chars) {
        CharRule("[${Str.fromChars(chars).toCode(null)}]") |Int peek->Bool| { chars.contains(peek) }
    }
    
    ** Matches any character *not* in the given list.  
    ** 
    ** Example PEG notation:
    ** 
    **   ![ChukNoris] .
    static Rule anyCharNotOf(Int[] chars) {
        CharRule("![${Str.fromChars(chars).toCode(null)}] .") |Int peek->Bool| { !chars.contains(peek) }
    }

    ** Matches any character in the given range.  
    ** 
    ** Example PEG notation:
    ** 
    **   [C-N]
    static Rule anyCharInRange(Range charRange) {
        CharRule("[${charRange.min.toChar.toCode(null)}-${charRange.last.toChar.toCode(null)}]") |Int peek->Bool| { charRange.contains(peek) }
    }

    ** Matches any character *not* in the given range. 
    ** 
    ** Example PEG notation:
    ** 
    **   ![C-N] .
    static Rule anyCharNotInRange(Range charRange) {
        CharRule("![${charRange.min.toChar.toCode(null)}-${charRange.last.toChar.toCode(null)}] .") |Int peek->Bool| { !charRange.contains(peek) }
    }
    
    ** Matches any alphabetical character. 
    ** 
    ** PEG notation:
    ** 
    **   [a-zA-Z]
    static Rule anyAlphaChar() {
        CharRule("[a-zA-Z]") |Int peek->Bool| { peek.isAlpha }
    }

    ** Matches any alphabetical or numerical character. 
    ** 
    ** PEG notation:
    ** 
    **   [a-zA-Z0-9]
    static Rule anyAlphaNumChar() {
        CharRule("[a-zA-Z0-9]") |Int peek->Bool| { peek.isAlphaNum }
    }

    ** Matches any numerical character. 
    ** 
    ** PEG notation:
    ** 
    **   [0-9]
    static Rule anyNumChar() {
        CharRule("[0-9]") |Int peek->Bool| { peek.isDigit }
    }

    ** Matches any hexadecimal character. 
    ** 
    ** PEG notation:
    ** 
    **   [a-fA-F0-9]
    static Rule anyHexChar() {
        CharRule("[a-fA-F0-9]") |Int peek->Bool| { peek.isDigit || ('A'..'F').contains(peek) || ('a'..'f').contains(peek) }
    }
    
    ** Matches any whitespace character. 
    ** 
    ** PEG notation:
    ** 
    **   [ \t\n\r\f]
    static Rule anySpaceChar() {
        CharRule("[ ]") |Int peek->Bool| { peek.isSpace }
    }

    
    ** Matches multiple whitespace characters. 
    ** 
    ** PEG notation:
    ** 
    **   [ \t\n\r\f]+
    static Rule anySpaceChars() {
        oneOrMore(anySpaceChar)
    }

    ** Matches any *non* whitespace character. 
    ** 
    ** PEG notation:
    ** 
    **   ![ \t\n\r\f]
    static Rule anyNonSpaceChar() {
        CharRule("![ ] .") |Int peek->Bool| { !peek.isSpace }
    }

    ** Processes the given rule and returns success whether it passes or not. 
    ** 
    ** Example PEG notation:
    ** 
    **   (rule)?
    static Rule optional(Rule rule) {
        RepetitionRule(0, 1, rule)
    }
    
    ** Processes the given rule repeatedly until it fails. 
    ** 
    ** Example PEG notation:
    ** 
    **   (rule)*
    static Rule zeroOrMore(Rule rule) {
        RepetitionRule(0, null, rule)
    }
    
    ** Processes the given rule repeatedly until it fails.
    ** Returns success if it succeeded at least once.
    ** 
    ** Example PEG notation:
    ** 
    **   (rule)+
    static Rule oneOrMore(Rule rule) {
        RepetitionRule(1, null, rule)
    }
    
    ** Processes the given rule repeatedly until it fails.
    ** Returns success if it succeeded at least 'n' times.
    ** 
    ** Example PEG notation:
    ** 
    **   ???
    static Rule atLeast(Int n, Rule rule) {
        RepetitionRule(n, null, rule)
    }

    ** Processes the given rule repeatedly, but at most 'n' times.
    ** Returns success always.
    ** 
    ** Example PEG notation:
    ** 
    **   ???
    static Rule atMost(Int n, Rule rule) {
        RepetitionRule(null, n, rule)
    }

    ** Processes the given rule 'n' times.
    ** Returns success if the it always succeeded.
    ** 
    ** Example PEG notation:
    ** 
    **   rule rule rule ... rule
    static Rule nTimes(Int times, Rule rule) {
        RepetitionRule(times, times, rule)
    }

    ** Processes the given rule at most 'n' times.
    ** Returns success if it succeeded at least 'n' times.
    ** 
    ** Example PEG notation:
    ** 
    **   ???
    static Rule between(Range times, Rule rule) {
        RepetitionRule(times.min, times.max, rule)
    }

    ** Processes the given rules in order until.
    ** Returns success if they all succeeded.
    ** 
    ** Example PEG notation:
    ** 
    **   rule1 rule2 rule3 ... rule4
    ** 
    ** When defining a 'sequence()' rule you may also use it-block syntax:
    ** 
    **   sequence { rule1, rule2, rule3, }
    static Rule sequence(Rule[] rules := [,]) {
        SequenceRule(rules)
    }
    
    ** Processes the given rules in order until one succeeds.
    ** Returns success any succeeded.
    ** 
    ** Example PEG notation:
    ** 
    **   rule1 / rule2 / rule3 / ... / rule4
    ** 
    ** When defining a 'firstOf()' rule you may also use it-block syntax:
    ** 
    **   firstOf { rule1, rule2, rule3, }
    static Rule firstOf(Rule[] rules := [,]) {
        FirstOfRule(rules)
    }
    
    ** A placeholder. 
    ** The rule will always succeed if 'pass' is 'true', and always fail if 'pass' is 'false'.
    static Rule todo(Bool pass := false) {
        TodoRule(pass)
    }

    ** Essentially a no-op rule as it always returns 'true' - but processes the given action func when successful.
    ** Useful for inserting arbitrary actions in sequences:
    ** 
    **   sequence { rule1, doAction { echo("Hello!") }, rule2 }
    ** 
    ** Example PEG notation:
    ** 
    **   ???
    static Rule doAction(|Str|? action) {
        ActionRule(action)
    }
    
    ** Processes the given rule and return success if it succeeded.
    ** The rule is always rolled back so the characters may be subsequently re-read. 
    ** 
    ** Example PEG notation:
    ** 
    **   &(rule)
    static Rule onlyIf(Rule rule) {
        PredicateRule(rule, false)
    }
    
    ** Processes the given rule and return success if it failed.
    ** The rule is always rolled back so the characters may be subsequently re-read. 
    ** 
    ** Example PEG notation:
    ** 
    **   !(rule)
    static Rule onlyIfNot(Rule rule) {
        PredicateRule(rule, true)
    }
}