Bug 1308056: wasm: add syntax for inline import/export in globals; r=luke

MozReview-Commit-ID: DLc7oCNkbpi

--HG--
extra : rebase_source : 2a9472e84eaf7363c9c9bb3c5a8e1b03a55d33ae
This commit is contained in:
Benjamin Bouvier 2016-10-07 17:14:17 +02:00
parent 5db4b59105
commit cff747d16b
6 changed files with 121 additions and 57 deletions

View File

@ -93,7 +93,6 @@ class WasmToken
GetLocal, GetLocal,
Global, Global,
If, If,
Immutable,
Import, Import,
Index, Index,
Memory, Memory,
@ -102,6 +101,7 @@ class WasmToken
Local, Local,
Loop, Loop,
Module, Module,
Mutable,
Name, Name,
Nop, Nop,
Offset, Offset,
@ -296,7 +296,7 @@ class WasmToken
case Float: case Float:
case Func: case Func:
case Global: case Global:
case Immutable: case Mutable:
case Import: case Import:
case Index: case Index:
case Memory: case Memory:
@ -1377,8 +1377,6 @@ WasmTokenStream::next()
} }
break; break;
} }
if (consume(u"immutable"))
return WasmToken(WasmToken::Immutable, begin, cur_);
if (consume(u"import")) if (consume(u"import"))
return WasmToken(WasmToken::Import, begin, cur_); return WasmToken(WasmToken::Import, begin, cur_);
if (consume(u"infinity")) if (consume(u"infinity"))
@ -1399,6 +1397,8 @@ WasmTokenStream::next()
return WasmToken(WasmToken::Module, begin, cur_); return WasmToken(WasmToken::Module, begin, cur_);
if (consume(u"memory")) if (consume(u"memory"))
return WasmToken(WasmToken::Memory, begin, cur_); return WasmToken(WasmToken::Memory, begin, cur_);
if (consume(u"mut"))
return WasmToken(WasmToken::Mutable, begin, cur_);
break; break;
case 'n': case 'n':
@ -2798,15 +2798,18 @@ ParseStartFunc(WasmParseContext& c, WasmToken token, AstModule* module)
static bool static bool
ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, uint32_t* flags) ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, uint32_t* flags)
{ {
if (!c.ts.match(WasmToken::ValueType, typeToken, c.error)) // Either (mut i32) or i32.
return false; if (c.ts.getIf(WasmToken::OpenParen)) {
// Immutable by default.
*flags = c.ts.getIf(WasmToken::Mutable) ? 0x1 : 0x0;
if (!c.ts.match(WasmToken::ValueType, typeToken, c.error))
return false;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return false;
return true;
}
// Mutable by default. return c.ts.match(WasmToken::ValueType, typeToken, c.error);
*flags = 0x1;
if (c.ts.getIf(WasmToken::Immutable))
*flags = 0x0;
return true;
} }
static bool static bool
@ -2861,17 +2864,22 @@ ParseImport(WasmParseContext& c, AstModule* module)
DefinitionKind::Table, table); DefinitionKind::Table, table);
} }
if (c.ts.getIf(WasmToken::Global)) { if (c.ts.getIf(WasmToken::Global)) {
if (name.empty())
name = c.ts.getIfName();
WasmToken typeToken; WasmToken typeToken;
uint32_t flags = 0; uint32_t flags = 0;
if (!ParseGlobalType(c, &typeToken, &flags)) if (!ParseGlobalType(c, &typeToken, &flags))
return nullptr; return nullptr;
if (!c.ts.match(WasmToken::CloseParen, c.error)) if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr; return nullptr;
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(), return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
AstGlobal(AstName(), typeToken.valueType(), flags)); AstGlobal(AstName(), typeToken.valueType(), flags));
} }
if (c.ts.getIf(WasmToken::Func)) { if (c.ts.getIf(WasmToken::Func)) {
AstName name = c.ts.getIfName(); if (name.empty())
name = c.ts.getIfName();
AstRef sigRef; AstRef sigRef;
if (!ParseFuncType(c, &sigRef, module)) if (!ParseFuncType(c, &sigRef, module))
@ -3084,21 +3092,58 @@ ParseElemSegment(WasmParseContext& c)
return new(c.lifo) AstElemSegment(offset, Move(elems)); return new(c.lifo) AstElemSegment(offset, Move(elems));
} }
static AstGlobal* static bool
ParseGlobal(WasmParseContext& c) ParseGlobal(WasmParseContext& c, AstModule* module)
{ {
AstName name = c.ts.getIfName(); AstName name = c.ts.getIfName();
WasmToken typeToken; WasmToken typeToken;
uint32_t flags = 0; uint32_t flags = 0;
WasmToken openParen;
if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
if (c.ts.getIf(WasmToken::Import)) {
if (module->globals().length()) {
c.ts.generateError(openParen, "import after global definition", c.error);
return false;
}
InlineImport names;
if (!ParseInlineImport(c, &names))
return false;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return false;
if (!ParseGlobalType(c, &typeToken, &flags))
return false;
auto* imp = new(c.lifo) AstImport(name, names.module.text(), names.field.text(),
AstGlobal(AstName(), typeToken.valueType(), flags));
return imp && module->append(imp);
}
if (c.ts.getIf(WasmToken::Export)) {
AstRef ref = name.empty()
? AstRef(AstName(), module->globals().length())
: AstRef(name, AstNoIndex);
if (!ParseInlineExport(c, DefinitionKind::Global, module, ref))
return false;
if (!c.ts.match(WasmToken::CloseParen, c.error))
return false;
} else {
c.ts.unget(openParen);
}
}
if (!ParseGlobalType(c, &typeToken, &flags)) if (!ParseGlobalType(c, &typeToken, &flags))
return nullptr; return false;
AstExpr* init = ParseExpr(c, true); AstExpr* init = ParseExpr(c, true);
if (!init) if (!init)
return nullptr; return false;
return new(c.lifo) AstGlobal(name, typeToken.valueType(), flags, Some(init)); auto* glob = new(c.lifo) AstGlobal(name, typeToken.valueType(), flags, Some(init));
return glob && module->append(glob);
} }
static AstModule* static AstModule*
@ -3136,8 +3181,7 @@ ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
break; break;
} }
case WasmToken::Global: { case WasmToken::Global: {
AstGlobal* global = ParseGlobal(c); if (!ParseGlobal(c, module))
if (!global || !module->append(global))
return nullptr; return nullptr;
break; break;
} }

