github.com/mattn/anko@v0.1.10/vm/vm.go (about)

     1  package vm
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/mattn/anko/ast"
    10  	"github.com/mattn/anko/env"
    11  )
    12  
    13  // Options provides options to run VM with
    14  type Options struct {
    15  	Debug bool // run in Debug mode
    16  }
    17  
    18  type (
    19  	// Error is a VM run error.
    20  	Error struct {
    21  		Message string
    22  		Pos     ast.Position
    23  	}
    24  
    25  	// runInfo provides run incoming and outgoing information
    26  	runInfoStruct struct {
    27  		// incoming
    28  		ctx      context.Context
    29  		env      *env.Env
    30  		options  *Options
    31  		stmt     ast.Stmt
    32  		expr     ast.Expr
    33  		operator ast.Operator
    34  
    35  		// outgoing
    36  		rv  reflect.Value
    37  		err error
    38  	}
    39  )
    40  
    41  var (
    42  	nilType            = reflect.TypeOf(nil)
    43  	stringType         = reflect.TypeOf("a")
    44  	byteType           = reflect.TypeOf(byte('a'))
    45  	runeType           = reflect.TypeOf('a')
    46  	interfaceType      = reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type()
    47  	interfaceSliceType = reflect.TypeOf([]interface{}{})
    48  	reflectValueType   = reflect.TypeOf(reflect.Value{})
    49  	errorType          = reflect.ValueOf([]error{nil}).Index(0).Type()
    50  	vmErrorType        = reflect.TypeOf(&Error{})
    51  	contextType        = reflect.TypeOf((*context.Context)(nil)).Elem()
    52  
    53  	nilValue                  = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
    54  	trueValue                 = reflect.ValueOf(true)
    55  	falseValue                = reflect.ValueOf(false)
    56  	zeroValue                 = reflect.Value{}
    57  	reflectValueNilValue      = reflect.ValueOf(nilValue)
    58  	reflectValueErrorNilValue = reflect.ValueOf(reflect.New(errorType).Elem())
    59  
    60  	errInvalidTypeConversion = fmt.Errorf("invalid type conversion")
    61  
    62  	// ErrBreak when there is an unexpected break statement
    63  	ErrBreak = errors.New("unexpected break statement")
    64  	// ErrContinue when there is an unexpected continue statement
    65  	ErrContinue = errors.New("unexpected continue statement")
    66  	// ErrReturn when there is an unexpected return statement
    67  	ErrReturn = errors.New("unexpected return statement")
    68  	// ErrInterrupt when execution has been interrupted
    69  	ErrInterrupt = errors.New("execution interrupted")
    70  )
    71  
    72  // Error returns the VM error message.
    73  func (e *Error) Error() string {
    74  	return e.Message
    75  }
    76  
    77  // newError makes VM error from error
    78  func newError(pos ast.Pos, err error) error {
    79  	if err == nil {
    80  		return nil
    81  	}
    82  	if pos == nil {
    83  		return &Error{Message: err.Error(), Pos: ast.Position{Line: 1, Column: 1}}
    84  	}
    85  	return &Error{Message: err.Error(), Pos: pos.Position()}
    86  }
    87  
    88  // newStringError makes VM error from string
    89  func newStringError(pos ast.Pos, err string) error {
    90  	if err == "" {
    91  		return nil
    92  	}
    93  	if pos == nil {
    94  		return &Error{Message: err, Pos: ast.Position{Line: 1, Column: 1}}
    95  	}
    96  	return &Error{Message: err, Pos: pos.Position()}
    97  }
    98  
    99  // recoverFunc generic recover function
   100  func recoverFunc(runInfo *runInfoStruct) {
   101  	recoverInterface := recover()
   102  	if recoverInterface == nil {
   103  		return
   104  	}
   105  	switch value := recoverInterface.(type) {
   106  	case *Error:
   107  		runInfo.err = value
   108  	case error:
   109  		runInfo.err = value
   110  	default:
   111  		runInfo.err = fmt.Errorf("%v", recoverInterface)
   112  	}
   113  }
   114  
   115  func isNil(v reflect.Value) bool {
   116  	switch v.Kind() {
   117  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
   118  		// from reflect IsNil:
   119  		// Note that IsNil is not always equivalent to a regular comparison with nil in Go.
   120  		// For example, if v was created by calling ValueOf with an uninitialized interface variable i,
   121  		// i==nil will be true but v.IsNil will panic as v will be the zero Value.
   122  		return v.IsNil()
   123  	default:
   124  		return false
   125  	}
   126  }
   127  
   128  func isNum(v reflect.Value) bool {
   129  	switch v.Kind() {
   130  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   131  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
   132  		reflect.Float32, reflect.Float64:
   133  		return true
   134  	}
   135  	return false
   136  }
   137  
   138  // equal returns true when lhsV and rhsV is same value.
   139  func equal(lhsV, rhsV reflect.Value) bool {
   140  	lhsIsNil, rhsIsNil := isNil(lhsV), isNil(rhsV)
   141  	if lhsIsNil && rhsIsNil {
   142  		return true
   143  	}
   144  	if (!lhsIsNil && rhsIsNil) || (lhsIsNil && !rhsIsNil) {
   145  		return false
   146  	}
   147  	if lhsV.Kind() == reflect.Interface || lhsV.Kind() == reflect.Ptr {
   148  		lhsV = lhsV.Elem()
   149  	}
   150  	if rhsV.Kind() == reflect.Interface || rhsV.Kind() == reflect.Ptr {
   151  		rhsV = rhsV.Elem()
   152  	}
   153  
   154  	// Compare a string and a number.
   155  	// This will attempt to convert the string to a number,
   156  	// while leaving the other side alone. Code further
   157  	// down takes care of converting ints and floats as needed.
   158  	if isNum(lhsV) && rhsV.Kind() == reflect.String {
   159  		rhsF, err := tryToFloat64(rhsV)
   160  		if err != nil {
   161  			// Couldn't convert RHS to a float, they can't be compared.
   162  			return false
   163  		}
   164  		rhsV = reflect.ValueOf(rhsF)
   165  	} else if lhsV.Kind() == reflect.String && isNum(rhsV) {
   166  		// If the LHS is a string formatted as an int, try that before trying float
   167  		lhsI, err := tryToInt64(lhsV)
   168  		if err != nil {
   169  			// if LHS is a float, e.g. "1.2", we need to set lhsV to a float64
   170  			lhsF, err := tryToFloat64(lhsV)
   171  			if err != nil {
   172  				return false
   173  			}
   174  			lhsV = reflect.ValueOf(lhsF)
   175  		} else {
   176  			lhsV = reflect.ValueOf(lhsI)
   177  		}
   178  	}
   179  
   180  	if isNum(lhsV) && isNum(rhsV) {
   181  		return fmt.Sprintf("%v", lhsV) == fmt.Sprintf("%v", rhsV)
   182  	}
   183  
   184  	// Try to compare bools to strings and numbers
   185  	if lhsV.Kind() == reflect.Bool || rhsV.Kind() == reflect.Bool {
   186  		lhsB, err := tryToBool(lhsV)
   187  		if err != nil {
   188  			return false
   189  		}
   190  		rhsB, err := tryToBool(rhsV)
   191  		if err != nil {
   192  			return false
   193  		}
   194  		return lhsB == rhsB
   195  	}
   196  
   197  	return reflect.DeepEqual(lhsV.Interface(), rhsV.Interface())
   198  }
   199  
   200  func getMapIndex(key reflect.Value, aMap reflect.Value) reflect.Value {
   201  	if aMap.IsNil() {
   202  		return nilValue
   203  	}
   204  
   205  	var err error
   206  	key, err = convertReflectValueToType(key, aMap.Type().Key())
   207  	if err != nil {
   208  		return nilValue
   209  	}
   210  
   211  	// From reflect MapIndex:
   212  	// It returns the zero Value if key is not found in the map or if v represents a nil map.
   213  	value := aMap.MapIndex(key)
   214  	if !value.IsValid() {
   215  		return nilValue
   216  	}
   217  
   218  	if aMap.Type().Elem() == interfaceType && !value.IsNil() {
   219  		value = reflect.ValueOf(value.Interface())
   220  	}
   221  
   222  	return value
   223  }
   224  
   225  // appendSlice appends rhs to lhs
   226  // function assumes lhsV and rhsV are slice or array
   227  func appendSlice(expr ast.Expr, lhsV reflect.Value, rhsV reflect.Value) (reflect.Value, error) {
   228  	lhsT := lhsV.Type().Elem()
   229  	rhsT := rhsV.Type().Elem()
   230  
   231  	if lhsT == rhsT {
   232  		return reflect.AppendSlice(lhsV, rhsV), nil
   233  	}
   234  
   235  	if rhsT.ConvertibleTo(lhsT) {
   236  		for i := 0; i < rhsV.Len(); i++ {
   237  			lhsV = reflect.Append(lhsV, rhsV.Index(i).Convert(lhsT))
   238  		}
   239  		return lhsV, nil
   240  	}
   241  
   242  	leftHasSubArray := lhsT.Kind() == reflect.Slice || lhsT.Kind() == reflect.Array
   243  	rightHasSubArray := rhsT.Kind() == reflect.Slice || rhsT.Kind() == reflect.Array
   244  
   245  	if leftHasSubArray != rightHasSubArray && lhsT != interfaceType && rhsT != interfaceType {
   246  		return nilValue, newStringError(expr, "invalid type conversion")
   247  	}
   248  
   249  	if !leftHasSubArray && !rightHasSubArray {
   250  		for i := 0; i < rhsV.Len(); i++ {
   251  			value := rhsV.Index(i)
   252  			if rhsT == interfaceType {
   253  				value = value.Elem()
   254  			}
   255  			if lhsT == value.Type() {
   256  				lhsV = reflect.Append(lhsV, value)
   257  			} else if value.Type().ConvertibleTo(lhsT) {
   258  				lhsV = reflect.Append(lhsV, value.Convert(lhsT))
   259  			} else {
   260  				return nilValue, newStringError(expr, "invalid type conversion")
   261  			}
   262  		}
   263  		return lhsV, nil
   264  	}
   265  
   266  	if (leftHasSubArray || lhsT == interfaceType) && (rightHasSubArray || rhsT == interfaceType) {
   267  		for i := 0; i < rhsV.Len(); i++ {
   268  			value := rhsV.Index(i)
   269  			if rhsT == interfaceType {
   270  				value = value.Elem()
   271  				if value.Kind() != reflect.Slice && value.Kind() != reflect.Array {
   272  					return nilValue, newStringError(expr, "invalid type conversion")
   273  				}
   274  			}
   275  			newSlice, err := appendSlice(expr, reflect.MakeSlice(lhsT, 0, value.Len()), value)
   276  			if err != nil {
   277  				return nilValue, err
   278  			}
   279  			lhsV = reflect.Append(lhsV, newSlice)
   280  		}
   281  		return lhsV, nil
   282  	}
   283  
   284  	return nilValue, newStringError(expr, "invalid type conversion")
   285  }
   286  
   287  func makeType(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type {
   288  	switch typeStruct.Kind {
   289  	case ast.TypeDefault:
   290  		return getTypeFromEnv(runInfo, typeStruct)
   291  	case ast.TypePtr:
   292  		var t reflect.Type
   293  		if typeStruct.SubType != nil {
   294  			t = makeType(runInfo, typeStruct.SubType)
   295  		} else {
   296  			t = getTypeFromEnv(runInfo, typeStruct)
   297  		}
   298  		if runInfo.err != nil {
   299  			return nil
   300  		}
   301  		if t == nil {
   302  			return nil
   303  		}
   304  		return reflect.PtrTo(t)
   305  	case ast.TypeSlice:
   306  		var t reflect.Type
   307  		if typeStruct.SubType != nil {
   308  			t = makeType(runInfo, typeStruct.SubType)
   309  		} else {
   310  			t = getTypeFromEnv(runInfo, typeStruct)
   311  		}
   312  		if runInfo.err != nil {
   313  			return nil
   314  		}
   315  		if t == nil {
   316  			return nil
   317  		}
   318  		for i := 1; i < typeStruct.Dimensions; i++ {
   319  			t = reflect.SliceOf(t)
   320  		}
   321  		return reflect.SliceOf(t)
   322  	case ast.TypeMap:
   323  		key := makeType(runInfo, typeStruct.Key)
   324  		if runInfo.err != nil {
   325  			return nil
   326  		}
   327  		if key == nil {
   328  			return nil
   329  		}
   330  		t := makeType(runInfo, typeStruct.SubType)
   331  		if runInfo.err != nil {
   332  			return nil
   333  		}
   334  		if t == nil {
   335  			return nil
   336  		}
   337  		if !runInfo.options.Debug {
   338  			// captures panic
   339  			defer recoverFunc(runInfo)
   340  		}
   341  		t = reflect.MapOf(key, t)
   342  		return t
   343  	case ast.TypeChan:
   344  		var t reflect.Type
   345  		if typeStruct.SubType != nil {
   346  			t = makeType(runInfo, typeStruct.SubType)
   347  		} else {
   348  			t = getTypeFromEnv(runInfo, typeStruct)
   349  		}
   350  		if runInfo.err != nil {
   351  			return nil
   352  		}
   353  		if t == nil {
   354  			return nil
   355  		}
   356  		return reflect.ChanOf(reflect.BothDir, t)
   357  	case ast.TypeStructType:
   358  		var t reflect.Type
   359  		fields := make([]reflect.StructField, 0, len(typeStruct.StructNames))
   360  		for i := 0; i < len(typeStruct.StructNames); i++ {
   361  			t = makeType(runInfo, typeStruct.StructTypes[i])
   362  			if runInfo.err != nil {
   363  				return nil
   364  			}
   365  			if t == nil {
   366  				return nil
   367  			}
   368  			fields = append(fields, reflect.StructField{Name: typeStruct.StructNames[i], Type: t})
   369  		}
   370  		if !runInfo.options.Debug {
   371  			// captures panic
   372  			defer recoverFunc(runInfo)
   373  		}
   374  		t = reflect.StructOf(fields)
   375  		return t
   376  	default:
   377  		runInfo.err = fmt.Errorf("unknown kind")
   378  		return nil
   379  	}
   380  }
   381  
   382  func getTypeFromEnv(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type {
   383  	var e *env.Env
   384  	e, runInfo.err = runInfo.env.GetEnvFromPath(typeStruct.Env)
   385  	if runInfo.err != nil {
   386  		return nil
   387  	}
   388  
   389  	var t reflect.Type
   390  	t, runInfo.err = e.Type(typeStruct.Name)
   391  	return t
   392  }
   393  
   394  func makeValue(t reflect.Type) (reflect.Value, error) {
   395  	switch t.Kind() {
   396  	case reflect.Chan:
   397  		return reflect.MakeChan(t, 0), nil
   398  	case reflect.Func:
   399  		return reflect.MakeFunc(t, nil), nil
   400  	case reflect.Map:
   401  		// note creating slice as work around to create map
   402  		// just doing MakeMap can give incorrect type for defined types
   403  		value := reflect.MakeSlice(reflect.SliceOf(t), 0, 1)
   404  		value = reflect.Append(value, reflect.MakeMap(reflect.MapOf(t.Key(), t.Elem())))
   405  		return value.Index(0), nil
   406  	case reflect.Ptr:
   407  		ptrV := reflect.New(t.Elem())
   408  		v, err := makeValue(t.Elem())
   409  		if err != nil {
   410  			return nilValue, err
   411  		}
   412  
   413  		ptrV.Elem().Set(v)
   414  		return ptrV, nil
   415  	case reflect.Slice:
   416  		return reflect.MakeSlice(t, 0, 0), nil
   417  	case reflect.Struct:
   418  		structV := reflect.New(t).Elem()
   419  		for i := 0; i < structV.NumField(); i++ {
   420  			if structV.Field(i).Kind() == reflect.Ptr {
   421  				continue
   422  			}
   423  			v, err := makeValue(structV.Field(i).Type())
   424  			if err != nil {
   425  				return nilValue, err
   426  			}
   427  			if structV.Field(i).CanSet() {
   428  				structV.Field(i).Set(v)
   429  			}
   430  		}
   431  		return structV, nil
   432  	}
   433  	return reflect.New(t).Elem(), nil
   434  }
   435  
   436  // precedenceOfKinds returns the greater of two kinds
   437  // string > float > int
   438  func precedenceOfKinds(kind1 reflect.Kind, kind2 reflect.Kind) reflect.Kind {
   439  	if kind1 == kind2 {
   440  		return kind1
   441  	}
   442  	switch kind1 {
   443  	case reflect.String:
   444  		return kind1
   445  	case reflect.Float64, reflect.Float32:
   446  		switch kind2 {
   447  		case reflect.String:
   448  			return kind2
   449  		}
   450  		return kind1
   451  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   452  		switch kind2 {
   453  		case reflect.String, reflect.Float64, reflect.Float32:
   454  			return kind2
   455  		}
   456  	}
   457  	return kind1
   458  }