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

@ -109,9 +109,9 @@ enum PaymentResult {
fun describe(result: PaymentResult): String { fun describe(result: PaymentResult): String {
return match (result) { return match (result) {
PaymentResult::Accepted(id) -> id PaymentResult.Accepted(id) -> id
PaymentResult::Rejected(reason) -> reason PaymentResult.Rejected(reason) -> reason
PaymentResult::Pending -> "pending" PaymentResult.Pending -> "pending"
} }
} }
``` ```

View file

@ -646,7 +646,7 @@ func indexSymbols(text string, program *lang.Program) []symbol {
} }
symbols = append(symbols, symbol{Name: decl.Name, Kind: symbolKindEnum, Detail: "enum " + decl.Name, Range: r}) symbols = append(symbols, symbol{Name: decl.Name, Kind: symbolKindEnum, Detail: "enum " + decl.Name, Range: r})
for _, variant := range decl.Variants { for _, variant := range decl.Variants {
symbols = append(symbols, symbol{Name: variant.Name, Kind: symbolKindVariable, Detail: decl.Name + "::" + variant.Name, Range: r, Targets: []string{decl.Name}}) symbols = append(symbols, symbol{Name: variant.Name, Kind: symbolKindVariable, Detail: decl.Name + "." + variant.Name, Range: r, Targets: []string{decl.Name}})
} }
} }

View file

@ -8,13 +8,13 @@ enum PaymentResult {
fun describe(result: PaymentResult): String { fun describe(result: PaymentResult): String {
return match (result) { return match (result) {
PaymentResult::Accepted(id) -> "accepted " + id PaymentResult.Accepted(id) -> "accepted " + id
PaymentResult::Rejected(reason) -> "rejected " + reason PaymentResult.Rejected(reason) -> "rejected " + reason
PaymentResult::Pending -> "pending" PaymentResult.Pending -> "pending"
} }
} }
fun main() { fun main() {
val result = PaymentResult::Accepted("payment-1") val result = PaymentResult.Accepted("payment-1")
println(describe(result)) println(describe(result))
} }

View file

@ -29,12 +29,12 @@ data class AccountResponse(
) )
fun main() { fun main() {
val entity = AccountEntity("account-1", AddressEntity("Berlin"), listOf("active"), EntityState::Active) val entity = AccountEntity("account-1", AddressEntity("Berlin"), listOf("active"), EntityState.Active)
val response = entity.mapTo<AccountResponse>() val response = entity.mapTo<AccountResponse>()
println(response.address.city) println(response.address.city)
match (response.state) { match (response.state) {
ResponseState::Active -> { println("active") } ResponseState.Active -> { println("active") }
ResponseState::Failed(reason) -> { println(reason) } ResponseState.Failed(reason) -> { println(reason) }
ResponseState::Pending -> { println("pending") } ResponseState.Pending -> { println("pending") }
} }
} }

View file

