// typEnumDecl type checks enum declarations. func (c *checker) typEnumDecl(e *ast.EnumDecl) Type { var values []*Const c.iota = constant.MakeInt64(-1) for _, e := range e.List { var x operand if e.X != nil { c.constExpr(&x, e.X) if x.mode == invalid { return Typ[Invalid] } } else { x.val = constant.BinaryOp(c.iota, scan.Plus, constant.MakeInt64(1)) } c.iota = x.val pos := e.Name.Span().Start name := e.Name.Name obj := NewConst(pos, name, Typ[Int], c.iota) values = append(values, obj) c.declare(Ord, c.scope, e.Name, obj, scan.NoPos) } t := new(Enum) t.values = values return t }
// reduce transforms expressions into equivalent but faster expressions. func (c *compiler) reduce(n *node) *node { var vl, vr int var lv arch.LV op := n.op cl := n.left.op == opLit cr := n.right.op == opLit if cl { vl, _ = strconv.Atoi(n.left.lv[0].Value.String()) } if cr { vr, _ = strconv.Atoi(n.right.lv[0].Value.String()) } switch { case (op == opPlus || op == opAdd) && cr && vr == 0: // x+0 -> x return n.left case (op == opPlus || op == opAdd) && cl && vl == 0: // 0+x -> x return n.right case op == opSub && cr && vr == 0: // x-0 -> x return n.left case op == opSub && cl && vl == 0: // 0-x -> -x return newNode(opNeg, nil, nil, n.right, nil) case op == opMul && ((cl && vl == 0) || (cr && vr == 0)): // 0*x -> 0 || x*0 -> 0 lv.Value = constant.MakeInt64(0) return newNode(opLit, &lv, nil, nil, nil) case op == opMul || op == opDiv: // reduce x*(2^n) or x/(2^n) to x<<n or x>>n lim := c.cg.Int()*8 - 1 for i, k := 0, 1; i < lim; i, k = i+1, k<<1 { lv.Value = constant.MakeInt64(int64(i)) m := newNode(opLit, &lv, nil, nil, nil) if cr && k == vr { if op == opMul { return newNode(opLsh, nil, nil, n.left, m) } else { return newNode(opRsh, nil, nil, n.left, m) } } else if cl && k == vl && op == opMul { return newNode(opLsh, nil, nil, n.right, m) } } } return n }
// selectorExpr generates code for record accesses (a.x, a->x, etc) func (c *compiler) selectorExpr(e *ast.SelectorExpr, lv *arch.LV) *node { sel, found := c.Selections[e] if !found { c.errorf(e.Op.Pos, "no selection expression information found") return nil } n := c.exprInternal(e.X, lv) if sel.Indirect() { n = c.rvalue(n, lv) lv.Ident = false } lv.Addressable = true if !sel.IsUnion() && sel.Offset() != 0 { lv.Value = constant.MakeInt64(sel.Offset()) m := newNode(opLit, lv, nil, nil, nil) n = newNode(opAdd, lv, nil, n, m) } if isArray(sel.Obj().Type()) { lv.Addressable = false } lv.Type = sel.Type().Underlying() return n }
// fold1 folds constant unary expressions. func (c *compiler) fold1(n *node) *node { var lv arch.LV switch n.op { case opScale: v, _ := strconv.Atoi(n.left.lv[0].Value.String()) lv.Value = constant.MakeInt64(int64(v * c.cg.Int())) default: return n } return newNode(opLit, &lv, nil, nil, nil) }
// exprInternal is the main driver, it does a recursive descent // through the expressions to type check them. func (c *checker) exprInternal(x *operand, e ast.Expr) exprType { x.mode = invalid x.typ = Typ[Invalid] pos := e.Span().Start switch e := e.(type) { case *ast.BadExpr: goto Error case *ast.BasicType: x.typ = c.typBasic(e) x.expr = e x.mode = typexpr return expression case *ast.Ident: c.ident(x, e, false) case *ast.StringLit: var text string for _, lit := range e.Lits { text += lit.Text[1 : len(lit.Text)-1] } text = strconv.Quote(text) x.setConst(scan.String, text) if x.mode == invalid { c.invalidAST(pos, "invalid literal %v", text) } case *ast.BasicLit: x.setConst(e.Type, e.Text) if x.mode == invalid { c.invalidAST(pos, "invalid literal %v", e.Text) goto Error } case *ast.CompositeLit: var y operand for _, elt := range e.Elts { c.expr(&y, elt) if y.mode != constant_ { c.errorf(y.pos(), "constant expression expected") } } case *ast.CallExpr: return c.call(x, e) case *ast.BinaryExpr: c.binary(x, e.X, e.Y, e.Op.Type) if x.mode == invalid { goto Error } case *ast.StarExpr: c.expr(x, e.X) switch x.mode { case invalid: goto Error case typexpr: x.typ = NewPointer(x.typ, nil) default: if typ, ok := x.typ.Underlying().(*Pointer); ok { x.mode = variable x.typ = typ.base } else { c.invalidOp(pos, "cannot indirect %s", x) } } case *ast.IndexExpr: c.expr(x, e.X) if x.mode == invalid { goto Error } valid := false switch typ := x.typ.Underlying().(type) { case *Pointer: valid = true if x.mode != variable { x.mode = value } x.typ = typ.Elem() } if !valid { c.invalidOp(x.pos(), "cannot index %s", x) goto Error } if e.Index == nil { c.invalidAST(pos, "missing index for %s", x) goto Error } c.index(e.Index) case *ast.UnaryExpr: c.expr(x, e.X) if x.mode == invalid { goto Error } c.unary(x, e, e.Op.Type) if x.mode == invalid { goto Error } case *ast.ParenExpr: exprType := c.expr(x, e.X) x.expr = e return exprType case *ast.SizeofExpr: c.expr(x, e.X) if x.mode == invalid { goto Error } typ := x.typ ptr, ok := typ.(*Pointer) if ok && ptr.Decay() != nil { typ = ptr.Decay() } x.mode = constant_ x.val = constant.MakeInt64(int64(c.conf.Sizes.Sizeof(typ))) x.typ = Typ[Int] case *ast.SelectorExpr: c.selector(x, e) case *ast.CondExpr: var y, z, w operand c.expr(&y, e.Cond) c.expr(&z, e.X) c.expr(&w, e.Y) x.mode = value x.typ = z.typ case *ast.CastExpr: typ := c.typExpr(e.Type) c.expr(x, e.X) x.typ = typ case *ast.RecordType: x.mode = typexpr x.typ = c.typExpr(e) default: panic(fmt.Sprintf("%s: unknown expression type %T", e.Span().Start, e)) } x.expr = e return expression Error: x.mode = invalid x.expr = e return statement }