mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 09:24:36 +00:00
implemented case expressions
This commit is contained in:
@@ -781,6 +781,11 @@ proc add*(father, son: PNode) =
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
# son access operators with support for negative indices
|
||||
template `{}`*(n: PNode, i: int): expr = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
var emptyNode* = newNode(nkEmpty)
|
||||
# There is a single empty node that is shared! Do not overwrite it!
|
||||
|
||||
|
||||
@@ -743,7 +743,7 @@ proc isExprStart(p: TParser): bool =
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
|
||||
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
|
||||
tkTuple, tkType, tkWhen:
|
||||
tkTuple, tkType, tkWhen, tkCase:
|
||||
result = true
|
||||
else: result = false
|
||||
|
||||
@@ -763,9 +763,9 @@ proc parseExpr(p: var TParser): PNode =
|
||||
case p.tok.tokType:
|
||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||
of tkCase: result = parseCase(p)
|
||||
else: result = lowestExpr(p)
|
||||
# XXX needs proper support:
|
||||
#of tkCase: result = parseCase(p)
|
||||
#of tkTry: result = parseTry(p)
|
||||
|
||||
proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||
@@ -1044,9 +1044,9 @@ proc parseCase(p: var TParser): PNode =
|
||||
if b.kind == nkElse: break
|
||||
|
||||
if wasIndented:
|
||||
eat(p, tkDed)
|
||||
if p.tok.tokType != tkEof: eat(p, tkDed)
|
||||
popInd(p.lex)
|
||||
|
||||
|
||||
proc parseTry(p: var TParser): PNode =
|
||||
result = newNodeP(nkTryStmt, p)
|
||||
getTok(p)
|
||||
|
||||
@@ -1528,6 +1528,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
|
||||
renderTree(a, {renderNoComments}))
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
|
||||
# The case expression is simply rewritten to a StmtListExpr:
|
||||
# var res {.noInit, genSym.}: type(values)
|
||||
#
|
||||
# case E
|
||||
# of X: res = value1
|
||||
# of Y: res = value2
|
||||
#
|
||||
# res
|
||||
var
|
||||
info = caseStmt.info
|
||||
resVar = newSym(skVar, getIdent":res", getCurrOwner(), info)
|
||||
resNode = newSymNode(resVar, info)
|
||||
resType: PType
|
||||
|
||||
resVar.flags = { sfGenSym, sfNoInit }
|
||||
|
||||
for i in countup(1, caseStmt.len - 1):
|
||||
var cs = caseStmt[i]
|
||||
case cs.kind
|
||||
of nkOfBranch, nkElifBranch, nkElse:
|
||||
# the value is always the last son regardless of the branch kind
|
||||
cs.checkMinSonsLen 1
|
||||
var value = cs{-1}
|
||||
if value.kind == nkStmtList: value.kind = nkStmtListExpr
|
||||
|
||||
value = semExprWithType(c, value)
|
||||
if resType == nil:
|
||||
resType = value.typ
|
||||
elif not sameType(resType, value.typ):
|
||||
# XXX: semeType is a bit too harsh.
|
||||
# work on finding a common base type.
|
||||
# this will be useful for arrays/seq too:
|
||||
# [ref DerivedA, ref DerivedB, ref Base]
|
||||
typeMismatch(cs, resType, value.typ)
|
||||
|
||||
cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value])
|
||||
else:
|
||||
IllFormedAst(caseStmt)
|
||||
|
||||
result = newNode(nkStmtListExpr, info, @[
|
||||
newNode(nkVarSection, info, @[
|
||||
newNode(nkIdentDefs, info, @[
|
||||
resNode,
|
||||
symNodeFromType(c, resType, info),
|
||||
emptyNode])]),
|
||||
caseStmt,
|
||||
resNode])
|
||||
|
||||
result = semStmtListExpr(c, result)
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = n
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
@@ -1707,7 +1758,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkTryStmt: result = semTry(c, n)
|
||||
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
||||
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
||||
of nkCaseStmt: result = semCase(c, n)
|
||||
of nkCaseStmt:
|
||||
if efWantStmt in flags: result = semCase(c, n)
|
||||
else: result = semCaseExpr(c, n)
|
||||
of nkReturnStmt: result = semReturn(c, n)
|
||||
of nkAsmStmt: result = semAsm(c, n)
|
||||
of nkYieldStmt: result = semYield(c, n)
|
||||
|
||||
@@ -2237,6 +2237,28 @@ An if expression always results in a value, so the ``else`` part is
|
||||
required. ``Elif`` parts are also allowed (but unlikely to be good
|
||||
style).
|
||||
|
||||
When expression
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Just like an `if expression`, but corresponding to the when statement.
|
||||
|
||||
Case expression
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The `case expression` is again very similar to the case statement:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var favoriteFood = case animal
|
||||
of "dog": "bones"
|
||||
of "cat": "mice"
|
||||
elif animal.endsWith"whale": "plankton"
|
||||
else:
|
||||
echo "I'm not sure what to serve, but everybody loves ice cream"
|
||||
"ice cream"
|
||||
|
||||
As seen in the above example, the case expression can also introduce side
|
||||
effects. When multiple statements are given for a branch, Nimrod will use
|
||||
the last expression as the result value, much like in an `expr` template.
|
||||
|
||||
Table constructor
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -3464,15 +3486,14 @@ a type-safe wrapper for the unsafe `printf` function form C:
|
||||
macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr =
|
||||
var i = 0
|
||||
for c in formatChars(formatString):
|
||||
const FormatChars = {
|
||||
'c': char,
|
||||
'd', 'i', 'x', 'X': int,
|
||||
'f', 'e', 'E', 'g', 'G': float,
|
||||
's': string,
|
||||
'p': pointer,
|
||||
}
|
||||
var expectedType = case c
|
||||
of 'c': char
|
||||
of 'd', 'i', 'x', 'X': int
|
||||
of 'f', 'e', 'E', 'g', 'G': float
|
||||
of 's': string
|
||||
of 'p': pointer
|
||||
else: EOutOfRange
|
||||
|
||||
var expectedType = find(FormatChars, c, EOutOfRange)
|
||||
var actualType = args[i].getType
|
||||
inc i
|
||||
|
||||
|
||||
@@ -2116,7 +2116,7 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
|
||||
## integer division that results in a float.
|
||||
result = toFloat(x) / toFloat(y)
|
||||
|
||||
template `-|`(b, s: expr): expr =
|
||||
template `-|`*(b, s: expr): expr =
|
||||
(if b >= 0: b else: s.len + b)
|
||||
|
||||
proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =
|
||||
|
||||
30
tests/reject/tcaseexpr1.nim
Normal file
30
tests/reject/tcaseexpr1.nim
Normal file
@@ -0,0 +1,30 @@
|
||||
discard """
|
||||
file: "tcaseexpr1.nim"
|
||||
|
||||
line: 23
|
||||
errormsg: "not all cases are covered"
|
||||
|
||||
line: 29
|
||||
errormsg: "type mismatch: got (string) but expected 'int'"
|
||||
"""
|
||||
|
||||
type
|
||||
E = enum A, B, C
|
||||
|
||||
proc foo(x): auto =
|
||||
return case x
|
||||
of 1..9: "digit"
|
||||
else: "number"
|
||||
|
||||
var r = foo(10)
|
||||
|
||||
var x = C
|
||||
|
||||
var t1 = case x:
|
||||
of A: "a"
|
||||
of B: "b"
|
||||
|
||||
var t2 = case x:
|
||||
of A: 10
|
||||
of B, C: "23"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
file: "tcasestm.nim"
|
||||
output: "ayyy"
|
||||
output: "ayyydd"
|
||||
"""
|
||||
# Test the case statement
|
||||
|
||||
@@ -22,16 +22,18 @@ of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
|
||||
of "cc", "hash", "when": nil
|
||||
of "will", "it", "finally", "be", "generated": nil
|
||||
|
||||
case i
|
||||
of 1..5, 8, 9: nil
|
||||
of 6, 7: nil
|
||||
elif x == "Ha":
|
||||
nil
|
||||
elif x == "yyy":
|
||||
write(stdout, x)
|
||||
else:
|
||||
nil
|
||||
var z = case i
|
||||
of 1..5, 8, 9: "aa"
|
||||
of 6, 7: "bb"
|
||||
elif x == "Ha":
|
||||
"cc"
|
||||
elif x == "yyy":
|
||||
write(stdout, x)
|
||||
"dd"
|
||||
else:
|
||||
"zz"
|
||||
|
||||
echo z
|
||||
#OUT ayyy
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ Compiler Additions
|
||||
Language Additions
|
||||
------------------
|
||||
|
||||
- ``case expressions`` are now supported.
|
||||
- table constructors now mimic more closely the syntax of case... of...
|
||||
- Nimrod can now infer the return type of a proc from its body
|
||||
|
||||
|
||||
2012-09-23 Version 0.9.0 released
|
||||
|
||||
Reference in New Issue
Block a user