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 * expr.go 12 * 13 * Created on Apr 01, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 "go/ast" 21 "go/token" 22 r "reflect" 23 24 xr "github.com/cosmos72/gomacro/xreflect" 25) 26 27// ExprsMultipleValues either a single expression returning multiple values, 28// or multiple expressions each returning a value. 29func (c *Comp) ExprsMultipleValues(nodes []ast.Expr, expectedValuesN int) (inits []*Expr) { 30 n := len(nodes) 31 if n != expectedValuesN { 32 if n != 1 { 33 c.Errorf("value count mismatch: cannot assign %d values to %d places: %v", 34 n, expectedValuesN, nodes) 35 return nil 36 } 37 e := c.expr(nodes[0], nil) 38 if actualN := e.NumOut(); actualN != expectedValuesN { 39 var plural string 40 if actualN != 1 { 41 plural = "s" 42 } 43 c.Errorf("expression returns %d value%s, expecting %d: %v", actualN, plural, expectedValuesN, nodes[0]) 44 } 45 inits = []*Expr{e} 46 } else { 47 inits = c.exprs(nodes) 48 } 49 return inits 50} 51 52// Exprs compiles multiple expressions 53func (c *Comp) Exprs(nodes []ast.Expr) []*Expr { 54 es := c.exprs(nodes) 55 for _, e := range es { 56 c.Jit.Fun(e) 57 } 58 return es 59} 60 61// same as Exprs, but does not replace e[i].Fun with jit-compiled code 62func (c *Comp) exprs(nodes []ast.Expr) []*Expr { 63 var es []*Expr 64 if n := len(nodes); n != 0 { 65 es = make([]*Expr, n) 66 for i := range nodes { 67 es[i] = c.expr1(nodes[i], nil) 68 } 69 } 70 return es 71} 72 73// Expr1 compiles an expression that returns a single value 74// t is optional and used for type inference on composite literals, 75// see https://golang.org/ref/spec#Composite_literals 76func (c *Comp) Expr1(in ast.Expr, t xr.Type) *Expr { 77 return c.expr1(in, t) 78} 79 80// same as Expr1, but does not replace e.Fun with jit-compiled code 81func (c *Comp) expr1(in ast.Expr, t xr.Type) *Expr { 82 for { 83 if in != nil { 84 c.Pos = in.Pos() 85 } 86 // env.Debugf("Expr1() %v", node) 87 switch node := in.(type) { 88 case *ast.ParenExpr: 89 in = node.X 90 continue 91 case *ast.IndexExpr: 92 return c.IndexExpr1(node) 93 case *ast.TypeAssertExpr: 94 return c.TypeAssert1(node) 95 case *ast.UnaryExpr: 96 if node.Op == token.ARROW { 97 xe := c.Expr1(node.X, nil) 98 return c.Recv1(node, xe) 99 } else { 100 return c.UnaryExpr(node) 101 } 102 } 103 break 104 } 105 e := c.expr(in, t) 106 nout := e.NumOut() 107 switch nout { 108 case 0: 109 c.Errorf("expression returns no values, expecting one: %v", in) 110 return nil 111 case 1: 112 return e 113 default: 114 return e.exprXVAsI() 115 } 116} 117 118// Expr compiles an expression. 119// t is optional and used for type inference on composite literals, 120// see https://golang.org/ref/spec#Composite_literals 121func (c *Comp) Expr(in ast.Expr, t xr.Type) *Expr { 122 e := c.expr(in, t) 123 return c.Jit.Fun(e) 124} 125 126// same as Expr, but does not replace e.Fun with jit-compiled code 127func (c *Comp) expr(in ast.Expr, t xr.Type) *Expr { 128 for { 129 if in != nil { 130 c.Pos = in.Pos() 131 } 132 // env.Debugf("Expr() %v", node) 133 switch node := in.(type) { 134 case *ast.BasicLit: 135 return c.BasicLit(node) 136 case *ast.BinaryExpr: 137 return c.BinaryExpr(node) 138 case *ast.CallExpr: 139 return c.CallExpr(node) 140 case *ast.CompositeLit: 141 // propagate inferred type 142 return c.CompositeLit(node, t) 143 case *ast.FuncLit: 144 return c.FuncLit(node) 145 case *ast.Ident: 146 return c.Ident(node.Name) 147 case *ast.IndexExpr: 148 return c.IndexExpr(node) 149 case *ast.ParenExpr: 150 in = node.X 151 continue 152 case *ast.UnaryExpr: 153 return c.UnaryExpr(node) 154 case *ast.SelectorExpr: 155 return c.SelectorExpr(node) 156 case *ast.SliceExpr: 157 return c.SliceExpr(node) 158 case *ast.StarExpr: 159 return c.StarExpr(node) 160 case *ast.TypeAssertExpr: 161 return c.TypeAssert2(node) 162 default: 163 } 164 c.Errorf("unimplemented Compile() for: %v <%v>", in, r.TypeOf(in)) 165 return nil 166 } 167} 168 169// Expr1OrType compiles an single-valued expression or a type. 170// performs simultaneous lookup for type names, constants, variables and functions 171func (c *Comp) Expr1OrType(expr ast.Expr) (e *Expr, t xr.Type) { 172 node := expr 173 for { 174 switch n := node.(type) { 175 case *ast.StarExpr: 176 node = n.X 177 continue 178 case *ast.ParenExpr: 179 node = n.X 180 continue 181 case *ast.Ident: 182 name := n.Name 183 for o := c; o != nil; o = o.Outer { 184 bind, okb := o.Binds[name] 185 var okt bool 186 if GENERICS_V1 && okb { 187 _, okt = bind.Value.(*TemplateType) // template types are stored in Comp.Bind[] 188 okb = !okt 189 } 190 if okb { 191 return c.Expr1(expr, nil), nil 192 } else if _, ok := o.Types[name]; ok || okt { 193 return nil, c.Type(expr) 194 } 195 } 196 case *ast.IndexExpr: 197 if GENERICS_V1 { 198 if lit, ok := n.Index.(*ast.CompositeLit); ok && lit.Type == nil { 199 // foo#[a, b...] can be a template function or a template type 200 node = n.X 201 continue 202 } 203 } 204 } 205 break 206 } 207 panicking := true 208 defer func() { 209 if panicking { 210 recover() 211 t = c.Type(expr) 212 } 213 }() 214 e = c.Expr1(expr, nil) 215 panicking = false 216 return 217} 218 219// IndexExpr compiles a read operation on obj[idx] 220// or a template function name#[T1, T2...] 221func (c *Comp) IndexExpr(node *ast.IndexExpr) *Expr { 222 if GENERICS_V1 { 223 if e := c.TemplateFunc(node); e != nil { 224 return e 225 } 226 } 227 return c.indexExpr(node, true) 228} 229 230// IndexExpr1 compiles a single-valued read operation on obj[idx] 231// or a template function name#[T1, T2...] 232func (c *Comp) IndexExpr1(node *ast.IndexExpr) *Expr { 233 if GENERICS_V1 { 234 if e := c.TemplateFunc(node); e != nil { 235 return e 236 } 237 } 238 return c.indexExpr(node, false) 239} 240