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 `