diff --git a/book/src/super-sql/expressions/match.md b/book/src/super-sql/expressions/match.md index db77fe66e..5688f660d 100644 --- a/book/src/super-sql/expressions/match.md +++ b/book/src/super-sql/expressions/match.md @@ -4,15 +4,15 @@ A match expression is a multi-way [type assertion](type-assertions.md) that selects a result according to the type of a value and has the form ``` match [:=] [ with ] -case [then] -[ case [then] ] +when [then] +[ when [then] ] ... [ else ] [ end ] ``` where `` is any [expression](intro.md) and each `` is any [type](../types/intro.md). The value of `` is compared with each type -in turn and the result of the first matching `case` becomes the value of the +in turn and the result of the first matching `when` becomes the value of the match expression. A value matches a type by the same rules as a [type assertion](type-assertions.md), so a value of a [union](../types/union.md), option, or fusion type matches the type of @@ -26,9 +26,9 @@ unless a case has its type. A result is evaluated with `this` bound to the value of `` asserted to the type of its case, i.e., `.()`, so `this` in -`match x case int64 this+1` is an `int64`. The else result is evaluated +`match x when int64 this+1` is an `int64`. The else result is evaluated with `this` bound to the value of ``. To keep the rest of a record, -use a [spread](../types/record.md), e.g., `{...this,x:match x case int64 this+1 else 0}`. +use a [spread](../types/record.md), e.g., `{...this,x:match x when int64 this+1 else 0}`. To refer to other values in a result, give the match a name with `:=` or list the values in a `with` clause. Then `this` in a result is a record @@ -37,12 +37,12 @@ are the `with` values, where each field's name is given with `:=` or, as for [put](../operators/put.md), derived from its expression (e.g., `upper(s)` is named `upper` and `this` is named `that`). For example, ``` -match s:=upper(s) with that:=this case string s||that.suffix +match s:=upper(s) with that:=this when string s||that.suffix ``` evaluates its result on `{s:upper(s).(string),that:this}`. The `then` and `end` keywords are optional. Without `end`, a nested match -extends as far as possible, i.e., any `case` or `else` that follows belongs to +extends as far as possible, i.e., any `when` or `else` that follows belongs to the innermost match, so a nested match should be parenthesized or ended with `end`. @@ -55,8 +55,8 @@ _Dispatch on the type of a value_ ```mdtest-spq # spq values match this - case int64 this+1 - case string upper(this) + when int64 this+1 + when string upper(this) else "other" # input 1 @@ -78,8 +78,8 @@ type Push = {ref:string} type Watch = {action:string} values cast(this, ) | values match this - case Push "push to "||ref - case Watch "watch "||action + when Push "push to "||ref + when Watch "watch "||action # input {ref:"main"} {action:"started"} @@ -94,7 +94,7 @@ _Refer to other values with a with clause_ ```mdtest-spq # spq -values match x with y case int64 x+y case string x else y +values match x with y when int64 x+y when string x else y # input {x:1,y:10} {x:"a",y:20} @@ -111,7 +111,7 @@ _Without an else, an unmatched value is none_ ```mdtest-spq # spq -values {n:match x case int64 this*2} +values {n:match x when int64 this*2} # input {x:1} {x:"a"} @@ -127,8 +127,8 @@ _Errors pass through unless a case has an error type_ ```mdtest-spq # spq values { - passed: match this case int64 this else 0, - caught: match this case int64 this case error(string) "caught" else 0 + passed: match this when int64 this else 0, + caught: match this when int64 this when error(string) "caught" else 0 } # input 1 diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 18a21f7f4..55ab417f4 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -9089,7 +9089,7 @@ var g = &grammar{ }, &ruleRefExpr{ pos: position{line: 1366, col: 7, offset: 33737}, - name: "CASE", + name: "WHEN", }, &ruleRefExpr{ pos: position{line: 1366, col: 12, offset: 33742}, diff --git a/compiler/parser/parser.peg b/compiler/parser/parser.peg index 3e042cb85..b6013a46d 100644 --- a/compiler/parser/parser.peg +++ b/compiler/parser/parser.peg @@ -1363,7 +1363,7 @@ MatchExpr } MatchCase - = _ CASE _ typ:Type (_ THEN)? _ expr:Expr { + = _ WHEN _ typ:Type (_ THEN)? _ expr:Expr { return ast.MatchCase{ Type: typ.(ast.Type), Expr: expr.(ast.Expr), diff --git a/compiler/parser/valid.spq b/compiler/parser/valid.spq index b2f89e39a..696bc1099 100644 --- a/compiler/parser/valid.spq +++ b/compiler/parser/valid.spq @@ -47,4 +47,4 @@ insert into "t" from 'x.json' | where a > 1; const x = 1; values x insert into baz (values 1,2|{x:this,y:this*2}); insert into baz (select 5, 6) values a.(string) ?? "x", b.(int64|string), this.({x:int64}).x, c.d.(foo)?.e -values match x case int64 this+1 case string then upper(this) else 0 end, match this case {a:int64} a case Push ref, match s:=upper(s) with that:=this, n case string that.n else 0 +values match x when int64 this+1 when string then upper(this) else 0 end, match this when {a:int64} a when Push ref, match s:=upper(s) with that:=this, n when string that.n else 0 diff --git a/compiler/sfmt/ast.go b/compiler/sfmt/ast.go index 7566e3c0e..58d884828 100644 --- a/compiler/sfmt/ast.go +++ b/compiler/sfmt/ast.go @@ -161,7 +161,7 @@ func (c *canon) expr(e ast.Expr, parent string) { c.assignments(e.With) } for _, mc := range e.Cases { - c.write(" case ") + c.write(" when ") c.typ(mc.Type) c.write(" then ") c.expr(mc.Expr, "") diff --git a/compiler/sfmt/dag.go b/compiler/sfmt/dag.go index 7c660e936..dd4f2f75a 100644 --- a/compiler/sfmt/dag.go +++ b/compiler/sfmt/dag.go @@ -130,7 +130,7 @@ func (c *canonDAG) expr(e dag.Expr, parent string) { c.write("match ") c.expr(e.Expr, "") for _, mc := range e.Cases { - c.write(" case ") + c.write(" when ") c.expr(mc.Type, "") if _, ok := mc.Input.(*dag.RecordExpr); ok { c.write(" input ") diff --git a/runtime/ztests/expr/derive-name-noneish.yaml b/runtime/ztests/expr/derive-name-noneish.yaml index 6b2c5698a..2a081ac02 100644 --- a/runtime/ztests/expr/derive-name-noneish.yaml +++ b/runtime/ztests/expr/derive-name-noneish.yaml @@ -2,7 +2,7 @@ # from it (e.g., by put, aggregate, a record expression, or match). spq: | put o?.y - | values this, {p.o?.y}, match o?.y with o?.z case int64 y+(z ?? 0) else 0 + | values this, {p.o?.y}, match o?.y with o?.z when int64 y+(z ?? 0) else 0 input: | {o:some({y:1,z:2}),p:{o:some({y:3})}} diff --git a/runtime/ztests/expr/match.yaml b/runtime/ztests/expr/match.yaml index 4cd0bfe95..f3fc42b90 100644 --- a/runtime/ztests/expr/match.yaml +++ b/runtime/ztests/expr/match.yaml @@ -3,9 +3,9 @@ # result on the matched value. spq: | values match this - case int64 then this+1 - case string upper(this) - case {a:int64} a + when int64 then this+1 + when string upper(this) + when {a:int64} a else "other" end @@ -25,7 +25,7 @@ output: | # Unions, options, and fusions match their underlying values. (An option # may be none, which no case matches, so an else is needed.) -spq: values match x case int64 this+1 case string this||"!" else "none" +spq: values match x when int64 this+1 when string this||"!" else "none" input: | {x:1::(int64|string)} @@ -40,7 +40,7 @@ output: | --- # Any expression may be matched and an unmatched value is none. -spq: values {v:match a.b case int64 this*10} +spq: values {v:match a.b when int64 this*10} input: | {a:{b:1}} @@ -53,7 +53,7 @@ output: | --- # A union-type case matches any of its members. -spq: values match this case int64|string "scalar" else "other" +spq: values match this when int64|string "scalar" else "other" input: | 1 @@ -69,8 +69,8 @@ output: | # Errors and missing pass through unless a case has an error type. spq: | - values match this case int64 this, - match this case error(string) "caught" else "ok" + values match this when int64 this, + match this when error(string) "caught" else "ok" input: | 1 @@ -87,7 +87,7 @@ output: | # A match covering all members of a union has no none in its type. spq: | values cast(this, ) - | values typeof(match this case int64 "i" case string "s") + | values typeof(match this when int64 "i" when string "s") input: | 1 @@ -98,7 +98,7 @@ output: | --- # Without end, else belongs to the innermost match. -spq: values match this case int64 match this case int64 "inner" else "x" case string "s" +spq: values match this when int64 match this when int64 "inner" else "x" when string "s" input: | 1 @@ -111,11 +111,11 @@ output: | --- # A match without an else may be none, which must be handled. -spq: values (match this case int64 this) + 1 +spq: values (match this when int64 this) + 1 error: | int64|none: none not handled (consider ?? or ?.) at line 1, column 9: - values (match this case int64 this) + 1 + values (match this when int64 this) + 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~ --- @@ -135,9 +135,9 @@ output: | # (including an option's none) matches its option type, and the first case # whose type the value has wins. spq: | - values match this case option(int64) "option" case int64 "int64" else "other", - match this case int64 "member" case int64|string "union" else "other", - match this case int64|string "union" case int64 "member" else "other" + values match this when option(int64) "option" when int64 "int64" else "other", + match this when int64 "member" when int64|string "union" else "other", + match this when int64|string "union" when int64 "member" else "other" input: | some(1) @@ -158,7 +158,7 @@ output: | --- # A subquery in a case has the case's input as its input. -spq: values match x case int64 then (values this+1) else 0 +spq: values match x when int64 then (values this+1) else 0 input: | {x:1::(int64|string)} @@ -175,7 +175,7 @@ output: | # A match with a with clause has a record input whose first field is the # (asserted) matched value and whose other fields are the with values. # Names are derived from the expressions as for put. -spq: values match x with y case int64 x+y case string x else y +spq: values match x with y when int64 x+y when string x else y input: | {x:1,y:10} @@ -192,9 +192,9 @@ output: | # A derived name for a function call is the function's name and for this is # "that", and a name may be given with :=. spq: | - values match upper(s) with this case string upper||"/"||that.s else "", - match s:=upper(s) with that:=this case string s||"/"||that.s else "", - match s:=upper(s) case string s||"!" else "" + values match upper(s) with this when string upper||"/"||that.s else "", + match s:=upper(s) with that:=this when string s||"/"||that.s else "", + match s:=upper(s) when string s||"!" else "" input: | {s:"a"} @@ -207,12 +207,12 @@ output: | --- # The field names of a match's input must be unique. -spq: values match x with x case int64 1 else 0 +spq: values match x with x when int64 1 else 0 input: | {x:1} error: | match: duplicate field name "x" at line 1, column 21: - values match x with x case int64 1 else 0 + values match x with x when int64 1 else 0 ~