summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/parser.nim127
-rw-r--r--compiler/semstmts.nim8
-rw-r--r--doc/grammar.txt30
-rw-r--r--lib/core/macros.nim18
-rw-r--r--lib/pure/pegs.nim8
-rw-r--r--tests/macros/tmemit.nim7
-rw-r--r--tests/parser/tcommand_as_expr.nim12
-rw-r--r--tests/parser/tdomulttest.nim17
-rw-r--r--tests/parser/tinvwhen.nim15
-rw-r--r--tests/patterns/tpatterns.nim (renamed from tests/pattern/tpatterns.nim)0
-rw-r--r--tests/pragmas/tuserpragma.nim (renamed from tests/pragma/tuserpragma.nim)0
-rw-r--r--todo.txt4
-rw-r--r--web/news.txt7
13 files changed, 173 insertions, 80 deletions
diff --git a/compiler/parser.nim b/compiler/parser.nim
index c44036c5f..d255949a4 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -18,10 +18,10 @@
 # In fact the grammar is generated from this file:
 when isMainModule:
   import pegs
-  var outp = open("compiler/grammar.txt", fmWrite)
+  var outp = open("doc/grammar.txt", fmWrite)
   for line in lines("compiler/parser.nim"):
     if line =~ peg" \s* '#| ' {.*}":
-      outp.writeln matches[0]
+      outp.write matches[0], "\L"
   outp.close
 
 import
@@ -34,6 +34,7 @@ type
     firstTok: bool
     lex*: TLexer              # the lexer that is used for parsing
     tok*: TToken              # the current token
+    inPragma: int
 
 proc parseAll*(p: var TParser): PNode
 proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@@ -518,14 +519,14 @@ proc parsePar(p: var TParser): PNode =
   eat(p, tkParRi)
 
 proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = 
+  #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+  #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+  #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+  #|           | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+  #|           | CHAR_LIT
+  #|           | NIL
   #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-  #| identOrLiteral = generalizedLit | symbol 
-  #|                | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-  #|                | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-  #|                | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-  #|                | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-  #|                | CHAR_LIT
-  #|                | NIL
+  #| identOrLiteral = generalizedLit | symbol | literal
   #|                | par | arrayConstr | setOrTableConstr
   #|                | castExpr
   #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -634,12 +635,15 @@ proc namedParams(p: var TParser, callee: PNode,
   addSon(result, a)
   exprColonEqExprListAux(p, endTok, result)
 
+proc parseMacroColon(p: var TParser, x: PNode): PNode
 proc primarySuffix(p: var TParser, r: PNode): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|               | doBlocks
   #|               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
   #|               | '[' optInd indexExprList optPar ']'
   #|               | '{' optInd indexExprList optPar '}'
+  #|               | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
+  #|                      (doBlock | macroColon)?
   result = r
   while p.tok.indent < 0:
     case p.tok.tokType
@@ -661,8 +665,27 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
       result = namedParams(p, result, nkBracketExpr, tkBracketRi)
     of tkCurlyLe:
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
-    else: break
-
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
+      if p.inPragma == 0:
+        # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
+        # solution, but pragmas.nim can't handle that
+        let a = result
+        result = newNodeP(nkCommand, p)
+        addSon(result, a)
+        while p.tok.tokType != tkEof:
+          let a = parseExpr(p)
+          addSon(result, a)
+          if p.tok.tokType != tkComma: break
+          getTok(p)
+          optInd(p, a)
+        if p.tok.tokType == tkDo:
+          parseDoBlocks(p, result)
+        else:
+          result = parseMacroColon(p, result)
+      break
+    else:
+      break
+    
 proc primary(p: var TParser, mode: TPrimaryMode): PNode
 
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
@@ -713,6 +736,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
 proc parsePragma(p: var TParser): PNode =
   #| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
   result = newNodeP(nkPragma, p)
+  inc p.inPragma
   getTok(p)
   optInd(p, result)
   while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
@@ -724,6 +748,7 @@ proc parsePragma(p: var TParser): PNode =
   optPar(p)
   if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
   else: parMessage(p, errTokenExpected, ".}")
+  dec p.inPragma
   
 proc identVis(p: var TParser): PNode = 
   #| identVis = symbol opr?  # postfix position
@@ -965,7 +990,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
   of tkTuple: result = parseTuple(p, mode == pmTypeDef)
   of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
   of tkIterator:
-    when true:
+    when false:
       if mode in {pmTypeDesc, pmTypeDef}:
         result = parseProcExpr(p, false)
         result.kind = nkIteratorTy
@@ -976,7 +1001,8 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
         result = ast.emptyNode
     else:
       result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-      result.kind = nkIteratorTy
