UNPKG

@fink/prattler

Version:

A generic Pratt/top down operator precedence parser.

197 lines (161 loc) 3.27 kB
const { add_error } = require("./errors.js"); const auto = { auto: true }; exports.auto = auto; const error_nud = ctx => { const { curr_token } = ctx; const { value } = curr_token; return add_error(ctx, `Unexpected token \`${value}\` at start of expression.`, curr_token); }; exports.error_nud = error_nud; const error_led = ctx => { const { curr_token } = ctx; const { value } = curr_token; return add_error(ctx, `Cannot use \`${value}\` as an infix operator.`, curr_token); }; exports.error_led = error_led; const left_binding = token_type => ({ token_type, nud: () => error_nud, lbp: lbp => () => lbp, led: () => error_led }); exports.left_binding = left_binding; const non_binding = token_type => ({ token_type, nud: () => error_nud, lbp: () => () => 0, led: () => error_led }); exports.non_binding = non_binding; const add_expr = (expr_builder, lbp_value) => ({ expr_builders, ...ctx }) => { const { next_lbp, lbps, nuds, leds } = expr_builders; let _do_result; ˆmatch_2: { const ˆvalue_1 = lbp_value; if (ˆvalue_1 === auto) { _do_result = next_lbp; break ˆmatch_2; } { _do_result = lbp_value; break ˆmatch_2; } } const final_lbp_value = _do_result; _do_result = undefined; const { token_type, nud, lbp, led } = expr_builder; return { ...ctx, expr_builders: { next_lbp: next_lbp + 2, nuds: { ...nuds, [token_type]: nud(final_lbp_value) }, lbps: { ...lbps, [token_type]: lbp(final_lbp_value) }, leds: { ...leds, [token_type]: led(final_lbp_value) } } }; }; exports.add_expr = add_expr; const add_ignorable = token_type => ({ igns, ...ctx }) => ({ ...ctx, igns: { ...igns, [token_type]: true } }); exports.add_ignorable = add_ignorable; const add_separator = expr_builder => add_expr(expr_builder, 0); exports.add_separator = add_separator; const add_operator = expr_builder => add_expr(expr_builder, auto); exports.add_operator = add_operator; const add_identifier = expr_builder => add_expr(expr_builder, auto); exports.add_identifier = add_identifier; const add_literal = expr_builder => add_expr(expr_builder, auto); exports.add_literal = add_literal; const is_ignorable = (ctx, token) => ctx.igns[token.type] === true; exports.is_ignorable = is_ignorable; const nud = ctx => { const { curr_token: { type }, expr_builders: { nuds } } = ctx; const { [type]: nud_fn } = nuds; return nud_fn(ctx); }; exports.nud = nud; const led = (ctx, left) => { const { curr_token: { type }, expr_builders: { leds } } = ctx; const { [type]: led_fn } = leds; return led_fn(ctx, left); }; exports.led = led; const next_lbp = (ctx, left) => { const { next_token: { type }, expr_builders: { lbps } } = ctx; const { [type]: lbp_fn } = lbps; return lbp_fn(ctx, left); }; exports.next_lbp = next_lbp; const init_expr_builders = () => ({ next_lbp: 2, nuds: {}, lbps: { end: () => 0 }, leds: {}, igns: {} }); exports.init_expr_builders = init_expr_builders;