github.com/goplus/gossa@v0.3.25/binop_gen.go (about)

     1  //go:build ignore
     2  // +build ignore
     3  
     4  package main
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"go/format"
    10  	"io/ioutil"
    11  	"os"
    12  	"strings"
    13  )
    14  
    15  var (
    16  	ints = []string{"int", "int8", "int16", "int32", "int64",
    17  		"uint", "uint8", "uint16", "uint32", "uint64", "uintptr"}
    18  	floats = []string{"float32", "float64"}
    19  	comps  = []string{"complex64", "complex128"}
    20  	str    = []string{"string"}
    21  )
    22  
    23  func json(kinds ...[]string) (r []string) {
    24  	for _, kind := range kinds {
    25  		r = append(r, kind...)
    26  	}
    27  	return
    28  }
    29  
    30  func main() {
    31  	var buf bytes.Buffer
    32  	buf.WriteString(pkg_head)
    33  
    34  	makeFuncOp(&buf, "makeBinOpADD", "+", json(ints, floats, comps, str))
    35  	makeFuncOp(&buf, "makeBinOpSUB", "-", json(ints, floats, comps))
    36  	makeFuncOp(&buf, "makeBinOpMUL", "*", json(ints, floats, comps))
    37  	makeFuncOp(&buf, "makeBinOpQUO", "/", json(ints, floats, comps))
    38  
    39  	makeFuncOp(&buf, "makeBinOpREM", "%", json(ints))
    40  	makeFuncOp(&buf, "makeBinOpAND", "&", json(ints))
    41  	makeFuncOp(&buf, "makeBinOpOR", "|", json(ints))
    42  	makeFuncOp(&buf, "makeBinOpXOR", "^", json(ints))
    43  	makeFuncOp(&buf, "makeBinOpANDNOT", "&^", json(ints))
    44  
    45  	makeFuncCmp(&buf, "makeBinOpLSS", "<", json(ints, floats, str))
    46  	makeFuncCmp(&buf, "makeBinOpLEQ", "<=", json(ints, floats, str))
    47  	makeFuncCmp(&buf, "makeBinOpGTR", ">", json(ints, floats, str))
    48  	makeFuncCmp(&buf, "makeBinOpGEQ", ">=", json(ints, floats, str))
    49  
    50  	data, err := format.Source(buf.Bytes())
    51  	if err != nil {
    52  		fmt.Println("format error", err)
    53  		os.Exit(2)
    54  	}
    55  	ioutil.WriteFile("./binop.go", data, 0666)
    56  }
    57  
    58  func makeFuncOp(buf *bytes.Buffer, fnname string, op string, kinds []string) {
    59  	buf.WriteString(strings.Replace(func_head_op, "$NAME", fnname, 1))
    60  	buf.WriteString(`if typ.PkgPath() == "" {
    61  		switch typ.Kind() {
    62  `)
    63  	var div_case1 string
    64  	var div_case2 string
    65  	if op == "/" {
    66  		div_case1 = get_func_case1_div()
    67  		div_case2 = get_func_case2_div()
    68  	}
    69  	for _, kind := range kinds {
    70  		r := strings.NewReplacer(
    71  			"Int", strings.Title(kind),
    72  			"int", kind,
    73  			"+", op)
    74  		if op == "/" && strings.Contains(kind, "int") {
    75  			r.WriteString(buf, div_case1)
    76  		} else {
    77  			r.WriteString(buf, func_case1)
    78  		}
    79  	}
    80  	buf.WriteString(`}
    81  	} else {
    82  	t := xtype.TypeOfType(typ)
    83  	switch typ.Kind() {
    84  `)
    85  	for _, kind := range kinds {
    86  		r := strings.NewReplacer(
    87  			"Int", strings.Title(kind),
    88  			"int", kind,
    89  			"+", op)
    90  		if op == "/" && strings.Contains(kind, "int") {
    91  			r.WriteString(buf, div_case2)
    92  		} else {
    93  			r.WriteString(buf, func_case2)
    94  		}
    95  	}
    96  	buf.WriteString(`}
    97  	}
    98  	panic("unreachable")
    99  }`)
   100  }
   101  
   102  func makeFuncCmp(buf *bytes.Buffer, fnname string, op string, kinds []string) {
   103  	buf.WriteString(strings.Replace(func_head_cmp, "$NAME", fnname, 1))
   104  	buf.WriteString(`if typ.PkgPath() == "" {
   105  		switch typ.Kind() {
   106  `)
   107  	for _, kind := range kinds {
   108  		r := strings.NewReplacer(
   109  			"Int", strings.Title(kind),
   110  			"int", kind,
   111  			"+", op)
   112  		r.WriteString(buf, func_case1)
   113  	}
   114  	buf.WriteString(`}
   115  	} else {
   116  	switch typ.Kind() {
   117  `)
   118  	for _, kind := range kinds {
   119  		r := strings.NewReplacer(
   120  			"Int", strings.Title(kind),
   121  			"int", kind,
   122  			"<", op)
   123  		r.WriteString(buf, func_case2_cmp)
   124  	}
   125  	buf.WriteString(`}
   126  	}
   127  	panic("unreachable")
   128  }`)
   129  }
   130  
   131  var pkg_head = `package gossa
   132  
   133  import (
   134  	"reflect"
   135  
   136  	"github.com/goplus/gossa/internal/xtype"
   137  	"golang.org/x/tools/go/ssa"
   138  )
   139  `
   140  
   141  var func_head_op = `
   142  func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) {
   143  	ir := pfn.regIndex(instr)
   144  	ix, kx, vx := pfn.regIndex3(instr.X)
   145  	iy, ky, vy := pfn.regIndex3(instr.Y)
   146  	typ := pfn.Interp.preToType(instr.Type())
   147  `
   148  
   149  var func_head_cmp = `
   150  func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) {
   151  	ir := pfn.regIndex(instr)
   152  	ix, kx, vx := pfn.regIndex3(instr.X)
   153  	iy, ky, vy := pfn.regIndex3(instr.Y)
   154  	typ := pfn.Interp.preToType(instr.X.Type())
   155  `
   156  
   157  func get_func_case1_div() string {
   158  	return strings.Replace(func_case1,
   159  		"v := vx.(int)+vy.(int)",
   160  		`x := vx.(int)
   161  	y := vy.(int)
   162  	if y == 0 {
   163  		return func(fr *frame) { fr.setReg(ir, x/y) }
   164  	}
   165  	v := x/y`, 1)
   166  }
   167  
   168  var func_case1 = `case reflect.Int:
   169  if kx == kindConst && ky == kindConst {
   170  	v := vx.(int)+vy.(int)
   171  	return func(fr *frame) { fr.setReg(ir, v) }
   172  } else if kx == kindConst {
   173  	x := vx.(int)
   174  	return func(fr *frame) { fr.setReg(ir, x+fr.reg(iy).(int)) }
   175  } else if ky == kindConst {
   176  	y := vy.(int)
   177  	return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+y) }
   178  } else {
   179  	return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+fr.reg(iy).(int)) }
   180  }
   181  `
   182  
   183  func get_func_case2_div() string {
   184  	return strings.Replace(func_case2,
   185  		"v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy))",
   186  		`x := xtype.Int(vx)
   187  		y := xtype.Int(vy)
   188  		if y == 0 {
   189  		return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x/y)) }
   190  	}
   191  	v := xtype.Make(t,x/y)`, 1)
   192  }
   193  
   194  var func_case2 = `case reflect.Int:
   195  if kx == kindConst && ky == kindConst {
   196  	v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy))
   197  	return func(fr *frame) { fr.setReg(ir, v) }
   198  } else if kx == kindConst {
   199  	x := xtype.Int(vx)
   200  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x+fr.int(iy))) }
   201  } else if ky == kindConst {
   202  	y := xtype.Int(vy)
   203  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+y)) }
   204  } else {
   205  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+fr.int(iy))) }
   206  }
   207  `
   208  
   209  var func_case2_cmp = `case reflect.Int:
   210  if kx == kindConst && ky == kindConst {
   211  	v := xtype.Int(vx)<xtype.Int(vy)
   212  	return func(fr *frame) { fr.setReg(ir, v) }
   213  } else if kx == kindConst {
   214  	x := xtype.Int(vx)
   215  	return func(fr *frame) { fr.setReg(ir, x<fr.int(iy)) }
   216  } else if ky == kindConst {
   217  	y := xtype.Int(vy)
   218  	return func(fr *frame) { fr.setReg(ir, fr.int(ix)<y) }
   219  } else {
   220  	return func(fr *frame) { fr.setReg(ir, fr.int(ix)<fr.int(iy)) }
   221  }
   222  `