Repository: tetratelabs/wazero
Pull request #302 (2022-03-01 01:57:03)

text: changes string value of externtype "mem" to "memory"
This changes the string value of "mem" to "memory" so that the same
constants currently used for error context can also be used for field
parsing dispatch.



Patch:
diff --git a/internal/wasm/module.go b/internal/wasm/module.go
index 79bb142c..609693cf 100644
--- a/internal/wasm/module.go
+++ b/internal/wasm/module.go
@@ -459,20 +459,32 @@ const (
 	ExternTypeGlobal ExternType = 0x03
 )
 
-// ExternTypeName returns the canonical name of the import or export description.
+// The below are exported to consolidate parsing behavior for external types.
+const (
+	// ExternTypeFuncName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeFunc.
+	ExternTypeFuncName = "func"
+	// ExternTypeTableName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeTable.
+	ExternTypeTableName = "table"
+	// ExternTypeMemoryName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeMemory.
+	ExternTypeMemoryName = "memory"
+	// ExternTypeGlobalName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeGlobal.
+	ExternTypeGlobalName = "global"
+)
+
+// ExternTypeName returns the name of the WebAssembly 1.0 (20191205) Text Format field of the given type.
 //
-// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-importdesc
-// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-exportdesc
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#imports⑤
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A4
 func ExternTypeName(et ExternType) string {
 	switch et {
 	case ExternTypeFunc:
-		return "func"
+		return ExternTypeFuncName
 	case ExternTypeTable:
-		return "table"
+		return ExternTypeTableName
 	case ExternTypeMemory:
-		return "mem"
+		return ExternTypeMemoryName
 	case ExternTypeGlobal:
-		return "global"
+		return ExternTypeGlobalName
 	}
 	return fmt.Sprintf("%#x", et)
 }
diff --git a/internal/wasm/text/decoder.go b/internal/wasm/text/decoder.go
index 5baec8f3..1a15f0bf 100644
--- a/internal/wasm/text/decoder.go
+++ b/internal/wasm/text/decoder.go
@@ -91,6 +91,10 @@ type moduleParser struct {
 
 	// unresolvedExports holds any exports whose type index wasn't resolvable when parsed.
 	unresolvedExports map[wasm.Index]*wasm.Export
+
+	// field counts can be different from the count in a section when abbreviated imports exist. To give an accurate
+	// errorContext, we count explicitly.
+	fieldCountFunc, fieldCountMemory uint32
 }
 
 // DecodeModule implements wasm.DecodeModule for the WebAssembly 1.0 (20191205) Text Format
