@fink/prattler
Version:
A generic Pratt/top down operator precedence parser.
257 lines (213 loc) • 4.51 kB
JavaScript
const {
is_empty
} = require("@fink/std-lib/iter.js");
const {
next,
iter,
unfold,
filter
} = require("@fink/std-lib/iter.js");
const {
init_expr_builders,
is_ignorable,
next_lbp,
led,
nud
} = require("./expressions.js");
const {
add_error
} = require("./errors.js");
const start_token = {
start: true,
loc: {
start: {
pos: 0,
line: 1,
column: 0
},
end: {
pos: 0,
line: 1,
column: 0
}
}
};
exports.start_token = start_token;
const has_errors = ctx => {
const ˆvalue_1 = ctx;
if (ˆvalue_1 != null) {
const {
errors: ˆp_3
} = ˆvalue_1;
if (!is_empty(ˆp_3)) {
return true;
}
}
{
return false;
}
};
exports.has_errors = has_errors;
const curr_value = ({
curr_token
}) => curr_token.value;
exports.curr_value = curr_value;
const curr_loc = ({
curr_token
}) => curr_token.loc;
exports.curr_loc = curr_loc;
const next_value = ({
next_token
}) => next_token.value;
exports.next_value = next_value;
const next_loc = ({
next_token
}) => next_token.loc;
exports.next_loc = next_loc;
const next_is = (ctx, expected) => expected === next_value(ctx);
exports.next_is = next_is;
const next_is_end = ctx => {
const ˆvalue_4 = ctx;
if (ˆvalue_4 != null) {
const {
next_token: ˆp_6
} = ˆvalue_4;
if (ˆp_6 != null) {
const {
type: ˆp_7
} = ˆp_6;
if (ˆp_7 === `end`) {
return true;
}
}
}
// {tokens: {done: true}}:
// console.log '>>>>>'
// true
{
return false;
}
};
exports.next_is_end = next_is_end;
const advance = (..._args) => {
while (true) {
const [ctx] = _args;
const {
next_token: curr_token,
tokens,
ignored_tokens
} = ctx;
{
const ˆvalue_8 = curr_token;
if (ˆvalue_8 != null) {
const {
type: ˆp_10
} = ˆvalue_8;
if (ˆp_10 === `end`) {
return { ...ctx,
curr_token
};
}
}
{
{
const [next_token, next_tokens] = next(tokens);
{
const ˆvalue_11 = next_token;
if (is_ignorable(ctx, ˆvalue_11)) {
_args = [{ ...ctx,
tokens: next_tokens,
ignored_tokens: [...ignored_tokens, next_token]
}];
continue;
}
{
{
const next_ctx = { ...ctx,
tokens: next_tokens,
curr_token,
next_token,
ignored_tokens
};
return next_ctx;
}
}
}
}
}
}
}
};
exports.advance = advance;
const expression = (ctx, rbp) => {
const ˆvalue_13 = ctx;
if (next_is_end(ˆvalue_13)) {
return add_error(ctx, `Unexpected end of code.`, ctx.curr_token);
}
{
{
let _do_result;
{
let ˆpipe_result_15 = ctx;
ˆpipe_result_15 = advance(ˆpipe_result_15);
ˆpipe_result_15 = nud(ˆpipe_result_15);
ˆpipe_result_15 = unfold(([left, ctx]) => {
const ˆvalue_16 = ctx;
if (has_errors(ˆvalue_16)) {
return [left, ctx, true];
}
if (rbp < next_lbp(ˆvalue_16, left)) {
{
const led_ctx = advance(ctx);
const [next_left, next_ctx] = led(led_ctx, left);
return [next_left, next_ctx, false];
}
}
{
return [left, ctx, true];
}
})(ˆpipe_result_15);
_do_result = ˆpipe_result_15 = filter(([,, found]) => found)(ˆpipe_result_15);
}
const [[left, next_ctx]] = _do_result;
_do_result = undefined;
return [left, next_ctx];
}
}
};
exports.expression = expression;
const init_parser = ({
code,
filename,
tokens
}) => {
const expr_builders = init_expr_builders();
const start_loc = {
pos: 0,
line: 1,
column: 0
};
return {
code,
filename,
tokens: iter(tokens),
curr_token: {
loc: {
start: start_loc,
end: start_loc
}
},
next_token: {
loc: {
start: start_loc,
end: start_loc
}
},
ignored_tokens: [],
expr_builders,
errors: []
};
};
exports.init_parser = init_parser;
const start_parser = ctx => advance(ctx);
exports.start_parser = start_parser;