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

     1  package vm
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/mattn/anko/ast"
     7  	"github.com/mattn/anko/env"
     8  )
     9  
    10  func (runInfo *runInfoStruct) invokeLetExpr() {
    11  	switch expr := runInfo.expr.(type) {
    12  
    13  	// IdentExpr
    14  	case *ast.IdentExpr:
    15  		if runInfo.env.SetValue(expr.Lit, runInfo.rv) != nil {
    16  			runInfo.err = nil
    17  			runInfo.env.DefineValue(expr.Lit, runInfo.rv)
    18  		}
    19  
    20  	// MemberExpr
    21  	case *ast.MemberExpr:
    22  		value := runInfo.rv
    23  
    24  		runInfo.expr = expr.Expr
    25  		runInfo.invokeExpr()
    26  		if runInfo.err != nil {
    27  			return
    28  		}
    29  
    30  		if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() {
    31  			runInfo.rv = runInfo.rv.Elem()
    32  		}
    33  
    34  		if env, ok := runInfo.rv.Interface().(*env.Env); ok {
    35  			runInfo.err = env.SetValue(expr.Name, value)
    36  			if runInfo.err != nil {
    37  				runInfo.err = newError(expr, runInfo.err)
    38  				runInfo.rv = nilValue
    39  			}
    40  			return
    41  		}
    42  
    43  		if runInfo.rv.Kind() == reflect.Ptr {
    44  			runInfo.rv = runInfo.rv.Elem()
    45  		}
    46  
    47  		switch runInfo.rv.Kind() {
    48  
    49  		// Struct
    50  		case reflect.Struct:
    51  			field, found := runInfo.rv.Type().FieldByName(expr.Name)
    52  			if !found {
    53  				runInfo.err = newStringError(expr, "no member named '"+expr.Name+"' for struct")
    54  				runInfo.rv = nilValue
    55  				return
    56  			}
    57  			runInfo.rv = runInfo.rv.FieldByIndex(field.Index)
    58  			// From reflect CanSet:
    59  			// A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields.
    60  			// Often a struct has to be passed as a pointer to be set
    61  			if !runInfo.rv.CanSet() {
    62  				runInfo.err = newStringError(expr, "struct member '"+expr.Name+"' cannot be assigned")
    63  				runInfo.rv = nilValue
    64  				return
    65  			}
    66  
    67  			value, runInfo.err = convertReflectValueToType(value, runInfo.rv.Type())
    68  			if runInfo.err != nil {
    69  				runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+runInfo.rv.Type().String()+" for struct")
    70  				runInfo.rv = nilValue
    71  				return
    72  			}
    73  
    74  			runInfo.rv.Set(value)
    75  			return
    76  
    77  		// Map
    78  		case reflect.Map:
    79  			value, runInfo.err = convertReflectValueToType(value, runInfo.rv.Type().Elem())
    80  			if runInfo.err != nil {
    81  				runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+runInfo.rv.Type().Elem().String()+" for map")
    82  				runInfo.rv = nilValue
    83  				return
    84  			}
    85  			if runInfo.rv.IsNil() {
    86  				// make new map
    87  				item := reflect.MakeMap(runInfo.rv.Type())
    88  				item.SetMapIndex(reflect.ValueOf(expr.Name), value)
    89  				// assign new map
    90  				runInfo.rv = item
    91  				runInfo.expr = expr.Expr
    92  				runInfo.invokeLetExpr()
    93  				runInfo.rv = item.MapIndex(reflect.ValueOf(expr.Name))
    94  				return
    95  			}
    96  			runInfo.rv.SetMapIndex(reflect.ValueOf(expr.Name), value)
    97  
    98  		default:
    99  			runInfo.err = newStringError(expr, "type "+runInfo.rv.Kind().String()+" does not support member operation")
   100  			runInfo.rv = nilValue
   101  		}
   102  
   103  	// ItemExpr
   104  	case *ast.ItemExpr:
   105  		value := runInfo.rv
   106  
   107  		runInfo.expr = expr.Item
   108  		runInfo.invokeExpr()
   109  		if runInfo.err != nil {
   110  			return
   111  		}
   112  		item := runInfo.rv
   113  
   114  		runInfo.expr = expr.Index
   115  		runInfo.invokeExpr()
   116  		if runInfo.err != nil {
   117  			return
   118  		}
   119  
   120  		if item.Kind() == reflect.Interface && !item.IsNil() {
   121  			item = item.Elem()
   122  		}
   123  
   124  		switch item.Kind() {
   125  
   126  		// Slice && Array
   127  		case reflect.Slice, reflect.Array:
   128  			var index int
   129  			index, runInfo.err = tryToInt(runInfo.rv)
   130  			if runInfo.err != nil {
   131  				runInfo.err = newStringError(expr, "index must be a number")
   132  				runInfo.rv = nilValue
   133  				return
   134  			}
   135  
   136  			if index == item.Len() {
   137  				// try to do automatic append
   138  				value, runInfo.err = convertReflectValueToType(value, item.Type().Elem())
   139  				if runInfo.err != nil {
   140  					runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().Elem().String()+" for slice index")
   141  					runInfo.rv = nilValue
   142  					return
   143  				}
   144  				item = reflect.Append(item, value)
   145  				runInfo.rv = item
   146  				runInfo.expr = expr.Item
   147  				runInfo.invokeLetExpr()
   148  				runInfo.rv = item.Index(index)
   149  				return
   150  			}
   151  
   152  			if index < 0 || index >= item.Len() {
   153  				runInfo.err = newStringError(expr, "index out of range")
   154  				runInfo.rv = nilValue
   155  				return
   156  			}
   157  			item = item.Index(index)
   158  			if !item.CanSet() {
   159  				runInfo.err = newStringError(expr, "index cannot be assigned")
   160  				runInfo.rv = nilValue
   161  				return
   162  			}
   163  
   164  			value, runInfo.err = convertReflectValueToType(value, item.Type())
   165  			if runInfo.err != nil {
   166  				runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().String()+" for slice index")
   167  				runInfo.rv = nilValue
   168  				return
   169  			}
   170  
   171  			item.Set(value)
   172  			runInfo.rv = item
   173  
   174  		// Map
   175  		case reflect.Map:
   176  			runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, item.Type().Key())
   177  			if runInfo.err != nil {
   178  				runInfo.err = newStringError(expr, "index type "+runInfo.rv.Type().String()+" cannot be used for map index type "+item.Type().Key().String())
   179  				runInfo.rv = nilValue
   180  				return
   181  			}
   182  
   183  			value, runInfo.err = convertReflectValueToType(value, item.Type().Elem())
   184  			if runInfo.err != nil {
   185  				runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().Elem().String()+" for map")
   186  				runInfo.rv = nilValue
   187  				return
   188  			}
   189  
   190  			if item.IsNil() {
   191  				// make new map
   192  				item = reflect.MakeMap(item.Type())
   193  				item.SetMapIndex(runInfo.rv, value)
   194  				mapIndex := runInfo.rv
   195  				// assign new map
   196  				runInfo.rv = item
   197  				runInfo.expr = expr.Item
   198  				runInfo.invokeLetExpr()
   199  				runInfo.rv = item.MapIndex(mapIndex)
   200  				return
   201  			}
   202  			item.SetMapIndex(runInfo.rv, value)
   203  
   204  		// String
   205  		case reflect.String:
   206  			var index int
   207  			index, runInfo.err = tryToInt(runInfo.rv)
   208  			if runInfo.err != nil {
   209  				runInfo.err = newStringError(expr, "index must be a number")
   210  				runInfo.rv = nilValue
   211  				return
   212  			}
   213  
   214  			value, runInfo.err = convertReflectValueToType(value, item.Type())
   215  			if runInfo.err != nil {
   216  				runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().String())
   217  				runInfo.rv = nilValue
   218  				return
   219  			}
   220  
   221  			if index == item.Len() {
   222  				// automatic append
   223  				if item.CanSet() {
   224  					item.SetString(item.String() + value.String())
   225  					return
   226  				}
   227  
   228  				runInfo.rv = reflect.ValueOf(item.String() + value.String())
   229  				runInfo.expr = expr.Item
   230  				runInfo.invokeLetExpr()
   231  				return
   232  			}
   233  
   234  			if index < 0 || index >= item.Len() {
   235  				runInfo.err = newStringError(expr, "index out of range")
   236  				runInfo.rv = nilValue
   237  				return
   238  			}
   239  
   240  			if item.CanSet() {
   241  				item.SetString(item.Slice(0, index).String() + value.String() + item.Slice(index+1, item.Len()).String())
   242  				runInfo.rv = item
   243  				return
   244  			}
   245  
   246  			runInfo.rv = reflect.ValueOf(item.Slice(0, index).String() + value.String() + item.Slice(index+1, item.Len()).String())
   247  			runInfo.expr = expr.Item
   248  			runInfo.invokeLetExpr()
   249  
   250  		default:
   251  			runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support index operation")
   252  			runInfo.rv = nilValue
   253  		}
   254  
   255  	// SliceExpr
   256  	case *ast.SliceExpr:
   257  		value := runInfo.rv
   258  
   259  		runInfo.expr = expr.Item
   260  		runInfo.invokeExpr()
   261  		if runInfo.err != nil {
   262  			return
   263  		}
   264  		item := runInfo.rv
   265  
   266  		if item.Kind() == reflect.Interface && !item.IsNil() {
   267  			item = item.Elem()
   268  		}
   269  
   270  		switch item.Kind() {
   271  
   272  		// Slice && Array
   273  		case reflect.Slice, reflect.Array:
   274  			var beginIndex int
   275  			endIndex := item.Len()
   276  
   277  			if expr.Begin != nil {
   278  				runInfo.expr = expr.Begin
   279  				runInfo.invokeExpr()
   280  				if runInfo.err != nil {
   281  					return
   282  				}
   283  				beginIndex, runInfo.err = tryToInt(runInfo.rv)
   284  				if runInfo.err != nil {
   285  					runInfo.err = newStringError(expr, "index must be a number")
   286  					runInfo.rv = nilValue
   287  					return
   288  				}
   289  				// (0 <= low) <= high <= len(a)
   290  				if beginIndex < 0 {
   291  					runInfo.err = newStringError(expr, "index out of range")
   292  					runInfo.rv = nilValue
   293  					return
   294  				}
   295  			}
   296  
   297  			if expr.End != nil {
   298  				runInfo.expr = expr.End
   299  				runInfo.invokeExpr()
   300  				if runInfo.err != nil {
   301  					return
   302  				}
   303  				endIndex, runInfo.err = tryToInt(runInfo.rv)
   304  				if runInfo.err != nil {
   305  					runInfo.err = newStringError(expr, "index must be a number")
   306  					runInfo.rv = nilValue
   307  					return
   308  				}
   309  				// 0 <= low <= (high <= len(a))
   310  				if endIndex > item.Len() {
   311  					runInfo.err = newStringError(expr, "index out of range")
   312  					runInfo.rv = nilValue
   313  					return
   314  				}
   315  			}
   316  
   317  			// 0 <= (low <= high) <= len(a)
   318  			if beginIndex > endIndex {
   319  				runInfo.err = newStringError(expr, "index out of range")
   320  				runInfo.rv = nilValue
   321  				return
   322  			}
   323  
   324  			sliceCap := item.Cap()
   325  			if expr.Cap != nil {
   326  				runInfo.expr = expr.Cap
   327  				runInfo.invokeExpr()
   328  				if runInfo.err != nil {
   329  					return
   330  				}
   331  				sliceCap, runInfo.err = tryToInt(runInfo.rv)
   332  				if runInfo.err != nil {
   333  					runInfo.err = newStringError(expr, "cap must be a number")
   334  					runInfo.rv = nilValue
   335  					return
   336  				}
   337  				//  0 <= low <= (high <= max <= cap(a))
   338  				if sliceCap < endIndex || sliceCap > item.Cap() {
   339  					runInfo.err = newStringError(expr, "cap out of range")
   340  					runInfo.rv = nilValue
   341  					return
   342  				}
   343  			}
   344  
   345  			item = item.Slice3(beginIndex, endIndex, sliceCap)
   346  
   347  			if !item.CanSet() {
   348  				runInfo.err = newStringError(expr, "slice cannot be assigned")
   349  				runInfo.rv = nilValue
   350  				return
   351  			}
   352  			item.Set(value)
   353  
   354  		// String
   355  		case reflect.String:
   356  			runInfo.err = newStringError(expr, "type string does not support slice operation for assignment")
   357  			runInfo.rv = nilValue
   358  
   359  		default:
   360  			runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support slice operation")
   361  			runInfo.rv = nilValue
   362  		}
   363  
   364  	// DerefExpr
   365  	case *ast.DerefExpr:
   366  		value := runInfo.rv
   367  
   368  		runInfo.expr = expr.Expr
   369  		runInfo.invokeExpr()
   370  		if runInfo.err != nil {
   371  			return
   372  		}
   373  
   374  		runInfo.rv.Elem().Set(value)
   375  		runInfo.rv = value
   376  
   377  	default:
   378  		runInfo.err = newStringError(expr, "invalid operation")
   379  		runInfo.rv = nilValue
   380  	}
   381  
   382  }