Skip to content

Commit

Permalink
Merge pull request #149 from jmattheis/variables-v4
Browse files Browse the repository at this point in the history
Add input/output formats
  • Loading branch information
jmattheis authored Jun 23, 2024
2 parents 4f99aca + b8d3708 commit 595aa02
Show file tree
Hide file tree
Showing 191 changed files with 1,507 additions and 231 deletions.
2 changes: 1 addition & 1 deletion builder/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ func mapField(
OutputPackagePath: ctx.OutputPackagePath,
ErrorPrefix: "Error parsing struct method",
Params: method.ParamsNone,
CustomCall: nextIDCode,
})
if err != nil {
return nil, nil, nil, nil, false, NewError(err.Error()).Lift(lift...)
}
def.Call = nextIDCode

methodCallInner, callID, callErr := gen.CallMethod(ctx, def, nil, nil, def.Target, errPath)
if callErr != nil {
Expand Down
121 changes: 81 additions & 40 deletions comments/parse_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
prefix = "goverter"
delimter = ":"
converterMarker = prefix + delimter + "converter"
variablesMarker = prefix + delimter + "variables"
)

// ParseDocsConfig provides input to the ParseDocs method below.
Expand All @@ -38,9 +39,8 @@ type Converter struct {
// ParseDocs parses the docs for the given pattern.
func ParseDocs(c ParseDocsConfig) ([]config.RawConverter, error) {
loadCfg := &packages.Config{
Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedTypes |
packages.NeedModule | packages.NeedFiles | packages.NeedName | packages.NeedImports,
Dir: c.WorkingDir,
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax,
Dir: c.WorkingDir,
}
if c.BuildTags != "" {
loadCfg.BuildFlags = append(loadCfg.BuildFlags, "-tags", c.BuildTags)
Expand Down Expand Up @@ -75,77 +75,114 @@ requires the type information from the compiled sources.`, pkg.PkgPath, pkg.Erro
return rawConverters, nil
}

func parseFunctions(fset *token.FileSet, pkg *types.Package, decl *ast.GenDecl, comments string) ([]config.RawConverter, error) {
if decl.Tok != token.VAR {
return nil, fmt.Errorf("%s must be defined on %q-block but was %q", converterMarker, token.VAR, decl.Tok.String())
}

location := fset.Position(decl.Pos())
converterLines := parseRawLines(fileWithLine(location), comments)

result := map[string]config.RawLines{}
for _, spec := range decl.Specs {
value, ok := spec.(*ast.ValueSpec)
if !ok {
return nil, fmt.Errorf("expected value spec but got %#v", spec)
}
if len(value.Names) != 1 {
return nil, fmt.Errorf("must have one name")
}
name := value.Names[0].Name

location := fileWithLine(fset.Position(value.Pos()))
result[name] = parseRawLines(location, value.Doc.Text())
}

converter := config.RawConverter{
FileName: location.Filename,
Converter: converterLines,
Methods: result,
PackageName: pkg.Name(),
PackagePath: pkg.Path(),
}
return []config.RawConverter{converter}, nil
}

func parseGenDecl(fset *token.FileSet, pkg *types.Package, decl *ast.GenDecl) ([]config.RawConverter, error) {
declDocs := decl.Doc.Text()

if strings.Contains(declDocs, variablesMarker) {
return parseFunctions(fset, pkg, decl, declDocs)
}

if strings.Contains(declDocs, converterMarker) {
if decl.Tok != token.TYPE {
return nil, fmt.Errorf("%s must be defined on %q-block but was %q", converterMarker, token.TYPE, decl.Tok.String())
}

if len(decl.Specs) != 1 {
return nil, fmt.Errorf("found %s on type but it has multiple interfaces inside", converterMarker)
}
typeSpec, ok := decl.Specs[0].(*ast.TypeSpec)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type declarations ", converterMarker)
}
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()

location := fset.Position(decl.Pos())
converterLines := parseRawLines(location.String(), declDocs)
methods, err := parseInterface(fset, interfaceType)
c, err := parseInterface(fset, pkg, typeSpec, declDocs)
if err != nil {
return nil, fmt.Errorf("type %s: %s", typeName, err)
}
converter := config.RawConverter{
FileSource: location.Filename,
InterfaceName: typeName,
Converter: converterLines,
Methods: methods,
Package: pkg.Path(),
return nil, err
}
return []config.RawConverter{converter}, nil
return []config.RawConverter{c}, nil
}

var converters []config.RawConverter

for _, spec := range decl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok && strings.Contains(typeSpec.Doc.Text(), converterMarker) {
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()
location := fset.Position(interfaceType.Pos())
lines := parseRawLines(location.String(), typeSpec.Doc.Text())
methods, err := parseInterface(fset, interfaceType)
c, err := parseInterface(fset, pkg, typeSpec, typeSpec.Doc.Text())
if err != nil {
return nil, fmt.Errorf("type %s: %s", typeName, err)
return nil, err
}
converters = append(converters, config.RawConverter{
FileSource: location.Filename,
InterfaceName: typeName,
Converter: lines,
Methods: methods,
Package: pkg.Path(),
})
converters = append(converters, c)
}
}

return converters, nil
}

func parseInterface(location *token.FileSet, inter *ast.InterfaceType) (map[string]config.RawLines, error) {
func parseInterface(fset *token.FileSet, pkg *types.Package, typeSpec *ast.TypeSpec, declDocs string) (config.RawConverter, error) {
astInterface, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return config.RawConverter{}, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()

location := fset.Position(typeSpec.Pos())
converterLines := parseRawLines(fileWithLine(location), declDocs)
methods, err := parseInterfaceMethods(fset, astInterface)
if err != nil {
return config.RawConverter{}, fmt.Errorf("type %s: %s", typeName, err)
}
converter := config.RawConverter{
InterfaceName: typeName,
FileName: location.Filename,
Converter: converterLines,
Methods: methods,
PackageName: pkg.Name(),
PackagePath: pkg.Path(),
}
return converter, nil
}

func parseInterfaceMethods(location *token.FileSet, inter *ast.InterfaceType) (map[string]config.RawLines, error) {
result := map[string]config.RawLines{}
for _, method := range inter.Methods.List {
if len(method.Names) != 1 {
return result, fmt.Errorf("method must have one name")
}
name := method.Names[0].String()

location := location.Position(method.Pos()).String()
result[name] = parseRawLines(location, method.Doc.Text())
location := location.Position(method.Pos())
result[name] = parseRawLines(fileWithLine(location), method.Doc.Text())
}
return result, nil
}
Expand All @@ -162,3 +199,7 @@ func parseRawLines(location, comment string) config.RawLines {
}
return raw
}

func fileWithLine(p token.Position) string {
return fmt.Sprintf("%s:%d", p.Filename, p.Line)
}
12 changes: 4 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ type RawLines struct {
}

type RawConverter struct {
Package string
PackagePath string
PackageName string
InterfaceName string
Converter RawLines
Methods map[string]RawLines
FileSource string
FileName string
}

type Raw struct {
Expand Down Expand Up @@ -46,14 +47,9 @@ func Parse(raw *Raw) ([]*Converter, error) {

ctx := &context{Loader: loader, EnumTransformers: raw.EnumTransformers}

global, err := parseGlobal(ctx, raw.Global)
if err != nil {
return nil, err
}

converters := []*Converter{}
for _, rawConverter := range raw.Converters {
converter, err := parseConverter(ctx, &rawConverter, *global)
converter, err := parseConverter(ctx, &rawConverter, raw.Global)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 595aa02

Please sign in to comment.