...
1 package gojs
2
3 import (
4 "context"
5 "fmt"
6 "math"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/gojs/config"
10 "github.com/tetratelabs/wazero/internal/gojs/goos"
11 "github.com/tetratelabs/wazero/internal/gojs/values"
12 )
13
14 func NewState(config *config.Config) *State {
15 return &State{
16 config: config,
17 values: values.NewValues(),
18 valueGlobal: newJsGlobal(config),
19 _nextCallbackTimeoutID: 1,
20 _scheduledTimeouts: map[uint32]chan bool{},
21 }
22 }
23
24
25 type StateKey struct{}
26
27 func getState(ctx context.Context) *State {
28 return ctx.Value(StateKey{}).(*State)
29 }
30
31
32 func GetLastEventArgs(ctx context.Context) []interface{} {
33 if ls := ctx.Value(StateKey{}).(*State)._lastEvent; ls != nil {
34 if args := ls.args; args != nil {
35 return args.slice
36 }
37 }
38 return nil
39 }
40
41 type event struct {
42
43 id uint32
44 this goos.Ref
45 args *objectArray
46 result interface{}
47 }
48
49
50 func (e *event) Get(propertyKey string) interface{} {
51 switch propertyKey {
52 case "id":
53 return e.id
54 case "this":
55 return e.this
56 case "args":
57 return e.args
58 }
59 panic(fmt.Sprintf("TODO: event.%s", propertyKey))
60 }
61
62 var NaN = math.NaN()
63
64
65
66
67
68 func LoadValue(ctx context.Context, ref goos.Ref) interface{} {
69 switch ref {
70 case 0:
71 return goos.Undefined
72 case goos.RefValueNaN:
73 return NaN
74 case goos.RefValueZero:
75 return float64(0)
76 case goos.RefValueNull:
77 return nil
78 case goos.RefValueTrue:
79 return true
80 case goos.RefValueFalse:
81 return false
82 case goos.RefValueGlobal:
83 return getState(ctx).valueGlobal
84 case goos.RefJsGo:
85 return getState(ctx)
86 case goos.RefObjectConstructor:
87 return objectConstructor
88 case goos.RefArrayConstructor:
89 return arrayConstructor
90 case goos.RefJsProcess:
91 return getState(ctx).valueGlobal.Get("process")
92 case goos.RefJsfs:
93 return getState(ctx).valueGlobal.Get("fs")
94 case goos.RefJsfsConstants:
95 return jsfsConstants
96 case goos.RefUint8ArrayConstructor:
97 return uint8ArrayConstructor
98 case goos.RefJsCrypto:
99 return jsCrypto
100 case goos.RefJsDateConstructor:
101 return jsDateConstructor
102 case goos.RefJsDate:
103 return jsDate
104 default:
105 if f, ok := ref.ParseFloat(); ok {
106 return f
107 }
108 return getState(ctx).values.Get(uint32(ref))
109 }
110 }
111
112
113
114
115
116
117 func storeValue(ctx context.Context, v interface{}) goos.Ref {
118
119 if v == goos.Undefined {
120 return goos.RefValueUndefined
121 } else if v == nil {
122 return goos.RefValueNull
123 } else if r, ok := v.(goos.Ref); ok {
124 return r
125 } else if b, ok := v.(bool); ok {
126 if b {
127 return goos.RefValueTrue
128 } else {
129 return goos.RefValueFalse
130 }
131 } else if c, ok := v.(*jsVal); ok {
132 return c.ref
133 } else if _, ok := v.(*event); ok {
134 id := getState(ctx).values.Increment(v)
135 return goos.ValueRef(id, goos.TypeFlagFunction)
136 } else if _, ok := v.(funcWrapper); ok {
137 id := getState(ctx).values.Increment(v)
138 return goos.ValueRef(id, goos.TypeFlagFunction)
139 } else if _, ok := v.(jsFn); ok {
140 id := getState(ctx).values.Increment(v)
141 return goos.ValueRef(id, goos.TypeFlagFunction)
142 } else if _, ok := v.(string); ok {
143 id := getState(ctx).values.Increment(v)
144 return goos.ValueRef(id, goos.TypeFlagString)
145 } else if i32, ok := v.(int32); ok {
146 return toFloatRef(float64(i32))
147 } else if u32, ok := v.(uint32); ok {
148 return toFloatRef(float64(u32))
149 } else if i64, ok := v.(int64); ok {
150 return toFloatRef(float64(i64))
151 } else if u64, ok := v.(uint64); ok {
152 return toFloatRef(float64(u64))
153 } else if f64, ok := v.(float64); ok {
154 return toFloatRef(f64)
155 }
156 id := getState(ctx).values.Increment(v)
157 return goos.ValueRef(id, goos.TypeFlagObject)
158 }
159
160 func toFloatRef(f float64) goos.Ref {
161 if f == 0 {
162 return goos.RefValueZero
163 }
164
165 return goos.Ref(api.EncodeF64(f))
166 }
167
168
169
170 type State struct {
171 config *config.Config
172 values *values.Values
173 _pendingEvent *event
174
175 _lastEvent *event
176
177 valueGlobal *jsVal
178
179 _nextCallbackTimeoutID uint32
180 _scheduledTimeouts map[uint32]chan bool
181 }
182
183
184 func (s *State) Get(propertyKey string) interface{} {
185 switch propertyKey {
186 case "_pendingEvent":
187 return s._pendingEvent
188 }
189 panic(fmt.Sprintf("TODO: state.%s", propertyKey))
190 }
191
192
193 func (s *State) call(_ context.Context, _ api.Module, _ goos.Ref, method string, args ...interface{}) (interface{}, error) {
194 switch method {
195 case "_makeFuncWrapper":
196 return funcWrapper(args[0].(float64)), nil
197 }
198 panic(fmt.Sprintf("TODO: state.%s", method))
199 }
200
201
202
203 func (s *State) close() {
204
205 for k, cancel := range s._scheduledTimeouts {
206 delete(s._scheduledTimeouts, k)
207 cancel <- true
208 }
209
210
211 s.values.Reset()
212 s._pendingEvent = nil
213 s._lastEvent = nil
214 s.valueGlobal = newJsGlobal(s.config)
215 s._nextCallbackTimeoutID = 1
216 s._scheduledTimeouts = map[uint32]chan bool{}
217 }
218
219 func toInt64(arg interface{}) int64 {
220 if arg == goos.RefValueZero || arg == goos.Undefined {
221 return 0
222 } else if u, ok := arg.(int64); ok {
223 return u
224 }
225 return int64(arg.(float64))
226 }
227
228 func toUint64(arg interface{}) uint64 {
229 if arg == goos.RefValueZero || arg == goos.Undefined {
230 return 0
231 } else if u, ok := arg.(uint64); ok {
232 return u
233 }
234 return uint64(arg.(float64))
235 }
236
237
238 func valueString(v interface{}) string {
239 if s, ok := v.(string); ok {
240 return s
241 } else {
242 return fmt.Sprintf("%v", v)
243 }
244 }
245
View as plain text