Skip to content

Commit b3e14af

Browse files
committed
poc wasifill
Signed-off-by: Jordan Rash <[email protected]>
1 parent 6c554d6 commit b3e14af

File tree

8 files changed

+346
-2
lines changed

8 files changed

+346
-2
lines changed

cmd/core.wit cmd/simple/core.wit

File renamed without changes.

cmd/main.go cmd/simple/main.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ func main() {
5252
}
5353
fmt.Println("\t", tC.Name.TokenLiteral(), tC.Value.TokenLiteral())
5454

55+
case "func":
56+
tC, ok := c.(*ast.FuncShape)
57+
if !ok {
58+
// error
59+
}
60+
fmt.Println("\t", tC.TokenLiteral(), tC.Value.TokenLiteral())
5561
case "use":
5662
tC, ok := c.(*ast.UseShape)
5763
if !ok {
@@ -94,7 +100,7 @@ func parseWit(done chan *ast.AST) {
94100
panic(err)
95101
}
96102

97-
fmt.Printf("Parsing the following file:\n\n```\n%s\n```\n\n", string(b))
103+
fmt.Printf("Parsing the following file:\n\n```wit\n%s\n```\n\n", string(b))
98104

99105
p := parser.New(lexer.NewLexer(string(b)))
100106
t := p.Parse()
File renamed without changes.

cmd/wasifill/main.go

+218
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
"text/template"
8+
9+
"github.com/jordan-rash/go-wit/ast"
10+
"github.com/jordan-rash/go-wit/lexer"
11+
"github.com/jordan-rash/go-wit/parser"
12+
13+
_ "embed"
14+
)
15+
16+
//go:embed "rpc.tmpl"
17+
var rpc string
18+
19+
const witfile string = `package jordan-rash:[email protected]
20+
21+
interface types {
22+
type pong = string
23+
}
24+
25+
interface pingpong {
26+
use types.{pong}
27+
ping: func() -> pong
28+
}
29+
30+
world ping-pong {
31+
export pingpong
32+
}
33+
`
34+
35+
type wasifill struct {
36+
PackageNamespace string
37+
PackageContract string
38+
Version string
39+
Types []wftype
40+
Funcs []wffunc
41+
Exports []wfexports
42+
}
43+
44+
type wftype struct {
45+
Interface string
46+
Name string
47+
Type string
48+
}
49+
50+
type wffunc struct {
51+
Interface string
52+
Name string
53+
Input string
54+
Output string
55+
}
56+
57+
func (w wffunc) PubName() string {
58+
return strings.Title(w.Name)
59+
}
60+
61+
func (w wffunc) PubOutput() string {
62+
return strings.Title(w.Output)
63+
}
64+
65+
func (w wftype) PubName() string {
66+
return strings.Title(w.Name)
67+
}
68+
69+
func (w wfexports) PubName() string {
70+
return strings.Title(w.Name)
71+
}
72+
73+
func (w wasifill) PubName() string {
74+
return strings.Title(w.PackageContract)
75+
}
76+
77+
type wfexports struct {
78+
Type string
79+
Name string
80+
}
81+
82+
func main() {
83+
p := parser.New(lexer.NewLexer(witfile))
84+
t := p.Parse()
85+
86+
if p.Errors() != nil {
87+
fmt.Printf("parser errors: %s", p.Errors().Error())
88+
return
89+
}
90+
91+
wf := new(wasifill)
92+
93+
for _, s := range t.Shapes {
94+
switch s.TokenLiteral() {
95+
case "package":
96+
tS, ok := s.(*ast.PackageShape)
97+
if !ok {
98+
fmt.Println("package error")
99+
return
100+
}
101+
102+
wf.PackageNamespace = strings.Split(tS.Value, ":")[0]
103+
wf.PackageContract = strings.Split(tS.Value, ":")[1]
104+
wf.Version = tS.Version
105+
case "interface":
106+
tS, ok := s.(*ast.InterfaceShape)
107+
if !ok {
108+
fmt.Println("interface error")
109+
return
110+
}
111+
for _, c := range tS.Children {
112+
switch c.TokenLiteral() {
113+
case "type":
114+
tC, ok := c.(*ast.TypeStatement)
115+
if !ok {
116+
fmt.Println("interface type error")
117+
return
118+
}
119+
120+
tT := wftype{
121+
Interface: tS.Name.Value,
122+
Name: tC.Name.TokenLiteral(),
123+
Type: tC.Value.TokenLiteral(),
124+
}
125+
126+
wf.Types = append(wf.Types, tT)
127+
case "func":
128+
tC, ok := c.(*ast.FuncShape)
129+
if !ok {
130+
fmt.Println("interface use error")
131+
return
132+
}
133+
134+
tF := wffunc{
135+
Interface: tS.Name.Value,
136+
Name: tC.Name.TokenLiteral(),
137+
Input: "",
138+
Output: tC.Value.TokenLiteral(),
139+
}
140+
141+
wf.Funcs = append(wf.Funcs, tF)
142+
case "use":
143+
_, ok := c.(*ast.UseShape)
144+
if !ok {
145+
fmt.Println("interface use error")
146+
return
147+
}
148+
// fmt.Println("\t", tC.TokenLiteral(), tC.Value.TokenLiteral())
149+
default:
150+
fmt.Printf("interface child error: %T\n", c)
151+
return
152+
}
153+
}
154+
155+
case "world":
156+
tS, ok := s.(*ast.WorldShape)
157+
if !ok {
158+
fmt.Println("world error")
159+
return
160+
}
161+
for _, c := range tS.Children {
162+
switch c.TokenLiteral() {
163+
case "export":
164+
tC, ok := c.(*ast.ExportShape)
165+
if !ok {
166+
fmt.Println("interface use error")
167+
return
168+
}
169+
tE := wfexports{
170+
Type: "function",
171+
Name: tC.Value.TokenLiteral(),
172+
}
173+
wf.Exports = append(wf.Exports, tE)
174+
}
175+
}
176+
177+
default:
178+
fmt.Println("error: invalid root token")
179+
return
180+
}
181+
182+
}
183+
184+
err := generateFiles(wf)
185+
if err != nil {
186+
fmt.Println(err.Error())
187+
return
188+
}
189+
}
190+
191+
func generateFiles(wf *wasifill) error {
192+
_, err := os.Stat("gen")
193+
if os.IsNotExist(err) {
194+
if err := os.Mkdir("gen", os.ModePerm); err != nil {
195+
return err
196+
}
197+
} else if err != nil {
198+
return err
199+
}
200+
201+
tmpl, err := template.New("rpc.tmpl").Parse(rpc)
202+
if err != nil {
203+
panic(err)
204+
}
205+
206+
f, err := os.Create("./gen/gen.go")
207+
if err != nil {
208+
return err
209+
}
210+
defer f.Close()
211+
212+
err = tmpl.Execute(f, wf)
213+
if err != nil {
214+
panic(err)
215+
}
216+
217+
return nil
218+
}

