feat: Add support for missing assign operators (#30)

This commit is contained in:
Marc Vertes
2019-01-22 19:08:15 +01:00
committed by Ludovic Fernandez
parent 83c21d4bc0
commit 2619434b64
6 changed files with 468 additions and 30 deletions

View File

@@ -14,7 +14,8 @@ const model = `package interp
import "reflect"
{{range $name, $op := .Ops}}
// Arithmetic opertators
{{range $name, $op := .Arithmetic}}
func {{$name}}(n *Node) {
i := n.findex
next := getExec(n.tnext)
@@ -67,14 +68,68 @@ func {{$name}}(n *Node) {
}
}
{{end}}
// Assign operators
{{range $name, $op := .Arithmetic}}
func {{$name}}Assign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
{{- if $op.Str}}
case reflect.String:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetString(v0(f).String() {{$op.Name}} v1(f).String())
return next
}
{{- end}}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
{{- if $op.Shift}}
v1 := genValueUint(n.child[1])
{{else}}
v1 := genValueInt(n.child[1])
{{end -}}
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) {{$op.Name}} v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) {{$op.Name}} v1(f))
return next
}
{{- if $op.Float}}
case reflect.Float32, reflect.Float64:
v0 := genValueFloat(n.child[0])
v1 := genValueFloat(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetFloat(v0(f) {{$op.Name}} v1(f))
return next
}
case reflect.Complex64, reflect.Complex128:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetComplex(v0(f).Complex() {{$op.Name}} v1(f).Complex())
return next
}
{{- end}}
}
}
{{end}}
`
// Op FIXME
// Op define operator name and properties
type Op struct {
Name string
Str bool
Float bool
Shift bool
Name string // +, -, ...
Str bool // true if operator applies to string
Float bool // true if operator applies to float
Shift bool // true if operator is a shift operation
}
func main() {
@@ -86,7 +141,7 @@ func main() {
b := &bytes.Buffer{}
data := map[string]interface{}{
"Ops": map[string]Op{
"Arithmetic": map[string]Op{
"add": {"+", true, true, false},
"sub": {"-", false, true, false},
"mul": {"*", false, true, false},

View File

@@ -188,8 +188,11 @@ const (
Assign
AssignX
Add
AddAssign
And
AndAssign
AndNot
AndNotAssign
Call
Case
CompositeLit
@@ -203,25 +206,34 @@ const (
Land
Lor
Lower
Lshift
Mul
MulAssign
Negate
Not
NotEqual
Quotient
Or
OrAssign
Quo
QuoAssign
Range
Recv
Remain
Rem
RemAssign
Return
Rshift
Select
Send
Shl
ShlAssign
Shr
ShrAssign
Slice
Slice0
Star
Sub
SubAssign
TypeAssert
Xor
XorAssign
)
var actions = [...]string{
@@ -230,8 +242,11 @@ var actions = [...]string{
Assign: "=",
AssignX: "X=",
Add: "+",
AddAssign: "+=",
And: "&",
AndAssign: "&=",
AndNot: "&^",
AndNotAssign: "&^=",
Call: "call",
Case: "case",
CompositeLit: "compositeLit",
@@ -245,24 +260,31 @@ var actions = [...]string{
Land: "&&",
Lor: "||",
Lower: "<",
Lshift: "<<",
Mul: "*",
MulAssign: "*=",
Negate: "-",
Not: "!",
NotEqual: "!=",
Quotient: "/",
Quo: "/",
QuoAssign: "/=",
Range: "range",
Recv: "<-",
Remain: "%",
Rem: "%",
RemAssign: "%=",
Return: "return",
Rshift: ">>",
Send: "<~",
Shl: "<<",
ShlAssign: "<<=",
Shr: ">>",
ShrAssign: ">>=",
Slice: "slice",
Slice0: "slice0",
Star: "*",
Sub: "-",
SubAssign: "-=",
TypeAssert: "TypeAssert",
Xor: "^",
XorAssign: "^=",
}
func (a Action) String() string {
@@ -402,13 +424,37 @@ func (interp *Interpreter) ast(src, name string) (string, *Node, error) {
}
action = AssignX
} else {
if a.Tok == token.DEFINE {
kind = Define
} else {
kind = AssignStmt
}
action = Assign
nbAssign = len(a.Lhs)
kind = AssignStmt
switch a.Tok {
case token.ASSIGN:
action = Assign
case token.ADD_ASSIGN:
action = AddAssign
case token.AND_ASSIGN:
action = AndAssign
case token.AND_NOT_ASSIGN:
action = AndNotAssign
case token.DEFINE:
kind = Define
action = Assign
case token.SHL_ASSIGN:
action = ShlAssign
case token.SHR_ASSIGN:
action = ShrAssign
case token.MUL_ASSIGN:
action = MulAssign
case token.OR_ASSIGN:
action = OrAssign
case token.QUO_ASSIGN:
action = QuoAssign
case token.REM_ASSIGN:
action = RemAssign
case token.SUB_ASSIGN:
action = SubAssign
case token.XOR_ASSIGN:
action = XorAssign
}
}
st.push(addChild(&root, anc, pos, kind, action))
@@ -457,16 +503,18 @@ func (interp *Interpreter) ast(src, name string) (string, *Node, error) {
action = Mul
case token.NEQ:
action = NotEqual
case token.OR:
action = Or
case token.REM:
action = Remain
action = Rem
case token.SUB:
action = Sub
case token.SHL:
action = Lshift
action = Shl
case token.SHR:
action = Rshift
action = Shr
case token.QUO:
action = Quotient
action = Quo
case token.XOR:
action = Xor
}

View File

@@ -291,6 +291,7 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) {
// TODO: perform constant folding and propagation here
// Convert literal value to destination type
src.val = reflect.ValueOf(src.val).Convert(dest.typ.TypeOf())
src.typ = dest.typ
}
n.typ = dest.typ
if sym != nil {

View File

@@ -4,6 +4,8 @@ package interp
import "reflect"
// Arithmetic opertators
func add(n *Node) {
i := n.findex
next := getExec(n.tnext)
@@ -319,3 +321,321 @@ func xor(n *Node) {
}
}
}
// Assign operators
func addAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.String:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetString(v0(f).String() + v1(f).String())
return next
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) + v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) + v1(f))
return next
}
case reflect.Float32, reflect.Float64:
v0 := genValueFloat(n.child[0])
v1 := genValueFloat(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetFloat(v0(f) + v1(f))
return next
}
case reflect.Complex64, reflect.Complex128:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetComplex(v0(f).Complex() + v1(f).Complex())
return next
}
}
}
func andAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) & v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) & v1(f))
return next
}
}
}
func andnotAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) &^ v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) &^ v1(f))
return next
}
}
}
func mulAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) * v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) * v1(f))
return next
}
case reflect.Float32, reflect.Float64:
v0 := genValueFloat(n.child[0])
v1 := genValueFloat(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetFloat(v0(f) * v1(f))
return next
}
case reflect.Complex64, reflect.Complex128:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetComplex(v0(f).Complex() * v1(f).Complex())
return next
}
}
}
func orAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) | v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) | v1(f))
return next
}
}
}
func quoAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) / v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) / v1(f))
return next
}
case reflect.Float32, reflect.Float64:
v0 := genValueFloat(n.child[0])
v1 := genValueFloat(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetFloat(v0(f) / v1(f))
return next
}
case reflect.Complex64, reflect.Complex128:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetComplex(v0(f).Complex() / v1(f).Complex())
return next
}
}
}
func remAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) % v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) % v1(f))
return next
}
}
}
func shlAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) << v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) << v1(f))
return next
}
}
}
func shrAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) >> v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) >> v1(f))
return next
}
}
}
func subAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) - v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) - v1(f))
return next
}
case reflect.Float32, reflect.Float64:
v0 := genValueFloat(n.child[0])
v1 := genValueFloat(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetFloat(v0(f) - v1(f))
return next
}
case reflect.Complex64, reflect.Complex128:
v0 := genValue(n.child[0])
v1 := genValue(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetComplex(v0(f).Complex() - v1(f).Complex())
return next
}
}
}
func xorAssign(n *Node) {
next := getExec(n.tnext)
typ := n.typ.TypeOf()
value := genValue(n.child[0])
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v0 := genValueInt(n.child[0])
v1 := genValueInt(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetInt(v0(f) ^ v1(f))
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v0 := genValueUint(n.child[0])
v1 := genValueUint(n.child[1])
n.exec = func(f *Frame) Builtin {
value(f).SetUint(v0(f) ^ v1(f))
return next
}
}
}

