github.com/lmittmann/w3@v0.20.0/internal/fourbyte/gen.go (about) 1 //go:build ignore 2 3 package main 4 5 import ( 6 "bufio" 7 "bytes" 8 "fmt" 9 "os" 10 "slices" 11 "strings" 12 "sync" 13 "text/template" 14 15 "github.com/lmittmann/w3" 16 ) 17 18 func main() { 19 var ( 20 errFuncs, errEvents error 21 wg sync.WaitGroup 22 ) 23 24 wg.Add(2) 25 go func() { 26 defer wg.Done() 27 errFuncs = genFuncs("funcs.txt", "funcs.go") 28 }() 29 go func() { 30 defer wg.Done() 31 errEvents = genEvents("events.txt", "events.go") 32 }() 33 34 wg.Wait() 35 if errFuncs != nil { 36 fmt.Printf("error generating functions: %v\n", errFuncs) 37 } 38 if errEvents != nil { 39 fmt.Printf("error generating events: %v\n", errEvents) 40 } 41 if errFuncs != nil || errEvents != nil { 42 os.Exit(1) 43 } 44 } 45 46 func genFuncs(fn, goFn string) error { 47 // open function definitions 48 f, err := os.Open(fn) 49 if err != nil { 50 return err 51 } 52 defer f.Close() 53 54 // parse function definitions from file 55 var functions []function 56 knownIdentifiers := make(map[[4]byte]struct{}) 57 58 scanner := bufio.NewScanner(f) 59 for i := 0; scanner.Scan(); i++ { 60 line := scanner.Text() 61 tokens := strings.Split(line, "\t") 62 if len(tokens) == 1 && strings.HasSuffix(tokens[0], ")") { 63 tokens = append(tokens, "") // no returns 64 } 65 if len(tokens) != 2 { 66 return fmt.Errorf("line %d: invalid line %q", i, line) 67 } 68 69 fn, err := w3.NewFunc(tokens[0], tokens[1]) 70 if err != nil { 71 return fmt.Errorf("line %d: %v (%q)", i, err, line) 72 } 73 74 if _, ok := knownIdentifiers[fn.Selector]; ok { 75 return fmt.Errorf("line %d: duplicate function selector %q", i, line) 76 } 77 knownIdentifiers[fn.Selector] = struct{}{} 78 79 functions = append(functions, function{ 80 Selector: fn.Selector, 81 Signature: tokens[0], 82 Returns: tokens[1], 83 }) 84 } 85 if err := scanner.Err(); err != nil { 86 return fmt.Errorf("scan lines: %v", err) 87 } 88 89 // make sure function definitions stay in alphabetical order 90 slices.SortFunc(functions, func(a, b function) int { 91 return strings.Compare(strings.ToLower(a.Signature), strings.ToLower(b.Signature)) 92 }) 93 f, err = os.OpenFile(fn, os.O_WRONLY, 0644) 94 if err != nil { 95 return err 96 } 97 defer f.Close() 98 99 for _, fn := range functions { 100 if _, err := f.WriteString(strings.TrimSpace(fn.Signature+"\t"+fn.Returns) + "\n"); err != nil { 101 return err 102 } 103 } 104 105 // generate go file 106 goF, err := os.Create(goFn) 107 if err != nil { 108 return err 109 } 110 defer goF.Close() 111 112 slices.SortFunc(functions, func(a, b function) int { 113 return bytes.Compare(a.Selector[:], b.Selector[:]) 114 }) 115 116 if err := tmplFuncs.Execute(goF, &model{Functions: functions}); err != nil { 117 return fmt.Errorf("execute template: %v", err) 118 } 119 120 return nil 121 } 122 123 func genEvents(fn, goFn string) error { 124 // open event definitions 125 f, err := os.Open(fn) 126 if err != nil { 127 return err 128 } 129 defer f.Close() 130 131 var events []event 132 knownTopic0s := make(map[[32]byte]struct{}) 133 scanner := bufio.NewScanner(f) 134 for i := 0; scanner.Scan(); i++ { 135 line := scanner.Text() 136 137 evt, err := w3.NewEvent(line) 138 if err != nil { 139 return fmt.Errorf("line %d: %v (%q)", i, err, line) 140 } 141 142 if _, ok := knownTopic0s[evt.Topic0]; ok { 143 return fmt.Errorf("line %d: duplicate function selector %q", i, line) 144 } 145 knownTopic0s[evt.Topic0] = struct{}{} 146 147 events = append(events, event{ 148 Topic0: evt.Topic0, 149 Signature: line, 150 }) 151 } 152 if err := scanner.Err(); err != nil { 153 return fmt.Errorf("scan lines: %v", err) 154 } 155 156 // make sure event definitions stay in alphabetical order 157 slices.SortFunc(events, func(a, b event) int { 158 return strings.Compare(strings.ToLower(a.Signature), strings.ToLower(b.Signature)) 159 }) 160 f, err = os.OpenFile(fn, os.O_WRONLY, 0644) 161 if err != nil { 162 return err 163 } 164 defer f.Close() 165 166 for _, evt := range events { 167 if _, err := f.WriteString(evt.Signature + "\n"); err != nil { 168 return err 169 } 170 } 171 172 // generate go file 173 goF, err := os.Create(goFn) 174 if err != nil { 175 return err 176 } 177 defer goF.Close() 178 179 slices.SortFunc(events, func(a, b event) int { 180 return bytes.Compare(a.Topic0[:], b.Topic0[:]) 181 }) 182 183 if err := tmplEvents.Execute(goF, &model{Events: events}); err != nil { 184 return fmt.Errorf("execute template: %v", err) 185 } 186 187 return nil 188 189 } 190 191 type model struct { 192 Functions []function 193 Events []event 194 } 195 196 type function struct { 197 Selector [4]byte 198 Signature string 199 Returns string 200 } 201 202 type event struct { 203 Topic0 [32]byte 204 Signature string 205 } 206 207 var ( 208 tmplFuncs = template.Must(template.New("funcs").Parse(`// Code generated by "go generate"; DO NOT EDIT. 209 package fourbyte 210 211 import "github.com/lmittmann/w3" 212 213 var functions = map[[4]byte]*w3.Func{ 214 {{- range .Functions }} 215 {{ printf "{0x%02x, 0x%02x, 0x%02x, 0x%02x}: w3.MustNewFunc(%q, %q)" 216 (index .Selector 0) 217 (index .Selector 1) 218 (index .Selector 2) 219 (index .Selector 3) 220 .Signature 221 .Returns 222 }}, 223 {{- end }} 224 } 225 `)) 226 227 tmplEvents = template.Must(template.New("events").Parse(`// Code generated by "go generate"; DO NOT EDIT. 228 package fourbyte 229 230 import "github.com/lmittmann/w3" 231 232 var events = map[[32]byte]*w3.Event{ 233 {{- range .Events }} 234 {{ printf "{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}: w3.MustNewEvent(%q)" 235 (index .Topic0 0) 236 (index .Topic0 1) 237 (index .Topic0 2) 238 (index .Topic0 3) 239 (index .Topic0 4) 240 (index .Topic0 5) 241 (index .Topic0 6) 242 (index .Topic0 7) 243 (index .Topic0 8) 244 (index .Topic0 9) 245 (index .Topic0 10) 246 (index .Topic0 11) 247 (index .Topic0 12) 248 (index .Topic0 13) 249 (index .Topic0 14) 250 (index .Topic0 15) 251 (index .Topic0 16) 252 (index .Topic0 17) 253 (index .Topic0 18) 254 (index .Topic0 19) 255 (index .Topic0 20) 256 (index .Topic0 21) 257 (index .Topic0 22) 258 (index .Topic0 23) 259 (index .Topic0 24) 260 (index .Topic0 25) 261 (index .Topic0 26) 262 (index .Topic0 27) 263 (index .Topic0 28) 264 (index .Topic0 29) 265 (index .Topic0 30) 266 (index .Topic0 31) 267 .Signature 268 }}, 269 {{- end }} 270 } 271 `)) 272 )