1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2017-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * compositelit.go 12 * 13 * Created on May 28, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 "go/ast" 21 r "reflect" 22 23 . "github.com/cosmos72/gomacro/base" 24 "github.com/cosmos72/gomacro/base/untyped" 25 xr "github.com/cosmos72/gomacro/xreflect" 26) 27 28func (c *Comp) CompositeLit(node *ast.CompositeLit, t xr.Type) *Expr { 29 var ellipsis bool 30 // node.Type is nil when exploiting type inference 31 if node.Type != nil { 32 var et xr.Type 33 et, ellipsis = c.compileType2(node.Type, false) 34 if et != nil { 35 if t == nil || et.AssignableTo(t) { 36 t = et 37 } else { 38 c.Errorf("invalid type for composite literal: <%v> %v, expecting %v", et, node.Type, t) 39 } 40 } 41 } 42 if t == nil { 43 c.Errorf("no explicit type and no inferred type, cannot compile composite literal: %v", node) 44 } 45 switch t.Kind() { 46 case r.Array: 47 return c.compositeLitArray(t, ellipsis, node) 48 case r.Map: 49 return c.compositeLitMap(t, node) 50 case r.Slice: 51 return c.compositeLitSlice(t, node) 52 case r.Struct: 53 return c.compositeLitStruct(t, node) 54 case r.Ptr: 55 switch t.Elem().Kind() { 56 case r.Array, r.Map, r.Slice, r.Struct: 57 return c.addressOf(node, t) 58 } 59 } 60 c.Errorf("invalid type for composite literal: <%v> %v", t, node.Type) 61 return nil 62} 63 64func (c *Comp) compositeLitArray(t xr.Type, ellipsis bool, node *ast.CompositeLit) *Expr { 65 rtype := t.ReflectType() 66 n := len(node.Elts) 67 if n == 0 { 68 return exprX1(t, func(env *Env) r.Value { 69 // array len is already encoded in its type 70 return r.New(rtype).Elem() 71 }) 72 } 73 size, keys, funvals := c.compositeLitElements(t, ellipsis, node) 74 if ellipsis { 75 // rebuild type with correct length 76 t = c.Universe.ArrayOf(size, t.Elem()) 77 rtype = t.ReflectType() 78 } 79 80 rtval := rtype.Elem() 81 zeroval := r.Zero(rtval) 82 83 return exprX1(t, func(env *Env) r.Value { 84 obj := r.New(rtype).Elem() 85 var val r.Value 86 for i, funval := range funvals { 87 val = funval(env) 88 if val == Nil || val == None { 89 val = zeroval 90 } else if val.Type() != rtval { 91 val = convert(val, rtval) 92 } 93 obj.Index(keys[i]).Set(val) 94 } 95 return obj 96 }) 97} 98 99func (c *Comp) compositeLitSlice(t xr.Type, node *ast.CompositeLit) *Expr { 100 rtype := t.ReflectType() 101 n := len(node.Elts) 102 if n == 0 { 103 return exprX1(t, func(env *Env) r.Value { 104 return r.MakeSlice(rtype, 0, 0) 105 }) 106 } 107 size, keys, funvals := c.compositeLitElements(t, false, node) 108 109 rtval := rtype.Elem() 110 zeroval := r.Zero(rtval) 111 return exprX1(t, func(env *Env) r.Value { 112 obj := r.MakeSlice(rtype, size, size) 113 var val r.Value 114 for i, funval := range funvals { 115 val = funval(env) 116 if val == Nil || val == None { 117 val = zeroval 118 } else if val.Type() != rtval { 119 val = convert(val, rtval) 120 } 121 obj.Index(keys[i]).Set(val) 122 } 123 return obj 124 }) 125} 126 127func (c *Comp) compositeLitElements(t xr.Type, ellipsis bool, node *ast.CompositeLit) (size int, keys []int, funvals []func(*Env) r.Value) { 128 n := len(node.Elts) 129 tval := t.Elem() 130 seen := make(map[int]bool) // indexes already seen 131 keys = make([]int, n) 132 funvals = make([]func(*Env) r.Value, n) 133 size = 0 134 key, lastkey := 0, -1 135 136 for i, el := range node.Elts { 137 elv := el 138 switch elkv := el.(type) { 139 case *ast.KeyValueExpr: 140 ekey := c.Expr1(elkv.Key, nil) 141 if !ekey.Const() { 142 c.Errorf("literal %s index must be non-negative integer constant: %v", t.Kind(), elkv.Key) 143 } else if ekey.Untyped() { 144 key = ekey.ConstTo(c.TypeOfInt()).(int) 145 } else { 146 key = untyped.ConvertLiteralCheckOverflow(ekey.Value, c.TypeOfInt()).(int) 147 } 148 lastkey = key 149 elv = elkv.Value 150 default: 151 lastkey++ 152 } 153 if lastkey < 0 { 154 c.Errorf("literal %s index must be non-negative integer constant: %v", t.Kind(), lastkey) 155 } else if !ellipsis && t.Kind() == r.Array && lastkey >= t.Len() { 156 c.Errorf("%s index %d out of bounds [0:%d]", t.Kind(), lastkey, t.Len()) 157 } else if seen[lastkey] { 158 c.Errorf("duplicate index in %s literal: %d", t.Kind(), lastkey) 159 } 160 seen[lastkey] = true 161 if size <= lastkey { 162 if lastkey == MaxInt { 163 c.Errorf("literal %s too large: found index == MaxInt", t.Kind()) 164 } 165 size = lastkey + 1 166 } 167 keys[i] = lastkey 168 169 eval := c.Expr1(elv, tval) 170 if eval.Const() { 171 eval.ConstTo(tval) 172 } else if !eval.Type.AssignableTo(tval) { 173 c.Errorf("cannot use %v <%v> as type <%v> in %s value", elv, eval.Type, tval, t.Kind()) 174 } else { 175 eval.To(c, tval) 176 } 177 funvals[i] = eval.AsX1() 178 } 179 return size, keys, funvals 180} 181 182func (c *Comp) compositeLitMap(t xr.Type, node *ast.CompositeLit) *Expr { 183 rtype := t.ReflectType() 184 n := len(node.Elts) 185 if n == 0 { 186 return exprX1(t, func(env *Env) r.Value { 187 return r.MakeMap(rtype) 188 }) 189 } 190 tkey := t.Key() 191 tval := t.Elem() 192 193 seen := make(map[interface{}]bool) // constant keys already seen 194 funkeys := make([]func(*Env) r.Value, n) 195 funvals := make([]func(*Env) r.Value, n) 196 197 for i, el := range node.Elts { 198 switch elkv := el.(type) { 199 case *ast.KeyValueExpr: 200 ekey := c.Expr1(elkv.Key, tkey) 201 if ekey.Const() { 202 ekey.ConstTo(tkey) 203 if seen[ekey.Value] { 204 c.Errorf("duplicate key %v in map literal", elkv.Key) 205 } 206 seen[ekey.Value] = true 207 } else if !ekey.Type.AssignableTo(tkey) { 208 c.Errorf("cannot use %v <%v> as type <%v> in map key", elkv.Key, ekey.Type, tkey) 209 } else { 210 ekey.To(c, tkey) 211 } 212 eval := c.Expr1(elkv.Value, tval) 213 if eval.Const() { 214 eval.ConstTo(tval) 215 } else if !eval.Type.AssignableTo(tval) { 216 c.Errorf("cannot use %v <%v> as type <%v> in map value", elkv.Value, eval.Type, tval) 217 } else { 218 eval.To(c, tval) 219 } 220 funkeys[i] = ekey.AsX1() 221 funvals[i] = eval.AsX1() 222 223 default: 224 c.Errorf("missing key in map literal: %v", el) 225 } 226 } 227 return exprX1(t, func(env *Env) r.Value { 228 obj := r.MakeMap(rtype) 229 var key, val r.Value 230 for i, funkey := range funkeys { 231 key = funkey(env) 232 val = funvals[i](env) 233 obj.SetMapIndex(key, val) 234 } 235 return obj 236 }) 237} 238 239func (c *Comp) compositeLitStruct(t xr.Type, node *ast.CompositeLit) *Expr { 240 rtype := t.ReflectType() 241 n := len(node.Elts) 242 if n == 0 { 243 return exprX1(t, func(env *Env) r.Value { 244 return r.New(rtype).Elem() 245 }) 246 } 247 248 var seen map[string]bool 249 var all map[string]xr.StructField 250 inits := make([]func(*Env) r.Value, n) 251 indexes := make([]int, n) 252 var flagkv, flagv bool 253 254 for i, el := range node.Elts { 255 switch elkv := el.(type) { 256 case *ast.KeyValueExpr: 257 flagkv = true 258 if flagv { 259 c.Errorf("mixture of field:value and value in struct literal: %v", node) 260 } 261 switch k := elkv.Key.(type) { 262 case *ast.Ident: 263 name := k.Name 264 if seen[name] { 265 c.Errorf("duplicate field name in struct literal: %v", name) 266 } else if seen == nil { 267 seen = make(map[string]bool) 268 all = listStructFields(t, c.FileComp().Path) 269 } 270 field, ok := all[name] 271 if !ok { 272 c.Errorf("unknown field '%v' in struct literal of type %v", name, t) 273 } 274 expr := c.Expr1(elkv.Value, field.Type) 275 if expr.Const() { 276 expr.ConstTo(field.Type) 277 } else if !expr.Type.AssignableTo(field.Type) { 278 c.Errorf("cannot use %v <%v> as type <%v> in field value", elkv.Value, expr.Type, field.Type) 279 } else { 280 expr.To(c, field.Type) 281 } 282 inits[i] = expr.AsX1() 283 indexes[i] = field.Index[0] 284 default: 285 c.Errorf("invalid field name '%v' in struct literal", k) 286 } 287 default: 288 flagv = true 289 if flagkv { 290 c.Errorf("mixture of field:value and value in struct literal: %v", node) 291 } 292 field := t.Field(i) 293 expr := c.Expr1(el, field.Type) 294 if expr.Const() { 295 expr.ConstTo(field.Type) 296 } else if !expr.Type.AssignableTo(field.Type) { 297 c.Errorf("cannot use %v <%v> as type <%v> in field value", el, expr.Type, field.Type) 298 } else { 299 expr.To(c, field.Type) 300 } 301 if !ast.IsExported(field.Name) && field.Pkg.Path() != c.FileComp().Path { 302 c.Errorf("implicit assignment of unexported field '%v' in struct literal <%v>", field.Name, t) 303 } 304 inits[i] = expr.AsX1() 305 indexes[i] = field.Index[0] 306 } 307 } 308 if nfield := t.NumField(); flagv && n != nfield { 309 var label, plural = "few", "s" 310 if n > nfield { 311 label = "many" 312 } else if n == 1 { 313 plural = "" 314 } 315 c.Errorf("too %s values in struct initializer: <%v> has %d fields, found %d initializer%s", 316 label, t, nfield, n, plural) 317 } 318 return exprX1(t, func(env *Env) r.Value { 319 obj := r.New(rtype).Elem() 320 var val, field r.Value 321 var tfield r.Type 322 for i, init := range inits { 323 val = init(env) 324 if val == Nil || val == None { 325 continue 326 } 327 field = obj.Field(indexes[i]) 328 tfield = field.Type() 329 if val.Type() != tfield { 330 val = convert(val, tfield) 331 } 332 field.Set(val) 333 } 334 return obj 335 }) 336} 337 338// listStructFields lists the field names of a struct. It ignores embedded fields. 339// Unexported fields are listed only if their package's path matches given pkgpath 340func listStructFields(t xr.Type, pkgpath string) map[string]xr.StructField { 341 list := make(map[string]xr.StructField) 342 for i, n := 0, t.NumField(); i < n; i++ { 343 f := t.Field(i) 344 if ast.IsExported(f.Name) || f.Pkg.Path() == pkgpath { 345 list[f.Name] = f 346 } 347 } 348 return list 349} 350