Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}
Beispiel #3
0
// 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
}
Beispiel #4
0
// 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)
}
Beispiel #5
0
// 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
}