When working with an untyped const expression involving a division, if
the default type of the result should be an int (for example because the
default types of all the operands are ints as well), then we should make
sure that the operation that is applied is indeed an integer division,
and that the type of the result is not a float.
This is achieved by using the QUO_ASSIGN operator, instead of the QUO
operator.
This should fix several problems lurking around, and it notably fixes
one of the visible consequences, which is a systematic panic when using
the REPL as a "calculator".
This incidentally also allows us to revert what was done in
5dfc3b86dc since it now turns out it was
just a hack to fix one of the symptoms.
Fixes #864
1016 lines
23 KiB
Go
1016 lines
23 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"go/format"
|
|
"io/ioutil"
|
|
"log"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
const model = `package interp
|
|
|
|
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
|
|
|
|
import (
|
|
"go/constant"
|
|
"go/token"
|
|
"reflect"
|
|
)
|
|
|
|
// Arithmetic operators
|
|
{{range $name, $op := .Arithmetic}}
|
|
func {{$name}}(n *node) {
|
|
next := getExec(n.tnext)
|
|
typ := n.typ.concrete().TypeOf()
|
|
dest := genValueOutput(n, typ)
|
|
c0, c1 := n.child[0], n.child[1]
|
|
|
|
switch typ.Kind() {
|
|
{{- if $op.Str}}
|
|
case reflect.String:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vString(c0.rval)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetString(s0 {{$op.Name}} v1(f).String())
|
|
return next
|
|
}
|
|
case c1.rval.IsValid():
|
|
v0 := genValue(c0)
|
|
s1 := vString(c1.rval)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetString(v0(f).String() {{$op.Name}} s1)
|
|
return next
|
|
}
|
|
default:
|
|
v0 := genValue(c0)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetString(v0(f).String() {{$op.Name}} v1(f).String())
|
|
return next
|
|
}
|
|
}
|
|
{{- end}}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
i := vInt(c0.rval)
|
|
{{- if $op.Shift}}
|
|
v1 := genValueUint(c1)
|
|
{{else}}
|
|
v1 := genValueInt(c1)
|
|
{{end -}}
|
|
n.exec = func(f *frame) bltn {
|
|
_, j := v1(f)
|
|
dest(f).SetInt(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case c1.rval.IsValid():
|
|
v0 := genValueInt(c0)
|
|
{{- if $op.Shift}}
|
|
j := vUint(c1.rval)
|
|
{{else}}
|
|
j := vInt(c1.rval)
|
|
{{end -}}
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
dest(f).SetInt(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
default:
|
|
v0 := genValueInt(c0)
|
|
{{- if $op.Shift}}
|
|
v1 := genValueUint(c1)
|
|
{{else}}
|
|
v1 := genValueInt(c1)
|
|
{{end -}}
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
_, j := v1(f)
|
|
dest(f).SetInt(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
i := vUint(c0.rval)
|
|
v1 := genValueUint(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
_, j := v1(f)
|
|
dest(f).SetUint(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case c1.rval.IsValid():
|
|
j := vUint(c1.rval)
|
|
v0 := genValueUint(c0)
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
dest(f).SetUint(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
default:
|
|
v0 := genValueUint(c0)
|
|
v1 := genValueUint(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
_, j := v1(f)
|
|
dest(f).SetUint(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
}
|
|
{{- if $op.Float}}
|
|
case reflect.Float32, reflect.Float64:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
i := vFloat(c0.rval)
|
|
v1 := genValueFloat(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
_, j := v1(f)
|
|
dest(f).SetFloat(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case c1.rval.IsValid():
|
|
j := vFloat(c1.rval)
|
|
v0 := genValueFloat(c0)
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
dest(f).SetFloat(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
default:
|
|
v0 := genValueFloat(c0)
|
|
v1 := genValueFloat(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
_, i := v0(f)
|
|
_, j := v1(f)
|
|
dest(f).SetFloat(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
}
|
|
case reflect.Complex64, reflect.Complex128:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
r0 := vComplex(c0.rval)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetComplex(r0 {{$op.Name}} v1(f).Complex())
|
|
return next
|
|
}
|
|
case c1.rval.IsValid():
|
|
r1 := vComplex(c1.rval)
|
|
v0 := genValue(c0)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetComplex(v0(f).Complex() {{$op.Name}} r1)
|
|
return next
|
|
}
|
|
default:
|
|
v0 := genValue(c0)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
dest(f).SetComplex(v0(f).Complex() {{$op.Name}} v1(f).Complex())
|
|
return next
|
|
}
|
|
}
|
|
{{- end}}
|
|
}
|
|
}
|
|
|
|
func {{$name}}Const(n *node) {
|
|
v0, v1 := n.child[0].rval, n.child[1].rval
|
|
{{- if $op.Shift}}
|
|
isConst := (v0.IsValid() && isConstantValue(v0.Type()))
|
|
{{- else}}
|
|
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
|
{{- end}}
|
|
t := n.typ.rtype
|
|
if isConst {
|
|
t = constVal
|
|
}
|
|
n.rval = reflect.New(t).Elem()
|
|
switch {
|
|
case isConst:
|
|
{{- if $op.Shift}}
|
|
v := constant.Shift(vConstantValue(v0), token.{{tokenFromName $name}}, uint(vUint(v1)))
|
|
n.rval.Set(reflect.ValueOf(v))
|
|
{{- else if (eq $op.Name "/")}}
|
|
var operator token.Token
|
|
// When the result of the operation is expected to be an int (because both
|
|
// operands are ints), we want to force the type of the whole expression to be an
|
|
// int (and not a float), which is achieved by using the QUO_ASSIGN operator.
|
|
if n.typ.untyped && isInt(n.typ.rtype) {
|
|
operator = token.QUO_ASSIGN
|
|
} else {
|
|
operator = token.QUO
|
|
}
|
|
v := constant.BinaryOp(vConstantValue(v0), operator, vConstantValue(v1))
|
|
n.rval.Set(reflect.ValueOf(v))
|
|
{{- else}}
|
|
v := constant.BinaryOp(vConstantValue(v0), token.{{tokenFromName $name}}, vConstantValue(v1))
|
|
n.rval.Set(reflect.ValueOf(v))
|
|
{{- end}}
|
|
{{- if $op.Str}}
|
|
case isString(t):
|
|
n.rval.SetString(vString(v0) {{$op.Name}} vString(v1))
|
|
{{- end}}
|
|
{{- if $op.Float}}
|
|
case isComplex(t):
|
|
n.rval.SetComplex(vComplex(v0) {{$op.Name}} vComplex(v1))
|
|
case isFloat(t):
|
|
n.rval.SetFloat(vFloat(v0) {{$op.Name}} vFloat(v1))
|
|
{{- end}}
|
|
case isUint(t):
|
|
n.rval.SetUint(vUint(v0) {{$op.Name}} vUint(v1))
|
|
case isInt(t):
|
|
{{- if $op.Shift}}
|
|
n.rval.SetInt(vInt(v0) {{$op.Name}} vUint(v1))
|
|
{{- else}}
|
|
n.rval.SetInt(vInt(v0) {{$op.Name}} vInt(v1))
|
|
{{- end}}
|
|
}
|
|
}
|
|
{{end}}
|
|
// Assign operators
|
|
{{range $name, $op := .Arithmetic}}
|
|
func {{$name}}Assign(n *node) {
|
|
next := getExec(n.tnext)
|
|
typ := n.typ.TypeOf()
|
|
c0, c1 := n.child[0], n.child[1]
|
|
|
|
if c1.rval.IsValid() {
|
|
switch typ.Kind() {
|
|
{{- if $op.Str}}
|
|
case reflect.String:
|
|
v0 := genValueString(c0)
|
|
v1 := vString(c1.rval)
|
|
n.exec = func(f *frame) bltn {
|
|
v, s := v0(f)
|
|
v.SetString(s {{$op.Name}} v1)
|
|
return next
|
|
}
|
|
{{- end}}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
v0 := genValueInt(c0)
|
|
{{- if $op.Shift}}
|
|
j := vUint(c1.rval)
|
|
{{else}}
|
|
j := vInt(c1.rval)
|
|
{{end -}}
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetInt(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
v0 := genValueUint(c0)
|
|
j := vUint(c1.rval)
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetUint(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
{{- if $op.Float}}
|
|
case reflect.Float32, reflect.Float64:
|
|
v0 := genValueFloat(c0)
|
|
j := vFloat(c1.rval)
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetFloat(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case reflect.Complex64, reflect.Complex128:
|
|
v0 := genValue(c0)
|
|
v1 := vComplex(c1.rval)
|
|
n.exec = func(f *frame) bltn {
|
|
v := v0(f)
|
|
v.SetComplex(v.Complex() {{$op.Name}} v1)
|
|
return next
|
|
}
|
|
{{- end}}
|
|
}
|
|
} else {
|
|
switch typ.Kind() {
|
|
{{- if $op.Str}}
|
|
case reflect.String:
|
|
v0 := genValueString(c0)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
v, s := v0(f)
|
|
v.SetString(s {{$op.Name}} v1(f).String())
|
|
return next
|
|
}
|
|
{{- end}}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
v0 := genValueInt(c0)
|
|
{{- if $op.Shift}}
|
|
v1 := genValueUint(c1)
|
|
{{else}}
|
|
v1 := genValueInt(c1)
|
|
{{end -}}
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
_, j := v1(f)
|
|
v.SetInt(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
v0 := genValueUint(c0)
|
|
v1 := genValueUint(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
_, j := v1(f)
|
|
v.SetUint(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
{{- if $op.Float}}
|
|
case reflect.Float32, reflect.Float64:
|
|
v0 := genValueFloat(c0)
|
|
v1 := genValueFloat(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
_, j := v1(f)
|
|
v.SetFloat(i {{$op.Name}} j)
|
|
return next
|
|
}
|
|
case reflect.Complex64, reflect.Complex128:
|
|
v0 := genValue(c0)
|
|
v1 := genValue(c1)
|
|
n.exec = func(f *frame) bltn {
|
|
v := v0(f)
|
|
v.SetComplex(v.Complex() {{$op.Name}} v1(f).Complex())
|
|
return next
|
|
}
|
|
{{- end}}
|
|
}
|
|
}
|
|
}
|
|
{{end}}
|
|
{{range $name, $op := .IncDec}}
|
|
func {{$name}}(n *node) {
|
|
next := getExec(n.tnext)
|
|
typ := n.typ.TypeOf()
|
|
|
|
switch typ.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
v0 := genValueInt(n.child[0])
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetInt(i {{$op.Name}} 1)
|
|
return next
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
v0 := genValueUint(n.child[0])
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetUint(i {{$op.Name}} 1)
|
|
return next
|
|
}
|
|
case reflect.Float32, reflect.Float64:
|
|
v0 := genValueFloat(n.child[0])
|
|
n.exec = func(f *frame) bltn {
|
|
v, i := v0(f)
|
|
v.SetFloat(i {{$op.Name}} 1)
|
|
return next
|
|
}
|
|
case reflect.Complex64, reflect.Complex128:
|
|
v0 := genValue(n.child[0])
|
|
n.exec = func(f *frame) bltn {
|
|
v := v0(f)
|
|
v.SetComplex(v.Complex() {{$op.Name}} 1)
|
|
return next
|
|
}
|
|
}
|
|
}
|
|
{{end}}
|
|
{{range $name, $op := .Unary}}
|
|
func {{$name}}Const(n *node) {
|
|
v0 := n.child[0].rval
|
|
isConst := v0.IsValid() && isConstantValue(v0.Type())
|
|
t := n.typ.rtype
|
|
if isConst {
|
|
t = constVal
|
|
}
|
|
n.rval = reflect.New(t).Elem()
|
|
|
|
{{- if $op.Bool}}
|
|
if isConst {
|
|
v := constant.UnaryOp(token.{{tokenFromName $name}}, vConstantValue(v0), 0)
|
|
n.rval.Set(reflect.ValueOf(v))
|
|
} else {
|
|
n.rval.SetBool({{$op.Name}} v0.Bool())
|
|
}
|
|
{{- else}}
|
|
switch {
|
|
case isConst:
|
|
v := constant.UnaryOp(token.{{tokenFromName $name}}, vConstantValue(v0), 0)
|
|
n.rval.Set(reflect.ValueOf(v))
|
|
case isInt(t):
|
|
n.rval.SetInt({{$op.Name}} v0.Int())
|
|
case isUint(t):
|
|
n.rval.SetUint({{$op.Name}} v0.Uint())
|
|
{{- if $op.Float}}
|
|
case isFloat(t):
|
|
n.rval.SetFloat({{$op.Name}} v0.Float())
|
|
case isComplex(t):
|
|
n.rval.SetComplex({{$op.Name}} v0.Complex())
|
|
{{- end}}
|
|
}
|
|
{{- end}}
|
|
}
|
|
{{end}}
|
|
{{range $name, $op := .Comparison}}
|
|
func {{$name}}(n *node) {
|
|
tnext := getExec(n.tnext)
|
|
dest := genValueOutput(n, reflect.TypeOf(true))
|
|
c0, c1 := n.child[0], n.child[1]
|
|
|
|
{{- if or (eq $op.Name "==") (eq $op.Name "!=") }}
|
|
|
|
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
i0 := c0.rval.Interface()
|
|
v1 := genValue(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i1 := v1(f).Interface()
|
|
if i0 != i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i1 := v1(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
i1 := c1.rval.Interface()
|
|
v0 := genValue(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
if i0 != i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValue(c0)
|
|
v1 := genValue(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
i1 := v1(f).Interface()
|
|
if i0 != i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
i1 := v1(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
{{- end}}
|
|
|
|
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
|
case isString(t0) || isString(t1):
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vString(c0.rval)
|
|
v1 := genValueString(n.child[1])
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
s1 := vString(c1.rval)
|
|
v0 := genValueString(n.child[0])
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValueString(n.child[0])
|
|
v1 := genValueString(n.child[1])
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
case isFloat(t0) || isFloat(t1):
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vFloat(c0.rval)
|
|
v1 := genValueFloat(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
s1 := vFloat(c1.rval)
|
|
v0 := genValueFloat(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValueFloat(c0)
|
|
v1 := genValueFloat(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
case isUint(t0) || isUint(t1):
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vUint(c0.rval)
|
|
v1 := genValueUint(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
s1 := vUint(c1.rval)
|
|
v0 := genValueUint(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValueUint(c0)
|
|
v1 := genValueUint(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
case isInt(t0) || isInt(t1):
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vInt(c0.rval)
|
|
v1 := genValueInt(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
s1 := vInt(c1.rval)
|
|
v0 := genValueInt(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValueInt(c0)
|
|
v1 := genValueInt(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
_, s0 := v0(f)
|
|
_, s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
{{- if $op.Complex}}
|
|
case isComplex(t0) || isComplex(t1):
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
s0 := vComplex(c0.rval)
|
|
v1 := genComplex(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
s1 := vComplex(c1.rval)
|
|
v0 := genComplex(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
s0 := v0(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
s0 := v0(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genComplex(n.child[0])
|
|
v1 := genComplex(n.child[1])
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
s0 := v0(f)
|
|
s1 := v1(f)
|
|
if s0 {{$op.Name}} s1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
n.exec = func(f *frame) bltn {
|
|
s0 := v0(f)
|
|
s1 := v1(f)
|
|
dest(f).SetBool(s0 {{$op.Name}} s1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
switch {
|
|
case c0.rval.IsValid():
|
|
i0 := c0.rval.Interface()
|
|
v1 := genValue(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i1 := v1(f).Interface()
|
|
if i0 {{$op.Name}} i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i1 := v1(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
case c1.rval.IsValid():
|
|
i1 := c1.rval.Interface()
|
|
v0 := genValue(c0)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
if i0 {{$op.Name}} i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
default:
|
|
v0 := genValue(c0)
|
|
v1 := genValue(c1)
|
|
if n.fnext != nil {
|
|
fnext := getExec(n.fnext)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
i1 := v1(f).Interface()
|
|
if i0 {{$op.Name}} i1 {
|
|
dest(f).SetBool(true)
|
|
return tnext
|
|
}
|
|
dest(f).SetBool(false)
|
|
return fnext
|
|
}
|
|
} else {
|
|
dest := genValue(n)
|
|
n.exec = func(f *frame) bltn {
|
|
i0 := v0(f).Interface()
|
|
i1 := v1(f).Interface()
|
|
dest(f).SetBool(i0 {{$op.Name}} i1)
|
|
return tnext
|
|
}
|
|
}
|
|
}
|
|
{{- end}}
|
|
}
|
|
}
|
|
{{end}}
|
|
`
|
|
|
|
// Op define operator name and properties.
|
|
type Op struct {
|
|
Name string // +, -, ...
|
|
Str bool // true if operator applies to string
|
|
Float bool // true if operator applies to float
|
|
Complex bool // true if operator applies to complex
|
|
Shift bool // true if operator is a shift operation
|
|
Bool bool // true if operator applies to bool
|
|
}
|
|
|
|
func main() {
|
|
base := template.New("genop")
|
|
base.Funcs(template.FuncMap{
|
|
"tokenFromName": func(name string) string {
|
|
switch name {
|
|
case "andNot":
|
|
return "AND_NOT"
|
|
case "neg":
|
|
return "SUB"
|
|
case "pos":
|
|
return "ADD"
|
|
case "bitNot":
|
|
return "XOR"
|
|
default:
|
|
return strings.ToUpper(name)
|
|
}
|
|
},
|
|
})
|
|
parse, err := base.Parse(model)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
b := &bytes.Buffer{}
|
|
data := map[string]interface{}{
|
|
"Arithmetic": map[string]Op{
|
|
"add": {"+", true, true, true, false, false},
|
|
"sub": {"-", false, true, true, false, false},
|
|
"mul": {"*", false, true, true, false, false},
|
|
"quo": {"/", false, true, true, false, false},
|
|
"rem": {"%", false, false, false, false, false},
|
|
"shl": {"<<", false, false, false, true, false},
|
|
"shr": {">>", false, false, false, true, false},
|
|
"and": {"&", false, false, false, false, false},
|
|
"or": {"|", false, false, false, false, false},
|
|
"xor": {"^", false, false, false, false, false},
|
|
"andNot": {"&^", false, false, false, false, false},
|
|
},
|
|
"IncDec": map[string]Op{
|
|
"inc": {Name: "+"},
|
|
"dec": {Name: "-"},
|
|
},
|
|
"Comparison": map[string]Op{
|
|
"equal": {Name: "==", Complex: true},
|
|
"greater": {Name: ">", Complex: false},
|
|
"greaterEqual": {Name: ">=", Complex: false},
|
|
"lower": {Name: "<", Complex: false},
|
|
"lowerEqual": {Name: "<=", Complex: false},
|
|
"notEqual": {Name: "!=", Complex: true},
|
|
},
|
|
"Unary": map[string]Op{
|
|
"not": {Name: "!", Float: false, Bool: true},
|
|
"neg": {Name: "-", Float: true, Bool: false},
|
|
"pos": {Name: "+", Float: true, Bool: false},
|
|
"bitNot": {Name: "^", Float: false, Bool: false},
|
|
},
|
|
}
|
|
if err = parse.Execute(b, data); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// gofmt
|
|
source, err := format.Source(b.Bytes())
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if err = ioutil.WriteFile("op.go", source, 0666); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|