feature: refactor numeric constants and detect overflow
This commit is contained in:
16
_test/const13.go
Normal file
16
_test/const13.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const tooBig = 1267650600228229401496703205376
|
||||
const huge = 1 << 100
|
||||
const large = huge >> 38
|
||||
|
||||
fmt.Println(large)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 4611686018427387904
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
@@ -12,7 +13,11 @@ const model = `package interp
|
||||
|
||||
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Arithmetic operators
|
||||
{{range $name, $op := .Arithmetic}}
|
||||
@@ -176,9 +181,22 @@ func {{$name}}(n *node) {
|
||||
|
||||
func {{$name}}Const(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
{{- if $op.Shift}}
|
||||
s, _ := constant.Uint64Val(vConstantValue(v1))
|
||||
v := constant.Shift(vConstantValue(v0), token.{{tokenFromName $name}}, uint(s))
|
||||
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(v0.String() {{$op.Name}} v1.String())
|
||||
@@ -354,23 +372,35 @@ func {{$name}}(n *node) {
|
||||
{{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
|
||||
v := n.child[0].rval
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
|
||||
{{- if $op.Bool}}
|
||||
n.rval.SetBool({{$op.Name}} v.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 t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt({{$op.Name}} v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint({{$op.Name}} v.Uint())
|
||||
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 reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat({{$op.Name}} v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex({{$op.Name}} v.Complex())
|
||||
case isFloat(t):
|
||||
n.rval.SetFloat({{$op.Name}} v0.Float())
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex({{$op.Name}} v0.Complex())
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
@@ -822,6 +852,22 @@ type Op struct {
|
||||
|
||||
func main() {
|
||||
base := template.New("goexports")
|
||||
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)
|
||||
|
||||
@@ -3,6 +3,7 @@ package interp
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
@@ -474,14 +475,14 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
|
||||
v, _, _, _ := strconv.UnquoteChar(a.Value[1:len(a.Value)-1], '\'')
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.FLOAT:
|
||||
v, _ := strconv.ParseFloat(a.Value, 64)
|
||||
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.IMAG:
|
||||
v, _ := strconv.ParseFloat(a.Value[:len(a.Value)-1], 64)
|
||||
n.rval = reflect.ValueOf(complex(0, v))
|
||||
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.INT:
|
||||
v, _ := strconv.ParseInt(a.Value, 0, 0)
|
||||
n.rval = reflect.ValueOf(int(v))
|
||||
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
|
||||
n.rval = reflect.ValueOf(v)
|
||||
case token.STRING:
|
||||
v, _ := strconv.Unquote(a.Value)
|
||||
n.rval = reflect.ValueOf(v)
|
||||
|
||||
@@ -2,6 +2,7 @@ package interp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"log"
|
||||
"math"
|
||||
"reflect"
|
||||
@@ -543,8 +544,11 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case !src.rval.IsValid():
|
||||
// Assign to nil.
|
||||
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
|
||||
case n.anc.kind == constDecl:
|
||||
// Possible conversion from const to actual type will be handled later
|
||||
default:
|
||||
// Convert literal value to destination type.
|
||||
convertConstantValue(src)
|
||||
src.rval = src.rval.Convert(dest.typ.TypeOf())
|
||||
src.typ = dest.typ
|
||||
}
|
||||
@@ -559,6 +563,12 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
dest.gen = nop // skip getIndexMap
|
||||
}
|
||||
if n.anc.kind == constDecl {
|
||||
if !dest.typ.untyped {
|
||||
// If the dest is untyped, any constant rval needs to be converted
|
||||
convertConstantValue(src)
|
||||
}
|
||||
n.gen = nop
|
||||
n.findex = -1
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
if childPos(n) == len(n.anc.child)-1 {
|
||||
sc.iota = 0
|
||||
@@ -1082,7 +1092,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.rval = sym.rval
|
||||
n.kind = basicLit
|
||||
case n.ident == "iota":
|
||||
n.rval = reflect.ValueOf(sc.iota)
|
||||
n.rval = reflect.ValueOf(constant.Make(int64(sc.iota)))
|
||||
n.kind = basicLit
|
||||
case n.ident == "nil":
|
||||
n.kind = basicLit
|
||||
@@ -1791,13 +1801,13 @@ func compDefineX(sc *scope, n *node) error {
|
||||
}
|
||||
|
||||
// TODO used for allocation optimization, temporarily disabled
|
||||
//func isAncBranch(n *node) bool {
|
||||
// func isAncBranch(n *node) bool {
|
||||
// switch n.anc.kind {
|
||||
// case If0, If1, If2, If3:
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
//}
|
||||
// }
|
||||
|
||||
func childPos(n *node) int {
|
||||
for i, c := range n.anc.child {
|
||||
@@ -1966,6 +1976,20 @@ func (n *node) isInteger() bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if isConstantValue(t) {
|
||||
c := n.rval.Interface().(constant.Value)
|
||||
switch c.Kind() {
|
||||
case constant.Int:
|
||||
return true
|
||||
case constant.Float:
|
||||
f, _ := constant.Float64Val(c)
|
||||
if f == math.Trunc(f) {
|
||||
n.rval = reflect.ValueOf(constant.ToInt(c))
|
||||
n.typ.rtype = n.rval.Type()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1993,6 +2017,23 @@ func (n *node) isNatural() bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if isConstantValue(t) {
|
||||
c := n.rval.Interface().(constant.Value)
|
||||
switch c.Kind() {
|
||||
case constant.Int:
|
||||
i, _ := constant.Int64Val(c)
|
||||
if i >= 0 {
|
||||
return true
|
||||
}
|
||||
case constant.Float:
|
||||
f, _ := constant.Float64Val(c)
|
||||
if f == math.Trunc(f) {
|
||||
n.rval = reflect.ValueOf(constant.ToInt(c))
|
||||
n.typ.rtype = n.rval.Type()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ func TestEvalArithmetic(t *testing.T) {
|
||||
{desc: "sub_FI", src: "7.2 - 3", res: "4.2"},
|
||||
{desc: "sub_IF", src: "7 - 3.2", res: "3.8"},
|
||||
{desc: "mul_II", src: "2 * 3", res: "6"},
|
||||
{desc: "mul_FI", src: "2.2 * 3", res: "6.6000000000000005"},
|
||||
{desc: "mul_IF", src: "3 * 2.2", res: "6.6000000000000005"},
|
||||
{desc: "mul_FI", src: "2.2 * 3", res: "6.6"},
|
||||
{desc: "mul_IF", src: "3 * 2.2", res: "6.6"},
|
||||
{desc: "rem_FI", src: "8.2 % 4", err: "1:28: illegal operand types for '%' operator"},
|
||||
{desc: "shl_II", src: "1 << 8", res: "256"},
|
||||
{desc: "shl_IN", src: "1 << -1", err: "1:28: illegal operand types for '<<' operator"},
|
||||
|
||||
171
interp/op.go
171
interp/op.go
@@ -2,7 +2,11 @@ package interp
|
||||
|
||||
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Arithmetic operators
|
||||
|
||||
@@ -150,9 +154,16 @@ func add(n *node) {
|
||||
|
||||
func addConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.ADD, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isString(t):
|
||||
n.rval.SetString(v0.String() + v1.String())
|
||||
case isComplex(t):
|
||||
@@ -234,9 +245,16 @@ func and(n *node) {
|
||||
|
||||
func andConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.AND, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) & vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -312,9 +330,16 @@ func andNot(n *node) {
|
||||
|
||||
func andNotConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.AND_NOT, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) &^ vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -442,9 +467,16 @@ func mul(n *node) {
|
||||
|
||||
func mulConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.MUL, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex(vComplex(v0) * vComplex(v1))
|
||||
case isFloat(t):
|
||||
@@ -524,9 +556,16 @@ func or(n *node) {
|
||||
|
||||
func orConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.OR, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) | vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -654,9 +693,16 @@ func quo(n *node) {
|
||||
|
||||
func quoConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.QUO, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex(vComplex(v0) / vComplex(v1))
|
||||
case isFloat(t):
|
||||
@@ -736,9 +782,16 @@ func rem(n *node) {
|
||||
|
||||
func remConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.REM, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) % vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -814,9 +867,17 @@ func shl(n *node) {
|
||||
|
||||
func shlConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
s, _ := constant.Uint64Val(vConstantValue(v1))
|
||||
v := constant.Shift(vConstantValue(v0), token.SHL, uint(s))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) << vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -892,9 +953,17 @@ func shr(n *node) {
|
||||
|
||||
func shrConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
s, _ := constant.Uint64Val(vConstantValue(v1))
|
||||
v := constant.Shift(vConstantValue(v0), token.SHR, uint(s))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) >> vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -1022,9 +1091,16 @@ func sub(n *node) {
|
||||
|
||||
func subConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.SUB, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex(vComplex(v0) - vComplex(v1))
|
||||
case isFloat(t):
|
||||
@@ -1104,9 +1180,16 @@ func xor(n *node) {
|
||||
|
||||
func xorConst(n *node) {
|
||||
v0, v1 := n.child[0].rval, n.child[1].rval
|
||||
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
|
||||
t := n.typ.rtype
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.BinaryOp(vConstantValue(v0), token.XOR, vConstantValue(v1))
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isUint(t):
|
||||
n.rval.SetUint(vUint(v0) ^ vUint(v1))
|
||||
case isInt(t):
|
||||
@@ -1865,53 +1948,83 @@ func inc(n *node) {
|
||||
}
|
||||
|
||||
func bitNotConst(n *node) {
|
||||
v0 := n.child[0].rval
|
||||
isConst := v0.IsValid() && isConstantValue(v0.Type())
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(^v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(^v.Uint())
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.UnaryOp(token.XOR, vConstantValue(v0), 0)
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isInt(t):
|
||||
n.rval.SetInt(^v0.Int())
|
||||
case isUint(t):
|
||||
n.rval.SetUint(^v0.Uint())
|
||||
}
|
||||
}
|
||||
|
||||
func negConst(n *node) {
|
||||
v0 := n.child[0].rval
|
||||
isConst := v0.IsValid() && isConstantValue(v0.Type())
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(-v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(-v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat(-v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex(-v.Complex())
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.UnaryOp(token.SUB, vConstantValue(v0), 0)
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isInt(t):
|
||||
n.rval.SetInt(-v0.Int())
|
||||
case isUint(t):
|
||||
n.rval.SetUint(-v0.Uint())
|
||||
case isFloat(t):
|
||||
n.rval.SetFloat(-v0.Float())
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex(-v0.Complex())
|
||||
}
|
||||
}
|
||||
|
||||
func notConst(n *node) {
|
||||
v0 := n.child[0].rval
|
||||
isConst := v0.IsValid() && isConstantValue(v0.Type())
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
n.rval.SetBool(!v.Bool())
|
||||
if isConst {
|
||||
v := constant.UnaryOp(token.NOT, vConstantValue(v0), 0)
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
} else {
|
||||
n.rval.SetBool(!v0.Bool())
|
||||
}
|
||||
}
|
||||
|
||||
func posConst(n *node) {
|
||||
v0 := n.child[0].rval
|
||||
isConst := v0.IsValid() && isConstantValue(v0.Type())
|
||||
t := n.typ.rtype
|
||||
v := n.child[0].rval
|
||||
if isConst {
|
||||
t = constVal
|
||||
}
|
||||
n.rval = reflect.New(t).Elem()
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n.rval.SetInt(+v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n.rval.SetUint(+v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n.rval.SetFloat(+v.Float())
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
n.rval.SetComplex(+v.Complex())
|
||||
switch {
|
||||
case isConst:
|
||||
v := constant.UnaryOp(token.ADD, vConstantValue(v0), 0)
|
||||
n.rval.Set(reflect.ValueOf(v))
|
||||
case isInt(t):
|
||||
n.rval.SetInt(+v0.Int())
|
||||
case isUint(t):
|
||||
n.rval.SetUint(+v0.Uint())
|
||||
case isFloat(t):
|
||||
n.rval.SetFloat(+v0.Float())
|
||||
case isComplex(t):
|
||||
n.rval.SetComplex(+v0.Complex())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
111
interp/run.go
111
interp/run.go
@@ -4,6 +4,7 @@ package interp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
@@ -1204,6 +1205,7 @@ func getIndexMap(n *node) {
|
||||
z := reflect.New(n.child[0].typ.frameType().Elem()).Elem()
|
||||
|
||||
if n.child[1].rval.IsValid() { // constant map index
|
||||
convertConstantValue(n.child[1])
|
||||
mi := n.child[1].rval
|
||||
|
||||
switch {
|
||||
@@ -1297,6 +1299,7 @@ func getIndexMap2(n *node) {
|
||||
return
|
||||
}
|
||||
if n.child[1].rval.IsValid() { // constant map index
|
||||
convertConstantValue(n.child[1])
|
||||
mi := n.child[1].rval
|
||||
switch {
|
||||
case !doValue:
|
||||
@@ -2632,6 +2635,9 @@ func convertLiteralValue(n *node, t reflect.Type) {
|
||||
// Skip non-constant values, undefined target type or interface target type.
|
||||
case n.rval.IsValid():
|
||||
// Convert constant value to target type.
|
||||
if n.typ != nil {
|
||||
convertConstantValue(n)
|
||||
}
|
||||
n.rval = n.rval.Convert(t)
|
||||
default:
|
||||
// Create a zero value of target type.
|
||||
@@ -2639,6 +2645,111 @@ func convertLiteralValue(n *node, t reflect.Type) {
|
||||
}
|
||||
}
|
||||
|
||||
func convertConstantValue(n *node) {
|
||||
if !n.rval.IsValid() {
|
||||
return
|
||||
}
|
||||
c, ok := n.rval.Interface().(constant.Value)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
t := n.typ
|
||||
for t != nil && t.cat == aliasT {
|
||||
// If it is an alias, get the actual type
|
||||
t = t.val
|
||||
}
|
||||
|
||||
v := n.rval
|
||||
switch t.cat {
|
||||
case intT, int8T, int16T, int32T, int64T:
|
||||
i, _ := constant.Int64Val(c)
|
||||
l := constant.BitLen(c)
|
||||
switch t.cat {
|
||||
case intT:
|
||||
if l > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows int", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(int(i))
|
||||
case int8T:
|
||||
if l > 8 {
|
||||
panic(fmt.Sprintf("constant %s overflows int8", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(int8(i))
|
||||
case int16T:
|
||||
if l > 16 {
|
||||
panic(fmt.Sprintf("constant %s overflows int16", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(int16(i))
|
||||
case int32T:
|
||||
if l > 32 {
|
||||
panic(fmt.Sprintf("constant %s overflows int32", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(int32(i))
|
||||
case int64T:
|
||||
if l > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows int64", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(i)
|
||||
}
|
||||
case uintT, uint8T, uint16T, uint32T, uint64T:
|
||||
i, _ := constant.Uint64Val(c)
|
||||
l := constant.BitLen(c)
|
||||
switch t.cat {
|
||||
case uintT:
|
||||
if l > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows uint", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(uint(i))
|
||||
case uint8T:
|
||||
if l > 8 {
|
||||
panic(fmt.Sprintf("constant %s overflows uint8", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(uint8(i))
|
||||
case uint16T:
|
||||
if l > 16 {
|
||||
panic(fmt.Sprintf("constant %s overflows uint16", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(uint16(i))
|
||||
case uint32T:
|
||||
if l > 32 {
|
||||
panic(fmt.Sprintf("constant %s overflows uint32", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(uint32(i))
|
||||
case uint64T:
|
||||
if l > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows uint64", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(i)
|
||||
case uintptrT:
|
||||
if l > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows uintptr", c.ExactString()))
|
||||
}
|
||||
v = reflect.ValueOf(i)
|
||||
}
|
||||
case float32T:
|
||||
f, _ := constant.Float32Val(c)
|
||||
v = reflect.ValueOf(f)
|
||||
case float64T:
|
||||
f, _ := constant.Float64Val(c)
|
||||
v = reflect.ValueOf(f)
|
||||
case complex64T:
|
||||
r, _ := constant.Float32Val(constant.Real(c))
|
||||
i, _ := constant.Float32Val(constant.Imag(c))
|
||||
v = reflect.ValueOf(complex(r, i))
|
||||
case complex128T:
|
||||
r, _ := constant.Float64Val(constant.Real(c))
|
||||
i, _ := constant.Float64Val(constant.Imag(c))
|
||||
v = reflect.ValueOf(complex(r, i))
|
||||
case boolT:
|
||||
b := constant.BoolVal(c)
|
||||
v = reflect.ValueOf(b)
|
||||
case stringT:
|
||||
s := constant.StringVal(c)
|
||||
v = reflect.ValueOf(s)
|
||||
}
|
||||
n.rval = v
|
||||
}
|
||||
|
||||
// Write to a channel
|
||||
func send(n *node) {
|
||||
next := getExec(n.tnext)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
@@ -152,10 +154,16 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
case arrayType:
|
||||
t.cat = arrayT
|
||||
if len(n.child) > 1 {
|
||||
v := n.child[0].rval
|
||||
switch {
|
||||
case n.child[0].rval.IsValid():
|
||||
case v.IsValid():
|
||||
// constant size
|
||||
t.size = int(n.child[0].rval.Int())
|
||||
if isConstantValue(v.Type()) {
|
||||
c := v.Interface().(constant.Value)
|
||||
t.size = constToInt(c)
|
||||
} else {
|
||||
t.size = int(v.Int())
|
||||
}
|
||||
case n.child[0].kind == ellipsisExpr:
|
||||
// [...]T expression
|
||||
t.size = arrayTypeLen(n.anc)
|
||||
@@ -165,6 +173,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if sym.typ != nil && sym.typ.cat == intT {
|
||||
if v, ok := sym.rval.Interface().(int); ok {
|
||||
t.size = v
|
||||
} else if c, ok := sym.rval.Interface().(constant.Value); ok {
|
||||
t.size = constToInt(c)
|
||||
} else {
|
||||
t.incomplete = true
|
||||
}
|
||||
@@ -231,6 +241,23 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t.cat = stringT
|
||||
t.name = "string"
|
||||
t.untyped = true
|
||||
case constant.Value:
|
||||
switch v.Kind() {
|
||||
case constant.Int:
|
||||
t.cat = intT
|
||||
t.name = "int"
|
||||
t.untyped = true
|
||||
case constant.Float:
|
||||
t.cat = float64T
|
||||
t.name = "float64"
|
||||
t.untyped = true
|
||||
case constant.Complex:
|
||||
t.cat = complex128T
|
||||
t.name = "complex128"
|
||||
t.untyped = true
|
||||
default:
|
||||
err = n.cfgErrorf("missing support for type %v", n.rval)
|
||||
}
|
||||
default:
|
||||
err = n.cfgErrorf("missing support for type %T: %v", v, n.rval)
|
||||
}
|
||||
@@ -1063,6 +1090,7 @@ func exportName(s string) string {
|
||||
}
|
||||
|
||||
var interf = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
var constVal = reflect.TypeOf((*constant.Value)(nil)).Elem()
|
||||
|
||||
// RefType returns a reflect.Type representation from an interpereter type.
|
||||
// In simple cases, reflect types are directly mapped from the interpreter
|
||||
@@ -1198,6 +1226,14 @@ func (t *itype) implements(it *itype) bool {
|
||||
return t.methods().contains(it.methods())
|
||||
}
|
||||
|
||||
func constToInt(c constant.Value) int {
|
||||
if constant.BitLen(c) > 64 {
|
||||
panic(fmt.Sprintf("constant %s overflows int64", c.ExactString()))
|
||||
}
|
||||
i, _ := constant.Int64Val(c)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
func defRecvType(n *node) *itype {
|
||||
if n.kind != funcDecl || len(n.child[0].child) == 0 {
|
||||
return nil
|
||||
@@ -1311,5 +1347,8 @@ func isByteArray(t reflect.Type) bool {
|
||||
|
||||
func isFloat32(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float32 }
|
||||
func isFloat64(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float64 }
|
||||
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
|
||||
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
|
||||
func isNumber(t reflect.Type) bool {
|
||||
return isInt(t) || isFloat(t) || isComplex(t) || isConstantValue(t)
|
||||
}
|
||||
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
|
||||
func isConstantValue(t reflect.Type) bool { return t != nil && t.Implements(constVal) }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"go/constant"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@@ -96,6 +97,7 @@ func genValueAs(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
func genValue(n *node) func(*frame) reflect.Value {
|
||||
switch n.kind {
|
||||
case basicLit:
|
||||
convertConstantValue(n)
|
||||
v := n.rval
|
||||
if !v.IsValid() {
|
||||
v = reflect.New(interf).Elem()
|
||||
@@ -111,6 +113,7 @@ func genValue(n *node) func(*frame) reflect.Value {
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
default:
|
||||
if n.rval.IsValid() {
|
||||
convertConstantValue(n)
|
||||
v := n.rval
|
||||
return func(f *frame) reflect.Value { return v }
|
||||
}
|
||||
@@ -277,6 +280,10 @@ func vInt(v reflect.Value) (i int64) {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
i = int64(real(v.Complex()))
|
||||
}
|
||||
if v.Type().Implements(constVal) {
|
||||
c := v.Interface().(constant.Value)
|
||||
i, _ = constant.Int64Val(constant.ToInt(c))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -291,6 +298,11 @@ func vUint(v reflect.Value) (i uint64) {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
i = uint64(real(v.Complex()))
|
||||
}
|
||||
if v.Type().Implements(constVal) {
|
||||
c := v.Interface().(constant.Value)
|
||||
iv, _ := constant.Int64Val(constant.ToInt(c))
|
||||
i = uint64(iv)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -305,6 +317,13 @@ func vComplex(v reflect.Value) (c complex128) {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
c = v.Complex()
|
||||
}
|
||||
if v.Type().Implements(constVal) {
|
||||
con := v.Interface().(constant.Value)
|
||||
con = constant.ToComplex(con)
|
||||
rel, _ := constant.Float64Val(constant.Real(con))
|
||||
img, _ := constant.Float64Val(constant.Imag(con))
|
||||
c = complex(rel, img)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -319,6 +338,17 @@ func vFloat(v reflect.Value) (i float64) {
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
i = real(v.Complex())
|
||||
}
|
||||
if v.Type().Implements(constVal) {
|
||||
c := v.Interface().(constant.Value)
|
||||
i, _ = constant.Float64Val(constant.ToFloat(c))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func vConstantValue(v reflect.Value) (c constant.Value) {
|
||||
if v.Type().Implements(constVal) {
|
||||
c = v.Interface().(constant.Value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user