-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.go
123 lines (104 loc) · 2.84 KB
/
script.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
package engine
// declare functionality for interpreted input scripts
import (
"github.com/mumax/3/httpfs"
"github.com/mumax/3/script"
"reflect"
)
func CompileFile(fname string) (*script.BlockStmt, error) {
bytes, err := httpfs.Read(fname)
if err != nil {
return nil, err
}
return World.Compile(string(bytes))
}
func Eval(code string) {
tree, err := World.Compile(code)
if err != nil {
LogIn(code)
LogErr(err.Error())
return
}
LogIn(rmln(tree.Format()))
tree.Eval()
}
func Eval1Line(code string) interface{} {
tree, err := World.Compile(code)
if err != nil {
LogErr(err.Error())
return nil
}
if len(tree.Children) != 1 {
LogErr("expected single statement:" + code)
return nil
}
return tree.Children[0].Eval()
}
// holds the script state (variables etc)
var World = script.NewWorld()
// Add a function to the script world
func DeclFunc(name string, f interface{}, doc string) {
World.Func(name, f, doc)
}
// Add a constant to the script world
func DeclConst(name string, value float64, doc string) {
World.Const(name, value, doc)
}
// Add a read-only variable to the script world.
// It can be changed, but not by the user.
func DeclROnly(name string, value interface{}, doc string) {
World.ROnly(name, value, doc)
GUIAdd(name, value)
}
func Export(q Quantity, doc string) {
DeclROnly(q.Name(), q, cat(doc, q.Unit()))
}
// Add a (pointer to) variable to the script world
func DeclVar(name string, value interface{}, doc string) {
World.Var(name, value, doc)
GUIAdd(name, value)
}
// Hack for fixing the closure caveat:
// Defines "t", the time variable, handled specially by Fix()
func DeclTVar(name string, value interface{}, doc string) {
World.TVar(name, value, doc)
GUIAdd(name, value)
}
// Add an LValue to the script world.
// Assign to LValue invokes SetValue()
func DeclLValue(name string, value LValue, doc string) {
World.LValue(name, newLValueWrapper(value), doc)
GUIAdd(name, value)
}
// LValue is settable
type LValue interface {
SetValue(interface{}) // assigns a new value
Eval() interface{} // evaluate and return result (nil for void)
Type() reflect.Type // type that can be assigned and will be returned by Eval
}
// evaluate code, exit on error (behavior for input files)
func EvalFile(code *script.BlockStmt) {
for i := range code.Children {
formatted := rmln(script.Format(code.Node[i]))
LogIn(formatted)
code.Children[i].Eval()
}
}
// wraps LValue and provides empty Child()
type lValueWrapper struct {
LValue
}
func newLValueWrapper(lv LValue) script.LValue {
return &lValueWrapper{lv}
}
func (w *lValueWrapper) Child() []script.Expr { return nil }
func (w *lValueWrapper) Fix() script.Expr { return script.NewConst(w) }
func (w *lValueWrapper) InputType() reflect.Type {
if i, ok := w.LValue.(interface {
InputType() reflect.Type
}); ok {
return i.InputType()
} else {
return w.Type()
}
}