diff --git a/deno.lock b/deno.lock index 5393f70..e3496b3 100644 --- a/deno.lock +++ b/deno.lock @@ -1496,8 +1496,8 @@ "npm:@eslint/js@^9.11.1", "npm:@types/babel__code-frame@^7.0.6", "npm:@types/json-stable-stringify@^1.1.0", - "npm:@types/node@^22.10.1", - "npm:@types/react-dom@^19.0.1", + "npm:@types/node@^22.10.2", + "npm:@types/react-dom@^19.0.2", "npm:@types/react@^19.0.1", "npm:@uiw/codemirror-theme-abcdef@^4.23.6", "npm:@uiw/react-codemirror@^4.23.6", diff --git a/examples/arrow-function-1.ts.md b/examples/arrow-function-1.ts.md index 78a2c03..51b9531 100644 --- a/examples/arrow-function-1.ts.md +++ b/examples/arrow-function-1.ts.md @@ -13,8 +13,8 @@ const h = (x) => x((x) => f(x)); ### Output Program ```typescript -export const f_2 = (x_8) => x_8; -export const g_4 = (x_9) => f_2(x_9); -export const h_6 = (x_10) => x_10((x_11) => f_2(x_11)); +export const f_2 = (x_9) => x_9; +export const g_4 = (x_12) => f_2(x_12); +export const h_6 = (x_15) => x_15((x_18) => f_2(x_18)); ``` diff --git a/examples/arrow-function-3.ts.md b/examples/arrow-function-3.ts.md index 26fcbb2..36c3c70 100644 --- a/examples/arrow-function-3.ts.md +++ b/examples/arrow-function-3.ts.md @@ -13,8 +13,8 @@ const foo = (x) => { ### Output Program ```typescript -export const foo_2 = (x_4) => { - const bar_5 = x_4(13); +export const foo_2 = (x_5) => { + const bar_7 = x_5(13); }; ``` diff --git a/examples/arrow-function-4.ts.md b/examples/arrow-function-4.ts.md index 8644b64..5c1972d 100644 --- a/examples/arrow-function-4.ts.md +++ b/examples/arrow-function-4.ts.md @@ -13,8 +13,8 @@ const foo = (x) => { ### Output Program ```typescript -export const foo_2 = (x_4) => { - x_4; +export const foo_2 = (x_5) => { + x_5; }; ``` diff --git a/examples/arrow-function-5.ts.md b/examples/arrow-function-5.ts.md index b7eeffa..e16a9e9 100644 --- a/examples/arrow-function-5.ts.md +++ b/examples/arrow-function-5.ts.md @@ -15,8 +15,8 @@ const foo = (x) => { ### Output Program ```typescript -export const foo_2 = (x_4) => { - x_4; +export const foo_2 = (x_5) => { + x_5; }; ``` diff --git a/examples/confused-parens-with-calls.ts.md b/examples/confused-parens-with-calls.ts.md index 794a0d3..14e42c0 100644 --- a/examples/confused-parens-with-calls.ts.md +++ b/examples/confused-parens-with-calls.ts.md @@ -18,9 +18,9 @@ const foo = (x) => { ### Output Program ```typescript -export const foo_2 = (x_4) => { - x_4; - x_4; +export const foo_2 = (x_5) => { + x_5; + x_5; }; ``` diff --git a/examples/curry-1.ts.md b/examples/curry-1.ts.md index 6247425..686812e 100644 --- a/examples/curry-1.ts.md +++ b/examples/curry-1.ts.md @@ -16,6 +16,6 @@ using_rewrite_rules( ### Output Program ```typescript -(a_5) => (b_7) => (c_9) => (d_11) => a_5 + b_7 + c_9 + d_11; +(a_6) => (b_10) => (c_14) => (d_18) => a_6 + b_10 + c_14 + d_18; ``` diff --git a/examples/curry-2.ts.md b/examples/curry-2.ts.md index 9692825..8ac692c 100644 --- a/examples/curry-2.ts.md +++ b/examples/curry-2.ts.md @@ -19,6 +19,6 @@ const curried = ### Output Program ```typescript -export const curried_3 = (a_6) => (b_8) => (c_10) => (d_12) => a_6 + b_8 + c_10 + d_12; +export const curried_3 = (a_7) => (b_11) => (c_15) => (d_19) => a_7 + b_11 + c_15 + d_19; ``` diff --git a/examples/expr-dot-where.ts.md b/examples/expr-dot-where.ts.md index fa9187e..627da55 100644 --- a/examples/expr-dot-where.ts.md +++ b/examples/expr-dot-where.ts.md @@ -20,6 +20,6 @@ console.log(x + y).where(x = 1, y = x + 2); ### Output Program ```typescript -((x_4) => ((y_6) => console.log(x_4 + y_6))(x_4 + 2))(1); +((x_5) => ((y_9) => console.log(x_5 + y_9))(x_5 + 2))(1); ``` diff --git a/examples/lexical-declarations-1.ts.md b/examples/lexical-declarations-1.ts.md index a62b8d9..25ee8aa 100644 --- a/examples/lexical-declarations-1.ts.md +++ b/examples/lexical-declarations-1.ts.md @@ -21,8 +21,8 @@ export const y_4 = 13, z_6: t_2 = y_4, q_8: t_2, r_10; -export const x_12 = (z_14) => { - const t_15 = z_14; +export const x_12 = (z_15) => { + const t_17 = z_15; }; ``` diff --git a/examples/macro-generating-macro-1.ts.md b/examples/macro-generating-macro-1.ts.md index 2855eb6..cab8057 100644 --- a/examples/macro-generating-macro-1.ts.md +++ b/examples/macro-generating-macro-1.ts.md @@ -15,6 +15,6 @@ using_rewrite_rules( ### Output Program ```typescript -(x_4) => (x_8) => x_8 + x_4; +(x_5) => (x_11) => x_11 + x_5; ``` diff --git a/examples/macro-generating-macro-2.ts.md b/examples/macro-generating-macro-2.ts.md index a2eb0a9..988a633 100644 --- a/examples/macro-generating-macro-2.ts.md +++ b/examples/macro-generating-macro-2.ts.md @@ -22,9 +22,9 @@ using_rewrite_rules( ### Output Program ```typescript -(x_4) => { - const using_rewrite_rules_5 = 10; - (x_10) => x_10 + x_4; +(x_5) => { + const using_rewrite_rules_7 = 10; + (x_13) => x_13 + x_5; }; ``` diff --git a/examples/not-test-1.ts.md b/examples/not-test-1.ts.md index 61f3703..bfa3cb8 100644 --- a/examples/not-test-1.ts.md +++ b/examples/not-test-1.ts.md @@ -15,6 +15,6 @@ using_rewrite_rules( ### Output Program ```typescript -1 ? !3 : (x_9) => !x_9; +1 ? !3 : (x_10) => !x_10; ``` diff --git a/examples/splice-2.ts.md b/examples/splice-2.ts.md index 7dd87f1..f1e2811 100644 --- a/examples/splice-2.ts.md +++ b/examples/splice-2.ts.md @@ -16,9 +16,9 @@ const foo = (x) => { ### Output Program ```typescript -export const foo_2 = (x_4) => { - x_4; - x_4; +export const foo_2 = (x_5) => { + x_5; + x_5; }; ``` diff --git a/examples/using-rewrite-rules-3.ts.md b/examples/using-rewrite-rules-3.ts.md index c425b77..2a88269 100644 --- a/examples/using-rewrite-rules-3.ts.md +++ b/examples/using-rewrite-rules-3.ts.md @@ -15,7 +15,7 @@ const x = 12; ### Output Program ```typescript -(foo_7) => x_5 + x_5; +(foo_8) => x_5 + x_5; export const x_5 = 12; ``` diff --git a/examples/using-rewrite-rules-4.ts.md b/examples/using-rewrite-rules-4.ts.md index 4d744b3..5591071 100644 --- a/examples/using-rewrite-rules-4.ts.md +++ b/examples/using-rewrite-rules-4.ts.md @@ -16,7 +16,7 @@ const x = 12; ### Output Program ```typescript -x_6 + ((foo_8, foo_10) => foo_10 + foo_8); +x_6 + ((foo_9, foo_11) => foo_11 + foo_9); export const x_6 = 12; ``` diff --git a/rtsc/.rts/testing-file-extensions.rts.json b/rtsc/.rts/testing-file-extensions.rts.json index cda34e9..bc881a2 100644 --- a/rtsc/.rts/testing-file-extensions.rts.json +++ b/rtsc/.rts/testing-file-extensions.rts.json @@ -1,6 +1,6 @@ { "cid": "rtsc/testing-file-extensions.rts rewrite-ts-visualized 0.0.0", - "cookie": "rewrite-ts-007", + "cookie": "rewrite-ts-008", "exported_identifiers": { "x": [ { diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..7a5d3c3 --- /dev/null +++ b/src/data.ts @@ -0,0 +1,20 @@ +import { preexpand_helpers } from "./preexpand-helpers"; +import { import_req, lexical_extension, modular_extension } from "./stx"; +import { CompilationUnit, Context, Loc } from "./syntax-structures"; + +export type data = { + loc: Loc; + lexical: lexical_extension; + context: Context; + counter: number; + unit: CompilationUnit; + helpers: preexpand_helpers; + imp: import_req; + modular: modular_extension; +}; + +export type walker = (data: data) => Promise; + +export type walkerplus = (data: data & T) => Promise; + +export type swalker = (data: data) => data; diff --git a/src/expander.ts b/src/expander.ts index eb41bb4..a570a63 100644 --- a/src/expander.ts +++ b/src/expander.ts @@ -25,8 +25,9 @@ import { import { apply_syntax_rules, core_handlers } from "./syntax-core-patterns"; import { debug, in_isolation, syntax_error } from "./stx-error"; import { array_to_ll, join_separated, llappend } from "./llhelpers"; -import { gen_binding, goodies, preexpand_list_handlers } from "./preexpand-handlers"; +import { gen_binding, preexpand_list_handlers } from "./preexpand-handlers"; import { preexpand_helpers } from "./preexpand-helpers"; +import { data, swalker, walker, walkerplus } from "./data"; export function initial_step( ast: AST, @@ -45,24 +46,25 @@ export function initial_step( const { stx, counter, unit, rib, rib_id } = init_top_level(ast, cu_id, globals, global_macros); const initial_loc: Loc = mkzipper(stx); const lexical: lexical_extension = { extensible: true, rib, rib_id }; + const empty_rib: Rib = { type: "rib", normal_env: {}, types_env: {} }; + const modular: modular_extension = { extensible: true, explicit: empty_rib, implicit: empty_rib }; const context: Context = {}; const imp: import_req = {}; + const data = { loc: initial_loc, unit, context, imp, counter, lexical, modular }; return [ initial_loc, (helpers: preexpand_helpers) => - expand_program(initial_loc, unit, context, imp, counter, lexical, helpers).then( - async ({ loc, unit, context, modular, imp }) => { - const import_code = await generate_imports(imp, helpers); - assert(loc.t.tag === "program"); - assert(loc.p.type === "top"); - const new_program: STX = { - ...loc.t, - wrap: empty_wrap, - content: llappend(array_to_ll(import_code), loc.t.content), - }; - return { loc: mkzipper(new_program), unit, context, modular }; - }, - ), + expand_program({ ...data, helpers }).then(async ({ loc, imp, ...data }) => { + const import_code = await generate_imports(imp, helpers); + assert(loc.t.tag === "program"); + assert(loc.p.type === "top"); + const new_program: STX = { + ...loc.t, + wrap: empty_wrap, + content: llappend(array_to_ll(import_code), loc.t.content), + }; + return { loc: mkzipper(new_program), ...data }; + }), ]; } @@ -130,15 +132,7 @@ async function generate_imports(imp: import_req, helpers: preexpand_helpers): Pr return Promise.all(Object.entries(imp).map(([cuid, bindings]) => generate(cuid, bindings))); } -async function expand_program( - loc: Loc, - unit: CompilationUnit, - context: Context, - imp: import_req, - counter: number, - lexical: lexical_extension, - helpers: preexpand_helpers, -): Promise<{ +async function expand_program({ loc, ...data }: data): Promise<{ loc: Loc; unit: CompilationUnit; context: Context; @@ -146,33 +140,24 @@ async function expand_program( imp: import_req; }> { async function expand(loc: Loc) { - return preexpand_body(loc, lexical, unit, context, counter, "value", helpers).then( - ({ loc, lexical, counter, context, unit }) => { - // rib is filled - // context is filled also - const new_unit = extend_unit(unit, lexical); - const modular: modular_extension = { - extensible: true, - explicit: { type: "rib", normal_env: {}, types_env: {} }, - implicit: { type: "rib", normal_env: {}, types_env: {} }, - }; - return helpers.inspect(loc, "After preexpanding the program", () => - postexpand_program(loc, modular, new_unit, counter, context, imp, helpers).then( - ({ loc, modular, imp, counter }) => { - return { loc, unit: new_unit, context, modular, imp, counter }; - }, - ), - ); - }, - ); + return preexpand_body({ + loc, + sort: "value", + ...data, + }).then(({ loc, lexical, unit, ...new_data }) => { + // rib is filled + // context is filled also + const new_unit = extend_unit(unit, lexical); + return data.helpers.inspect(loc, "After preexpanding the program", () => + postexpand_program({ loc, ...data, ...new_data, unit: new_unit, lexical }).then( + ({ loc, ...new_new_data }) => { + return { ...new_data, ...new_new_data, loc, unit: new_unit }; + }, + ), + ); + }); } async function expand_empty_program() { - const empty_rib: Rib = { type: "rib", normal_env: {}, types_env: {} }; - const modular: modular_extension = { - extensible: true, - implicit: empty_rib, - explicit: empty_rib, - }; const empty_export: STX = { type: "list", tag: "export_declaration", @@ -187,75 +172,29 @@ async function expand_program( content: array_to_ll([empty_export]), src: false, }; - return { loc: mkzipper(empty_program), unit, context, modular, imp, counter }; + return { loc: mkzipper(empty_program), ...data }; } if (loc.t.tag !== "program") syntax_error(loc, "expected a program"); return go_down(loc, expand, expand_empty_program); } -async function preexpand_body( - loc: Loc, - lexical: lexical_extension, - unit: CompilationUnit, - context: Context, - counter: number, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise { - return in_isolation( - loc, - (loc) => preexpand_forms(loc, lexical, counter, unit, context, sort, helpers), - (loc, { lexical, context, counter, unit }) => - go_next( - loc, - (loc) => preexpand_body(loc, lexical, unit, context, counter, sort, helpers), - (loc) => Promise.resolve({ loc, lexical, context, counter, unit }), - ), +const preexpand_body: walkerplus<{ sort: "type" | "value" }> = async ({ loc, sort, ...data }) => + in_isolation(loc, (loc) => preexpand_forms(sort)({ loc, ...data })).then(({ loc, ...data }) => + go_next( + loc, + (loc) => preexpand_body({ loc, sort, ...data }), + (loc) => Promise.resolve({ loc, ...data }), + ), ); -} -async function preexpand_body_curly( - loc: Loc, - lexical: lexical_extension, - unit: CompilationUnit, - context: Context, - counter: number, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise { - if (loc.t.type === "atom" && loc.t.tag === "other" && loc.t.content === "}") { - return go_right(loc, syntax_error, () => - Promise.resolve({ - loc: go_up(loc), - context, - counter, - lexical, - unit, - }), - ); - } - return in_isolation( - loc, - (loc) => preexpand_forms(loc, lexical, counter, unit, context, sort, helpers), - (loc, { lexical, context, counter, unit }) => { - return go_right( - loc, - (loc) => preexpand_body_curly(loc, lexical, unit, context, counter, sort, helpers), - (loc) => syntax_error(loc, "no right"), +const preexpand_body_curly: walker = async ({ loc, ...data }) => + loc.t.content === "}" + ? go_right(loc, syntax_error, () => ({ loc: go_up(loc), ...data })) + : in_isolation(loc, (loc) => preexpand_forms("value")({ loc, ...data })).then( + ({ loc, ...data }) => go_right(loc, (loc) => preexpand_body_curly({ loc, ...data })), ); - }, - ); -} -async function handle_core_syntax( - loc: Loc, - name: string, - context: Context, - unit: CompilationUnit, - counter: number, - lexical: lexical_extension, - helpers: preexpand_helpers, -): Promise<{ +async function handle_core_syntax({ name, ...data }: data & { name: string }): Promise<{ loc: Loc; counter: number; unit: CompilationUnit; @@ -264,7 +203,7 @@ async function handle_core_syntax( }> { const handler = core_handlers[name]; assert(handler !== undefined); - return handler(loc, context, unit, counter, lexical, helpers); + return handler(data); } const atom_handlers_table: { [tag in atom_tag]: "next" | "stop" } = { @@ -324,63 +263,36 @@ const list_handlers_table: { [tag in list_tag]: "descend" | "stop" | "todo" } = syntax_list: "descend", }; -async function preexpand_block( - loc: Loc, - lexical: lexical_extension, - counter: number, - unit: CompilationUnit, - context: Context, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise { +const preexpand_block: walker = async ({ loc, ...data }) => { assert(loc.t.type === "list" && loc.t.tag === "statement_block"); const bodies = go_down(loc, itself, (loc) => syntax_error(loc, "no bodies")); assert(bodies.t.type === "atom" && bodies.t.tag === "other" && bodies.t.content === "{"); const bodies_rest = go_right(bodies, itself, (loc) => syntax_error(loc, "no body rest")); - const gs = await preexpand_body_curly( - bodies_rest, - lexical, - unit, - context, - counter, - sort, - helpers, - ); + const gs = await preexpand_body_curly({ loc: bodies_rest, ...data }); assert(gs.loc.t.type === "list" && gs.loc.t.tag === "statement_block"); return gs; -} +}; -async function expand_concise_body( - loc: Loc, - lexical: lexical_extension, - counter: number, - unit: CompilationUnit, - context: Context, - imp: import_req, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise<{ loc: Loc; imp: import_req; counter: number }> { - const gs = await (loc.t.type === "list" && loc.t.tag === "statement_block" - ? preexpand_block(loc, lexical, counter, unit, context, sort, helpers).then(({ loc, ...gs }) => - go_down( - loc, - (loc) => ({ ...gs, loc }), - (loc) => debug(loc, "???"), - ), - ) - : preexpand_forms(loc, lexical, counter, unit, context, sort, helpers)); - const new_unit = extend_unit(gs.unit, gs.lexical); - return postexpand_body( - gs.loc, - { extensible: false }, - new_unit, - gs.counter, - gs.context, - imp, - sort, - helpers, - ); -} +const non_modular: (walker: walker) => walker = + (walker) => + ({ modular, ...data }) => + walker({ ...data, modular: { extensible: false } }).then((data) => ({ ...data, modular })); + +const preexpand_concise_body: walker = ({ loc, ...data }) => + loc.t.tag === "statement_block" + ? preexpand_block({ ...data, loc }) + : preexpand_forms("value")({ ...data, loc }); + +const postexpand_concise_body: walker = ({ loc, ...data }) => + loc.t.tag === "statement_block" + ? go_down(loc, (loc) => postexpand_body("value")({ loc, ...data })) + : postexpand_body("value")({ loc, ...data }); + +const expand_concise_body = non_modular((data) => + preexpand_concise_body(data) + .then(({ unit, lexical, ...data }) => ({ ...data, lexical, unit: extend_unit(unit, lexical) })) + .then(postexpand_concise_body), +); function rewrap(loc: Loc, rib_id: string, cu_id: string): Loc { return { @@ -390,119 +302,115 @@ function rewrap(loc: Loc, rib_id: string, cu_id: string): Loc { }; } -async function preexpand_forms( - loc: Loc, - lexical: lexical_extension, - counter: number, - unit: CompilationUnit, - context: Context, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise { - function done(loc: Loc): Promise { - return Promise.resolve({ - loc, - lexical, - context, - counter, - unit, - }); - } - function next(loc: Loc): Promise { - return go_next(loc, (loc) => h(find_form(loc)), done); - } - function descend(loc: Loc): Promise { - return go_down(loc, (loc) => h(find_form(loc)), syntax_error); - } - async function h(ffrv: ffrv): Promise { - const loc = ffrv.loc; - switch (ffrv.type) { - case "done": - return done(loc); - case "identifier": { - assert(loc.t.type === "atom" && loc.t.tag === "identifier", loc.t); - const { content, wrap } = loc.t; - const resolution = await resolve(content, wrap, context, unit, sort_env[sort], helpers); - switch (resolution.type) { - case "unbound": - return next(loc); - case "bound": { - const binding = resolution.binding; - switch (binding.type) { - case "lexical": - case "type": - case "ts": - case "imported_lexical": - return next(loc); - case "core_syntax": { - const { name } = binding; - return helpers.inspect(loc, "core form", () => - handle_core_syntax(loc, name, context, unit, counter, lexical, helpers).then( - ({ loc, counter, unit, context, lexical }) => - helpers.inspect(loc, `core output`, () => - preexpand_forms(loc, lexical, counter, unit, context, sort, helpers), +const preexpand_forms = + (sort: "type" | "value") => + async ({ loc, ...data }: data) => { + function done(loc: Loc): Promise { + return Promise.resolve({ loc, ...data }); + } + function next(loc: Loc): Promise { + return go_next(loc, (loc) => h(find_form(loc)), done); + } + function descend(loc: Loc): Promise { + return go_down(loc, (loc) => h(find_form(loc)), syntax_error); + } + async function h(ffrv: ffrv): Promise { + const loc = ffrv.loc; + switch (ffrv.type) { + case "done": + return done(loc); + case "identifier": { + assert(loc.t.type === "atom" && loc.t.tag === "identifier", loc.t); + const { content, wrap } = loc.t; + const resolution = await resolve( + content, + wrap, + data.context, + data.unit, + sort_env[sort], + data.helpers, + ); + switch (resolution.type) { + case "unbound": + return next(loc); + case "bound": { + const binding = resolution.binding; + switch (binding.type) { + case "lexical": + case "type": + case "ts": + case "imported_lexical": + return next(loc); + case "core_syntax": { + const { name } = binding; + return data.helpers.inspect(loc, "core form", () => + handle_core_syntax({ ...data, loc, name }).then(({ loc, ...new_data }) => + data.helpers.inspect(loc, `core output`, () => + preexpand_forms(sort)({ loc, ...data, ...new_data }), ), - ), - ); - } - case "syntax_rules_transformer": { - const { clauses } = binding; - return helpers.inspect(loc, `transformer form`, () => - apply_syntax_rules(loc, clauses, unit, counter, helpers).then( - ({ loc, counter }) => { - const rewrapped = lexical.extensible - ? rewrap(loc, lexical.rib_id, unit.cu_id) - : loc; - return helpers.inspect(rewrapped, `transformer output`, () => - preexpand_forms(rewrapped, lexical, counter, unit, context, sort, helpers), - ); - }, - ), - ); + ), + ); + } + case "syntax_rules_transformer": { + const { clauses } = binding; + return data.helpers.inspect(loc, `transformer form`, () => + apply_syntax_rules(loc, clauses, data.unit, data.counter, data.helpers).then( + ({ loc, counter }) => { + const rewrapped = data.lexical.extensible + ? rewrap(loc, data.lexical.rib_id, data.unit.cu_id) + : loc; + return data.helpers.inspect(rewrapped, `transformer output`, () => + preexpand_forms(sort)({ loc: rewrapped, ...data, counter }), + ); + }, + ), + ); + } + default: + const invalid: never = binding; + throw invalid; } - default: - const invalid: never = binding; - throw invalid; } + case "error": + syntax_error(loc, resolution.reason); + default: + const invalid: never = resolution; + throw invalid; } - case "error": - syntax_error(loc, resolution.reason); - default: - const invalid: never = resolution; - throw invalid; } - } - case "list": { - assert(loc.t.type === "list"); - const h = preexpand_list_handlers[loc.t.tag]; - if (h) { - return h({ loc, lexical, counter, unit, context }, helpers).then( - ({ loc, lexical, counter, unit, context }) => + case "list": { + assert(loc.t.type === "list"); + const h = preexpand_list_handlers[loc.t.tag]; + if (h) { + return h({ loc, ...data }).then(({ loc, ...data }) => go_next( loc, - (loc) => preexpand_forms(loc, lexical, counter, unit, context, sort, helpers), - (loc) => Promise.resolve({ loc, lexical, counter, unit, context }), + (loc) => preexpand_forms(sort)({ loc, ...data }), + (loc) => Promise.resolve({ loc, ...data }), ), - ); - } - switch (loc.t.tag) { - case "arrow_function": - return next(loc); - case "member_expression": - return descend(loc); - default: { - if (list_handlers_table[loc.t.tag] === "todo") { - debug(loc, `todo list handler for '${loc.t.tag}'`); + ); + } + switch (loc.t.tag) { + case "arrow_function": + return next(loc); + case "member_expression": + return descend(loc); + default: { + if (list_handlers_table[loc.t.tag] === "todo") { + debug(loc, `todo list handler for '${loc.t.tag}'`); + } + assert( + list_handlers_table[loc.t.tag] === "descend", + `non descend tag '${loc.t.tag}'`, + ); + return next(loc); } - assert(list_handlers_table[loc.t.tag] === "descend", `non descend tag '${loc.t.tag}'`); - return next(loc); } } } } - } - return h(find_form(loc)); -} + return h(find_form(loc)); + }; type ffrv = | { type: "done"; loc: Loc } @@ -561,103 +469,71 @@ function find_form(loc: Loc): ffrv { return find_form(loc); } -function postexpand_program( - loc: Loc, - modular: modular_extension, - unit: CompilationUnit, - counter: number, - context: Context, - imp: import_req, - helpers: preexpand_helpers, -): Promise<{ loc: Loc; modular: modular_extension; counter: number; imp: import_req }> { - assert(loc.t.tag === "program"); - return go_down(loc, (loc) => - postexpand_body(loc, modular, unit, counter, context, imp, "value", helpers), - ); -} - -function invalid_form(loc: Loc): never { - syntax_error(loc, "invalid form"); -} +const postexpand_program: walker = ({ loc, ...data }: data) => + go_down(loc, (loc) => postexpand_body("value")({ loc, ...data })); function itself(loc: Loc): Loc { return loc; } -function extract_parameters(goodies: goodies): goodies { +const extract_parameters: swalker = (data) => { // - function tail(goodies: goodies): goodies { - const loc = goodies.loc; - switch (loc.t.type) { - case "atom": { - switch (loc.t.tag) { - case "other": { - switch (loc.t.content) { - case ",": - return go_right(loc, (loc) => head({ ...goodies, loc }), invalid_form); - case ")": - return go_right(loc, invalid_form, (loc) => ({ ...goodies, loc: go_up(loc) })); - } - } - } - } + const tail: swalker = ({ loc, ...data }) => { + switch (loc.t.content) { + case ",": + return go_right(loc, (loc) => head({ ...data, loc })); + case ")": + return go_right(loc, syntax_error, (loc) => ({ ...data, loc: go_up(loc) })); + default: + syntax_error(loc); } - syntax_error(loc); - } + }; - function head(goodies: goodies): goodies { - const loc = goodies.loc; - switch (loc.t.type) { - case "atom": { - switch (loc.t.tag) { - case "identifier": { - const gs = identifier(goodies); - return go_right(gs.loc, (loc) => tail({ ...gs, loc }), invalid_form); - } - case "other": { - switch (loc.t.content) { - case ",": - return invalid_form(loc); - case ")": - return go_right(loc, invalid_form, (loc) => ({ ...goodies, loc: go_up(loc) })); - } - } + const head: swalker = ({ loc, ...data }) => { + switch (loc.t.tag) { + case "identifier": { + const gs = identifier({ loc, ...data }); + return go_right(gs.loc, (loc) => tail({ ...gs, loc })); + } + case "other": { + switch (loc.t.content) { + case ",": + return syntax_error(loc); + case ")": + return go_right(loc, syntax_error, (loc) => ({ ...data, loc: go_up(loc) })); } } } syntax_error(loc); - } + }; - function identifier(goodies: goodies): goodies { - const id = goodies.loc.t; + const identifier: swalker = (data) => { + const id = data.loc.t; assert(id.type === "atom" && id.tag === "identifier"); - const { name, ...gs } = gen_binding({ ...goodies, sort: "value" }); - return { ...gs, loc: rename(goodies.loc, name) }; - } + const { name, ...gs } = gen_binding({ ...data, sort: "value" }); + return { ...data, ...gs, loc: rename(data.loc, name) }; + }; - function first_param(goodies: goodies): goodies { - switch (goodies.loc.t.type) { - case "atom": { - switch (goodies.loc.t.tag) { - case "identifier": - const gs = identifier(goodies); - return go_right(gs.loc, invalid_form, (loc) => ({ ...gs, loc: go_up(loc) })); - case "other": { - if (goodies.loc.t.content === "(") { - return go_right(goodies.loc, (loc) => head({ ...goodies, loc }), invalid_form); - } - } + const first_param: swalker = (data) => { + switch (data.loc.t.tag) { + case "identifier": + const gs = identifier(data); + return go_right(gs.loc, syntax_error, (loc) => ({ ...gs, loc: go_up(loc) })); + case "other": { + if (data.loc.t.content === "(") { + return go_right(data.loc, (loc) => head({ ...data, loc })); } - return syntax_error(goodies.loc); } + default: + syntax_error(data.loc); } - debug(goodies.loc, "non atom first_param"); - } + }; + { - assert(goodies.loc.t.type === "list" && goodies.loc.t.tag === "formal_parameters"); - return go_down(goodies.loc, (loc) => first_param({ ...goodies, loc }), invalid_form); + assert(data.loc.t.type === "list" && data.loc.t.tag === "formal_parameters"); + return go_down(data.loc, (loc) => first_param({ ...data, loc })); } -} +}; function check_punct(loc: Loc, content: string) { if (loc.t.type !== "atom" || loc.t.tag !== "other" || loc.t.content !== content) { @@ -665,99 +541,55 @@ function check_punct(loc: Loc, content: string) { } } -function expand_arrow_function( - loc: Loc, - counter: number, - context: Context, - imp: import_req, - unit: CompilationUnit, - helpers: preexpand_helpers, -): Promise<{ loc: Loc; imp: import_req; counter: number }> { - return go_down( - loc, - (loc) => { - const [rib_id, new_counter] = new_rib_id(counter); - const lexical: lexical_extension = { - extensible: true, - rib_id, - rib: { type: "rib", normal_env: {}, types_env: {} }, +const expand_arrow_function: walker = ({ loc, counter, ...data }) => + go_down(loc, (loc) => { + const [rib_id, new_counter] = new_rib_id(counter); + const lexical: lexical_extension = { + extensible: true, + rib_id, + rib: { type: "rib", normal_env: {}, types_env: {} }, + }; + const pgs = extract_parameters({ ...data, loc, lexical, counter: new_counter }); + const arr = go_right(pgs.loc, itself); + check_punct(arr, "=>"); + const body = go_right(arr, itself); + return in_isolation(body, (body) => { + const wrap: Wrap = { + marks: null, + subst: [{ rib_id, cu_id: pgs.unit.cu_id }, null], + aes: null, }; - const pgs = extract_parameters({ loc, lexical, counter, context, unit }); - const arr = go_right(pgs.loc, itself, invalid_form); - check_punct(arr, "=>"); - const body = go_right(arr, itself, invalid_form); - return in_isolation( - body, - async (body) => { - const wrap: Wrap = { - marks: null, - subst: [{ rib_id, cu_id: unit.cu_id }, null], - aes: null, - }; - const loc = wrap_loc(body, wrap); - const new_unit = extend_unit(pgs.unit, pgs.lexical); // params are in rib - return expand_concise_body( - loc, - pgs.lexical, - new_counter, - new_unit, - pgs.context, - imp, - "value", - helpers, - ); - }, - (loc, { imp, counter }) => ({ loc, imp, counter }), - ); - }, - invalid_form, - ); -} + return expand_concise_body({ + ...pgs, + loc: wrap_loc(body, wrap), + unit: extend_unit(pgs.unit, pgs.lexical), + }); + }); + }); -function expand_type_parameters( - loc: Loc, - unit: CompilationUnit, - orig_counter: number, - context: Context, - imp: import_req, - helpers: preexpand_helpers, -): Promise { - type T = Promise; - function post_after_var({ - loc, - lexical, - counter, - unit, - context, - imp, - }: goodies & { imp: import_req }): T { +const expand_type_parameters: walker = ({ loc, ...data }) => { + // + const post_after_var: walker = ({ loc, ...data }) => { return go_right( loc, (loc) => { assert(loc.t.content === ","); return go_right( loc, - (loc) => post_var({ loc, lexical, counter, unit, context, imp }), + (loc) => post_var({ loc, ...data }), (loc) => { debug(loc, "cant go past commma2?"); }, ); }, - (loc) => end({ loc: go_up(loc), lexical, unit, counter, context, imp }), + (loc) => end({ loc: go_up(loc), ...data }), ); - } + }; - function post_var({ - loc, - lexical, - counter, - unit, - context, - imp, - }: goodies & { imp: import_req }): T { + const post_var: walker = ({ loc, lexical, ...data }) => { switch (loc.t.tag) { case "identifier": - return post_after_var({ loc, lexical, counter, unit, context, imp }); + return post_after_var({ loc, lexical, ...data }); case "type_parameter": return go_down(loc, (loc) => { assert(loc.t.tag === "identifier"); @@ -765,22 +597,16 @@ function expand_type_parameters( if (loc.t.content !== "extends") syntax_error(loc, "expected 'extends'"); assert(lexical.extensible); return go_right(loc, (loc) => - expand_expr( - wrap_loc(loc, { + expand_expr("type")({ + loc: wrap_loc(loc, { marks: null, - subst: [{ rib_id: lexical.rib_id, cu_id: unit.cu_id }, null], + subst: [{ rib_id: lexical.rib_id, cu_id: data.unit.cu_id }, null], aes: null, }), - counter, - unit, - context, - imp, - "type", - helpers, - ).then(({ loc, counter, unit, context, imp }) => - go_right(loc, syntax_error, () => - post_after_var({ loc: go_up(loc), lexical, counter, unit, context, imp }), - ), + lexical, + ...data, + }).then(({ loc, ...data }) => + go_right(loc, syntax_error, () => post_after_var({ loc: go_up(loc), ...data })), ), ); }); @@ -788,16 +614,9 @@ function expand_type_parameters( default: syntax_error(loc); } - } + }; - function pre_after_var({ - loc, - lexical, - counter, - unit, - context, - imp, - }: goodies & { imp: import_req }): T { + const pre_after_var: walker = ({ loc, lexical, counter, unit, ...data }) => { assert(lexical.extensible); return go_right( loc, @@ -805,7 +624,7 @@ function expand_type_parameters( if (loc.t.content !== ",") syntax_error(loc, "expected a comma ','"); return go_right( loc, - (loc) => pre_var({ loc, lexical, counter, unit, context, imp }), + (loc) => pre_var({ loc, lexical, counter, unit, ...data }), (loc) => debug(loc, "cant go past commma?"), ); }, @@ -816,127 +635,54 @@ function expand_type_parameters( lexical, counter, unit: extend_unit(unit, lexical), - context, - imp, + ...data, }), ), ); - } + }; - function pre_var({ - loc, - lexical, - counter, - unit, - context, - imp, - }: goodies & { imp: import_req }): T { + const pre_var: walker = ({ loc, ...data }) => { switch (loc.t.tag) { case "identifier": - const { name, ...gs } = gen_binding({ - loc, - lexical, - counter, - context, - unit, - sort: "type", - }); - return pre_after_var({ ...gs, loc: rename(loc, name), imp }); + const { name, ...gs } = gen_binding({ loc, ...data, sort: "type" }); + return pre_after_var({ ...data, ...gs, loc: rename(loc, name) }); case "type_parameter": return go_down(loc, (loc) => { if (loc.t.tag !== "identifier") syntax_error(loc, "expected an identifier"); - const { name, ...gs } = gen_binding({ - loc, - lexical, - counter, - context, - unit, - sort: "type", - }); - return pre_after_var({ ...gs, loc: go_up(rename(loc, name)), imp }); + const { name, ...gs } = gen_binding({ loc, ...data, sort: "type" }); + return pre_after_var({ ...data, ...gs, loc: go_up(rename(loc, name)) }); }); default: syntax_error(loc); } - } + }; - function start(loc: Loc): T { + const start: walker = ({ loc, counter, ...data }) => { assert(loc.t.tag === "syntax_list"); - - const [rib_id, counter] = new_rib_id(orig_counter); + const [rib_id, new_counter] = new_rib_id(counter); const rib: Rib = { type: "rib", normal_env: {}, types_env: {} }; const lexical: lexical_extension = { extensible: true, rib_id, rib }; return go_down( loc, - (loc) => pre_var({ loc, lexical, unit, counter, context, imp }), - (loc) => end({ loc, unit, lexical, context, counter, imp }), + (loc) => pre_var({ loc, ...data, lexical, counter: new_counter }), + (loc) => end({ loc, ...data, lexical, counter: new_counter }), ); - } + }; - async function end({ - loc, - lexical, - unit, - context, - counter, - imp, - }: goodies & { imp: import_req }): T { - return go_right( - loc, - (loc) => { - assert(loc.t.content === ">"); - return { loc, lexical, unit, counter, context, imp }; - }, - syntax_error, - ); - } + const end: walker = async ({ loc, ...data }) => + go_right(loc, (loc) => { + assert(loc.t.content === ">"); + return { loc, ...data }; + }); assert(loc.t.content === "<"); - return go_right(loc, start, syntax_error); -} + return go_right(loc, (loc) => start({ loc, ...data }), syntax_error); +}; -function expand_expr( - loc: Loc, - counter: number, - unit: CompilationUnit, - context: Context, - imp: import_req, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise & { imp: import_req }> { - return in_isolation( - loc, - async (loc) => { - return preexpand_forms( - loc, - { extensible: false }, - counter, - unit, - context, - sort, - helpers, - ).then(({ loc, unit, counter, context }) => - postexpand_body( - loc, - { extensible: false }, - unit, - counter, - context, - imp, - sort, - helpers, - ).then(({ loc, imp, counter }) => ({ - loc, - unit, - counter, - context, - imp, - })), - ); - }, - (loc, { unit, counter, context, imp }) => ({ loc, unit, counter, context, imp }), +const expand_expr = (sort: "type" | "value") => + non_modular(({ loc, ...data }) => + in_isolation(loc, (loc) => preexpand_forms(sort)({ loc, ...data }).then(postexpand_body(sort))), ); -} const empty_wrap: Wrap = { marks: null, subst: null, aes: null }; @@ -1014,26 +760,17 @@ const as_keyword: STX = { src: false, }; -function insert_export_keyword( - loc: Loc, - counter: number, - modular: modular_extension, - imp: import_req, -): { - loc: Loc; - modular: modular_extension; - counter: number; - imp: import_req; -} { +const insert_export_keyword: swalker = ({ loc, counter, modular, imp, ...data }) => { if (modular.extensible) { assert(loc.t.type === "list"); const content = stx_list_content(loc.t); assert(content !== null); const fst = content[0]; if (fst.content === "export") { - return { loc, modular, imp, counter }; + return { ...data, loc, modular, imp, counter }; } else { return { + ...data, loc: { type: "loc", t: { ...loc.t, content: [export_keyword, content] }, p: loc.p }, modular, imp, @@ -1041,84 +778,61 @@ function insert_export_keyword( }; } } else { - return { loc, modular, counter, imp }; + return { ...data, loc, modular, counter, imp }; } -} +}; -async function postexpand_type_alias_declaration( - loc: Loc, - modular: modular_extension, - unit: CompilationUnit, - counter: number, - context: Context, - imp: import_req, - helpers: preexpand_helpers, -): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - async function do_after_equal( - loc: Loc, - counter: number, - unit: CompilationUnit, - context: Context, - imp: import_req, - ): Promise<{ loc: Loc; imp: import_req; counter: number }> { - return expand_expr(loc, counter, unit, context, imp, "type", helpers).then( - ({ loc, unit: _unit, counter, context: _context, imp }) => { - function done(loc: Loc) { - return { loc: go_up(loc), imp, counter }; - } - return go_right( - loc, - (loc) => { - assert(loc.t.content === ";"); - return go_right(loc, syntax_error, done); - }, - done, - ); - }, - ); +const handle_optional_semi: walker = async ({ loc, ...data }) => { + function done(loc: Loc) { + return { ...data, loc: go_up(loc) }; } - async function do_after_identifier( - loc: Loc, - counter: number, - unit: CompilationUnit, - context: Context, - imp: import_req, - ): Promise<{ loc: Loc; imp: import_req; counter: number }> { + return go_right( + loc, + (loc) => { + assert(loc.t.content === ";"); + return go_right(loc, syntax_error, done); + }, + done, + ); +}; + +const postexpand_type_alias_declaration: walker = async (data) => { + const do_after_equal: walker = (data: data) => + expand_expr("type")(data).then(handle_optional_semi); + const do_after_identifier: walker = async ({ loc, ...data }) => { switch (loc.t.content) { case "=": - return go_right(loc, (loc) => do_after_equal(loc, counter, unit, context, imp)); + return go_right(loc, (loc) => do_after_equal({ loc, ...data })); case "<": - return expand_type_parameters(loc, unit, counter, context, imp, helpers).then( - ({ loc, counter, unit, context, lexical, imp }) => { - assert(loc.t.content === ">"); - assert(lexical.extensible); - return go_right(loc, (loc) => { - if (loc.t.content !== "=") syntax_error(loc, "expected '='"); - return go_right(loc, (loc) => - do_after_equal( - wrap_loc(loc, { - marks: null, - subst: [{ rib_id: lexical.rib_id, cu_id: unit.cu_id }, null], - aes: null, - }), - counter, - unit, - context, - imp, - ), - ); - }); - }, - ); + return expand_type_parameters({ + loc, + ...data, + }).then(({ loc, unit, lexical, ...data }) => { + assert(loc.t.content === ">"); + assert(lexical.extensible); + return go_right(loc, (loc) => { + if (loc.t.content !== "=") syntax_error(loc, "expected '='"); + return go_right(loc, (loc) => + do_after_equal({ + loc: wrap_loc(loc, { + marks: null, + subst: [{ rib_id: lexical.rib_id, cu_id: unit.cu_id }, null], + aes: null, + }), + unit, + lexical, + ...data, + }), + ); + }); + }); default: return syntax_error(loc); } - } + }; - function handle_type( - loc: Loc, - exporting: boolean, - ): Promise<{ loc: Loc; imp: import_req; counter: number; modular: modular_extension }> { + function handle_type(loc: Loc, exporting: boolean): Promise { + const { context, unit, modular, helpers } = data; assert(loc.t.content === "type"); return go_right(loc, async (loc) => { assert(loc.t.tag === "identifier"); @@ -1128,7 +842,7 @@ async function postexpand_type_alias_declaration( assert(resolution.binding.type === "type"); const new_name = resolution.binding.name; const gs = await go_right(rename(loc, new_name), (loc) => - do_after_identifier(loc, counter, unit, context, imp), + do_after_identifier({ ...data, loc }), ); const new_modular = extend_modular( modular, @@ -1139,67 +853,55 @@ async function postexpand_type_alias_declaration( "types_env", loc, ); - return { loc: gs.loc, modular: new_modular, counter: gs.counter, imp: gs.imp }; + return { ...gs, modular: new_modular }; }); } - function handle_export( - loc: Loc, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { + function handle_export(loc: Loc): Promise { assert(loc.t.content === "export"); + const { modular } = data; if (!modular.extensible) syntax_error(loc, "location does not permit export"); return go_right(loc, (loc) => handle_type(loc, true), syntax_error); } - return go_down(loc, (loc) => { - switch (loc.t.content) { - case "type": - return handle_type(loc, false); - case "export": - return handle_export(loc); - default: - syntax_error(loc); - } - }).then(({ loc, modular, imp, counter }) => insert_export_keyword(loc, counter, modular, imp)); -} -async function postexpand_lexical_declaration( - loc: Loc, - modular: modular_extension, - unit: CompilationUnit, - counter: number, - context: Context, - imp: import_req, - helpers: preexpand_helpers, -): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - async function handle_value_initializer( - loc: Loc, - ): Promise<{ loc: Loc; imp: import_req; counter: number }> { + { + const { loc } = data; + return go_down(loc, (loc) => { + switch (loc.t.content) { + case "type": + return handle_type(loc, false); + case "export": + return handle_export(loc); + default: + syntax_error(loc); + } + }).then(insert_export_keyword); + } +}; + +const postexpand_lexical_declaration: walker = async ({ loc, ...data }) => { + async function handle_value_initializer(loc: Loc): Promise { assert(loc.t.content === "="); return go_right( loc, - (loc) => expand_expr(loc, counter, unit, context, imp, "value", helpers), + (loc) => expand_expr("value")({ loc, ...data }), (loc) => syntax_error(loc, "expected an expression following the '=' sign"), ); } - async function handle_type_then_initializer( - loc: Loc, - ): Promise<{ loc: Loc; imp: import_req; counter: number }> { + + async function handle_type_then_initializer(loc: Loc): Promise { assert(loc.t.content === ":"); return go_right( loc, (loc) => - expand_expr(loc, counter, unit, context, imp, "type", helpers).then( - ({ loc, counter, unit: _ignored_unit, context: _ignored_context, imp }) => - go_right(loc, handle_value_initializer, (loc) => - Promise.resolve({ loc, imp, counter }), - ), + expand_expr("type")({ loc, ...data }).then(({ loc, ...data }) => + go_right(loc, handle_value_initializer, (loc) => Promise.resolve({ loc, ...data })), ), (loc) => syntax_error(loc, "expected an expression following the '=' sign"), ); } - async function handle_initializer( - loc: Loc, - ): Promise<{ loc: Loc; imp: import_req; counter: number }> { + + async function handle_initializer(loc: Loc): Promise { switch (loc.t.content) { case "=": return handle_value_initializer(loc); @@ -1209,63 +911,52 @@ async function postexpand_lexical_declaration( syntax_error(loc); } } - async function handle_inner_variable_declarator( - loc: Loc, - exporting: boolean, - modular: modular_extension, - imp: import_req, - counter: number, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - assert(loc.t.tag === "identifier"); - const { content, wrap } = loc.t; - const resolution = await resolve(content, wrap, context, unit, "normal_env", helpers); - assert(resolution.type === "bound"); - assert(resolution.binding.type === "lexical"); - const new_name = resolution.binding.name; - const gs = await go_right( - rename(loc, new_name), - (loc) => handle_initializer(loc), - (loc) => Promise.resolve({ loc, imp, counter }), - ); - return { - loc: go_up(gs.loc), - modular: extend_modular( - modular, - exporting, + + function handle_declaration_list(exporting: boolean) { + // + async function handle_inner_variable_declarator(loc: Loc): Promise { + assert(loc.t.tag === "identifier"); + const { content, wrap } = loc.t; + const resolution = await resolve( content, - wrap.marks, - resolution.label, + wrap, + data.context, + data.unit, "normal_env", - loc, - ), - imp: gs.imp, - counter: gs.counter, - }; - } - async function handle_variable_declarator( - loc: Loc, - exporting: boolean, - modular: modular_extension, - imp: import_req, - counter: number, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - assert(loc.t.tag === "variable_declarator"); - return go_down( - loc, - (loc) => handle_inner_variable_declarator(loc, exporting, modular, imp, counter), - syntax_error, - ); - } - async function handle_declarations( - loc: Loc, - exporting: boolean, - modular: modular_extension, - imp: import_req, - counter: number, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - if (loc.t.tag === "variable_declarator") { - return handle_variable_declarator(loc, exporting, modular, imp, counter).then( - ({ loc, modular, imp, counter }) => + data.helpers, + ); + assert(resolution.type === "bound"); + assert(resolution.binding.type === "lexical"); + const new_name = resolution.binding.name; + const gs = await go_right( + rename(loc, new_name), + (loc) => handle_initializer(loc), + (loc) => Promise.resolve({ ...data, loc }), + ); + return { + ...data, + ...gs, + loc: go_up(gs.loc), + modular: extend_modular( + data.modular, + exporting, + content, + wrap.marks, + resolution.label, + "normal_env", + loc, + ), + }; + } + + async function handle_variable_declarator(loc: Loc): Promise { + assert(loc.t.tag === "variable_declarator"); + return go_down(loc, (loc) => handle_inner_variable_declarator(loc)); + } + + async function handle_declarations(loc: Loc): Promise { + if (loc.t.tag === "variable_declarator") { + return handle_variable_declarator(loc).then(({ loc, ...data }) => go_right( loc, (loc) => { @@ -1273,58 +964,47 @@ async function postexpand_lexical_declaration( case ",": return go_right( loc, - (loc) => handle_declarations(loc, exporting, modular, imp, counter), - (loc) => Promise.resolve({ loc: go_up(loc), modular, imp, counter }), + (loc) => handle_declarations(loc), + (loc) => Promise.resolve({ loc: go_up(loc), ...data }), ); case ";": - return Promise.resolve({ loc: go_up(loc), modular, imp, counter }); + return Promise.resolve({ loc: go_up(loc), ...data }); default: syntax_error(loc); } }, - (loc) => Promise.resolve({ loc: go_up(loc), modular, imp, counter }), + (loc) => Promise.resolve({ loc: go_up(loc), ...data }), ), - ); + ); + } + debug(loc, "handle_declarations"); } - debug(loc, "handle_declarations"); - } - async function handle_declaration_list( - loc: Loc, - exporting: boolean, - imp: import_req, - counter: number, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - assert(loc.t.content === "let" || loc.t.content === "const"); - return go_right( - loc, - (loc) => handle_declarations(loc, exporting, modular, imp, counter), - syntax_error, - ); + + async function handle_declaration_list(loc: Loc): Promise { + assert(loc.t.content === "let" || loc.t.content === "const"); + return go_right(loc, (loc) => handle_declarations(loc)); + } + + return handle_declaration_list; } - async function handle_export( - loc: Loc, - ): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - if (!modular.extensible) syntax_error(loc, "unexpected export keyword"); - return go_right(loc, (loc) => handle_declaration_list(loc, true, imp, counter), syntax_error); + + async function handle_export(loc: Loc): Promise { + if (!data.modular.extensible) syntax_error(loc, "unexpected export keyword"); + return go_right(loc, handle_declaration_list(true)); } - return go_down( - loc, - (loc) => { - switch (loc.t.content) { - case "export": - return handle_export(loc); - case "const": - case "let": - return handle_declaration_list(loc, false, imp, counter); - default: - syntax_error(loc); - } - }, - syntax_error, - ).then(({ loc, modular: new_modular, imp, counter }) => - insert_export_keyword(loc, counter, new_modular, imp), - ); -} + + return go_down(loc, (loc) => { + switch (loc.t.content) { + case "export": + return handle_export(loc); + case "const": + case "let": + return handle_declaration_list(false)(loc); + default: + syntax_error(loc); + } + }).then(insert_export_keyword); +}; function rename(loc: Loc, new_name: string): Loc { const new_id: STX = { @@ -1339,38 +1019,34 @@ function rename(loc: Loc, new_name: string): Loc { const sort_env = { type: "types_env" as const, value: "normal_env" as const }; -async function postexpand_body( - loc: Loc, - modular: modular_extension, - unit: CompilationUnit, - counter: number, - context: Context, - imp: import_req, - sort: "type" | "value", - helpers: preexpand_helpers, -): Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }> { - type T = Promise<{ loc: Loc; modular: modular_extension; imp: import_req; counter: number }>; - async function done(loc: Loc, modular: modular_extension, imp: import_req, counter: number): T { - return { loc, modular, imp, counter }; - } - function cont(loc: Loc, modular: modular_extension, imp: import_req, counter: number): T { - return go_next( +const postexpand_forms = (sort: "type" | "value") => non_modular(postexpand_body(sort)); + +const postexpand_body = (sort: "type" | "value") => (data: data) => { + const cont: walker = ({ loc, ...data }) => + go_next( loc, - (loc) => h(find_form(loc), modular, imp, counter), - (loc) => done(loc, modular, imp, counter), + (loc) => h({ loc, ...data }), + (loc) => Promise.resolve({ loc, ...data }), ); - } - async function h(ffrv: ffrv, modular: modular_extension, imp: import_req, counter: number): T { + const h: walker = async ({ loc: old_loc, ...data }) => { + const ffrv = find_form(old_loc); const loc = ffrv.loc; switch (ffrv.type) { case "done": - return done(loc, modular, imp, counter); + return { ...data, loc }; case "identifier": { assert(loc.t.type === "atom"); const { tag, content, wrap } = loc.t; switch (tag) { case "identifier": { - const resolution = await resolve(content, wrap, context, unit, sort_env[sort], helpers); + const resolution = await resolve( + content, + wrap, + data.context, + data.unit, + sort_env[sort], + data.helpers, + ); switch (resolution.type) { case "bound": { const { binding, label } = resolution; @@ -1378,12 +1054,13 @@ async function postexpand_body( case "ts": case "type": case "lexical": { - return cont(rename(loc, binding.name), modular, imp, counter); + return cont({ ...data, loc: rename(loc, binding.name) }); } case "imported_lexical": { + const { imp, counter } = data; const existing = (imp[label.cuid] ?? {})[label.name]; if (existing) { - return cont(rename(loc, existing.new_name), modular, imp, counter); + return cont({ ...data, loc: rename(loc, existing.new_name) }); } else { const { name } = binding; const new_name = `${name}_${counter}`; @@ -1395,7 +1072,12 @@ async function postexpand_body( [label.name]: { type: "value", new_name }, }, }; - return cont(rename(loc, new_name), modular, new_imp, new_counter); + return cont({ + ...data, + loc: rename(loc, new_name), + imp: new_imp, + counter: new_counter, + }); } } default: { @@ -1418,75 +1100,44 @@ async function postexpand_body( switch (loc.t.tag) { case "lexical_declaration": assert(sort === "value"); - return postexpand_lexical_declaration( - loc, - modular, - unit, - counter, - context, - imp, - helpers, - ).then(({ loc, modular, imp, counter }) => cont(loc, modular, imp, counter)); + return postexpand_lexical_declaration({ ...data, loc }).then(cont); case "arrow_function": { - return in_isolation( - loc, - (loc) => expand_arrow_function(loc, counter, context, imp, unit, helpers), - (loc, gs) => ({ ...gs, loc }), - ).then(({ loc, imp, counter }) => cont(loc, modular, imp, counter)); + return in_isolation(loc, (loc) => expand_arrow_function({ ...data, loc })).then(cont); } case "slice": { return syntax_error(loc, "invalid slice"); } case "type_alias_declaration": { - return postexpand_type_alias_declaration( - loc, - modular, - unit, - counter, - context, - imp, - helpers, - ).then(({ loc, modular, imp, counter }) => cont(loc, modular, imp, counter)); + return postexpand_type_alias_declaration({ ...data, loc }).then(cont); } case "member_expression": { return go_down(loc, (loc) => - in_isolation( - loc, - (loc) => - postexpand_body( - loc, - { extensible: false }, - unit, - counter, - context, - imp, - sort, - helpers, - ), - (loc, { modular: _ignored_modular, imp, counter }) => + in_isolation(loc, (loc) => postexpand_forms(sort)({ ...data, loc })) + .then(({ loc, ...data }) => go_right(loc, (loc) => { assert(loc.t.content === "."); return go_right(loc, (loc) => { if (loc.t.tag === "identifier") { // rename to identifier name itself - return { loc: rename(loc, loc.t.content), modular, imp, counter }; + return { ...data, loc: rename(loc, loc.t.content) }; } else { return syntax_error(loc, "not an identifier"); } }); }), - ).then(({ loc, modular, imp, counter }) => cont(loc, modular, imp, counter)), + ) + .then(cont), ); } default: { if (list_handlers_table[loc.t.tag] !== "descend") { debug(loc, `unhandled '${loc.t.tag}' form in postexpand_body`); } - return cont(loc, modular, imp, counter); + return cont({ ...data, loc }); } } } } - } - return h(find_form(loc), modular, imp, counter); -} + }; + return h(data); +}; diff --git a/src/library-manager.ts b/src/library-manager.ts index b0365a3..d9a9847 100644 --- a/src/library-manager.ts +++ b/src/library-manager.ts @@ -19,7 +19,7 @@ import { Binding, CompilationUnit, Context, Loc } from "./syntax-structures"; import stringify from "json-stringify-pretty-compact"; import { init_global_context } from "./global-module"; -const cookie = "rewrite-ts-007"; +const cookie = "rewrite-ts-008"; type module_state = | { type: "initial" } diff --git a/src/preexpand-handlers.ts b/src/preexpand-handlers.ts index afbfd31..1d066bd 100644 --- a/src/preexpand-handlers.ts +++ b/src/preexpand-handlers.ts @@ -1,10 +1,10 @@ import { assert } from "./assert"; -import { imported_module, preexpand_helpers } from "./preexpand-helpers"; +import { data, walker } from "./data"; +import { imported_module } from "./preexpand-helpers"; import { extend_context_lexical, extend_rib, extend_unit, - import_req, lexical_extension, rib_push, } from "./stx"; @@ -13,14 +13,6 @@ import { CompilationUnit, Context, Loc, STX } from "./syntax-structures"; import { list_tag } from "./tags"; import { change, go_down, go_right, go_up, mkzipper } from "./zipper"; -export type goodies = { - loc: Loc; - lexical: lexical_extension; - context: Context; - counter: number; - unit: CompilationUnit; -}; - function skip_optional(loc: Loc, kwd: string): Loc { if (loc.t.content === kwd) { return go_right(loc, (loc) => loc, syntax_error); @@ -44,7 +36,20 @@ export function gen_binding({ context, unit, sort, -}: goodies & { sort: "type" | "value" }): Omit & { name: string } { +}: { + loc: Loc; + lexical: lexical_extension; + counter: number; + context: Context; + unit: CompilationUnit; + sort: "type" | "value"; +}): { + name: string; + lexical: lexical_extension; + counter: number; + context: Context; + unit: CompilationUnit; +} { const stx = loc.t; assert(stx.type === "atom" && stx.tag === "identifier", stx); assert(lexical.extensible); @@ -77,15 +82,15 @@ export function gen_binding({ ); } -function lexical_declaration({ loc, lexical, context, counter, unit }: goodies): Promise { - async function after_vars({ loc, lexical, context, counter, unit }: goodies): Promise { +const lexical_declaration: walker = ({ loc, lexical, context, counter, unit, ...data }) => { + const after_vars: walker = async ({ loc, lexical, context, counter, unit, ...data }) => { if (loc.t.type === "atom" && loc.t.tag === "other") { switch (loc.t.content) { case ";": return go_right( loc, (loc) => syntax_error(loc, "expected nothing after semicolon"), - (loc) => ({ loc, lexical, context, counter, unit }), + (loc) => ({ loc, lexical, context, counter, unit, ...data }), ); case ",": return go_right( @@ -96,17 +101,24 @@ function lexical_declaration({ loc, lexical, context, counter, unit }: goodies): } } syntax_error(loc, "expected a ',' or a ';'"); - } - async function get_vars(ls: Loc, lexical: lexical_extension, context: Context, counter: number) { + }; + function get_vars(ls: Loc, lexical: lexical_extension, context: Context, counter: number) { if (ls.t.type === "list" && ls.t.tag === "variable_declarator") { return go_down( ls, (loc) => { - const goodies = gen_binding({ loc, lexical, counter, context, unit, sort: "value" }); + const goodies = gen_binding({ + loc, + lexical, + counter, + context, + unit, + sort: "value", + }); return go_right( ls, - (loc) => after_vars({ ...goodies, loc }), - (loc) => Promise.resolve({ ...goodies, loc }), + (loc) => after_vars({ ...data, ...goodies, loc }), + (loc) => Promise.resolve({ ...data, ...goodies, loc }), ); }, syntax_error, @@ -126,44 +138,38 @@ function lexical_declaration({ loc, lexical, context, counter, unit }: goodies): ), syntax_error, ); -} +}; -function type_alias_declaration({ - loc, - lexical, - context, - counter, - unit, -}: goodies): Promise { +const type_alias_declaration: walker = ({ loc, ...data }) => { async function after_type(loc: Loc) { assert(loc.t.type === "atom" && loc.t.tag === "identifier", "expected an identifier"); - const gs = gen_binding({ loc, lexical, counter, context, unit, sort: "type" }); - return { ...gs, loc: go_up(loc) }; + const gs = gen_binding({ loc, sort: "type", ...data }); + return { ...data, ...gs, loc: go_up(loc) }; } return go_down( loc, (loc) => after_type(skip_required(skip_optional(loc, "export"), ["type"])), syntax_error, ); -} +}; -const import_declaration: preexpand_list_handler = ({ loc, ...goodies }, helpers) => { +const import_declaration: walker = async ({ loc, helpers, ...data }) => { async function handle_import_from_file(loc: Loc) { if (loc.t.tag !== "string") syntax_error(loc, "expected a string literal for import"); const mod = await helpers.manager.resolve_import(loc); return mod; } - async function after_var(loc: Loc, mod: imported_module): Promise { + async function after_var(loc: Loc, mod: imported_module): Promise { switch (loc.t.content) { case "}": - return { loc: go_up(loc), ...goodies }; + return { loc: go_up(loc), helpers, ...data }; case ",": return go_right(loc, (loc) => handle_named_import(loc, mod), syntax_error); default: syntax_error(loc); } } - async function handle_named_import(loc0: Loc, mod: imported_module): Promise { + async function handle_named_import(loc0: Loc, mod: imported_module): Promise { switch (loc0.t.tag) { case "identifier": { const name = loc0.t.content; @@ -189,17 +195,17 @@ const import_declaration: preexpand_list_handler = ({ loc, ...goodies }, helpers }, rib); const new_lexical: lexical_extension = { extensible: true, rib: new_rib, rib_id }; const new_unit = extend_unit(unit, new_lexical); - return { loc, counter, unit: new_unit, context, lexical: new_lexical }; + return { loc, ...data, counter, unit: new_unit, context, lexical: new_lexical, helpers }; } default: syntax_error(loc, `unexpected ${loc.t.tag} in import context`); } } - async function handle_named_imports(loc: Loc, mod: imported_module): Promise { + async function handle_named_imports(loc: Loc, mod: imported_module): Promise { if (loc.t.content !== "{") syntax_error(loc); return go_right(loc, (loc) => handle_named_import(loc, mod), syntax_error); } - async function handle_imports(loc: Loc, mod: imported_module): Promise { + async function handle_imports(loc: Loc, mod: imported_module): Promise { switch (loc.t.tag) { case "named_imports": return go_down(loc, (loc) => handle_named_imports(loc, mod), syntax_error); @@ -207,7 +213,7 @@ const import_declaration: preexpand_list_handler = ({ loc, ...goodies }, helpers syntax_error(loc, `unexpected ${loc.t.tag} in import`); } } - async function handle_import_clause(loc: Loc): Promise { + async function handle_import_clause(loc: Loc): Promise { if (loc.t.tag === "import_clause") { const mod = await handle_import_from_file( skip_required( @@ -234,9 +240,7 @@ const import_declaration: preexpand_list_handler = ({ loc, ...goodies }, helpers ).then(({ ...gs }) => ({ ...gs, loc: change(loc, mkzipper(empty_slice)) })); }; -type preexpand_list_handler = (goodies: goodies, helpers: preexpand_helpers) => Promise; - -export const preexpand_list_handlers: { [k in list_tag]?: preexpand_list_handler } = { +export const preexpand_list_handlers: { [k in list_tag]?: walker } = { lexical_declaration, type_alias_declaration, import_declaration, diff --git a/src/stx-error.ts b/src/stx-error.ts index d9d432d..a34cacb 100644 --- a/src/stx-error.ts +++ b/src/stx-error.ts @@ -28,12 +28,11 @@ export function syntax_error(loc: Loc, reason?: string): never { throw new StxError("SyntaxError", loc, reason ?? "syntax error"); } -export const in_isolation: ( +export const in_isolation: ( loc: Loc, f: (loc: Loc) => Promise, - k: (loc: Loc, g: Omit) => T, -) => Promise = async (loc, f, k) => { - return f(isolate(loc)).then(({ loc: res, ...g }) => k(unisolate(loc, res), g)); +) => Promise & { loc: Loc }> = async (loc, f) => { + return f(isolate(loc)).then(({ loc: res, ...g }) => ({ ...g, loc: unisolate(loc, res) })); }; type LibraryManager = { diff --git a/src/syntax-core-patterns.ts b/src/syntax-core-patterns.ts index 9323a4d..69cb207 100644 --- a/src/syntax-core-patterns.ts +++ b/src/syntax-core-patterns.ts @@ -24,21 +24,7 @@ import { } from "./syntax-structures"; import { go_next, go_down, mkzipper, stx_list_content, go_up, change } from "./zipper"; import { preexpand_helpers } from "./preexpand-helpers"; - -type handler = ( - loc: Loc, - context: Context, - unit: CompilationUnit, - counter: number, - lexical: lexical_extension, - helpers: preexpand_helpers, -) => Promise<{ - loc: Loc; - counter: number; - unit: CompilationUnit; - context: Context; - lexical: lexical_extension; -}>; +import { walker } from "./data"; const zipper_find: (loc: Loc, pred: (x: STX) => boolean) => Loc | null = (loc, pred) => { const t = loc.t; @@ -266,7 +252,7 @@ export const core_pattern_match: ( return unification; }; -const splice: handler = async (loc, context, unit, counter, lexical, helpers) => { +const splice: walker = async ({ loc, context, unit, counter, lexical, helpers, ...data }) => { const unification = await core_pattern_match(loc, unit, "splice", helpers); assert(unification !== null); const { subst } = unification; @@ -286,6 +272,8 @@ const splice: handler = async (loc, context, unit, counter, lexical, helpers) => unit, context, lexical, + helpers, + ...data, }; }; @@ -356,14 +344,15 @@ function group_by(ls: [K, V][], eq: (a: K, b: K) => boolean): [K, V[]][] { return ac; } -const using_rewrite_rules: handler = async ( - orig_loc, - orig_context, - orig_unit, - orig_counter, - orig_lexical, +const using_rewrite_rules: walker = async ({ + loc: orig_loc, + context: orig_context, + unit: orig_unit, + counter: orig_counter, + lexical: orig_lexical, helpers, -) => { + ...data +}) => { const unification = await core_pattern_match(orig_loc, orig_unit, "using_rewrite_rules", helpers); if (!unification) syntax_error(orig_loc); const { subst, loc } = unification; @@ -426,6 +415,8 @@ const using_rewrite_rules: handler = async ( unit: final_unit, context: final_context, lexical: orig_lexical, + helpers, + ...data, }; }; @@ -498,14 +489,15 @@ export async function apply_syntax_rules( return { loc: new_loc, counter: new_counter }; } -const define_rewrite_rules: handler = async ( - orig_loc, - orig_context, - orig_unit, - orig_counter, - orig_lexical, +const define_rewrite_rules: walker = async ({ + loc: orig_loc, + context: orig_context, + unit: orig_unit, + counter: orig_counter, + lexical: orig_lexical, helpers, -) => { + ...data +}) => { if (orig_lexical.extensible === false) syntax_error(orig_loc, "cannot define rules in nondefinition context"); const unification = await core_pattern_match( @@ -570,6 +562,8 @@ const define_rewrite_rules: handler = async ( unit: final_unit, context: final_context, lexical, + helpers, + ...data, }; }; @@ -593,7 +587,7 @@ const define_rewrite_rules: handler = async ( // } //}; -export const core_handlers: { [k: string]: handler } = { +export const core_handlers: { [k: string]: walker } = { splice, using_rewrite_rules, define_rewrite_rules, diff --git a/test-project/.rts/main.rts.json b/test-project/.rts/main.rts.json index bba218c..a961edb 100644 --- a/test-project/.rts/main.rts.json +++ b/test-project/.rts/main.rts.json @@ -1,6 +1,6 @@ { "cid": "test-project/main.rts rewrite-ts-visualized 0.0.0", - "cookie": "rewrite-ts-007", + "cookie": "rewrite-ts-008", "exported_identifiers": {}, "context": {} } \ No newline at end of file diff --git a/test-project/.rts/mod.rts.json b/test-project/.rts/mod.rts.json index 03885d0..9ac5014 100644 --- a/test-project/.rts/mod.rts.json +++ b/test-project/.rts/mod.rts.json @@ -1,6 +1,6 @@ { "cid": "test-project/mod.rts rewrite-ts-visualized 0.0.0", - "cookie": "rewrite-ts-007", + "cookie": "rewrite-ts-008", "exported_identifiers": { "x": [ { diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index aed54ea..a85d85e 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./files.test.ts","./generate-stdlibs.test.ts","./vite.config.ts","./vitest.config.ts","./rtsc/testing-file-extensions.rts.ts","./rtsc/watch.ts","./src/assert.ts","./src/ast.ts","./src/expander.ts","./src/fs-helpers.ts","./src/generate-stdlibs.ts","./src/generated-stdlibs.ts","./src/global-module.ts","./src/library-manager.ts","./src/llhelpers.ts","./src/parse.ts","./src/pprint.ts","./src/preexpand-handlers.ts","./src/preexpand-helpers.ts","./src/proxy-code.ts","./src/serialize.ts","./src/stx-error.ts","./src/stx.ts","./src/syntax-core-patterns.ts","./src/syntax-structures.ts","./src/tags.ts","./src/zipper.ts","./test-project/index.ts","./test-project/main.rts.ts","./test-project/mod.rts.ts","./ui/astvis.tsx","./ui/app.tsx","./ui/editor.tsx","./ui/main.tsx","./ui/vite-env.d.ts"],"version":"5.7.2"} \ No newline at end of file +{"root":["./files.test.ts","./generate-stdlibs.test.ts","./vite.config.ts","./vitest.config.ts","./rtsc/testing-file-extensions.rts.ts","./rtsc/watch.ts","./src/assert.ts","./src/ast.ts","./src/data.ts","./src/expander.ts","./src/fs-helpers.ts","./src/generate-stdlibs.ts","./src/generated-stdlibs.ts","./src/global-module.ts","./src/library-manager.ts","./src/llhelpers.ts","./src/parse.ts","./src/pprint.ts","./src/preexpand-handlers.ts","./src/preexpand-helpers.ts","./src/proxy-code.ts","./src/serialize.ts","./src/stx-error.ts","./src/stx.ts","./src/syntax-core-patterns.ts","./src/syntax-structures.ts","./src/tags.ts","./src/zipper.ts","./test-project/index.ts","./test-project/main.rts.ts","./test-project/mod.rts.ts","./ui/astvis.tsx","./ui/app.tsx","./ui/editor.tsx","./ui/main.tsx","./ui/vite-env.d.ts"],"version":"5.7.2"} \ No newline at end of file