diff options
Diffstat (limited to 'llparse-builder/src/builder.ts')
-rw-r--r-- | llparse-builder/src/builder.ts | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/llparse-builder/src/builder.ts b/llparse-builder/src/builder.ts new file mode 100644 index 0000000..a335a85 --- /dev/null +++ b/llparse-builder/src/builder.ts @@ -0,0 +1,147 @@ +import * as code from './code'; +import * as node from './node'; +import { Property, PropertyType } from './property'; +import { Span } from './span'; +import * as transform from './transform'; + +export { code, node, transform, Property, PropertyType, Span }; +export { Edge } from './edge'; +export { LoopChecker } from './loop-checker'; +export { ISpanAllocatorResult, SpanAllocator } from './span-allocator'; +export { Reachability } from './reachability'; + +/** + * Construct parsing graph for later use in `llparse`. + */ +export class Builder { + /** + * API for creating external callbacks and intrinsic operations. + */ + public readonly code: code.Creator = new code.Creator(); + + /** + * API for creating character transforms for use in nodes created with + * `builder.node()` + */ + public readonly transform: transform.Creator = new transform.Creator(); + + private readonly privProperties: Map<string, Property> = new Map(); + + // Various nodes + + /** + * Create regular node for matching characters and sequences. + * + * @param name Node name + */ + public node(name: string): node.Match { + return new node.Match(name); + } + + /** + * Create terminal error node. Returns error code to user, and sets reason + * in the parser's state object. + * + * This node does not consume any bytes upon execution. + * + * @param errorCode Integer error code + * @param reason Error description + */ + public error(errorCode: number, reason: string): node.Error { + return new node.Error(errorCode, reason); + } + + /** + * Create invoke node that calls either external user callback or an + * intrinsic operation. + * + * This node does not consume any bytes upon execution. + * + * NOTE: When `.invoke()` is a target of `node().select()` - callback must + * have signature that accepts `.select()`'s value, otherwise it must be of + * the signature that takes no such value. + * + * @param fn Code instance to invoke + * @param map Object with integer keys and `Node` values. Describes + * nodes that are visited upon receiving particular + * return integer value + * @param otherwise Convenience `Node` argument. Effect is the same as calling + * `p.invoke(...).otherwise(node)` + */ + public invoke(fn: code.Code, map?: node.IInvokeMap | node.Node, + otherwise?: node.Node): node.Invoke { + let res: node.Invoke; + + // `.invoke(name)` + if (map === undefined) { + res = new node.Invoke(fn, {}); + // `.invoke(name, otherwise)` + } else if (map instanceof node.Node) { + res = new node.Invoke(fn, {}); + otherwise = map; + } else { + res = new node.Invoke(fn, map as node.IInvokeMap); + } + + if (otherwise !== undefined) { + res.otherwise(otherwise); + } + return res; + } + + /** + * Create node that consumes number of bytes specified by value of the + * state's property with name in `field` argument. + * + * @param field Property name to use + */ + public consume(field: string): node.Consume { + return new node.Consume(field); + } + + /** + * Create non-terminal node that returns `errorCode` as error number to + * user, but still allows feeding more data to the parser. + * + * This node does not consume any bytes upon execution. + * + * @param errorCode Integer error code + * @param reason Error description + */ + public pause(errorCode: number, reason: string): node.Pause { + return new node.Pause(errorCode, reason); + } + + // Span + + /** + * Create Span with given `callback`. + * + * @param callback External span callback, must be result of + * `.code.span(...)` + */ + public span(callback: code.Span): Span { + return new Span(callback); + } + + // Custom property API + + /** + * Allocate space for property in parser's state. + */ + public property(ty: PropertyType, name: string): void { + if (this.privProperties.has(name)) { + throw new Error(`Duplicate property with a name: "${name}"`); + } + + const prop = new Property(ty, name); + this.privProperties.set(name, prop); + } + + /** + * Return list of all allocated properties in parser's state. + */ + public get properties(): ReadonlyArray<Property> { + return Array.from(this.privProperties.values()); + } +} |