import {Range, Parser, sequence, choose, string, regExp, lazy} from "tparse";
interface IntegerNode {
value: number;
range: Range;
}
interface BinOpNode {
left: Node;
op: string;
right: Node;
}
type Node = IntegerNode | BinOpNode;
const _ = regExp(/[ \t\n\r]/).repeat();
const integer: Parser<IntegerNode> =
regExp(/[0-9]/).repeat(1)
.withRange()
.thenSkip(_)
.map(([chars, range]) => {
return {value: parseInt(chars.join("")), range};
});
function token(str: string) {
return string(str).thenSkip(_);
}
const factor: Parser<Node> =
choose(
integer,
token("(")
.thenTake(lazy(() => expr))
.thenSkip(token(")"))
)
function buildTree([first, rest]: [Node, [string, Node][]]) {
let left = first;
for (const [op, right] of rest) {
left = {left, op, right};
}
return left;
}
const term: Parser<Node> =
sequence(
factor,
_.thenTake(
sequence(
_.thenTake(choose(string("*"), string("/"))),
_.thenTake(factor)
).repeat()
)
)
.map(buildTree);
const expr: Parser<Node> =
sequence(
term,
_.thenTake(
sequence(
_.thenTake(choose(string("+"), string("-"))),
_.thenTake(term)
).repeat()
)
)
.map(buildTree);
const parser = _.thenTake(expr);
parser.parse("test.txt", "1 + (2 * 3)");