diff --git a/tools/common/wit/ast/ast.go b/tools/common/wit/ast/ast.go index 0a7b92b..75c05d7 100644 --- a/tools/common/wit/ast/ast.go +++ b/tools/common/wit/ast/ast.go @@ -70,6 +70,7 @@ type Function struct { Doc string Params []Param Results *TypeRef // nil means void / unit + Static bool // declared `name: static func(...)`; only meaningful inside a resource } // Field represents a field in a WIT record. diff --git a/tools/common/wit/ast/parser.go b/tools/common/wit/ast/parser.go index 704b4f7..1d4d447 100644 --- a/tools/common/wit/ast/parser.go +++ b/tools/common/wit/ast/parser.go @@ -413,6 +413,12 @@ func (p *Parser) parseFunction() (*Function, error) { } funcKeyword, err := p.expectIdent() + static := false + if err == nil && funcKeyword == "static" { + // WIT spells a static function `name: static func(...)`. + static = true + funcKeyword, err = p.expectIdent() + } if err != nil || funcKeyword != "func" { return nil, fmt.Errorf("expected 'func', got %q", funcKeyword) } @@ -465,6 +471,7 @@ func (p *Parser) parseFunction() (*Function, error) { Name: name, Params: params, Results: resultType, + Static: static, }, nil } @@ -680,18 +687,24 @@ func (p *Parser) parseResource() (*Resource, error) { } res.Constructor = fn case "static": + // Older, non-standard spelling: `static name: func(...)`. p.next() fn, err := p.parseFunction() if err != nil { return nil, err } + fn.Static = true res.Static = append(res.Static, *fn) default: fn, err := p.parseFunction() if err != nil { return nil, err } - res.Methods = append(res.Methods, *fn) + if fn.Static { + res.Static = append(res.Static, *fn) + } else { + res.Methods = append(res.Methods, *fn) + } } } else { p.next() diff --git a/tools/common/wit/ast/parser_test.go b/tools/common/wit/ast/parser_test.go index 374957c..27a378b 100644 --- a/tools/common/wit/ast/parser_test.go +++ b/tools/common/wit/ast/parser_test.go @@ -698,3 +698,25 @@ func TestParseFileLenient(t *testing.T) { t.Error("expected an error for a missing file") } } + +func TestParseResourceStaticFunctionSpellings(t *testing.T) { + pkg, err := ParseContent(`interface i { + resource counter { + constructor(start: u32); + get: func() -> u32; + reset-all: static func(); + static legacy-reset: func(to: u32); + } +}`) + if err != nil { + t.Fatal(err) + } + res := pkg.Interfaces[0].Resources[0] + if len(res.Methods) != 1 || res.Methods[0].Name != "get" || res.Methods[0].Static { + t.Errorf("methods = %+v", res.Methods) + } + if len(res.Static) != 2 || res.Static[0].Name != "reset-all" || !res.Static[0].Static || + res.Static[1].Name != "legacy-reset" || !res.Static[1].Static || len(res.Static[1].Params) != 1 { + t.Errorf("static = %+v", res.Static) + } +}