372 lines
10 KiB
Go
372 lines
10 KiB
Go
package lang
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type Type interface {
|
|
typeNode()
|
|
String() string
|
|
}
|
|
|
|
type TypeRef struct {
|
|
Source string
|
|
Syntax Type
|
|
}
|
|
|
|
func ParseTypeRef(source string) (TypeRef, error) {
|
|
typ, err := ParseType(source)
|
|
if err != nil {
|
|
return TypeRef{}, err
|
|
}
|
|
return TypeRef{Source: source, Syntax: typ}, nil
|
|
}
|
|
|
|
type UnknownType struct{}
|
|
|
|
func (UnknownType) typeNode() {}
|
|
func (UnknownType) String() string { return "<unknown>" }
|
|
|
|
type NamedType struct{ Name string }
|
|
|
|
func (NamedType) typeNode() {}
|
|
func (t NamedType) String() string { return t.Name }
|
|
|
|
type TypeParameterType struct{ Name string }
|
|
|
|
func (TypeParameterType) typeNode() {}
|
|
func (t TypeParameterType) String() string { return t.Name }
|
|
|
|
type ClassType struct{ Class *ClassSymbol }
|
|
|
|
func (ClassType) typeNode() {}
|
|
func (t ClassType) String() string { return t.Class.Name }
|
|
|
|
type NullableType struct{ Element Type }
|
|
|
|
func (NullableType) typeNode() {}
|
|
func (t NullableType) String() string { return t.Element.String() + "?" }
|
|
|
|
type GoPointerType struct{ Element Type }
|
|
|
|
func (GoPointerType) typeNode() {}
|
|
func (t GoPointerType) String() string { return "*" + t.Element.String() }
|
|
|
|
type FunctionType struct {
|
|
TypeParams []string
|
|
Params []Type
|
|
Result Type
|
|
Effects Effect
|
|
}
|
|
|
|
func (FunctionType) typeNode() {}
|
|
func (t FunctionType) String() string {
|
|
params := make([]string, 0, len(t.Params))
|
|
for _, param := range t.Params {
|
|
params = append(params, param.String())
|
|
}
|
|
return "(" + strings.Join(params, ", ") + ") -> " + t.Result.String()
|
|
}
|
|
|
|
type GenericType struct {
|
|
Base Type
|
|
Args []Type
|
|
}
|
|
|
|
type TupleType struct{ Elements []Type }
|
|
|
|
func (TupleType) typeNode() {}
|
|
func (t TupleType) String() string {
|
|
elements := make([]string, len(t.Elements))
|
|
for index, element := range t.Elements {
|
|
elements[index] = element.String()
|
|
}
|
|
return "(" + strings.Join(elements, ", ") + ")"
|
|
}
|
|
|
|
func (GenericType) typeNode() {}
|
|
func (t GenericType) String() string {
|
|
args := make([]string, 0, len(t.Args))
|
|
for _, arg := range t.Args {
|
|
args = append(args, arg.String())
|
|
}
|
|
return t.Base.String() + "<" + strings.Join(args, ", ") + ">"
|
|
}
|
|
|
|
func ParseType(text string) (Type, error) {
|
|
text = strings.TrimSpace(text)
|
|
if text == "" {
|
|
return UnknownType{}, nil
|
|
}
|
|
if strings.HasSuffix(text, "?") {
|
|
element, err := ParseType(strings.TrimSpace(strings.TrimSuffix(text, "?")))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NullableType{Element: element}, nil
|
|
}
|
|
if strings.HasPrefix(text, "*") {
|
|
element, err := ParseType(strings.TrimSpace(strings.TrimPrefix(text, "*")))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return GoPointerType{Element: element}, nil
|
|
}
|
|
if params, result, ok := parseFunctionType(text); ok {
|
|
resolvedParams := make([]Type, 0, len(params))
|
|
for _, param := range params {
|
|
resolved, err := ParseType(param)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resolvedParams = append(resolvedParams, resolved)
|
|
}
|
|
resolvedResult, err := ParseType(result)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return FunctionType{Params: resolvedParams, Result: resolvedResult}, nil
|
|
}
|
|
if base, args, ok := parseGenericType(text); ok {
|
|
resolvedBase, err := ParseType(base)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resolvedArgs := make([]Type, 0, len(args))
|
|
for _, arg := range args {
|
|
resolved, err := ParseType(arg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resolvedArgs = append(resolvedArgs, resolved)
|
|
}
|
|
return GenericType{Base: resolvedBase, Args: resolvedArgs}, nil
|
|
}
|
|
if strings.ContainsAny(text, "<>?()") {
|
|
return nil, fmt.Errorf("invalid type %q", text)
|
|
}
|
|
return NamedType{Name: text}, nil
|
|
}
|
|
|
|
func resolveClassTypes(typ Type, classes map[string]*ClassSymbol) Type {
|
|
switch value := typ.(type) {
|
|
case NamedType:
|
|
if class, ok := classes[value.Name]; ok {
|
|
return ClassType{Class: class}
|
|
}
|
|
return value
|
|
case TypeParameterType:
|
|
return value
|
|
case NullableType:
|
|
return NullableType{Element: resolveClassTypes(value.Element, classes)}
|
|
case GoPointerType:
|
|
return GoPointerType{Element: resolveClassTypes(value.Element, classes)}
|
|
case FunctionType:
|
|
params := make([]Type, len(value.Params))
|
|
for i, param := range value.Params {
|
|
params[i] = resolveClassTypes(param, classes)
|
|
}
|
|
return FunctionType{Params: params, Result: resolveClassTypes(value.Result, classes)}
|
|
case GenericType:
|
|
args := make([]Type, len(value.Args))
|
|
for i, arg := range value.Args {
|
|
args[i] = resolveClassTypes(arg, classes)
|
|
}
|
|
return GenericType{Base: resolveClassTypes(value.Base, classes), Args: args}
|
|
case TupleType:
|
|
elements := make([]Type, len(value.Elements))
|
|
for index, element := range value.Elements {
|
|
elements[index] = resolveClassTypes(element, classes)
|
|
}
|
|
return TupleType{Elements: elements}
|
|
default:
|
|
return typ
|
|
}
|
|
}
|
|
|
|
func resolveTypeParameters(typ Type, params map[string]bool) Type {
|
|
switch value := typ.(type) {
|
|
case NamedType:
|
|
if params[value.Name] {
|
|
return TypeParameterType{Name: value.Name}
|
|
}
|
|
return value
|
|
case NullableType:
|
|
return NullableType{Element: resolveTypeParameters(value.Element, params)}
|
|
case GoPointerType:
|
|
return GoPointerType{Element: resolveTypeParameters(value.Element, params)}
|
|
case FunctionType:
|
|
resolved := make([]Type, len(value.Params))
|
|
for index, param := range value.Params {
|
|
resolved[index] = resolveTypeParameters(param, params)
|
|
}
|
|
return FunctionType{TypeParams: value.TypeParams, Params: resolved, Result: resolveTypeParameters(value.Result, params), Effects: value.Effects}
|
|
case GenericType:
|
|
args := make([]Type, len(value.Args))
|
|
for index, arg := range value.Args {
|
|
args[index] = resolveTypeParameters(arg, params)
|
|
}
|
|
return GenericType{Base: resolveTypeParameters(value.Base, params), Args: args}
|
|
case TupleType:
|
|
elements := make([]Type, len(value.Elements))
|
|
for index, element := range value.Elements {
|
|
elements[index] = resolveTypeParameters(element, params)
|
|
}
|
|
return TupleType{Elements: elements}
|
|
default:
|
|
return typ
|
|
}
|
|
}
|
|
|
|
func typeEqual(left, right Type) bool { return left.String() == right.String() }
|
|
|
|
func substituteType(typ Type, bindings map[string]Type) Type {
|
|
switch value := typ.(type) {
|
|
case TypeParameterType:
|
|
if bound, ok := bindings[value.Name]; ok {
|
|
return bound
|
|
}
|
|
return value
|
|
case NullableType:
|
|
return NullableType{Element: substituteType(value.Element, bindings)}
|
|
case GoPointerType:
|
|
return GoPointerType{Element: substituteType(value.Element, bindings)}
|
|
case GenericType:
|
|
args := make([]Type, len(value.Args))
|
|
for index, arg := range value.Args {
|
|
args[index] = substituteType(arg, bindings)
|
|
}
|
|
return GenericType{Base: substituteType(value.Base, bindings), Args: args}
|
|
case TupleType:
|
|
elements := make([]Type, len(value.Elements))
|
|
for index, element := range value.Elements {
|
|
elements[index] = substituteType(element, bindings)
|
|
}
|
|
return TupleType{Elements: elements}
|
|
case FunctionType:
|
|
params := make([]Type, len(value.Params))
|
|
for index, param := range value.Params {
|
|
params[index] = substituteType(param, bindings)
|
|
}
|
|
return FunctionType{TypeParams: value.TypeParams, Params: params, Result: substituteType(value.Result, bindings), Effects: value.Effects}
|
|
default:
|
|
return typ
|
|
}
|
|
}
|
|
|
|
func inferTypeBindings(parameter, argument Type, bindings map[string]Type) {
|
|
switch expected := parameter.(type) {
|
|
case TypeParameterType:
|
|
if _, exists := bindings[expected.Name]; !exists && !isUnknownType(argument) {
|
|
bindings[expected.Name] = argument
|
|
}
|
|
case NullableType:
|
|
if actual, ok := argument.(NullableType); ok {
|
|
inferTypeBindings(expected.Element, actual.Element, bindings)
|
|
}
|
|
case GenericType:
|
|
actual, ok := argument.(GenericType)
|
|
if !ok || expected.Base.String() != actual.Base.String() {
|
|
return
|
|
}
|
|
for index := range expected.Args {
|
|
if index < len(actual.Args) {
|
|
inferTypeBindings(expected.Args[index], actual.Args[index], bindings)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func renderGoType(typ Type) string {
|
|
switch value := typ.(type) {
|
|
case UnknownType:
|
|
return ""
|
|
case ClassType:
|
|
return "*" + value.Class.Name
|
|
case NullableType:
|
|
element := renderGoType(value.Element)
|
|
switch value.Element.(type) {
|
|
case ClassType, GoPointerType:
|
|
return element
|
|
}
|
|
if element == "error" || element == "any" {
|
|
return element
|
|
}
|
|
return "*" + element
|
|
case GoPointerType:
|
|
return "*" + renderGoType(value.Element)
|
|
case FunctionType:
|
|
params := make([]string, len(value.Params))
|
|
for i, param := range value.Params {
|
|
params[i] = renderGoType(param)
|
|
}
|
|
result := renderGoType(value.Result)
|
|
if result == "" {
|
|
return "func(" + strings.Join(params, ", ") + ")"
|
|
}
|
|
return "func(" + strings.Join(params, ", ") + ") " + result
|
|
case GenericType:
|
|
base := value.Base.String()
|
|
args := make([]string, len(value.Args))
|
|
for i, arg := range value.Args {
|
|
args[i] = renderGoType(arg)
|
|
}
|
|
switch base {
|
|
case "List", "MutableList":
|
|
return "[]" + args[0]
|
|
case "Map", "MutableMap":
|
|
return "map[" + args[0] + "]" + args[1]
|
|
case "Channel":
|
|
return "chan " + args[0]
|
|
case "Result":
|
|
if args[0] == "" {
|
|
args[0] = "struct{}"
|
|
}
|
|
return "GotlinResult[" + args[0] + "]"
|
|
case "GotlinSQLIterator":
|
|
argument := args[0]
|
|
if class, ok := value.Args[0].(ClassType); ok {
|
|
argument = class.Class.Name
|
|
}
|
|
return "*GotlinSQLIterator[" + argument + "]"
|
|
}
|
|
if class, ok := value.Base.(ClassType); ok {
|
|
return "*" + class.Class.Name + "[" + strings.Join(args, ", ") + "]"
|
|
}
|
|
return base + "[" + strings.Join(args, ", ") + "]"
|
|
case TypeParameterType:
|
|
return value.Name
|
|
case NamedType:
|
|
switch value.Name {
|
|
case "Int":
|
|
return "int"
|
|
case "Long":
|
|
return "int64"
|
|
case "Float", "Double":
|
|
return "float64"
|
|
case "String":
|
|
return "string"
|
|
case "Any":
|
|
return "any"
|
|
case "ByteSlice":
|
|
return "[]byte"
|
|
case "Boolean":
|
|
return "bool"
|
|
case "Unit":
|
|
return ""
|
|
case "Error":
|
|
return "error"
|
|
default:
|
|
return value.Name
|
|
}
|
|
case TupleType:
|
|
elements := make([]string, len(value.Elements))
|
|
for index, element := range value.Elements {
|
|
elements[index] = renderGoType(element)
|
|
}
|
|
return "(" + strings.Join(elements, ", ") + ")"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|