Refactor generate

This commit is contained in:
Anton Medvedev
2022-10-17 22:36:34 +02:00
parent 370551eb7e
commit 7c2a8a87ff
+210 -169
View File
@@ -1,189 +1,230 @@
package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"strings"
"text/template"
)
func check(e error) {
if e != nil {
panic(e)
func main() {
var b bytes.Buffer
err := template.Must(
template.New("helpers").
Funcs(template.FuncMap{
"cases": func(op string) string { return cases(op, false) },
"cases_int_only": func(op string) string { return cases(op, true) },
}).
Parse(helpers),
).Execute(&b, types)
if err != nil {
panic(err)
}
formatted, err := format.Source(b.Bytes())
if err != nil {
panic(err)
}
fmt.Print(string(formatted))
}
func main() {
var data string
var types = []string{
"uint",
"uint8",
"uint16",
"uint32",
"uint64",
"int",
"int8",
"int16",
"int32",
"int64",
"float32",
"float64",
}
func cases(op string, noFloat bool) string {
var out string
echo := func(s string, xs ...interface{}) {
data += fmt.Sprintf(s, xs...) + "\n"
out += fmt.Sprintf(s, xs...) + "\n"
}
echo(`// Code generated by vm/runtime/generate/main.go. DO NOT EDIT.`)
echo(``)
echo(`package runtime`)
echo(`import (`)
echo(`"fmt"`)
echo(`"reflect"`)
echo(`"time"`)
echo(`)`)
types := []string{
"uint",
"uint8",
"uint16",
"uint32",
"uint64",
"int",
"int8",
"int16",
"int32",
"int64",
"float32",
"float64",
}
helpers := []struct {
name, op string
noFloat, string bool
}{
{
name: "Equal",
op: "==",
string: true,
},
{
name: "Less",
op: "<",
string: true,
},
{
name: "More",
op: ">",
string: true,
},
{
name: "LessOrEqual",
op: "<=",
string: true,
},
{
name: "MoreOrEqual",
op: ">=",
string: true,
},
{
name: "Add",
op: "+",
string: true,
},
{
name: "Subtract",
op: "-",
},
{
name: "Multiply",
op: "*",
},
{
name: "Divide",
op: "/",
},
{
name: "Modulo",
op: "%",
noFloat: true,
},
}
for _, helper := range helpers {
name := helper.name
op := helper.op
echo(`func %v(a, b interface{}) interface{} {`, name)
echo(`switch x := a.(type) {`)
for i, a := range types {
if helper.noFloat && strings.HasPrefix(a, "float") {
for i, a := range types {
if noFloat && strings.HasPrefix(a, "float") {
continue
}
echo(`case %v:`, a)
echo(`switch y := b.(type) {`)
for j, b := range types {
if noFloat && strings.HasPrefix(b, "float") {
continue
}
echo(`case %v:`, a)
echo(`switch y := b.(type) {`)
for j, b := range types {
if helper.noFloat && strings.HasPrefix(b, "float") {
continue
}
echo(`case %v:`, b)
if i == j {
echo(`return x %v y`, op)
}
if i < j {
echo(`return %v(x) %v y`, b, op)
}
if i > j {
echo(`return x %v %v(y)`, op, a)
}
echo(`case %v:`, b)
if i == j {
echo(`return x %v y`, op)
}
if i < j {
echo(`return %v(x) %v y`, b, op)
}
if i > j {
echo(`return x %v %v(y)`, op, a)
}
echo(`}`)
}
if helper.string {
echo(`case string:`)
echo(`switch y := b.(type) {`)
echo(`case string: return x %v y`, op)
echo(`}`)
}
switch op {
case "==":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.Equal(y)`)
echo(`}`)
case "<":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.Before(y)`)
echo(`}`)
case ">":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.After(y)`)
echo(`}`)
case "<=":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.Before(y) || x.Equal(y)`)
echo(`}`)
case ">=":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.After(y) || x.Equal(y)`)
echo(`}`)
case "+":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Duration: return x.Add(y)`)
echo(`}`)
echo(`case time.Duration:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return y.Add(x)`)
echo(`}`)
case "-":
echo(`case time.Time:`)
echo(`switch y := b.(type) {`)
echo(`case time.Time: return x.Sub(y)`)
echo(`}`)
}
echo(`}`)
if name == "Equal" {
echo(`if IsNil(a) && IsNil(b) { return true }`)
echo(`return reflect.DeepEqual(a, b)`)
} else {
echo(`panic(fmt.Sprintf("invalid operation: %%T %%v %%T", a, "%v", b))`, op)
}
echo(`}`)
echo(``)
}
b, err := format.Source([]byte(data))
check(err)
err = ioutil.WriteFile("helpers.go", b, 0644)
check(err)
return strings.TrimRight(out, "\n")
}
const helpers = `// Code generated by vm/runtime/generate/main.go. DO NOT EDIT.
package runtime
import (
"fmt"
"reflect"
"time"
)
func Equal(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "==" }}
case string:
switch y := b.(type) {
case string:
return x == y
}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.Equal(y)
}
}
if IsNil(a) && IsNil(b) {
return true
}
return reflect.DeepEqual(a, b)
}
func Less(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "<" }}
case string:
switch y := b.(type) {
case string:
return x < y
}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.Before(y)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "<", b))
}
func More(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases ">" }}
case string:
switch y := b.(type) {
case string:
return x > y
}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.After(y)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, ">", b))
}
func LessOrEqual(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "<=" }}
case string:
switch y := b.(type) {
case string:
return x <= y
}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.Before(y) || x.Equal(y)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "<=", b))
}
func MoreOrEqual(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases ">=" }}
case string:
switch y := b.(type) {
case string:
return x >= y
}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.After(y) || x.Equal(y)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, ">=", b))
}
func Add(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "+" }}
case string:
switch y := b.(type) {
case string:
return x + y
}
case time.Time:
switch y := b.(type) {
case time.Duration:
return x.Add(y)
}
case time.Duration:
switch y := b.(type) {
case time.Time:
return y.Add(x)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "+", b))
}
func Subtract(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "-" }}
case time.Time:
switch y := b.(type) {
case time.Time:
return x.Sub(y)
}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "-", b))
}
func Multiply(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "*" }}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "*", b))
}
func Divide(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases "/" }}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "/", b))
}
func Modulo(a, b interface{}) interface{} {
switch x := a.(type) {
{{ cases_int_only "%" }}
}
panic(fmt.Sprintf("invalid operation: %T %v %T", a, "%", b))
}
`