+      if result.kind == nkLambda: result.kind = nkIteratorDef
+      else: result.kind = nkIteratorTy
   of tkEnum:
     if mode == pmTypeDef:
       result = parseEnum(p)
@@ -1031,15 +1057,50 @@ proc makeCall(n: PNode): PNode =
     result = newNodeI(nkCall, n.info)
     result.add n
 
+proc parseMacroColon(p: var TParser, x: PNode): PNode =
+  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+  #|                        | IND{=} 'elif' expr ':' stmt
+  #|                        | IND{=} 'except' exprList ':' stmt
+  #|                        | IND{=} 'else' ':' stmt )*
+  result = x
+  if p.tok.tokType == tkColon and p.tok.indent < 0:
+    result = makeCall(result)
+    getTok(p)
+    skipComment(p, result)
+    if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
+      let body = parseStmt(p)
+      addSon(result, newProcNode(nkDo, body.info, body))
+    while sameInd(p):
+      var b: PNode
+      case p.tok.tokType
+      of tkOf:
+        b = newNodeP(nkOfBranch, p)
+        exprList(p, tkColon, b)
+      of tkElif: 
+        b = newNodeP(nkElifBranch, p)
+        getTok(p)
+        optInd(p, b)
+        addSon(b, parseExpr(p))
+        eat(p, tkColon)
+      of tkExcept: 
+        b = newNodeP(nkExceptBranch, p)
+        exprList(p, tkColon, b)
+        skipComment(p, b)
+      of tkElse: 
+        b = newNodeP(nkElse, p)
+        getTok(p)
+        eat(p, tkColon)
+      else: break 
+      addSon(b, parseStmt(p))
+      addSon(result, b)
+      if b.kind == nkElse: break
+
 proc parseExprStmt(p: var TParser): PNode = 
   #| exprStmt = simpleExpr
   #|          (( '=' optInd expr )
   #|          / ( expr ^+ comma
   #|              doBlocks
-  #|               / ':' stmt? ( IND{=} 'of' exprList ':' stmt 
-  #|                           | IND{=} 'elif' expr ':' stmt
-  #|                           | IND{=} 'except' exprList ':' stmt
-  #|                           | IND{=} 'else' ':' stmt )*
+  #|               / macroColon
   #|            ))?
   var a = simpleExpr(p)
   if p.tok.tokType == tkEquals: 
@@ -1064,37 +1125,7 @@ proc parseExprStmt(p: var TParser): PNode =
       result = makeCall(result)
       parseDoBlocks(p, result)
       return result
-    if p.tok.tokType == tkColon and p.tok.indent < 0:
-      result = makeCall(result)
-      getTok(p)
-      skipComment(p, result)
-      if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
-        let body = parseStmt(p)
-        addSon(result, newProcNode(nkDo, body.info, body))
-      while sameInd(p):
-        var b: PNode
-        case p.tok.tokType
-        of tkOf:
-          b = newNodeP(nkOfBranch, p)
-          exprList(p, tkColon, b)
-        of tkElif: 
-          b = newNodeP(nkElifBranch, p)
-          getTok(p)
-          optInd(p, b)
-          addSon(b, parseExpr(p))
-          eat(p, tkColon)
-        of tkExcept: 
-          b = newNodeP(nkExceptBranch, p)
-          exprList(p, tkColon, b)
-          skipComment(p, b)
-        of tkElse: 
-          b = newNodeP(nkElse, p)
-          getTok(p)
-          eat(p, tkColon)
-        else: break 
-        addSon(b, parseStmt(p))
-        addSon(result, b)
-        if b.kind == nkElse: break
+    result = parseMacroColon(p, result)
 
 proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
   result = parseExpr(p)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 1aa6a793c..fc1706200 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -922,7 +922,7 @@ proc activate(c: PContext, n: PNode) =
     of nkCallKinds:
       for i in 1 .. <n.len: activate(c, n[i])
     else:
-      nil
+      discard
 
 proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
   if s.typ.sons[0] != nil and
@@ -951,7 +951,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   var typeIsDetermined = false
   if n[namePos].kind != nkSym:
     assert phase == stepRegisterSymbol
-    s = semIdentDef(c, n.sons[0], kind)
+
+    if n[namePos].kind == nkEmpty:
+      s = newSym(kind, idAnon, getCurrOwner(), n.info)
+    else:
+      s = semIdentDef(c, n.sons[0], kind)
     n.sons[namePos] = newSymNode(s)
     s.ast = n
     s.scope = c.currentScope
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 7fe2b56aa..b002747fa 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -42,14 +42,14 @@ par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
         optPar ')'
+literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+          | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+          | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+          | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+          | CHAR_LIT
+          | NIL
 generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
-identOrLiteral = generalizedLit | symbol 
-               | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
-               | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
-               | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
-               | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
-               | CHAR_LIT
-               | NIL
+identOrLiteral = generalizedLit | symbol | literal
                | par | arrayConstr | setOrTableConstr
                | castExpr
 tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -59,6 +59,8 @@ primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
               | '[' optInd indexExprList optPar ']'
               | '{' optInd indexExprList optPar '}'
+              | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
+                     (doBlock | macroColon)?
 condExpr = expr colcom expr optInd
         ('elif' expr colcom expr optInd)*
          'else' colcom expr
@@ -95,18 +97,18 @@ primary = typeKeyw typeDescK
         / 'bind' primary
 typeDesc = simpleExpr
 typeDefAux = simpleExpr
+macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+                       | IND{=} 'elif' expr ':' stmt
+                       | IND{=} 'except' exprList ':' stmt
+                       | IND{=} 'else' ':' stmt )*
 exprStmt = simpleExpr
          (( '=' optInd expr )
          / ( expr ^+ comma
              doBlocks
-              / ':' stmt? ( IND{=} 'of' exprList ':' stmt 
-                          | IND{=} 'elif' expr ':' stmt
-                          | IND{=} 'except' exprList ':' stmt
-                          | IND{=} 'else' ':' stmt )*
+              / macroColon
            ))?
-moduleName = expr ('as' expr)?
-importStmt = 'import' optInd moduleName
-              ((comma moduleName)*
+importStmt = 'import' optInd expr
+              ((comma expr)*
               / 'except' optInd (expr ^+ comma))
 includeStmt = 'include' optInd expr ^+ comma
 fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 0356067f1..7cb084653 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -300,9 +300,12 @@ when not defined(booting):
     ## that should be inserted verbatim in the program
     ## Example:
     ##
+    ## .. code-block:: nimrod
     ##   emit("echo " & '"' & "hello world".toUpper & '"')
     ##
-    eval: result = e.parseStmt
+    macro payload: stmt {.gensym.} =
+      result = e.parseStmt
+    payload()
 
 proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
   ## checks that `n` is of kind `k`. If this is not the case,
@@ -645,10 +648,13 @@ iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
   for i in 0 .. high(n):
     yield n[i]
 
-template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.immediate, dirty.} =
-  ## Find the first child node matching condition (or nil)
-  ## var res = findChild(n, it.kind == nnkPostfix and it.basename.ident == !"foo")
-  
+template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
+  immediate, dirty.} =
+  ## Find the first child node matching condition (or nil).
+  ## 
+  ## .. code-block:: nimrod
+  ##   var res = findChild(n, it.kind == nnkPostfix and
+  ##                          it.basename.ident == !"foo")
   block:
     var result: PNimrodNode
     for it in n.children:
@@ -736,6 +742,6 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
       if ident.eqIdent($node): return
     of nnkExprColonExpr:
       if ident.eqIdent($node[0]): return
-    else: nil
+    else: discard
   dest.add(ident(ident))
 
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index a6147a96c..70b617393 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -306,7 +306,7 @@ proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
 
 proc spaceCost(n: TPeg): int =
   case n.kind
-  of pkEmpty: nil
+  of pkEmpty: discard
   of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
      pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
      pkAny..pkWhitespace, pkGreedyAny:
@@ -1117,7 +1117,7 @@ proc handleHexChar(c: var TPegLexer, xi: var int) =
   of 'A'..'F': 
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
-  else: nil
+  else: discard
 
 proc getEscapedChar(c: var TPegLexer, tok: var TToken) = 
   inc(c.bufpos)
@@ -1347,7 +1347,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
       of "i": tok.modifier = modIgnoreCase
       of "y": tok.modifier = modIgnoreStyle
       of "v": tok.modifier = modVerbatim
-      else: nil
+      else: discard
       setLen(tok.literal, 0)
       if c.buf[c.bufpos] == '$':
         getDollar(c, tok)
@@ -1494,7 +1494,7 @@ proc primary(p: var TPegParser): TPeg =
   of tkCurlyAt:
     getTok(p)
     return !*\primary(p).token(p)