cmd/wasifill/rpc.tmpl

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package {{ .PackageContract }}
2+
3+
import (
4+
actor "github.com/wasmCloud/actor-tinygo"
5+
msgpack "github.com/wasmcloud/tinygo-msgpack"
6+
)
7+
8+
{{ range .Types }}
9+
type {{ .PubName }} {{ .Type }}
10+
{{ end }}
11+
12+
{{- range $e := .Exports }}
13+
{{- if (eq $e.Type "function") }}
14+
{{- range $f := $.Funcs -}}
15+
{{- if (eq $f.Interface $e.Name) }}
16+
type {{ $e.Name }} interface {
17+
{{ $f.PubName }}(ctx *actor.Context{{ $f.Input }}) {{ $f.PubOutput }}
18+
}
19+
{{- end -}}
20+
{{- end -}}
21+
{{- end -}}
22+
{{- end }}
23+
24+
{{ range .Types }}
25+
func (o *{{ .PubName }}) MEncode(encoder msgpack.Writer) error {
26+
encoder.WriteString(string(*o))
27+
return encoder.CheckError()
28+
}
29+
30+
func MDecode{{ .PubName }}(d *msgpack.Decoder) ({{ .PubName }}, error) {
31+
val, err := d.ReadString()
32+
if err != nil {
33+
return "", err
34+
}
35+
36+
return {{ .PubName }}(val), nil
37+
}
38+
{{ end }}
39+
40+
{{ range $e := .Exports }}
41+
type {{$.PubName}}Sender struct { transport actor.Transport }
42+
type {{$.PubName}}Receiver struct {}
43+
44+
func NewProvider{{$.PubName}}() *{{$.PubName}}Sender {
45+
transport := actor.ToProvider("{{$.PackageNamespace}}:{{$.PackageContract}}", "default")
46+
return &{{$.PubName}}Sender{transport: transport}
47+
}
48+
49+
func {{$.PubName}}Handler(a {{ .Name }}) actor.Handler {
50+
return actor.NewHandler("{{$.PubName}}", &{{$.PubName}}Receiver{}, a)
51+
}
52+
53+
func (r *{{$.PubName}}Receiver) Dispatch(ctx *actor.Context, svc interface{}, message *actor.Message) (*actor.Message, error) {
54+
switch message.Method {
55+
{{- range $f := $.Funcs }}
56+
{{- if eq $e.Name .Interface }}
57+
case "{{.PubName}}":
58+
{
59+
var sizer msgpack.Sizer
60+
size_enc := &sizer
61+
size_enc.WriteString(string(message.Arg))
62+
buf := make([]byte, sizer.Len())
63+
encoder := msgpack.NewEncoder(buf)
64+
enc := &encoder
65+
enc.WriteString(string(message.Arg))
66+
return &actor.Message{Method: "{{$.PubName}}.{{.PubName}}", Arg: buf}, nil
67+
}
68+
{{- end }}
69+
{{- end }}
70+
default:
71+
return nil, actor.NewRpcError("MethodNotHandled", "{{$.PubName}}."+message.Method)
72+
}
73+
}
74+
{{ end }}

