Support Array types

This commit is contained in:
Lea Anthony
2020-11-01 07:29:45 +11:00
parent f046c0c2ee
commit ae1f771879
2 changed files with 134 additions and 29 deletions

View File

@@ -40,16 +40,17 @@ func goTypeToJS(input string) JSType {
}
}
func goTypeToTS(input string) string {
switch input {
func goTypeToTS(input *ParsedParameter) string {
var result string
switch input.Type {
case "string":
return "string"
result = "string"
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
return "number"
result = "number"
case "float32", "float64":
return "number"
result = "number"
case "bool":
return "boolean"
result = "boolean"
// case reflect.Array, reflect.Slice:
// return string(JsArray)
// case reflect.Ptr, reflect.Struct:
@@ -61,4 +62,10 @@ func goTypeToTS(input string) string {
println("UNSUPPORTED: ", input)
return JsUnsupported
}
if input.IsArray {
result = "Array<" + result + ">"
}
return result
}

View File

@@ -3,6 +3,7 @@ package backendjs
import (
"fmt"
"go/ast"
"os"
"strings"
"github.com/leaanthony/slicer"
@@ -16,19 +17,24 @@ type Parser struct {
boundStructLiterals slicer.StringSlicer
boundMethods []string
boundStructs map[string]*ParsedStruct
boundStructPointerLiterals []string
boundVariables slicer.StringSlicer
variableFunctionDecls map[string]string
variableStructDecls map[string]string
internalMethods slicer.StringSlicer
variableFunctionDecls map[string]string
variableStructDecls map[string]string
internalMethods slicer.StringSlicer
structCache map[string]*ParsedStruct
structPointerFunctionDecls map[string]string
structFunctionDecls map[string]string
}
type ParsedParameter struct {
Name string
Type string
Name string
Type string
IsArray bool
}
func (p *ParsedParameter) JSType() string {
@@ -49,7 +55,7 @@ func (m *ParsedMethod) InputsAsTSText() string {
var inputs []string
for _, input := range m.Inputs {
inputText := fmt.Sprintf("%s: %s", input.Name, goTypeToTS(input.Type))
inputText := fmt.Sprintf("%s: %s", input.Name, goTypeToTS(input))
inputs = append(inputs, inputText)
}
@@ -79,15 +85,7 @@ func (m *ParsedMethod) OutputsAsTSText() string {
var result []string
for _, output := range m.Returns {
jsType := goTypeToJS(output.Type)
switch jsType {
case JsArray:
result = append(result, "Array<any>")
case JsObject:
result = append(result, "any")
default:
result = append(result, string(jsType))
}
result = append(result, goTypeToTS(output))
}
return strings.Join(result, ", ")
}
@@ -105,6 +103,7 @@ func NewParser() *Parser {
structCache: make(map[string]*ParsedStruct),
structPointerFunctionDecls: make(map[string]string),
structFunctionDecls: make(map[string]string),
boundStructs: make(map[string]*ParsedStruct),
}
}
@@ -126,11 +125,11 @@ func parseProject(projectPath string) ([]*Package, error) {
var result []*Package
p := NewParser()
// Iterate the packages
for _, pkg := range pkgs {
p := NewParser()
thisPackage, err := p.parsePackage(pkg)
if err != nil {
return nil, err
@@ -144,6 +143,12 @@ func parseProject(projectPath string) ([]*Package, error) {
}
// Resolve links between data
err = p.Resolve()
if err != nil {
return nil, err
}
return result, nil
}
@@ -344,15 +349,31 @@ func (p *Parser) parseFile(file *ast.File) error {
if x.Type.Results != nil {
for _, outputField := range x.Type.Results.List {
// Check for basic types
t, ok := outputField.Type.(*ast.Ident)
if !ok {
continue
}
if len(outputField.Names) == 0 {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Type: t.Name})
// Check for arrays
a, ok := outputField.Type.(*ast.ArrayType)
if ok {
// spew.Dump(a)
ident := a.Elt.(*ast.Ident)
if len(outputField.Names) == 0 {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Type: ident.Name, IsArray: true})
} else {
for _, name := range outputField.Names {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Name: name.Name, Type: ident.Name, IsArray: true})
}
}
}
} else {
for _, name := range outputField.Names {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Name: name.Name, Type: t.Name})
if len(outputField.Names) == 0 {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Type: t.Name})
} else {
for _, name := range outputField.Names {
structMethod.Returns = append(structMethod.Returns, &ParsedParameter{Name: name.Name, Type: t.Name})
}
}
}
}
@@ -401,3 +422,80 @@ func (p *Parser) parseFile(file *ast.File) error {
return nil
}
func (p *Parser) Resolve() error {
// Resolve bound Methods
for _, method := range p.boundMethods {
s, ok := p.structPointerFunctionDecls[method]
if !ok {
s, ok = p.structFunctionDecls[method]
if !ok {
return fmt.Errorf("bind statement using " + method + " but cannot find " + method + " declaration")
} else {
return fmt.Errorf("cannot bind struct using method `" + method + "` because it returns a struct (" + s + "). Return a pointer to " + s + " instead.")
}
}
structDefinition := p.structCache[s]
if structDefinition == nil {
return fmt.Errorf("Fatal: Bind statement using `" + method + "` but cannot find struct " + s + " definition")
}
p.boundStructs[s] = structDefinition
}
// Resolve bound vars
for _, structLiteral := range p.boundStructPointerLiterals {
s, ok := p.structCache[structLiteral]
if !ok {
return fmt.Errorf("bind statement using " + structLiteral + " but cannot find " + structLiteral + " declaration")
}
p.boundStructs[structLiteral] = s
}
var err error
// Resolve bound variables
p.boundVariables.Each(func(variable string) {
v, ok := p.variableStructDecls[variable]
if !ok {
method, ok := p.variableFunctionDecls[variable]
if !ok {
if err == nil {
err = fmt.Errorf("bind statement using variable `" + variable + "` which does not resolve to a struct pointer")
}
}
// Resolve function name
v, ok = p.structPointerFunctionDecls[method]
if !ok {
v, ok = p.structFunctionDecls[method]
if !ok {
if err == nil {
err = fmt.Errorf("bind statement using " + method + " but cannot find " + method + " declaration")
}
} else {
if err == nil {
err = fmt.Errorf("cannot bind variable `" + variable + "` because it resolves to a struct (" + v + "). Return a pointer to " + v + " instead.")
}
}
}
}
s, ok := p.structCache[v]
if !ok {
println("Fatal: Bind statement using variable `" + variable + "` which resolves to a `" + v + "` but cannot find its declaration")
os.Exit(1)
}
p.boundStructs[v] = s
})
// Return first error when resolving bound variables
if err != nil {
return err
}
// Check for struct literals
if p.boundStructLiterals.Length() > 0 {
return fmt.Errorf("cannot bind structs using struct literals. Create a pointer to the struct instead: %s", p.boundStructLiterals.Join(", "))
}
return nil
}