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
|
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 interface {
Name() string
Unit() string
}, 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()
}
}
|