parser/parser.go

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Parser struct {
2424
errors error
2525
}
2626

27+
// TODO: change input to string and create lexer
2728
func New(l *lexer.Lexer) *Parser {
2829
p := &Parser{lexer: l}
2930

parser/parser_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ var (
106106
{"package wasi:derp", "wasi:derp", ""},
107107
{"package wasi:[email protected]", "wasi:derp", "0.1.0"},
108108
}
109+
funcTests = []struct {
110+
Input string
111+
name string
112+
expectedReturnType string
113+
}{
114+
{"derp: func() -> string", "derp", token.KEYWORD_STRING},
115+
{"derp: func() -> foo", "derp", token.IDENTIFIER},
116+
}
109117
)
110118

111119
func TestParsePingPong(t *testing.T) {
@@ -183,6 +191,21 @@ func TestNestedInterfaceShapes(t *testing.T) {
183191
assert.NotNil(t, tree)
184192
assert.Len(t, tree.Shapes, 1)
185193
}
194+
195+
for _, tt := range funcTests {
196+
sb := strings.Builder{}
197+
err = tmpl.Execute(&sb, tt)
198+
assert.NoError(t, err)
199+
200+
p := New(lexer.NewLexer(sb.String()))
201+
202+
tree := p.Parse()
203+
assert.NotNil(t, tree)
204+
assert.NoError(t, p.Errors())
205+
206+
assert.NotNil(t, tree)
207+
assert.Len(t, tree.Shapes, 1)
208+
}
186209
}
187210

188211
func TestNestedWorldShapes(t *testing.T) {
@@ -342,3 +365,24 @@ func TestExportShape(t *testing.T) {
342365
}
343366
}
344367
}
368+
369+
func TestFuncShape(t *testing.T) {
370+
for i, tt := range funcTests {
371+
p := Parser{lexer: lexer.NewLexer(tt.Input)}
372+
p.nextToken()
373+
374+
for p.peekToken.Type != token.END_OF_FILE {
375+
tempType := p.parseFuncLine()
376+
assert.NoError(t, p.Errors())
377+
378+
assert.Equal(t, tt.name, tempType.Name.Value, i)
379+
switch tT := tempType.Value.(type) {
380+
case *ast.Identifier:
381+
assert.Equal(t, tt.expectedReturnType, string(tT.Token.Type), i)
382+
case *ast.Child:
383+
assert.Equal(t, tt.expectedReturnType, string(tT.Token.Type), i)
384+
}
385+
386+
}
387+
}
388+
}

0 commit comments

Comments
 (0)