Rule

public protocol Rule : CustomStringConvertible

Behavioural rule is both an extension to and ultimately a replacement for current Rule. It bakes in the logic for repeating, negation, lookahead, as well as transient and void rules both flattening the evaluation hierarchy and making it easier to extend (previously implementations would have to add any of this logic themselves, and it’s easy to get wrong.

  • The behaviour for the rule controlling things like cardinality and lookahead

    Declaration

    Swift

    var behaviour: Behaviour { get }
  • The annotations on the rule

    Declaration

    Swift

    var annotations: RuleAnnotations { get }
  • This function implements the actual test. It is responsible soley for performing the test. The scanner head will be managed correctly based on success (it will be left in the position at the end of the test), or returned to its pre-test position on failure.

    Declaration

    Swift

    func test(with lexer: LexicalAnalyzer, for ir: IntermediateRepresentation) throws

    Parameters

    lexer

    The lexer controlling the scanner

    ir

    The intermediate representation

  • Creates a rule with the specified behaviour and annotations.

    Declaration

    Swift

    func rule(with behaviour: Behaviour?, annotations: RuleAnnotations?) -> Rule

    Parameters

    behaviour

    The behaviour for the new instance, if nil the rule should use the default behaviour for the producer.

    annotations

    The annotations for the new rule, if nil the rule should use the default behaviour for the producer.

    Return Value

    A new instance with the specified behaviour and annotations.

  • An abrieviated description of the rule that should reflect behaviour, but not annotations and should not expand references

    Declaration

    Swift

    var shortDescription: String { get }
  • match(with:for:) Default implementation

    Should perform the actual check and manage the communicaion with the supplied IntermedidateRepresentation. If the match fails, and that failure cannot be ignored an Error should be thrown. It is the responsiblity of the implementer to ensure the following basic pattern is followed

    1. ir.willEvaluate() is called to inform the ir that evaluation is beginning. If the ir returns an existing match result that should be used (proceed to step XXX)
    2. lexer.mark() should be called so that an accurate LexicalContext can be generated.
    3. Perform apply your rule using lexer.
    4. Depending on the outcome, and the to-be-generated token:
    5. If the rule was satisfied, return a MatchResult.success together with a generated lexer.proceed() generated context
    6. If the rule was satisfied, but the result should be consumed (no node/token created, but scanning should proceed after the match) return MatchResult.consume with a generated lexer.proceed() context
    7. If the rule was not satisfied but the failure can be ignored return MatchResult.ignoreFailure. Depending on your grammar you may want to leave the scanner in the same position in which case issue a lexer.proceed() but discard the result. Otherwise issue a lexer.rewind().
    8. If the rule was not satisfied but the failure should not be ignored. Call lexer.rewind() and return a MatchResult.failure
    9. If the rule was not satisifed and parsing of this branch of the grammar should stop immediately throw an Error

    For standard implementations of rules that should satisfy almost every grammar see ParserRule and ScannerRule. ParserRule has a custom case which provides all of the logic above with the exception of actual matching which is a lot simpler, and it is recommended that you use that if you wish to provide your own rules.

    Default Implementation

    Standard implementation that uses the evaluate function to apply the behaviour of the rule.

    Declaration

    Swift

    func match(with lexer: LexicalAnalyzer, for ir: IntermediateRepresentation) throws

    Parameters

    with

    The LexicalAnalyzer providing the scanning functions

    for

    The IntermediateRepresentation that wil be building any data structures required for subsequent interpretation of the parsing results

  • parse(as:) Extension method

    Changes the behaviour (or creates a rule with the behaviour) to create a token.

    Declaration

    Swift

    public func parse(as token: TokenType) -> Rule

    Parameters

    rule

    The rule (or thing that can become a rule)

    Return Value

    A rule

  • annotatedWith(_:) Extension method

    Creates a new instance of the rule annotated with the specified annotations. If you supply annotations that impact scanning (token, void, transient), they will be filtered out, but applied to the resultant behaviour.

    Declaration

    Swift

    public func annotatedWith(_ annotations: RuleAnnotations) -> Rule

    Parameters

    annotations

    The desired annotations

    Return Value

    A new instance of the rule with the specified annotations

  • require(_:) Extension method

    Creates a new instance of the rule that requires matches of the specified cardinality

    Declaration

    Swift

    public func require(_ cardinality: Cardinality) -> Rule

    Parameters

    cardinality

    The desired cardinalitiy

    Return Value

    The new rule instance

  • lookahead() Extension method

    Creates a new instance of the rule set to have lookahead behaviour

    // Creates a lookahead version of of the rule let lookahead = -CharacterSet.letters.lookahead()

    Declaration

    Swift

    public func lookahead() -> Rule

    Return Value

    A new version of the rule

  • negate() Extension method

    Creates a new instance of the rule which negates its match. Note that negate does not toggle, that is !!rule != rule.

    // Creates a negated version of of the rule let notLetter = CharacterSet.letters.negate()

    Declaration

    Swift

    public func negate() -> Rule

    Return Value

    A new version of the rule

  • skip() Extension method

    Creates a new instance of the rule which skips.

    // Creates a skipping version of of the rule let skipLetters = CharacterSet.letters.skip()

    Declaration

    Swift

    public func skip() -> Rule

    Return Value

    A new version of the rule

  • scan() Extension method

    Creates a new instance of the rule which scans.

    // Creates a scanning version of of the rule let scanLetters = CharacterSet.letters.scan()

    Declaration

    Swift

    public func scan() -> Rule

    Return Value

    A new version of the rule

  • reference(_:annotations:) Extension method

    Undocumented

    Declaration

    Swift

    public func reference(_ kind:Behaviour.Kind, annotations: RuleAnnotations? = nil)->Rule
  • error Extension method

    The user specified (in an annotation) error associated with the rule

    Declaration

    Swift

    public var error: String? { get }
  • subscript(_:) Extension method

    Returns the value of the specific RuleAnnotationValue identified by annotation if present

    Declaration

    Swift

    public subscript(annotation: RuleAnnotation) -> RuleAnnotationValue? { get }
  • structural Extension method

    true if the rule creates ndoes, false otherwise

    Declaration

    Swift

    public var structural: Bool { get }
  • skipping Extension method

    true if the rule creates ndoes, false otherwise

    Declaration

    Swift

    public var skipping: Bool { get }
  • scanning Extension method

    true if the rule creates ndoes, false otherwise

    Declaration

    Swift

    public var scanning: Bool { get }
  • evaluate(_:using:and:) Extension method

    Standard implementation that applies the behaviour of the rule.

    Declaration

    Swift

    public func evaluate(_ matcher:@escaping Test, using lexer:LexicalAnalyzer, and ir:IntermediateRepresentation) throws

    Parameters

    matcher

    The test to use, wrap, in the specified behaviour.

    lexer

    The lexer controlling the scanning head

    ir

    The intermediate representation to use

    Return Value

    The match result