File: script.go

package info (click to toggle)
mumax3 3.11.1-1
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 10,668 kB
  • sloc: makefile: 194; ansic: 155; sh: 86; javascript: 16
file content (126 lines) | stat: -rw-r--r-- 2,943 bytes parent folder | download | duplicates (3)
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()
	}
}