192 lines
5.9 KiB
Go
192 lines
5.9 KiB
Go
package lang
|
|
|
|
import "strings"
|
|
|
|
func normalizeClassReferences(program *Program) {
|
|
classes := map[string]bool{}
|
|
for _, class := range program.Classes {
|
|
classes[class.Name] = true
|
|
}
|
|
normalize := func(value string) string { return normalizeReferenceType(value, classes) }
|
|
for i := range program.Interfaces {
|
|
for j := range program.Interfaces[i].Methods {
|
|
normalizeSignature(&program.Interfaces[i].Methods[j], normalize)
|
|
}
|
|
}
|
|
for i := range program.Enums {
|
|
for j := range program.Enums[i].Variants {
|
|
for k := range program.Enums[i].Variants[j].PayloadTypes {
|
|
program.Enums[i].Variants[j].PayloadTypes[k] = normalize(program.Enums[i].Variants[j].PayloadTypes[k])
|
|
}
|
|
}
|
|
}
|
|
for i := range program.Classes {
|
|
for j := range program.Classes[i].Fields {
|
|
program.Classes[i].Fields[j].Type = normalize(program.Classes[i].Fields[j].Type)
|
|
}
|
|
for j := range program.Classes[i].Methods {
|
|
normalizeFunction(&program.Classes[i].Methods[j], normalize)
|
|
}
|
|
}
|
|
for i := range program.Workers {
|
|
for j := range program.Workers[i].Fields {
|
|
program.Workers[i].Fields[j].Type = normalize(program.Workers[i].Fields[j].Type)
|
|
normalizeExprTypes(program.Workers[i].Fields[j].Value, normalize)
|
|
}
|
|
for j := range program.Workers[i].Methods {
|
|
normalizeFunction(&program.Workers[i].Methods[j], normalize)
|
|
}
|
|
}
|
|
for i := range program.Functions {
|
|
normalizeFunction(&program.Functions[i], normalize)
|
|
}
|
|
}
|
|
|
|
func normalizeSignature(signature *FunctionSignature, normalize func(string) string) {
|
|
for i := range signature.Params {
|
|
signature.Params[i].Type = normalize(signature.Params[i].Type)
|
|
}
|
|
signature.ReturnType = normalize(signature.ReturnType)
|
|
}
|
|
|
|
func normalizeFunction(function *FunctionDecl, normalize func(string) string) {
|
|
for i := range function.Params {
|
|
function.Params[i].Type = normalize(function.Params[i].Type)
|
|
}
|
|
function.ReturnType = normalize(function.ReturnType)
|
|
normalizeStmtTypes(function.Body, normalize)
|
|
}
|
|
|
|
func normalizeStmtTypes(statements []Stmt, normalize func(string) string) {
|
|
for index, statement := range statements {
|
|
switch value := statement.(type) {
|
|
case VarDecl:
|
|
value.Type = normalize(value.Type)
|
|
normalizeExprTypes(value.Value, normalize)
|
|
statements[index] = value
|
|
case MultiVarDecl:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case AssignStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case AddAssignStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case MultiAssignStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case ReturnStmt:
|
|
if value.Value != nil {
|
|
normalizeExprTypes(value.Value, normalize)
|
|
}
|
|
case ThrowStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case GoStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case DeferStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case ExprStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case IfStmt:
|
|
normalizeExprTypes(value.Cond, normalize)
|
|
normalizeStmtTypes(value.Then, normalize)
|
|
normalizeStmtTypes(value.Else, normalize)
|
|
case WhileStmt:
|
|
normalizeExprTypes(value.Cond, normalize)
|
|
normalizeStmtTypes(value.Body, normalize)
|
|
case ForEachStmt:
|
|
normalizeExprTypes(value.Source, normalize)
|
|
normalizeStmtTypes(value.Body, normalize)
|
|
case SelectStmt:
|
|
for _, c := range value.Cases {
|
|
normalizeExprTypes(c.Source, normalize)
|
|
normalizeStmtTypes(c.Body, normalize)
|
|
}
|
|
case MatchStmt:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
for _, c := range value.Cases {
|
|
normalizeStmtTypes(c.Body, normalize)
|
|
}
|
|
case TryCatchStmt:
|
|
value.CatchType = normalize(value.CatchType)
|
|
normalizeStmtTypes(value.TryBody, normalize)
|
|
normalizeStmtTypes(value.CatchBody, normalize)
|
|
statements[index] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
func normalizeExprTypes(expression Expr, normalize func(string) string) {
|
|
switch value := expression.(type) {
|
|
case UnaryExpr:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case NonNullExpr:
|
|
normalizeExprTypes(value.Value, normalize)
|
|
case BinaryExpr:
|
|
normalizeExprTypes(value.Left, normalize)
|
|
normalizeExprTypes(value.Right, normalize)
|
|
case SelectorExpr:
|
|
normalizeExprTypes(value.Receiver, normalize)
|
|
case SafeSelectorExpr:
|
|
normalizeExprTypes(value.Receiver, normalize)
|
|
case IndexExpr:
|
|
normalizeExprTypes(value.Receiver, normalize)
|
|
normalizeExprTypes(value.Index, normalize)
|
|
case EnumVariantExpr:
|
|
for _, item := range value.Values {
|
|
normalizeExprTypes(item, normalize)
|
|
}
|
|
case LambdaExpr:
|
|
for i := range value.Params {
|
|
value.Params[i].Type = normalize(value.Params[i].Type)
|
|
}
|
|
normalizeStmtTypes(value.Body, normalize)
|
|
case CallExpr:
|
|
skipTypeArgs := false
|
|
if selector, ok := value.Callee.(SelectorExpr); ok {
|
|
if root, ok := selector.Receiver.(IdentExpr); ok && root.Name == "sql" {
|
|
skipTypeArgs = true
|
|
}
|
|
}
|
|
if !skipTypeArgs {
|
|
for i := range value.TypeArgs {
|
|
value.TypeArgs[i] = normalize(value.TypeArgs[i])
|
|
}
|
|
}
|
|
normalizeExprTypes(value.Callee, normalize)
|
|
for _, item := range value.Args {
|
|
normalizeExprTypes(item, normalize)
|
|
}
|
|
for _, item := range value.NamedArgs {
|
|
normalizeExprTypes(item.Value, normalize)
|
|
}
|
|
}
|
|
}
|
|
|
|
func normalizeReferenceType(value string, classes map[string]bool) string {
|
|
if value == "" {
|
|
return value
|
|
}
|
|
nullable := strings.HasSuffix(value, "?")
|
|
if nullable {
|
|
value = strings.TrimSuffix(value, "?")
|
|
}
|
|
explicitPointer := strings.HasPrefix(value, "*")
|
|
if explicitPointer {
|
|
value = strings.TrimPrefix(value, "*")
|
|
}
|
|
if params, result, ok := parseFunctionType(value); ok {
|
|
for i := range params {
|
|
params[i] = normalizeReferenceType(params[i], classes)
|
|
}
|
|
value = "(" + strings.Join(params, ", ") + ") -> " + normalizeReferenceType(result, classes)
|
|
} else if base, args, ok := parseGenericType(value); ok {
|
|
for i := range args {
|
|
args[i] = normalizeReferenceType(args[i], classes)
|
|
}
|
|
value = base + "<" + strings.Join(args, ", ") + ">"
|
|
} else if classes[value] || explicitPointer {
|
|
value = "*" + value
|
|
}
|
|
if nullable {
|
|
value += "?"
|
|
}
|
|
return value
|
|
}
|