use kinako instead of anko
This commit is contained in:
409
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
Normal file
409
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
Normal file
@@ -0,0 +1,409 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"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)
|
||||
|
||||
func (f Func) String() string {
|
||||
return fmt.Sprintf("[Func: %p]", f)
|
||||
}
|
||||
|
||||
func ToFunc(f Func) reflect.Value {
|
||||
return reflect.ValueOf(f)
|
||||
}
|
||||
|
||||
// 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.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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user