summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore114
-rw-r--r--compiler/sempass2.nim13
-rw-r--r--doc/manual.txt7
-rw-r--r--lib/pure/strutils.nim91
-rw-r--r--lib/system.nim17
-rw-r--r--lib/system/threads.nim4
-rw-r--r--tests/reject/teffects5.nim14
7 files changed, 204 insertions, 56 deletions
diff --git a/.gitignore b/.gitignore
index 59b76e242..7bca71531 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,117 @@ examples/cross_calculator/android/libs/
 examples/cross_calculator/android/local.properties
 examples/cross_calculator/android/obj/
 examples/cross_calculator/android/tags
+
+# Generated files.
+/compile.json
+/compiler/c2nim/c2nim
+/compiler/pas2nim/pas2nim
+/compiler/service
+/examples/allany
+/examples/cairoex
+/examples/cgiex
+/examples/curlex
+/examples/docstrings
+/examples/filterex
+/examples/fizzbuzz
+/examples/gtk/ex1
+/examples/gtk/ex2
+/examples/gtk/ex3
+/examples/gtk/ex4
+/examples/gtk/ex5
+/examples/gtk/ex6
+/examples/gtk/ex7
+/examples/gtk/ex8
+/examples/gtk/ex9
+/examples/hallo
+/examples/htmlrefs
+/examples/htmltitle
+/examples/httpserver2
+/examples/iupex1
+/examples/keyval
+/examples/keyval2
+/examples/luaex
+/examples/maximum
+/examples/parsecfgex
+/examples/pythonex
+/examples/sdlex
+/examples/statcsv
+/examples/tclex
+/examples/transff
+/examples/tunit
+/examples/wingui
+/examples/x11ex
+/lib/libnimrtl.dylib
+/lib/libserver.dylib
+/lib/pure/actors
+/lib/pure/algorithm
+/lib/pure/asyncio
+/lib/pure/base64
+/lib/pure/browsers
+/lib/pure/cgi
+/lib/pure/collections/sequtils
+/lib/pure/collections/tables
+/lib/pure/colors
+/lib/pure/complex
+/lib/pure/cookies
+/lib/pure/dynlib
+/lib/pure/encodings
+/lib/pure/endians
+/lib/pure/events
+/lib/pure/ftpclient
+/lib/pure/gentabs
+/lib/pure/hashes
+/lib/pure/htmlgen
+/lib/pure/htmlparser
+/lib/pure/httpclient
+/lib/pure/httpserver
+/lib/pure/irc
+/lib/pure/json
+/lib/pure/lexbase
+/lib/pure/lib/
+/lib/pure/marshal
+/lib/pure/matchers
+/lib/pure/math
+/lib/pure/md5
+/lib/pure/memfiles
+/lib/pure/mimetypes
+/lib/pure/nimprof
+/lib/pure/oids
+/lib/pure/os
+/lib/pure/osproc
+/lib/pure/parsecfg
+/lib/pure/parsecsv
+/lib/pure/parseopt
+/lib/pure/parsesql
+/lib/pure/parseurl
+/lib/pure/parseutils
+/lib/pure/parsexml
+/lib/pure/pegs
+/lib/pure/redis
+/lib/pure/romans
+/lib/pure/ropes
+/lib/pure/scgi
+/lib/pure/smtp
+/lib/pure/sockets
+/lib/pure/streams
+/lib/pure/strtabs
+/lib/pure/strutils
+/lib/pure/subexes
+/lib/pure/terminal
+/lib/pure/times
+/lib/pure/typetraits
+/lib/pure/unicode
+/lib/pure/unittest
+/lib/pure/uri
+/lib/pure/xmldom
+/lib/pure/xmldomparser
+/lib/pure/xmlparser
+/lib/pure/xmltree
+/lib/system/sysio
+/lib/weird
+/lib/wrappers/gtk/gtk2
+/reject.json
+/run.json
+/testresults.html
+/testresults.json
+/tools/nimgrep
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 9213bd48d..b78e36531 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -79,6 +79,7 @@ type
     exc: PNode  # stack of exceptions
     tags: PNode # list of tags
     bottom: int
+    owner: PSym
   
   PEffects = var TEffects
 
@@ -173,11 +174,16 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
     track(tracked, b.sons[blen-1])
   tracked.bottom = oldBottom
 
