Mona
Composable parsing for JavaScript
Install / Use
/learn @zkat/MonaREADME
mona
mona is a Javascript library for easily writing reusable, composable parsers.
It makes parsing complex grammars easy and fun!
With mona, you simply write some Javascript functions that parse small pieces
of text and return any Javascript value, and then you glue them together into
big, intricate parsers using combinators to... combine them! No custom syntax
or separate files or separate command line tools to run: you can integrate this
into your regular JS app.
It even makes it really really easy to give excellent error messages, including line and column numbers, and messages with what was expected, with little to no effort.
New parsers are hella easy to write -- give it a shot! And if you're familiar with Parsec, then you've come to the right place. :)
Table of Contents
- Install
- Examples
- API
- Gentle Introduction to Monadic Parser Combinators
Install
$ npm install mona
You can directly require mona through your module loader of choice, or you can
use the prebuilt UMD versions found in the browser/ directory:
- Node.js/CommonJS -
var mona = require('mona') - ES6 Modules/Babel -
import mona from 'mona' - AMD -
define(['node_modules/mona/browser/mona'], function (mona) { ... }) - Global -
<script src=/js/node_modules/mona/browser/mona.min.js></script>
Examples
Parse a series of ints separated by commas
function commaInts () {
return mona.split(mona.integer(), mona.string(','))
}
mona.parse(commaInts(), '1,2,3,49829,49,139')
// => [1, 2, 3, 49829, 49, 139]
A simple, readable CSV parser in ~25 lines
function parseCSV (text) {
return mona.parse(csv(), text)
}
function csv () {
return mona.splitEnd(line(), mona.eol())
}
function line () {
return mona.split(cell(), mona.string(','))
}
function cell () {
return mona.or(quotedCell(),
mona.text(mona.noneOf(',\n\r')))
}
function quotedCell () {
return mona.between(mona.string('"'),
mona.string('"'),
mona.text(quotedChar()))
}
function quotedChar () {
return mona.or(mona.noneOf('"'),
mona.and(mona.string('""'),
mona.value('"')))
}
parseCSV('foo,"bar"\n"b""az",quux\n')
// => [['foo', 'bar'], ['b"az', 'quux']]
API
mona is a package composed of multiple other packages, re-exported through a
single module. You have the option of installing mona from npm directly, or
installing any of the subpackages and using those independently.
This API section is organized such that each parser or function is listed under the subpackage it belongs to, along with the name of the npm package you can find it in.
@mona/parse
This module or one of its siblings is needed in order to actually execute defined parsers. Currently, it exports only a single function: a synchronous parser runner.
<a name="mona-parse"></a>> parse(parser, string[, opts]) -> T
Synchronously executes a parser on a given string, and returns the resulting value.
{Parser<T>} parser- The parser to execute.{String} string- String to parse.{Opts} [opts]- Options object.{Boolean} [opts.throwOnError=true]- If truthy, throws a ParserError if the parser fails and returns ParserState instead of its value.{String} [opts.fileName]- filename to use for error messages.
parse(token(), 'a') // => 'a'
parse(integer(), '123') // => 123
@mona/parse-async
This module exports only a single function: an asynchronous parser runner. You need this module or something similar in order to actually execute your parsers.
<a name="mona-parseAsync"></a>> parseAsync(parser, callback[, opts]) -> Handle
Executes a parser asynchronously, returning an object that can be used to manage the parser state.
You can feed new data into the parsing process by calling the returned handle's
#data() method. Unless the parser given tries to match eof(), parsing will
continue until the handle's #done() method is called.
{Function} parser- The parser to execute.{AsyncParserCallback} callback- node-style 2-arg callback executed once per successful application ofparser.{Object} [opts]- Options object.{String} [opts.fileName]- filename to use for error messages.
var handle = parseAsync(token(), function(tok) {
console.log('Got a token: ', tok)
})
handle.data('foo')
// logs:
// > Got a token: f
// > Got a token: o
// > Got a token: o
@mona/core
The core parser package contains essential and dev-utility parsers that are
intended to be the core of the rest of the parser libraries. Some of these are
very low level, such as bind(). Others are not necessarily meant to be used in
production, but can help with debugging, such as log().
<a name="mona-value"></a>> value(val) -> Parser<T>
Always succeeds with val as its value, without consuming any input.
{T} val- value to use as this parser's value.
parse(value('foo'), '') // => 'foo'
<a name="mona-bind"></a>> bind(parser, fun) -> Parser<U>
Calls fun on the value from parser. Fails without executing fun if
parser fails.
-
{Parser<T>} parser- The parser to execute. -
{Function(Parser<T>) -> Parser<U>} fun- Function called with the resulting value ofparser.
parse(bind(token(), function (x) {
return value(x + '!')
}), 'a') // => 'a!'
<a name="mona-fail"></a>> fail([msg[, type]]) -> Parser<Fail>
Always fails without consuming input. Automatically includes the line and column
positions in the final ParserError.
{String} [msg='parser error']- Message to report with the failure.{String} [type='failure']- A type to apply to the ParserError.
<a name="mona-label"></a>> label(parser, msg) -> Parser<T>
Label a parser failure by replacing its error messages with msg.
{Parser<T>} parser- Parser whose errors to replace.{String} msg- Error message to replace errors with.
parse(token(), '') // => unexpected eof
parse(label(token(), 'thing'), '') // => expected thing
<a name="mona-token"></a>> token([count]) -> Parser<String>
Consumes a single item from the input, or fails with an unexpected eof error if there is no input left.
{Integer} [count=1]- number of tokens to consume. Must be > 0.
parse(token(), 'a') // => 'a'
<a name="mona-eof"></a>> eof() -> Parser<true>
Succeeds with a value of true if there is no more input to consume.
parse(eof(), '') // => true
<a name="mona-delay"></a>> delay(constructor, ...args) -> Parser<T>
Delays calling of a parser constructor function until parse-time. Useful for recursive parsers that would otherwise blow the stack at construction time.
{Function(...T) -> Parser<T>} constructor- A function that returns a Parser.{...T} args- Arguments to apply to the constructor.
// The following would usually result in an infinite loop:
function foo() {
return or(x(), foo())
}
// But you can use delay() to remedy this...
function foo() {
return or(x(), delay(foo))
}
<a name="mona-log"></a>>log(parser, label[, level]) -> Parser<T>
Logs the ParserState resulting from parser with a label.
{Parser<T>} parser- Parser to wrap.{String} tag- Tag to use when logging messages.{String} [level='log']- 'log', 'info', 'debug', 'warn', 'error'.
<a name="mona-map"></a>>map(fun, parser) -> Parser<T>
Transforms the resulting value of a successful application of its
