Skip to content

Commit ea40a8f

Browse files
committed
fix(#92 regression): restore gen_imports + deduplicate extern parser rules
PR #92 introduced three bugs on top of the cross-module infrastructure that landed in #90: 1. Removed gen_imports from lib/codegen.ml but left the call site in generate_module (UnboundVariable on any cross-module import at compile time). 2. Changed generate_module to drop the ?loader parameter but did not update bin/main.ml or test/test_e2e.ml callers (type error at build time). 3. Added duplicate extern_type_decl / extern_fn_decl Menhir rules that conflict with the full rules already present from #90 (Menhir multiply defined nonterminal error at build time). Fixes: - Restore gen_imports and the ?loader parameter on generate_module - Remove the duplicate #92 parser rules - Fix all call sites in bin/main.ml and test/test_e2e.ml 207/207 tests pass.
1 parent c4f5153 commit ea40a8f

3 files changed

Lines changed: 74 additions & 16 deletions

File tree

bin/main.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ let compile_file face json wasm_gc path output =
652652
end else if Filename.check_suffix output ".cjs" then begin
653653
(* Issue #35 Phase 1: Node-CJS shim around the compiled wasm. *)
654654
let optimized_prog = Affinescript.Opt.fold_constants_program prog in
655-
match Affinescript.Codegen.generate_module optimized_prog with
655+
match Affinescript.Codegen.generate_module ~loader optimized_prog with
656656
| Error e ->
657657
add { severity = Error; code = "E0810";
658658
message = Printf.sprintf "Node-CJS codegen error: %s"
@@ -665,7 +665,7 @@ let compile_file face json wasm_gc path output =
665665
close_out oc
666666
end else begin
667667
let optimized_prog = Affinescript.Opt.fold_constants_program prog in
668-
match Affinescript.Codegen.generate_module optimized_prog with
668+
match Affinescript.Codegen.generate_module ~loader optimized_prog with
669669
| Error e ->
670670
add { severity = Error; code = "E0801";
671671
message = Printf.sprintf "WASM codegen error: %s"
@@ -1038,7 +1038,7 @@ let compile_to_wasm_module face path
10381038
Error "Quantity error"
10391039
| Ok () ->
10401040
let optimized_prog = Affinescript.Opt.fold_constants_program prog in
1041-
(match Affinescript.Codegen.generate_module optimized_prog with
1041+
(match Affinescript.Codegen.generate_module ~loader optimized_prog with
10421042
| Error e ->
10431043
Format.eprintf "%s: codegen error: %s@." path
10441044
(Affinescript.Codegen.show_codegen_error e);

lib/codegen.ml

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,8 +1960,77 @@ let gen_decl (ctx : context) (decl : top_level) : context result =
19601960
imports = ctx_with_type.imports @ [import_entry];
19611961
func_indices = (ef.ef_name.name, func_idx) :: ctx_with_type.func_indices }
19621962

1963-
(** Generate WASM module from AffineScript program *)
1964-
let generate_module (prog : program) : wasm_module result =
1963+
(** Cross-module imports: walk [prog.prog_imports], load each referenced module
1964+
via [loader], and for every imported function name register
1965+
a WASM [(import "<mod>" "<fn>" (func ...))] entry plus a
1966+
[(local_alias_name -> func_idx)] mapping in [func_indices].
1967+
1968+
Silent on missing modules / non-function items / loader errors: the
1969+
resolver runs before codegen and would have already errored. *)
1970+
let gen_imports (loader : Module_loader.t) (imports : import_decl list) (ctx : context)
1971+
: context result =
1972+
let process_one ctx (mod_path, orig_name, alias_opt) =
1973+
match Module_loader.load_module loader mod_path with
1974+
| Error _ -> Ok ctx
1975+
| Ok loaded ->
1976+
let fn_decl_opt = List.find_map (function
1977+
| TopFn fd when fd.fd_name.name = orig_name -> Some fd
1978+
| _ -> None
1979+
) loaded.mod_program.prog_decls in
1980+
match fn_decl_opt with
1981+
| None -> Ok ctx
1982+
| Some fd ->
1983+
let local_name = Option.value alias_opt ~default:orig_name in
1984+
let ft = func_type_of_fn_decl fd in
1985+
let (type_idx, types_after) = intern_func_type ctx.types ft in
1986+
let import_func_idx = import_func_count ctx in
1987+
let import = {
1988+
i_module = String.concat "." mod_path;
1989+
i_name = orig_name;
1990+
i_desc = ImportFunc type_idx;
1991+
} in
1992+
Ok { ctx with
1993+
types = types_after;
1994+
imports = ctx.imports @ [import];
1995+
func_indices = (local_name, import_func_idx) :: ctx.func_indices;
1996+
}
1997+
in
1998+
let expand_import imp : (string list * string * string option) list =
1999+
let path_strs path = List.map (fun (id : ident) -> id.name) path in
2000+
match imp with
2001+
| ImportSimple _ -> []
2002+
| ImportList (path, items) ->
2003+
let p = path_strs path in
2004+
List.map (fun item ->
2005+
(p, item.ii_name.name, Option.map (fun (id : ident) -> id.name) item.ii_alias)
2006+
) items
2007+
| ImportGlob path ->
2008+
let p = path_strs path in
2009+
(match Module_loader.load_module loader p with
2010+
| Error _ -> []
2011+
| Ok lm ->
2012+
List.filter_map (function
2013+
| TopFn fd when fd.fd_vis = Public || fd.fd_vis = PubCrate ->
2014+
Some (p, fd.fd_name.name, None)
2015+
| _ -> None
2016+
) lm.mod_program.prog_decls)
2017+
in
2018+
let entries = List.concat_map expand_import imports in
2019+
List.fold_left (fun acc e ->
2020+
let* ctx = acc in
2021+
process_one ctx e
2022+
) (Ok ctx) entries
2023+
2024+
(** Generate WASM module from AffineScript program.
2025+
2026+
[?loader] supplies the module loader used to resolve cross-module imports.
2027+
Defaults to a fresh loader with [Module_loader.default_config ()] so that
2028+
existing call sites keep working without modification. *)
2029+
let generate_module ?loader (prog : program) : wasm_module result =
2030+
let loader = match loader with
2031+
| Some l -> l
2032+
| None -> Module_loader.create (Module_loader.default_config ())
2033+
in
19652034
let ctx = create_context () in
19662035

19672036
(* Add WASI fd_write import at index 0 *)

lib/parser.mly

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,17 +158,6 @@ const_decl:
158158
{ TopConst { tc_vis = Option.value vis ~default:Private;
159159
tc_name = name; tc_ty = ty; tc_value = value } }
160160

161-
extern_type_decl:
162-
| EXTERN TYPE name = upper_ident SEMICOLON
163-
{ TopExternType { et_name = name } }
164-
165-
extern_fn_decl:
166-
| EXTERN FN name = ident LPAREN params = separated_list(COMMA, param) RPAREN SEMICOLON
167-
{ TopExternFn { ef_name = name; ef_params = params; ef_ret_ty = None } }
168-
| EXTERN FN name = ident LPAREN params = separated_list(COMMA, param) RPAREN ARROW ret = type_expr SEMICOLON
169-
{ TopExternFn { ef_name = name; ef_params = params; ef_ret_ty = Some ret } }
170-
171-
/* ========== Functions ========== */
172161

173162
fn_decl:
174163
| vis = visibility? total = TOTAL? FN name = ident

0 commit comments

Comments
 (0)