@fink/larix
Version:
A parser for generating fink's AST.
204 lines (185 loc) • 5.17 kB
JavaScript
import { _in_ } from "@fink/js-interop/runtime.js";
import { advance, expression, next_is, has_errors } from "@fink/prattler/parser.js";
import { curr_loc, next_loc } from "@fink/prattler/parser.js";
import { add_error } from "@fink/prattler/errors.js";
import { unfold, filter } from "@fink/std-lib/iter.js";
import { update_indentation, push_block, pop_block } from "./indentation.js";
import { next_is_unindented } from "./indentation.js";
import { next_is_indented } from "./indentation.js";
import { get_comments } from "../comments/collect.js";
export const empty_expr = ({
loc: {
end
}
}) => ({
type: `empty`,
value: ``,
loc: {
start: end,
end
}
});
export const get_end_symb = ({
blocks: [block]
}) => block.end_symbol;
export const end_of_block_tokens = [`:`, `}`, `]`, `)`, `str-expr-end`, `jsx-expr-end`, `end`];
export const next_is_end_of_block = ctx => {
const ˆvalue_1 = ctx;
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
next_token: ˆp_3
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_3 != null) {
const {
type: ˆp_4
} = ˆp_3;
/* istanbul ignore else */
if (_in_(ˆp_4, end_of_block_tokens)) {
return true;
}
}
}
/* istanbul ignore else */
if (next_is_unindented(ˆvalue_1)) {
return true;
}
{
return false;
}
};
export const next_is_nl = ctx => {
const {
end: {
line: curr_line
}
} = curr_loc(ctx);
const {
start: {
line: next_line
}
} = next_loc(ctx);
return curr_line < next_line;
};
export const get_all = (ctx, single_expr) => {
let _do_result;
{
let ˆpipe_result_5 = [, [[], ctx, true, false]];
ˆpipe_result_5 = unfold(([, [exprs, ctx, at_start, was_comma]]) => {
const ˆvalue_6 = ctx;
/* istanbul ignore else */
if (has_errors(ˆvalue_6)) {
return [true, [exprs, ctx]];
}
/* istanbul ignore else */
if (next_is_indented(ˆvalue_6)) {
{
const next_ctx = update_indentation(ctx);
return [false, [exprs, next_ctx, true, was_comma]];
}
}
/* istanbul ignore else */
if (next_is_end_of_block(ˆvalue_6)) {
{
const ˆvalue_8 = was_comma;
/* istanbul ignore else */
if (ˆvalue_8 === true) {
{
const expr = empty_expr(ctx.curr_token);
return [true, [[...exprs, expr], ctx]];
}
}
{
return [true, [exprs, ctx]];
}
}
}
/* istanbul ignore else */
if (next_is(ˆvalue_6, `,`)) {
{
const next_ctx = advance(ctx);
{
const ˆvalue_10 = at_start;
/* istanbul ignore else */
if (ˆvalue_10 === true) {
{
const expr = empty_expr(ctx.next_token);
return [false, [[...exprs, expr], next_ctx, true, false]];
}
}
{
{
const ˆvalue_12 = next_ctx;
/* istanbul ignore else */
if (next_is(ˆvalue_12, `,`)) {
{
const expr = empty_expr(ctx.next_token);
return [false, [[...exprs, expr], next_ctx, false, false]];
}
}
{
return [false, [exprs, next_ctx, true, true]];
}
}
}
}
}
}
{
{
const ˆvalue_14 = at_start;
/* istanbul ignore else */
if (ˆvalue_14 === false) {
{
const [, err_ctx] = add_error(ctx, `Expected \`,\` or indented new line or ${get_end_symb(ctx)}.`, ctx.next_token);
return [true, [exprs, err_ctx]];
}
}
{
{
// TODO: check if next is actually a start of an expr.
const [expr, next_ctx] = single_expr(ctx);
// new line at end of expr is a separator
const next_is_start = next_is_nl(next_ctx);
return [false, [[...exprs, expr], next_ctx, next_is_start, false]];
}
}
}
}
})(ˆpipe_result_5);
_do_result = ˆpipe_result_5 = filter(([done]) => done)(ˆpipe_result_5);
}
// TODO this is a monster, needs breakdown
const [[, [exprs, next_ctx]]] = _do_result;
_do_result = undefined;
return [exprs, next_ctx];
};
export const expressions = (ctx, end_symbol, single_expr) => {
const {
start
} = curr_loc(ctx);
const block_ctx = push_block(ctx, end_symbol);
const [exprs, next_ctx] = get_all(block_ctx, single_expr);
const end_ctx = pop_block(next_ctx);
const {
end
} = curr_loc(end_ctx);
return [{
type: `exprs`,
exprs,
loc: {
start,
end
}
}, end_ctx];
};
export const single_expression = (ctx, lbp = 0) => {
const [leading, expr_ctx] = get_comments(ctx);
const [expr, next_ctx] = expression(expr_ctx, lbp);
return [{ ...expr,
comments: {
leading
}
}, next_ctx];
};