Files
gotext/vendor/github.com/mattn/kinako/vm/vm.go
2017-09-01 17:05:40 -03:00

477 lines
12 KiB
Go

package vm
import (
"errors"
"fmt"
"math"
"os"
"reflect"
"strconv"
"strings"
"github.com/mattn/kinako/ast"
)
var (
NilValue = reflect.ValueOf((*interface{})(nil))
NilType = reflect.TypeOf((*interface{})(nil))
TrueValue = reflect.ValueOf(true)
FalseValue = reflect.ValueOf(false)
)
// Error provides a convenient interface for handling runtime error.
// It can be Error interface with type cast which can call Pos().
type Error struct {
Message string
}
var (
BreakError = errors.New("Unexpected break statement")
ContinueError = errors.New("Unexpected continue statement")
ReturnError = errors.New("Unexpected return statement")
InterruptError = errors.New("Execution interrupted")
)
// Error returns the error message.
func (e *Error) Error() string {
return e.Message
}
// Func is function interface to reflect functions internaly.
type Func func(args ...reflect.Value) (reflect.Value, error)
// Run executes statements in the specified environment.
func Run(stmts []ast.Stmt, env *Env) (reflect.Value, error) {
rv := NilValue
var err error
for _, stmt := range stmts {
rv, err = RunSingleStmt(stmt, env)
if err != nil {
return rv, err
}
}
return rv, nil
}
// Interrupts the execution of any running statements in the specified environment.
//
// Note that the execution is not instantly aborted: after a call to Interrupt,
// the current running statement will finish, but the next statement will not run,
// and instead will return a NilValue and an InterruptError.
func Interrupt(env *Env) {
env.Lock()
*(env.interrupt) = true
env.Unlock()
}
// RunSingleStmt executes one statement in the specified environment.
func RunSingleStmt(stmt ast.Stmt, env *Env) (reflect.Value, error) {
env.Lock()
if *(env.interrupt) {
*(env.interrupt) = false
env.Unlock()
return NilValue, InterruptError
}
env.Unlock()
switch stmt := stmt.(type) {
case *ast.ExprStmt:
rv, err := invokeExpr(stmt.Expr, env)
if err != nil {
return rv, err
}
return rv, nil
case *ast.LetStmt:
rv := NilValue
var err error
rv, err = invokeExpr(stmt.Rhs, env)
if err != nil {
return rv, err
}
_, err = invokeLetExpr(stmt.Lhs, rv, env)
if err != nil {
return rv, err
}
return rv, nil
default:
return NilValue, errors.New("unknown statement")
}
}
// toString converts all reflect.Value-s into string.
func toString(v reflect.Value) string {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
if v.Kind() == reflect.String {
return v.String()
}
if !v.IsValid() {
return "nil"
}
return fmt.Sprint(v.Interface())
}
// toBool converts all reflect.Value-s into bool.
func toBool(v reflect.Value) bool {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
switch v.Kind() {
case reflect.Float32, reflect.Float64:
return v.Float() != 0.0
case reflect.Int, reflect.Int32, reflect.Int64:
return v.Int() != 0
case reflect.Bool:
return v.Bool()
case reflect.String:
if v.String() == "true" {
return true
}
if toInt64(v) != 0 {
return true
}
}
return false
}
// toFloat64 converts all reflect.Value-s into float64.
func toFloat64(v reflect.Value) float64 {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
switch v.Kind() {
case reflect.Float32, reflect.Float64:
return v.Float()
case reflect.Int, reflect.Int32, reflect.Int64:
return float64(v.Int())
}
return 0.0
}
func isNil(v reflect.Value) bool {
if !v.IsValid() || v.Kind().String() == "unsafe.Pointer" {
return true
}
if (v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr) && v.IsNil() {
return true
}
return false
}
func isNum(v reflect.Value) bool {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
return true
}
return false
}
// equal returns true when lhsV and rhsV is same value.
func equal(lhsV, rhsV reflect.Value) bool {
lhsIsNil, rhsIsNil := isNil(lhsV), isNil(rhsV)
if lhsIsNil && rhsIsNil {
return true
}
if (!lhsIsNil && rhsIsNil) || (lhsIsNil && !rhsIsNil) {
return false
}
if lhsV.Kind() == reflect.Interface || lhsV.Kind() == reflect.Ptr {
lhsV = lhsV.Elem()
}
if rhsV.Kind() == reflect.Interface || rhsV.Kind() == reflect.Ptr {
rhsV = rhsV.Elem()
}
if !lhsV.IsValid() || !rhsV.IsValid() {
return true
}
if isNum(lhsV) && isNum(rhsV) {
if rhsV.Type().ConvertibleTo(lhsV.Type()) {
rhsV = rhsV.Convert(lhsV.Type())
}
}
if lhsV.CanInterface() && rhsV.CanInterface() {
return reflect.DeepEqual(lhsV.Interface(), rhsV.Interface())
}
return reflect.DeepEqual(lhsV, rhsV)
}
// toInt64 converts all reflect.Value-s into int64.
func toInt64(v reflect.Value) int64 {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
switch v.Kind() {
case reflect.Float32, reflect.Float64:
return int64(v.Float())
case reflect.Int, reflect.Int32, reflect.Int64:
return v.Int()
case reflect.String:
s := v.String()
var i int64
var err error
if strings.HasPrefix(s, "0x") {
i, err = strconv.ParseInt(s, 16, 64)
} else {
i, err = strconv.ParseInt(s, 10, 64)
}
if err == nil {
return int64(i)
}
}
return 0
}
func invokeLetExpr(expr ast.Expr, rv reflect.Value, env *Env) (reflect.Value, error) {
switch lhs := expr.(type) {
case *ast.IdentExpr:
if env.Set(lhs.Lit, rv) != nil {
if strings.Contains(lhs.Lit, ".") {
return NilValue, fmt.Errorf("Undefined symbol '%s'", lhs.Lit)
}
env.Define(lhs.Lit, rv)
}
return rv, nil
}
return NilValue, errors.New("Invalid operation")
}
// invokeExpr evaluates one expression.
func invokeExpr(expr ast.Expr, env *Env) (reflect.Value, error) {
switch e := expr.(type) {
case *ast.NumberExpr:
if strings.Contains(e.Lit, ".") || strings.Contains(e.Lit, "e") {
v, err := strconv.ParseFloat(e.Lit, 64)
if err != nil {
return NilValue, err
}
return reflect.ValueOf(float64(v)), nil
}
var i int64
var err error
if strings.HasPrefix(e.Lit, "0x") {
i, err = strconv.ParseInt(e.Lit[2:], 16, 64)
} else {
i, err = strconv.ParseInt(e.Lit, 10, 64)
}
if err != nil {
return NilValue, err
}
return reflect.ValueOf(i), nil
case *ast.IdentExpr:
return env.Get(e.Lit)
case *ast.StringExpr:
return reflect.ValueOf(e.Lit), nil
case *ast.UnaryExpr:
v, err := invokeExpr(e.Expr, env)
if err != nil {
return v, err
}
switch e.Operator {
case "-":
if v.Kind() == reflect.Float64 {
return reflect.ValueOf(-v.Float()), nil
}
return reflect.ValueOf(-v.Int()), nil
case "^":
return reflect.ValueOf(^toInt64(v)), nil
case "!":
return reflect.ValueOf(!toBool(v)), nil
default:
return NilValue, errors.New("Unknown operator ''")
}
case *ast.ParenExpr:
v, err := invokeExpr(e.SubExpr, env)
if err != nil {
return v, err
}
return v, nil
case *ast.BinOpExpr:
lhsV := NilValue
rhsV := NilValue
var err error
lhsV, err = invokeExpr(e.Lhs, env)
if err != nil {
return lhsV, err
}
if lhsV.Kind() == reflect.Interface {
lhsV = lhsV.Elem()
}
if e.Rhs != nil {
rhsV, err = invokeExpr(e.Rhs, env)
if err != nil {
return rhsV, err
}
if rhsV.Kind() == reflect.Interface {
rhsV = rhsV.Elem()
}
}
switch e.Operator {
case "+":
if lhsV.Kind() == reflect.String || rhsV.Kind() == reflect.String {
return reflect.ValueOf(toString(lhsV) + toString(rhsV)), nil
}
if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() != reflect.Array && rhsV.Kind() != reflect.Slice) {
return reflect.Append(lhsV, rhsV), nil
}
if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() == reflect.Array || rhsV.Kind() == reflect.Slice) {
return reflect.AppendSlice(lhsV, rhsV), nil
}
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
return reflect.ValueOf(toFloat64(lhsV) + toFloat64(rhsV)), nil
}
return reflect.ValueOf(toInt64(lhsV) + toInt64(rhsV)), nil
case "-":
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
return reflect.ValueOf(toFloat64(lhsV) - toFloat64(rhsV)), nil
}
return reflect.ValueOf(toInt64(lhsV) - toInt64(rhsV)), nil
case "*":
if lhsV.Kind() == reflect.String && (rhsV.Kind() == reflect.Int || rhsV.Kind() == reflect.Int32 || rhsV.Kind() == reflect.Int64) {
return reflect.ValueOf(strings.Repeat(toString(lhsV), int(toInt64(rhsV)))), nil
}
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
return reflect.ValueOf(toFloat64(lhsV) * toFloat64(rhsV)), nil
}
return reflect.ValueOf(toInt64(lhsV) * toInt64(rhsV)), nil
case "/":
return reflect.ValueOf(toFloat64(lhsV) / toFloat64(rhsV)), nil
case "%":
return reflect.ValueOf(toInt64(lhsV) % toInt64(rhsV)), nil
case "==":
return reflect.ValueOf(equal(lhsV, rhsV)), nil
case "!=":
return reflect.ValueOf(equal(lhsV, rhsV) == false), nil
case ">":
return reflect.ValueOf(toFloat64(lhsV) > toFloat64(rhsV)), nil
case ">=":
return reflect.ValueOf(toFloat64(lhsV) >= toFloat64(rhsV)), nil
case "<":
return reflect.ValueOf(toFloat64(lhsV) < toFloat64(rhsV)), nil
case "<=":
return reflect.ValueOf(toFloat64(lhsV) <= toFloat64(rhsV)), nil
case "|":
return reflect.ValueOf(toInt64(lhsV) | toInt64(rhsV)), nil
case "||":
if toBool(lhsV) {
return lhsV, nil
}
return rhsV, nil
case "&":
return reflect.ValueOf(toInt64(lhsV) & toInt64(rhsV)), nil
case "&&":
if toBool(lhsV) {
return rhsV, nil
}
return lhsV, nil
case "**":
if lhsV.Kind() == reflect.Float64 {
return reflect.ValueOf(math.Pow(toFloat64(lhsV), toFloat64(rhsV))), nil
}
return reflect.ValueOf(int64(math.Pow(toFloat64(lhsV), toFloat64(rhsV)))), nil
case ">>":
return reflect.ValueOf(toInt64(lhsV) >> uint64(toInt64(rhsV))), nil
case "<<":
return reflect.ValueOf(toInt64(lhsV) << uint64(toInt64(rhsV))), nil
default:
return NilValue, errors.New("Unknown operator")
}
case *ast.CallExpr:
f, err := env.Get(e.Name)
if err != nil {
return f, err
}
args := []reflect.Value{}
for i, expr := range e.SubExprs {
arg, err := invokeExpr(expr, env)
if err != nil {
return arg, err
}
if i < f.Type().NumIn() {
if !f.Type().IsVariadic() {
it := f.Type().In(i)
if arg.Kind().String() == "unsafe.Pointer" {
arg = reflect.New(it).Elem()
}
if arg.Kind() != it.Kind() && arg.IsValid() && arg.Type().ConvertibleTo(it) {
arg = arg.Convert(it)
} else if arg.Kind() == reflect.Func {
if _, isFunc := arg.Interface().(Func); isFunc {
rfunc := arg
arg = reflect.MakeFunc(it, func(args []reflect.Value) []reflect.Value {
for i := range args {
args[i] = reflect.ValueOf(args[i])
}
return rfunc.Call(args)[:it.NumOut()]
})
}
} else if !arg.IsValid() {
arg = reflect.Zero(it)
}
}
}
if !arg.IsValid() {
arg = NilValue
}
args = append(args, arg)
}
ret := NilValue
fnc := func() {
defer func() {
if os.Getenv("KINAKO_DEBUG") == "" {
if ex := recover(); ex != nil {
if e, ok := ex.(error); ok {
err = e
} else {
err = errors.New(fmt.Sprint(ex))
}
}
}
}()
if f.Kind() == reflect.Interface {
f = f.Elem()
}
rets := f.Call(args)
if f.Type().NumOut() == 1 {
ret = rets[0]
} else {
var result []interface{}
for _, r := range rets {
result = append(result, r.Interface())
}
ret = reflect.ValueOf(result)
}
}
fnc()
if err != nil {
return ret, err
}
return ret, nil
case *ast.TernaryOpExpr:
rv, err := invokeExpr(e.Expr, env)
if err != nil {
return rv, err
}
if toBool(rv) {
lhsV, err := invokeExpr(e.Lhs, env)
if err != nil {
return lhsV, err
}
return lhsV, nil
}
rhsV, err := invokeExpr(e.Rhs, env)
if err != nil {
return rhsV, err
}
return rhsV, nil
default:
return NilValue, errors.New("Unknown expression")
}
}