func buildBinaryOpExpr(b *builder, expr *tast.OpExpr) *ref { op := expr.Op.Lit A := b.buildExpr(expr.A) atyp := A.Type() if types.IsBasic(atyp, types.Bool) && (op == "&&" || op == "||") { switch op { case "&&": return buildLogicAnd(b, A, expr.B) case "||": return buildLogicOr(b, A, expr.B) } panic("unreachable") } B := b.buildExpr(expr.B) btyp := B.Type() if types.IsConst(atyp) && types.IsConst(btyp) { return binaryOpConst(b, op, A, B) } if op == ">>" || op == "<<" { ret := b.newTemp(atyp) buildShift(b, ret, A, B, op) return ret } if ok, t := types.SameBasic(atyp, btyp); ok { switch t { case types.Int, types.Int8: return binaryOpInt(b, op, A, B, t) case types.Uint, types.Uint8: return binaryOpUint(b, op, A, B, t) case types.Bool: return binaryOpBool(b, op, A, B) } panic("bug") } if types.IsNil(atyp) && types.IsNil(btyp) { return binaryOpNil(b, op, A, B) } else if types.BothPointer(atyp, btyp) { return binaryOpPtr(b, op, A, B) } else if types.BothFuncPointer(atyp, btyp) { return binaryOpPtr(b, op, A, B) } else if types.BothSlice(atyp, btyp) { return binaryOpSlice(b, op, A, B) } panic("bug") }
func buildUnaryOpExpr(b *builder, expr *ast.OpExpr) tast.Expr { opTok := expr.Op op := opTok.Lit opPos := opTok.Pos B := b.buildExpr(expr.B) if B == nil { return nil } bref := B.R() if !bref.IsSingle() { b.Errorf(opPos, "%q on %s", op, bref) return nil } btyp := bref.T if op == "&" { return refAddress(b, opTok, B) } else if types.IsConst(btyp) { return unaryOpConst(b, opTok, B) } else if types.IsInteger(btyp) { return unaryOpInt(b, opTok, B) } else if types.IsBasic(btyp, types.Bool) { return unaryOpBool(b, opTok, B) } b.Errorf(opPos, "invalid unary operator %q", op) return nil }
func buildUnaryOpExpr(b *builder, expr *tast.OpExpr) *ref { op := expr.Op.Lit B := b.buildExpr(expr.B) btyp := B.Type() if op == "&" { ret := b.newTemp(&types.Pointer{btyp}) b.b.Arith(ret.IR(), nil, op, B.IR()) return ret } else if types.IsConst(btyp) { panic("bug") } else if types.IsInteger(btyp) { return unaryOpInt(b, op, B) } else if types.IsBasic(btyp, types.Bool) { return unaryOpBool(b, op, B) } panic("bug") }
func buildConstDecl(b *builder, d *ast.ConstDecl) *tast.Define { if d.Type != nil { b.Errorf(ast.ExprPos(d.Type), "typed const not implemented yet") return nil } right := buildConstExprList(b, d.Exprs) if right == nil { return nil } nright := right.R().Len() idents := d.Idents.Idents nleft := len(idents) if nleft != nright { b.Errorf(d.Eq.Pos, "%d values for %d identifiers", nright, nleft, ) return nil } var syms []*sym8.Symbol for i, ident := range idents { t := right.R().At(i).Type() if !types.IsConst(t) { b.Errorf(ast.ExprPos(d.Exprs.Exprs[i]), "not a const") return nil } sym := declareConst(b, ident, t) if sym == nil { return nil } syms = append(syms, sym) } return &tast.Define{syms, right} }
func buildBinaryOpExpr(b *builder, expr *ast.OpExpr) tast.Expr { opTok := expr.Op op := opTok.Lit opPos := opTok.Pos A := b.buildExpr(expr.A) if A == nil { return nil } aref := A.R() if !aref.IsSingle() { b.Errorf(opPos, "%q on %s", op, aref) return nil } atyp := aref.T B := b.buildExpr(expr.B) if B == nil { return nil } bref := B.R() if !bref.IsSingle() { b.Errorf(opPos, "%q on %s", op, bref) return nil } btyp := bref.T if types.IsConst(atyp) && types.IsConst(btyp) { return binaryOpConst(b, opTok, A, B) } if op == ">>" || op == "<<" { if v, ok := types.NumConst(btyp); ok { B = constCast(b, opPos, v, B, types.Uint) if B == nil { return nil } btyp = types.Uint } if v, ok := types.NumConst(atyp); ok { A = constCast(b, opPos, v, A, types.Int) if A == nil { return nil } atyp = types.Int } if !canShift(b, atyp, btyp, opPos, op) { return nil } r := tast.NewRef(atyp) return &tast.OpExpr{A, opTok, B, r} } if v, ok := types.NumConst(atyp); ok { A = constCast(b, opPos, v, A, btyp) if A == nil { return nil } atyp = btyp } else if c, ok := atyp.(*types.Const); ok { atyp = c.Type } if v, ok := types.NumConst(btyp); ok { B = constCast(b, opPos, v, B, atyp) if B == nil { return nil } btyp = atyp } else if c, ok := btyp.(*types.Const); ok { btyp = c.Type } if ok, t := types.SameBasic(atyp, btyp); ok { switch t { case types.Int, types.Int8, types.Uint, types.Uint8: return binaryOpInt(b, opTok, A, B, t) case types.Bool: return binaryOpBool(b, opTok, A, B) case types.Float32: b.Errorf(opPos, "floating point operations not implemented") return nil } } if types.IsNil(atyp) && types.IsNil(btyp) { return binaryOpNil(b, opTok, A, B) } else if types.BothPointer(atyp, btyp) { return binaryOpPtr(b, opTok, A, B) } else if types.BothFuncPointer(atyp, btyp) { return binaryOpPtr(b, opTok, A, B) } else if types.BothSlice(atyp, btyp) { return binaryOpSlice(b, opTok, A, B) } b.Errorf(opPos, "invalid operation of %s %s %s", atyp, op, btyp) if types.IsInteger(atyp) && types.IsInteger(btyp) { switch op { case "+", "-", "*", "&", "|", "^", "%", "/", "==", "!=", ">", "<", ">=", "<=": b.Errorf( opPos, "operation %s needs the same type on both sides", op, ) } } return nil }
func (r *ref) IsConst() bool { return r.IsSingle() && types.IsConst(r.Type()) }