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  }