diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 6ea942796..6d698ef11 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -133,6 +133,7 @@ let empty_context () = datas = empty (); elems = empty (); locals = empty (); labels = empty (); deferred_locals = ref [] } +let empty_context_with_types_from (c : context) = {(empty_context ()) with types = c.types} let enter_block (c : context) loc = {c with labels = scoped "label" 1l c.labels (at loc)} let enter_let (c : context) loc = {c with locals = empty (); deferred_locals = ref []} @@ -1258,9 +1259,8 @@ compact_item1 : fun () -> ($3, df ()) } compact_item1_list : - | compact_item1 - { fun c -> let f = $1 c in - fun () -> [f ()] } + | /* empty */ + { fun _c -> fun () -> [] } | compact_item1 compact_item1_list { fun c -> let f = $1 c in let fs = $2 c in fun () -> f () :: fs () } @@ -1283,8 +1283,13 @@ import : | LPAR IMPORT name compact_item2_list RPAR { fun c -> let (item_names, xt_fn) = $4 in + (* Run the externtype function once, even if there are zero items, to + * ensure it has no identifiers and to ensure that any implicit function + * types still get defined. *) + let df0 = xt_fn (empty_context_with_types_from c) false in let dfs = List.map (fun _ -> xt_fn c false) item_names in fun () -> + ignore (df0 ()); List.map2 (fun item_name df -> Import ($3, item_name, df ()) @@ $sloc) item_names dfs } diff --git a/spectec/doc/example/output/NanoWasm.pdf b/spectec/doc/example/output/NanoWasm.pdf index ffc8d13cf..af4d0a661 100644 Binary files a/spectec/doc/example/output/NanoWasm.pdf and b/spectec/doc/example/output/NanoWasm.pdf differ diff --git a/test/core/compact-import-section/imports-compact.wast b/test/core/compact-import-section/imports-compact.wast index 577967020..188c2824c 100644 --- a/test/core/compact-import-section/imports-compact.wast +++ b/test/core/compact-import-section/imports-compact.wast @@ -97,6 +97,32 @@ ) +;; Zero-length groups + +(module (import "not-test")) ;; encoding 1 +(module (import "not-test" (func))) ;; encoding 2 + +(module + (import "test") + (import "test" (func (result i32))) ;; no func + (import "test" (item "func->11i" (func (result i32)))) ;; func 0 + (import "test" (global i32)) ;; no global + (import "test" (item "global->20") (global i32)) ;; global 0 + + (func (export "check") (result i32) + call 0 + global.get 0 + i32.add + ) +) +(assert_return (invoke "check") (i32.const 31)) + +(module + (import "not-test" (func (param i32))) ;; still implicitly defines a func type + (func (type 0)) +) + + ;; Identifiers (module @@ -118,10 +144,18 @@ (assert_return (invoke "sum") (i32.const 32)) +(assert_malformed + (module quote "(import \"test\" (func $foo))") + "identifier not allowed" +) (assert_malformed (module quote "(import \"test\" (item \"foo\") (func $foo))") "identifier not allowed" ) +(assert_malformed + (module quote "(import \"test\" (item \"foo\") (item \"bar\") (func $foo))") + "identifier not allowed" +) ;; All externtype kinds in a single encoding-1 group