github.com/goplus/igop@v0.25.0/binop_gen.go (about)

     1  //go:build ignore
     2  // +build ignore
     3  
     4  /*
     5   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package main
    21  
    22  import (
    23  	"bytes"
    24  	"fmt"
    25  	"go/format"
    26  	"io/ioutil"
    27  	"os"
    28  	"strings"
    29  )
    30  
    31  var (
    32  	ints = []string{"int", "int8", "int16", "int32", "int64",
    33  		"uint", "uint8", "uint16", "uint32", "uint64", "uintptr"}
    34  	floats = []string{"float32", "float64"}
    35  	comps  = []string{"complex64", "complex128"}
    36  	str    = []string{"string"}
    37  )
    38  
    39  func json(kinds ...[]string) (r []string) {
    40  	for _, kind := range kinds {
    41  		r = append(r, kind...)
    42  	}
    43  	return
    44  }
    45  
    46  func main() {
    47  	var buf bytes.Buffer
    48  	buf.WriteString(pkg_head)
    49  
    50  	makeFuncOp(&buf, "makeBinOpADD", "+", json(ints, floats, comps, str))
    51  	makeFuncOp(&buf, "makeBinOpSUB", "-", json(ints, floats, comps))
    52  	makeFuncOp(&buf, "makeBinOpMUL", "*", json(ints, floats, comps))
    53  	makeFuncOp(&buf, "makeBinOpQUO", "/", json(ints, floats, comps))
    54  
    55  	makeFuncOp(&buf, "makeBinOpREM", "%", json(ints))
    56  	makeFuncOp(&buf, "makeBinOpAND", "&", json(ints))
    57  	makeFuncOp(&buf, "makeBinOpOR", "|", json(ints))
    58  	makeFuncOp(&buf, "makeBinOpXOR", "^", json(ints))
    59  	makeFuncOp(&buf, "makeBinOpANDNOT", "&^", json(ints))
    60  
    61  	makeFuncCmp(&buf, "makeBinOpLSS", "<", json(ints, floats, str))
    62  	makeFuncCmp(&buf, "makeBinOpLEQ", "<=", json(ints, floats, str))
    63  	makeFuncCmp(&buf, "makeBinOpGTR", ">", json(ints, floats, str))
    64  	makeFuncCmp(&buf, "makeBinOpGEQ", ">=", json(ints, floats, str))
    65  
    66  	data, err := format.Source(buf.Bytes())
    67  	if err != nil {
    68  		fmt.Println("format error", err)
    69  		os.Exit(2)
    70  	}
    71  	ioutil.WriteFile("./binop.go", data, 0666)
    72  }
    73  
    74  func makeFuncOp(buf *bytes.Buffer, fnname string, op string, kinds []string) {
    75  	buf.WriteString(strings.Replace(func_head_op, "$NAME", fnname, 1))
    76  	buf.WriteString(`if typ.PkgPath() == "" {
    77  		switch typ.Kind() {
    78  `)
    79  	var div_case1 string
    80  	var div_case2 string
    81  	if op == "/" {
    82  		div_case1 = get_func_case1_div()
    83  		div_case2 = get_func_case2_div()
    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_case1)
    92  		} else {
    93  			r.WriteString(buf, func_case1)
    94  		}
    95  	}
    96  	buf.WriteString(`}
    97  	} else {
    98  	t := xtype.TypeOfType(typ)
    99  	switch typ.Kind() {
   100  `)
   101  	for _, kind := range kinds {
   102  		r := strings.NewReplacer(
   103  			"Int", strings.Title(kind),
   104  			"int", kind,
   105  			"+", op)
   106  		if op == "/" && strings.Contains(kind, "int") {
   107  			r.WriteString(buf, div_case2)
   108  		} else {
   109  			r.WriteString(buf, func_case2)
   110  		}
   111  	}
   112  	buf.WriteString(`}
   113  	}
   114  	panic("unreachable")
   115  }`)
   116  }
   117  
   118  func makeFuncCmp(buf *bytes.Buffer, fnname string, op string, kinds []string) {
   119  	buf.WriteString(strings.Replace(func_head_cmp, "$NAME", fnname, 1))
   120  	buf.WriteString(`if typ.PkgPath() == "" {
   121  		switch typ.Kind() {
   122  `)
   123  	for _, kind := range kinds {
   124  		r := strings.NewReplacer(
   125  			"Int", strings.Title(kind),
   126  			"int", kind,
   127  			"+", op)
   128  		r.WriteString(buf, func_case1)
   129  	}
   130  	buf.WriteString(`}
   131  	} else {
   132  	switch typ.Kind() {
   133  `)
   134  	for _, kind := range kinds {
   135  		r := strings.NewReplacer(
   136  			"Int", strings.Title(kind),
   137  			"int", kind,
   138  			"<", op)
   139  		r.WriteString(buf, func_case2_cmp)
   140  	}
   141  	buf.WriteString(`}
   142  	}
   143  	panic("unreachable")
   144  }`)
   145  }
   146  
   147  var pkg_head = `/*
   148   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
   149   *
   150   * Licensed under the Apache License, Version 2.0 (the "License");
   151   * you may not use this file except in compliance with the License.
   152   * You may obtain a copy of the License at
   153   *
   154   *     http://www.apache.org/licenses/LICENSE-2.0
   155   *
   156   * Unless required by applicable law or agreed to in writing, software
   157   * distributed under the License is distributed on an "AS IS" BASIS,
   158   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   159   * See the License for the specific language governing permissions and
   160   * limitations under the License.
   161   */
   162  
   163  package igop
   164  
   165  import (
   166  	"reflect"
   167  
   168  	"github.com/visualfc/xtype"
   169  	"golang.org/x/tools/go/ssa"
   170  )
   171  `
   172  
   173  var func_head_op = `
   174  func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) {
   175  	ir := pfn.regIndex(instr)
   176  	ix, kx, vx := pfn.regIndex3(instr.X)
   177  	iy, ky, vy := pfn.regIndex3(instr.Y)
   178  	typ := pfn.Interp.preToType(instr.Type())
   179  `
   180  
   181  var func_head_cmp = `
   182  func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) {
   183  	ir := pfn.regIndex(instr)
   184  	ix, kx, vx := pfn.regIndex3(instr.X)
   185  	iy, ky, vy := pfn.regIndex3(instr.Y)
   186  	typ := pfn.Interp.preToType(instr.X.Type())
   187  `
   188  
   189  func get_func_case1_div() string {
   190  	return strings.Replace(func_case1,
   191  		"v := vx.(int)+vy.(int)",
   192  		`x := vx.(int)
   193  	y := vy.(int)
   194  	if y == 0 {
   195  		return func(fr *frame) { fr.setReg(ir, x/y) }
   196  	}
   197  	v := x/y`, 1)
   198  }
   199  
   200  var func_case1 = `case reflect.Int:
   201  if kx == kindConst && ky == kindConst {
   202  	v := vx.(int)+vy.(int)
   203  	return func(fr *frame) { fr.setReg(ir, v) }
   204  } else if kx == kindConst {
   205  	x := vx.(int)
   206  	return func(fr *frame) { fr.setReg(ir, x+fr.reg(iy).(int)) }
   207  } else if ky == kindConst {
   208  	y := vy.(int)
   209  	return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+y) }
   210  } else {
   211  	return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+fr.reg(iy).(int)) }
   212  }
   213  `
   214  
   215  func get_func_case2_div() string {
   216  	return strings.Replace(func_case2,
   217  		"v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy))",
   218  		`x := xtype.Int(vx)
   219  		y := xtype.Int(vy)
   220  		if y == 0 {
   221  		return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x/y)) }
   222  	}
   223  	v := xtype.Make(t,x/y)`, 1)
   224  }
   225  
   226  var func_case2 = `case reflect.Int:
   227  if kx == kindConst && ky == kindConst {
   228  	v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy))
   229  	return func(fr *frame) { fr.setReg(ir, v) }
   230  } else if kx == kindConst {
   231  	x := xtype.Int(vx)
   232  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x+fr.int(iy))) }
   233  } else if ky == kindConst {
   234  	y := xtype.Int(vy)
   235  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+y)) }
   236  } else {
   237  	return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+fr.int(iy))) }
   238  }
   239  `
   240  
   241  var func_case2_cmp = `case reflect.Int:
   242  if kx == kindConst && ky == kindConst {
   243  	v := xtype.Int(vx)<xtype.Int(vy)
   244  	return func(fr *frame) { fr.setReg(ir, v) }
   245  } else if kx == kindConst {
   246  	x := xtype.Int(vx)
   247  	return func(fr *frame) { fr.setReg(ir, x<fr.int(iy)) }
   248  } else if ky == kindConst {
   249  	y := xtype.Int(vy)
   250  	return func(fr *frame) { fr.setReg(ir, fr.int(ix)<y) }
   251  } else {
   252  	return func(fr *frame) { fr.setReg(ir, fr.int(ix)<fr.int(iy)) }
   253  }
   254  `