Skip to content

Latest commit

 

History

History
65 lines (51 loc) · 2.44 KB

customMatchers.md

File metadata and controls

65 lines (51 loc) · 2.44 KB

Defining Custom Matchers

Microgrammar capabilities can be extended by implementing the MatchingLogic interface. Implementations of MatchingLogic can be used in microgrammar definition fields.

While this is a low level interface, it's not hard to implement. As an example, consider the core Literal class that matches a literal string:

export class Literal implements MatchingLogic {

    public $id = `Literal[${this.literal}]`;

    constructor(public literal: string) {
    }

    public matchPrefix(is: InputState): MatchPrefixResult {
        const peek = is.peek(this.literal.length);
        return (peek === this.literal) ?
            matchPrefixSuccess(new TerminalPatternMatch(this.$id, this.literal, is.offset, this.literal) ) :
            new MatchFailureReport(this.$id, is.offset, {},
                `Did not match literal [${this.literal}]: saw [${peek}]`);
    }

    public canStartWith(char: string): boolean {
        return this.literal[0] === char;
    }

    get requiredPrefix(): string {
        return this.literal;
    }
}

The most important method is matchPrefix. This implementation looks ahead in the input using the InputState interface to see if a match is possible. If it is not, it returns a MatchFailureReport. The remaining two methods are optional, for optimization.

The full MatchingLogic interface is as follows:

export interface MatchingLogic extends Term {

    /**
     * Optimization property. Prefix that's required for this to match.
     * Return undefined if we don't know. If we can provide this information,
     * it can make matching much more efficient if this is the first
     * matcher in a Microgrammar.
     */
    readonly requiredPrefix?: string;

    /**
     * Core matching method. Can we match at the present point in the
     * given InputState? Context arguments may be used by matchers that
     * require knowledge of current match or global context.
     * @param is input state
     * @param thisMatchContext context for this match, beginning from the top level and
     * passed into nested matchers
     * @param parseContext context for the whole parsing operation we're in: e.g. parsing a file
     */
    matchPrefix(is: InputState, thisMatchContext: {}, parseContext: {}): MatchPrefixResult;

    /**
     * Optimization method. Can a match start with this character?
     * @param char character to test for
     */
    canStartWith?(char: string): boolean;

}