-proc isIndirectCall(n: PNode): bool =
+proc isIndirectCall(n: PNode, owner: PSym): bool =
   # we don't count f(...) as an indirect call if 'f' is an parameter.
   # Instead we track expressions of type tyProc too. See the manual for
   # details:
-  result = n.kind != nkSym or n.sym.kind notin (routineKinds+{skParam})
+  if n.kind != nkSym: 
+    result = true
+  elif n.sym.kind == skParam:
+    result = owner != n.sym.owner or owner == nil
+  elif n.sym.kind notin routineKinds:
+    result = true
 
 proc isForwardedProc(n: PNode): bool =
   result = n.kind == nkSym and sfForward in n.sym.flags
@@ -274,7 +280,7 @@ proc track(tracked: PEffects, n: PNode) =
       elif effectList.len == 0:
         if isForwardedProc(a):
           propagateEffects(tracked, n, a.sym)
-        elif isIndirectCall(a):
+        elif isIndirectCall(a, tracked.owner):
           addEffect(tracked, createRaise(n))
           addTag(tracked, createTag(n))
       else:
@@ -355,6 +361,7 @@ proc trackProc*(s: PSym, body: PNode) =
   var t: TEffects
   t.exc = effects.sons[exceptionEffects]
   t.tags = effects.sons[tagEffects]
+  t.owner = s
   track(t, body)
   
   let p = s.ast.sons[pragmasPos]
diff --git a/doc/manual.txt b/doc/manual.txt
index 22aa22266..e6fe5fbdb 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2910,7 +2910,8 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
    raise ``system.E_Base`` (the base type of the exception hierarchy) and
    thus any exception unless ``T`` has an explicit ``raises`` list.
    However if the call is of the form ``f(...)`` where ``f`` is a parameter
-   is ignored. Rule 2 compensates for this case.
+   of the currently analysed routine it is ignored. The call is optimistically 
+   assumed to have no effect. Rule 2 compensates for this case.
 2. Every expression of some proc type wihtin a call that is not a call 
    itself (and not nil) is assumed to be called indirectly somehow and thus 
    its raises list is added to ``p``'s raises list.
@@ -2933,9 +2934,9 @@ Rules 1-2 ensure the following works:
   proc doRaise() {.raises: [EIO].} =
     raise newException(EIO, "IO")
   
-  proc use() =
+  proc use() {.raises: [].} =
+    # doesn't compile! Can raise EIO!
     noRaise(doRaise)
-    # Here the compiler inferes that EIO can be raised.
 
 So in many cases a callback does not cause the compiler to be overly
 conservative in its effect analysis.
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index b5f5a41eb..6f34b1996 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -165,45 +165,50 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
     result[i] = Chr(val mod 8 + ord('0'))

     val = val div 8

 

-iterator split*(s: string, seps: set[char] = Whitespace): string =

-  ## Splits the string `s` into substrings.

-  ##

-  ## Substrings are separated by a substring containing only `seps`.

-  ## Examples:

-  ##

-  ## .. code-block:: nimrod

-  ##   for word in split("  this is an  example  "):

-  ##     writeln(stdout, word)

-  ##

-  ## Results in:

-  ##

-  ## .. code-block:: nimrod

-  ##   "this"

-  ##   "is"

-  ##   "an"

-  ##   "example"

-  ##

-  ##   for word in split(";;this;is;an;;example;;;", {';'}):

-  ##     writeln(stdout, word)

-  ##

-  ## produces the same output. The code:

-  ##

-  ## .. code-block:: nimrod

-  ##   let date = "2012-11-20T22:08:08.398990"

-  ##   let separators = {' ', '-', ':', 'T'}

-  ##   for number in split(date, separators):

-  ##     writeln(stdout, number)

-  ##

-  ## Results in:

-  ##

-  ## .. code-block:: nimrod

-  ##   "2012"

-  ##   "11"

-  ##   "20"

-  ##   "22"

-  ##   "08"

-  ##   "08.398990"

-  ##

