1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package wasm
16
17 import (
18 "path/filepath"
19 "strings"
20 "sync"
21
22 "cuelang.org/go/cue/build"
23 "cuelang.org/go/cue/cuecontext"
24 "cuelang.org/go/cue/errors"
25 "cuelang.org/go/cue/token"
26 "cuelang.org/go/internal"
27 "cuelang.org/go/internal/core/adt"
28 coreruntime "cuelang.org/go/internal/core/runtime"
29 )
30
31
32 type interpreter struct{}
33
34
35
36 func New() cuecontext.ExternInterpreter {
37 return &interpreter{}
38 }
39
40 func (i *interpreter) Kind() string {
41 return "wasm"
42 }
43
44
45
46 func (i *interpreter) NewCompiler(b *build.Instance, r *coreruntime.Runtime) (coreruntime.Compiler, errors.Error) {
47 return &compiler{
48 b: b,
49 runtime: r,
50 wasmRuntime: newRuntime(),
51 instances: make(map[string]*instance),
52 }, nil
53 }
54
55
56
57 type compiler struct {
58 b *build.Instance
59 runtime *coreruntime.Runtime
60 wasmRuntime runtime
61
62
63 mu sync.Mutex
64
65
66
67 instances map[string]*instance
68 }
69
70
71
72
73 func (c *compiler) Compile(funcName string, scope adt.Value, a *internal.Attr) (adt.Expr, errors.Error) {
74 file, err := fileName(a)
75 if err != nil {
76 return nil, errors.Promote(err, "invalid attribute")
77 }
78
79
80 if !strings.HasSuffix(file, "wasm") {
81 return nil, errors.Newf(token.NoPos, "load %q: invalid file name", file)
82 }
83
84 file, found := findFile(file, c.b)
85 if !found {
86 return nil, errors.Newf(token.NoPos, "load %q: file not found", file)
87 }
88
89 inst, err := c.instance(file)
90 if err != nil {
91 return nil, errors.Newf(token.NoPos, "can't load Wasm module: %v", err)
92 }
93
94 args, err := argList(a)
95 if err != nil {
96 return nil, errors.Newf(token.NoPos, "invalid function signature: %v", err)
97 }
98 builtin, err := generateCallThatReturnsBuiltin(funcName, scope, args, inst)
99 if err != nil {
100 return nil, errors.Newf(token.NoPos, "can't instantiate function: %v", err)
101 }
102 return builtin, nil
103 }
104
105
106
107 func (c *compiler) instance(filename string) (inst *instance, err error) {
108 c.mu.Lock()
109 defer c.mu.Unlock()
110 inst, ok := c.instances[filename]
111 if !ok {
112 inst, err = c.wasmRuntime.compileAndLoad(filename)
113 if err != nil {
114 return nil, err
115 }
116 c.instances[filename] = inst
117 }
118 return inst, nil
119 }
120
121
122
123
124 func findFile(name string, b *build.Instance) (path string, found bool) {
125 for _, f := range b.UnknownFiles {
126 if f.Filename == name {
127 return filepath.Join(b.Dir, name), true
128 }
129 }
130 return name, false
131 }
132
133
134
135 func fileName(a *internal.Attr) (string, error) {
136 file, err := a.String(0)
137 if err != nil {
138 return "", err
139 }
140 return file, nil
141 }
142
View as plain text