forked from mumax/3
/
typeconv.go
140 lines (117 loc) · 4.44 KB
/
typeconv.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package script
import (
"fmt"
"github.com/mumax/3/data"
"go/token"
"reflect"
)
// converts in to an expression of type OutT.
// also serves as type check (not convertible == type error)
// pos is used for error message on impossible conversion.
func typeConv(pos token.Pos, in Expr, outT reflect.Type) Expr {
inT := in.Type()
switch {
default:
panic(err(pos, "type mismatch: can not use type", inT, "as", outT))
// treat 'void' (type nil) separately:
case inT == nil && outT != nil:
panic(err(pos, "void used as value"))
case inT != nil && outT == nil:
panic("script internal bug: void input type")
// strict go conversions:
case inT == outT:
return in
case inT.AssignableTo(outT):
return in
// extra conversions for ease-of-use:
// int -> float64
case outT == float64_t && inT == int_t:
return &intToFloat64{in}
// float64 -> int
case outT == int_t && inT == float64_t:
return &float64ToInt{in}
case outT == float64_t && inT.AssignableTo(ScalarIf_t):
return &getScalar{in.Eval().(ScalarIf)}
case outT == float64_t && inT.AssignableTo(VectorIf_t):
return &getVector{in.Eval().(VectorIf)}
// magical expression -> function conversions
case inT == float64_t && outT.AssignableTo(ScalarFunction_t):
return &scalFn{in}
case inT == int_t && outT.AssignableTo(ScalarFunction_t):
return &scalFn{&intToFloat64{in}}
case inT == vector_t && outT.AssignableTo(VectorFunction_t):
return &vecFn{in}
case inT == bool_t && outT == func_bool_t:
return &boolToFunc{in}
}
}
// returns input type for expression. Usually this is the same as the return type,
// unless the expression has a method InputType()reflect.Type.
func inputType(e Expr) reflect.Type {
if in, ok := e.(interface {
InputType() reflect.Type
}); ok {
return in.InputType()
}
return e.Type()
}
// common type definitions
var (
float64_t = reflect.TypeOf(float64(0))
bool_t = reflect.TypeOf(false)
func_float64_t = reflect.TypeOf(func() float64 { panic(0) })
func_bool_t = reflect.TypeOf(func() bool { panic(0) })
int_t = reflect.TypeOf(int(0))
string_t = reflect.TypeOf("")
vector_t = reflect.TypeOf(data.Vector{})
func_vector_t = reflect.TypeOf(func() data.Vector { panic(0) })
ScalarFunction_t = reflect.TypeOf(dummy_f).In(0)
VectorFunction_t = reflect.TypeOf(dummy_f3).In(0)
ScalarIf_t = reflect.TypeOf(dummy_scalarif).In(0)
VectorIf_t = reflect.TypeOf(dummy_vectorif).In(0)
)
// maneuvers to get interface type of Func (simpler way?)
func dummy_f(ScalarFunction) {}
func dummy_f3(VectorFunction) {}
func dummy_scalarif(ScalarIf) {}
func dummy_vectorif(VectorIf) {}
// converts int to float64
type intToFloat64 struct{ in Expr }
func (c *intToFloat64) Eval() interface{} { return float64(c.in.Eval().(int)) }
func (c *intToFloat64) Type() reflect.Type { return float64_t }
func (c *intToFloat64) Child() []Expr { return []Expr{c.in} }
func (c *intToFloat64) Fix() Expr { return &intToFloat64{in: c.in.Fix()} }
// converts float64 to int
type float64ToInt struct{ in Expr }
func (c *float64ToInt) Eval() interface{} { return safe_int(c.in.Eval().(float64)) }
func (c *float64ToInt) Type() reflect.Type { return int_t }
func (c *float64ToInt) Child() []Expr { return []Expr{c.in} }
func (c *float64ToInt) Fix() Expr { return &float64ToInt{in: c.in.Fix()} }
type boolToFunc struct{ in Expr }
func (c *boolToFunc) Eval() interface{} { return func() bool { return c.in.Eval().(bool) } }
func (c *boolToFunc) Type() reflect.Type { return func_bool_t }
func (c *boolToFunc) Child() []Expr { return []Expr{c.in} }
func (c *boolToFunc) Fix() Expr { return &boolToFunc{in: c.in.Fix()} }
type getScalar struct{ in ScalarIf }
type getVector struct{ in VectorIf }
func (c *getScalar) Eval() interface{} { return c.in.Get() }
func (c *getScalar) Type() reflect.Type { return float64_t }
func (c *getScalar) Child() []Expr { return nil }
func (c *getScalar) Fix() Expr { return NewConst(c) }
func (c *getVector) Eval() interface{} { return c.in.Get() }
func (c *getVector) Type() reflect.Type { return vector_t }
func (c *getVector) Child() []Expr { return nil }
func (c *getVector) Fix() Expr { return NewConst(c) }
func safe_int(x float64) int {
i := int(x)
if float64(i) != x {
panic(fmt.Errorf("can not use %v as int", x))
}
return i
}
type ScalarIf interface {
Get() float64
} // TODO: Scalar
type VectorIf interface {
Get() data.Vector
} // TODO: Vector