Ejemplo n.º 1
0
func buildCast(b *builder, expr *ast.CallExpr, t types.T) tast.Expr {
	pos := expr.Lparen.Pos

	args := buildExprList(b, expr.Args)
	if args == nil {
		return nil
	}

	ref := args.R()
	if !ref.IsSingle() {
		b.Errorf(pos, "cannot convert %s to %s", ref, t)
		return nil
	}

	srcType := ref.T
	if c, ok := srcType.(*types.Const); ok {
		if v, ok := types.NumConst(srcType); ok && types.IsInteger(t) {
			return constCast(b, pos, v, args, t)
		}
		srcType = c.Type // using the underlying type
	}

	if types.IsInteger(t) && types.IsInteger(srcType) {
		return tast.NewCast(args, t)
	}
	if regSizeCastable(t, srcType) {
		return tast.NewCast(args, t)
	}

	b.Errorf(pos, "cannot convert from %s to %s", srcType, t)
	return nil
}
Ejemplo n.º 2
0
func canShift(b *builder, atyp, btyp types.T, pos *lex8.Pos, op string) bool {
	if !types.IsInteger(atyp) {
		b.Errorf(pos, "%q on %s", op, atyp)
		return false
	} else if !types.IsInteger(btyp) {
		b.Errorf(pos, "%q with %s", op, btyp)
		return false
	} else if !types.IsUnsigned(btyp) {
		b.Errorf(pos, "%q with %s; must be unsigned", op, btyp)
		return false
	}
	return true
}
Ejemplo n.º 3
0
Archivo: op.go Proyecto: 272489711/e8vm
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
}
Ejemplo n.º 4
0
func buildIncStmt(b *builder, stmt *ast.IncStmt) tast.Stmt {
	op := stmt.Op.Lit
	expr := b.buildExpr(stmt.Expr)
	if expr == nil {
		return nil
	}

	ref := expr.R()
	if !ref.IsSingle() {
		b.Errorf(stmt.Op.Pos, "%s on expression list", op)
		return nil
	}

	t := ref.Type()
	if !types.IsInteger(t) {
		b.Errorf(stmt.Op.Pos, "%s on %s", op, t)
		return nil
	}

	if !ref.Addressable {
		b.Errorf(stmt.Op.Pos, "%s on non-addressable", op)
		return nil
	}

	switch stmt.Op.Lit {
	case "++", "--":
		return &tast.IncStmt{expr, stmt.Op}
	default:
		b.Errorf(stmt.Op.Pos, "invalid inc op %s", op)
		return nil
	}
}
Ejemplo n.º 5
0
func constCast(
	b *builder, pos *lex8.Pos, v int64, from tast.Expr, to types.T,
) tast.Expr {
	if types.IsInteger(to) && types.InRange(v, to) {
		return tast.NewCast(from, to)
	}
	b.Errorf(pos, "cannot cast %d to %s", v, to)
	return nil
}
Ejemplo n.º 6
0
func checkArrayIndex(b *builder, index tast.Expr, pos *lex8.Pos) tast.Expr {
	t := index.R().T
	if v, ok := types.NumConst(t); ok {
		if v < 0 {
			b.Errorf(pos, "array index is negative: %d", v)
			return nil
		}
		return constCastInt(b, pos, v, index)
	}
	if !types.IsInteger(t) {
		b.Errorf(pos, "index must be an integer")
		return nil
	}
	return index
}
Ejemplo n.º 7
0
func buildCast(b *builder, from *ref, t types.T) *ref {
	srcType := from.Type()
	ret := b.newTemp(t)

	if types.IsNil(srcType) {
		size := t.Size()
		if size == arch8.RegSize {
			return newRef(t, ir.Num(0))
		}
		if _, ok := t.(*types.Slice); !ok {
			panic("bug")
		}
		ret := b.newTemp(t)
		b.b.Zero(ret.IR())
		return ret
	}

	if c, ok := srcType.(*types.Const); ok {
		if v, ok := types.NumConst(srcType); ok && types.IsInteger(t) {
			return newRef(t, constNumIr(v, t))
		}
		// TODO: we do not support typed const right?
		// so why need this line?
		srcType = c.Type // using the underlying type
	}

	if types.IsInteger(t) && types.IsInteger(srcType) {
		b.b.Arith(ret.IR(), nil, "cast", from.IR())
		return ret
	}
	if regSizeCastable(t, srcType) {
		b.b.Arith(ret.IR(), nil, "", from.IR())
		return ret
	}
	panic("bug")
}
Ejemplo n.º 8
0
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")
}
Ejemplo n.º 9
0
Archivo: op.go Proyecto: 272489711/e8vm
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
}
Ejemplo n.º 10
0
func buildArrayLit(b *builder, lit *ast.ArrayLiteral) tast.Expr {
	hold := b.lhsSwap(false)
	defer b.lhsRestore(hold)

	if lit.Type.Len != nil {
		b.Errorf(
			ast.ExprPos(lit),
			"array literal with length not supported yet",
		)
		return nil
	}

	buf := new(bytes.Buffer)
	t := buildType(b, lit.Type.Type)
	if t == nil {
		return nil
	}

	if !types.IsInteger(t) {
		pos := ast.ExprPos(lit.Type.Type)
		b.Errorf(pos, "array literal must be integer type")
		return nil
	}
	bt := t.(types.Basic)

	if lit.Exprs != nil {
		for _, expr := range lit.Exprs.Exprs {
			n := b.buildConstExpr(expr)
			if n == nil {
				return nil
			}
			ntype := n.R().T
			if _, ok := ntype.(*types.Const); !ok {
				b.Errorf(ast.ExprPos(expr), "array literal not a constant")
				return nil
			}

			if v, ok := types.NumConst(ntype); ok {
				if !types.InRange(v, t) {
					b.Errorf(
						ast.ExprPos(expr),
						"constant out of range of %s",
						t,
					)
					return nil
				}

				switch bt {
				case types.Int, types.Uint:
					var bs [4]byte
					binary.LittleEndian.PutUint32(bs[:], uint32(v))
					buf.Write(bs[:])
				case types.Int8, types.Uint8:
					buf.Write([]byte{byte(v)})
				default:
					panic("not integer")
				}
			}
		}
	}

	ref := tast.NewConstRef(&types.Slice{bt}, buf.Bytes())
	return &tast.Const{ref}
}