-  else: nil
+  else: discard
   case p.tok.kind
   of tkIdentifier:
     if p.identIsVerbatim: 
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
new file mode 100644
index 000000000..e4bb2daed
--- /dev/null
+++ b/tests/macros/tmemit.nim
@@ -0,0 +1,7 @@
+discard """
+  out: '''HELLO WORLD'''
+"""
+
+import macros, strutils
+
+emit("echo " & '"' & "hello world".toUpper & '"')
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
new file mode 100644
index 000000000..f6868a2fc
--- /dev/null
+++ b/tests/parser/tcommand_as_expr.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "12"
+"""
+
+proc foo(x: int): int = x-1
+proc foo(x, y: int): int = x-y
+
+let x = foo 7.foo,  # comment here
+            foo(1, foo 8)
+#  12 =       6     -     -6
+echo x
+
diff --git a/tests/parser/tdomulttest.nim b/tests/parser/tdomulttest.nim
new file mode 100644
index 000000000..4ee6de128
--- /dev/null
+++ b/tests/parser/tdomulttest.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tdomulttest.nim"
+  output: "555\ntest\nmulti lines\n99999999\nend"
+  disabled: true
+"""
+proc foo(bar, baz: proc (x: int): int) =
+  echo bar(555)
+  echo baz(99999999)
+
+foo do (x: int) -> int:
+  return x
+do (x: int) -> int:
+  echo("test")
+  echo("multi lines")
+  return x
+
+echo("end")
\ No newline at end of file
diff --git a/tests/parser/tinvwhen.nim b/tests/parser/tinvwhen.nim
new file mode 100644
index 000000000..5ff94cc6c
--- /dev/null
+++ b/tests/parser/tinvwhen.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvwhen.nim"
+  line: 11
+  errormsg: "invalid indentation"
+"""
+# This was parsed even though it should not!

+

+proc chdir(path: cstring): cint {.importc: "chdir", header: "dirHeader".}

+

+proc getcwd(buf: cstring, buflen: cint): cstring

+    when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation

+    elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}

+    else: {.error: "os library not ported to your OS. Please help!".}

+
+
diff --git a/tests/pattern/tpatterns.nim b/tests/patterns/tpatterns.nim
index 6bc8772e3..6bc8772e3 100644
--- a/tests/pattern/tpatterns.nim
+++ b/tests/patterns/tpatterns.nim
diff --git a/tests/pragma/tuserpragma.nim b/tests/pragmas/tuserpragma.nim
index 784baa176..784baa176 100644
--- a/tests/pragma/tuserpragma.nim
+++ b/tests/pragmas/tuserpragma.nim
diff --git a/todo.txt b/todo.txt
index 21416f279..15ce93df7 100644
--- a/todo.txt
+++ b/todo.txt
@@ -6,6 +6,7 @@ version 0.9.4
 - ensure (ref T)(a, b) works as a type conversion and type constructor
 - document new templating symbol binding rules
 - make '--implicitStatic:on' the default
+- change comment handling in the AST
 
 - special rule for ``[]=``
 - ``=`` should be overloadable; requires specialization for ``=``; general
@@ -27,8 +28,6 @@ Bugs
 - docgen: sometimes effects are listed twice
 - 'result' is not properly cleaned for NRVO --> use uninit checking instead
 - sneaking with qualifiedLookup() is really broken!
-- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' -- 
-  use a qualifier
 - blocks can "export" an identifier but the CCG generates {} for them ...
 - osproc execProcesses can deadlock if all processes fail (as experienced
   in c++ mode)
@@ -54,7 +53,6 @@ version 0.9.X
 - implement the missing features wrt inheritance
 - better support for macros that rewrite procs
 - macros need access to types and symbols (partially implemented)
-- perhaps: change comment handling in the AST
 - enforce 'simpleExpr' more often --> doesn't work; tkProc is
   part of primary!
 - the typeDesc/expr unification is weird and only necessary because of
diff --git a/web/news.txt b/web/news.txt
index 1ed447009..01b6d18b9 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -28,8 +28,8 @@ Changes affecting backwards compatibility
   require an error code to be passed to them. This error code can be retrieved
   using the new ``OSLastError`` proc.
 - ``os.parentDir`` now returns "" if there is no parent dir.
-- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
-  is used.
+- In CGI scripts stacktraces are shown to the user only 
+  if ``cgi.setStackTraceStdout`` is used.
 - The symbol binding rules for clean templates changed: ``bind`` for any
   symbol that's not a parameter is now the default. ``mixin`` can be used
   to require instantiation scope for a symbol.
@@ -71,8 +71,9 @@ Language Additions
 - Added a new ``delegator pragma`` for handling calls to missing procs and
   fields at compile-time.
 - The overload resolution now supports ``static[T]`` params that must be
-  evaluatable at compile-time.
+  evaluable at compile-time.
 - Support for user-defined type classes has been added.
+- The *command syntax* is supported in a lot more contexts.
 
 
 Tools improvements