@@ -177,20 +181,20 @@ func (p *moduleParser) beginModuleField(tok tokenType, tokenBytes []byte, _, _ u
 		case "import":
 			p.pos = positionImport
 			return p.parseImportModule, nil
-		case "func":
+		case wasm.ExternTypeFuncName:
 			p.pos = positionFunc
 			p.funcParser.currentIdx = p.module.SectionElementCount(wasm.SectionIDFunction)
 			return p.funcParser.begin, nil
-		case "table":
-			return nil, errors.New("TODO: table")
-		case "memory":
+		case wasm.ExternTypeTableName:
+			return nil, fmt.Errorf("TODO: %s", tokenBytes)
+		case wasm.ExternTypeMemoryName:
 			if p.memoryNamespace.count > 0 {
 				return nil, moreThanOneInvalidInSection(wasm.SectionIDMemory)
 			}
 			p.pos = positionMemory
 			return p.memoryParser.begin, nil
-		case "global":
-			return nil, errors.New("TODO: global")
+		case wasm.ExternTypeGlobalName:
+			return nil, fmt.Errorf("TODO: %s", tokenBytes)
 		case "export":
 			p.pos = positionExport
 			return p.parseExportName, nil
@@ -313,13 +317,13 @@ func (p *moduleParser) beginImportDesc(tok tokenType, tokenBytes []byte, _, _ ui
 	}
 
 	switch string(tokenBytes) {
-	case "func":
+	case wasm.ExternTypeFuncName:
 		if p.module.SectionElementCount(wasm.SectionIDFunction) > 0 {
 			return nil, importAfterModuleDefined(wasm.SectionIDFunction)
 		}
 		p.pos = positionImportFunc
 		return p.parseImportFuncID, nil
-	case "table", "memory", "global":
+	case wasm.ExternTypeTableName, wasm.ExternTypeMemoryName, wasm.ExternTypeGlobalName:
 		return nil, fmt.Errorf("TODO: %s", tokenBytes)
 	default:
 		return nil, unexpectedFieldName(tokenBytes)
@@ -436,6 +440,7 @@ func (p *moduleParser) endFunc(typeIdx wasm.Index, code *wasm.Code, name string,
 
 	// Multiple funcs are allowed, so advance in case there's a next.
 	p.funcNamespace.count++
+	p.fieldCountFunc++
 	p.pos = positionModule
 	return p.parseModule, nil
 }
@@ -447,6 +452,7 @@ func (p *moduleParser) endMemory(min uint32, max *uint32) tokenParser {
 
 	// Multiple memories are allowed, so advance in case there's a next.
 	p.memoryNamespace.count++
+	p.fieldCountMemory++
 	p.pos = positionModule
 	return p.parseModule
 }
@@ -497,13 +503,13 @@ func (p *moduleParser) beginExportDesc(tok tokenType, tokenBytes []byte, _, _ ui
 	}
 
 	switch string(tokenBytes) {
-	case "func":
+	case wasm.ExternTypeFuncName:
 		p.pos = positionExportFunc
 		return p.parseExportDesc, nil
-	case "memory":
+	case wasm.ExternTypeMemoryName:
 		p.pos = positionExportMemory
 		return p.parseExportDesc, nil
-	case "table", "global":
+	case wasm.ExternTypeTableName, wasm.ExternTypeGlobalName:
 		return nil, fmt.Errorf("TODO: %s", tokenBytes)
 	default:
 		return nil, unexpectedFieldName(tokenBytes)
@@ -741,19 +747,18 @@ func (p *moduleParser) errorContext() string {
 		if p.pos == positionImport {
 			return fmt.Sprintf("module.import[%d]", idx)
 		}
-		return fmt.Sprintf("module.import[%d].func%s", idx, p.typeUseParser.errorContext())
+		return fmt.Sprintf("module.import[%d].%s%s", idx, wasm.ExternTypeFuncName, p.typeUseParser.errorContext())
 	case positionFunc:
-		idx := p.module.SectionElementCount(wasm.SectionIDFunction)
-		return fmt.Sprintf("module.func[%d]%s", idx, p.typeUseParser.errorContext())
+		idx := p.fieldCountFunc
+		return fmt.Sprintf("module.%s[%d]%s", wasm.ExternTypeFuncName, idx, p.typeUseParser.errorContext())
 	case positionMemory:
-		idx := p.module.SectionElementCount(wasm.SectionIDMemory)
-		return fmt.Sprintf("module.memory[%d]", idx)
+		return fmt.Sprintf("module.%s[%d]", wasm.ExternTypeMemoryName, p.fieldCountMemory)
 	case positionExport, positionExportFunc: // TODO: table, memory or global
 		idx := p.module.SectionElementCount(wasm.SectionIDExport)
 		if p.pos == positionExport {
 			return fmt.Sprintf("module.export[%d]", idx)
 		}
-		return fmt.Sprintf("module.export[%d].func", idx)
+		return fmt.Sprintf("module.export[%d].%s", idx, wasm.ExternTypeFuncName)
 	case positionStart:
 		return "module.start"
 	default: // parserPosition is an enum, we expect to have handled all cases above. panic if we didn't
diff --git a/internal/wasm/text/func_parser.go b/internal/wasm/text/func_parser.go
index 79aa96b9..b24b11d8 100644
--- a/internal/wasm/text/func_parser.go
+++ b/internal/wasm/text/func_parser.go
@@ -45,8 +45,8 @@ type funcParser struct {
 var end = []byte{wasm.OpcodeEnd}
 var codeEnd = &wasm.Code{Body: end}
 
-// begin should be called after reaching the "func" keyword in a module field. Parsing continues until onFunc or
-// error.
+// begin should be called after reaching the internalwasm.ExternTypeFuncName keyword in a module field. Parsing
+// continues until onFunc or error.
 //
 // This stage records the ID of the current function, if present, and resumes with onFunc.
 //
diff --git a/internal/wasm/text/memory_parser.go b/internal/wasm/text/memory_parser.go
index 6b763f9e..47c4a04b 100644
--- a/internal/wasm/text/memory_parser.go
+++ b/internal/wasm/text/memory_parser.go
@@ -33,8 +33,8 @@ type memoryParser struct {
 	currentMax *uint32
 }
 
-// begin should be called after reaching the "memory" keyword in a module field. Parsing continues until onMemory or
-// error.
+// begin should be called after reaching the internalwasm.ExternTypeMemoryName keyword in a module field. Parsing
+// continues until onMemory or error.
 //
 // This stage records the ID of the current memory, if present, and resumes with beginMin.
 //
diff --git a/internal/wasm/text/type_parser.go b/internal/wasm/text/type_parser.go
index 110bfb32..80ed37e7 100644
--- a/internal/wasm/text/type_parser.go
+++ b/internal/wasm/text/type_parser.go
@@ -91,7 +91,7 @@ func (p *typeParser) beginFunc(tok tokenType, tokenBytes []byte, _, _ uint32) (t
 		return nil, expectedField(tok)
 	}
 
-	if string(tokenBytes) != "func" {
+	if string(tokenBytes) != wasm.ExternTypeFuncName {
 		return nil, unexpectedFieldName(tokenBytes)
 	}
 
@@ -118,7 +118,7 @@ func (p *typeParser) parseFunc(tok tokenType, tokenBytes []byte, line, col uint3
 	}
 }
 
-// parseFuncEnd completes the "func" field and returns end
+// parseFuncEnd completes the internalwasm.ExternTypeFuncName field and returns end
 func (p *typeParser) parseFuncEnd(tok tokenType, tokenBytes []byte, _, _ uint32) (tokenParser, error) {
 	if tok != tokenRParen {
 		return nil, unexpectedToken(tok, tokenBytes)
diff --git a/internal/wasm/text/typeuse_parser.go b/internal/wasm/text/typeuse_parser.go
index edc5b7c2..bbf33dff 100644
--- a/internal/wasm/text/typeuse_parser.go
+++ b/internal/wasm/text/typeuse_parser.go
@@ -22,7 +22,7 @@ func newTypeUseParser(module *wasm.Module, typeNamespace *indexNamespace) *typeU
 // that is not a "result": pos clarifies this.
 type onTypeUse func(typeIdx wasm.Index, paramNames wasm.NameMap, pos callbackPosition, tok tokenType, tokenBytes []byte, line, col uint32) (tokenParser, error)
 
-// typeUseParser parses an inlined type from a field such "func" and calls onTypeUse.
+// typeUseParser parses an inlined type from a field such internalwasm.ExternTypeFuncName and calls onTypeUse.
 //
 // Ex. `(import "Math" "PI" (func $math.pi (result f32)))`
 //                           starts here --^           ^


Test patch:
diff --git a/internal/wasm/module_test.go b/internal/wasm/module_test.go
index ab286b17..f5b02230 100644
--- a/internal/wasm/module_test.go
+++ b/internal/wasm/module_test.go
@@ -68,7 +68,7 @@ func TestExternTypeName(t *testing.T) {
 	}{
 		{"func", ExternTypeFunc, "func"},
 		{"table", ExternTypeTable, "table"},
-		{"mem", ExternTypeMemory, "mem"},
+		{"mem", ExternTypeMemory, "memory"},
 		{"global", ExternTypeGlobal, "global"},
 		{"unknown", 100, "0x64"},
 	}