Example #1
0
// indexExpr generates code for array accesses (a[x], etc).
func (c *compiler) indexExpr(e *ast.IndexExpr, lv *arch.LV) *node {
	var lv2 arch.LV
	n := c.exprInternal(e.X, lv)
	lv.Type = lv.Type.Underlying()
	n = c.indirection(e, n, lv)

	m := c.exprInternal(e.Index, &lv2)
	m = c.rvalue(m, &lv2)

	record, isRecord := lv.Type.(*types.Record)
	if !isRecord && lv.Type != types.Typ[types.Char] {
		// if it is not a record, we just need to scale
		// it by the sizeof of the type
		m = newNode(opScale, nil, nil, m, nil)
	} else if isRecord {
		// if it is a struct, we use sizeof to figure
		// out the size to multiply by to get to the index
		lv2.Size = c.cg.Sizeof(record)
		m = newNode(opScaleBy, &lv2, nil, m, nil)
	}

	lv.Ident = false
	lv.Addressable = true

	return newNode(opAdd, lv, &lv2, n, m)
}
Example #2
0
// call expression generates code for calling functions (f(x), fact(1), etc).
func (c *compiler) callExpr(e *ast.CallExpr, lv *arch.LV) *node {
	c.exprInternal(e.Fun, lv)
	n := c.fnArgs(e.Args)
	if sig, ok := lv.Type.(*types.Signature); ok {
		lv.Size = len(e.Args)
		lv.Type = sig.Result().Type().Underlying()
		if !lv.Addressable {
			// regular function calls
			n = newNode(opCall, lv, nil, n, nil)
		} else {
			// function pointer calls
			n = newNode(opCalr, lv, nil, n, nil)
		}
	}
	lv.Addressable = false
	return n
}