Skip to content

Commit

Permalink
internal/go/gen, wit/bindgen: make use of identifier (Ident, ID, id) …
Browse files Browse the repository at this point in the history
…instead of Decl
  • Loading branch information
ydnar committed Feb 13, 2024
1 parent d1c0a8f commit 872e3ed
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 98 deletions.
7 changes: 0 additions & 7 deletions internal/go/gen/decl.go

This file was deleted.

12 changes: 6 additions & 6 deletions internal/go/gen/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ func (f *File) Bytes() ([]byte, error) {
return format.Source(b.Bytes())
}

// Decl adds a package-scoped declaration to f and f.Package.
// Declare adds a package-scoped identifier to [File] f.
// It additionally checks the file-scoped declarations (local package names).
// It returns the package-unique name (which may be different than name).
func (f *File) Decl(name string) Decl {
name = Unique(name, IsReserved, HasKey(f.Imports), HasKey(f.Package.Decls))
f.Package.Decls[name] = true
return Decl{
func (f *File) Declare(name string) Ident {
name = Unique(name, IsReserved, HasKey(f.Imports), HasKey(f.Package.Idents))
f.Package.Idents[name] = true
return Ident{
Package: f.Package,
Name: name,
}
Expand All @@ -95,7 +95,7 @@ func (f *File) Import(path string) string {
if f.Imports[path] != "" {
return f.Imports[path]
}
name = Unique(name, IsReserved, HasKey(f.Imports), HasKey(f.Package.Decls))
name = Unique(name, IsReserved, HasKey(f.Imports), HasKey(f.Package.Idents))
f.Imports[path] = name
return name
}
Expand Down
36 changes: 3 additions & 33 deletions internal/go/gen/ident.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,10 @@ import (
"strings"
)

// Ident represents a qualified Go identifier. It is a combination of
// a package path and a short name. For package identifiers, Path
// represents the package path (e.g. "encoding/json") and Name
// represents the short package name (e.g. "json").
// Ident represents a package-level Go declaration.
type Ident struct {
Path string
Name string
}

// ParseIdent parses string s into an [Ident].
// It returns an error if s cannot be successfully parsed
func ParseIdent(s string) (Ident, error) {
var id Ident
id.Path, id.Name, _ = strings.Cut(s, "#")
if id.Name == "" {
i := strings.LastIndex(id.Path, "/")
if i >= 0 && i < len(id.Path)-1 {
id.Name = id.Path[i+1:] // encoding/json -> json
} else {
id.Name = id.Path // encoding -> encoding
}
}
return id, nil
}

// String returns the canonical string representation of id. It implements the [fmt.Stringer] interface.
//
// The canonical string representation of an [Ident] is "$path#$name". Examples:
// - For a package: "encoding/xml#xml"
// - For a type: "encoding/xml#Attr"
// - For a constant: "encoding/xml#Header"
// - For a function: "encoding/xml#Marshal"
func (id Ident) String() string {
return id.Path + "#" + id.Name
Package *Package
Name string
}

// ParseSelector parses string s into a package path and short name.
Expand Down
48 changes: 20 additions & 28 deletions internal/go/gen/ident_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,31 @@ package gen

import "testing"

func TestParseIdent(t *testing.T) {
func TestParseSelector(t *testing.T) {
tests := []struct {
s string
want Ident
wantErr bool
s string
path string
name string
}{
{"io", Ident{"io", "io"}, false},
{"io/fs", Ident{"io/fs", "fs"}, false},
{"encoding/json", Ident{"encoding/json", "json"}, false},
{"encoding/xml", Ident{"encoding/xml", "xml"}, false},
{"encoding/xml#xml", Ident{"encoding/xml", "xml"}, false},
{"encoding/xml#encxml", Ident{"encoding/xml", "encxml"}, false},
{"encoding/xml#Encoder", Ident{"encoding/xml", "Encoder"}, false},
{"encoding/xml#Decoder", Ident{"encoding/xml", "Decoder"}, false},
{"wasi/clocks", Ident{"wasi/clocks", "clocks"}, false},
{"wasi/clocks#clocks", Ident{"wasi/clocks", "clocks"}, false},
{"wasi/clocks/wallclock", Ident{"wasi/clocks/wallclock", "wallclock"}, false},
{"wasi/clocks/wallclock#wallclock", Ident{"wasi/clocks/wallclock", "wallclock"}, false},
{"wasi/clocks/wallclock#DateTime", Ident{"wasi/clocks/wallclock", "DateTime"}, false},
{"io", "io", "io"},
{"io/fs", "io/fs", "fs"},
{"encoding/json", "encoding/json", "json"},
{"encoding/xml", "encoding/xml", "xml"},
{"encoding/xml#xml", "encoding/xml", "xml"},
{"encoding/xml#encxml", "encoding/xml", "encxml"},
{"encoding/xml#Encoder", "encoding/xml", "Encoder"},
{"encoding/xml#Decoder", "encoding/xml", "Decoder"},
{"wasi/clocks", "wasi/clocks", "clocks"},
{"wasi/clocks#clocks", "wasi/clocks", "clocks"},
{"wasi/clocks/wallclock", "wasi/clocks/wallclock", "wallclock"},
{"wasi/clocks/wallclock#wallclock", "wasi/clocks/wallclock", "wallclock"},
{"wasi/clocks/wallclock#DateTime", "wasi/clocks/wallclock", "DateTime"},
}
for _, tt := range tests {
t.Run(tt.s, func(t *testing.T) {
got, err := ParseIdent(tt.s)
if tt.wantErr && err == nil {
t.Errorf("ParseIdent(%q): expected error, got nil error", tt.s)
} else if !tt.wantErr && err != nil {
t.Errorf("ParseIdent(%q): expected no error, got error: %v", tt.s, err)
}
if err != nil {
return
}
if got != tt.want {
t.Errorf("ParseIdent(%q): %v, expected %v", tt.s, got, tt.want)
path, name := ParseSelector(tt.s)
if path != tt.path || name != tt.name {
t.Errorf("ParseSelector(%q): %q, %q; expected %q, %q", tt.s, path, name, tt.path, tt.name)
}
})
}
Expand Down
8 changes: 4 additions & 4 deletions internal/go/gen/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ type Package struct {
// Files is the list of Go source files in this package.
Files map[string]*File

// Decls represents package-scoped declarations,
// Idents represents package-scoped identifiers,
// including constants, variables, and functions.
Decls map[string]bool
Idents map[string]bool
}

// NewPackage returns a newly instantiated Package for path.
// The local name may optionally be specified with a "#name" suffix.
func NewPackage(path string) *Package {
p := &Package{
Files: make(map[string]*File),
Decls: make(map[string]bool),
Files: make(map[string]*File),
Idents: make(map[string]bool),
}
p.Path, p.Name = ParseSelector(path)
return p
Expand Down
40 changes: 20 additions & 20 deletions wit/bindgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ type generator struct {
// interfacePackages map [wit.Interface] to Go packages.
interfacePackages map[*wit.Interface]*gen.Package

// typeDecls map [wit.TypeDef] to their equivalent Go declaration.
typeDecls map[*wit.TypeDef]gen.Decl
// types map [wit.TypeDef] to their equivalent Go identifier.
types map[*wit.TypeDef]gen.Ident

// funcDecls map [wit.Function] to their equivalent Go declaration.
funcDecls map[*wit.Function]gen.Decl
// funcs map [wit.Function] to their equivalent Go identifier.
funcs map[*wit.Function]gen.Ident

// defined represent whether a type or function has been defined.
defined map[gen.Decl]bool
defined map[gen.Ident]bool
}

func newGenerator(res *wit.Resolve, opts ...Option) (*generator, error) {
Expand All @@ -71,9 +71,9 @@ func newGenerator(res *wit.Resolve, opts ...Option) (*generator, error) {
witPackages: make(map[string]*gen.Package),
worldPackages: make(map[*wit.World]*gen.Package),
interfacePackages: make(map[*wit.Interface]*gen.Package),
typeDecls: make(map[*wit.TypeDef]gen.Decl),
funcDecls: make(map[*wit.Function]gen.Decl),
defined: make(map[gen.Decl]bool),
types: make(map[*wit.TypeDef]gen.Ident),
funcs: make(map[*wit.Function]gen.Ident),
defined: make(map[gen.Ident]bool),
}
err := g.opts.apply(opts...)
if err != nil {
Expand Down Expand Up @@ -169,8 +169,8 @@ func (g *generator) declareTypeDef(t *wit.TypeDef) error {

pkg := g.packageForIdent(ownerID)
file := pkg.File(ownerID.Extension + GoSuffix)
decl := file.Decl(GoName(name))
g.typeDecls[t] = decl
id := file.Declare(GoName(name))
g.types[t] = id

// fmt.Fprintf(os.Stderr, "Type:\t%s.%s\n\t%s.%s\n", ownerID.String(), name, decl.Package.Path, decl.Name)

Expand Down Expand Up @@ -275,11 +275,11 @@ func (g *generator) defineTypeDef(t *wit.TypeDef, name string) error {
name = *t.Name
}

decl := g.typeDecls[t]
if decl == (gen.Decl{}) {
id := g.types[t]
if id == (gen.Ident{}) {
return fmt.Errorf("typedef %s not declared", name)
}
if g.defined[decl] {
if g.defined[id] {
return nil
}
// TODO: should we emit data for aliases?
Expand All @@ -297,17 +297,17 @@ func (g *generator) defineTypeDef(t *wit.TypeDef, name string) error {
ownerID.Extension = *owner.Name // FIXME: this might panic
}

pkg := decl.Package
pkg := id.Package
file := pkg.File(ownerID.Extension + GoSuffix)

fmt.Fprintf(file, "// %s represents the %s \"%s#%s\".\n", decl.Name, t.WITKind(), ownerID.String(), name)
fmt.Fprintf(file, "// %s represents the %s \"%s#%s\".\n", id.Name, t.WITKind(), ownerID.String(), name)
fmt.Fprintf(file, "//\n")
fmt.Fprint(file, gen.FormatDocComments(t.WIT(nil, "")))
fmt.Fprintf(file, "//\n")
if t.Docs.Contents != "" {
fmt.Fprintf(file, "//\n%s", gen.FormatDocComments(t.Docs.Contents))
}
fmt.Fprintf(file, "type %s ", decl.Name)
fmt.Fprintf(file, "type %s ", id.Name)
fmt.Fprint(file, g.typeDefExpr(file, t))
fmt.Fprint(file, "\n\n")

Expand Down Expand Up @@ -426,16 +426,16 @@ func (g *generator) defineImportedFunction(f *wit.Function, ownerID wit.Ident) e
if !f.IsFreestanding() {
return nil
}
if _, ok := g.funcDecls[f]; ok {
if _, ok := g.funcs[f]; ok {
return nil
}

pkg := g.packageForIdent(ownerID)
file := pkg.File(ownerID.Extension + GoSuffix)

funcDecl := file.Decl(GoName(f.Name))
g.funcDecls[f] = funcDecl
snakeDecl := file.Decl(SnakeName(f.Name))
funcDecl := file.Declare(GoName(f.Name))
g.funcs[f] = funcDecl
snakeDecl := file.Declare(SnakeName(f.Name))

fmt.Fprintf(file, "// %s represents the %s \"%s#%s\".\n", funcDecl.Name, f.WITKind(), ownerID.String(), f.Name)
if f.Docs.Contents != "" {
Expand Down

0 comments on commit 872e3ed

Please sign in to comment.