diff --git a/src/generate.test.fnk.snap b/src/generate.test.fnk.snap index 5301c36..bdb9087 100644 --- a/src/generate.test.fnk.snap +++ b/src/generate.test.fnk.snap @@ -45,33 +45,31 @@ export default ni_0;" `; exports[`source maps compiles to mjs 1`] = ` -"const nanu_0 = 345; -const foo_0 = { +"const foo_0 = { bar: 12345, - \\"spam ni\\": nanu_0, - nanu: nanu_0 + \\"spam ni\\": 345, + nanu: 345 }; const bar_0 = \`foo\`; const ham_0 = \`foo: \${foo_0} bar:\${bar_0}\`; -const el_0 = bar {123}
; +const el_0 = bar {123}
; const ni_0 = spam + fooᜭbar; -const item_1 = 1; const item_0 = \`ni\`; -const a_0 = [item_1, item_0]; -const out_0 = [a_0, item_1, item_0]; +const a_0 = [1, item_0]; +const out_0 = [a_0, 1, item_0]; const func_0 = (x_0, y_0) => { - return x_0 + y_0 + item_1; + return x_0 + y_0 + 1; }; -const y_1 = func_0(bar_0, a_0, item_1); +const y_1 = func_0(bar_0, a_0, 1); spam(ham_0); const r1_0 = { foo: foo_0, bar: bar_0, spam: 123 }; -export const nanu = nanu_0, +export const nanu = 345, foo = foo_0, bar = bar_0, ham = ham_0, @@ -88,9 +86,9 @@ export const nanu = nanu_0, \\"test.fnk\\" ], \\"names\\": [ - \\"nanu\\", \\"foo\\", \\"bar\\", + \\"nanu\\", \\"ham\\", \\"el\\", \\"div\\", @@ -106,7 +104,7 @@ export const nanu = nanu_0, \\"y\\", \\"r1\\" ], - \\"mappings\\": \\"AAAAA,MAAAA,MAAI,GAAG,GAAPA;AACAC,MAAAA,KAAG,GAAiC;AAA7BC,EAAAA,GAA6B,EAAxB,KAAwB;AAAjB,WAAiB,EAANF,MAAM;AAAAA,EAAAA,IAAI,EAAJA;AAAA,CAApCC;AACAC,MAAAA,KAAG,GAAI,KAAPA;AACAC,MAAAA,KAAG,GAAI,QAAOF,KAAI,QAAOC,KAAG,EAA5BC;AACAC,MAAAA,IAAE,GAAG,KAAK,IAAI,KAAK,CAAC,CAACC,GAAD,CAAKJ,GAAL,CAAS,KAAT,CAAaC,GAAb,CAAaA,CAAAA,KAAG,CAAhB,CAAiBI,IAAjB,CAAsBN,CAAAA,MAAI,CAA1B,GAAf,MAALI;AACAG,MAAAA,IAAE,GAAGD,IAAI,GAAGE,OAAZD;AACK,MAAA,MAAC,GAAD;AAAG,MAAA,MAAI,GAAH,IAAD;AAARE,MAAAA,GAAC,GAAO,CAAH,MAAG,EAAA,MAAI,CAAZA;AAEAC,MAAAA,KAAG,GAAUC,CAANF,GAAME,EAAHC,MAAGD,EAAAA,MAAC,CAAdD;;AACAG,MAAAA,MAAI,GAAG,CAAGC,GAAH,EAAMC,GAAN;AACL,SAAAD,GAAC,GAAGC,GAAJ,GAAQH,MAAR;AADK,CAAPC;;AAEAE,MAAAA,GAAC,GAAGF,MAAI,CAACX,KAAD,EAAMO,GAAN,EAASG,MAAT,CAARG;AACAT,IAAI,CAACH,KAAD,CAAJ;AACAa,MAAAA,IAAE,GAAc;AAAVf,EAAAA,GAAU,EAAVA,KAAU;AAALC,EAAAA,GAAK,EAALA,KAAK;AAAAI,EAAAA,IAAI,EAAE;AAAN,CAAhBU;aAbAhB,IAAI,GAAJA,M;MACAC,GAAG,GAAHA,K;MACAC,GAAG,GAAHA,K;MACAC,GAAG,GAAHA,K;MACAC,EAAE,GAAFA,I;MACAG,EAAE,GAAFA,I;MACAE,CAAC,GAADA,G;MAEAC,GAAG,GAAHA,K;MACAG,IAAI,GAAJA,M;MAEAE,CAAC,GAADA,G;MAEAC,EAAE,GAAFA,I\\" + \\"mappings\\": \\"AACAA,MAAAA,KAAG,GAAiC;AAA7BC,EAAAA,GAA6B,EAAxB,KAAwB;AAAjB,WAAiB,EAANC,GAAM;AAAAA,EAAAA,IAAI,EAAJA;AAAA,CAApCF;AACAC,MAAAA,KAAG,GAAI,KAAPA;AACAE,MAAAA,KAAG,GAAI,QAAOH,KAAI,QAAOC,KAAG,EAA5BE;AACAC,MAAAA,IAAE,GAAG,KAAK,IAAI,KAAK,CAAC,CAACC,GAAD,CAAKL,GAAL,CAAS,KAAT,CAAaC,GAAb,CAAaA,CAAAA,KAAG,CAAhB,CAAiBK,IAAjB,CAAsBJ,KAAtB,GAAf,MAALE;AACAG,MAAAA,IAAE,GAAGD,IAAI,GAAGE,OAAZD;AACQ,MAAA,MAAI,GAAH,IAAD;AAARE,MAAAA,GAAC,GAAO,CAAH,CAAG,EAAA,MAAI,CAAZA;AAEAC,MAAAA,KAAG,GAAUC,CAANF,GAAME,EAAHC,CAAGD,EAAAA,MAAC,CAAdD;;AACAG,MAAAA,MAAI,GAAG,CAAGC,GAAH,EAAMC,GAAN;AACL,SAAAD,GAAC,GAAGC,GAAJ,GAAQH,CAAR;AADK,CAAPC;;AAEAE,MAAAA,GAAC,GAAGF,MAAI,CAACZ,KAAD,EAAMQ,GAAN,EAASG,CAAT,CAARG;AACAT,IAAI,CAACH,KAAD,CAAJ;AACAa,MAAAA,IAAE,GAAc;AAAVhB,EAAAA,GAAU,EAAVA,KAAU;AAALC,EAAAA,GAAK,EAALA,KAAK;AAAAK,EAAAA,IAAI,EAAE;AAAN,CAAhBU;aAbAd,IAAI,GAAJA,G;MACAF,GAAG,GAAHA,K;MACAC,GAAG,GAAHA,K;MACAE,GAAG,GAAHA,K;MACAC,EAAE,GAAFA,I;MACAG,EAAE,GAAFA,I;MACAE,CAAC,GAADA,G;MAEAC,GAAG,GAAHA,K;MACAG,IAAI,GAAJA,M;MAEAE,CAAC,GAADA,G;MAEAC,EAAE,GAAFA,I\\" } " `; diff --git a/src/ir/block/init.fnk b/src/ir/block/init.fnk index 10b3fc2..d312b69 100644 --- a/src/ir/block/init.fnk +++ b/src/ir/block/init.fnk @@ -16,7 +16,11 @@ transform_exprs = fn [expr, ...exprs], res_id, ctx, out=[]: transform_block = fn expr, res_id, ctx: - transform_exprs expr.exprs, res_id, ctx + {scopes} = ctx + block_ctx = {...ctx, scopes: [{}, ...scopes]} + [out, next_ctx] = transform_exprs expr.exprs, res_id, block_ctx + [out, {...next_ctx, scopes}] + add_block = fn ctx: diff --git a/src/ir/conditionals/match.fnk b/src/ir/conditionals/match.fnk index 07af853..0e67a52 100644 --- a/src/ir/conditionals/match.fnk +++ b/src/ir/conditionals/match.fnk @@ -227,9 +227,12 @@ match_expr = fn val, expr, gen_true, else_id, ctx: match_res_exprs = fn exprs, name, ret_id, {loc}, ctx: - [block, res_id, ret_ctx] = transform_exprs exprs, ctx, [] + {scopes} = ctx + cond_ctx = {...ctx, scopes: [{}, ...scopes]} + [block, res_id, ret_ctx] = transform_exprs exprs, cond_ctx, [] [ret, , next_ctx] = cc ret_id, res_id, , {loc}, ret_ctx - cn [], [...block, ...ret], name, {loc}, next_ctx + [a, b, todo] = cn [], [...block, ...ret], name, {loc}, next_ctx + [a, b, {...todo, scopes}] diff --git a/src/ir/literals/list.test.fnk b/src/ir/literals/list.test.fnk index 29fca3f..44917bf 100644 --- a/src/ir/literals/list.test.fnk +++ b/src/ir/literals/list.test.fnk @@ -1,5 +1,5 @@ -{fink2lir, fink2js} = import '../../testing/generate.fnk' {skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2lir, fink2js} = import '../../testing/generate.fnk' describe 'list', fn: @@ -124,3 +124,13 @@ describe 'optimizations', fn: spam = [foo, ...ham] ', {optimize: {refs: true, tails: true, unused: true}} to_match_snapshot + + + it 'removes tails', fn: + expect + fink2lir ' + [bar, spam, ham] = [...shrub] + ni = bar + spam + ham + ', {optimize: {refs: true, tails: true, unused: true}} + to_match_snapshot + diff --git a/src/ir/literals/list.test.fnk.snap b/src/ir/literals/list.test.fnk.snap index 73eaf4d..f34cd62 100644 --- a/src/ir/literals/list.test.fnk.snap +++ b/src/ir/literals/list.test.fnk.snap @@ -87,53 +87,58 @@ rec_e fn exports_0: exports[`optimizations ignores empty concats 1`] = ` " rec_e fn exports_0: - lst_e fn lst_0: + tpl, fn lst_0: lst_c lst_0, b, fn foo_0: str 'foo', fn key_0: rec_s exports_0, key_0, foo_0, fn exports_1: - lst_e fn ham_0: + tpl, fn ham_0: str 'ham', fn key_1: rec_s exports_1, key_1, ham_0, fn exports_2: - lst_e fn lst_2: - lst_a lst_2, foo_0, fn lst_1: - str 'spam', fn key_2: - rec_s exports_2, key_2, lst_1, fn exports_3: - lst_e fn drctvs_0: - mod exports_3, drctvs_0, fn mod_0:" + tpl foo_0, fn spam_0: + str 'spam', fn key_2: + rec_s exports_2, key_2, spam_0, fn exports_3: + tpl, fn drctvs_0: + mod exports_3, drctvs_0, fn mod_0:" `; exports[`optimizations optimizes spreads 1`] = ` "const y_0 = [1, 2]; -const item_4 = 1; -log(item_4, y_0, lala, lala, [item_4, 2], 3); +log(1, y_0, lala, lala, [1, 2], 3); export const y = y_0;" `; +exports[`optimizations removes tails 1`] = ` +" +rec_e fn exports_0: + tpl, fn lst_0: + lst_c lst_0, shrub, fn dlst_0: + tpl_i dlst_0, 0, fn bar_0: + tpl_i dlst_0, 1, fn spam_0: + tpl_i dlst_0, 2, fn ham_0: + add bar_0, spam_0, fn left_0: + add left_0, ham_0, fn ni_0: + str 'ni', fn key_0: + rec_s exports_0, key_0, ni_0, fn exports_1: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" +`; + exports[`optimizations reuses item refs 1`] = ` " rec_e fn exports_0: int '1', fn item_3: int '2', fn item_2: int '3', fn item_1: - lst_e fn lst_5: - lst_a lst_5, item_2, fn lst_4: - lst_a lst_4, item_3, fn foo_0: - str 'foo', fn key_0: - rec_s exports_0, key_0, foo_0, fn exports_1: - int '1', fn left_1: - int '2', fn right_1: - add left_1, right_1, fn item_7: - lst_e fn cargs_0: - lst_a cargs_0, item_3, fn cargs_1: - lst_a cargs_1, item_2, fn cargs_2: - lst_a cargs_2, item_1, fn cargs_3: - lst_a cargs_3, foo_0, fn cargs_4: - lst_a cargs_4, item_7, fn cargs_5: - lst_a cargs_5, item_2, fn cargs_6: - lst_a cargs_6, item_3, fn cargs_7: - af log, cargs_7, fn mex_3: - lst_e fn drctvs_0: - mod exports_1, drctvs_0, fn mod_0:" + tpl item_2, item_3, fn foo_0: + str 'foo', fn key_0: + rec_s exports_0, key_0, foo_0, fn exports_1: + int '1', fn left_1: + int '2', fn right_1: + add left_1, right_1, fn item_7: + tpl item_3, item_2, item_1, foo_0, item_7, item_2, item_3, fn cargs_7: + af log, cargs_7, fn mex_3: + tpl, fn drctvs_0: + mod exports_1, drctvs_0, fn mod_0:" `; exports[`unpacking list destructures recs 1`] = ` diff --git a/src/ir/literals/record.test.fnk.snap b/src/ir/literals/record.test.fnk.snap index 8b57304..e559676 100644 --- a/src/ir/literals/record.test.fnk.snap +++ b/src/ir/literals/record.test.fnk.snap @@ -12,7 +12,7 @@ rec_e fn exports_0: rec_s rec_0, key_0, foo-bar, fn foo_0: str 'foo', fn key_3: rec_s exports_0, key_3, foo_0, fn exports_1: - lst_e fn drctvs_0: + tpl, fn drctvs_0: mod exports_1, drctvs_0, fn mod_0:" `; diff --git a/src/ir/serialize.fnk b/src/ir/serialize.fnk index 685c63f..e924a78 100644 --- a/src/ir/serialize.fnk +++ b/src/ir/serialize.fnk @@ -8,7 +8,10 @@ a2s = fn [arg=false, ...args], out=[]: false: match out: [?]: ' ${out | join ', '}' else: '' - else: a2s args, [...out, arg.i] + {i: ?}: + a2s args, [...out, arg.i] + else: + a2s args, [...out, arg] diff --git a/src/js/assignment/init.test.fnk.snap b/src/js/assignment/init.test.fnk.snap index 1015201..89ea345 100644 --- a/src/js/assignment/init.test.fnk.snap +++ b/src/js/assignment/init.test.fnk.snap @@ -1,12 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`assignment compiles 1`] = ` -"const assign_0 = 1; -const no_clash_with_await_0 = 13; -const multi_line_assign_0 = 123 + 234 + (-567 - 1111); -export const assign = assign_0, - assign2 = assign_0, - no_clash_with_await = no_clash_with_await_0, +"const multi_line_assign_0 = 123 + 234 + (-567 - 1111); +export const assign = 1, + assign2 = 1, + no_clash_with_await = 13, assign_lang_const1 = true, assign_lang_const2 = false, multi_line_assign = multi_line_assign_0, diff --git a/src/js/conditionals/init.fnk b/src/js/conditionals/init.fnk index 83b6eee..ecd4f42 100644 --- a/src/js/conditionals/init.fnk +++ b/src/js/conditionals/init.fnk @@ -48,6 +48,7 @@ transform_is_rec = fn expr, ctx: set_js2 expr, js, ctx + transform_is_lst = fn expr, ctx: [{args: [val_id]}] = expr val = get_js val_id, ctx diff --git a/src/js/conditionals/match.test.fnk b/src/js/conditionals/match.test.fnk index 349656b..f3faf16 100644 --- a/src/js/conditionals/match.test.fnk +++ b/src/js/conditionals/match.test.fnk @@ -121,6 +121,20 @@ describe 'match', fn: to_match_snapshot + it 'handles scoping', fn: + expect + fink2js ' + foo = nanu + + test = fn foo, bar: + match foo: + bar: + foo + spam: + foo = bar * 2 + [foo, bar, foo] + ' + to_match_snapshot describe 'match iterables', fn: it 'matches values', fn: diff --git a/src/js/conditionals/match.test.fnk.snap b/src/js/conditionals/match.test.fnk.snap index ad6b658..994f757 100644 --- a/src/js/conditionals/match.test.fnk.snap +++ b/src/js/conditionals/match.test.fnk.snap @@ -6,8 +6,7 @@ exports[`match compiles match with ref 1`] = ` ret_0: { /* istanbul ignore else */ if (foo === 1) { - const x_0 = 123; - ret_0 = [1, x_0, x_0]; + ret_0 = [1, 123, 123]; /* istanbul ignore next */ break ret_0; @@ -37,8 +36,7 @@ exports[`match compiles match with ref 2`] = ` ret_0: { /* istanbul ignore else */ if (foo === 1) { - const x_0 = 123; - ret_0 = [1, x_0, x_0]; + ret_0 = [1, 123, 123]; /* istanbul ignore next */ break ret_0; @@ -46,8 +44,7 @@ ret_0: { /* istanbul ignore else */ if (foo === 2) { - const y_0 = 45678; - ret_0 = [2, foo, y_0, y_0]; + ret_0 = [2, foo, 45678, 45678]; /* istanbul ignore next */ break ret_0; @@ -69,8 +66,7 @@ exports[`match compiles match with ref 3`] = ` ret_0: { /* istanbul ignore else */ if (foo === 1) { - const x_0 = 123; - ret_0 = [1, x_0, x_0]; + ret_0 = [1, 123, 123]; /* istanbul ignore next */ break ret_0; @@ -78,15 +74,13 @@ ret_0: { /* istanbul ignore else */ if (foo === 2) { - const y_0 = 45678; - ret_0 = [2, foo, y_0, y_0]; + ret_0 = [2, foo, 45678, 45678]; /* istanbul ignore next */ break ret_0; } - const z_0 = 1234; - ret_0 = [3, foo, z_0, z_0]; + ret_0 = [3, foo, 1234, 1234]; /* istanbul ignore next */ break ret_0; @@ -102,8 +96,7 @@ exports[`match compiles match with ref 4`] = ` ret_0: { /* istanbul ignore else */ if (foo === 1) { - const x_0 = 123; - ret_0 = [1, x_0, x_0]; + ret_0 = [1, 123, 123]; /* istanbul ignore next */ break ret_0; @@ -117,8 +110,7 @@ ret_0: { break ret_0; } - const z_0 = 1234; - ret_0 = [3, foo, z_0, z_0]; + ret_0 = [3, foo, 1234, 1234]; /* istanbul ignore next */ break ret_0; @@ -171,6 +163,27 @@ ret_0: { const mex_0 = ret_0;" `; +exports[`match handles scoping 1`] = ` +"const test_0 = (foo_1, bar_0) => { + /* istanbul ignore else */ + if (foo_1 === bar_0) { + return foo_1; + } + + /* istanbul ignore else */ + if (foo_1 === spam) { + const foo_2 = bar_0 * 2; + return [foo_2, bar_0, foo_2]; + } + + /* istanbul ignore next */ + return; +}; + +export const foo = nanu, + test = test_0;" +`; + exports[`match iterables handles non iterables 1`] = ` "import { _in_ } from \\"@fink/js-interop/runtime.js\\"; const hdm_0 = args[0]; @@ -231,7 +244,7 @@ ret_0: { /* istanbul ignore else */ if (shrub[0] === 1) { /* istanbul ignore else */ - if ([...shrub.slice(1)].reverse()[0] === 3) { + if (shrub.at(-1) === 3) { ret_0 = foo; /* istanbul ignore next */ @@ -243,7 +256,7 @@ ret_0: { /* istanbul ignore else */ if (null != shrub) { /* istanbul ignore else */ - if ([...shrub].reverse()[0] === 4) { + if (shrub.at(-1) === 4) { ret_0 = foo; /* istanbul ignore next */ @@ -255,10 +268,8 @@ ret_0: { if (null != shrub) { /* istanbul ignore else */ if (shrub[0] === 5) { - const tail_0 = shrub.slice(1); - /* istanbul ignore else */ - if (null != tail_0) { + if (null != shrub.slice(1)) { /* istanbul ignore else */ if (shrub[1] === 6) { /* istanbul ignore else */ @@ -410,8 +421,6 @@ ret_0: { if (null != shrub) { /* istanbul ignore else */ if (shrub[0] === 1) { - const tail_15 = shrub.slice(1); - /* istanbul ignore else */ if (shrub[1] === 2) { const itm_17 = shrub[2]; @@ -434,7 +443,6 @@ ret_0: { if (null != shrub) { /* istanbul ignore else */ if (shrub[0] === 1) { - const tail_10 = shrub.slice(1); const itm_11 = shrub[1]; /* istanbul ignore else */ @@ -460,7 +468,6 @@ ret_0: { if (null != shrub) { /* istanbul ignore else */ if (shrub[0] === 1) { - const tail_0 = shrub.slice(1); const itm_1 = shrub[1]; /* istanbul ignore else */ @@ -475,7 +482,6 @@ ret_0: { if (itm_3[0] === 3) { /* istanbul ignore else */ if (itm_3[1] === 4) { - const tail_1 = tail_0.slice(1); const itm_6 = shrub[2]; /* istanbul ignore else */ @@ -550,12 +556,11 @@ const mex_0 = ret_0;" `; exports[`match matches value assertions 1`] = ` -"const value_0 = 123; -let ret_0; +"let ret_0; ret_0: { /* istanbul ignore else */ - if (true === !value_0) { + if (true === !123) { ret_0 = ni; /* istanbul ignore next */ @@ -563,14 +568,14 @@ ret_0: { } /* istanbul ignore else */ - if (true === value_0 > 123) { + if (true === 123 > 123) { ret_0 = ni; /* istanbul ignore next */ break ret_0; } - const val_1 = value_0(); + const val_1 = 123(); /* istanbul ignore else */ if (true === val_1) { @@ -580,7 +585,7 @@ ret_0: { break ret_0; } - const val_0 = shrub(value_0); + const val_0 = shrub(123); /* istanbul ignore else */ if (true === val_0) { @@ -591,7 +596,7 @@ ret_0: { } /* istanbul ignore else */ - if (undefined !== value_0) { + if (undefined !== 123) { ret_0 = true; /* istanbul ignore next */ diff --git a/src/js/context.fnk b/src/js/context.fnk index a73971c..26d3537 100644 --- a/src/js/context.fnk +++ b/src/js/context.fnk @@ -18,7 +18,9 @@ with_loc = fn {loc}, expr: get_js = fn id, ctx: val = get_value id, ctx match val: + # TODO: use inline: true? {ignore_refs: true}: with_loc id, val.js + {inline: true}: with_loc id, val.js {inline: false}: ident id {refs: ? > 1}: ident id {js: ?}: with_loc id, val.js diff --git a/src/js/func/init.fnk b/src/js/func/init.fnk index df76668..e47962f 100644 --- a/src/js/func/init.fnk +++ b/src/js/func/init.fnk @@ -4,70 +4,69 @@ types = import '@babel/types' labeledStatement, doWhileStatement, booleanLiteral } = types -{map, is_empty} = import '@fink/std-lib/iter.fnk' - -{get_refs, update_value} = import '../../ir/context.fnk' +{get_refs, dec_ref, update_value} = import '../../ir/context.fnk' {transform_exprs} = import '../transform.fnk' -{add, set_js, set_js2, with_loc} = import '../context.fnk' +{add, set_js, set_js2} = import '../context.fnk' {ident} = import '../identifier/init.fnk' +clean_args = fn args, body, ctx, out=[]: + match args: + {c: ? < 0}: + [out, body, ctx] -clean_args = fn args_id, args, body, ctx: - fn_args = match [args, get_refs args_id, ctx]: - [(is_empty ?), ? > 0]: - [with_loc args_id, restElement ident args_id, ctx] - else: - [..., last] = args - pipe args: - map fn arg: match arg: - last: arg - {type: 'RestElement'}: arg.argument - else: arg - [...?] + {(args.c): ?}: + clean_args {...args, c: args.c - 1}, body, ctx, [args.(args.c), ...out] - [fn_args, body, ctx] + else: + # TODO: unique id + unused = ident {i: '_${args.c}'} + clean_args {...args, c: args.c - 1}, body, ctx, [unused, ...out] # These are mostly ir transformations, should this be done as a prep step -split_args_body = fn [expr=false, ...exprs], args_id, ctx, args=[], body=[]: +split_args_body = fn [expr=false, ...exprs], args_id, ctx, args={c: -1}, body=[]: match expr: false: - [args_id, args, body, ctx] - - [{f: 'lst_h', args: [{i: args_id.i}]}]: - [...prev, ] = match args: - [?, ?]: args - else: [...args, ] - - [, [head_id]] = expr - arg = ident head_id - next_ctx = set_js2 expr, arg, ctx - split_args_body exprs, args_id, next_ctx, [...prev, arg], body - - [{f: 'lst_r', args: [{i: args_id.i}]}]: - split_args_body [], args_id, ctx, args, [...body, expr, ...exprs] - - [{f: 'lst_t', args: [{i: args_id.i}]}]: - [, [tail_id]] = expr - arg = ident tail_id - rest = with_loc arg, restElement arg - - match get_refs tail_id, ctx: - # the rest is used for more than just getting next arg and tail - ? > 2: - split_args_body [], tail_id, ctx, [...args, rest], [...body, ...exprs] - # this is an ignored arg or last spread + [args, body, ctx] + + [{f: 'tpl_i', args: [{i: args_id.i}]}]: + [{args: [tpl_id, idx]}, [arg_id]] = expr + + match idx: + ? < 0: + split_args_body exprs, args_id, ctx, args, [...body, expr] + else: match args: + {foo: true}: + [foo] = expr + nexpr = [{...foo, args: [tpl_id, idx - args.c - 1]}, [arg_id]] + split_args_body exprs, args_id, ctx, args, [...body, nexpr] + else: + arg = ident arg_id + nargs = {...args, c: idx, (idx): arg} + next_ctx = pipe ctx: + set_js2 expr, arg, ? + dec_ref args_id, ? + split_args_body exprs, args_id, next_ctx, nargs, body + + [{f: 'tpl_s', args: [{i: args_id.i}]}]: + [{args: [args_id, start, end], ...rex}, res] = expr + [foo, next_ctx] = match [start, end]: + [args.c + 1, 0]: + slc = ident args_id + next_ctx = set_js2 expr, slc, ctx + [[], next_ctx] else: - split_args_body exprs, tail_id, ctx, [...args, rest], body + [[[{...rex, args: [args_id, start - args.c - 1, end]}, res]], ctx] + split_args_body exprs, args_id, next_ctx, {...args, foo: true}, [...body, ...foo] [{f: ? in ['fn', 'cn']}]: [foo, bar] = expr {args: [fargs, fbody]} = foo - [next_args_id, next_args, next_body, next_ctx] = split_args_body fbody, args_id, ctx, args + [next_args, next_body, next_ctx] = split_args_body fbody, args_id, ctx, args nexpr = [{...foo, args: [fargs, next_body]}, bar] - split_args_body exprs, next_args_id, next_ctx, next_args, [...body, nexpr] + split_args_body exprs, args_id, next_ctx, next_args, [...body, nexpr] else: split_args_body exprs, args_id, ctx, args, [...body, expr] @@ -98,9 +97,13 @@ transform_normal_fn = fn expr, ctx: split_args_body fn_block, args_id, ? clean_args ...? + all_args = match get_refs args_id, fn_ctx: + ? > 0: [...args, restElement ident args_id] + else: args + [body, next_ctx] = transform_exprs block, fn_ctx - js = arrowFunctionExpression args, blockStatement body + js = arrowFunctionExpression all_args, blockStatement body set_js2 expr, js, next_ctx diff --git a/src/js/func/init.test.fnk.snap b/src/js/func/init.test.fnk.snap index edea596..814567e 100644 --- a/src/js/func/init.test.fnk.snap +++ b/src/js/func/init.test.fnk.snap @@ -28,15 +28,15 @@ export const fun = fun_0;" `; exports[`func compiles destructuring args in body 1`] = ` -"const fun_0 = (a_0, b_0, ...tail_1) => { - return [a_0 + b_0, tail_1, tail_1[0], tail_1[1]]; +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0, args_0[0], args_0[1]]; }; export const fun = fun_0;" `; exports[`func compiles empty arg 1`] = ` -"const fun_0 = (a_0, tail_0, tail_1, b_0) => { +"const fun_0 = (a_0, _1, _2, b_0) => { return a_0 + b_0; }; @@ -44,7 +44,7 @@ export const fun = fun_0;" `; exports[`func compiles empty arg 2`] = ` -"const fun_0 = (tail_0, tail_1, b_0) => { +"const fun_0 = (_0, _1, _2, b_0) => { return b_0; }; @@ -52,7 +52,7 @@ export const fun = fun_0;" `; exports[`func compiles empty arg 3`] = ` -"const fun_0 = (tail_0, a_0) => { +"const fun_0 = (_0, a_0) => { return a_0; }; @@ -95,9 +95,8 @@ export const fun5 = fun5_0;" `; exports[`func compiles middle spread 1`] = ` -"const fun_0 = (a_0, b_0, ...tail_1) => { - const rtail_0 = [...tail_1].reverse(); - return [a_0 + b_0, [...rtail_0.slice(1)].reverse(), rtail_0[0]]; +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0.slice(0, -1), args_0.at(-1)]; }; export const fun = fun_0;" @@ -120,16 +119,16 @@ export const fun = fun_0;" `; exports[`func compiles spread 1`] = ` -"const fun_0 = (a_0, b_0, ...tail_1) => { - return [a_0 + b_0, tail_1]; +"const fun_0 = (a_0, b_0, ...args_0) => { + return [a_0 + b_0, args_0]; }; export const fun = fun_0;" `; exports[`func compiles spread 2`] = ` -"const fun_0 = (a_0, ...tail_0) => { - return [a_0, tail_0]; +"const fun_0 = (a_0, ...args_0) => { + return [a_0, args_0]; }; export const fun = fun_0;" @@ -159,12 +158,11 @@ export const fun = fun_0;" exports[`recursive functions compiles spread 1`] = ` "const fun_0 = (...args_0) => { fun_0: do { - const tail_0 = args_0.slice(1); const b_0 = args_0[1]; /* istanbul ignore else */ if (args_0[0] === b_0) { - args_0 = [...tail_0.slice(1)]; + args_0 = [...args_0.slice(2)]; continue fun_0; } diff --git a/src/js/identifier/init.fnk b/src/js/identifier/init.fnk index 774847e..3e08a12 100644 --- a/src/js/identifier/init.fnk +++ b/src/js/identifier/init.fnk @@ -69,6 +69,14 @@ safe_names = fn [curr=false, ...exprs], renames={}, out=[]: [nres, next_ren] = rename res, renames safe_names exprs, next_ren, [...out, [expr, nres]] + [{f: ? in ['tpl_i', 'tpl_s']}]: + [expr, res] = curr + {args: [tpl_id, ...rest_args]} = expr + nargs = replace_refs [tpl_id], renames + nexpr = {...expr, args: [...nargs, ...rest_args]} + [nres, next_ren] = rename res, renames + safe_names exprs, next_ren, [...out, [nexpr, nres]] + [{f: ? in ['fn', 'cn']}]: [expr, res] = curr {args: [args, body]} = expr diff --git a/src/js/identifier/init.test.fnk.snap b/src/js/identifier/init.test.fnk.snap index 7841c58..3680a22 100644 --- a/src/js/identifier/init.test.fnk.snap +++ b/src/js/identifier/init.test.fnk.snap @@ -6,10 +6,9 @@ export const foo = foo_0;" `; exports[`identifiers does not escapes unicode names 1`] = ` -"const ಠ_ಠ_0 = 1234; -export const ƒ = shrub, +"export const ƒ = shrub, π = ni, - ಠ_ಠ = ಠ_ಠ_0;" + ಠ_ಠ = 1234;" `; exports[`identifiers escapes hyphenated idents 1`] = ` @@ -18,87 +17,46 @@ export const fooᜭbar = fooᜭbar_0;" `; exports[`identifiers escapes reserved JS identifiers 1`] = ` -"const do_0 = 1; -const if_0 = 1; -const in_0 = 1; -const for_0 = 1; -const let_0 = 1; -const new_0 = 1; -const try_0 = 1; -const var_0 = 1; -const case_0 = 1; -const enum_0 = 1; -const void_0 = 1; -const with_0 = 1; -const break_0 = 1; -const catch_0 = 1; -const class_0 = 1; -const const_0 = 1; -const super_0 = 1; -const while_0 = 1; -const yield_0 = 1; -const delete_0 = 1; -const export_0 = 1; -const import_0 = 1; -const public_0 = 1; -const return_0 = 1; -const static_0 = 1; -const switch_0 = 1; -const typeof_0 = 1; -const default_0 = 1; -const extends_0 = 1; -const finally_0 = 1; -const package_0 = 1; -const private_0 = 1; -const continue_0 = 1; -const function_0 = 1; -const arguments_0 = 1; -const interface_0 = 1; -const protected_0 = 1; -const implements_0 = 1; -const instanceof_0 = 1; -const undefined_0 = 1; -const null_0 = 1; -export const ˆdo = do_0, - ˆif = if_0, - ˆin = in_0, - ˆfor = for_0, - ˆlet = let_0, - ˆnew = new_0, - ˆtry = try_0, - ˆvar = var_0, - ˆcase = case_0, - ˆenum = enum_0, - ˆvoid = void_0, - ˆwith = with_0, - ˆbreak = break_0, - ˆcatch = catch_0, - ˆclass = class_0, - ˆconst = const_0, - ˆsuper = super_0, - ˆwhile = while_0, - ˆyield = yield_0, - ˆdelete = delete_0, - ˆexport = export_0, - ˆimport = import_0, - ˆpublic = public_0, - ˆreturn = return_0, - ˆstatic = static_0, - ˆswitch = switch_0, - ˆtypeof = typeof_0, - ˆdefault = default_0, - ˆextends = extends_0, - ˆfinally = finally_0, - ˆpackage = package_0, - ˆprivate = private_0, - ˆcontinue = continue_0, - ˆfunction = function_0, - ˆarguments = arguments_0, - ˆinterface = interface_0, - ˆprotected = protected_0, - ˆimplements = implements_0, - ˆinstanceof = instanceof_0, - ˆundefined = undefined_0, - ˆnull = null_0; -export default default_0;" +"export const ˆdo = 1, + ˆif = 1, + ˆin = 1, + ˆfor = 1, + ˆlet = 1, + ˆnew = 1, + ˆtry = 1, + ˆvar = 1, + ˆcase = 1, + ˆenum = 1, + ˆvoid = 1, + ˆwith = 1, + ˆbreak = 1, + ˆcatch = 1, + ˆclass = 1, + ˆconst = 1, + ˆsuper = 1, + ˆwhile = 1, + ˆyield = 1, + ˆdelete = 1, + ˆexport = 1, + ˆimport = 1, + ˆpublic = 1, + ˆreturn = 1, + ˆstatic = 1, + ˆswitch = 1, + ˆtypeof = 1, + ˆdefault = 1, + ˆextends = 1, + ˆfinally = 1, + ˆpackage = 1, + ˆprivate = 1, + ˆcontinue = 1, + ˆfunction = 1, + ˆarguments = 1, + ˆinterface = 1, + ˆprotected = 1, + ˆimplements = 1, + ˆinstanceof = 1, + ˆundefined = 1, + ˆnull = 1; +export default 1;" `; diff --git a/src/js/init.fnk b/src/js/init.fnk index 3223c37..c96ace1 100644 --- a/src/js/init.fnk +++ b/src/js/init.fnk @@ -90,6 +90,7 @@ prepare_imports = fn [expr=false, ...exprs], ctx: [{f: 'imp'}]: [{args: [sr_id]}] = expr + # TODO: is there a better option than setting ref? next_ctx = update_value sr_id, {refs: 1}, ctx prepare_imports exprs, next_ctx @@ -127,6 +128,11 @@ prepare_non_inlinable = fn [expr=false, ...exprs], ctx: prepare_non_inlinable exprs, next_ctx + [{f: ? in ['int', 'float']}]: + [, [res_id]] = expr + next_ctx = update_value res_id, {inline: true}, ctx + prepare_non_inlinable exprs, next_ctx + [{f: ? in ['fn', 'cn']}]: [{args: [, body]}] = expr prepare_non_inlinable [...body, ...exprs], ctx diff --git a/src/js/literals/list.fnk b/src/js/literals/list.fnk index 1186af7..b78a323 100644 --- a/src/js/literals/list.fnk +++ b/src/js/literals/list.fnk @@ -10,18 +10,60 @@ types = import '@babel/types' -set_tail_of = fn items_id, tail_of, {tails={}, ...ctx}: - {...ctx, tails: {...tails, (items_id.i): tail_of}} +ids_to_js = fn [id=false, ...rest], ctx, out=[]: + match id: + false: + out + {i: '_'}: + ids_to_js rest, ctx, [...out, null] + else: + item = get_js id, ctx + # console.log id, arg + ids_to_js rest, ctx, [...out, item] + + + +transform_tpl = fn expr, ctx: + [{args: items_ids}] = expr + js = arrayExpression + ids_to_js items_ids, ctx + set_js2 expr, js, ctx + + + +transform_tpl_i = fn expr, ctx: + [{args: [tpl_id, idx]}] = expr + js = match idx: + ? < 0: + callExpression + memberExpression + get_js tpl_id, ctx + identifier 'at' + [numericLiteral idx] + else: + memberExpression + get_js tpl_id, ctx + numericLiteral idx + true + + set_js2 expr, js, ctx + -get_tail_of = fn items_id, {tails={}}: - {(items_id.i): tail_of=[items_id, 0]} = tails - tail_of +transform_tpl_s = fn expr, ctx: + [{args: [items_id, start_idx, end_idx]}] = expr + items = get_js items_id, ctx + start = numericLiteral start_idx + args = match end_idx: + ? >= 0: [start] + else: [start, numericLiteral end_idx] + + js = callExpression + memberExpression items, identifier 'slice' + args -transform_empty_list = fn expr, ctx: - js = arrayExpression [] set_js2 expr, js, ctx @@ -38,7 +80,6 @@ elems_or_spread = fn expr: transform_list_append = fn expr, ctx: [{args: [items_id, val_id]}] = expr elems = elems_or_spread get_js items_id, ctx - elem = match val_id: {i: '_'}: null else: get_js val_id, ctx @@ -52,58 +93,21 @@ transform_list_chain = fn expr, ctx: [{args: [items1_id, items2_id]}] = expr elems1 = elems_or_spread get_js items1_id, ctx elems2 = elems_or_spread get_js items2_id, ctx - - js = arrayExpression [...elems1, ...elems2] - set_js2 expr, js, ctx - - - -transform_list_head = fn expr, ctx: - [{args: [items_id]}] = expr - [tail_src, idx] = get_tail_of items_id, ctx - arr = get_js tail_src, ctx - js_idx = numericLiteral idx - js = memberExpression arr, js_idx, true - set_js2 expr, js, ctx - - - -transform_list_reverse = fn expr, ctx: - [{args: [items_id]}] = expr - arr = get_js items_id, ctx - - js = callExpression - memberExpression - arrayExpression [spreadElement arr] - identifier 'reverse' - [] + js = arrayExpression [...elems1, ...elems2] set_js2 expr, js, ctx -transform_list_tail = fn expr, ctx: - [{args: [items_id]}, [result_id]] = expr - - items = get_js items_id, ctx - [tail_src, idx] = get_tail_of items_id, ctx - - js = callExpression - memberExpression items, identifier 'slice' - [numericLiteral 1] - - pipe ctx: - set_tail_of result_id, [tail_src, idx + 1], ? - set_js2 expr, js, ? - - - - add_list = fn ctx: pipe ctx: - add 'lst', transform_empty_list + add 'tpl', transform_tpl + add 'tpl_i', transform_tpl_i + add 'tpl_s', transform_tpl_s + + # add 'lst', transform_empty_list add 'lst_a', transform_list_append add 'lst_c', transform_list_chain - add 'lst_h', transform_list_head - add 'lst_t', transform_list_tail - add 'lst_r', transform_list_reverse + # add 'lst_h', transform_list_head + # add 'lst_t', transform_list_tail + # add 'lst_r', transform_list_reverse diff --git a/src/js/literals/list.test.fnk b/src/js/literals/list.test.fnk index 5d6fa5a..564b1c0 100644 --- a/src/js/literals/list.test.fnk +++ b/src/js/literals/list.test.fnk @@ -1,6 +1,7 @@ -{fink2js} = import '../../testing/generate.fnk' {skip, describe, it, expect, to_match_snapshot} = import '@fink/jest/test.fnk' +{fink2js} = import '../../testing/generate.fnk' + describe 'list', fn: it 'compiles', fn: @@ -35,6 +36,7 @@ describe 'list', fn: spam = [7] shrub = [...bar, ...spam] ni = [...nu, na] + nie = [...nu, , na] ham = [...nu, ...na] ' to_match_snapshot @@ -50,18 +52,19 @@ describe 'list', fn: describe 'unpacking list', fn: - it 'destructures simple', fn: + it 'destructures known tuples', fn: expect fink2js ' [a, [b, c]] = [1, [2, 3]] foo = [b, a] [z] = [1 + 2, 3 * 4] [x, y] = foo - out = [a, b, c, foo, z, x, y] + [, ...w] = [] + out = [a, b, c, foo, z, x, y, w] ' to_match_snapshot - it 'destructures empty', fn: + it 'destructures missing item', fn: expect fink2js ' [a, , b] = foo @@ -70,6 +73,13 @@ describe 'unpacking list', fn: to_match_snapshot it 'destructures spread', fn: + expect + fink2js ' + [..., a] = foo + out = a + ' + to_match_snapshot + expect fink2js ' [a, ..., b] = foo @@ -98,6 +108,20 @@ describe 'unpacking list', fn: ' to_match_snapshot + expect + fink2js ' + [a, b, ...c, d] = foo + out = [a, b, c, d] + ' + to_match_snapshot + + expect + fink2js ' + [a, b, ...c, d, e] = foo + out = [a, b, c, d, e] + ' + to_match_snapshot + it 'destructures recs', fn: expect @@ -122,3 +146,13 @@ describe 'unpacking list', fn: out = [a, b, c] ' to_match_snapshot + + + it 'TODO', fn: + expect + fink2js " + [bar, spam, ham] = [...shrub] + ni = bar + spam + ham + " + to_match_snapshot + diff --git a/src/js/literals/list.test.fnk.snap b/src/js/literals/list.test.fnk.snap index 7f1a51b..81c042a 100644 --- a/src/js/literals/list.test.fnk.snap +++ b/src/js/literals/list.test.fnk.snap @@ -30,20 +30,35 @@ export const foo = foo_0, exports[`list compiles spread 2`] = ` "const foo_0 = [1, 2, 3]; -const bar_0 = [...foo_0, 4, 5, 6]; +const bar_0 = [1, 2, 3, 4, 5, 6]; const spam_0 = [7]; -const shrub_0 = [...bar_0, ...spam_0]; +const shrub_0 = [1, 2, 3, 4, 5, 6, 7]; const ni_0 = [...nu, na]; +const nie_0 = [...nu,, na]; const ham_0 = [...nu, ...na]; export const foo = foo_0, bar = bar_0, spam = spam_0, shrub = shrub_0, ni = ni_0, + nie = nie_0, ham = ham_0;" `; -exports[`unpacking list destructures empty 1`] = ` +exports[`unpacking list TODO 1`] = ` +"const dlst_0 = [...shrub]; +const ni_0 = dlst_0[0] + dlst_0[1] + dlst_0[2]; +export const ni = ni_0;" +`; + +exports[`unpacking list destructures known tuples 1`] = ` +"const foo_0 = [2, 1]; +const out_0 = [1, 2, 3, foo_0, 1 + 2, 2, 1, []]; +export const foo = foo_0, + out = out_0;" +`; + +exports[`unpacking list destructures missing item 1`] = ` "const out_0 = [foo[0], foo[2]]; export const out = out_0;" `; @@ -54,34 +69,38 @@ const out_0 = [drec_0.a, drec_0.b, ni[1]]; export const out = out_0;" `; -exports[`unpacking list destructures simple 1`] = ` -"const item_3 = 1; -const item_2 = 2; -const foo_0 = [item_2, item_3]; -const out_0 = [item_3, item_2, 3, foo_0, 1 + 2, item_2, item_3]; -export const foo = foo_0, - out = out_0;" -`; - exports[`unpacking list destructures spread 1`] = ` -"const out_0 = [foo[0], [...foo.slice(1)].reverse()[0]]; -export const out = out_0;" +"const a_0 = foo.at(-1); +export const out = a_0;" `; exports[`unpacking list destructures spread 2`] = ` -"const rtail_0 = [...foo.slice(1)].reverse(); -const out_0 = [foo[0], rtail_0[1], rtail_0[0]]; +"const out_0 = [foo[0], foo.at(-1)]; export const out = out_0;" `; exports[`unpacking list destructures spread 3`] = ` -"const out_0 = [foo[0], ...foo.slice(1)]; +"const out_0 = [foo[0], foo.at(-2), foo.at(-1)]; export const out = out_0;" `; exports[`unpacking list destructures spread 4`] = ` -"const rtail_0 = [...foo.slice(1)].reverse(); -const out_0 = [foo[0], [...rtail_0.slice(1)].reverse(), rtail_0[0]]; +"const out_0 = [foo[0], ...foo.slice(1)]; +export const out = out_0;" +`; + +exports[`unpacking list destructures spread 5`] = ` +"const out_0 = [foo[0], foo.slice(1, -1), foo.at(-1)]; +export const out = out_0;" +`; + +exports[`unpacking list destructures spread 6`] = ` +"const out_0 = [foo[0], foo[1], foo.slice(2, -1), foo.at(-1)]; +export const out = out_0;" +`; + +exports[`unpacking list destructures spread 7`] = ` +"const out_0 = [foo[0], foo[1], foo.slice(2, -2), foo.at(-2), foo.at(-1)]; export const out = out_0;" `; diff --git a/src/js/literals/number.test.fnk.snap b/src/js/literals/number.test.fnk.snap index c3b03e3..b92adf3 100644 --- a/src/js/literals/number.test.fnk.snap +++ b/src/js/literals/number.test.fnk.snap @@ -1,30 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`numbers transforms floats 1`] = ` -"const x_0 = 1.234578; -const y_0 = 1.23e+45; -const z_0 = 1.23e-45; -const a_0 = 1.23e+45; -export const x = x_0, - y = y_0, - z = z_0, - a = a_0;" +"export const x = 1.234578, + y = 1.23e+45, + z = 1.23e-45, + a = 1.23e+45;" `; exports[`numbers transforms hex, octet, binary 1`] = ` -"const h_0 = 0x123456789ABCDEF0; -const o_0 = 0o12345670; -const b_0 = 0b01010; -export const h = h_0, - o = o_0, - b = b_0;" +"export const h = 0x123456789ABCDEF0, + o = 0o12345670, + b = 0b01010;" `; exports[`numbers transforms integers 1`] = ` -"const x_0 = 1234578; -const y_0 = 0123; -const z_0 = 123_456_789; -export const x = x_0, - y = y_0, - z = z_0;" +"export const x = 1234578, + y = 0123, + z = 123_456_789;" `; diff --git a/src/js/module/init.test.fnk.snap b/src/js/module/init.test.fnk.snap index e2550f3..0ed37db 100644 --- a/src/js/module/init.test.fnk.snap +++ b/src/js/module/init.test.fnk.snap @@ -2,8 +2,7 @@ exports[`module handles directives 1`] = ` "#!/usr/bin/env node -const foo_0 = 1234; -export const foo = foo_0;" +export const foo = 1234;" `; exports[`module handles exports 1`] = ` @@ -15,15 +14,12 @@ const π_0 = () => { return true; }; -const foo_bar_0 = 1234; -const fooᜭbar_0 = 1234; -const default_0 = 456; export const ˆdelete = delete_0, π = π_0, - foo_bar = foo_bar_0, - fooᜭbar = fooᜭbar_0, - ˆdefault = default_0; -export default default_0;" + foo_bar = 1234, + fooᜭbar = 1234, + ˆdefault = 456; +export default 456;" `; exports[`module handles exports 2`] = ` @@ -35,15 +31,12 @@ const π_0 = () => { return true; }; -const foo_bar_0 = 1234; -const fooᜭbar_0 = 1234; -const default_0 = 456; -module.exports = default_0; +module.exports = 456; exports.ˆdelete = delete_0; exports.π = π_0; -exports.foo_bar = foo_bar_0; -exports.fooᜭbar = fooᜭbar_0; -exports.ˆdefault = default_0;" +exports.foo_bar = 1234; +exports.fooᜭbar = 1234; +exports.ˆdefault = 456;" `; exports[`module handles side effects 1`] = ` diff --git a/src/js/transform.fnk b/src/js/transform.fnk index 87bd877..17b8bd2 100644 --- a/src/js/transform.fnk +++ b/src/js/transform.fnk @@ -72,7 +72,7 @@ transform_body_expr = fn expr, ctx: [[js], next_ctx] - [, {refs: ? > 1}]: + [, {inline: ? != true, refs: ? > 1}]: val = get_js_literal res_id, next_ctx js = match val: {type: 'VariableDeclaration'}: diff --git a/src/optimize/init.test.fnk b/src/optimize/init.test.fnk index 2c2337d..173dd8f 100644 --- a/src/optimize/init.test.fnk +++ b/src/optimize/init.test.fnk @@ -86,11 +86,14 @@ describe 'optimize', fn: nanu = fn foo, bar: foo + bar + ham - ni = fn spam, ham, ni: - [spam, ham, ni] + ni = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] - na = fn spam, ham, ni: - [spam, ham, ni] + na = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] + + nu = fn foo, bar, spam, ham, ni: + [foo, bar, spam, ham, ni] ', {optimize: {refs: true, tails: true, unused: true, names: true}} to_match_snapshot diff --git a/src/optimize/init.test.fnk.snap b/src/optimize/init.test.fnk.snap index 2433a57..0ac37a3 100644 --- a/src/optimize/init.test.fnk.snap +++ b/src/optimize/init.test.fnk.snap @@ -9,42 +9,37 @@ rec_e fn exports_0: int '2', fn b_0: str 'b', fn key_1: rec_s exports_1, key_1, b_0, fn exports_2: - lst_e fn lst_1: - lst_a lst_1, a_0, fn lst_0: - lst_a lst_0, b_0, fn c_0: - str 'c', fn key_2: - rec_s exports_2, key_2, c_0, fn exports_3: - add a_0, b_0, fn f_0: - str 'f', fn key_3: - rec_s exports_3, key_3, f_0, fn exports_4: - lst_e fn drctvs_0: - mod exports_4, drctvs_0, fn mod_0:" + tpl a_0, b_0, fn c_0: + str 'c', fn key_2: + rec_s exports_2, key_2, c_0, fn exports_3: + add a_0, b_0, fn f_0: + str 'f', fn key_3: + rec_s exports_3, key_3, f_0, fn exports_4: + tpl, fn drctvs_0: + mod exports_4, drctvs_0, fn mod_0:" `; exports[`optimize optimizes ac ...>> res: cc ..., res 1`] = ` " rec_e fn exports_0: z (fn args_0, ret_1, gcd_0_0: #fn - lst_h args_0, fn x_0: - lst_t args_0, fn tail_0: - lst_h tail_0, fn y_0: - id (fn: #cn - lst_e fn cargs_0: - lst_a cargs_0, y_0, fn cargs_1: - rem x_0, y_0, fn arg_1: - lst_a cargs_1, arg_1, fn cargs_2: - cf gcd_0_0, cargs_2 - ), fn else_0: - int '0', fn val_0: - eq y_0, val_0, fn cond_0: - id (fn: #cn - cc ret_1, x_0 - ), fn match_res_0: - cif cond_0, match_res_0, else_0 + tpl_i args_0, 0, fn x_0: + tpl_i args_0, 1, fn y_0: + id (fn: #cn + rem x_0, y_0, fn arg_1: + tpl y_0, arg_1, fn cargs_2: + cf gcd_0_0, cargs_2 + ), fn else_0: + int '0', fn val_0: + eq y_0, val_0, fn cond_0: + id (fn: #cn + cc ret_1, x_0 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 ), fn gcd_0: str 'gcd', fn key_0: rec_s exports_0, key_0, gcd_0, fn exports_1: - lst_e fn drctvs_0: + tpl, fn drctvs_0: mod exports_1, drctvs_0, fn mod_0:" `; @@ -55,45 +50,37 @@ rec_e fn exports_0: str 'ni', fn key_0: rec_s exports_0, key_0, ni_0, fn exports_1: id (fn args_0, ret_1: #fn - lst_h args_0, fn foo_0: - lst_t args_0, fn tail_0: - lst_h tail_0, fn bar_0: - id (fn ret_0: #cn - id (fn: #cn - lst_e fn lst_1: - int '2', fn item_1: - lst_a lst_1, item_1, fn lst_0: - int '2', fn right_0: - mul ni_0, right_0, fn item_0: - lst_a lst_0, item_0, fn result_1: - cc ret_0, result_1 - ), fn else_0: - eq foo_0, bar_0, fn cond_0: - id (fn: #cn - lst_e fn lst_3: - int '1', fn item_3: - lst_a lst_3, item_3, fn lst_2: - lst_a lst_2, ni_0, fn result_2: - cc ret_0, result_2 - ), fn match_res_0: - cif cond_0, match_res_0, else_0 - ), fn match_0: - ac match_0, fn dlst_0: - lst_h dlst_0, fn spam_1: - lst_t dlst_0, fn tail_2: - lst_h tail_2, fn ham_0: - add spam_1, ni_0, fn left_1: - add left_1, ham_0, fn result_3: - cc ret_1, result_3 + tpl_i args_0, 0, fn foo_0: + tpl_i args_0, 1, fn bar_0: + id (fn ret_0: #cn + id (fn: #cn + int '2', fn item_1: + int '2', fn right_0: + mul ni_0, right_0, fn item_0: + tpl item_1, item_0, fn result_1: + cc ret_0, result_1 + ), fn else_0: + eq foo_0, bar_0, fn cond_0: + id (fn: #cn + int '1', fn item_3: + tpl item_3, ni_0, fn result_2: + cc ret_0, result_2 + ), fn match_res_0: + cif cond_0, match_res_0, else_0 + ), fn match_0: + ac match_0, fn dlst_0: + tpl_i dlst_0, 0, fn spam_1: + tpl_i dlst_0, 1, fn ham_0: + add spam_1, ni_0, fn left_1: + add left_1, ham_0, fn result_3: + cc ret_1, result_3 ), fn spam_0: str 'spam', fn key_1: rec_s exports_1, key_1, spam_0, fn exports_2: - lst_e fn cargs_0: - lst_a cargs_0, foo, fn cargs_1: - lst_a cargs_1, bar, fn cargs_2: - af spam_0, cargs_2, fn mex_0: - lst_e fn drctvs_0: - mod exports_2, drctvs_0, fn mod_0:" + tpl foo, bar, fn cargs_2: + af spam_0, cargs_2, fn mex_0: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" `; exports[`optimize optimizes functions 1`] = ` @@ -103,21 +90,18 @@ rec_e fn exports_0: str 'ni', fn key_0: rec_s exports_0, key_0, ni_0, fn exports_1: id (fn args_0, ret_0: #fn - lst_h args_0, fn foo_0: - lst_t args_0, fn tail_0: - lst_h tail_0, fn bar_0: - add bar_0, foo_0, fn left_0: - add left_0, ni_0, fn result_1: - cc ret_0, result_1 + tpl_i args_0, 0, fn foo_0: + tpl_i args_0, 1, fn bar_0: + add bar_0, foo_0, fn left_0: + add left_0, ni_0, fn result_1: + cc ret_0, result_1 ), fn spam_0: str 'spam', fn key_1: rec_s exports_1, key_1, spam_0, fn exports_2: - lst_e fn cargs_0: - lst_a cargs_0, foo, fn cargs_1: - lst_a cargs_1, bar, fn cargs_2: - af spam_0, cargs_2, fn mex_0: - lst_e fn drctvs_0: - mod exports_2, drctvs_0, fn mod_0:" + tpl foo, bar, fn cargs_2: + af spam_0, cargs_2, fn mex_0: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" `; exports[`optimize optimizes using short names 1`] = ` @@ -130,87 +114,78 @@ rec_e fn a: str 'foobar', fn f: rec_s d, f, e, fn g: id (fn h, i: #fn - lst_h h, fn j: - lst_t h, fn k: - lst_h k, fn l: - add j, l, fn m: - cc i, m - ), fn n: - str 'shrurb', fn o: - rec_s g, o, n, fn p: - id (fn q, r: #fn - lst_h q, fn s: - lst_t q, fn t: - lst_h t, fn u: - add s, u, fn v: - add v, b, fn w: - cc r, w - ), fn x: - str 'nanu', fn y: - rec_s p, y, x, fn z: - id (fn A, B: #fn - lst_h A, fn C: - lst_t A, fn D: - lst_h D, fn E: - lst_t D, fn F: - lst_h F, fn G: - lst_e fn H: - lst_a H, C, fn I: - lst_a I, E, fn J: - lst_a J, G, fn K: - cc B, K - ), fn L: - str 'ni', fn M: - rec_s z, M, L, fn N: - id (fn O, P: #fn - lst_h O, fn Q: - lst_t O, fn R: - lst_h R, fn S: - lst_t R, fn T: - lst_h T, fn U: - lst_e fn V: - lst_a V, Q, fn W: - lst_a W, S, fn X: - lst_a X, U, fn Y: - cc P, Y - ), fn Z: - str 'na', fn aa: - rec_s N, aa, Z, fn ab: - lst_e fn ac: - mod ab, ac, fn ad:" + tpl_i h, 0, fn j: + tpl_i h, 1, fn k: + add j, k, fn l: + cc i, l + ), fn m: + str 'shrurb', fn n: + rec_s g, n, m, fn o: + id (fn p, q: #fn + tpl_i p, 0, fn r: + tpl_i p, 1, fn s: + add r, s, fn t: + add t, b, fn u: + cc q, u + ), fn v: + str 'nanu', fn w: + rec_s o, w, v, fn x: + id (fn y, z: #fn + tpl_i y, 0, fn A: + tpl_i y, 1, fn B: + tpl_i y, 2, fn C: + tpl_i y, 3, fn D: + tpl_i y, 4, fn E: + tpl A, B, C, D, E, fn F: + cc z, F + ), fn G: + str 'ni', fn H: + rec_s x, H, G, fn I: + id (fn J, K: #fn + tpl_i J, 0, fn L: + tpl_i J, 1, fn M: + tpl_i J, 2, fn N: + tpl_i J, 3, fn O: + tpl_i J, 4, fn P: + tpl L, M, N, O, P, fn Q: + cc K, Q + ), fn R: + str 'na', fn S: + rec_s I, S, R, fn T: + id (fn U, V: #fn + tpl_i U, 0, fn W: + tpl_i U, 1, fn X: + tpl_i U, 2, fn Y: + tpl_i U, 3, fn Z: + tpl_i U, 4, fn aa: + tpl W, X, Y, Z, aa, fn ab: + cc V, ab + ), fn ac: + str 'nu', fn ad: + rec_s T, ad, ac, fn ae: + tpl, fn af: + mod ae, af, fn ag:" `; exports[`optimize optimizes values 1`] = ` " rec_e fn exports_0: - lst_e fn lst_1: - int '1', fn item_1: - lst_a lst_1, item_1, fn lst_0: - int '2', fn item_0: - lst_a lst_0, item_0, fn y_0: - str 'y', fn key_0: - rec_s exports_0, key_0, y_0, fn exports_1: - int '3', fn x_0: - str 'x', fn key_1: - rec_s exports_1, key_1, x_0, fn exports_2: - int '4', fn item_6: - int '5', fn item_4: - int '1', fn item_9: - int '2', fn item_8: - int '3', fn item_7: - lst_e fn sp_0_1: - lst_a sp_0_1, item_9, fn sp_0_0: - lst_a sp_0_0, item_8, fn sp_0: - lst_e fn cargs_0: - lst_a cargs_0, item_6, fn cargs_1: - lst_a cargs_1, x_0, fn cargs_2: - lst_a cargs_2, item_4, fn cargs_3: - lst_a cargs_3, y_0, fn cargs_4: - lst_a cargs_4, item_7, fn cargs_5: - lst_a cargs_5, sp_0, fn cargs_6: - lst_a cargs_6, item_9, fn cargs_7: - lst_a cargs_7, lala, fn cargs_8: - af log, cargs_8, fn mex_5: - lst_e fn drctvs_0: - mod exports_2, drctvs_0, fn mod_0:" + int '1', fn item_1: + int '2', fn item_0: + tpl item_1, item_0, fn y_0: + str 'y', fn key_0: + rec_s exports_0, key_0, y_0, fn exports_1: + int '3', fn x_0: + str 'x', fn key_1: + rec_s exports_1, key_1, x_0, fn exports_2: + int '4', fn item_6: + int '5', fn item_4: + int '1', fn item_9: + int '2', fn item_8: + int '3', fn item_7: + tpl item_9, item_8, fn sp_0: + tpl item_6, x_0, item_4, y_0, item_7, sp_0, item_9, lala, fn cargs_8: + af log, cargs_8, fn mex_5: + tpl, fn drctvs_0: + mod exports_2, drctvs_0, fn mod_0:" `; diff --git a/src/optimize/refs.fnk b/src/optimize/refs.fnk index 87a324e..98210ca 100644 --- a/src/optimize/refs.fnk +++ b/src/optimize/refs.fnk @@ -1,6 +1,6 @@ {reverse} = import '@fink/std-lib/iter.fnk' -{update_value, get_value, unique_name} = import '../ir/context.fnk' +{update_value, get_value} = import '../ir/context.fnk' @@ -39,23 +39,29 @@ add_alias = fn id, target, ctx: optimize_lst = fn [expr, res], ctx: [res_id] = res - opt_expr = optimize_args expr, ctx - next_ctx = update_value res_id, {empty_tpl: true, item_aliases: []}, ctx + opt_expr = {...expr, f: 'tpl', args: []} + next_ctx = update_value res_id, {type: 'tpl', items: []}, ctx [[opt_expr, res], next_ctx] -add_lst_aliases = fn {args: [lst_id, val_id]}, res_id, ctx: - {item_aliases=[]} = get_value lst_id, ctx - update_value res_id, {item_aliases: [...item_aliases, val_id]}, ctx - - - optimize_lst_a = fn [expr, res], ctx: [res_id] = res opt_expr = optimize_args expr, ctx - next_ctx = add_lst_aliases opt_expr, res_id, ctx - [[[opt_expr, res]], next_ctx] + {args: [lst_id, val_id]} = opt_expr + info = get_value lst_id, ctx + + match info: + {type: 'tpl', items: ?}: + {items} = get_value lst_id, ctx + + next_ctx = update_value res_id, {type: 'tpl', items: [...items, val_id]}, ctx + expr = {...opt_expr, f: 'tpl', args: [...items, val_id]} + [[[expr, res]], next_ctx] + + else: + next_ctx = update_value res_id, {type: 'lst'}, ctx + [[[opt_expr, res]], next_ctx] @@ -65,12 +71,23 @@ optimize_lst_h = fn [expr, res], ctx: {args: [lst_id]} = opt_expr info = get_value lst_id, ctx match info: - {item_aliases: [?]}: - {item_aliases: [val_id]} = info + {type: 'tpl', items: [?]}: + {items: [val_id]} = info next_ctx = add_alias res_id, val_id, ctx [[], next_ctx] + + {type: 'tpl', slice_of: ?}: + [lst_id, start, end, inc] = info.slice_of + idx = match inc: + 1: start + else: end - 1 + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, idx]}, res]], ctx] + + {type: 'tpl'}: + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, 0]}, res]], ctx] + else: - [[[opt_expr, res]], ctx] + [[[{...opt_expr, f: 'tpl_i', args: [lst_id, 0]}, res]], ctx] @@ -78,21 +95,38 @@ optimize_lst_t = fn [expr, res], ctx: [res_id] = res opt_expr = optimize_args expr, ctx {args: [lst_id]} = opt_expr + info = get_value lst_id, ctx match info: - {item_aliases: [?]}: - {item_aliases: [, ...item_aliases]} = info - next_ctx = update_value res_id, {item_aliases}, ctx - [[[opt_expr, res]], next_ctx] - else: - [[[opt_expr, res]], ctx] + {type: 'tpl', items: [?]}: + {items: [, ...items]} = info + foo = {...opt_expr, f: 'tpl', args: items} + next_ctx = update_value res_id, {type: 'tpl', items}, ctx + [[[foo, res]], next_ctx] + + {type: 'tpl', items: ?}: + next_ctx = add_alias res_id, lst_id, ctx + [[], next_ctx] + {type: 'tpl', slice_of: ?}: + [lst_id, start, end, inc] = info.slice_of + args = match inc: + 1: [lst_id, start + 1, end] + else: [lst_id, start, end - 1] + next_ctx = update_value res_id, {type: 'tpl', slice_of: [...args, inc]}, ctx + foo = {...opt_expr, f: 'tpl_s', args} + [[[foo, res]], next_ctx] -is_empty_lst = fn id, ctx: - match get_value id, ctx: - {empty_tpl: true}: true - else: false + {type: 'tpl'}: + next_ctx = update_value res_id, {type: 'tpl', slice_of: [lst_id, 1, 0, 1]}, ctx + foo = {...opt_expr, f: 'tpl_s', args: [lst_id, 1, 0]} + [[[foo, res]], next_ctx] + + else: + next_ctx = update_value res_id, {type: 'tpl', slice_of: [lst_id, 1, 0, 1]}, ctx + foo = {...opt_expr, f: 'tpl_s', args: [lst_id, 1, 0]} + [[[foo, res]], next_ctx] @@ -100,25 +134,21 @@ optimize_lst_c = fn [expr, res], ctx: [res_id] = res opt_expr = optimize_args expr, ctx {args: [lst1_id, lst2_id]} = opt_expr - - match ctx: - is_empty_lst lst2_id, ?: - next_ctx = add_alias res_id, lst1_id, ctx - [[], next_ctx] - else: - [[[opt_expr, res]], ctx] - - - -create_lst = fn [id=false, ...ids], lst_id, tmp_id, ctx, out=[]: - match id: - false: - [[[{f: 'lst', args: [], loc: lst_id.loc}, [tmp_id]], ...out], ctx] + info1 = get_value lst1_id, ctx + info2 = get_value lst2_id, ctx + + match [info1, info2]: + [{type: 'tpl', items: ?}, {type: 'tpl', items: ?}]: + {items: [...items1]} = info1 + {items: [...items2]} = info2 + items = [...items1, ...items2] + next_ctx = update_value res_id, {type: 'tpl', items}, ctx + foo = {...opt_expr, f: 'tpl', args: items} + [[[foo, res]], next_ctx] else: - [next_tmp_id, end_ctx] = unique_name lst_id.i, lst_id, ctx - lst = [{f: 'lst_a', args: [next_tmp_id, id], loc: id.loc}, [tmp_id]] - create_lst ids, lst_id, next_tmp_id, end_ctx, [lst, ...out] + next_ctx = update_value res_id, {type: 'tpl'}, ctx + [[[opt_expr, res]], next_ctx] @@ -134,22 +164,47 @@ optimize_lst_r = fn [expr, res], ctx: next_ctx = add_alias res_id, tpr, ctx [[], next_ctx] - {item_aliases: ?}: - {item_aliases: rev_aliases} = info + {type: 'tpl', items: ?}: # find existing tpl instead of creating - item_aliases = reverse rev_aliases - lst_ctx = update_value res_id, {item_aliases, tpr: lst_id}, ctx - create_lst rev_aliases, res_id, res_id, lst_ctx + items = reverse info.items + next_ctx = update_value res_id, {type: 'tpl', items, tpr: lst_id}, ctx + foo = {...opt_expr, f: 'tpl', args: items} + [[[foo, res]], next_ctx] + + {type: 'tpl', slice_of: ?}: + [tpl_id, start_idx, end_idx, inc] = info.slice_of + + slice_of = match inc: + 1: [tpl_id, start_idx, end_idx, -inc] + else: [tpl_id, start_idx, end_idx, -inc] + + next_ctx = update_value res_id, {type: 'tpl', slice_of, tpr: lst_id}, ctx + + match inc: + 1: + [[[opt_expr, res]], next_ctx] + else: + foo = {...opt_expr, f: 'tpl_s', args: [tpl_id, start_idx, end_idx]} + [[[foo, res]], next_ctx] else: - next_ctx = update_value res_id, {tpr: lst_id}, ctx + slice_of = [lst_id, 0, 0, -1] + next_ctx = update_value res_id, {type: 'tpl', slice_of, tpr: lst_id}, ctx [[[opt_expr, res]], next_ctx] optimize_body = fn [expr, res], ctx, optimize_refs: {args: [args, body]} = expr - [o_body, next_ctx] = optimize_refs body, ctx, [] + + body_ctx = match expr: + {f: 'fn'}: + [args_id] = args + update_value args_id, {type: 'tpl'}, ctx + else: + ctx + + [o_body, next_ctx] = optimize_refs body, body_ctx, [] [[[{...expr, args: [args, o_body]}, res]], next_ctx] diff --git a/src/optimize/short-ids.fnk b/src/optimize/short-ids.fnk index 4e7953e..28f5218 100644 --- a/src/optimize/short-ids.fnk +++ b/src/optimize/short-ids.fnk @@ -52,6 +52,13 @@ shorten_names = fn [curr=false, ...rest], renames={}, out=[]: [nres, next_ren] = rename res, renames shorten_names rest, next_ren, [...out, [expr, nres]] + [{f: ? in ['tpl_i', 'tpl_s']}]: + [expr, res] = curr + {args: [tpl_id, ...args]} = expr + [ntpl_id] = replace_refs [tpl_id], renames + [nres, next_ren] = rename res, renames + shorten_names rest, next_ren, [...out, [{...expr, args: [ntpl_id, ...args]}, nres]] + [{f: ? in ['fn', 'cn']}]: [expr, res] = curr [args, body] = expr.args diff --git a/src/optimize/unused.fnk b/src/optimize/unused.fnk index 0290fa9..424934a 100644 --- a/src/optimize/unused.fnk +++ b/src/optimize/unused.fnk @@ -8,6 +8,9 @@ get_ref_args = fn [{f: op, args}]: match op: ? in ['int', 'float', 'str']: [] + ? in ['tpl_i', 'tpl_s']: + [tpl_id] = args + [tpl_id] else: args