@ -12,13 +12,13 @@ enum PaymentResult { Accepted(String), Rejected(String), Pending }
fun describe(result: PaymentResult): String { fun describe(result: PaymentResult): String {
var description = "" var description = ""
match (result) { match (result) {
PaymentResult::Accepted(id) -> { description = id } PaymentResult.Accepted(id) -> { description = id }
PaymentResult::Rejected(reason) -> { description = reason } PaymentResult.Rejected(reason) -> { description = reason }
PaymentResult::Pending -> { description = "pending" } PaymentResult.Pending -> { description = "pending" }
} }
return description return description
} }
fun main() { println(describe(PaymentResult::Accepted("p1"))) } fun main() { println(describe(PaymentResult.Accepted("p1"))) }
`) `)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -37,7 +37,7 @@ fun main() { println(describe(PaymentResult::Accepted("p1"))) }
func TestRejectNonExhaustiveEnumMatch(t *testing.T) { func TestRejectNonExhaustiveEnumMatch(t *testing.T) {
prog, err := Parse(`package demo prog, err := Parse(`package demo
enum Result { Ok, Error(String) } enum Result { Ok, Error(String) }
fun use(result: Result) { match (result) { Result::Ok -> { println("ok") } } }`) fun use(result: Result) { match (result) { Result.Ok -> { println("ok") } } }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -50,7 +50,7 @@ fun use(result: Result) { match (result) { Result::Ok -> { println("ok") } } }`)
func TestRejectWrongVariantPayloadCount(t *testing.T) { func TestRejectWrongVariantPayloadCount(t *testing.T) {
prog, err := Parse(`package demo prog, err := Parse(`package demo
enum Outcome { Ok(String) } enum Outcome { Ok(String) }
fun main() { val result = Outcome::Ok() }`) fun main() { val result = Outcome.Ok() }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -60,10 +60,17 @@ fun main() { val result = Outcome::Ok() }`)
} }
} }
func TestRejectDoubleColonEnumSyntax(t *testing.T) {
_, err := Parse(`package demo enum State { Ready } fun main() { println(State::Ready) }`)
if err == nil {
t.Fatal("deprecated double-colon enum syntax parsed")
}
}
func TestPayloadlessEnumUsesExactVariantStrings(t *testing.T) { func TestPayloadlessEnumUsesExactVariantStrings(t *testing.T) {
prog, err := Parse(`package demo prog, err := Parse(`package demo
enum Status { PendingReservation, Initiated } enum Status { PendingReservation, Initiated }
fun main() { println(Status::PendingReservation) }`) fun main() { println(Status.PendingReservation) }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -83,8 +90,8 @@ func TestGenerateExhaustiveMatchExpression(t *testing.T) {
enum AccountType { BASIC, SAVINGS } enum AccountType { BASIC, SAVINGS }
fun interestRate(accountType: AccountType): Double { fun interestRate(accountType: AccountType): Double {
return match (accountType) { return match (accountType) {
AccountType::BASIC -> 0.0 AccountType.BASIC -> 0.0
AccountType::SAVINGS -> 0.02 AccountType.SAVINGS -> 0.02
} }
}`) }`)
if err != nil { if err != nil {
@ -106,8 +113,8 @@ func TestGeneratePayloadMatchExpression(t *testing.T) {
enum Outcome { Success(String), Failure(String) } enum Outcome { Success(String), Failure(String) }
fun message(outcome: Outcome): String { fun message(outcome: Outcome): String {
return match (outcome) { return match (outcome) {
Outcome::Success(value) -> value Outcome.Success(value) -> value
Outcome::Failure(reason) -> reason Outcome.Failure(reason) -> reason
} }
}`) }`)
if err != nil { if err != nil {
@ -129,8 +136,8 @@ func TestRejectInvalidMatchExpression(t *testing.T) {
source string source string
want string want string
}{ }{
{`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State::On -> 1 } }`, "missing Off"}, {`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State.On -> 1 } }`, "missing Off"},
{`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State::On -> 1 State::Off -> "off" } }`, "has type String, expected Int"}, {`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State.On -> 1 State.Off -> "off" } }`, "has type String, expected Int"},
} { } {
prog, err := Parse(test.source) prog, err := Parse(test.source)
if err != nil { if err != nil {

View file

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

View file

@ -93,9 +93,6 @@ func (l *lexer) next() (token, error) {
case '.': case '.':
return token{kind: tokenDot, lexeme: ".", pos: start}, nil return token{kind: tokenDot, lexeme: ".", pos: start}, nil
case ':': case ':':
if l.match(':') {
return token{kind: tokenDoubleColon, lexeme: "::", pos: start}, nil
}
return token{kind: tokenColon, lexeme: ":", pos: start}, nil return token{kind: tokenColon, lexeme: ":", pos: start}, nil
case ';': case ';':
return token{kind: tokenSemicolon, lexeme: ";", pos: start}, nil return token{kind: tokenSemicolon, lexeme: ";", pos: start}, nil

View file

@ -97,7 +97,7 @@ func (g *goGenerator) validateMapping(source, target, path string, seen map[stri
} }
for _, sourceVariant := range sourceEnum.Variants { for _, sourceVariant := range sourceEnum.Variants {
targetVariant := enumVariant(targetEnum, sourceVariant.Name) targetVariant := enumVariant(targetEnum, sourceVariant.Name)
variantPath := path + "::" + sourceVariant.Name variantPath := path + "." + sourceVariant.Name
if targetVariant == nil { if targetVariant == nil {
return fmt.Errorf("cannot map %s: target enum %s has no compatible variant", variantPath, targetEnum.Name) return fmt.Errorf("cannot map %s: target enum %s has no compatible variant", variantPath, targetEnum.Name)
} }
@ -158,7 +158,7 @@ func (g *goGenerator) emitMapping(pair mappingPair) error {
g.indentLevel++ g.indentLevel++
fields := make([]string, 0, len(sourceVariant.PayloadTypes)) fields := make([]string, 0, len(sourceVariant.PayloadTypes))
for i := range sourceVariant.PayloadTypes { for i := range sourceVariant.PayloadTypes {
expr, err := g.mappingExpr(fmt.Sprintf("value.Value%d", i), sourceVariant.PayloadTypes[i], targetVariant.PayloadTypes[i], sourceEnum.Name+"::"+sourceVariant.Name) expr, err := g.mappingExpr(fmt.Sprintf("value.Value%d", i), sourceVariant.PayloadTypes[i], targetVariant.PayloadTypes[i], sourceEnum.Name+"."+sourceVariant.Name)
if err != nil { if err != nil {
return err return err
} }

View file

@ -751,7 +751,7 @@ func (p *parser) parseMatch() (Stmt, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, err := p.expect(tokenDoubleColon, "expected '::' in match case"); err != nil { if _, err := p.expect(tokenDot, "expected '.' in match case"); err != nil {
return nil, err return nil, err
} }
variant, err := p.expect(tokenIdent, "expected variant name") variant, err := p.expect(tokenIdent, "expected variant name")
@ -813,7 +813,7 @@ func (p *parser) parseMatchExpr() (Expr, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, err := p.expect(tokenDoubleColon, "expected '::' in match case"); err != nil { if _, err := p.expect(tokenDot, "expected '.' in match case"); err != nil {
return nil, err return nil, err
} }
variant, err := p.expect(tokenIdent, "expected variant name") variant, err := p.expect(tokenIdent, "expected variant name")
@ -1029,31 +1029,6 @@ func (p *parser) parsePrefix() (Expr, error) {
tok := p.advance() tok := p.advance()
switch tok.kind { switch tok.kind {
case tokenIdent: case tokenIdent:
if p.match(tokenDoubleColon) {
variant, err := p.expect(tokenIdent, "expected enum variant")
if err != nil {
return nil, err
}
var values []Expr
if p.match(tokenLParen) {
if !p.check(tokenRParen) {
for {
value, err := p.parseExpr(0)
if err != nil {
return nil, err
}
values = append(values, value)
if !p.match(tokenComma) {
break
}
}
}
if _, err := p.expect(tokenRParen, "expected ')' after variant values"); err != nil {
return nil, err
}
}
return p.parsePostfix(EnumVariantExpr{EnumName: tok.lexeme, VariantName: variant.lexeme, Values: values})
}
return p.parsePostfix(IdentExpr{Name: tok.lexeme}) return p.parsePostfix(IdentExpr{Name: tok.lexeme})
case tokenInt: case tokenInt:
return IntExpr{Value: tok.lexeme}, nil return IntExpr{Value: tok.lexeme}, nil

View file

@ -10,7 +10,7 @@ func TestResultQuestionPropagatesGoError(t *testing.T) {
import strconv import strconv
fun parse(value: String): Result<Int, Error> { fun parse(value: String): Result<Int, Error> {
val parsed = strconv.atoi(value)? val parsed = strconv.atoi(value)?
return Result::Ok(parsed) return Result.Ok(parsed)
}`) }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -74,8 +74,8 @@ fun changeDirectory(path: String): Result<Unit, Error> { return os.chdir(path) }
func TestResultQuestionPropagatesGotlinResult(t *testing.T) { func TestResultQuestionPropagatesGotlinResult(t *testing.T) {
prog, err := Parse(`package demo prog, err := Parse(`package demo
import errors import errors
fun inner(ok: Boolean): Result<String, Error> { if (!ok) { return Result::Err(errors.new("failed")) }; return Result::Ok("ok") } fun inner(ok: Boolean): Result<String, Error> { if (!ok) { return Result.Err(errors.new("failed")) }; return Result.Ok("ok") }
fun outer(): Result<String, Error> { val value = inner(true)?; return Result::Ok(value) }`) fun outer(): Result<String, Error> { val value = inner(true)?; return Result.Ok(value) }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -127,7 +127,7 @@ import strconv
fun parse(value: String): Result<Int, Error> { fun parse(value: String): Result<Int, Error> {
val input = value val input = value
val parsed = strconv.atoi(input)? val parsed = strconv.atoi(input)?
return Result::Ok(parsed) return Result.Ok(parsed)
}`) }`)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -3,73 +3,72 @@ package lang
type tokenKind string type tokenKind string
const ( const (
tokenEOF tokenKind = "EOF" tokenEOF tokenKind = "EOF"
tokenIdent tokenKind = "IDENT" tokenIdent tokenKind = "IDENT"
tokenInt tokenKind = "INT" tokenInt tokenKind = "INT"
tokenFloat tokenKind = "FLOAT" tokenFloat tokenKind = "FLOAT"
tokenString tokenKind = "STRING" tokenString tokenKind = "STRING"
tokenTrue tokenKind = "TRUE" tokenTrue tokenKind = "TRUE"
tokenFalse tokenKind = "FALSE" tokenFalse tokenKind = "FALSE"
tokenNull tokenKind = "NULL" tokenNull tokenKind = "NULL"
tokenImport tokenKind = "IMPORT" tokenImport tokenKind = "IMPORT"
tokenPackage tokenKind = "PACKAGE" tokenPackage tokenKind = "PACKAGE"
tokenClass tokenKind = "CLASS" tokenClass tokenKind = "CLASS"
tokenData tokenKind = "DATA" tokenData tokenKind = "DATA"
tokenWorker tokenKind = "WORKER" tokenWorker tokenKind = "WORKER"
tokenInterface tokenKind = "INTERFACE" tokenInterface tokenKind = "INTERFACE"
tokenEnum tokenKind = "ENUM" tokenEnum tokenKind = "ENUM"
tokenMatch tokenKind = "MATCH" tokenMatch tokenKind = "MATCH"
tokenFun tokenKind = "FUN" tokenFun tokenKind = "FUN"
tokenSuspend tokenKind = "SUSPEND" tokenSuspend tokenKind = "SUSPEND"
tokenOverride tokenKind = "OVERRIDE" tokenOverride tokenKind = "OVERRIDE"
tokenPrivate tokenKind = "PRIVATE" tokenPrivate tokenKind = "PRIVATE"
tokenVal tokenKind = "VAL" tokenVal tokenKind = "VAL"
tokenVar tokenKind = "VAR" tokenVar tokenKind = "VAR"
tokenIf tokenKind = "IF" tokenIf tokenKind = "IF"
tokenElse tokenKind = "ELSE" tokenElse tokenKind = "ELSE"
tokenWhile tokenKind = "WHILE" tokenWhile tokenKind = "WHILE"
tokenFor tokenKind = "FOR" tokenFor tokenKind = "FOR"
tokenIn tokenKind = "IN" tokenIn tokenKind = "IN"
tokenSelect tokenKind = "SELECT" tokenSelect tokenKind = "SELECT"
tokenReturn tokenKind = "RETURN" tokenReturn tokenKind = "RETURN"
tokenGo tokenKind = "GO" tokenGo tokenKind = "GO"
tokenDefer tokenKind = "DEFER" tokenDefer tokenKind = "DEFER"
tokenTry tokenKind = "TRY" tokenTry tokenKind = "TRY"
tokenCatch tokenKind = "CATCH" tokenCatch tokenKind = "CATCH"
tokenThrow tokenKind = "THROW" tokenThrow tokenKind = "THROW"
tokenLParen tokenKind = "(" tokenLParen tokenKind = "("
tokenRParen tokenKind = ")" tokenRParen tokenKind = ")"
tokenLBrace tokenKind = "{" tokenLBrace tokenKind = "{"
tokenRBrace tokenKind = "}" tokenRBrace tokenKind = "}"
tokenLBracket tokenKind = "[" tokenLBracket tokenKind = "["
tokenRBracket tokenKind = "]" tokenRBracket tokenKind = "]"
tokenComma tokenKind = "," tokenComma tokenKind = ","
tokenDot tokenKind = "." tokenDot tokenKind = "."
tokenColon tokenKind = ":" tokenColon tokenKind = ":"
tokenDoubleColon tokenKind = "::" tokenSemicolon tokenKind = ";"
tokenSemicolon tokenKind = ";" tokenPlus tokenKind = "+"
tokenPlus tokenKind = "+" tokenMinus tokenKind = "-"
tokenMinus tokenKind = "-" tokenStar tokenKind = "*"
tokenStar tokenKind = "*" tokenSlash tokenKind = "/"
tokenSlash tokenKind = "/" tokenPercent tokenKind = "%"
tokenPercent tokenKind = "%" tokenBang tokenKind = "!"
tokenBang tokenKind = "!" tokenAssign tokenKind = "="
tokenAssign tokenKind = "=" tokenPlusAssign tokenKind = "+="
tokenPlusAssign tokenKind = "+=" tokenEq tokenKind = "=="
tokenEq tokenKind = "==" tokenNeq tokenKind = "!="
tokenNeq tokenKind = "!=" tokenLt tokenKind = "<"
tokenLt tokenKind = "<" tokenLte tokenKind = "<="
tokenLte tokenKind = "<=" tokenGt tokenKind = ">"
tokenGt tokenKind = ">" tokenGte tokenKind = ">="
tokenGte tokenKind = ">=" tokenAnd tokenKind = "&&"
tokenAnd tokenKind = "&&" tokenAmp tokenKind = "&"
tokenAmp tokenKind = "&" tokenAt tokenKind = "@"
tokenAt tokenKind = "@" tokenQuestion tokenKind = "?"
tokenQuestion tokenKind = "?" tokenSafeDot tokenKind = "?."
tokenSafeDot tokenKind = "?." tokenDoubleBang tokenKind = "!!"
tokenDoubleBang tokenKind = "!!" tokenOr tokenKind = "||"
tokenOr tokenKind = "||" tokenArrow tokenKind = "->"
tokenArrow tokenKind = "->"
) )
var keywords = map[string]tokenKind{ var keywords = map[string]tokenKind{

View file

@ -67,13 +67,13 @@
"prefix": "match", "prefix": "match",
"body": [ "body": [
"match (${1:result}) {", "match (${1:result}) {",
" ${2:Result}::${3:Success}(${4:value}) -> {", " ${2:Result}.${3:Success}(${4:value}) -> {",
" $5", " $5",
" }", " }",
" ${2:Result}::${6:Failure}(${7:reason}) -> {", " ${2:Result}.${6:Failure}(${7:reason}) -> {",
" $8", " $8",
" }", " }",
" ${2:Result}::${9:Pending} -> {", " ${2:Result}.${9:Pending} -> {",
" $0", " $0",
" }", " }",
"}" "}"
@ -84,8 +84,8 @@
"prefix": "matchvalue", "prefix": "matchvalue",
"body": [ "body": [
"val ${1:value} = match (${2:result}) {", "val ${1:value} = match (${2:result}) {",
" ${3:Result}::${4:Success}(${5:item}) -> ${5:item}", " ${3:Result}.${4:Success}(${5:item}) -> ${5:item}",
" ${3:Result}::${6:Failure}(${7:reason}) -> ${7:reason}", " ${3:Result}.${6:Failure}(${7:reason}) -> ${7:reason}",
" $0", " $0",
"}" "}"
], ],
@ -111,7 +111,7 @@
"body": [ "body": [
"fun ${1:name}(${2}): Result<${3:Value}, Error> {", "fun ${1:name}(${2}): Result<${3:Value}, Error> {",
" val ${4:value} = ${5:operation}()?", " val ${4:value} = ${5:operation}()?",
" return Result::Ok(${4:value})", " return Result.Ok(${4:value})",
"}" "}"
], ],
"description": "Function with Rust-style Result propagation" "description": "Function with Rust-style Result propagation"
@ -120,8 +120,8 @@
"prefix": "resultmatch", "prefix": "resultmatch",
"body": [ "body": [
"match (${1:result}) {", "match (${1:result}) {",
" Result::Ok(${2:value}) -> { $3 }", " Result.Ok(${2:value}) -> { $3 }",
" Result::Err(${4:error}) -> { $0 }", " Result.Err(${4:error}) -> { $0 }",
"}" "}"
], ],
"description": "Match a Result value" "description": "Match a Result value"

View file

@ -356,10 +356,6 @@
"name": "keyword.operator.arrow.gotlin", "name": "keyword.operator.arrow.gotlin",
"match": "->" "match": "->"
}, },
{
"name": "punctuation.accessor.enum.gotlin",
"match": "::"
},
{ {
"name": "keyword.operator.arithmetic.gotlin", "name": "keyword.operator.arithmetic.gotlin",
"match": "[+\\-*/%<>]" "match": "[+\\-*/%<>]"