// typAndValue returns a type and value from the type checker for an expression. func (c *compiler) typAndValue(e ast.Expr) (types.TypeAndValue, bool) { tv, found := c.Types[e] if !found { c.errorf(e.Span().Start, "no type info for expression") } return tv, found }
// indirection dereferences a pointer and generate code to load it. func (c *compiler) indirection(e ast.Expr, n *node, lv *arch.LV) *node { pos := e.Span().Start n = c.rvalue(n, lv) ptr, ok := lv.Type.(*types.Pointer) if !ok { c.errorf(pos, "indirection through non pointer") return nil } else if isVoidPointer(lv.Type) { c.errorf(pos, "dereferencing void pointer") return nil } lv.Ident = false lv.Type = ptr.Elem().Underlying() return n }
// typExprInternal is the main driver that type checks an expression. func (c *checker) typExprInternal(e ast.Expr) Type { switch e := e.(type) { case *ast.EnumDecl: return c.typEnumDecl(e) case *ast.VarDecl: // defaults to int if there is no type, for declarations such as // volatile count = 0; and such if e.Type == nil { return Typ[Int] } return c.typExpr(e.Type) case *ast.BasicType: return c.typBasic(e) case *ast.RecordType: return c.typRecord(e) case *ast.FuncType: return c.typFunc(e) case *ast.ParenExpr: return c.typExpr(e.X) case *ast.StarExpr: return NewPointer(c.typExpr(e.X), nil) case nil: c.errorf(scan.NoPos, "invalid nil node") default: c.errorf(e.Span().Start, "%T: %v is not a type", e, e) } typ := Typ[Invalid] return typ }
// constExpr type checks an expression for a constant value. func (c *checker) constExpr(x *operand, e ast.Expr) { c.expr(x, e) if x.mode != constant_ { c.errorf(e.Span().Start, "expected constant declaration, got %v", x.typ) } }
// 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 }
// exprInternal is the main function for generating code by figuring // out what kind of expression it is. func (c *compiler) exprInternal(e ast.Expr, lv *arch.LV) *node { lv.Ident = false pos := e.Span().Start tv, found := c.typAndValue(e) if !found { return nil } // for constants we can just get the value right away if tv.Value != nil { lv.Type = tv.Type lv.Value = tv.Value switch tv.Type { case types.Typ[types.UntypedString]: str, err := strconv.Unquote(tv.Value.String()) if err != nil { c.errorf(pos, "invalid constant %v: %v", tv.Value, err) } c.cg.Data() lab := c.cg.Label() c.cg.Lab(lab) c.cg.Defs(str) c.cg.Defb(0) c.cg.Align(len(str)+1, c.cg.Int()) lv.Addr = lab return newNode(opLdlab, lv, nil, nil, nil) default: return newNode(opLit, lv, nil, nil, nil) } } switch e := e.(type) { case *ast.BinaryExpr: return c.binaryExpr(e, lv) case *ast.UnaryExpr: return c.unaryExpr(e, lv) case *ast.SizeofExpr: return c.sizeofExpr(e, lv, tv) case *ast.StarExpr: return c.starExpr(e, lv) case *ast.CallExpr: return c.callExpr(e, lv) case *ast.Ident: return c.ident(e, lv, tv) case *ast.ParenExpr: return c.exprInternal(e.X, lv) case *ast.IndexExpr: return c.indexExpr(e, lv) case *ast.SelectorExpr: return c.selectorExpr(e, lv) case *ast.CondExpr: return c.condExpr(e, lv) case *ast.CastExpr: return c.castExpr(e, lv, tv) case *ast.BasicType: lv.Type = tv.Type default: c.errorf(pos, "invalid expression: %T", e) } return nil }