bread-n-butter
Version:
Parser combinators for JavaScript and TypeScript
222 lines (221 loc) • 7.43 kB
TypeScript
/**
* Represents a parsing action; typically not created directly via `new`.
*/
export declare class Parser<A> {
/**
* The parsing action. Takes a parsing Context and returns an ActionResult
* representing success or failure.
*/
action: (context: Context) => ActionResult<A>;
/**
* Creates a new custom parser that performs the given parsing action.
*/
constructor(action: (context: Context) => ActionResult<A>);
/**
* Returns a parse result with either the value or error information.
*/
parse(input: string): ParseOK<A> | ParseFail;
/**
* Returns the parsed result or throws an error.
*/
tryParse(input: string): A;
/**
* Combines two parsers one after the other, yielding the results of both in
* an array.
*/
and<B>(parserB: Parser<B>): Parser<[A, B]>;
/** Parse both and return the value of the first */
skip<B>(parserB: Parser<B>): Parser<A>;
/** Parse both and return the value of the second */
next<B>(parserB: Parser<B>): Parser<B>;
/**
* Try to parse using the current parser. If that fails, parse using the
* second parser.
*/
or<B>(parserB: Parser<B>): Parser<A | B>;
/**
* Parse using the current parser. If it succeeds, pass the value to the
* callback function, which returns the next parser to use.
*/
chain<B>(fn: (value: A) => Parser<B>): Parser<B>;
/**
* Yields the value from the parser after being called with the callback.
*/
map<B>(fn: (value: A) => B): Parser<B>;
/**
* Returns the callback called with the parser.
*/
thru<B>(fn: (parser: this) => B): B;
/**
* Returns a parser which parses the same value, but discards other error
* messages, using the ones supplied instead.
*/
desc(expected: string[]): Parser<A>;
/**
* Wraps the current parser with before & after parsers.
*/
wrap<B, C>(before: Parser<B>, after: Parser<C>): Parser<A>;
/**
* Ignores content before and after the current parser, based on the supplied
* parser.
*/
trim<B>(beforeAndAfter: Parser<B>): Parser<A>;
/**
* Repeats the current parser between min and max times, yielding the results
* in an array.
*/
repeat(min?: number, max?: number): Parser<A[]>;
/**
* Returns a parser that parses between min and max times, separated by the separator
* parser supplied.
*/
sepBy<B>(separator: Parser<B>, min?: number, max?: number): Parser<A[]>;
/**
* Returns a parser that adds name and start/end location metadata.
*/
node<S extends string>(name: S): Parser<ParseNode<S, A>>;
}
/**
* Result type from `node`. See `node` for more details.
*/
export interface ParseNode<S extends string, A> {
type: "ParseNode";
name: S;
value: A;
start: SourceLocation;
end: SourceLocation;
}
/**
* Parser that yields the current `SourceLocation`, containing properties
* `index`, `line` and `column`.
*/
export declare const location: Parser<SourceLocation>;
/**
* Returns a parser that yields the given value and consumes no input.
*/
export declare function ok<A>(value: A): Parser<A>;
/**
* Returns a parser that fails with the given messages and consumes no input.
*/
export declare function fail<A>(expected: string[]): Parser<A>;
/**
* This parser succeeds if the input has already been fully parsed.
*/
export declare const eof: Parser<"<EOF>">;
/** Returns a parser that matches the exact text supplied. */
export declare function text<A extends string>(string: A): Parser<A>;
/**
* Returns a parser that matches the entire regular expression at the current
* parser position.
*/
export declare function match(regexp: RegExp): Parser<string>;
/** A tuple of parsers */
declare type ManyParsers<A extends any[]> = {
[]: Parser<A[P]>;
};
/** Parse all items, returning their values in the same order. */
export declare function all<A extends any[]>(...parsers: ManyParsers<A>): Parser<A>;
/** Parse using the parsers given, returning the first one that succeeds. */
export declare function choice<Parsers extends Parser<any>[]>(...parsers: Parsers): Parser<ReturnType<Parsers[number]["tryParse"]>>;
/**
* Takes a lazily invoked callback that returns a parser, so you can create
* recursive parsers.
*/
export declare function lazy<A>(fn: () => Parser<A>): Parser<A>;
/**
* Represents a location in the input (source code). Keeps track of `index` (for
* use with `.slice` and such), as well as `line` and `column` for displaying to
* users.
*/
export interface SourceLocation {
/** The string index into the input (e.g. for use with `.slice`) */
index: number;
/**
* The line number for error reporting. Only the character `\n` is used to
* signify the beginning of a new line.
*/
line: number;
/**
* The column number for error reporting.
*/
column: number;
}
/**
* Represents the result of a parser's action callback.
*/
export declare type ActionResult<A> = ActionOK<A> | ActionFail;
/**
* Represents a successful result from a parser's action callback. This is made
* automatically by calling `context.ok`. Make sure to use `context.merge`
* when writing a custom parser that executes multiple parser actions.
*/
export interface ActionOK<A> {
type: "ActionOK";
location: SourceLocation;
value: A;
furthest: SourceLocation;
expected: string[];
}
/**
* Represents a successful result from a parser's action callback. This is made
* automatically by calling `context.ok`. Make sure to use `context.merge`
* when writing a custom parser that executes multiple parser actions.
*/
export interface ActionFail {
type: "ActionFail";
furthest: SourceLocation;
expected: string[];
}
/**
* Represents the current parsing context.
*/
declare class Context {
/** the string being parsed */
input: string;
/** the current parse location */
location: SourceLocation;
constructor(options: {
input: string;
location: SourceLocation;
});
/**
* Returns a new context with the supplied location and the current input.
*/
moveTo(location: SourceLocation): Context;
private _internal_move;
/**
* Represents a successful parse ending before the given `index`, with the
* specified `value`.
*/
ok<A>(index: number, value: A): ActionResult<A>;
/**
* Represents a failed parse starting at the given `index`, with the specified
* list `expected` messages (note: this list usually only has one item).
*/
fail<A>(index: number, expected: string[]): ActionResult<A>;
/**
* Merge two sequential `ActionResult`s so that the `expected` and location data
* is preserved correctly.
*/
merge<A, B>(a: ActionResult<A>, b: ActionResult<B>): ActionResult<B>;
}
/**
* Represents a successful parse result.
*/
export interface ParseOK<A> {
type: "ParseOK";
/** The parsed value */
value: A;
}
/**
* Represents a failed parse result, where it failed, and what types of
* values were expected at the point of failure.
*/
export interface ParseFail {
type: "ParseFail";
/** The input location where the parse failed */
location: SourceLocation;
/** List of expected values at the location the parse failed */
expected: string[];
}
export {};