@fink/larix
Version:
A parser for generating fink's AST.
474 lines (422 loc) • 9.94 kB
JavaScript
import { curr_value, curr_loc } from "@fink/prattler/parser.js";
import { next_is } from "@fink/prattler/parser.js";
import { advance } from "@fink/prattler/parser.js";
import { add_error } from "@fink/prattler/errors.js";
import { prefix } from "../expressions.js";
import { terminated_block } from "../block/init.js";
import { single_expression } from "../block/expr.js";
import { get_unindented_text } from "../literals/string.js";
import { identifier } from "../identifier/init.js";
export const jsx_expr_container = ctx => {
const [block, next_ctx] = terminated_block(ctx, `jsx-expr-end`);
const expr = { ...block,
type: `block`
};
const {
end
} = curr_loc(next_ctx);
return [{
type: `jsx:expr`,
expr,
loc: {
start: expr.loc.start,
end
}
}, next_ctx];
};
export const jsx_txt = ctx => {
const {
value,
loc
} = ctx.curr_token;
return [{
type: `jsx:text`,
value,
loc
}, ctx];
};
export const get_children = ctx => {
const ˆvalue_1 = ctx.next_token;
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
type: ˆp_3
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_3 === `jsx-elem-close`) {
return [[], ctx];
}
}
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
type: ˆp_4
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_4 === `jsx-text`) {
{
const [expr, children_ctx] = jsx_txt(advance(ctx));
const [children, end_ctx] = get_children(children_ctx);
return [[expr, ...children], end_ctx];
}
}
}
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
type: ˆp_5
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_5 === `jsx-frag-open`) {
{
const [expr, children_ctx] = jsx_frag(advance(ctx));
const [children, end_ctx] = get_children(children_ctx);
return [[expr, ...children], end_ctx];
}
}
}
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
type: ˆp_6
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_6 === `jsx-elem-start`) {
{
const [expr, children_ctx] = jsx_elem(advance(ctx));
const [children, end_ctx] = get_children(children_ctx);
return [[expr, ...children], end_ctx];
}
}
}
/* istanbul ignore else */
if (ˆvalue_1 != null) {
const {
type: ˆp_7
} = ˆvalue_1;
/* istanbul ignore else */
if (ˆp_7 === `jsx-expr-start`) {
{
const [expr, children_ctx] = jsx_expr_container(advance(ctx));
const [children, end_ctx] = get_children(children_ctx);
return [[expr, ...children], end_ctx];
}
}
}
{
{
const [err, err_ctx] = add_error(ctx, `Expected JSX element <...>, </...> or JSX text or JSX expr {...}.`, ctx.next_token);
return [[err], err_ctx];
}
}
};
export const jsx_ident = ctx => identifier(advance(ctx));
export const jsx_body = (name, ctx) => {
const [children, close_ctx] = get_children(ctx);
let _do_result;
ˆmatch_9: {
const ˆvalue_8 = close_ctx.next_token;
// TODO: name can also be a member expr, ...
/* istanbul ignore else */
if (ˆvalue_8 != null) {
const {
type: ˆp_10,
value: ˆp_11
} = ˆvalue_8;
// TODO: name can also be a member expr, ...
/* istanbul ignore else */
if (ˆp_10 === `jsx-elem-close`) // TODO: name can also be a member expr, ...
/* istanbul ignore else */
if (ˆp_11 === `</${name.value}>`) {
_do_result = advance(close_ctx);
break ˆmatch_9;
}
}
{
{
const [, err_ctx] = add_error(close_ctx, `Expected JSX closing element </${name.value}>.`, close_ctx.next_token);
_do_result = err_ctx;
}
break ˆmatch_9;
}
}
const end_ctx = _do_result;
_do_result = undefined;
return [children, end_ctx];
};
export const jsx_string_val = ctx => {
const {
start
} = curr_loc(ctx);
const op = curr_value(ctx);
const [{
loc: {
end
},
...str
}, next_ctx] = get_unindented_text(ctx, op);
return [{ ...str,
loc: {
start,
end
}
}, next_ctx];
};
export const jsx_attr_value = ctx => {
const ˆvalue_12 = ctx.next_token;
/* istanbul ignore else */
if (ˆvalue_12 != null) {
const {
type: ˆp_14
} = ˆvalue_12;
/* istanbul ignore else */
if (ˆp_14 === `jsx-expr-start`) {
return jsx_expr_container(advance(ctx));
}
}
/* istanbul ignore else */
if (ˆvalue_12 != null) {
const {
type: ˆp_15
} = ˆvalue_12;
/* istanbul ignore else */
if (ˆp_15 === `str-start`) {
return jsx_string_val(advance(ctx));
}
}
{
return single_expression({ ...ctx,
jsx: true
}, 0);
}
};
export const jsx_attr = ctx => {
const [name, value_ctx] = jsx_ident(ctx);
const {
start
} = name.loc;
let _do_result2;
ˆmatch_17: {
const ˆvalue_16 = value_ctx;
/* istanbul ignore else */
if (next_is(ˆvalue_16, `=`)) {
_do_result2 = jsx_attr_value(advance(value_ctx));
break ˆmatch_17;
}
{
_do_result2 = [false, value_ctx];
break ˆmatch_17;
}
}
const [value, next_ctx] = _do_result2;
_do_result2 = undefined;
const {
end
} = curr_loc(next_ctx);
return [{
type: `jsx:attr`,
name,
value,
loc: {
start,
end
}
}, next_ctx];
};
export const jsx_spread_attr = ctx => {
const {
start
} = curr_loc(ctx);
const [right, next_ctx] = single_expression({ ...ctx,
jsx: true
}, 0);
const {
end
} = curr_loc(next_ctx);
return [{
type: `spread`,
op: `...`,
right,
loc: {
start,
end
}
}, next_ctx];
};
export const jsx_props = ctx => {
const ˆvalue_18 = ctx.next_token;
/* istanbul ignore else */
if (ˆvalue_18 != null) {
const {
type: ˆp_20,
value: ˆp_21
} = ˆvalue_18;
/* istanbul ignore else */
if (ˆp_20 === `jsx-elem-close`)
/* istanbul ignore else */
if (ˆp_21 === `/>`) {
return [[], ctx];
}
}
/* istanbul ignore else */
if (ˆvalue_18 != null) {
const {
type: ˆp_22
} = ˆvalue_18;
/* istanbul ignore else */
if (ˆp_22 === `jsx-elem-end`) {
return [[], ctx];
}
}
/* istanbul ignore else */
if (ˆvalue_18 != null) {
const {
type: ˆp_23
} = ˆvalue_18;
/* istanbul ignore else */
if (ˆp_23 === `...`) {
{
const [expr, next_ctx] = jsx_spread_attr(advance(ctx));
const [props, end_ctx] = jsx_props(next_ctx);
return [[expr, ...props], end_ctx];
}
}
}
/* istanbul ignore else */
if (ˆvalue_18 != null) {
const {
type: ˆp_24
} = ˆvalue_18;
/* istanbul ignore else */
if (ˆp_24 === `ident`) {
{
const [expr, next_ctx] = jsx_attr(ctx);
const [props, end_ctx] = jsx_props(next_ctx);
return [[expr, ...props], end_ctx];
}
}
}
{
{
const [err, err_ctx] = add_error(ctx, `Expected JSX prop identifier, spread expr, or end of tag.`, ctx.next_token);
return [[err], err_ctx];
}
}
};
export const body_or_end_elem = (ctx, name) => {
const ˆvalue_25 = ctx.next_token;
/* istanbul ignore else */
if (ˆvalue_25 != null) {
const {
type: ˆp_27
} = ˆvalue_25;
/* istanbul ignore else */
if (ˆp_27 === `jsx-elem-end`) {
{
const [children, next_ctx] = jsx_body(name, advance(ctx));
return [false, children, next_ctx];
}
}
}
/* istanbul ignore else */
if (ˆvalue_25 != null) {
const {
type: ˆp_28
} = ˆvalue_25;
/* istanbul ignore else */
if (ˆp_28 === `jsx-elem-close`) {
return [true, [], advance(ctx)];
}
}
{
{
const [err, err_ctx] = add_error(ctx, `Expected end of JSX tag.`, ctx.next_token);
return [false, [err], err_ctx];
}
}
};
export const jsx_elem = ctx => {
const {
start
} = curr_loc(ctx);
const [name, elem_ctx] = jsx_ident(ctx);
const [props, body_ctx] = jsx_props(elem_ctx);
const [self_closing, children, next_ctx] = body_or_end_elem(body_ctx, name);
const {
end
} = curr_loc(next_ctx);
return [{
type: `jsx:elem`,
name,
props,
children,
self_closing,
loc: {
start,
end
}
}, next_ctx];
};
export const jsx_frag = ctx => {
const {
start
} = curr_loc(ctx);
const [children, close_ctx] = get_children(ctx);
let _do_result3;
ˆmatch_30: {
const ˆvalue_29 = close_ctx.next_token;
/* istanbul ignore else */
if (ˆvalue_29 != null) {
const {
type: ˆp_31,
value: ˆp_32
} = ˆvalue_29;
/* istanbul ignore else */
if (ˆp_31 === `jsx-elem-close`)
/* istanbul ignore else */
if (ˆp_32 === `</>`) {
_do_result3 = advance(close_ctx);
break ˆmatch_30;
}
}
{
{
const [, err_ctx] = add_error(ctx, `Expected closing JSX fragment </>.`, ctx.next_token);
_do_result3 = err_ctx;
}
break ˆmatch_30;
}
}
const end_ctx = _do_result3;
_do_result3 = undefined;
const {
end
} = curr_loc(end_ctx);
return [{
type: `jsx:frag`,
children,
loc: {
start,
end
}
}, end_ctx];
};
export const jsx_elem_or_fragment = ctx => {
const ˆvalue_33 = ctx.curr_token;
/* istanbul ignore else */
if (ˆvalue_33 != null) {
const {
type: ˆp_35
} = ˆvalue_33;
/* istanbul ignore else */
if (ˆp_35 === `jsx-frag-open`) {
return jsx_frag(ctx);
}
}
{
return jsx_elem(ctx);
}
};
export const jsx = token_type => ({ ...prefix(token_type),
nud: () => ctx => jsx_elem_or_fragment(ctx)
});