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") } }