+iterator split*(s: string, seps: set[char] = Whitespace): string =
+  ## Splits the string `s` into substrings using a group of separators.
+  ##
+  ## Substrings are separated by a substring containing only `seps`. Note
+  ## that whole sequences of characters found in ``seps`` will be counted as
+  ## a single split point and leading/trailing separators will be ignored.
+  ## The following example:
+  ##
+  ## .. code-block:: nimrod
+  ##   for word in split("  this is an  example  "):
+  ##     writeln(stdout, word)
+  ##
+  ## ...generates this output:
+  ##
+  ## .. code-block::
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   "example"
+  ##
+  ## And the following code:
+  ##
+  ## .. code-block:: nimrod
+  ##   for word in split(";;this;is;an;;example;;;", {';'}):
+  ##     writeln(stdout, word)
+  ##
+  ## ...produces the same output as the first example. The code:
+  ##
+  ## .. code-block:: nimrod
+  ##   let date = "2012-11-20T22:08:08.398990"
+  ##   let separators = {' ', '-', ':', 'T'}
+  ##   for number in split(date, separators):
+  ##     writeln(stdout, number)
+  ##
+  ## ...results in:
+  ##
+  ## .. code-block::
+  ##   "2012"
+  ##   "11"
+  ##   "20"
+  ##   "22"
+  ##   "08"
+  ##   "08.398990"
+  ##
   var last = 0

   assert(not ('\0' in seps))

   while last < len(s):

@@ -214,10 +219,12 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
       yield substr(s, first, last-1)

 

 iterator split*(s: string, sep: char): string =

-  ## Splits the string `s` into substrings.

+  ## Splits the string `s` into substrings using a single separator.

   ##

   ## Substrings are separated by the character `sep`.

-  ## Example:

+  ## Unlike the version of the iterator which accepts a set of separator

+  ## characters, this proc will not coalesce groups of the

+  ## separator, returning a string for each found character. The code:

   ##

   ## .. code-block:: nimrod

   ##   for word in split(";;this;is;an;;example;;;", ';'):

@@ -225,7 +232,7 @@ iterator split*(s: string, sep: char): string =
   ##

   ## Results in:

   ##

-  ## .. code-block:: nimrod

+  ## .. code-block::

   ##   ""

   ##   ""

   ##   "this"

diff --git a/lib/system.nim b/lib/system.nim
index 5dafd6e13..4cdc212b9 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -909,12 +909,17 @@ var programResult* {.exportc: "nim_program_result".}: int
 
 proc quit*(errorcode: int = QuitSuccess) {.
   magic: "Exit", importc: "exit", noDecl, noReturn.}
-  ## stops the program immediately; before stopping the program the
-  ## "quit procedures" are called in the opposite order they were added
-  ## with ``addQuitProc``. ``quit`` never returns and ignores any
-  ## exception that may have been raised by the quit procedures.
-  ## It does *not* call the garbage collector to free all the memory,
-  ## unless a quit procedure calls ``GC_collect``.
+  ## Stops the program immediately with an exit code.
+  ##
+  ## Before stopping the program the "quit procedures" are called in the
+  ## opposite order they were added with ``addQuitProc``. ``quit`` never
+  ## returns and ignores any exception that may have been raised by the quit
+  ## procedures.  It does *not* call the garbage collector to free all the
+  ## memory, unless a quit procedure calls ``GC_collect``.
+  ##
+  ## The proc ``quit(QuitSuccess)`` is called implicitly when your nimrod
+  ## program finishes without incident. A raised unhandled exception is
+  ## equivalent to calling ``quit(QuitFailure)``.
 
 template sysAssert(cond: bool, msg: string) =
   when defined(useSysAssert):
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index aba3bb275..7d74de92d 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -14,8 +14,8 @@
 ## Nimrod's memory model for threads is quite different from other common 
 ## programming languages (C, Pascal): Each thread has its own
 ## (garbage collected) heap and sharing of memory is restricted. This helps
-## to prevent race conditions and improves efficiency. See the manual for
-## details of this memory model.
+## to prevent race conditions and improves efficiency. See `the manual for
+## details of this memory model <manual.html#threads>`_.
 ##
 ## Example:
 ##
diff --git a/tests/reject/teffects5.nim b/tests/reject/teffects5.nim
new file mode 100644
index 000000000..42be115c3
--- /dev/null
+++ b/tests/reject/teffects5.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: 'type mismatch'
+  line: 7
+"""
+
+proc p(q: proc() ): proc() {.tags: [], raises: [], closure.} =
+  return proc () =
+    q()
+  
+let yay = p(proc () = raise newException(EIO, "IO"))
+
+proc main() {.raises: [], tags: [].} = yay()
+
+main()