From 15e5a562b11e92181869932b4452845666585bf7 Mon Sep 17 00:00:00 2001 From: Jan Klaas Kollhof Date: Sun, 25 Oct 2020 16:52:40 +0100 Subject: [PATCH 1/2] refactor: make transforms non-stateful --- src/js/identifier.fnk | 15 +++-- src/js/types.fnk | 15 +++-- src/lang/arithmitic/init.fnk | 21 +++++-- src/lang/assignment/init.fnk | 79 +++++++++++++++--------- src/lang/async/init.fnk | 12 +++- src/lang/block/init.fnk | 32 +++++++--- src/lang/call/call.fnk | 46 +++++++++----- src/lang/call/pipe.fnk | 30 +++++---- src/lang/comparison/init.fnk | 20 +++--- src/lang/conditionals/match.fnk | 106 +++++++++++++++++++++----------- src/lang/func/init.fnk | 32 +++++++--- src/lang/group/init.fnk | 5 +- src/lang/identifier/init.fnk | 7 ++- src/lang/init.fnk | 71 +++++---------------- src/lang/iterable/common.fnk | 75 ++++++++++++---------- src/lang/iterable/filter.fnk | 7 ++- src/lang/iterable/fold.fnk | 53 ++++++++++------ src/lang/iterable/map.fnk | 8 ++- src/lang/iterable/unfold.fnk | 60 ++++++++++-------- src/lang/iterable/until.fnk | 7 ++- src/lang/iterable/while.fnk | 8 ++- src/lang/js-compat/throw.fnk | 9 ++- src/lang/js-compat/try.fnk | 7 ++- src/lang/jsx/init.fnk | 74 ++++++++++++++-------- src/lang/literals/keywords.fnk | 5 +- src/lang/literals/list.fnk | 22 ++++--- src/lang/literals/number.fnk | 5 +- src/lang/literals/record.fnk | 38 +++++++----- src/lang/literals/string.fnk | 24 +++++--- src/lang/logical/in.fnk | 36 ++++++----- src/lang/logical/init.fnk | 21 ++++--- src/lang/module/import.fnk | 21 ++++--- src/lang/module/init.fnk | 80 ++++++++++++++++-------- src/lang/partial/init.fnk | 16 +++-- src/lang/prop-access/init.fnk | 18 +++--- src/lang/spread/init.fnk | 10 ++- src/lang/transform.fnk | 68 ++++++++++++++++++++ 37 files changed, 743 insertions(+), 420 deletions(-) create mode 100644 src/lang/transform.fnk diff --git a/src/js/identifier.fnk b/src/js/identifier.fnk index 8e35d91..eadd531 100644 --- a/src/js/identifier.fnk +++ b/src/js/identifier.fnk @@ -15,15 +15,15 @@ check_ident = rx' [_$\p{L}][_$\p{L}\p{N}]*$' - +# TODO: move into ctx var_prefix = 'ˆ' str_36 = base_n ?, 36 -replace_chars = fn name, idx=0: - prefixed_name = '${var_prefix}${name}' +replace_chars = fn name, idx, prefix: + prefixed_name = '${prefix}${name}' match prefixed_name: matches ?, check_ident: @@ -35,14 +35,17 @@ replace_chars = fn name, idx=0: end = slice name, idx + 1 new_name = '${start}${char_replacement}${end}' - replace_chars new_name, idx + length char_replacement + replace_chars + new_name + idx + length char_replacement + prefix -escape_ident = fn name: +escape_ident = fn name, {ident_prefix}: match name: matches ?, check_ident: name else: - replace_chars name + replace_chars name, 0, ident_prefix diff --git a/src/js/types.fnk b/src/js/types.fnk index aadaac3..d71e18d 100644 --- a/src/js/types.fnk +++ b/src/js/types.fnk @@ -62,7 +62,16 @@ not_nullish = fn value: and not_undef, not_null -ident = fn name: identifier escape_ident name +ident = fn name, ctx: + identifier escape_ident name, ctx + + + +unique_ident = fn name, ctx: + {unique_id, ident_prefix} = ctx + js = ident '${ident_prefix}${name}_${unique_id}', ctx + [js, {...ctx, unique_id: unique_id + 1}] + raw_str = fn value: @@ -113,9 +122,7 @@ async = true generator = fn name, args, ...statements: - func_name = ident name - - functionExpression func_name, args, + functionExpression name, args, blockStatement list: returnStatement objectExpression list: diff --git a/src/lang/arithmitic/init.fnk b/src/lang/arithmitic/init.fnk index dfb4414..ce137d4 100644 --- a/src/lang/arithmitic/init.fnk +++ b/src/lang/arithmitic/init.fnk @@ -1,22 +1,31 @@ babel_types = import '@babel/types' {binaryExpression, unaryExpression} = babel_types + {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' transform_op = dict: '^': '**' -transform_arithmitic = fn {op, left, right}, {transform}: + +transform_arithmitic = fn {op, left, right}, ctx: {(op): operator=op} = transform_op - binaryExpression operator, - transform left - transform right + [left_js, right_ctx] = transform left, ctx + [right_js, end_ctx] = transform right, right_ctx + js = binaryExpression operator, left_js, right_js + + [js, end_ctx] + + +transform_unary = fn {op, right}, ctx: + [right_js, next_ctx] = transform right, ctx + js = unaryExpression op, right_js -transform_unary = fn {op, right}, {transform}: - unaryExpression op, transform right + [js, next_ctx] diff --git a/src/lang/assignment/init.fnk b/src/lang/assignment/init.fnk index edf96d2..6ff4231 100644 --- a/src/lang/assignment/init.fnk +++ b/src/lang/assignment/init.fnk @@ -7,10 +7,18 @@ babel_types = import '@babel/types' } = babel_types {length, is_empty} = import '@fink/std-lib/iter.fnk' -{transform_left} = import '../../js/left.fnk' +{transform_left: xform_left} = import '../../js/left.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' {add, any} = import '../context.fnk' {transform_value} = import '../partial/init.fnk' +{transform} = import '../transform.fnk' + + + +transform_left = fn node, ctx: + [left, next_ctx] = transform node, ctx + js = xform_left left + [js, next_ctx] @@ -30,7 +38,7 @@ has_spread_not_last = fn {left}: false -transform_spread_left = fn {left}, {transform}: +transform_spread_left = fn {left}, ctx: [before, middle, end] = pipe left.exprs: fold expr, [before=[], middle=false, end=[]]=[]: match expr: @@ -53,7 +61,8 @@ transform_spread_left = fn {left}, {transform}: # TODO missing loc [{type: 'list', exprs: before}, middle, {type: 'list', exprs: end}] - transform_left transform {...left, exprs} + transform_left {...left, exprs}, ctx + slice = fn items, start, end=false: @@ -78,13 +87,15 @@ transform_spread_right = fn expr, ctx: {left, right} = expr items = ctx.unique_ident 'items' # TODO: wrap declarator? + [init, next_ctx] = transform_value right, ctx + items_init = wrap_with_comment_loc variableDeclaration 'const' list: variableDeclarator arrayPattern [restElement items] - transform_value right, ctx + init left len = (length left.exprs) - 1 @@ -102,14 +113,13 @@ transform_spread_right = fn expr, ctx: 0: slices else: [items, ...slices] - result = expressionStatement - arrayExpression result_items - - doExpression + js = doExpression wrap_with_comment_loc - blockStatement [items_init, result] + blockStatement list: + items_init + expressionStatement arrayExpression result_items left - + [js, next_ctx] has_await = fn node: @@ -124,7 +134,8 @@ has_await = fn node: transform_await_left = fn node, ctx: {left: {exprs: [{right: expr}, ...rest_exprs], ...rest_left}} = node left = {...rest_left, exprs: [expr, ...rest_exprs]} - transform_left ctx.transform left + transform_left left, ctx + @@ -133,13 +144,10 @@ transform_await_right = fn expr, ctx: items = ctx.unique_ident 'items' iter = ctx.unique_ident 'iter' + [init, next_ctx] = transform_value right, ctx + items_init = wrap_with_comment_loc - variableDeclaration - 'const' - list: - variableDeclarator - items - transform_value right, ctx + variableDeclaration 'const', [variableDeclarator items, init] right iter_init = wrap_with_comment_loc @@ -183,8 +191,7 @@ transform_await_right = fn expr, ctx: identifier 'value' expr - - doExpression + js = doExpression wrap_with_comment_loc blockStatement list: items_init @@ -193,24 +200,38 @@ transform_await_right = fn expr, ctx: arrayExpression right_exprs right + [js, next_ctx] + + + +transform_assign_left = fn node, ctx: + transform_left node.left, ctx + + + +transform_assign_right = fn node, ctx: + transform_value node.right, ctx + + transform_assign = fn node, ctx: - match node: + [left_transform, right_transform] = match node: has_await ?: - left = transform_await_left node, ctx - right = transform_await_right node, ctx - assignmentExpression '=', left, right + [transform_await_left, transform_await_right] has_spread_not_last ?: - left = transform_spread_left node, ctx - right = transform_spread_right node, ctx - assignmentExpression '=', left, right + [transform_spread_left, transform_spread_right] else: - left = transform_left ctx.transform node.left - right = transform_value node.right, ctx - assignmentExpression '=', left, right + [transform_assign_left, transform_assign_right] + + + [left, right_ctx] = left_transform node, ctx + [right, next_ctx] = right_transform node, right_ctx + + js = assignmentExpression '=', left, right + [js, next_ctx] diff --git a/src/lang/async/init.fnk b/src/lang/async/init.fnk index 59ef7dc..f493407 100644 --- a/src/lang/async/init.fnk +++ b/src/lang/async/init.fnk @@ -1,11 +1,17 @@ babel_types = import '@babel/types' {awaitExpression} = babel_types + {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' + + + +transform_await = fn node, ctx: + [right, next_ctx] = transform node.right, ctx + js = awaitExpression right + [js, next_ctx] -transform_await = fn node, {transform}: - right = transform node.right - awaitExpression right add_async = fn ctx: diff --git a/src/lang/block/init.fnk b/src/lang/block/init.fnk index 146bffd..9fca150 100644 --- a/src/lang/block/init.fnk +++ b/src/lang/block/init.fnk @@ -7,12 +7,14 @@ babel_types = import '@babel/types' {add, any} = import '../context.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' -block_statement = fn expr, {transform}: - st = transform expr - match st: +block_statement = fn expr, ctx: + [st, next_ctx] = transform expr, ctx + + js = match st: isAssignmentExpression ?: wrap_with_comment_loc variableDeclaration @@ -25,6 +27,20 @@ block_statement = fn expr, {transform}: expressionStatement st expr + [js, next_ctx] + + + +exprs_block = fn exprs, ctx: + pipe exprs: + # TODO: duplicate in other modules + map expr, expr_ctx=ctx: + [js_expr, next_ctx] = block_statement expr, expr_ctx + ([js_expr, next_ctx], next_ctx) + + collect_with_ctx ctx + + transform_block = fn node, ctx: {exprs} = node @@ -32,12 +48,12 @@ transform_block = fn node, ctx: match exprs: 1 == length ?: [expr] = exprs - ctx.transform expr + transform expr, ctx else: - doExpression - blockStatement list: - ...pipe exprs: - map expr: block_statement expr, ctx + [js_exprs, next_ctx] = exprs_block exprs, ctx + js = doExpression blockStatement js_exprs + [js, next_ctx] + add_block = fn ctx: diff --git a/src/lang/call/call.fnk b/src/lang/call/call.fnk index c994007..8463c2a 100644 --- a/src/lang/call/call.fnk +++ b/src/lang/call/call.fnk @@ -2,35 +2,51 @@ babel_types = import '@babel/types' {callExpression, identifier} = babel_types {is_empty, length} = import '@fink/std-lib/iter.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' -transform_args = fn args, {transform}: - pipe args: - map expr: - match expr: + + +transform_args = fn args, ctx: + [js_args, next_ctx] = pipe args: + map expr, arg_ctx=ctx: + [arg, next_ctx] = match expr: {type: 'empty'}: - identifier 'undefined' + undef = identifier 'undefined' + [undef, ctx] else: - transform expr + transform expr, arg_ctx + + ([arg, next_ctx], next_ctx) + + collect_with_ctx ctx + [js_args, next_ctx] -transform_single_arg = fn [expr], {transform}: + +transform_single_arg = fn [expr], ctx: match expr: - {type: 'empty'}: [] + {type: 'empty'}: + [[], ctx] # remove in favour of using _ as empty? - {type: 'group', exprs: is_empty ?}: [] - else: [transform expr] + {type: 'group', exprs: is_empty ?}: + [[], ctx] + else: + [arg, next_ctx] = transform expr, ctx + [[arg], next_ctx] transform_call = fn node, ctx: - callee = ctx.transform node.callee + [callee, args_ctx] = transform node.callee, ctx - args = match node.args: + [args, end_ctx] = match node.args: 1 == length ?: - transform_single_arg node.args, ctx + transform_single_arg node.args, args_ctx else: - transform_args node.args, ctx + transform_args node.args, args_ctx + + js = callExpression callee, args - callExpression callee, [...args] + [js, end_ctx] diff --git a/src/lang/call/pipe.fnk b/src/lang/call/pipe.fnk index 1a6fc22..3c7659e 100644 --- a/src/lang/call/pipe.fnk +++ b/src/lang/call/pipe.fnk @@ -5,35 +5,39 @@ babel_types = import '@babel/types' {assign, lets, expr_block, undef} = import '../../js/types.fnk' {transform_value} = import '../partial/init.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' transform_pipe = fn node, ctx: - {transform, unique_ident} = ctx + {unique_ident} = ctx {exprs} = node - start_value = match node.args: + [start_value, pipe_ctx] = match node.args: is_empty ?: - undef _ + [(undef _), ctx] else: [arg] = node.args - transform arg + transform arg, ctx result = unique_ident 'pipe_result' - pipe_calls = pipe exprs: - map expr: - wrap_with_comment_loc - assign - result - callExpression - transform_value expr, ctx - [result] + [pipe_calls, next_ctx] = pipe exprs: + map expr, callee_ctx=pipe_ctx: + [callee, next_ctx] = transform_value expr, callee_ctx + + js = wrap_with_comment_loc + assign result, callExpression callee, [result] expr - expr_block + ([js, next_ctx], next_ctx) + + collect_with_ctx ctx + + js = expr_block wrap_with_comment_loc lets result, start_value start_value ...pipe_calls + [js, next_ctx] \ No newline at end of file diff --git a/src/lang/comparison/init.fnk b/src/lang/comparison/init.fnk index ccf6636..dea3e4e 100644 --- a/src/lang/comparison/init.fnk +++ b/src/lang/comparison/init.fnk @@ -2,6 +2,7 @@ babel_types = import '@babel/types' {binaryExpression, logicalExpression} = babel_types {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' @@ -11,23 +12,22 @@ transform_op = dict: -transform_comp = fn {op, left, right}, {transform}: +transform_comp = fn {op, left, right}, ctx: {(op): operator=op} = transform_op - bin_left = transform left + [bin_left, next_ctx] = transform left, ctx + [bin_right, end_ctx] = transform right, next_ctx - match left: + js = match left: {op: ? in ['<', '>', '<=', '>=', '==', '!=']}: - bin_right = binaryExpression - operator - bin_left.right - transform right - - logicalExpression '&&', bin_left, bin_right + logicalExpression '&&', + bin_left + binaryExpression operator, bin_left.right, bin_right else: - bin_right = transform right binaryExpression operator, bin_left, bin_right + [js, end_ctx] + add_comparison = fn ctx: diff --git a/src/lang/conditionals/match.fnk b/src/lang/conditionals/match.fnk index 3092ae5..b4cbf87 100644 --- a/src/lang/conditionals/match.fnk +++ b/src/lang/conditionals/match.fnk @@ -12,6 +12,8 @@ babel_types = import '@babel/types' {get_key} = import '../literals/record.fnk' {is_partial} = import '../partial/init.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' +{transform} = import '../transform.fnk' + iter = fn value: @@ -21,6 +23,7 @@ iter = fn value: memberExpression value, symb_iter, true + is_iterable = fn value: and not_nullish value @@ -29,14 +32,19 @@ is_iterable = fn value: stringLiteral 'function' -comp = fn id, expected, {transform, ...ctx}: + +comp = fn id, expected, ctx: value_ctx = {...ctx, partial_ident: id} - value = transform expected, value_ctx + # TODO: test how deep `?` goes + [value, {partial_ident: _, ...next_ctx}] = transform expected, value_ctx - match expected: + cond = match expected: is_partial ?: value else: eq id, value + [cond, next_ctx] + + match_props = fn props, emit_result, ctx, cond: [{id, prop}, ...rest] = props @@ -48,12 +56,16 @@ match_props = fn props, emit_result, ctx, cond: prop.right emit = match props: - 1 == length ?: emit_result - else: fn: match_props rest, emit_result, ctx, cond + 1 == length ?: + emit_result + else: + fn ctx: + match_props rest, emit_result, ctx, cond match_condition id, value, emit, ctx, cond + match_obj = fn value, obj, emit_result, ctx, cond: [...id_props] = pipe obj.exprs: map prop: @@ -74,7 +86,7 @@ match_obj = fn value, obj, emit_result, ctx, cond: not_nullish value match id_props: is_empty ?: - emit_result _ + emit_result ctx else: blockStatement list: consts decl, value @@ -87,7 +99,7 @@ match_elems = fn elems, emit_result, ctx, cond: emit = match elems: 1 == length ?: emit_result - else: fn: match_elems rest, emit_result, ctx, cond + else: fn ctx: match_elems rest, emit_result, ctx, cond match_condition id, value, emit, ctx, cond @@ -115,14 +127,18 @@ get_array_decl = fn arr, id_elems, right, ctx: left = {type: 'list', exprs, loc: arr.loc} - decl = ctx.transform dict: - type: 'assign' - op: '=' - left - right: {type: 'ident', value: right.name, loc: arr.loc} - loc: arr.loc + [decl, next_ctx] = transform + dict: + type: 'assign' + op: '=' + left + right: {type: 'ident', value: right.name, loc: arr.loc} + loc: arr.loc + ctx + + js = consts decl.left, decl.right + [js, next_ctx] - consts decl.left, decl.right match_array = fn value, arr, emit_result, ctx, cond: @@ -131,7 +147,7 @@ match_array = fn value, arr, emit_result, ctx, cond: id = ctx.unique_ident 'a' {id, value: expr} - array_decl = get_array_decl arr, id_elems, value, ctx + [array_decl, next_ctx] = get_array_decl arr, id_elems, value, ctx [...filtered_id_elems] = pipe id_elems: filter {value}: @@ -143,21 +159,26 @@ match_array = fn value, arr, emit_result, ctx, cond: {type: 'spread'}: false else: true + result = match id_elems: + is_empty ?: + emit_result next_ctx + else: + blockStatement list: + array_decl + match_elems filtered_id_elems, emit_result, next_ctx, cond + ifStatement is_iterable value - match id_elems: - is_empty ?: - emit_result _ - else: - blockStatement list: - array_decl - match_elems filtered_id_elems, emit_result, ctx, cond + result + match_simple = fn value, expr, emit_result, ctx: - ifStatement - comp value, expr, {...ctx, wrap: 'loc'} - emit_result _ + [cond, result_ctx] = comp value, expr, {...ctx, wrap: 'loc'} + result = emit_result result_ctx + ifStatement cond, result + + match_condition = fn value, expr, emit_result, ctx, cond: @@ -177,22 +198,36 @@ match_condition = fn value, expr, emit_result, ctx, cond: wrap_with_comment_loc js_expr, cond + split_condition = fn {left, right}: [left, right] + match_all = fn value, matches, emit, ctx: - pipe matches: + exprs = pipe matches: map expr: match expr: {type: 'block', op: 'else'}: {op:_, ...block} = expr - js_expr = emit block + js_expr = emit block, ctx wrap_with_comment_loc js_expr, block else: [condition, result] = split_condition expr - emit_result = fn: emit result + emit_result = fn ctx: emit result, ctx match_condition value, condition, emit_result, ctx, condition + [exprs, ctx] + + + +result_emitter = fn break_lbl: fn result, ctx: + [result_js, next_ctx] = transform result, ctx + js = blockStatement list: + expressionStatement result_js + breakStatement break_lbl + + js # TODO [js, next_ctx] + transform_match = fn node, ctx: @@ -202,16 +237,17 @@ transform_match = fn node, ctx: value = ctx.unique_ident 'value' break_lbl = ctx.unique_ident 'match' - emit_result = fn result: - blockStatement list: - expressionStatement ctx.transform result - breakStatement break_lbl + emit_result = result_emitter break_lbl + + [inputs_js, next_ctx] = transform inputs, ctx + [match_exprs, end_ctx] = match_all value, exprs, emit_result, next_ctx - doExpression + js = doExpression blockStatement list: labeledStatement break_lbl blockStatement list: - consts value, ctx.transform inputs - ...match_all value, exprs, emit_result, ctx + consts value, inputs_js + ...match_exprs + [js, end_ctx] diff --git a/src/lang/func/init.fnk b/src/lang/func/init.fnk index a3c1534..99c62ef 100644 --- a/src/lang/func/init.fnk +++ b/src/lang/func/init.fnk @@ -4,23 +4,35 @@ babel_types = import '@babel/types' {transform_left} = import '../../js/left.fnk' {add, any} = import '../context.fnk' {transform_block} = import '../block/init.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' -transform_func = fn node, ctx: +transform_arg = fn arg, ctx: {unique_ident} = ctx - [...params] = pipe node.args: - map arg: - match arg: - {type: 'empty'}: - unique_ident '' - else: - transform_left ctx.transform arg + match arg: + {type: 'empty'}: + ident = unique_ident '' + [ident, ctx] + else: + [t_arg, next_ctx] = transform arg, ctx + js_arg = transform_left t_arg + [js_arg, next_ctx] + + + +transform_func = fn node, ctx: + [params, next_ctx] = pipe node.args: + map arg, arg_ctx=ctx: + [js_arg, next_ctx] = transform_arg arg, arg_ctx + ([js_arg, next_ctx], next_ctx) + collect_with_ctx ctx - body = transform_block node, ctx - arrowFunctionExpression params, body + [body, end_ctx] = transform_block node, next_ctx + js = arrowFunctionExpression params, body + [js, end_ctx] add_func = fn ctx: diff --git a/src/lang/group/init.fnk b/src/lang/group/init.fnk index 40ae719..a115e98 100644 --- a/src/lang/group/init.fnk +++ b/src/lang/group/init.fnk @@ -1,11 +1,12 @@ {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' -transform_group = fn node, {transform}: +transform_group = fn node, ctx: # TODO: what if group has multiple expr [expr] = node.exprs - transform expr + transform expr, ctx diff --git a/src/lang/identifier/init.fnk b/src/lang/identifier/init.fnk index 2c54517..af76bef 100644 --- a/src/lang/identifier/init.fnk +++ b/src/lang/identifier/init.fnk @@ -6,9 +6,10 @@ babel_types = import '@babel/types' -transform_ident = fn {value}: - name = escape_ident value - identifier name +transform_ident = fn {value}, ctx: + name = escape_ident value, ctx + js = identifier name + [js, ctx] diff --git a/src/lang/init.fnk b/src/lang/init.fnk index 894297b..09e4e51 100644 --- a/src/lang/init.fnk +++ b/src/lang/init.fnk @@ -1,10 +1,8 @@ {count} = import '@fink/std-lib/iter.fnk' -{ident, wrap} = import '../js/types.fnk' -{var_prefix} = import '../js/identifier.fnk' +{unique_ident} = import '../js/types.fnk' -{transform_error} = import './errors.fnk' -{get_transformer} = import './context.fnk' +{transform} = import './transform.fnk' {add_assignment} = import './assignment/init.fnk' {add_func} = import './func/init.fnk' @@ -25,7 +23,6 @@ {add_arithmitic} = import './arithmitic/init.fnk' {add_block} = import './block/init.fnk' {add_partial} = import './partial/init.fnk' -{wrap_with_comment_loc} = import './comments/init.fnk' add_transformers = fn ctx: @@ -52,53 +49,6 @@ add_transformers = fn ctx: add_js_compat -wrap_node = fn ctx, js_node, node: - match ctx: - {wrap: 'loc'}: - wrap node, js_node - else: - wrap_with_comment_loc js_node, node - - -try_transform = fn transform, node, ctx: - [err, js_node] = try: transform node, ctx - - match err: - false: - js_node - else: - transform_error err, node, ctx - - -transform_with_comments = fn transform, node, ctx: - js_node = try_transform transform, node, ctx - match js_node: - {error: {}}: - # TODO don't use mutable - ctx.errors.push js_node - js_node - else: - wrap_node ctx, js_node, node - - -transform_expr = fn node, ctx: - transform_ctx = dict: - ...ctx - transform: fn next_node, next_ctx=transform_ctx: - transform_expr next_node, next_ctx - - transform = get_transformer node, ctx - - match transform: - false: - err = transform_error 'Unknown expression.', node, ctx - # TODO don't use mutable - ctx.errors.push err - err - else: - transform_with_comments transform, node, transform_ctx - - init_ctx = fn code, filename: id_cntr = count 1 @@ -106,22 +56,31 @@ init_ctx = fn code, filename: filename code errors: [] + + unique_id: 0 + ident_prefix: 'ˆ' + unique_ident: fn name: + # console.log 'unique_ident', name # TODO: return ident and new ctx to make it not stateful - {value} = id_cntr.next _ - ident '${var_prefix}${name}_${value}' + {ident_prefix} = ctx + {value: unique_id} = id_cntr.next _ + [ident] = unique_ident name, {ident_prefix, unique_id} + ident pipe ctx: add_transformers + transform_ast = fn expr, code, filename, options: ctx = init_ctx code, filename - js_ast = transform_expr expr, {...ctx, options} + [js_ast, end_ctx] = transform expr, {...ctx, options} + # TODO: why can js_ast be an error, why not just use end_ctx? match js_ast: {error: {}}: - {errors: ctx.errors} + {errors: end_ctx.errors} else: {...js_ast, errors: []} diff --git a/src/lang/iterable/common.fnk b/src/lang/iterable/common.fnk index f6bbc0a..a6ac155 100644 --- a/src/lang/iterable/common.fnk +++ b/src/lang/iterable/common.fnk @@ -1,54 +1,61 @@ {length} = import '@fink/std-lib/iter.fnk' {consts, yields, lets, assign} = import '../../js/types.fnk' -{block_statement} = import '../block/init.fnk' +{exprs_block} = import '../block/init.fnk' +{transform} = import '../transform.fnk' -transform_init = fn left, right, {transform}: +transform_init = fn left, right, ctx: + [item_init, next_ctx] = transform + dict: + type: 'assign' + op: '=' + left + right: {type: 'ident', value: right.name, loc: left.loc} + loc: left.loc + ctx - item_init = transform dict: - type: 'assign' - op: '=' - left - right: {type: 'ident', value: right.name, loc: left.loc} - loc: left.loc + js = consts item_init.left, item_init.right + [js, next_ctx] - consts item_init.left, item_init.right - -yield_expr = fn result, expr, {transform}: +yield_expr = fn result, expr, ctx: [yield_value, is_spread] = match expr: {type: 'spread'}: [expr.right, true] else: [expr, false] - list: - consts result, transform yield_value - yields - result - is_spread + [result_value, next_ctx] = transform yield_value, ctx + + exprs = list: + consts result, result_value + yields result, is_spread + + [exprs, next_ctx] get_accs = fn node, last_expr, ctx: - {unique_ident, transform} = ctx + {unique_ident} = ctx [, acc_arg] = node.args match node.args: 2 == length ?: acc = unique_ident 'accu' - acc_init = lets acc, transform acc_arg.right + [acc_init_value, init_ctx] = transform acc_arg.right, ctx + acc_init = lets acc, acc_init_value - acc_assign = transform_init acc_arg.left, acc, ctx + [acc_assign, acc_ctx] = transform_init acc_arg.left, acc, init_ctx [result_expr, acc_expr] = last_expr.exprs - next_acc_assign = assign acc, transform acc_expr + [acc_val, next_ctx] = transform acc_expr, acc_ctx + next_acc_assign = assign acc, acc_val - [[acc_init], [acc_assign], result_expr, [next_acc_assign], acc] + [[acc_init], [acc_assign], result_expr, [next_acc_assign], acc, next_ctx] else: - [[], [], last_expr, []] + [[], [], last_expr, [], , ctx] @@ -60,21 +67,22 @@ get_item = fn node, ctx: match item_arg: {type: 'empty'}: - [item, []] + [item, [], ctx] else: - item_init = transform_init item_arg, item, ctx - [item, [item_init]] + [item_init, next_ctx] = transform_init item_arg, item, ctx + [item, [item_init], next_ctx] get_iter_helpers = fn node, ctx: - {unique_ident, transform} = ctx + {unique_ident} = ctx - [item, item_init] = get_item node, ctx + [item, item_init, acc_ctx] = get_item node, ctx # TODO move next line into get_accs? [...exprs, last_expr] = node.exprs - [acc_init, acc_assign, result_expr1, next_accu, accu] = get_accs node, last_expr, ctx + [acc_init, acc_assign, result_expr1, next_accu, accu, exprs_ctx] = get_accs + node, last_expr, acc_ctx items = unique_ident 'items' result = unique_ident 'result' @@ -85,9 +93,13 @@ get_iter_helpers = fn node, ctx: {type: 'spread'}: [result_expr1.right, true] else: [result_expr1, false] - expressions = pipe exprs: - map expr: block_statement expr, ctx - [...?, consts result, transform result_expr] + [expressions, next_ctx] = pipe exprs: + exprs_block ?, exprs_ctx + + fn [exprs, result_ctx]: + [result_value, next_ctx] = transform result_expr, result_ctx + result_const = consts result, result_value + [[...exprs, result_const], next_ctx] dict: accu, acc_init @@ -96,5 +108,6 @@ get_iter_helpers = fn node, ctx: expressions result, result_is_spread next_accu + next_ctx diff --git a/src/lang/iterable/filter.fnk b/src/lang/iterable/filter.fnk index 056f8d5..65b4015 100644 --- a/src/lang/iterable/filter.fnk +++ b/src/lang/iterable/filter.fnk @@ -1,7 +1,7 @@ babel_types = import '@babel/types' {ifStatement} = babel_types -{generator, for_of, yields} = import '../../js/types.fnk' +{generator, for_of, yields, ident} = import '../../js/types.fnk' {get_iter_helpers} = import './common.fnk' @@ -17,8 +17,9 @@ transform_filter = fn node, ctx: next_accu } = get_iter_helpers node, ctx + name = ident 'filter', ctx - generator 'filter', [items], + js = generator name, [items], ...acc_init for_of [item, items], @@ -31,3 +32,5 @@ transform_filter = fn node, ctx: yields item ...next_accu + + [js, ctx] \ No newline at end of file diff --git a/src/lang/iterable/fold.fnk b/src/lang/iterable/fold.fnk index 5c966ea..449bf21 100644 --- a/src/lang/iterable/fold.fnk +++ b/src/lang/iterable/fold.fnk @@ -1,41 +1,54 @@ {assign, for_of, func, lets, undef} = import '../../js/types.fnk' -{block_statement} = import '../block/init.fnk' +{exprs_block} = import '../block/init.fnk' +{transform} = import '../transform.fnk' {transform_init} = import './common.fnk' -transform_fold = fn node, ctx: - {transform, unique_ident} = ctx +get_acc = fn acc_arg, ctx: + {unique_ident} = ctx - [item_arg, acc_arg] = node.args + acc = unique_ident 'accu' - item = unique_ident 'item' - item_init = transform_init item_arg, item, ctx + [acc_init, acc_ctx] = match acc_arg: + {}: + transform acc_arg.right, ctx + else: + [(undef _), ctx] - acc = unique_ident 'accu' + [acc_assign, next_ctx] = match acc_arg: + {}: + [init, next_ctx] = transform_init acc_arg.left, acc, acc_ctx + [[init], next_ctx] + else: + [[], acc_ctx] - acc_init = match acc_arg: - {}: transform acc_arg.right - else: undef _ + [acc, acc_init, acc_assign, next_ctx] - acc_assign = match acc_arg: - {}: [transform_init acc_arg.left, acc, ctx] - else: [] - items = unique_ident 'items' +transform_fold = fn node, ctx: + {unique_ident} = ctx + + [item_arg, acc_arg] = node.args [...expressions, last_expr] = node.exprs - func [items], + item = unique_ident 'item' + [item_init, acc_ctx] = transform_init item_arg, item, ctx + [acc, acc_init, acc_assign, block_ctx] = get_acc acc_arg, acc_ctx + + items = unique_ident 'items' + [body, result_ctx] = exprs_block expressions, block_ctx + [result, end_ctx] = transform last_expr, result_ctx + + js = func [items], lets acc, acc_init for_of [item, items], ...acc_assign item_init - - ...pipe expressions: - map expr: block_statement expr, ctx - - assign acc, transform last_expr + ...body + assign acc, result acc + [js, end_ctx] diff --git a/src/lang/iterable/map.fnk b/src/lang/iterable/map.fnk index cb00137..bbbb082 100644 --- a/src/lang/iterable/map.fnk +++ b/src/lang/iterable/map.fnk @@ -1,4 +1,4 @@ -{generator, for_of, yields} = import '../../js/types.fnk' +{generator, for_of, yields, ident} = import '../../js/types.fnk' {get_iter_helpers} = import './common.fnk' @@ -14,7 +14,9 @@ transform_map = fn node, ctx: next_accu } = get_iter_helpers node, ctx - generator 'map', [items], + name = ident 'map', ctx + + js = generator name, [items], ...acc_init for_of [item, items], @@ -27,3 +29,5 @@ transform_map = fn node, ctx: result_is_spread ...next_accu + + [js, ctx] \ No newline at end of file diff --git a/src/lang/iterable/unfold.fnk b/src/lang/iterable/unfold.fnk index b0c4257..ae271ed 100644 --- a/src/lang/iterable/unfold.fnk +++ b/src/lang/iterable/unfold.fnk @@ -3,10 +3,11 @@ babel_types = import '@babel/types' {is_empty} = import '@fink/std-lib/iter.fnk' -{assign, generator, true_, lets} = import '../../js/types.fnk' +{assign, generator, true_, lets, ident} = import '../../js/types.fnk' -{block_statement} = import '../block/init.fnk' +{exprs_block} = import '../block/init.fnk' {transform_init, yield_expr} = import './common.fnk' +{transform} = import '../transform.fnk' @@ -18,58 +19,65 @@ loop = fn ...body: get_acc_exprs = fn node, next_value, ctx: - {transform, unique_ident} = ctx + {unique_ident} = ctx initial = unique_ident 'initial' acc = unique_ident 'accu' [acc_arg] = node.args; - [acc_left, acc_right] = match acc_arg: - {type: 'assign'}: [acc_arg.left, transform acc_arg.right] - else: [acc_arg, initial] + [acc_left, acc_right, init_ctx] = match acc_arg: + {type: 'assign'}: + [right, next_ctx] = transform acc_arg.right, ctx + [acc_arg.left, right, next_ctx] + else: + [acc_arg, initial, ctx] acc_init = lets acc, acc_right - acc_assign = transform_init acc_left, acc, ctx + [acc_assign, next_ctx] = transform_init acc_left, acc, init_ctx acc_result = assign acc, next_value - [[initial], [acc_init], [acc_assign], [acc_result]] + [[initial], [acc_init], [acc_assign], [acc_result], next_ctx] get_accs = fn node, next_value, ctx: match node.args: is_empty ?: - [[], [], [], []] + [[], [], [], [], ctx] else: get_acc_exprs node, next_value, ctx -transform_unfold = fn node, ctx: - {transform, unique_ident} = ctx +get_result = fn result_id, expr, ctx: + match expr: + {type: 'group'}: + [result_expr, acc_expr] = expr.exprs + [result_expr, ...transform acc_expr, ctx] + else: + [expr, result_id, ctx] + + +transform_unfold = fn node, ctx: + {unique_ident} = ctx [...expressions, last_expr] = node.exprs result_id = unique_ident 'result' - [result_expr, next_accu] = match last_expr: - {type: 'group'}: - [result_expr, acc_expr] = last_expr.exprs - [result_expr, transform acc_expr] - else: - [last_expr, result_id] + [result_expr, next_accu, acc_ctx] = get_result result_id, last_expr, ctx + [initial, acc_init, acc_assign, acc_result, block_ctx] = get_accs node, next_accu, acc_ctx - [initial, acc_init, acc_assign, acc_result] = get_accs node, next_accu, ctx + name = ident 'unfold', ctx + [body, yield_ctx] = exprs_block expressions, block_ctx + [yield_result, end_ctx] = yield_expr result_id, result_expr, yield_ctx - generator 'unfold', [...initial], + js = generator name, [...initial], ...acc_init - loop ...acc_assign - - ...pipe expressions: - map expr: block_statement expr, ctx - - ...yield_expr result_id, result_expr, ctx - + ...body + ...yield_result ...acc_result + + [js, end_ctx] \ No newline at end of file diff --git a/src/lang/iterable/until.fnk b/src/lang/iterable/until.fnk index 884a9df..b3f7064 100644 --- a/src/lang/iterable/until.fnk +++ b/src/lang/iterable/until.fnk @@ -1,7 +1,7 @@ babel_types = import '@babel/types' {returnStatement, ifStatement} = babel_types -{generator, for_of, yields, eq, true_} = import '../../js/types.fnk' +{generator, for_of, yields, eq, true_, ident} = import '../../js/types.fnk' {get_iter_helpers} = import './common.fnk' @@ -17,7 +17,9 @@ transform_until = fn node, ctx: next_accu } = get_iter_helpers node, ctx - generator 'filter_until', [items], + name = ident 'filter_until', ctx + + js = generator name, [items], ...acc_init for_of [item, items], @@ -34,5 +36,6 @@ transform_until = fn node, ctx: ...next_accu + [js, ctx] diff --git a/src/lang/iterable/while.fnk b/src/lang/iterable/while.fnk index 999b9e1..34ae88b 100644 --- a/src/lang/iterable/while.fnk +++ b/src/lang/iterable/while.fnk @@ -1,7 +1,7 @@ babel_types = import '@babel/types' {returnStatement, ifStatement} = babel_types -{generator, for_of, yields, neq, true_} = import '../../js/types.fnk' +{generator, for_of, yields, neq, true_, ident} = import '../../js/types.fnk' {get_iter_helpers} = import './common.fnk' @@ -17,7 +17,9 @@ transform_while = fn node, ctx: next_accu } = get_iter_helpers node, ctx - generator 'filter_while', [items], + name = ident 'filter_while', ctx + + js = generator name, [items], ...acc_init for_of [item, items], @@ -32,3 +34,5 @@ transform_while = fn node, ctx: yields item ...next_accu + + [js, ctx] \ No newline at end of file diff --git a/src/lang/js-compat/throw.fnk b/src/lang/js-compat/throw.fnk index 3073f2e..b79ac4f 100644 --- a/src/lang/js-compat/throw.fnk +++ b/src/lang/js-compat/throw.fnk @@ -1,10 +1,13 @@ babel_types = import '@babel/types' {unaryExpression} = babel_types + {wrap} = import '../../js/types.fnk' +{transform} = import '../transform.fnk' -transform_throw = fn node, {transform}: - right = transform node.right +transform_throw = fn node, ctx: + [right, next_ctx] = transform node.right, ctx + js = wrap node, unaryExpression 'throw', right - wrap node, unaryExpression 'throw', right + [js, next_ctx] diff --git a/src/lang/js-compat/try.fnk b/src/lang/js-compat/try.fnk index 73489bf..210cc49 100644 --- a/src/lang/js-compat/try.fnk +++ b/src/lang/js-compat/try.fnk @@ -11,7 +11,8 @@ babel_types = import '@babel/types' transform_try = fn node, ctx: - block = transform_block node, ctx + [block, end_ctx] = transform_block node, ctx + body = match block: isDoExpression ?: block.body.body else: [block] @@ -32,11 +33,11 @@ transform_try = fn node, ctx: expressionStatement arrayExpression [err] - - doExpression + js = doExpression blockStatement list: tryStatement try_block catch_block + [js, end_ctx] diff --git a/src/lang/jsx/init.fnk b/src/lang/jsx/init.fnk index 487e01b..5dfe262 100644 --- a/src/lang/jsx/init.fnk +++ b/src/lang/jsx/init.fnk @@ -8,70 +8,96 @@ babel_types = import '@babel/types' {length} = import '@fink/std-lib/iter.fnk' {add, any} = import '../context.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' -transform_jsx_elem = fn node, {transform}: +transform_exprs = fn exprs, ctx: + pipe exprs: + map expr, expr_ctx=ctx: + [result, next_ctx] = transform expr, expr_ctx + ([result, next_ctx], next_ctx) + collect_with_ctx ctx + + + +transform_jsx_elem = fn node, ctx: id = jsxIdentifier node.name - [...attrs] = pipe node.props: - map expr: - match expr: + # TODO: use transform_exprs with extra mapping func + [attrs, children_ctx] = pipe node.props: + map expr, expr_ctx= ctx: + [attr, next_ctx] = match expr: {type: 'spread'}: - jsxSpreadAttribute transform expr.right + [attr, next_ctx] = transform expr.right, expr_ctx + spread = jsxSpreadAttribute attr + [spread, next_ctx] else: - transform expr + transform expr, expr_ctx + ([attr, next_ctx], next_ctx) + + collect_with_ctx ctx - [...children] = pipe node.children: - map expr: transform expr + [children, next_ctx] = transform_exprs node.children, children_ctx - jsxElement + js = jsxElement jsxOpeningElement id, attrs, node.self_closing jsxClosingElement id children + [js, next_ctx] -transform_jsx_frag = fn node, {transform}: - [...children] = pipe node.children: - map expr: transform expr - jsxFragment +transform_jsx_frag = fn node, ctx: + [children, next_ctx] = transform_exprs node.children, ctx + + js = jsxFragment jsxOpeningFragment _ jsxClosingFragment _ children + [js, next_ctx] + -transform_jsx_attr = fn node, {transform}: +transform_jsx_attr = fn node, ctx: {loc, name} = node - value = match node: + [value, next_ctx] = match node: {value: {type: 'string', exprs: 1 == length ?}}: {exprs: [str]} = node.value - [stringLiteral str.value] + [[stringLiteral str.value], ctx] {value: {type: 'jsx:expr'}}: - [transform node.value] + [val, next_ctx] = transform node.value, ctx + [[val], next_ctx] {value: {}}: - [jsxExpressionContainer transform node.value] + [val, next_ctx] = transform node.value, ctx + [[jsxExpressionContainer val], next_ctx] else: - [jsxExpressionContainer transform {type: 'ident', value: name, loc}] + [val, next_ctx] = transform {type: 'ident', value: name, loc}, ctx + [[jsxExpressionContainer val], next_ctx] id = jsxIdentifier name - jsxAttribute id, ...value + js = jsxAttribute id, ...value + + [js, next_ctx] -transform_jsx_text = fn node: - jsxText node.value +transform_jsx_text = fn node, ctx: + js = jsxText node.value + [js, ctx] -transform_jsx_expr_container = fn node, {transform}: - jsxExpressionContainer transform node.expr +transform_jsx_expr_container = fn node, ctx: + [val, next_ctx] = transform node.expr, ctx + js = jsxExpressionContainer val + [js, next_ctx] diff --git a/src/lang/literals/keywords.fnk b/src/lang/literals/keywords.fnk index 3cc359d..ce3f922 100644 --- a/src/lang/literals/keywords.fnk +++ b/src/lang/literals/keywords.fnk @@ -2,7 +2,8 @@ babel_types = import '@babel/types' {booleanLiteral} = babel_types -transform_keyword = fn node: - match node: +transform_keyword = fn node, ctx: + js = match node: {'value': 'true'}: booleanLiteral true {'value': 'false'}: booleanLiteral false + [js, ctx] \ No newline at end of file diff --git a/src/lang/literals/list.fnk b/src/lang/literals/list.fnk index 6ff754b..b9089ee 100644 --- a/src/lang/literals/list.fnk +++ b/src/lang/literals/list.fnk @@ -2,13 +2,21 @@ babel_types = import '@babel/types' {arrayExpression} = babel_types {null} = import '@fink/js-interop/nullish.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' -transform_list = fn node, {transform}: - [...elems] = pipe node.exprs: - map elem: - match elem: - {type: 'empty'}: null - else: transform elem - arrayExpression elems +transform_list = fn node, ctx: + [elems, next_ctx] = pipe node.exprs: + map elem, elem_ctx=ctx: + [js, next_ctx] = match elem: + {type: 'empty'}: + [null, ctx] + else: + transform elem, elem_ctx + + ([js, next_ctx], next_ctx) + collect_with_ctx ctx + + js = arrayExpression elems + [js, next_ctx] diff --git a/src/lang/literals/number.fnk b/src/lang/literals/number.fnk index 8c4f356..458ea1a 100644 --- a/src/lang/literals/number.fnk +++ b/src/lang/literals/number.fnk @@ -5,8 +5,8 @@ babel_types = import '@babel/types' -transform_number = fn {value}: - match value: +transform_number = fn {value}, ctx: + js = match value: matches ?, rx'\.': numericLiteral parse_float value else: @@ -15,4 +15,5 @@ transform_number = fn {value}: ...numericLiteral num extra: {raw: value, rawValue: num} + [js, ctx] diff --git a/src/lang/literals/record.fnk b/src/lang/literals/record.fnk index e880f04..09c6d26 100644 --- a/src/lang/literals/record.fnk +++ b/src/lang/literals/record.fnk @@ -2,49 +2,56 @@ babel_types = import '@babel/types' {objectExpression, objectProperty, assignmentPattern} = babel_types {raw_str} = import '../../js/types.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' +transform_record = fn node, ctx: + [props, next_ctx] = pipe node.exprs: + map key_value, prop_ctx=ctx: + [prop, next_ctx] = transform key_value, prop_ctx + ([prop, next_ctx], next_ctx) -transform_record = fn node, {transform}: - [...props] = pipe node.exprs: - map key_value: transform key_value + collect_with_ctx ctx - objectExpression props + js = objectExpression props + [js, next_ctx] -str_key = fn {value, loc}: + +str_key = fn {value, loc}, ctx: str = raw_str value - {...str, loc} + [{...str, loc}, ctx] get_key = fn {left: key}, ctx: match key: {type: 'group'}: - [true, ctx.transform key] + [true, ...transform key, ctx] {type: 'string'}: - [true, ctx.transform key] + [true, ...transform key, ctx] else: - [false, str_key key] + [false, ...str_key key, ctx] get_value = fn {right}, ctx: match right: {type: 'empty'}: - ctx.unique_ident 'unused' + ident = ctx.unique_ident 'unused' + [ident, ctx] else: - ctx.transform right + transform right, ctx transform_kv = fn node, ctx: match node: {left: {type: 'spread'}}: - ctx.transform node.left + transform node.left, ctx else: - [computed, key] = get_key node, ctx - value = get_value node, ctx + [computed, key, next_ctx] = get_key node, ctx + [value, end_ctx] = get_value node, next_ctx shorthand = node.left == node.right @@ -54,6 +61,7 @@ transform_kv = fn node, ctx: else: value - objectProperty key, final_value, computed, shorthand + js = objectProperty key, final_value, computed, shorthand + [js, end_ctx] diff --git a/src/lang/literals/string.fnk b/src/lang/literals/string.fnk index 45ba5a8..b202bd1 100644 --- a/src/lang/literals/string.fnk +++ b/src/lang/literals/string.fnk @@ -2,13 +2,15 @@ babel_types = import '@babel/types' {templateElement, templateLiteral, taggedTemplateExpression} = babel_types {rx, replace_all} = import '@fink/std-lib/regex.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' + not_tagged = {tagged: false} -transform_string = fn node, {transform}: +transform_string = fn node, ctx: {exprs: parts, tag=not_tagged} = node [...quasies] = pipe parts: @@ -20,17 +22,23 @@ transform_string = fn node, {transform}: rx'\\([\s\S])|(`)' '\\$1$2' - [...expressions] = pipe parts: - filter part: part.type != 'string:text' - map part: transform part + [expressions, next_ctx] = pipe parts: + filter part: + part.type != 'string:text' + + map part, part_ctx=ctx: + [js, next_ctx] = transform part, part_ctx + ([js, next_ctx], next_ctx) + + collect_with_ctx ctx templ_str = templateLiteral quasies, expressions match tag: not_tagged: - templ_str + [templ_str, next_ctx] else: - taggedTemplateExpression - transform node.tag - templ_str + [tag, end_ctx] = transform node.tag, next_ctx + tagged_str = taggedTemplateExpression tag, templ_str + [tagged_str, end_ctx] diff --git a/src/lang/logical/in.fnk b/src/lang/logical/in.fnk index c021758..dde78db 100644 --- a/src/lang/logical/in.fnk +++ b/src/lang/logical/in.fnk @@ -1,65 +1,71 @@ babel_types = import '@babel/types' {identifier, optionalCallExpression, optionalMemberExpression, memberExpression, callExpression, logicalExpression} = babel_types +{transform} = import '../transform.fnk' + -transform_in = fn node, ctx: - {transform} = ctx +transform_in = fn node, ctx: {left, right} = node - match right: + [js_right, next_ctx] = transform right, ctx + [js_left, end_ctx] = transform left, next_ctx + + + js = match right: {type: 'list'}: callExpression memberExpression - transform right + js_right identifier 'includes' - [transform left] + [js_left] {type: 'string'}: callExpression memberExpression - transform right + js_right identifier 'includes' - [transform left] + [js_left] {type: 'rec'}: callExpression memberExpression - transform right + js_right identifier 'hasOwnProperty' - [transform left] + [js_left] else: logicalExpression '??' optionalCallExpression optionalMemberExpression - transform right + js_right identifier 'includes' false true - [transform left] + [js_left] true logicalExpression '??' optionalCallExpression optionalMemberExpression - transform right + js_right identifier 'has' false true - [transform left] + [js_left] true logicalExpression '??' optionalCallExpression optionalMemberExpression - transform right + js_right identifier 'hasOwnProperty' false true - [transform left] + [js_left] true identifier 'false' + [js, end_ctx] diff --git a/src/lang/logical/init.fnk b/src/lang/logical/init.fnk index 227d4d7..6b7ccc7 100644 --- a/src/lang/logical/init.fnk +++ b/src/lang/logical/init.fnk @@ -1,6 +1,9 @@ babel_types = import '@babel/types' {logicalExpression, unaryExpression} = babel_types + {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' + {transform_in} = import './in.fnk' @@ -12,20 +15,22 @@ transform_op = dict: -transform_not = fn node, {transform}: +transform_not = fn node, ctx: {(node.op): op} = transform_op - right = transform node.right + [right, next_ctx] = transform node.right, ctx + js = unaryExpression op, right + [js, next_ctx] - unaryExpression op, right - -transform_logical = fn node, {transform}: +transform_logical = fn node, ctx: {(node.op): op} = transform_op - left = transform node.left - right = transform node.right - logicalExpression op, left, right + [left, next_ctx] = transform node.left, ctx + [right, end_ctx] = transform node.right, next_ctx + js = logicalExpression op, left, right + + [js, end_ctx] diff --git a/src/lang/module/import.fnk b/src/lang/module/import.fnk index 37d0bcc..9fee78d 100644 --- a/src/lang/module/import.fnk +++ b/src/lang/module/import.fnk @@ -2,6 +2,8 @@ babel_types = import '@babel/types' {callExpression, Import: async_import} = babel_types {ends_with, starts_with, slice, is_str} = import '@fink/std-lib/str.fnk' +{transform} = import '../transform.fnk' + resolve_ext = fn import_url, options: @@ -23,18 +25,23 @@ resolve_ext = fn import_url, options: -transform_import = fn node, {transform, options}: +transform_import = fn node, ctx: + {options} = ctx - right = match node.right: + [right, next_ctx] = match node.right: {type: 'string', exprs: [..., {type: 'string:text'}]}: [...exprs, url] = node.right.exprs - transform dict: - ...node.right - exprs: [...exprs, {...url, value: resolve_ext url.value, options}] + transform + dict: + ...node.right + exprs: [...exprs, {...url, value: resolve_ext url.value, options}] + ctx else: - transform node.right + transform node.right, ctx - callExpression + js = callExpression async_import _ [right] + + [js, next_ctx] \ No newline at end of file diff --git a/src/lang/module/init.fnk b/src/lang/module/init.fnk index 851fc80..c28f024 100644 --- a/src/lang/module/init.fnk +++ b/src/lang/module/init.fnk @@ -9,6 +9,8 @@ babel_types = import '@babel/types' {add, any} = import '../context.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' {block_statement} = import '../block/init.fnk' +{transform, collect_with_ctx} = import '../transform.fnk' + {transform_import: transform_async_import, resolve_ext} = import './import.fnk' @@ -26,73 +28,99 @@ get_shebang = fn expr: -transform_import = fn node, {transform, options}: - [...imports] = match node.left: +transform_import = fn node, ctx: + {options} = ctx + + [imports, end_ctx] = match node.left: {type: 'ident'}: - [importDefaultSpecifier transform node.left] + [imp, next_ctx] = transform node.left, ctx + [[importDefaultSpecifier imp], next_ctx] {type: 'rec'}: pipe node.left.exprs: - map prop: - match prop: + map prop, imp_ctx=ctx: + [right, left_ctx] = transform prop.right, imp_ctx + + [imp, next_ctx] = match prop: {left: {value: 'default'}}: - importSpecifier - transform prop.right - identifier prop.left.value + imp = importSpecifier right, identifier prop.left.value + [imp, left_ctx] + else: - importSpecifier - transform prop.right - transform prop.left + [left, next_ctx] = transform prop.left, left_ctx + imp = importSpecifier right, left + [imp, next_ctx] + + ([imp, next_ctx], next_ctx) + + collect_with_ctx ctx {right: {right: {exprs: [url]}}} = node - importDeclaration + js = importDeclaration imports wrap_with_comment_loc stringLiteral resolve_ext url.value, options node.right.right + [js, end_ctx] + transform_module = fn node, ctx: [maybe_shebang, ...rest] = node.exprs [interpreter, first] = get_shebang maybe_shebang - [...body] = pipe [first, ...rest]: - map expr: - match expr: + [body, end_ctx] = pipe [first, ...rest]: + map expr, expr_ctx=ctx: + + [js, next_ctx] = match expr: {op: 'import'}: {right: {exprs: [url]}} = expr - wrap_with_comment_loc - importDeclaration [], stringLiteral resolve_ext url.value, ctx.options + js = wrap_with_comment_loc + importDeclaration + [], stringLiteral resolve_ext url.value, expr_ctx.options expr + [js, expr_ctx] {right: {op: 'import'}}: - wrap_with_comment_loc - transform_import expr, ctx - expr + [imp, next_ctx] = transform_import expr, expr_ctx + js = wrap_with_comment_loc imp, expr + [js, next_ctx] {type: 'assign', left: {type: 'ident', value: 'default'}}: - wrap_with_comment_loc - exportDefaultDeclaration ctx.transform expr.right + [decl, next_ctx] = transform expr.right, expr_ctx + js = wrap_with_comment_loc + exportDefaultDeclaration decl expr + [js, next_ctx] {type: 'assign', left: {type: 'ident'}}: # we don't want to double up on comments? {comments: _, ...decl} = expr - wrap_with_comment_loc - exportNamedDeclaration block_statement decl, ctx + [decl_st, next_ctx] = block_statement decl, expr_ctx + js = wrap_with_comment_loc + exportNamedDeclaration decl_st expr + [js, next_ctx] + else: - block_statement expr, ctx + block_statement expr, expr_ctx + + ([js, next_ctx], next_ctx) - file + collect_with_ctx ctx + + + js = file program body [] 'module' ...interpreter + [js, end_ctx] + add_module = fn ctx: diff --git a/src/lang/partial/init.fnk b/src/lang/partial/init.fnk index cd85255..a41dad8 100644 --- a/src/lang/partial/init.fnk +++ b/src/lang/partial/init.fnk @@ -3,6 +3,7 @@ babel_types = import '@babel/types' {escape_ident} = import '../../js/identifier.fnk' {add} = import '../context.fnk' +{transform} = import '../transform.fnk' @@ -27,7 +28,8 @@ is_partial = fn node: -transform_value = fn node, {transform}: +transform_value = fn node, ctx: + partial_or_node = match node: is_partial ?: dict: @@ -40,18 +42,22 @@ transform_value = fn node, {transform}: else: node - transform partial_or_node + transform partial_or_node, ctx + +transform_partial = fn {value}, ctx: + {partial_ident} = ctx -transform_partial = fn {value}, {partial_ident}: name = match partial_ident: {name: {}}: partial_ident.name else: - escape_ident value + escape_ident value, ctx + + js = identifier name - identifier name + [js, ctx] diff --git a/src/lang/prop-access/init.fnk b/src/lang/prop-access/init.fnk index 61130e7..9408520 100644 --- a/src/lang/prop-access/init.fnk +++ b/src/lang/prop-access/init.fnk @@ -5,22 +5,26 @@ babel_types = import '@babel/types' {raw_str} = import '../../js/types.fnk' {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' -transform_member = fn {left, right}, {transform}: - memb_left = transform left +transform_member = fn {left, right}, ctx: + [memb_left, next_ctx] = transform left, ctx + {loc, value} = right - [computed, memb_right] = match right: + [computed, memb_right, end_ctx] = match right: {type: 'ident', value: matches ?, rx'^[$_\p{L}][$_\p{L}\p{N}]*'}: - [false, {loc, ...identifier value}] + [false, {loc, ...identifier value}, next_ctx] {type: 'ident'}: - [true, {loc, ...raw_str value}] + [true, {loc, ...raw_str value}, next_ctx] else: - [true, transform right] + [true, ...transform right, next_ctx] + + js = memberExpression memb_left, memb_right, computed - memberExpression memb_left, memb_right, computed + [js, end_ctx] diff --git a/src/lang/spread/init.fnk b/src/lang/spread/init.fnk index 1ba22dd..e2d8db6 100644 --- a/src/lang/spread/init.fnk +++ b/src/lang/spread/init.fnk @@ -1,11 +1,15 @@ babel_types = import '@babel/types' {spreadElement} = babel_types + {add, any} = import '../context.fnk' +{transform} = import '../transform.fnk' + +transform_spread = fn node, ctx: + [right, next_ctx] = transform node.right, ctx + js = spreadElement right + [js, next_ctx] -transform_spread = fn node, {transform}: - right = transform node.right - spreadElement right add_spread = fn ctx: diff --git a/src/lang/transform.fnk b/src/lang/transform.fnk new file mode 100644 index 0000000..4ce347b --- /dev/null +++ b/src/lang/transform.fnk @@ -0,0 +1,68 @@ +{stack_trace} = import '@fink/std-lib/stack-trace.js' + +{wrap} = import '../js/types.fnk' + +{transform_error} = import './errors.fnk' +{get_transformer} = import './context.fnk' + +{wrap_with_comment_loc} = import './comments/init.fnk' + + + +wrap_node = fn ctx, js_node, node: + match ctx: + {wrap: 'loc'}: + wrap node, js_node + else: + wrap_with_comment_loc js_node, node + + + +collect_with_ctx = fn ctx: fn expr_ctx_items: + expr_ctx_items | fold [expr, next_ctx], [exprs]=[[], ctx]: + [[...exprs, expr], next_ctx] + + + +try_transform = fn transform, node, ctx: + [err, result] = try: transform node, ctx + + match err: + false: + result + else: + transform_error err, node, ctx + + + +transform_with_comments = fn transform, node, ctx: + [err, result] = try: + transform node, ctx + + match err: + false: + [js_node, next_ctx] = result + js = wrap_node next_ctx, js_node, node + [js, next_ctx] + else: + xform_error = transform_error err, node, ctx + # TODO don't use mutable + ctx.errors.push xform_error + # TODO: don't return error? + [xform_error, {...ctx, errors: [...ctx.errors, xform_error]}] + + + + +transform = fn node, ctx: + transform = get_transformer node, ctx + + [js, next_ctx] = match transform: + false: + err = transform_error 'Unknown expression.', node, ctx + # TODO: don't return err as ast + [err, {...ctx, errors: [...ctx.errors, err]}] + else: + transform_with_comments transform, node, ctx + + [js, next_ctx] From 0fd1576461e0f451e17ec7fc5f4493561e66d3e9 Mon Sep 17 00:00:00 2001 From: Jan Klaas Kollhof Date: Mon, 26 Oct 2020 09:43:57 +0100 Subject: [PATCH 2/2] refactor: make rest of transforms non-stateful BREAKING CHANGE: transform errors have different structure --- src/generate.fnk | 30 +++--- src/generate.test.fnk | 12 ++- src/js/identifier.fnk | 3 - src/lang/assignment/init.fnk | 11 +- src/lang/block/init.fnk | 9 +- src/lang/call/call.fnk | 17 +-- src/lang/call/pipe.fnk | 14 ++- src/lang/conditionals/match.fnk | 125 ++++++++++++---------- src/lang/conditionals/match.test.fnk.snap | 1 - src/lang/context.fnk | 20 ++-- src/lang/errors.fnk | 26 ++--- src/lang/func/init.fnk | 13 +-- src/lang/init.fnk | 33 +----- src/lang/iterable/common.fnk | 31 +++--- src/lang/iterable/filter.fnk | 3 +- src/lang/iterable/fold.fnk | 20 ++-- src/lang/iterable/map.fnk | 10 +- src/lang/iterable/map.test.fnk | 3 +- src/lang/iterable/unfold.fnk | 21 ++-- src/lang/iterable/until.fnk | 7 +- src/lang/iterable/while.fnk | 5 +- src/lang/js-compat/try.fnk | 6 +- src/lang/jsx/init.fnk | 25 ++--- src/lang/literals/list.fnk | 9 +- src/lang/literals/record.fnk | 15 +-- src/lang/literals/string.fnk | 11 +- src/lang/module/init.fnk | 24 ++--- src/lang/transform.fnk | 39 +++---- 28 files changed, 235 insertions(+), 308 deletions(-) diff --git a/src/generate.fnk b/src/generate.fnk index dc1befe..70f4ebd 100644 --- a/src/generate.fnk +++ b/src/generate.fnk @@ -2,9 +2,9 @@ babel_traverse = import '@babel/traverse' {default: traverse} = babel_traverse {transformFromAstSync} = import '@babel/core' -{is_empty} = import '@fink/std-lib/iter.fnk' -{transform_ast} = import './lang/init.fnk' +{transform} = import './lang/transform.fnk' +{init_ctx} = import './lang/init.fnk' {transform_do_expr} = import './js/do-expression.fnk' {transform_async} = import './js/async.fnk' @@ -12,20 +12,25 @@ babel_traverse = import '@babel/traverse' -transform = fn node, code, filename, options: - ast = transform_ast node, code, filename, options +transform_file = fn fink_ast, code, filename, options: + ctx = init_ctx code, filename + + [error, [js_ast]=[]] = try: + transform fink_ast, {...ctx, options} extras = match options: {module_type: 'cjs'}: module_transforms else: {} - match ast: - {errors: is_empty ?}: - traverse ast, dict: + match error: + false: + traverse js_ast, dict: DoExpression: transform_do_expr AwaitExpression: {enter: transform_async} ...extras - ast + {...js_ast, errors: []} + else: + {errors: [error]} @@ -51,17 +56,10 @@ babel_generate = fn ast, filename, source, options: generate = fn ast, filename, source, options={}: - js_ast = transform ast, source, filename, options + js_ast = transform_file ast, source, filename, options match js_ast: {errors: [{}]}: {code: '', source_map: '', errors: js_ast.errors} else: babel_generate js_ast, filename, source, options - - - - - - - diff --git a/src/generate.test.fnk b/src/generate.test.fnk index ec27ca0..4751fa9 100644 --- a/src/generate.test.fnk +++ b/src/generate.test.fnk @@ -51,13 +51,13 @@ describe 'errors', fn: ' it 'errors with code snippet', fn: - {errors: [{error}]} = fink2js ' + {errors: [{message}]} = fink2js ' foo = bar 123 = foo shrub = ni' expect - error + message to_equal ' test.fnk:2:0 1| foo = bar @@ -66,6 +66,8 @@ describe 'errors', fn: 3| shrub = ni Unable to transform `assign =`. + + TypeError: Property left of AssignmentExpression expected node to be of a type ["LVal"] but instead got "NumericLiteral" ' it 'errors with bad babel options', fn: @@ -79,7 +81,7 @@ describe 'errors', fn: it 'errors when provided with unknown tokens', fn: - {errors: [{error}]} = generate + {errors: [{message}]} = generate dict: type: 'test' op: 'foobar' @@ -90,11 +92,13 @@ describe 'errors', fn: 'test.fnk', 'foobar' expect - error + message to_equal ' test.fnk:1:0 1| foobar ^ Unable to transform `test foobar`. + + Unknown expression. ' diff --git a/src/js/identifier.fnk b/src/js/identifier.fnk index eadd531..b8cbdbf 100644 --- a/src/js/identifier.fnk +++ b/src/js/identifier.fnk @@ -15,9 +15,6 @@ check_ident = rx' [_$\p{L}][_$\p{L}\p{N}]*$' -# TODO: move into ctx -var_prefix = 'ˆ' - str_36 = base_n ?, 36 diff --git a/src/lang/assignment/init.fnk b/src/lang/assignment/init.fnk index 6ff4231..a20c730 100644 --- a/src/lang/assignment/init.fnk +++ b/src/lang/assignment/init.fnk @@ -7,6 +7,7 @@ babel_types = import '@babel/types' } = babel_types {length, is_empty} = import '@fink/std-lib/iter.fnk' +{unique_ident} = import '../../js/types.fnk' {transform_left: xform_left} = import '../../js/left.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' {add, any} = import '../context.fnk' @@ -85,9 +86,9 @@ slice = fn items, start, end=false: transform_spread_right = fn expr, ctx: {left, right} = expr - items = ctx.unique_ident 'items' + [items, init_ctx] = unique_ident 'items', ctx # TODO: wrap declarator? - [init, next_ctx] = transform_value right, ctx + [init, next_ctx] = transform_value right, init_ctx items_init = wrap_with_comment_loc variableDeclaration @@ -141,10 +142,10 @@ transform_await_left = fn node, ctx: transform_await_right = fn expr, ctx: {left, right} = expr - items = ctx.unique_ident 'items' - iter = ctx.unique_ident 'iter' + [items, iter_ctx] = unique_ident 'items', ctx + [iter, init_ctx] = unique_ident 'iter', iter_ctx - [init, next_ctx] = transform_value right, ctx + [init, next_ctx] = transform_value right, init_ctx items_init = wrap_with_comment_loc variableDeclaration 'const', [variableDeclarator items, init] diff --git a/src/lang/block/init.fnk b/src/lang/block/init.fnk index 9fca150..5d09ced 100644 --- a/src/lang/block/init.fnk +++ b/src/lang/block/init.fnk @@ -7,7 +7,7 @@ babel_types = import '@babel/types' {add, any} = import '../context.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' @@ -33,12 +33,7 @@ block_statement = fn expr, ctx: exprs_block = fn exprs, ctx: pipe exprs: - # TODO: duplicate in other modules - map expr, expr_ctx=ctx: - [js_expr, next_ctx] = block_statement expr, expr_ctx - ([js_expr, next_ctx], next_ctx) - - collect_with_ctx ctx + map_with_ctx ctx, block_statement diff --git a/src/lang/call/call.fnk b/src/lang/call/call.fnk index 8463c2a..2b4e245 100644 --- a/src/lang/call/call.fnk +++ b/src/lang/call/call.fnk @@ -2,26 +2,19 @@ babel_types = import '@babel/types' {callExpression, identifier} = babel_types {is_empty, length} = import '@fink/std-lib/iter.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' transform_args = fn args, ctx: - [js_args, next_ctx] = pipe args: - map expr, arg_ctx=ctx: - [arg, next_ctx] = match expr: + pipe args: + map_with_ctx ctx, fn expr, arg_ctx: + match expr: {type: 'empty'}: - undef = identifier 'undefined' - [undef, ctx] + [(identifier 'undefined'), ctx] else: transform expr, arg_ctx - ([arg, next_ctx], next_ctx) - - collect_with_ctx ctx - - [js_args, next_ctx] - transform_single_arg = fn [expr], ctx: diff --git a/src/lang/call/pipe.fnk b/src/lang/call/pipe.fnk index 3c7659e..f31f33b 100644 --- a/src/lang/call/pipe.fnk +++ b/src/lang/call/pipe.fnk @@ -2,37 +2,35 @@ babel_types = import '@babel/types' {callExpression} = babel_types {is_empty} = import '@fink/std-lib/iter.fnk' -{assign, lets, expr_block, undef} = import '../../js/types.fnk' +{assign, lets, expr_block, undef, unique_ident} = import '../../js/types.fnk' {transform_value} = import '../partial/init.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' transform_pipe = fn node, ctx: - {unique_ident} = ctx {exprs} = node - [start_value, pipe_ctx] = match node.args: + [start_value, id_ctx] = match node.args: is_empty ?: [(undef _), ctx] else: [arg] = node.args transform arg, ctx - result = unique_ident 'pipe_result' + [result, pipe_ctx] = unique_ident 'pipe_result', id_ctx [pipe_calls, next_ctx] = pipe exprs: - map expr, callee_ctx=pipe_ctx: + map_with_ctx pipe_ctx, fn expr, callee_ctx: [callee, next_ctx] = transform_value expr, callee_ctx js = wrap_with_comment_loc assign result, callExpression callee, [result] expr - ([js, next_ctx], next_ctx) + [js, next_ctx] - collect_with_ctx ctx js = expr_block wrap_with_comment_loc diff --git a/src/lang/conditionals/match.fnk b/src/lang/conditionals/match.fnk index b4cbf87..0d15fe3 100644 --- a/src/lang/conditionals/match.fnk +++ b/src/lang/conditionals/match.fnk @@ -7,12 +7,12 @@ babel_types = import '@babel/types' } = babel_types {length, is_empty} = import '@fink/std-lib/iter.fnk' -{and, eq, not_nullish, typof, consts} = import '../../js/types.fnk' +{and, eq, not_nullish, typof, consts, unique_ident} = import '../../js/types.fnk' {get_key} = import '../literals/record.fnk' {is_partial} = import '../partial/init.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' -{transform} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' @@ -59,38 +59,46 @@ match_props = fn props, emit_result, ctx, cond: 1 == length ?: emit_result else: - fn ctx: - match_props rest, emit_result, ctx, cond + fn ctx: match_props rest, emit_result, ctx, cond match_condition id, value, emit, ctx, cond match_obj = fn value, obj, emit_result, ctx, cond: - [...id_props] = pipe obj.exprs: - map prop: - id = ctx.unique_ident 'p' - {id, prop} - - decl = objectPattern list: - ... pipe id_props: - map {id, prop}: - match prop: - {left: {type: 'spread'}}: - restElement id - else: - [computed, key] = get_key prop, ctx - objectProperty key, id, computed - - ifStatement + [id_props, props_ctx] = pipe obj.exprs: + map_with_ctx ctx, fn prop, id_ctx: + [id, next_ctx] = unique_ident 'p', id_ctx + [{id, prop}, next_ctx] + + [props, result_ctx] = pipe id_props: + map_with_ctx props_ctx, fn {id, prop}, prop_ctx: + match prop: + {left: {type: 'spread'}}: + [(restElement id), prop_ctx] + else: + [computed, key, next_ctx] = get_key prop, prop_ctx + js = objectProperty key, id, computed + [js, next_ctx] + + decl = objectPattern props + + [result, end_ctx] = match id_props: + is_empty ?: + emit_result ctx + else: + [prop_match, next_ctx] = match_props + id_props, emit_result, result_ctx, cond + js = blockStatement list: + consts decl, value + prop_match + [js, next_ctx] + + js = ifStatement not_nullish value - match id_props: - is_empty ?: - emit_result ctx - else: - blockStatement list: - consts decl, value - match_props id_props, emit_result, ctx, cond + result + + [js, end_ctx] @@ -98,8 +106,10 @@ match_elems = fn elems, emit_result, ctx, cond: [{id, value}, ...rest] = elems emit = match elems: - 1 == length ?: emit_result - else: fn ctx: match_elems rest, emit_result, ctx, cond + 1 == length ?: + emit_result + else: + fn ctx: match_elems rest, emit_result, ctx, cond match_condition id, value, emit, ctx, cond @@ -142,12 +152,13 @@ get_array_decl = fn arr, id_elems, right, ctx: match_array = fn value, arr, emit_result, ctx, cond: - [...id_elems] = pipe arr.exprs: - map expr: - id = ctx.unique_ident 'a' - {id, value: expr} + [id_elems, elems_ctx] = pipe arr.exprs: + map_with_ctx ctx, fn expr, expr_ctx: + [id, next_ctx] = unique_ident 'a', expr_ctx + [{id, value: expr}, next_ctx] - [array_decl, next_ctx] = get_array_decl arr, id_elems, value, ctx + + [array_decl, result_ctx] = get_array_decl arr, id_elems, value, elems_ctx [...filtered_id_elems] = pipe id_elems: filter {value}: @@ -159,30 +170,33 @@ match_array = fn value, arr, emit_result, ctx, cond: {type: 'spread'}: false else: true - result = match id_elems: + [result, end_ctx] = match id_elems: is_empty ?: - emit_result next_ctx + emit_result result_ctx else: - blockStatement list: - array_decl - match_elems filtered_id_elems, emit_result, next_ctx, cond + [matched, next_ctx] = match_elems + filtered_id_elems, emit_result, result_ctx, cond + js = blockStatement [array_decl, matched] + [js, next_ctx] - ifStatement + js = ifStatement is_iterable value result + [js, end_ctx] match_simple = fn value, expr, emit_result, ctx: [cond, result_ctx] = comp value, expr, {...ctx, wrap: 'loc'} - result = emit_result result_ctx - ifStatement cond, result + [result, next_ctx] = emit_result result_ctx + js = ifStatement cond, result + [js, next_ctx] match_condition = fn value, expr, emit_result, ctx, cond: - js_expr = match expr: + [js_expr, next_ctx] = match expr: {type: 'rec'}: match_obj value, expr, emit_result, ctx, cond @@ -195,7 +209,8 @@ match_condition = fn value, expr, emit_result, ctx, cond: else: match_simple value, expr, emit_result, ctx - wrap_with_comment_loc js_expr, cond + js = wrap_with_comment_loc js_expr, cond + [js, next_ctx] @@ -205,18 +220,20 @@ split_condition = fn {left, right}: match_all = fn value, matches, emit, ctx: - exprs = pipe matches: - map expr: + [exprs, end_ctx] = pipe matches: + map_with_ctx ctx, fn expr, expr_ctx: match expr: {type: 'block', op: 'else'}: {op:_, ...block} = expr - js_expr = emit block, ctx - wrap_with_comment_loc js_expr, block + [js_expr, next_ctx] = emit block, expr_ctx + js = wrap_with_comment_loc js_expr, block + [js, next_ctx] else: [condition, result] = split_condition expr emit_result = fn ctx: emit result, ctx - match_condition value, condition, emit_result, ctx, condition - [exprs, ctx] + match_condition value, condition, emit_result, expr_ctx, condition + + [exprs, end_ctx] @@ -226,7 +243,7 @@ result_emitter = fn break_lbl: fn result, ctx: expressionStatement result_js breakStatement break_lbl - js # TODO [js, next_ctx] + [js, next_ctx] @@ -234,12 +251,12 @@ transform_match = fn node, ctx: {exprs} = node [inputs] = node.args - value = ctx.unique_ident 'value' - break_lbl = ctx.unique_ident 'match' + [value, match_ctx] = unique_ident 'value', ctx + [break_lbl, inputs_ctx] = unique_ident 'match', match_ctx emit_result = result_emitter break_lbl - [inputs_js, next_ctx] = transform inputs, ctx + [inputs_js, next_ctx] = transform inputs, inputs_ctx [match_exprs, end_ctx] = match_all value, exprs, emit_result, next_ctx js = doExpression diff --git a/src/lang/conditionals/match.test.fnk.snap b/src/lang/conditionals/match.test.fnk.snap index 7609fa7..f9a1a08 100644 --- a/src/lang/conditionals/match.test.fnk.snap +++ b/src/lang/conditionals/match.test.fnk.snap @@ -39,7 +39,6 @@ exports[`match compiles 1`] = ` // fallback if none of above match { - // fallback if none of above match shrub; break ˆmatch_2; } diff --git a/src/lang/context.fnk b/src/lang/context.fnk index 3a100fa..f899af6 100644 --- a/src/lang/context.fnk +++ b/src/lang/context.fnk @@ -1,3 +1,6 @@ +{get_type} = import '@fink/js-interop/reflect.fnk' + + any = false @@ -9,16 +12,19 @@ add = fn type, op, transformer: fn {transformers, ...ctx}: {transformers: next_transformers, ...ctx} -get_transformer = fn {op, type}, {transformers}: +is_fn = fn obj: + 'function' == get_type obj + +get_transformer = fn {op, type}, {transformers}: match transformers: - # TODO: why copy with spread instead of op in ? - op in {...?}: - transformers.(op) + {(op): is_fn ?}: + {(op): transform} = transformers + transform - # TODO: why copy with spread instead of op in ? - type in {...?}: - transformers.(type) + {(type): is_fn ?}: + {(type): transform} = transformers + transform else: false diff --git a/src/lang/errors.fnk b/src/lang/errors.fnk index def9831..042f6d1 100644 --- a/src/lang/errors.fnk +++ b/src/lang/errors.fnk @@ -1,22 +1,24 @@ {highlight_code_loc} = import '@fink/snippet/highlight.fnk' -{stack_trace} = import '@fink/std-lib/stack-trace.fnk' +{new, set_props} = import '@fink/js-interop/reflect.fnk' +{Error} = import '@fink/js-interop/globals.fnk' -transform_error = fn {message}, expr, {code, filename}: +transform_error = fn message, expr, ctx: + {code, filename} = ctx {start: {line, column}} = expr.loc type_op = '${expr.type} ${expr.op}' - error = dict: - error: ' - ${filename}:${line}:${column} - ${highlight_code_loc code, expr.loc} + # TODO: use std-lib/error.fnk + err = new Error, ' + ${filename}:${line}:${column} + ${highlight_code_loc code, expr.loc} - Unable to transform `${type_op}`. - ' - expr - message - stack: stack_trace transform_error + Unable to transform `${type_op}`. + + ${message} + ' + + set_props err, {transform_error: true} - error diff --git a/src/lang/func/init.fnk b/src/lang/func/init.fnk index 99c62ef..e647504 100644 --- a/src/lang/func/init.fnk +++ b/src/lang/func/init.fnk @@ -1,20 +1,18 @@ babel_types = import '@babel/types' {arrowFunctionExpression} = babel_types +{unique_ident} = import '../../js/types.fnk' {transform_left} = import '../../js/left.fnk' {add, any} = import '../context.fnk' {transform_block} = import '../block/init.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' transform_arg = fn arg, ctx: - {unique_ident} = ctx - match arg: {type: 'empty'}: - ident = unique_ident '' - [ident, ctx] + unique_ident '', ctx else: [t_arg, next_ctx] = transform arg, ctx js_arg = transform_left t_arg @@ -24,10 +22,7 @@ transform_arg = fn arg, ctx: transform_func = fn node, ctx: [params, next_ctx] = pipe node.args: - map arg, arg_ctx=ctx: - [js_arg, next_ctx] = transform_arg arg, arg_ctx - ([js_arg, next_ctx], next_ctx) - collect_with_ctx ctx + map_with_ctx ctx, transform_arg [body, end_ctx] = transform_block node, next_ctx js = arrowFunctionExpression params, body diff --git a/src/lang/init.fnk b/src/lang/init.fnk index 09e4e51..48bdc82 100644 --- a/src/lang/init.fnk +++ b/src/lang/init.fnk @@ -1,9 +1,3 @@ -{count} = import '@fink/std-lib/iter.fnk' - -{unique_ident} = import '../js/types.fnk' - -{transform} = import './transform.fnk' - {add_assignment} = import './assignment/init.fnk' {add_func} = import './func/init.fnk' {add_conditionals} = import './conditionals/init.fnk' @@ -25,6 +19,7 @@ {add_partial} = import './partial/init.fnk' + add_transformers = fn ctx: pipe ctx: add_module @@ -49,39 +44,17 @@ add_transformers = fn ctx: add_js_compat -init_ctx = fn code, filename: - id_cntr = count 1 +init_ctx = fn code, filename: ctx = dict: filename code errors: [] - unique_id: 0 + unique_id: 1 ident_prefix: 'ˆ' - unique_ident: fn name: - # console.log 'unique_ident', name - # TODO: return ident and new ctx to make it not stateful - {ident_prefix} = ctx - {value: unique_id} = id_cntr.next _ - [ident] = unique_ident name, {ident_prefix, unique_id} - ident - pipe ctx: add_transformers - -transform_ast = fn expr, code, filename, options: - ctx = init_ctx code, filename - [js_ast, end_ctx] = transform expr, {...ctx, options} - - # TODO: why can js_ast be an error, why not just use end_ctx? - match js_ast: - {error: {}}: - {errors: end_ctx.errors} - else: - {...js_ast, errors: []} - - diff --git a/src/lang/iterable/common.fnk b/src/lang/iterable/common.fnk index a6ac155..a45a42e 100644 --- a/src/lang/iterable/common.fnk +++ b/src/lang/iterable/common.fnk @@ -1,6 +1,6 @@ {length} = import '@fink/std-lib/iter.fnk' -{consts, yields, lets, assign} = import '../../js/types.fnk' +{consts, yields, lets, assign, unique_ident} = import '../../js/types.fnk' {exprs_block} = import '../block/init.fnk' {transform} = import '../transform.fnk' @@ -37,13 +37,12 @@ yield_expr = fn result, expr, ctx: get_accs = fn node, last_expr, ctx: - {unique_ident} = ctx [, acc_arg] = node.args match node.args: 2 == length ?: - acc = unique_ident 'accu' - [acc_init_value, init_ctx] = transform acc_arg.right, ctx + [acc, acc_init_ctx] = unique_ident 'accu', ctx + [acc_init_value, init_ctx] = transform acc_arg.right, acc_init_ctx acc_init = lets acc, acc_init_value [acc_assign, acc_ctx] = transform_init acc_arg.left, acc, init_ctx @@ -55,43 +54,41 @@ get_accs = fn node, last_expr, ctx: [[acc_init], [acc_assign], result_expr, [next_acc_assign], acc, next_ctx] else: - [[], [], last_expr, [], , ctx] + [[], [], last_expr, [], false, ctx] get_item = fn node, ctx: - {unique_ident} = ctx - [item_arg] = node.args - item = unique_ident 'item' + [item, init_ctx] = unique_ident 'item', ctx match item_arg: {type: 'empty'}: - [item, [], ctx] + [item, [], init_ctx] else: - [item_init, next_ctx] = transform_init item_arg, item, ctx + [item_init, next_ctx] = transform_init item_arg, item, init_ctx [item, [item_init], next_ctx] get_iter_helpers = fn node, ctx: - {unique_ident} = ctx - [item, item_init, acc_ctx] = get_item node, ctx # TODO move next line into get_accs? [...exprs, last_expr] = node.exprs - [acc_init, acc_assign, result_expr1, next_accu, accu, exprs_ctx] = get_accs + [acc_init, acc_assign, result_expr1, next_accu, accu, items_ctx] = get_accs node, last_expr, acc_ctx - items = unique_ident 'items' - result = unique_ident 'result' + [items, result_ctx] = unique_ident 'items', items_ctx + [result, exprs_ctx] = unique_ident 'result', result_ctx item_acc_assign = [...item_init, ...acc_assign] [result_expr, result_is_spread] = match result_expr1: - {type: 'spread'}: [result_expr1.right, true] - else: [result_expr1, false] + {type: 'spread'}: + [result_expr1.right, true] + else: + [result_expr1, false] [expressions, next_ctx] = pipe exprs: exprs_block ?, exprs_ctx diff --git a/src/lang/iterable/filter.fnk b/src/lang/iterable/filter.fnk index 65b4015..254b1d0 100644 --- a/src/lang/iterable/filter.fnk +++ b/src/lang/iterable/filter.fnk @@ -15,6 +15,7 @@ transform_filter = fn node, ctx: expressions result next_accu + next_ctx } = get_iter_helpers node, ctx name = ident 'filter', ctx @@ -33,4 +34,4 @@ transform_filter = fn node, ctx: ...next_accu - [js, ctx] \ No newline at end of file + [js, next_ctx] \ No newline at end of file diff --git a/src/lang/iterable/fold.fnk b/src/lang/iterable/fold.fnk index 449bf21..8d4d10f 100644 --- a/src/lang/iterable/fold.fnk +++ b/src/lang/iterable/fold.fnk @@ -1,4 +1,4 @@ -{assign, for_of, func, lets, undef} = import '../../js/types.fnk' +{assign, for_of, func, lets, undef, unique_ident} = import '../../js/types.fnk' {exprs_block} = import '../block/init.fnk' {transform} = import '../transform.fnk' {transform_init} = import './common.fnk' @@ -6,15 +6,13 @@ get_acc = fn acc_arg, ctx: - {unique_ident} = ctx - - acc = unique_ident 'accu' + [acc, init_ctx] = unique_ident 'accu', ctx [acc_init, acc_ctx] = match acc_arg: {}: - transform acc_arg.right, ctx + transform acc_arg.right, init_ctx else: - [(undef _), ctx] + [(undef _), init_ctx] [acc_assign, next_ctx] = match acc_arg: {}: @@ -28,16 +26,14 @@ get_acc = fn acc_arg, ctx: transform_fold = fn node, ctx: - {unique_ident} = ctx - [item_arg, acc_arg] = node.args [...expressions, last_expr] = node.exprs - item = unique_ident 'item' - [item_init, acc_ctx] = transform_init item_arg, item, ctx - [acc, acc_init, acc_assign, block_ctx] = get_acc acc_arg, acc_ctx + [item, init_ctx] = unique_ident 'item', ctx + [item_init, acc_ctx] = transform_init item_arg, item, init_ctx + [acc, acc_init, acc_assign, items_ctx] = get_acc acc_arg, acc_ctx - items = unique_ident 'items' + [items, block_ctx] = unique_ident 'items', items_ctx [body, result_ctx] = exprs_block expressions, block_ctx [result, end_ctx] = transform last_expr, result_ctx diff --git a/src/lang/iterable/map.fnk b/src/lang/iterable/map.fnk index bbbb082..e50ff6a 100644 --- a/src/lang/iterable/map.fnk +++ b/src/lang/iterable/map.fnk @@ -12,6 +12,7 @@ transform_map = fn node, ctx: expressions result, result_is_spread next_accu + next_ctx } = get_iter_helpers node, ctx name = ident 'map', ctx @@ -21,13 +22,8 @@ transform_map = fn node, ctx: for_of [item, items], ...item_acc_assign - ...expressions - - yields - result - result_is_spread - + yields result, result_is_spread ...next_accu - [js, ctx] \ No newline at end of file + [js, next_ctx] \ No newline at end of file diff --git a/src/lang/iterable/map.test.fnk b/src/lang/iterable/map.test.fnk index ede11e6..a5526b9 100644 --- a/src/lang/iterable/map.test.fnk +++ b/src/lang/iterable/map.test.fnk @@ -1,6 +1,7 @@ -{fink2js} = import '../../testing/generate.fnk' {describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' + describe 'map', fn: it 'compiles single line', fn: diff --git a/src/lang/iterable/unfold.fnk b/src/lang/iterable/unfold.fnk index ae271ed..b4e9695 100644 --- a/src/lang/iterable/unfold.fnk +++ b/src/lang/iterable/unfold.fnk @@ -3,7 +3,7 @@ babel_types = import '@babel/types' {is_empty} = import '@fink/std-lib/iter.fnk' -{assign, generator, true_, lets, ident} = import '../../js/types.fnk' +{assign, generator, true_, lets, ident, unique_ident} = import '../../js/types.fnk' {exprs_block} = import '../block/init.fnk' {transform_init, yield_expr} = import './common.fnk' @@ -19,18 +19,16 @@ loop = fn ...body: get_acc_exprs = fn node, next_value, ctx: - {unique_ident} = ctx - - initial = unique_ident 'initial' - acc = unique_ident 'accu' + [initial, acc_ctx] = unique_ident 'initial', ctx + [acc, acc_init_ctx] = unique_ident 'accu', acc_ctx [acc_arg] = node.args; [acc_left, acc_right, init_ctx] = match acc_arg: {type: 'assign'}: - [right, next_ctx] = transform acc_arg.right, ctx + [right, next_ctx] = transform acc_arg.right, acc_init_ctx [acc_arg.left, right, next_ctx] else: - [acc_arg, initial, ctx] + [acc_arg, initial, acc_init_ctx] acc_init = lets acc, acc_right @@ -61,14 +59,13 @@ get_result = fn result_id, expr, ctx: transform_unfold = fn node, ctx: - {unique_ident} = ctx [...expressions, last_expr] = node.exprs - result_id = unique_ident 'result' + [result_id, result_ctx] = unique_ident 'result', ctx - [result_expr, next_accu, acc_ctx] = get_result result_id, last_expr, ctx + [result_expr, next_accu, acc_ctx] = get_result result_id, last_expr, result_ctx [initial, acc_init, acc_assign, acc_result, block_ctx] = get_accs node, next_accu, acc_ctx - name = ident 'unfold', ctx + name = ident 'unfold', block_ctx [body, yield_ctx] = exprs_block expressions, block_ctx [yield_result, end_ctx] = yield_expr result_id, result_expr, yield_ctx @@ -80,4 +77,4 @@ transform_unfold = fn node, ctx: ...yield_result ...acc_result - [js, end_ctx] \ No newline at end of file + [js, end_ctx] diff --git a/src/lang/iterable/until.fnk b/src/lang/iterable/until.fnk index b3f7064..e181a7d 100644 --- a/src/lang/iterable/until.fnk +++ b/src/lang/iterable/until.fnk @@ -15,9 +15,10 @@ transform_until = fn node, ctx: expressions result next_accu + next_ctx } = get_iter_helpers node, ctx - name = ident 'filter_until', ctx + name = ident 'filter_until', next_ctx js = generator name, [items], ...acc_init @@ -36,6 +37,4 @@ transform_until = fn node, ctx: ...next_accu - [js, ctx] - - + [js, next_ctx] diff --git a/src/lang/iterable/while.fnk b/src/lang/iterable/while.fnk index 34ae88b..8d09e81 100644 --- a/src/lang/iterable/while.fnk +++ b/src/lang/iterable/while.fnk @@ -15,9 +15,10 @@ transform_while = fn node, ctx: expressions result next_accu + next_ctx } = get_iter_helpers node, ctx - name = ident 'filter_while', ctx + name = ident 'filter_while', next_ctx js = generator name, [items], ...acc_init @@ -35,4 +36,4 @@ transform_while = fn node, ctx: ...next_accu - [js, ctx] \ No newline at end of file + [js, next_ctx] \ No newline at end of file diff --git a/src/lang/js-compat/try.fnk b/src/lang/js-compat/try.fnk index 210cc49..e657ab5 100644 --- a/src/lang/js-compat/try.fnk +++ b/src/lang/js-compat/try.fnk @@ -4,21 +4,21 @@ babel_types = import '@babel/types' expressionStatement, doExpression, isDoExpression } = babel_types -{false_} = import '../../js/types.fnk' +{false_, unique_ident} = import '../../js/types.fnk' {transform_block} = import '../block/init.fnk' transform_try = fn node, ctx: - [block, end_ctx] = transform_block node, ctx + [block, next_ctx] = transform_block node, ctx body = match block: isDoExpression ?: block.body.body else: [block] [...expressions, last_expr] = body - err = ctx.unique_ident 'error' + [err, end_ctx] = unique_ident 'error', next_ctx try_block = blockStatement list: ...expressions diff --git a/src/lang/jsx/init.fnk b/src/lang/jsx/init.fnk index 5dfe262..4de10dc 100644 --- a/src/lang/jsx/init.fnk +++ b/src/lang/jsx/init.fnk @@ -8,37 +8,25 @@ babel_types = import '@babel/types' {length} = import '@fink/std-lib/iter.fnk' {add, any} = import '../context.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' - - - -transform_exprs = fn exprs, ctx: - pipe exprs: - map expr, expr_ctx=ctx: - [result, next_ctx] = transform expr, expr_ctx - ([result, next_ctx], next_ctx) - collect_with_ctx ctx +{transform, map_with_ctx} = import '../transform.fnk' transform_jsx_elem = fn node, ctx: id = jsxIdentifier node.name - # TODO: use transform_exprs with extra mapping func [attrs, children_ctx] = pipe node.props: - map expr, expr_ctx= ctx: - [attr, next_ctx] = match expr: + map_with_ctx ctx, fn expr, expr_ctx: + match expr: {type: 'spread'}: [attr, next_ctx] = transform expr.right, expr_ctx spread = jsxSpreadAttribute attr [spread, next_ctx] else: transform expr, expr_ctx - ([attr, next_ctx], next_ctx) - - collect_with_ctx ctx - [children, next_ctx] = transform_exprs node.children, children_ctx + [children, next_ctx] = pipe node.children: + map_with_ctx children_ctx, transform js = jsxElement jsxOpeningElement id, attrs, node.self_closing @@ -50,7 +38,8 @@ transform_jsx_elem = fn node, ctx: transform_jsx_frag = fn node, ctx: - [children, next_ctx] = transform_exprs node.children, ctx + [children, next_ctx] = pipe node.children: + map_with_ctx ctx, transform js = jsxFragment jsxOpeningFragment _ diff --git a/src/lang/literals/list.fnk b/src/lang/literals/list.fnk index b9089ee..fdee5e1 100644 --- a/src/lang/literals/list.fnk +++ b/src/lang/literals/list.fnk @@ -2,21 +2,18 @@ babel_types = import '@babel/types' {arrayExpression} = babel_types {null} = import '@fink/js-interop/nullish.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' transform_list = fn node, ctx: [elems, next_ctx] = pipe node.exprs: - map elem, elem_ctx=ctx: - [js, next_ctx] = match elem: + map_with_ctx ctx, fn elem, elem_ctx: + match elem: {type: 'empty'}: [null, ctx] else: transform elem, elem_ctx - ([js, next_ctx], next_ctx) - collect_with_ctx ctx - js = arrayExpression elems [js, next_ctx] diff --git a/src/lang/literals/record.fnk b/src/lang/literals/record.fnk index 09c6d26..4db9906 100644 --- a/src/lang/literals/record.fnk +++ b/src/lang/literals/record.fnk @@ -1,23 +1,19 @@ babel_types = import '@babel/types' {objectExpression, objectProperty, assignmentPattern} = babel_types -{raw_str} = import '../../js/types.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{raw_str, unique_ident} = import '../../js/types.fnk' +{transform, map_with_ctx} = import '../transform.fnk' transform_record = fn node, ctx: [props, next_ctx] = pipe node.exprs: - map key_value, prop_ctx=ctx: - [prop, next_ctx] = transform key_value, prop_ctx - ([prop, next_ctx], next_ctx) - - collect_with_ctx ctx + map_with_ctx ctx, transform js = objectExpression props - [js, next_ctx] + str_key = fn {value, loc}, ctx: str = raw_str value [{...str, loc}, ctx] @@ -38,8 +34,7 @@ get_key = fn {left: key}, ctx: get_value = fn {right}, ctx: match right: {type: 'empty'}: - ident = ctx.unique_ident 'unused' - [ident, ctx] + unique_ident 'unused', ctx else: transform right, ctx diff --git a/src/lang/literals/string.fnk b/src/lang/literals/string.fnk index b202bd1..17fda2e 100644 --- a/src/lang/literals/string.fnk +++ b/src/lang/literals/string.fnk @@ -2,7 +2,7 @@ babel_types = import '@babel/types' {templateElement, templateLiteral, taggedTemplateExpression} = babel_types {rx, replace_all} = import '@fink/std-lib/regex.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' @@ -14,7 +14,9 @@ transform_string = fn node, ctx: {exprs: parts, tag=not_tagged} = node [...quasies] = pipe parts: - filter part: part.type == 'string:text' + filter part: + part.type == 'string:text' + map part: templateElement dict: raw: replace_all @@ -26,11 +28,8 @@ transform_string = fn node, ctx: filter part: part.type != 'string:text' - map part, part_ctx=ctx: - [js, next_ctx] = transform part, part_ctx - ([js, next_ctx], next_ctx) + map_with_ctx ctx, transform - collect_with_ctx ctx templ_str = templateLiteral quasies, expressions diff --git a/src/lang/module/init.fnk b/src/lang/module/init.fnk index c28f024..3b38c17 100644 --- a/src/lang/module/init.fnk +++ b/src/lang/module/init.fnk @@ -9,14 +9,14 @@ babel_types = import '@babel/types' {add, any} = import '../context.fnk' {wrap_with_comment_loc} = import '../comments/init.fnk' {block_statement} = import '../block/init.fnk' -{transform, collect_with_ctx} = import '../transform.fnk' +{transform, map_with_ctx} = import '../transform.fnk' {transform_import: transform_async_import, resolve_ext} = import './import.fnk' # TODO should larix handle shebang as special expr? -get_shebang = fn expr: +get_hashbang = fn expr: {comments} = expr match comments: {leading: [{op: '#', loc: {start: {line: 1}}, value: starts_with ?, '!'}]}: @@ -38,10 +38,10 @@ transform_import = fn node, ctx: {type: 'rec'}: pipe node.left.exprs: - map prop, imp_ctx=ctx: + map_with_ctx ctx, fn prop, imp_ctx: [right, left_ctx] = transform prop.right, imp_ctx - [imp, next_ctx] = match prop: + match prop: {left: {value: 'default'}}: imp = importSpecifier right, identifier prop.left.value [imp, left_ctx] @@ -51,10 +51,6 @@ transform_import = fn node, ctx: imp = importSpecifier right, left [imp, next_ctx] - ([imp, next_ctx], next_ctx) - - collect_with_ctx ctx - {right: {right: {exprs: [url]}}} = node js = importDeclaration @@ -69,12 +65,11 @@ transform_import = fn node, ctx: transform_module = fn node, ctx: [maybe_shebang, ...rest] = node.exprs - [interpreter, first] = get_shebang maybe_shebang + [interpreter, first] = get_hashbang maybe_shebang [body, end_ctx] = pipe [first, ...rest]: - map expr, expr_ctx=ctx: - - [js, next_ctx] = match expr: + map_with_ctx ctx, fn expr, expr_ctx: + match expr: {op: 'import'}: {right: {exprs: [url]}} = expr js = wrap_with_comment_loc @@ -107,11 +102,6 @@ transform_module = fn node, ctx: else: block_statement expr, expr_ctx - ([js, next_ctx], next_ctx) - - collect_with_ctx ctx - - js = file program body diff --git a/src/lang/transform.fnk b/src/lang/transform.fnk index 4ce347b..b24237f 100644 --- a/src/lang/transform.fnk +++ b/src/lang/transform.fnk @@ -1,5 +1,3 @@ -{stack_trace} = import '@fink/std-lib/stack-trace.js' - {wrap} = import '../js/types.fnk' {transform_error} = import './errors.fnk' @@ -24,45 +22,38 @@ collect_with_ctx = fn ctx: fn expr_ctx_items: -try_transform = fn transform, node, ctx: - [err, result] = try: transform node, ctx +map_with_ctx = fn ctx, tf: fn items: + pipe items: + map item, item_ctx=ctx: + [result, next_ctx] = tf item, item_ctx + ([result, next_ctx], next_ctx) - match err: - false: - result - else: - transform_error err, node, ctx + collect_with_ctx ctx -transform_with_comments = fn transform, node, ctx: +transform_with_comments = fn transform_expr, node, ctx: [err, result] = try: - transform node, ctx + transform_expr node, ctx match err: false: [js_node, next_ctx] = result js = wrap_node next_ctx, js_node, node [js, next_ctx] + {transform_error: {}}: + throw err else: - xform_error = transform_error err, node, ctx - # TODO don't use mutable - ctx.errors.push xform_error - # TODO: don't return error? - [xform_error, {...ctx, errors: [...ctx.errors, xform_error]}] - + throw transform_error err, node, ctx transform = fn node, ctx: - transform = get_transformer node, ctx + transform_expr = get_transformer node, ctx - [js, next_ctx] = match transform: + match transform_expr: false: - err = transform_error 'Unknown expression.', node, ctx - # TODO: don't return err as ast - [err, {...ctx, errors: [...ctx.errors, err]}] + throw transform_error 'Unknown expression.', node, ctx else: - transform_with_comments transform, node, ctx + transform_with_comments transform_expr, node, ctx - [js, next_ctx]