forked from zjryan/e8vm
/
op.go
81 lines (73 loc) · 1.81 KB
/
op.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package g8
import (
"e8vm.io/e8vm/g8/tast"
"e8vm.io/e8vm/g8/types"
)
func buildOpExpr(b *builder, expr *tast.OpExpr) *ref {
if expr.A == nil {
return buildUnaryOpExpr(b, expr)
}
return buildBinaryOpExpr(b, expr)
}
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 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")
}