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
|