UNPKG

@fink/larix

Version:

A parser for generating fink's AST.

455 lines (377 loc) 8.9 kB
const { curr_loc, next_loc } = require("@fink/prattler/parser.js"); const { curr_value, advance } = require("@fink/prattler/parser.js"); const { add_separator, add_literal, left_binding } = require("@fink/prattler/expressions.js"); const { add_error } = require("@fink/prattler/errors.js"); const { rx, match_all, replace_all } = require("@fink/std-lib/regex.js"); const { starts_with, slice } = require("@fink/std-lib/str.js"); const { map, filter, flatten, length } = require("@fink/std-lib/iter.js"); const { min } = require("@fink/std-lib/math.js"); const { max_int } = require("@fink/std-lib/num.js"); const { terminator } = require("../expressions.js"); const { terminated_block } = require("../block/init.js"); const { next_is_new_expr, curr_indentation } = require("../block/indentation.js"); const curr_next_adjecent = ctx => { const curr = curr_loc(ctx); const next = next_loc(ctx); return curr.end.line === next.start.line && curr.end.column === next.start.column; }; exports.curr_next_adjecent = curr_next_adjecent; const get_str_empty = ctx => { const { start } = curr_loc(ctx); const end = start; return { type: `string:text`, value: ``, loc: { start, end } }; }; exports.get_str_empty = get_str_empty; const get_expr_part = ctx => { const [block, next_ctx] = terminated_block(ctx, `str-expr-end`); let _do_result; ˆmatch_2: { const ˆvalue_1 = block; /* istanbul ignore else */ if (ˆvalue_1 != null) { const { exprs: ˆp_3 } = ˆvalue_1; /* istanbul ignore else */ if (1 < length(ˆp_3)) { _do_result = { ...block, type: `block` }; break ˆmatch_2; } } { { const { exprs: [expr] } = block; _do_result = expr; } break ˆmatch_2; } } const expr = _do_result; _do_result = undefined; return [expr, next_ctx]; }; exports.get_expr_part = get_expr_part; const get_str_part = ctx => { const value = curr_value(ctx); const loc = curr_loc(ctx); return [{ type: `string:text`, value, loc }, ctx]; }; exports.get_str_part = get_str_part; const get_parts = ctx => { const ˆvalue_4 = ctx.next_token; /* istanbul ignore else */ if (ˆvalue_4 != null) { const { type: ˆp_6 } = ˆvalue_4; /* istanbul ignore else */ if (ˆp_6 === `str-end`) { { const expr = get_str_empty(ctx); return [[expr], advance(ctx)]; } } } /* istanbul ignore else */ if (ˆvalue_4 != null) { const { type: ˆp_7 } = ˆvalue_4; /* istanbul ignore else */ if (ˆp_7 === `str-text`) { { const [expr, next_ctx] = get_str_part(advance(ctx)); { const ˆvalue_8 = next_ctx.next_token; /* istanbul ignore else */ if (ˆvalue_8 != null) { const { type: ˆp_10 } = ˆvalue_8; /* istanbul ignore else */ if (ˆp_10 === `str-end`) { return [[expr], advance(next_ctx)]; } } { { const [rest, end_ctx] = get_parts(next_ctx); return [[expr, ...rest], end_ctx]; } } } } } } /* istanbul ignore else */ if (ˆvalue_4 != null) { const { type: ˆp_11 } = ˆvalue_4; /* istanbul ignore else */ if (ˆp_11 === `str-expr-start`) { { const [expr, next_ctx] = get_expr_part(advance(ctx)); const [rest, end_ctx] = get_parts(next_ctx); let _do_result2; ˆmatch_13: { const ˆvalue_12 = ctx.curr_token; /* istanbul ignore else */ if (ˆvalue_12 != null) { const { type: ˆp_14 } = ˆvalue_12; /* istanbul ignore else */ if (ˆp_14 === `str-expr-end`) { _do_result2 = [get_str_empty(ctx), expr, ...rest]; break ˆmatch_13; } } { _do_result2 = [expr, ...rest]; break ˆmatch_13; } } const exprs = _do_result2; _do_result2 = undefined; return [exprs, end_ctx]; } } } { { const [, err_ctx] = add_error(ctx, `Unexpected end of code.`, ctx.next_token); return [[], err_ctx]; } } }; exports.get_parts = get_parts; const get_str_ind = (str, min_ind) => { const matched = match_all(str, rx`\n([ ]{${min_ind},})`); { let ˆpipe_result_15 = matched; return ˆpipe_result_15 = map(([, spaces]) => length(spaces))(ˆpipe_result_15); } }; exports.get_str_ind = get_str_ind; const get_unindent = (ctx, parts) => { const min_ind = 1 + curr_indentation(ctx); let _do_result3; { let ˆpipe_result_16 = parts; ˆpipe_result_16 = filter(part => { const ˆvalue_17 = part; /* istanbul ignore else */ if (ˆvalue_17 != null) { const { type: ˆp_19 } = ˆvalue_17; /* istanbul ignore else */ if (ˆp_19 === `string:text`) { return true; } } { return false; } })(ˆpipe_result_16); ˆpipe_result_16 = map(part => get_str_ind(part.value, min_ind))(ˆpipe_result_16); ˆpipe_result_16 = flatten(ˆpipe_result_16); _do_result3 = ˆpipe_result_16 = min(max_int, ...ˆpipe_result_16); } const ind = _do_result3; _do_result3 = undefined; return str => replace_all(str, rx`\n[ ]{0,${ind}}`, `\n`); }; exports.get_unindent = get_unindent; const get_unindented_text = (ctx, op) => { const { start } = curr_loc(ctx); const [[first_part, ...parsed_parts], next_ctx] = get_parts(ctx, op); let _do_result4; ˆmatch_21: { const ˆvalue_20 = first_part; /* istanbul ignore else */ if (ˆvalue_20 != null) { const { type: ˆp_22 } = ˆvalue_20; /* istanbul ignore else */ if (ˆp_22 === `string:text`) { _do_result4 = [first_part, ...parsed_parts]; break ˆmatch_21; } } { { const expr = get_str_empty(ctx); _do_result4 = [expr, first_part, ...parsed_parts]; } break ˆmatch_21; } } const parts = _do_result4; _do_result4 = undefined; const { end } = curr_loc(next_ctx); const unindent = get_unindent(ctx, parts); let _do_result5; { let ˆpipe_result_23 = parts; _do_result5 = ˆpipe_result_23 = map(part => { const ˆvalue_24 = part; /* istanbul ignore else */ if (ˆvalue_24 != null) { const { type: ˆp_26 } = ˆvalue_24; /* istanbul ignore else */ if (ˆp_26 === `string:text`) { { const value = unindent(part.value); return { ...part, value }; } } } { return part; } })(ˆpipe_result_23); } const [first, ...rest] = _do_result5; _do_result5 = undefined; let _do_result6; ˆmatch_28: { const ˆvalue_27 = first.value; /* istanbul ignore else */ if (starts_with(ˆvalue_27, `\n`)) { _do_result6 = [{ ...first, value: slice(first.value, 1) }, ...rest]; break ˆmatch_28; } { _do_result6 = [first, ...rest]; break ˆmatch_28; } } // remove first empty line const exprs = _do_result6; _do_result6 = undefined; return [{ type: `string`, op, exprs, tag: false, loc: { start, end } }, next_ctx]; }; exports.get_unindented_text = get_unindented_text; const string = token_type => ({ ...left_binding(token_type), lbp: lbp => (ctx, left) => { const ˆvalue_29 = true; // default indentation behaviour /* istanbul ignore else */ if (ˆvalue_29 === next_is_new_expr(ctx)) { return 0; } /* istanbul ignore else */ if (ˆvalue_29 === (left.type === `ident` && curr_next_adjecent(ctx))) { return lbp; } { return 0; } }, led: () => (ctx, left) => { const { loc: { start } } = left; const op = curr_value(ctx); const [{ loc: { end }, ...str }, next_ctx] = get_unindented_text(ctx, op); return [{ ...str, tag: left, loc: { start, end } }, next_ctx]; }, nud: () => ctx => { const op = curr_value(ctx); return get_unindented_text(ctx, op); } }); exports.string = string; const add_string = ctx => { let ˆpipe_result_31 = ctx; ˆpipe_result_31 = add_literal(string(`str-start`))(ˆpipe_result_31); return ˆpipe_result_31 = add_separator(terminator(`str-expr-end`))(ˆpipe_result_31); }; exports.add_string = add_string;