View File

@@ -19,8 +19,11 @@ var builtin = [...]BuiltinGenerator{
Assign: assign,
AssignX: assignX,
Add: add,
AddAssign: addAssign,
And: and,
AndAssign: andAssign,
AndNot: andnot,
AndNotAssign: andnotAssign,
Call: call,
Case: _case,
CompositeLit: arrayLit,
@@ -33,24 +36,33 @@ var builtin = [...]BuiltinGenerator{
Land: land,
Lor: lor,
Lower: lower,
Lshift: shl,
Mul: mul,
MulAssign: mulAssign,
Negate: negate,
Not: not,
NotEqual: notEqual,
Quotient: quo,
Or: or,
OrAssign: orAssign,
Quo: quo,
QuoAssign: quoAssign,
Range: _range,
Recv: recv,
Remain: rem,
Rem: rem,
RemAssign: remAssign,
Return: _return,
Rshift: shr,
Send: send,
Shl: shl,
ShlAssign: shlAssign,
Shr: shr,
ShrAssign: shrAssign,
Slice: slice,
Slice0: slice0,
Star: deref,
Sub: sub,
SubAssign: subAssign,
TypeAssert: typeAssert,
Xor: xor,
XorAssign: xorAssign,
}
func (interp *Interpreter) run(n *Node, cf *Frame) {

View File

@@ -1,6 +1,8 @@
package interp
import "reflect"
import (
"reflect"
)
func valueGenerator(n *Node, i int) func(*Frame) reflect.Value {
switch n.level {