Introduce typed semantic analysis pipeline
This commit is contained in:
parent
117d188194
commit
f4cd4f4458
30 changed files with 2079 additions and 2381 deletions
|
|
@ -13,23 +13,20 @@ type mappingState struct {
|
|||
}
|
||||
|
||||
func (g *goGenerator) mappingTopLevelTarget(target string) string {
|
||||
if _, ok := g.classForType(target); ok && !strings.HasPrefix(target, "*") {
|
||||
return "*" + target
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
func (g *goGenerator) ensureMapping(source, target, path string) (string, error) {
|
||||
key := source + "->" + target
|
||||
if function, ok := g.mappings.functions[key]; ok {
|
||||
if function, ok := g.semantic.Mappings.functions[key]; ok {
|
||||
return function, nil
|
||||
}
|
||||
if err := g.validateMapping(source, target, path, map[string]bool{}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
function := fmt.Sprintf("gotlinMap%d", len(g.mappings.pairs)+1)
|
||||
g.mappings.functions[key] = function
|
||||
g.mappings.pairs = append(g.mappings.pairs, mappingPair{source: source, target: target, function: function})
|
||||
function := fmt.Sprintf("gotlinMap%d", len(g.semantic.Mappings.pairs)+1)
|
||||
g.semantic.Mappings.functions[key] = function
|
||||
g.semantic.Mappings.pairs = append(g.semantic.Mappings.pairs, mappingPair{source: source, target: target, function: function})
|
||||
return function, nil
|
||||
}
|
||||
|
||||
|
|
@ -83,8 +80,8 @@ func (g *goGenerator) validateMapping(source, target, path string, seen map[stri
|
|||
}
|
||||
return nil
|
||||
}
|
||||
sourceEnum, sourceEnumOK := g.enums[strings.TrimPrefix(source, "*")]
|
||||
targetEnum, targetEnumOK := g.enums[strings.TrimPrefix(target, "*")]
|
||||
sourceEnum, sourceEnumOK := g.semantic.Enums[strings.TrimPrefix(source, "*")]
|
||||
targetEnum, targetEnumOK := g.semantic.Enums[strings.TrimPrefix(target, "*")]
|
||||
if sourceEnumOK || targetEnumOK {
|
||||
if sourceEnumOK && enumIsString(sourceEnum) && target == "String" {
|
||||
return nil
|
||||
|
|
@ -134,16 +131,16 @@ func mappingFieldName(class ClassDecl, field FieldDecl) string {
|
|||
}
|
||||
|
||||
func (g *goGenerator) emitMapping(pair mappingPair) error {
|
||||
g.line(fmt.Sprintf("func %s(source %s) %s {", pair.function, mapGoType(pair.source), mapGoType(pair.target)))
|
||||
g.line(fmt.Sprintf("func %s(source %s) %s {", pair.function, g.goType(pair.source), g.goType(pair.target)))
|
||||
g.indentLevel++
|
||||
if sourceEnum, ok := g.enums[strings.TrimPrefix(pair.source, "*")]; ok {
|
||||
if sourceEnum, ok := g.semantic.Enums[strings.TrimPrefix(pair.source, "*")]; ok {
|
||||
if enumIsString(sourceEnum) && pair.target == "String" {
|
||||
g.line("return string(source)")
|
||||
g.indentLevel--
|
||||
g.line("}")
|
||||
return nil
|
||||
}
|
||||
targetEnum := g.enums[strings.TrimPrefix(pair.target, "*")]
|
||||
targetEnum := g.semantic.Enums[strings.TrimPrefix(pair.target, "*")]
|
||||
if enumIsString(sourceEnum) && enumIsString(targetEnum) {
|
||||
g.line("return " + targetEnum.Name + "(source)")
|
||||
g.indentLevel--
|
||||
|
|
@ -170,7 +167,7 @@ func (g *goGenerator) emitMapping(pair mappingPair) error {
|
|||
g.indentLevel--
|
||||
g.line("}")
|
||||
g.line(`panic("unreachable enum mapping")`)
|
||||
} else if targetEnum, ok := g.enums[strings.TrimPrefix(pair.target, "*")]; ok && pair.source == "String" && enumIsString(targetEnum) {
|
||||
} else if targetEnum, ok := g.semantic.Enums[strings.TrimPrefix(pair.target, "*")]; ok && pair.source == "String" && enumIsString(targetEnum) {
|
||||
g.line("switch source {")
|
||||
g.indentLevel++
|
||||
for _, variant := range targetEnum.Variants {
|
||||
|
|
@ -201,18 +198,22 @@ func (g *goGenerator) mappingExpr(expr, source, target, path string) (string, er
|
|||
if strings.HasSuffix(source, "?") || strings.HasSuffix(target, "?") {
|
||||
sourceInner := strings.TrimSuffix(source, "?")
|
||||
targetInner := strings.TrimSuffix(target, "?")
|
||||
inner, err := g.mappingExpr("*value", sourceInner, targetInner, path)
|
||||
innerExpr := "*value"
|
||||
if _, class := g.classForType(sourceInner); class {
|
||||
innerExpr = "value"
|
||||
}
|
||||
inner, err := g.mappingExpr(innerExpr, sourceInner, targetInner, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if strings.HasSuffix(source, "?") {
|
||||
return fmt.Sprintf("func(value %s) %s { if value == nil { return nil }; mapped := %s; return &mapped }(%s)", mapGoType(source), mapGoType(target), inner, expr), nil
|
||||
return fmt.Sprintf("func(value %s) %s { if value == nil { return nil }; return %s }(%s)", g.goType(source), g.goType(target), inner, expr), nil
|
||||
}
|
||||
inner, err = g.mappingExpr("value", sourceInner, targetInner, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("func(value %s) %s { mapped := %s; return &mapped }(%s)", mapGoType(source), mapGoType(target), inner, expr), nil
|
||||
return fmt.Sprintf("func(value %s) %s { return %s }(%s)", g.goType(source), g.goType(target), inner, expr), nil
|
||||
}
|
||||
if sourceBase, sourceArgs, ok := parseGenericType(source); ok {
|
||||
_, targetArgs, _ := parseGenericType(target)
|
||||
|
|
@ -221,14 +222,14 @@ func (g *goGenerator) mappingExpr(expr, source, target, path string) (string, er
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("func(values %s) %s { var result %s; for _, item := range values { result = append(result, %s) }; return result }(%s)", mapGoType(source), mapGoType(target), mapGoType(target), item, expr), nil
|
||||
return fmt.Sprintf("func(values %s) %s { var result %s; for _, item := range values { result = append(result, %s) }; return result }(%s)", g.goType(source), g.goType(target), g.goType(target), item, expr), nil
|
||||
}
|
||||
if sourceBase == "Map" || sourceBase == "MutableMap" {
|
||||
value, err := g.mappingExpr("item", sourceArgs[1], targetArgs[1], path+"[]")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("func(values %s) %s { result := make(%s, len(values)); for key, item := range values { result[key] = %s }; return result }(%s)", mapGoType(source), mapGoType(target), mapGoType(target), value, expr), nil
|
||||
return fmt.Sprintf("func(values %s) %s { result := make(%s, len(values)); for key, item := range values { result[key] = %s }; return result }(%s)", g.goType(source), g.goType(target), g.goType(target), value, expr), nil
|
||||
}
|
||||
}
|
||||
if sourceClass, ok := g.classForType(source); ok {
|
||||
|
|
@ -242,23 +243,16 @@ func (g *goGenerator) mappingExpr(expr, source, target, path string) (string, er
|
|||
}
|
||||
fields = append(fields, mappingFieldName(targetClass, targetField)+": "+mapped)
|
||||
}
|
||||
literal := targetClass.Name + "{" + strings.Join(fields, ", ") + "}"
|
||||
if strings.HasPrefix(target, "*") {
|
||||
literal = "&" + literal
|
||||
}
|
||||
if strings.HasPrefix(source, "*") {
|
||||
return fmt.Sprintf("func(value %s) %s { if value == nil { return nil }; return %s }(%s)", mapGoType(source), mapGoType(target), strings.ReplaceAll(literal, expr+".", "value."), expr), nil
|
||||
}
|
||||
return literal, nil
|
||||
return "&" + targetClass.Name + "{" + strings.Join(fields, ", ") + "}", nil
|
||||
}
|
||||
if _, ok := g.enums[strings.TrimPrefix(source, "*")]; ok {
|
||||
if _, ok := g.semantic.Enums[strings.TrimPrefix(source, "*")]; ok {
|
||||
function, err := g.ensureMapping(source, target, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return function + "(" + expr + ")", nil
|
||||
}
|
||||
if targetEnum, ok := g.enums[strings.TrimPrefix(target, "*")]; ok && source == "String" && enumIsString(targetEnum) {
|
||||
if targetEnum, ok := g.semantic.Enums[strings.TrimPrefix(target, "*")]; ok && source == "String" && enumIsString(targetEnum) {
|
||||
function, err := g.ensureMapping(source, target, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue