Skip to content

Position

mattbierner edited this page Dec 9, 2014 · 2 revisions

The position object is part of the parser state and tracks the current position in the input stream. The default Bennu Position, parse.Position, only tracks an index in the input stream and is used primarily error messaging.

You can use a custom position object to provide more detailed error messages (such as tracking line number and column for text input). And a custom position object can also be used as position aware user state. You do not need to defined a custom parser state to use a custom position so long as you implement the standard interfaces.

Interface

Positions must be immutable. All custom position functions must be side effect free and referentially transparent.

position.increment(tok, restOfInput)

Return the next position having consuming token tok, with remaining input [Nu][nu] stream restOfInput.

customPosition.compare(otherPos)

Compares this position to otherPos.

Return a number less than, equal to, or greater than zero if this position is before, at, or ahead of otherPos in the input stream.

customPosition.toString()

Return a human readable string for this position. Used for error messages.

Example - Tracking Previous Consumed Token

Example of using position as position- aware user data. Regular user data cannot know when the input advanced, but position can.

// Defined interface
var LastConsumedPosition = function \ index previous =self-> {
    self.index = index;
    self.previous = previous;
};

LastConsumedPosition.initial = new LastConsumedPosition(0, null);

LastConsumedPosition.prototype.toString := \ =self-> self.index + ''; 

LastConsumedPosition.prototype.inc := \tok =self->
    return new Position(self.index + 1, tok); 

LastConsumedPosition.prototype.eq := \other =self->
    return other && other.index === self.index && other.previous === self.previous; 

// Define a parser that uses this
var notFollowing = \x ->
    parse.getPosition
        .chain(\pos ->
             ?pos.previous === x
                :fail x
                :always x);

var notFollowingA = notFollowing 'a';

// Run with custom position
parse.runState(
    parse.sequence(
        parse.anyToken,
        notFollowingA,
        parse.anyToken),
    new parse.ParserState(
        stream.from 'xyz',
        LastConsumedPosition.initial));
Clone this wiki locally