this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

all: rename fallback keyword to otherwise

Add the `otherwise` keyword as the canonical form
of the comprehension fallback clause. The legacy
`fallback` keyword remains accepted by the parser
for backward compatibility. The formatter rewrites
`fallback` to `otherwise` on format.

Changes:
- cue/token: add OTHERWISE token alongside FALLBACK
- cue/parser: accept both `fallback` and `otherwise`;
update error messages to reference `otherwise`
- cue/format: emit `otherwise` (not `fallback`)
- internal/astinternal: use `otherwise` in debug str
- doc/ref/spec: update grammar and examples

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: I7b0c649e425a73a02729e581bc737822f4340f17
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1234954
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

+62 -55
+2 -2
cue/format/node.go
··· 230 230 231 231 func fallbackKeyword(n *ast.Comprehension) token.Token { 232 232 if len(n.Clauses) > 1 { 233 - return token.FALLBACK 233 + return token.OTHERWISE 234 234 } else if _, ok := n.Clauses[0].(*ast.ForClause); ok { 235 - return token.FALLBACK 235 + return token.OTHERWISE 236 236 } 237 237 return token.ELSE 238 238 }
+12 -8
cue/parser/parser.go
··· 867 867 sc.closeExpr(p, expr) 868 868 869 869 var fallbackClause *ast.FallbackClause 870 - if p.tok == token.ELSE || p.tok == token.FALLBACK { 870 + if p.tok == token.ELSE || p.tok == token.FALLBACK || p.tok == token.OTHERWISE { 871 871 fallbackClause = p.parseFallbackClause(clauses) 872 872 } 873 873 ··· 951 951 token.STRING, token.INTERPOLATION, 952 952 token.NULL, token.TRUE, token.FALSE, 953 953 token.FOR, token.IF, token.LET, token.IN, 954 - token.TRY, token.ELSE, token.FALLBACK: 954 + token.TRY, token.ELSE, token.FALLBACK, token.OTHERWISE: 955 955 return &ast.EmbedDecl{Expr: expr} 956 956 } 957 957 fallthrough ··· 1042 1042 } 1043 1043 expr = ident 1044 1044 1045 - case token.ELSE, token.FALLBACK: 1045 + case token.ELSE, token.FALLBACK, token.OTHERWISE: 1046 1046 // These keywords can be used as field labels 1047 1047 expr = p.parseExpr() 1048 1048 ··· 1264 1264 var pos token.Pos 1265 1265 if isSingleGuard { 1266 1266 // Single if/try clause: must use else 1267 - if p.tok == token.FALLBACK { 1267 + if p.tok == token.FALLBACK || p.tok == token.OTHERWISE { 1268 1268 p.errf(p.pos, "use 'else' with single 'if' or 'try' clause") 1269 1269 pos = p.pos 1270 1270 p.next() ··· 1272 1272 pos = p.expect(token.ELSE) 1273 1273 } 1274 1274 } else { 1275 - // Everything else: must use fallback 1275 + // Everything else: must use otherwise (or legacy fallback) 1276 1276 if p.tok == token.ELSE { 1277 - p.errf(p.pos, "use 'fallback' for comprehensions with multiple clauses or 'for' clauses") 1277 + p.errf(p.pos, "use 'otherwise' for comprehensions with multiple clauses or 'for' clauses") 1278 1278 pos = p.pos 1279 1279 p.next() 1280 1280 } else { 1281 - pos = p.expect(token.FALLBACK) 1281 + // Accept both 'otherwise' (primary) and 'fallback' (legacy alias) 1282 + // TODO: once support for fallback token is removed, use 1283 + // p.expect(token.OTHERWISE) here instead. 1284 + pos = p.pos 1285 + p.next() 1282 1286 } 1283 1287 } 1284 1288 body := p.parseStruct() ··· 1410 1414 sc.closeExpr(p, expr) 1411 1415 1412 1416 var fallbackClause *ast.FallbackClause 1413 - if p.tok == token.ELSE || p.tok == token.FALLBACK { 1417 + if p.tok == token.ELSE || p.tok == token.FALLBACK || p.tok == token.OTHERWISE { 1414 1418 fallbackClause = p.parseFallbackClause(clauses) 1415 1419 } 1416 1420
+19 -19
cue/parser/parser_test.go
··· 557 557 for x in [] { "\(x)": x } fallback { empty: true } 558 558 } 559 559 }`, 560 - out: `@experiment(try), {a: {for x in [] {"\(x)": x} fallback {empty: true}}}`, 560 + out: `@experiment(try), {a: {for x in [] {"\(x)": x} otherwise {empty: true}}}`, 561 561 }, 562 562 { 563 563 desc: "multi-clause comprehension with fallback", ··· 568 568 for x in [1,2] if x > 10 { "\(x)": x } fallback { none: true } 569 569 } 570 570 }`, 571 - out: `@experiment(try), {a: {for x in [1, 2] if x>10 {"\(x)": x} fallback {none: true}}}`, 571 + out: `@experiment(try), {a: {for x in [1, 2] if x>10 {"\(x)": x} otherwise {none: true}}}`, 572 572 }, 573 573 { 574 574 desc: "list comprehension with fallback", ··· 577 577 { 578 578 a: [for x in [] { x } fallback { 0 }] 579 579 }`, 580 - out: `@experiment(try), {a: [for x in [] {x} fallback {0}]}`, 580 + out: `@experiment(try), {a: [for x in [] {x} otherwise {0}]}`, 581 581 }, 582 582 { 583 583 desc: "try struct form", ··· 682 682 for x in [] { "\(x)": x } fallback { empty: true } 683 683 } 684 684 }`, 685 - out: `{a: {for x in [] {"\(x)": x} fallback {empty: true}}} 685 + out: `{a: {for x in [] {"\(x)": x} otherwise {empty: true}}} 686 686 fallback requires @experiment(try)`, 687 687 }, 688 688 { ··· 692 692 a: { 693 693 if true if false { x: 1 } else { y: 2 } 694 694 }`, 695 - out: `@experiment(try), a: {if true if false {x: 1} fallback {y: 2}} 696 - use 'fallback' for comprehensions with multiple clauses or 'for' clauses`, 695 + out: `@experiment(try), a: {if true if false {x: 1} otherwise {y: 2}} 696 + use 'otherwise' for comprehensions with multiple clauses or 'for' clauses`, 697 697 }, 698 698 { 699 699 desc: "else with chained try error", ··· 702 702 a: { 703 703 try x = val? try y = val2? { result: x } else { fallback: 0 } 704 704 }`, 705 - out: `@experiment(try), a: {try x = val? try y = val2? {result: x} fallback {fallback: 0}} 706 - use 'fallback' for comprehensions with multiple clauses or 'for' clauses`, 705 + out: `@experiment(try), a: {try x = val? try y = val2? {result: x} otherwise {fallback: 0}} 706 + use 'otherwise' for comprehensions with multiple clauses or 'for' clauses`, 707 707 }, 708 708 { 709 709 desc: "else with if and let error", ··· 712 712 a: { 713 713 if true let x = 5 { y: x } else { z: 0 } 714 714 }`, 715 - out: `@experiment(try), a: {if true let x=5 {y: x} fallback {z: 0}} 716 - use 'fallback' for comprehensions with multiple clauses or 'for' clauses`, 715 + out: `@experiment(try), a: {if true let x=5 {y: x} otherwise {z: 0}} 716 + use 'otherwise' for comprehensions with multiple clauses or 'for' clauses`, 717 717 }, 718 718 { 719 719 desc: "else with if and try error", ··· 722 722 a: { 723 723 if true try { x: val? } else { y: 0 } 724 724 }`, 725 - out: `@experiment(try), a: {if true try {x: val?} fallback {y: 0}} 726 - use 'fallback' for comprehensions with multiple clauses or 'for' clauses`, 725 + out: `@experiment(try), a: {if true try {x: val?} otherwise {y: 0}} 726 + use 'otherwise' for comprehensions with multiple clauses or 'for' clauses`, 727 727 }, 728 728 { 729 729 desc: "else with for clause error", ··· 732 732 a: { 733 733 if true for x in [] { y: x } else { empty: true } 734 734 }`, 735 - out: `@experiment(try), a: {if true for x in [] {y: x} fallback {empty: true}} 736 - use 'fallback' for comprehensions with multiple clauses or 'for' clauses`, 735 + out: `@experiment(try), a: {if true for x in [] {y: x} otherwise {empty: true}} 736 + use 'otherwise' for comprehensions with multiple clauses or 'for' clauses`, 737 737 }, 738 738 { 739 739 desc: "fallback without for clause error", ··· 770 770 a: { 771 771 for x in [] { y: x } fallback { empty: true } 772 772 }`, 773 - out: `@experiment(try), a: {for x in [] {y: x} fallback {empty: true}}`, 773 + out: `@experiment(try), a: {for x in [] {y: x} otherwise {empty: true}}`, 774 774 }, 775 775 { 776 776 desc: "for with if and fallback allowed", ··· 779 779 a: { 780 780 for x in list if x > 0 { y: x } fallback { empty: true } 781 781 }`, 782 - out: `@experiment(try), a: {for x in list if x>0 {y: x} fallback {empty: true}}`, 782 + out: `@experiment(try), a: {for x in list if x>0 {y: x} otherwise {empty: true}}`, 783 783 }, 784 784 { 785 785 desc: "if with for and fallback allowed", ··· 788 788 a: { 789 789 if true for x in list { y: x } fallback { empty: true } 790 790 }`, 791 - out: `@experiment(try), a: {if true for x in list {y: x} fallback {empty: true}}`, 791 + out: `@experiment(try), a: {if true for x in list {y: x} otherwise {empty: true}}`, 792 792 }, 793 793 { 794 794 desc: "two if clauses with fallback allowed", ··· 797 797 a: { 798 798 if cond1 if cond2 { a: 1 } fallback { b: 2 } 799 799 }`, 800 - out: `@experiment(try), a: {if cond1 if cond2 {a: 1} fallback {b: 2}}`, 800 + out: `@experiment(try), a: {if cond1 if cond2 {a: 1} otherwise {b: 2}}`, 801 801 }, 802 802 { 803 803 desc: "two try clauses with fallback allowed", ··· 806 806 a: { 807 807 try x = a? try y = b? { result: x + y } fallback { default: 0 } 808 808 }`, 809 - out: `@experiment(try), a: {try x = a? try y = b? {result: x+y} fallback {default: 0}}`, 809 + out: `@experiment(try), a: {try x = a? try y = b? {result: x+y} otherwise {default: 0}}`, 810 810 }, 811 811 { 812 812 desc: "let declaration",
+1 -1
cue/testdata/comprehensions/else_compile_errors.txtar
··· 19 19 // - Mixed if/try with else: if cond try { x } else { y } 20 20 // - if + for with else: if cond for x in [] { x } else { y } 21 21 // These all produce parser error: "else clause only allowed with single 'if' or 'try' clause" 22 - // or "use 'fallback' with 'for' clauses" 22 + // or "use 'otherwise' with 'for' clauses" 23 23 -- out/eval/stats -- 24 24 Leaks: 0 25 25 Freed: 2
+9 -7
cue/token/token.go
··· 95 95 96 96 keywordBeg 97 97 98 - IF // if 99 - ELSE // else 100 - FOR // for 101 - IN // in 102 - LET // let 103 - TRY // try 104 - FALLBACK // fallback 98 + IF // if 99 + ELSE // else 100 + FOR // for 101 + IN // in 102 + LET // let 103 + TRY // try 104 + // TODO: remove in favor of OTHERWISE 105 + FALLBACK // fallback 106 + OTHERWISE // otherwise 105 107 // experimental 106 108 FUNC // func 107 109
+8 -7
cue/token/token_string.go
··· 63 63 _ = x[LET-52] 64 64 _ = x[TRY-53] 65 65 _ = x[FALLBACK-54] 66 - _ = x[FUNC-55] 67 - _ = x[TRUE-56] 68 - _ = x[FALSE-57] 69 - _ = x[NULL-58] 70 - _ = x[keywordEnd-59] 66 + _ = x[OTHERWISE-55] 67 + _ = x[FUNC-56] 68 + _ = x[TRUE-57] 69 + _ = x[FALSE-58] 70 + _ = x[NULL-59] 71 + _ = x[keywordEnd-60] 71 72 } 72 73 73 - const _Token_name = "ILLEGALEOFCOMMENTATTRIBUTEliteralBegIDENTINTFLOATSTRINGINTERPOLATION_|_literalEndoperatorBeg+-*^/&|&&||===<>!<-!=<=>==~!~([{,....)]};:?~operatorEndkeywordBegifelseforinlettryfallbackfunctruefalsenullkeywordEnd" 74 + const _Token_name = "ILLEGALEOFCOMMENTATTRIBUTEliteralBegIDENTINTFLOATSTRINGINTERPOLATION_|_literalEndoperatorBeg+-*^/&|&&||===<>!<-!=<=>==~!~([{,....)]};:?~operatorEndkeywordBegifelseforinlettryfallbackotherwisefunctruefalsenullkeywordEnd" 74 75 75 - var _Token_index = [...]uint8{0, 7, 10, 17, 26, 36, 41, 44, 49, 55, 68, 71, 81, 92, 93, 94, 95, 96, 97, 98, 99, 101, 103, 104, 106, 107, 108, 109, 111, 113, 115, 117, 119, 121, 122, 123, 124, 125, 126, 129, 130, 131, 132, 133, 134, 135, 136, 147, 157, 159, 163, 166, 168, 171, 174, 182, 186, 190, 195, 199, 209} 76 + var _Token_index = [...]uint8{0, 7, 10, 17, 26, 36, 41, 44, 49, 55, 68, 71, 81, 92, 93, 94, 95, 96, 97, 98, 99, 101, 103, 104, 106, 107, 108, 109, 111, 113, 115, 117, 119, 121, 122, 123, 124, 125, 126, 129, 130, 131, 132, 133, 134, 135, 136, 147, 157, 159, 163, 166, 168, 171, 174, 182, 191, 195, 199, 204, 208, 218} 76 77 77 78 func (i Token) String() string { 78 79 idx := int(i) - 0
+3 -3
internal/astinternal/debug.go
··· 422 422 out := DebugStr(v.Clauses) 423 423 out += DebugStr(v.Value) 424 424 if v.Fallback != nil { 425 - // Use "fallback" for 'for' comprehensions, "else" for 'if'/'try' 425 + // Use "otherwise" for 'for' comprehensions, "else" for 'if'/'try' 426 426 kw := "else" 427 427 if len(v.Clauses) > 1 { 428 - kw = "fallback" 428 + kw = "otherwise" 429 429 } else if _, ok := v.Clauses[0].(*ast.ForClause); ok { 430 - kw = "fallback" 430 + kw = "otherwise" 431 431 } 432 432 out += " " + kw + " " + DebugStr(v.Fallback.Body) 433 433 }
+8 -8
internal/core/export/testdata/main/else.txtar
··· 36 36 forFallback: { 37 37 for x in [] { 38 38 "\(x)": x 39 - } fallback { 39 + } otherwise { 40 40 empty: true 41 41 } 42 42 } ··· 46 46 let val = 10 47 47 for x in [] { 48 48 x 49 - } fallback { 49 + } otherwise { 50 50 fallbackField: val 51 51 } 52 52 } ··· 74 74 for x in [] { 75 75 "\(x)": x 76 76 - } else { 77 - + } fallback { 77 + + } otherwise { 78 78 empty: true 79 79 } 80 80 } ··· 88 88 x 89 89 - } else { 90 90 - fallback: val 91 - + } fallback { 91 + + } otherwise { 92 92 + fallbackField: val 93 93 } 94 94 } ··· 110 110 forFallback: { 111 111 for x in [] { 112 112 "\(x)": x 113 - } fallback { 113 + } otherwise { 114 114 empty: true 115 115 } 116 116 } ··· 120 120 let val = 10 121 121 for x in [] { 122 122 x 123 - } fallback { 123 + } otherwise { 124 124 fallbackField: val 125 125 } 126 126 } ··· 148 148 for x in [] { 149 149 "\(x)": x 150 150 - } else { 151 - + } fallback { 151 + + } otherwise { 152 152 empty: true 153 153 } 154 154 } ··· 162 162 x 163 163 - } else { 164 164 - fallback: val 165 - + } fallback { 165 + + } otherwise { 166 166 + fallbackField: val 167 167 } 168 168 }