@fink/prattler
Version:
A generic Pratt/top down operator precedence parser.
148 lines (143 loc) • 2.81 kB
JavaScript
import { add_error } from "./errors.js";
export const auto = {
auto: true
};
export 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);
};
export 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);
};
export const left_binding = token_type => ({
token_type,
nud: () => error_nud,
lbp: lbp => () => lbp,
led: () => error_led
});
export const non_binding = token_type => ({
token_type,
nud: () => error_nud,
lbp: () => () => 0,
led: () => error_led
});
export 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)
}
}
};
};
export const add_ignorable = token_type => ({
igns,
...ctx
}) => ({ ...ctx,
igns: { ...igns,
[token_type]: true
}
});
export const add_separator = expr_builder => add_expr(expr_builder, 0);
export const add_operator = expr_builder => add_expr(expr_builder, auto);
export const add_identifier = expr_builder => add_expr(expr_builder, auto);
export const add_literal = expr_builder => add_expr(expr_builder, auto);
export const is_ignorable = (ctx, token) => ctx.igns[token.type] === true;
export const nud = ctx => {
const {
curr_token: {
type
},
expr_builders: {
nuds
}
} = ctx;
const {
[type]: nud_fn
} = nuds;
return nud_fn(ctx);
};
export const led = (ctx, left) => {
const {
curr_token: {
type
},
expr_builders: {
leds
}
} = ctx;
const {
[type]: led_fn
} = leds;
return led_fn(ctx, left);
};
export const next_lbp = (ctx, left) => {
const {
next_token: {
type
},
expr_builders: {
lbps
}
} = ctx;
const {
[type]: lbp_fn
} = lbps;
return lbp_fn(ctx, left);
};
export const init_expr_builders = () => ({
next_lbp: 2,
nuds: {},
lbps: {
end: () => 0
},
leds: {},
igns: {}
});