-
Notifications
You must be signed in to change notification settings - Fork 0
/
runtimeAction.go
132 lines (115 loc) · 3.48 KB
/
runtimeAction.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
package internal
import (
"fmt"
G "github.com/ionous/sashimi/game"
"github.com/ionous/sashimi/meta"
"github.com/ionous/sashimi/util/ident"
"github.com/ionous/sashimi/util/lang"
"strings"
)
var _ = fmt.Println
// RuntimeAction contains data for event handlers and actions.
type RuntimeAction struct {
action meta.Action
objs []meta.Instance
after []QueuedCallback // FIX: WHY DO WE COPY THIS!?!
cancelled bool
}
func NewRuntimeAction(act meta.Action, objects []meta.Instance) *RuntimeAction {
return &RuntimeAction{action: act, objs: objects}
}
func (act *RuntimeAction) GetTarget() (ret meta.Instance) {
if len(act.objs) > 0 {
ret = act.objs[0]
}
return
}
func (act *RuntimeAction) GetContext() (ret meta.Instance) {
if len(act.objs) > 1 {
ret = act.objs[1]
}
return
}
// each action can have a chain of default actions
type QueuedCallback struct {
src ident.Id
call G.Callback
}
// FIX: change callbacks to include a source file/line location
func (q QueuedCallback) String() string {
return fmt.Sprint(q.call)
}
func (act *RuntimeAction) Cancelled() bool {
return act.cancelled
}
// queue for running after the default actions
func (act *RuntimeAction) runAfterDefaults(cb QueuedCallback) {
act.after = append(act.after, cb)
}
// findByName:
func (act *RuntimeAction) findByName(m meta.Model, name string, hint ident.Id) (ret meta.Instance, okay bool) {
if obj, ok := act.findByParamName(name); ok {
okay, ret = true, obj
} else if obj, ok := act.findByClassName(m, name, hint); ok {
okay, ret = true, obj
}
return
}
// findByParamName: source, target, or context
func (act *RuntimeAction) findByParamName(name string) (ret meta.Instance, okay bool) {
for index, src := range []string{"action.Source", "action.Target", "action.Context"} {
if strings.EqualFold(name, src) {
ret, okay = act.getObject(index)
break
}
}
return
}
// findByClassName:
func (act *RuntimeAction) findByClassName(m meta.Model, name string, hint ident.Id) (ret meta.Instance, okay bool) {
clsid := MakeStringId(m.Pluralize(lang.StripArticle(name)))
if clsid == hint {
ret, okay = act.getObject(0)
} else {
ret, okay = act.findByClass(m, clsid)
}
return
}
// findByExactClass; true if found
func (act *RuntimeAction) findByClass(m meta.Model, id ident.Id) (ret meta.Instance, okay bool) {
// these are the classes originally named in the action declaration; not the sub-classes of the event target. ie. s.The("actors", Can("crawl"), not s.The("babies", When("crawling")
if obj, ok := act.findByExactClass(m, id); ok {
ret, okay = obj, true
} else {
// when all else fails try compatible classes one by one.
ret, okay = act.findBySimilarClass(m, id)
}
return ret, okay
}
// findByExactClass; true if found
func (act *RuntimeAction) findByExactClass(_ meta.Model, id ident.Id) (ret meta.Instance, okay bool) {
for i, nounClass := range act.action.GetNouns() {
if same := id == nounClass; same {
ret, okay = act.getObject(i)
break
}
}
return
}
// findBySimilarClass; true if found
func (act *RuntimeAction) findBySimilarClass(m meta.Model, id ident.Id) (ret meta.Instance, okay bool) {
for i, nounClass := range act.action.GetNouns() {
if similar := m.AreCompatible(id, nounClass); similar {
ret, okay = act.getObject(i)
break
}
}
return
}
// getObject returns the index object; true if the index was in range.
func (act *RuntimeAction) getObject(i int) (ret meta.Instance, okay bool) {
if i >= 0 && i < len(act.objs) {
ret, okay = act.objs[i], true
}
return
}