ftl-peg

Introduction

This small extension provides parsing expression grammar pattern matching with the help of the ftl egg. The parsing expressions are implemented as meta interfaces that can be constructed and combined programmatically. Data to match is consumed from arbitrary lookahead input interfaces.

Requirements

Interfaces

Mark input (mi)

An arbitrary lookahead input stream. The concrete implementations mi=list, mi=vector, mi=reverse-vector, mi=string, mi=reverse-string are available and operate on list stacks of their respective associated datatypes and their subranges.

A new implementation of the interface is created as

(mi-interface read empty? mark restore forget)

and the following methods are supported:

((%mi-read mi) in) => (values) | (values obj in)

Reads the next token from the input. If there is no more input, nothing is returned, otherwise the token and the new input are returned.

((%mi-empty? mi) in) => #t | #f

Returns whether the given input has no more tokens to read.

((%mi-mark mi) in) => in

Returns an input to use for further reading if a future reset to the current position may be necessary.

((%mi-restore mi) in) => in

Returns the input reset to the last position stored by the mark method.

((%mi-forget mi) in) => in

Returns the input with the last position stored by the mark method removed.

Matcher (m)

Represents a parsing expression that can be applied to any mark input.

A new implementation of this interface is created as

(m-interface match-%mi)

and the following basic operation is supported:

(((%m-match-%mi m) mi) in) => (values obj | #f in)

Compares the start of the given mark input to some pattern and returns the matching object and the advanced mark input in case of success or #f and the mark input restored to its former position.

To be able to create recursive patterns, the following special operations are supported:

(m-proxy) => <m-interface>

Creates a proxy matcher interface with no stored procedure.

(m-implement! tgt-m src-m)

Fixes a proxy matcher by copying the stored procedure from another matcher interface. Signals an error if the target interface is not a proxy or if the source interface is a proxy as well.

Most likely you will not have to create your own implementations of the matcher interface by hand but will rather use one of the generator procedures below.

Matcher constants and generators

Single item matchers

Creates a matcher that matches a sequence of arbitrary tokens from the input that is at least min-repeat long and at most max-repeat long. If max-repeat is #f, any remaining input is eaten up. The matched tokens are collected using the given accumulator interface.

((m=item/%t t) f) => <m-interface>

Creates a matcher that matches a single element satisfying the given test.

((m=not-item/%t t) f) => <m-interface>

Creates a matcher that matches a single element not satisfying the given test.

Multiple item matchers

Creates a matcher that matches a sequence of tokens matching the given test that is at least min-repeat long and at most max-repeat long. If max-repeat is #f, any remaining input is eaten up. The matched tokens are collected using the given accumulator interface.

Creates a matcher that matches a sequence of tokens not matching the given test that is at least min-repeat long and at most max-repeat long. If max-repeat is #f, any remaining input is eaten up. The matched tokens are collected using the given accumulator interface.

((m=sequence-%i/%t->%a i t a) src #!optional dst) => <m-interface>

Creates a matcher that matches all elements from the given input in sequence and collects them in the destination using the given accumulator.

((m=alternate-%g/%t g t) src) => <m-interface>

Creates a matcher that matches any element of the given sequence using the given test.

((m=not-alternate-%g/%t g t) src) => <m-interface>

Creates a matcher that matches any element not in the given sequence using the given test.

Compound matchers

Creates a matcher that matches a sequence of tokens matching the given matcher that is at least min-repeat long and at most max-repeat long. If max-repeat is #f, any remaining matching input is eaten up. The matched tokens are collected using the given accumulator interface.

((m=sequence->%a a) ms #!optional dst) => <m-interface>

Creates a matcher that matches all the given matchers in sequence and collects their results in the destination using the given accumulator.

(m=alternate ms) => <m-interface>

Creates a matcher that matches any of the given matchers.

Look ahead matchers

((m=look-ahead/%t t) f m) => <m-interface>

Creates a matcher that matches whenever the result of the given matcher m satisfies the given test t with fixed parameter f. The new matcher always never effectively changes the position of its mark input, though. It returns whatever the test function returns.

(m=positive-look-ahead m) => <m-interface>

Creates a matcher that matches whenever the given matcher matches and returns the same result but never effectively changes the position of its mark input.

(m=negative-look-ahead m) => <m-interface>

Creates a matcher that matches and returns #t whenever the given matcher doesn't match. If the given matcher matches, the new matcher doesn't match and returns #f. It never effectively changes the position of its mark input.