View File

@ -6,7 +6,7 @@ const { Instance, Module } = WebAssembly;
// Locally-defined globals // Locally-defined globals
assertErrorMessage(() => wasmEvalText(`(module (global))`), SyntaxError, /parsing/); assertErrorMessage(() => wasmEvalText(`(module (global))`), SyntaxError, /parsing/);
assertErrorMessage(() => wasmEvalText(`(module (global i32))`), SyntaxError, /parsing/); assertErrorMessage(() => wasmEvalText(`(module (global i32))`), SyntaxError, /parsing/);
assertErrorMessage(() => wasmEvalText(`(module (global i32 immutable))`), SyntaxError, /parsing/); assertErrorMessage(() => wasmEvalText(`(module (global (mut i32)))`), SyntaxError, /parsing/);
// Initializer expressions. // Initializer expressions.
wasmFailValidateText(`(module (global i32 (f32.const 13.37)))`, /type mismatch/); wasmFailValidateText(`(module (global i32 (f32.const 13.37)))`, /type mismatch/);
@ -14,14 +14,14 @@ wasmFailValidateText(`(module (global f64 (f32.const 13.37)))`, /type mismatch/)
wasmFailValidateText(`(module (global i32 (i32.add (i32.const 13) (i32.const 37))))`, /failed to read end/); wasmFailValidateText(`(module (global i32 (i32.add (i32.const 13) (i32.const 37))))`, /failed to read end/);
wasmFailValidateText(`(module (global i32 (get_global 0)))`, /out of range/); wasmFailValidateText(`(module (global i32 (get_global 0)))`, /out of range/);
wasmFailValidateText(`(module (global i32 (get_global 1)) (global i32 immutable (i32.const 1)))`, /out of range/); wasmFailValidateText(`(module (global i32 (get_global 1)) (global i32 (i32.const 1)))`, /out of range/);
// Test a well-defined global section. // Test a well-defined global section.
function testInner(type, initialValue, nextValue, coercion, assertFunc = assertEq) function testInner(type, initialValue, nextValue, coercion, assertFunc = assertEq)
{ {
var module = wasmEvalText(`(module var module = wasmEvalText(`(module
(global (mut ${type}) (${type}.const ${initialValue}))
(global ${type} (${type}.const ${initialValue})) (global ${type} (${type}.const ${initialValue}))
(global ${type} immutable (${type}.const ${initialValue}))
(func $get (result ${type}) (get_global 0)) (func $get (result ${type}) (get_global 0))
(func $set (param ${type}) (set_global 0 (get_local 0))) (func $set (param ${type}) (set_global 0 (get_local 0)))
@ -46,8 +46,8 @@ testInner('f32', 13.37, 0.1989, Math.fround);
testInner('f64', 13.37, 0.1989, x => +x); testInner('f64', 13.37, 0.1989, x => +x);
// Semantic errors. // Semantic errors.
wasmFailValidateText(`(module (global i32 (i32.const 1337)) (func (set_global 1 (i32.const 0))))`, /out of range/); wasmFailValidateText(`(module (global (mut i32) (i32.const 1337)) (func (set_global 1 (i32.const 0))))`, /out of range/);
wasmFailValidateText(`(module (global i32 immutable (i32.const 1337)) (func (set_global 0 (i32.const 0))))`, /can't write an immutable global/); wasmFailValidateText(`(module (global i32 (i32.const 1337)) (func (set_global 0 (i32.const 0))))`, /can't write an immutable global/);
// Big module with many variables: test that setting one doesn't overwrite the // Big module with many variables: test that setting one doesn't overwrite the
// other ones. // other ones.
@ -58,11 +58,11 @@ function get_set(i, type) { return `
} }
var module = wasmEvalText(`(module var module = wasmEvalText(`(module
(global i32 (i32.const 42)) (global (mut i32) (i32.const 42))
(global i32 (i32.const 10)) (global (mut i32) (i32.const 10))
(global f32 (f32.const 13.37)) (global (mut f32) (f32.const 13.37))
(global f64 (f64.const 13.37)) (global (mut f64) (f64.const 13.37))
(global i32 (i32.const -18)) (global (mut i32) (i32.const -18))
${get_set(0, 'i32')} ${get_set(0, 'i32')}
${get_set(1, 'i32')} ${get_set(1, 'i32')}
@ -93,10 +93,10 @@ for (let i = 0; i < 5; i++) {
} }
// Initializer expressions can also be used in elem section initializers. // Initializer expressions can also be used in elem section initializers.
wasmFailValidateText(`(module (import "globals" "a" (global f32 immutable)) (table 4 anyfunc) (elem (get_global 0) $f) (func $f))`, /type mismatch/); wasmFailValidateText(`(module (import "globals" "a" (global f32)) (table 4 anyfunc) (elem (get_global 0) $f) (func $f))`, /type mismatch/);
module = wasmEvalText(`(module module = wasmEvalText(`(module
(import "globals" "a" (global i32 immutable)) (import "globals" "a" (global i32))
(table (export "tbl") 4 anyfunc) (table (export "tbl") 4 anyfunc)
(elem (get_global 0) $f) (elem (get_global 0) $f)
(func $f) (func $f)
@ -109,12 +109,12 @@ module = wasmEvalText(`(module
assertEq(module.f, module.tbl.get(1)); assertEq(module.f, module.tbl.get(1));
// Import/export rules. // Import/export rules.
wasmFailValidateText(`(module (import "globals" "x" (global i32)))`, /can't import.* mutable globals in the MVP/); wasmFailValidateText(`(module (import "globals" "x" (global (mut i32))))`, /can't import.* mutable globals in the MVP/);
wasmFailValidateText(`(module (global i32 (i32.const 42)) (export "" global 0))`, /can't .*export mutable globals in the MVP/); wasmFailValidateText(`(module (global (mut i32) (i32.const 42)) (export "" global 0))`, /can't .*export mutable globals in the MVP/);
// Import/export semantics. // Import/export semantics.
module = wasmEvalText(`(module module = wasmEvalText(`(module
(import $g "globals" "x" (global i32 immutable)) (import $g "globals" "x" (global i32))
(func $get (result i32) (get_global $g)) (func $get (result i32) (get_global $g))
(export "getter" $get) (export "getter" $get)
(export "value" global 0) (export "value" global 0)
@ -125,8 +125,8 @@ assertEq(module.value, 42);
// Imported globals and locally defined globals use the same index space. // Imported globals and locally defined globals use the same index space.
module = wasmEvalText(`(module module = wasmEvalText(`(module
(import "globals" "x" (global i32 immutable)) (import "globals" "x" (global i32))
(global i32 immutable (i32.const 1337)) (global i32 (i32.const 1337))
(export "imported" global 0) (export "imported" global 0)
(export "defined" global 1) (export "defined" global 1)
)`, { globals: {x: 42} }).exports; )`, { globals: {x: 42} }).exports;
@ -135,18 +135,18 @@ assertEq(module.imported, 42);
assertEq(module.defined, 1337); assertEq(module.defined, 1337);
// Initializer expressions can reference an imported immutable global. // Initializer expressions can reference an imported immutable global.
wasmFailValidateText(`(module (global f32 immutable (f32.const 13.37)) (global i32 (get_global 0)))`, /must reference a global immutable import/);
wasmFailValidateText(`(module (global f32 (f32.const 13.37)) (global i32 (get_global 0)))`, /must reference a global immutable import/); wasmFailValidateText(`(module (global f32 (f32.const 13.37)) (global i32 (get_global 0)))`, /must reference a global immutable import/);
wasmFailValidateText(`(module (global i32 (i32.const 0)) (global i32 (get_global 0)))`, /must reference a global immutable import/); wasmFailValidateText(`(module (global (mut f32) (f32.const 13.37)) (global i32 (get_global 0)))`, /must reference a global immutable import/);
wasmFailValidateText(`(module (global (mut i32) (i32.const 0)) (global i32 (get_global 0)))`, /must reference a global immutable import/);
wasmFailValidateText(`(module (import "globals" "a" (global f32 immutable)) (global i32 (get_global 0)))`, /type mismatch/); wasmFailValidateText(`(module (import "globals" "a" (global f32)) (global i32 (get_global 0)))`, /type mismatch/);
function testInitExpr(type, initialValue, nextValue, coercion, assertFunc = assertEq) { function testInitExpr(type, initialValue, nextValue, coercion, assertFunc = assertEq) {
var module = wasmEvalText(`(module var module = wasmEvalText(`(module
(import "globals" "a" (global ${type} immutable)) (import "globals" "a" (global ${type}))
(global (mut ${type}) (get_global 0))
(global ${type} (get_global 0)) (global ${type} (get_global 0))
(global ${type} immutable (get_global 0))
(func $get0 (result ${type}) (get_global 0)) (func $get0 (result ${type}) (get_global 0))
@ -182,16 +182,16 @@ testInitExpr('f64', 13.37, 0.1989, x => +x);
// Int64. // Int64.
{ {
wasmFailValidateText(`(module (import "globals" "x" (global i64 immutable)))`, /can't import.* an Int64 global/); wasmFailValidateText(`(module (import "globals" "x" (global i64)))`, /can't import.* an Int64 global/);
wasmFailValidateText(`(module (global i64 immutable (i64.const 42)) (export "" global 0))`, /can't .*export an Int64 global/); wasmFailValidateText(`(module (global i64 (i64.const 42)) (export "" global 0))`, /can't .*export an Int64 global/);
setJitCompilerOption('wasm.test-mode', 1); setJitCompilerOption('wasm.test-mode', 1);
testInner('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64); testInner('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
testInitExpr('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64); testInitExpr('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
module = wasmEvalText(`(module module = wasmEvalText(`(module
(import "globals" "x" (global i64 immutable)) (import "globals" "x" (global i64))
(global i64 immutable (i64.const 0xFAFADADABABA)) (global i64 (i64.const 0xFAFADADABABA))
(export "imported" global 0) (export "imported" global 0)
(export "defined" global 1) (export "defined" global 1)
)`, { globals: {x: createI64('0x1234567887654321')} }).exports; )`, { globals: {x: createI64('0x1234567887654321')} }).exports;

View File

@ -366,7 +366,7 @@ assertEq(i8[102], 0x0);
var m = new Module(wasmTextToBinary(` var m = new Module(wasmTextToBinary(`
(module (module
(import "glob" "a" (global i32 immutable)) (import "glob" "a" (global i32))
(memory 1) (memory 1)
(data (get_global 0) "\\0a\\0b")) (data (get_global 0) "\\0a\\0b"))
`)); `));
@ -383,8 +383,8 @@ var m = new Module(wasmTextToBinary(`
(module (module
(import "a" "mem" (memory 1)) (import "a" "mem" (memory 1))
(import "a" "tbl" (table 1 anyfunc)) (import "a" "tbl" (table 1 anyfunc))
(import $memOff "a" "memOff" (global i32 immutable)) (import $memOff "a" "memOff" (global i32))
(import $tblOff "a" "tblOff" (global i32 immutable)) (import $tblOff "a" "tblOff" (global i32))
(func $f) (func $f)
(func $g) (func $g)
(data (i32.const 0) "\\01") (data (i32.const 0) "\\01")
@ -465,7 +465,7 @@ assertEq(i2.exports.call(0), 0x42);
assertEq(i2.exports.call(1), 0x13); assertEq(i2.exports.call(1), 0x13);
var m = new Module(wasmTextToBinary(`(module var m = new Module(wasmTextToBinary(`(module
(import $val "a" "val" (global i32 immutable)) (import $val "a" "val" (global i32))
(import $next "a" "next" (result i32)) (import $next "a" "next" (result i32))
(memory 1) (memory 1)
(func $start (i32.store (i32.const 0) (get_global $val))) (func $start (i32.store (i32.const 0) (get_global $val)))

View File

@ -81,7 +81,7 @@ assertEqNaN(nan, f32_qnan);
// Globals. // Globals.
var m = wasmEvalText(`(module var m = wasmEvalText(`(module
(import "globals" "x" (global f32 immutable)) (import "globals" "x" (global f32))
(func (result f32) (get_global 0)) (func (result f32) (get_global 0))
(export "global" global 0) (export "global" global 0)
(export "test" 0)) (export "test" 0))
@ -91,7 +91,7 @@ assertEqNaN(m.test(), f32_snan);
assertEqNaN(m.global, f32_snan); assertEqNaN(m.global, f32_snan);
var m = wasmEvalText(`(module var m = wasmEvalText(`(module
(import "globals" "x" (global f64 immutable)) (import "globals" "x" (global f64))
(func (result f64) (get_global 0)) (func (result f64) (get_global 0))
(export "global" global 0) (export "global" global 0)
(export "test" 0)) (export "test" 0))

View File

@ -16,18 +16,18 @@ wasmFailValidateText(`(module (table 10 anyfunc) (func) (elem (f32.const 0) 0) $
wasmFailValidateText(`(module (table 10 anyfunc) (elem (i32.const 10) $f0) ${callee(0)})`, /element segment does not fit/); wasmFailValidateText(`(module (table 10 anyfunc) (elem (i32.const 10) $f0) ${callee(0)})`, /element segment does not fit/);
wasmFailValidateText(`(module (table 10 anyfunc) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`, /element segment does not fit/); wasmFailValidateText(`(module (table 10 anyfunc) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`, /element segment does not fit/);
assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), RangeError, /elem segment does not fit/); assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), RangeError, /elem segment does not fit/);
assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), RangeError, /elem segment does not fit/); assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), RangeError, /elem segment does not fit/);
assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)) instanceof Module, true); assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)) instanceof Module, true);
assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)) instanceof Module, true); assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)) instanceof Module, true);
wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32 immutable)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}}); wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}});
wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32 immutable)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}}); wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}});
var m = new Module(wasmTextToBinary(` var m = new Module(wasmTextToBinary(`
(module (module
(import "globals" "table" (table 10 anyfunc)) (import "globals" "table" (table 10 anyfunc))
(import "globals" "a" (global i32 immutable)) (import "globals" "a" (global i32))
(elem (get_global 0) $f0 $f0) (elem (get_global 0) $f0 $f0)
${callee(0)}) ${callee(0)})
`)); `));

