summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2014-03-15 10:50:14 +0200
committerZahary Karadjov <zahary@gmail.com>2014-03-16 20:42:06 +0200
commit7080d02af47cdc459aa441baa76d06f32af2f1c3 (patch)
tree101b23f4265fa9d1c20d2938b07bc6ee00bc24ad /compiler
parent63d93ad1ab6d491d8fdf4bdb7f958a21e89c2785 (diff)
downloadNim-7080d02af47cdc459aa441baa76d06f32af2f1c3.tar.gz
allow multi-line expressions using the dot operator
this enables parsing of expressions like:

``` Nimrod
s.items
  .map(proc (x): auto = x * 2)
  .filter do (x) -> auto:
    return x % 2 == 0
  .group_by((x) => x.length)
```
Diffstat (limited to 'compiler')
-rw-r--r--compiler/lexer.nim9
-rw-r--r--compiler/parser.nim16
2 files changed, 17 insertions, 8 deletions
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 9c6c5e22f..be152eb55 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -101,6 +101,7 @@ type
     base10,                   # base10 is listed as the first element,
                               # so that it is the correct default value
     base2, base8, base16
+
   TToken* = object            # a Nimrod token
     tokType*: TTokType        # the type of the token
     indent*: int              # the indentation; != -1 if the token has been
@@ -121,8 +122,9 @@ type
     indentAhead*: int         # if > 0 an indendation has already been read
                               # this is needed because scanning comments
                               # needs so much look-ahead
+    currLineIndent*: int
     strongSpaces*: bool
-  
+
 
 var gLinesCompiled*: int  # all lines that have been compiled
 
@@ -206,6 +208,7 @@ proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
   lex.indentAhead = - 1
+  lex.currLineIndent = 0
   inc(lex.lineNumber, inputstream.lineOffset) 
 
 proc closeLexer(lex: var TLexer) = 
@@ -709,6 +712,7 @@ proc skip(L: var TLexer, tok: var TToken) =
       tok.strongSpaceA = 0
       if buf[pos] > ' ':
         tok.indent = indent
+        L.currLineIndent = indent
         break
     else:
       break                   # EndOfFile also leaves the loop
@@ -718,6 +722,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
   fillToken(tok)
   if L.indentAhead >= 0:
     tok.indent = L.indentAhead
+    L.currLineIndent = L.indentAhead
     L.indentAhead = -1
   else:
     tok.indent = -1
@@ -827,5 +832,5 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
         tok.tokType = tkInvalid
         lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
         inc(L.bufpos)
-  
+
 dummyIdent = getIdent("")
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 4ef5a300c..060629518 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -658,7 +658,7 @@ proc namedParams(p: var TParser, callee: PNode,
   exprColonEqExprListAux(p, endTok, result)
 
 proc parseMacroColon(p: var TParser, x: PNode): PNode
-proc primarySuffix(p: var TParser, r: PNode): PNode =
+proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|               | doBlocks
   #|               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
@@ -666,7 +666,8 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
   #|               | '{' optInd indexExprList optPar '}'
   #|               | &( '`'|IDENT|literal|'cast') expr # command syntax
   result = r
-  while p.tok.indent < 0:
+  while p.tok.indent < 0 or
+       (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
     case p.tok.tokType
     of tkParLe:
       if p.strongSpaces and p.tok.strongSpaceA > 0: break
@@ -1007,8 +1008,9 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     optInd(p, a)
     if isSigil: 
       #XXX prefix operators
+      let baseInd = p.lex.currLineIndent
       addSon(result, primary(p, pmSkipSuffix))
-      result = primarySuffix(p, result)
+      result = primarySuffix(p, result, baseInd)
     else:
       addSon(result, primary(p, pmNormal))
     return
@@ -1071,9 +1073,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     optInd(p, result)
     addSon(result, primary(p, pmNormal))
   else:
+    let baseInd = p.lex.currLineIndent
     result = identOrLiteral(p, mode)
     if mode != pmSkipSuffix:
-      result = primarySuffix(p, result)
+      result = primarySuffix(p, result, baseInd)
 
 proc parseTypeDesc(p: var TParser): PNode =
   #| typeDesc = simpleExpr
@@ -1901,7 +1904,7 @@ proc parseStmt(p: var TParser): PNode =
           if p.tok.indent < 0 or p.tok.indent == p.currInd: discard
           else: break
         else:
-          if p.tok.indent > p.currInd:
+          if p.tok.indent > p.currInd and p.tok.tokType != tkDot:
             parMessage(p, errInvalidIndentation)
           break
         if p.tok.tokType in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
@@ -1928,7 +1931,8 @@ proc parseStmt(p: var TParser): PNode =
       else:
         result = newNodeP(nkStmtList, p)
         while true:
-          if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)     
+          if p.tok.indent >= 0:
+            parMessage(p, errInvalidIndentation)
           let a = simpleStmt(p)
           if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
           result.add(a)