small set of monadic parser combinators.
$ npm i onia
import onia, {regex, alpha, map, many, sequence, optional} from 'onia';
const digit = map(
regex(/\d/g, 'digit'),
(digit) => parseInt(digit),
'digit'
);
const digits = map(
many(digit),
(digit) => parseInt(digit.join('')),
'digits'
);
const whitespace = alpha(' ', 'whitespace');
const operator = regex(/[+-]/g, 'operator');
const expression = map(
sequence([digits, optional(whitespace), operator, optional(whitespace), digits] as const),
([left, , operator, , right]) => [left, operator, right] as const,
'expression'
);
const result = onia('123 + 321', term);
// result === [123, '+', 321]
naive calculator parser adhering to the order of operations.
const digit = map(
regex(/\d*\.?\d*/g, 'digit'),
(digit) => parseFloat(digit),
'digit'
);
const whitespace = optional(alpha(' ', 'whitespace'), false);
const operator = regex(/[+\-*/]/g, 'operator');
const expression = lazy<number>(() => map(
sequence([
term,
many(sequence([whitespace, operator, whitespace, term] as const, 'expression'))
] as const),
([first, rest]) => rest.reduce((acc, [, op, , next]) => {
if (op === '+') return acc + parseFloat(next as any);
if (op === '-') return acc - parseFloat(next as any);
return acc;
}, first as number),
'expression'
));
const parentheses = lazy(() => {
const sequenceParser = sequence([
alpha('('),
expression,
alpha(')')
] as const);
const mappedParser: Parser<number> = map(
sequenceParser,
([, expr,]) => parseFloat(expr as any) as number,
'parentheses'
);
return mappedParser;
});
const term = map(
sequence([
any([parentheses, digit] as const),
many(sequence([whitespace, operator, whitespace, any([parentheses, digit] as const)] as const, 'term'))
] as const),
([first, rest]) => rest.reduce((acc, [, op, , next]) => {
if (op === '*') return acc * parseFloat(next as any);
if (op === '/') return acc / parseFloat(next as any);
if (op === '+') return acc + parseFloat(next as any);
if (op === '-') return acc - parseFloat(next as any);
return acc;
}, first as number),
'term'
);
const result = onia('(2 * (3 + 4)) - (5 / (2 + 3))', expression);
// result === 13
This project is still in early development and is subject to change.
MIT License, see LICENSE