View File

@ -92,5 +92,25 @@ assertErrorMessage(() => wasmEvalText(`
) )
`), SyntaxError, /import after function definition/); `), SyntaxError, /import after function definition/);
// Globals.
assertErrorMessage(() => wasmEvalText('(module (global $t (export)))'), SyntaxError, parsingError);
assertErrorMessage(() => wasmEvalText('(module (global $t (export "g")))'), SyntaxError, parsingError);
assertErrorMessage(() => wasmEvalText('(module (global $t (export "g") i32))'), SyntaxError, parsingError);
wasmEvalText('(module (global $t (export "g") i32 (i32.const 42)))');
assertErrorMessage(() => wasmEvalText('(module (global $t (import) i32))'), SyntaxError, parsingError);
assertErrorMessage(() => wasmEvalText('(module (global $t (import "mod") i32))'), SyntaxError, parsingError);
assertErrorMessage(() => wasmEvalText('(module (global $t (import "mod" "field")))'), SyntaxError, parsingError);
assertErrorMessage(() => wasmEvalText('(module (global $t (import "mod" "field")) i32 (i32.const 42))'), SyntaxError, parsingError);
wasmEvalText('(module (global $t (import "mod" "field") i32))', { mod: {field: 42} });
assertErrorMessage(() => wasmEvalText(`
(module
(global (import "mod" "a") i32)
(global (export "f1") i32 (i32.const 42))
(global (import "mod" "b") i32)
)
`), SyntaxError, /import after global definition/);
// Note: the s-expression text format is temporary, this file is mostly just to // Note: the s-expression text format is temporary, this file is mostly just to
// hold basic error smoke tests. // hold basic error smoke tests.