@@ -2,7 +2,9 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "encoding/binary"
5
6
"fmt"
7
+ "io"
6
8
"os"
7
9
8
10
"github.com/tetratelabs/wazero"
@@ -11,7 +13,7 @@ import (
11
13
12
14
// Constants for memory layout
13
15
const (
14
- wasmPageSize = 64 * 1024
16
+ wasmPageSize = 64 * 1024
15
17
InputBufferOffset = wasmPageSize
16
18
InputBufferSize = wasmPageSize
17
19
MemoTableOffset = InputBufferOffset + InputBufferSize
@@ -35,15 +37,72 @@ func (m *WasmMatcher) GetModule() api.Module {
35
37
}
36
38
37
39
func NewWasmMatcher (ctx context.Context ) * WasmMatcher {
40
+ // Create a new runtime with custom sections enabled
41
+ config := wazero .NewRuntimeConfig ().WithCustomSections (true )
42
+
38
43
return & WasmMatcher {
39
- runtime : wazero .NewRuntime (ctx ),
44
+ runtime : wazero .NewRuntimeWithConfig (ctx , config ),
40
45
ctx : ctx ,
41
46
ruleIds : make (map [string ]int ),
42
47
pos : 0 ,
43
48
lastMatchResult : false ,
44
49
}
45
50
}
46
51
52
+ // parseRuleNames parses the rule names from the custom section data
53
+ // The data is formatted as a WebAssembly vector of strings (each string is a length-prefixed UTF-8 bytes)
54
+ // with LEB128-encoded lengths
55
+ func parseRuleNames (data []byte ) ([]string , error ) {
56
+ if len (data ) == 0 {
57
+ return nil , fmt .Errorf ("empty custom section data" )
58
+ }
59
+
60
+ // Read the number of names (vec length) as LEB128-encoded uint32
61
+ numNamesUint64 , bytesRead := binary .Uvarint (data )
62
+ if bytesRead <= 0 {
63
+ return nil , fmt .Errorf ("failed to read number of names: %v" , io .ErrUnexpectedEOF )
64
+ }
65
+
66
+ // Ensure the value fits in uint32
67
+ if numNamesUint64 > uint64 (^ uint32 (0 )) {
68
+ return nil , fmt .Errorf ("number of names exceeds maximum uint32 value" )
69
+ }
70
+
71
+ numNames := uint32 (numNamesUint64 )
72
+ data = data [bytesRead :]
73
+
74
+ names := make ([]string , numNames )
75
+ for i := uint32 (0 ); i < numNames ; i ++ {
76
+ // Read the length of the name as LEB128-encoded uint32
77
+ nameLenUint64 , bytesRead := binary .Uvarint (data )
78
+ if bytesRead <= 0 {
79
+ return nil , fmt .Errorf ("failed to read name length: %v" , io .ErrUnexpectedEOF )
80
+ }
81
+
82
+ // Ensure the value fits in uint32
83
+ if nameLenUint64 > uint64 (^ uint32 (0 )) {
84
+ return nil , fmt .Errorf ("name length exceeds maximum uint32 value" )
85
+ }
86
+
87
+ nameLen := uint32 (nameLenUint64 )
88
+ data = data [bytesRead :]
89
+
90
+ // Ensure we have enough bytes to read
91
+ if uint64 (len (data )) < uint64 (nameLen ) {
92
+ return nil , fmt .Errorf ("buffer too small to read name bytes" )
93
+ }
94
+
95
+ // Read the name bytes
96
+ nameBytes := data [:nameLen ]
97
+ data = data [nameLen :]
98
+
99
+ // Convert to string
100
+ names [i ] = string (nameBytes )
101
+ }
102
+
103
+ return names , nil
104
+ }
105
+
47
106
func (m * WasmMatcher ) LoadModule (wasmPath string ) error {
48
107
// Read the WASM file
49
108
wasmBytes , err := os .ReadFile (wasmPath )
@@ -74,27 +133,51 @@ func (m *WasmMatcher) LoadModule(wasmPath string) error {
74
133
return fmt .Errorf ("failed to create host module: %v" , err )
75
134
}
76
135
77
- // Instantiate the module
78
- m . module , err = m .runtime .Instantiate (m .ctx , wasmBytes )
136
+ // First compile the module to access the custom sections
137
+ compiledModule , err : = m .runtime .CompileModule (m .ctx , wasmBytes )
79
138
if err != nil {
80
- return fmt .Errorf ("error instantiating module: %v" , err )
139
+ return fmt .Errorf ("error compiling module: %v" , err )
81
140
}
82
141
83
- // Extract rule IDs if this is a grammar module
84
- rulesFunc := m . module . ExportedFunction ( "getRuleIds" )
85
- if rulesFunc ! = nil {
86
- // In a real implementation, you would actually extract the rule IDs
87
- // by calling the exported function and reading the results
142
+ // Get all custom sections from the module
143
+ customSections := compiledModule . CustomSections ( )
144
+ if customSections = = nil {
145
+ return fmt . Errorf ( "no custom sections found in module" )
146
+ }
88
147
89
- // For now, just populate with some example rule IDs
90
- m .ruleIds = map [string ]int {
91
- "Start" : 0 ,
92
- "Expr" : 1 ,
93
- "Term" : 2 ,
94
- "Factor" : 3 ,
148
+ var ruleNamesSection api.CustomSection
149
+ for _ , section := range customSections {
150
+ if section .Name () == "ruleNames" {
151
+ ruleNamesSection = section
152
+ break
95
153
}
154
+ }
155
+
156
+ if ruleNamesSection == nil {
157
+ return fmt .Errorf ("required custom section 'ruleNames' not found" )
158
+ }
159
+
160
+ // Parse rule names from the custom section data
161
+ ruleNames , err := parseRuleNames (ruleNamesSection .Data ())
162
+ if err != nil {
163
+ return fmt .Errorf ("failed to parse rule names from custom section: %v" , err )
164
+ }
165
+
166
+ // Now instantiate the module
167
+ m .module , err = m .runtime .InstantiateModule (m .ctx , compiledModule , wazero .NewModuleConfig ())
168
+ if err != nil {
169
+ return fmt .Errorf ("error instantiating module: %v" , err )
170
+ }
171
+
172
+ // Build the ruleIds map (mapping from name to index)
173
+ m .ruleIds = make (map [string ]int , len (ruleNames ))
174
+ for i , name := range ruleNames {
175
+ m .ruleIds [name ] = i
176
+ }
96
177
97
- m .defaultStartRule = "Start"
178
+ // Set the default start rule to the first rule
179
+ if len (ruleNames ) > 0 {
180
+ m .defaultStartRule = ruleNames [0 ]
98
181
}
99
182
100
183
return nil
0 commit comments