github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/chem/element/gen.go (about) 1 // +build ignore 2 3 package main 4 5 import ( 6 "bytes" 7 "encoding/csv" 8 "fmt" 9 "go/format" 10 "io/ioutil" 11 "log" 12 "os" 13 "sort" 14 "strconv" 15 "strings" 16 ) 17 18 type Element struct { 19 AtomicNumber int 20 Symbol string 21 Name string 22 } 23 24 func main() { 25 file, err := os.Open("elements.csv") 26 if err != nil { 27 log.Fatal(err) 28 } 29 30 data := csv.NewReader(file) 31 records, err := data.ReadAll() 32 if err != nil || len(records) == 0 { 33 log.Fatal(err) 34 } 35 36 var elements []Element 37 for _, rec := range records[1:] { 38 nr, err := strconv.Atoi(rec[0]) 39 if err != nil { 40 log.Fatal(err) 41 } 42 elements = append(elements, Element{ 43 AtomicNumber: nr, 44 Symbol: strings.TrimSpace(rec[1]), 45 Name: strings.TrimSpace(rec[2]), 46 }) 47 } 48 49 sort.Slice(elements, func(i, j int) bool { 50 return elements[i].Symbol < elements[j].Symbol 51 }) 52 53 var buf bytes.Buffer 54 55 fmt.Fprintf(&buf, "package element\n") 56 fmt.Fprintf(&buf, "type Element byte\n") 57 58 fmt.Fprintf(&buf, "const (\n") 59 fmt.Fprintf(&buf, "\tInvalid = Element(0)\n") 60 for i, elem := range elements { 61 fmt.Fprintf(&buf, "\t%v = Element(%v)\n", elem.Symbol, i+1) 62 } 63 fmt.Fprintf(&buf, ")\n") 64 65 fmt.Fprintf(&buf, "var AtomSymbol = [...]string{\"<INVALID>\",\n") 66 for i, elem := range elements { 67 fmt.Fprintf(&buf, "%q, ", elem.Symbol) 68 if (i+1)%10 == 0 { 69 fmt.Fprintf(&buf, "\n") 70 } 71 } 72 fmt.Fprintf(&buf, "\n}\n") 73 74 fmt.Fprintf(&buf, "func (e Element) String() string {\n") 75 fmt.Fprintf(&buf, "\treturn AtomSymbol[int(e)]\n") 76 fmt.Fprintf(&buf, "}\n\n") 77 78 fmt.Fprintf(&buf, "func (m *Matcher) acceptElement(p, t byte) {\n") 79 fmt.Fprintf(&buf, "p0, p1, p2 := m.src[p], m.src[p+1], m.src[p+2]\n") // " 80 81 root := Trie{} 82 for _, elem := range elements { 83 root.Add(elem.Symbol, strings.ToLower(elem.Symbol)) 84 } 85 86 var emitLayer func(t *Trie, n int) 87 emitLayer = func(t *Trie, n int) { 88 if t.Accept != "" { 89 defer fmt.Fprintf(&buf, "m.accepted(%v, p+%v, t)\n", t.Accept, n) 90 } 91 92 if len(t.Child) == 0 { 93 return 94 } 95 96 if len(t.Child) == 1 { 97 fmt.Fprintf(&buf, "if p%v == %q {\n", n, t.Child[0].Rune) 98 defer fmt.Fprintf(&buf, "}\n") 99 emitLayer(t.Child[0], n+1) 100 return 101 } 102 103 fmt.Fprintf(&buf, "switch p%v {\n", n) 104 defer fmt.Fprintf(&buf, "}\n") 105 106 for _, child := range t.Child { 107 fmt.Fprintf(&buf, "case %q:\n", child.Rune) 108 emitLayer(child, n+1) 109 } 110 } 111 emitLayer(&root, 0) 112 fmt.Fprintf(&buf, "}\n\n") 113 114 //ioutil.WriteFile("element.raw.go", buf.Bytes(), 0755) 115 116 srcdata, err := format.Source(buf.Bytes()) 117 if err != nil { 118 log.Fatal(err) 119 } 120 121 ioutil.WriteFile("element.go", srcdata, 0755) 122 } 123 124 type Trie struct { 125 Rune rune 126 Accept string 127 Child []*Trie 128 } 129 130 func (t *Trie) Add(elem string, s string) { 131 if s == "" { 132 t.Accept = elem 133 return 134 } 135 136 for _, n := range t.Child { 137 if n.Rune == rune(s[0]) { 138 n.Add(elem, s[1:]) 139 return 140 } 141 } 142 143 n := &Trie{} 144 n.Rune = rune(s[0]) 145 n.Add(elem, s[1:]) 146 t.Child = append(t.Child, n) 147 }