From a95b6391fd353074daf2dbfed4d73e8d57f314ca Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 1 Sep 2022 19:10:00 +0300 Subject: [PATCH] support cstring in `case` (#20130) * implement case for cstring for now just converts to string on C backend * custom implementation for cstring * remove leftover * revert even more * add nil + fix packages weird variant literal bug * update docs --- changelog.md | 4 +++ compiler/ccgstmts.nim | 37 +++++++++++++++++++------- compiler/cgen.nim | 2 +- compiler/condsyms.nim | 1 + compiler/dfa.nim | 2 +- compiler/jsgen.nim | 8 +++--- compiler/optimizer.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/semtypes.nim | 4 ++- doc/manual.md | 5 ++++ lib/system/strmantle.nim | 23 ++++++++++++++++ tests/casestmt/tcstring.nim | 52 +++++++++++++++++++++++++++++++++++++ 13 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 tests/casestmt/tcstring.nim diff --git a/changelog.md b/changelog.md index 61e67161e6..d2a3544a4b 100644 --- a/changelog.md +++ b/changelog.md @@ -136,6 +136,10 @@ let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")] ``` +- `cstring` is now accepted as a selector in `case` statements, removing the + need to convert to `string`. On the JS backend, this is translated directly + to a `switch` statement. + ## Compiler changes - The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 0d17031df2..0980de98fe 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -837,17 +837,27 @@ template genCaseGeneric(p: BProc, t: PNode, d: var TLoc, fixLabel(p, lend) proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, + stringKind: TTypeKind, branches: var openArray[Rope]) = var x: TLoc for i in 0..= $2 && $1 <= $3) goto $4;$n", "if ($1 == $2) goto $3;$n") diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c0b94ebbb0..3896a46caf 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -966,7 +966,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = if containsResult(n[0]): return InitRequired result = InitSkippable var exhaustive = skipTypes(n[0].typ, - abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString} + abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString, tyCstring} for i in 1..", noSideEffect.} diff --git a/tests/casestmt/tcstring.nim b/tests/casestmt/tcstring.nim new file mode 100644 index 0000000000..288373402d --- /dev/null +++ b/tests/casestmt/tcstring.nim @@ -0,0 +1,52 @@ +discard """ + targets: "c cpp js" +""" + +type Result = enum none, a, b, c, d, e, f + +proc foo1(x: cstring): Result = + const y = cstring"hash" + const arr = [cstring"it", cstring"finally"] + result = none + case x + of "Andreas", "Rumpf": result = a + of cstring"aa", "bb": result = b + of "cc", y, "when": result = c + of "will", arr, "be", "generated": result = d + of nil: result = f + +var results = [ + foo1("Rumpf"), foo1("Andreas"), + foo1("aa"), foo1(cstring"bb"), + foo1("cc"), foo1("hash"), + foo1("finally"), foo1("generated"), + foo1("no"), foo1("another no"), + foo1(nil)] +doAssert results == [a, a, b, b, c, c, d, d, none, none, f], $results + +proc foo2(x: cstring): Result = + const y = cstring"hash" + const arr = [cstring"it", cstring"finally"] + doAssert not (compiles do: + result = case x + of "Andreas", "Rumpf": a + of cstring"aa", "bb": b + of "cc", y, "when": c + of "will", arr, "be", "generated": d) + case x + of "Andreas", "Rumpf": a + of cstring"aa", "bb": b + of "cc", y, "when": c + of "will", arr, "be", "generated": d + of nil: f + else: e + +results = [ + foo2("Rumpf"), foo2("Andreas"), + foo2("aa"), foo2(cstring"bb"), + foo2("cc"), foo2("hash"), + foo2("finally"), foo2("generated"), + foo2("no"), foo2("another no"), + foo2(nil)] + +doAssert results == [a, a, b, b, c, c, d, d, e, e, f], $results