summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-10-01 23:48:37 +0300
committerZahary Karadjov <zahary@gmail.com>2012-10-03 01:59:49 +0300
commit770d4a997eab25a04cdfd83b325491a2e63bea08 (patch)
tree54f7302645b240942ed43428586489d7df36377c /compiler
parent92f70b08f9c4d6108f61f37c29c1b001c6173a19 (diff)
downloadNim-770d4a997eab25a04cdfd83b325491a2e63bea08.tar.gz
implemented case expressions
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim5
-rwxr-xr-xcompiler/parser.nim8
-rwxr-xr-xcompiler/semexprs.nim55
3 files changed, 63 insertions, 5 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index c6e4d8318..aa94644aa 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -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!
 
diff --git a/compiler/parser.nim b/compiler/parser.nim
index cdbe42c7e..7612980c5 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -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)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 17e6e8048..a658f7f44 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -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)