Use dot notation for enum variants

This commit is contained in:
pavel 2026-08-27 18:05:28 +02:00
commit 117d188194
13 changed files with 162 additions and 154 deletions

View file

@ -1051,18 +1051,18 @@ func (g *goGenerator) stmt(stmt Stmt, tail []Stmt) error {
seen := map[string]bool{}
for _, c := range s.Cases {
if c.EnumName != enumName {
return fmt.Errorf("match case %s::%s does not match enum %s", c.EnumName, c.VariantName, enumName)
return fmt.Errorf("match case %s.%s does not match enum %s", c.EnumName, c.VariantName, enumName)
}
if seen[c.VariantName] {
return fmt.Errorf("duplicate match case %s::%s", enumName, c.VariantName)
return fmt.Errorf("duplicate match case %s.%s", enumName, c.VariantName)
}
seen[c.VariantName] = true
variant := enumVariant(decl, c.VariantName)
if variant == nil {
return fmt.Errorf("unknown variant %s::%s", enumName, c.VariantName)
return fmt.Errorf("unknown variant %s.%s", enumName, c.VariantName)
}
if len(c.Bindings) != len(variant.PayloadTypes) {
return fmt.Errorf("match case %s::%s expects %d bindings", enumName, c.VariantName, len(variant.PayloadTypes))
return fmt.Errorf("match case %s.%s expects %d bindings", enumName, c.VariantName, len(variant.PayloadTypes))
}
}
for _, variant := range decl.Variants {
@ -1250,6 +1250,16 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
}
return fmt.Sprintf("%s %s %s", left, e.Op, right), nil
case CallExpr:
if selector, ok := e.Callee.(SelectorExpr); ok {
if receiver, ok := selector.Receiver.(IdentExpr); ok {
if receiver.Name == "Result" {
return g.expr(EnumVariantExpr{EnumName: receiver.Name, VariantName: selector.Name, Values: e.Args}, expectedType)
}
if _, ok := g.enums[receiver.Name]; ok {
return g.expr(EnumVariantExpr{EnumName: receiver.Name, VariantName: selector.Name, Values: e.Args}, expectedType)
}
}
}
if ident, ok := e.Callee.(IdentExpr); ok && coroutineBuiltins[ident.Name] {
switch ident.Name {
case "runBlocking":
@ -1607,6 +1617,18 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
}
return call, nil
case SelectorExpr:
if receiver, ok := e.Receiver.(IdentExpr); ok {
if decl, ok := g.enums[receiver.Name]; ok {
variant := enumVariant(decl, e.Name)
if variant == nil {
return "", fmt.Errorf("unknown variant %s.%s", receiver.Name, e.Name)
}
if len(variant.PayloadTypes) != 0 {
return "", fmt.Errorf("variant %s.%s requires %d values", receiver.Name, e.Name, len(variant.PayloadTypes))
}
return g.expr(EnumVariantExpr{EnumName: receiver.Name, VariantName: e.Name}, expectedType)
}
}
if receiverType := g.exprType(e.Receiver); strings.HasSuffix(receiverType, "?") {
return "", fmt.Errorf("nullable receiver %s requires ?. or !! before .%s", receiverType, e.Name)
}
@ -1685,11 +1707,11 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
if e.EnumName == "Result" {
base, args, ok := parseGenericType(expectedType)
if !ok || base != "Result" || len(args) != 2 {
return "", fmt.Errorf("Result::%s requires an expected Result<T, Error> type", e.VariantName)
return "", fmt.Errorf("Result.%s requires an expected Result<T, Error> type", e.VariantName)
}
if e.VariantName == "Ok" {
if len(e.Values) != 1 {
return "", fmt.Errorf("Result::Ok expects one value")
return "", fmt.Errorf("Result.Ok expects one value")
}
value, err := g.expr(e.Values[0], args[0])
if err != nil {
@ -1699,7 +1721,7 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
}
if e.VariantName == "Err" {
if len(e.Values) != 1 {
return "", fmt.Errorf("Result::Err expects one error")
return "", fmt.Errorf("Result.Err expects one error")
}
value, err := g.expr(e.Values[0], "Error")
if err != nil {
@ -1721,10 +1743,10 @@ func (g *goGenerator) expr(expr Expr, expectedType string) (string, error) {
}
}
if variant == nil {
return "", fmt.Errorf("unknown variant %s::%s", e.EnumName, e.VariantName)
return "", fmt.Errorf("unknown variant %s.%s", e.EnumName, e.VariantName)
}
if len(e.Values) != len(variant.PayloadTypes) {
return "", fmt.Errorf("variant %s::%s expects %d values", e.EnumName, e.VariantName, len(variant.PayloadTypes))
return "", fmt.Errorf("variant %s.%s expects %d values", e.EnumName, e.VariantName, len(variant.PayloadTypes))
}
if enumIsString(decl) {
return e.EnumName + e.VariantName, nil
@ -1757,18 +1779,18 @@ func (g *goGenerator) valueMatch(match MatchExpr, expectedType string) (string,
seen := map[string]bool{}
for _, c := range match.Cases {
if c.EnumName != enumName {
return "", fmt.Errorf("match case %s::%s does not match enum %s", c.EnumName, c.VariantName, enumName)
return "", fmt.Errorf("match case %s.%s does not match enum %s", c.EnumName, c.VariantName, enumName)
}
if seen[c.VariantName] {
return "", fmt.Errorf("duplicate match case %s::%s", enumName, c.VariantName)
return "", fmt.Errorf("duplicate match case %s.%s", enumName, c.VariantName)
}
seen[c.VariantName] = true
variant := enumVariant(decl, c.VariantName)
if variant == nil {
return "", fmt.Errorf("unknown variant %s::%s", enumName, c.VariantName)
return "", fmt.Errorf("unknown variant %s.%s", enumName, c.VariantName)
}
if len(c.Bindings) != len(variant.PayloadTypes) {
return "", fmt.Errorf("match case %s::%s expects %d bindings", enumName, c.VariantName, len(variant.PayloadTypes))
return "", fmt.Errorf("match case %s.%s expects %d bindings", enumName, c.VariantName, len(variant.PayloadTypes))
}
}
for _, variant := range decl.Variants {
@ -1804,7 +1826,7 @@ func (g *goGenerator) valueMatch(match MatchExpr, expectedType string) (string,
armType := g.exprType(c.Value)
g.popScope()
if armType != "" && armType != resultType {
return "", fmt.Errorf("match expression arm %s::%s has type %s, expected %s", enumName, c.VariantName, armType, resultType)
return "", fmt.Errorf("match expression arm %s.%s has type %s, expected %s", enumName, c.VariantName, armType, resultType)
}
}
value, err := g.expr(match.Value, enumName)
@ -3110,6 +3132,13 @@ func (g *goGenerator) exprType(expr Expr) string {
case BoolExpr:
return "Boolean"
case CallExpr:
if selector, ok := e.Callee.(SelectorExpr); ok {
if receiver, ok := selector.Receiver.(IdentExpr); ok {
if _, ok := g.enums[receiver.Name]; ok {
return receiver.Name
}
}
}
if ident, ok := e.Callee.(IdentExpr); ok && ident.Name == "keys" && len(e.Args) == 1 {
if _, args, ok := parseGenericType(g.exprType(e.Args[0])); ok && len(args) == 2 {
return "List<" + args[0] + ">"
@ -3173,6 +3202,11 @@ func (g *goGenerator) exprType(expr Expr) string {
}
}
case SelectorExpr:
if receiver, ok := e.Receiver.(IdentExpr); ok {
if _, ok := g.enums[receiver.Name]; ok {
return receiver.Name
}
}
if class, ok := g.classForType(g.exprType(e.Receiver)); ok {
for _, field := range class.Fields {
if field.Name == e.Name {