mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
niminst: bugfixes; documentation changes
This commit is contained in:
@@ -1024,7 +1024,7 @@ proc getStrOrChar*(a: PNode): string =
|
||||
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
case s.kind
|
||||
of skProc, skTemplate, skMacro, skIterator, skMethod:
|
||||
of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
|
||||
result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
|
||||
else: nil
|
||||
|
||||
|
||||
@@ -736,37 +736,10 @@ variadic proc, it is implicitely converted to ``cstring`` too:
|
||||
|
||||
Even though the conversion is implict, it is not *safe*: The garbage collector
|
||||
does not consider a ``cstring`` to be a root and may collect the underlying
|
||||
memory:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var nimStr = "example"
|
||||
var cStr: cstring = nimStr
|
||||
var i = 0
|
||||
while cStr[i] != '\0':
|
||||
# since `nimStr`'s lifetime ended here the GC is allowed to free
|
||||
# the memory occupied by "example":
|
||||
GC_collect()
|
||||
# now cStr points to garbage:
|
||||
echo cStr[i]
|
||||
inc i
|
||||
|
||||
However this a very contrived example; in practice this almost never happens.
|
||||
One can use the builtin procs ``GC_ref`` and ``GC_unref`` to make this code
|
||||
safe:
|
||||
|
||||
.. code-block:: nimrod
|
||||
var nimStr = "example"
|
||||
GC_ref(nimStr) # keep GC from freeing 'nimStr'
|
||||
var cStr: cstring = nimStr
|
||||
var i = 0
|
||||
while cStr[i] != '\0':
|
||||
# since `nimStr`'s lifetime ended here the GC is allowed to free
|
||||
# the memory occupied by "example":
|
||||
GC_collect()
|
||||
# now cStr points to garbage:
|
||||
echo cStr[i]
|
||||
inc i
|
||||
GC_unref(nimStr) # GC is allowed to free 'nimStr'
|
||||
memory. However in practice this almost never happens as the GC considers
|
||||
stack roots conservatively. One can use the builtin procs ``GC_ref`` and
|
||||
``GC_unref`` to keep the string data alive for the rare cases where it does
|
||||
not work.
|
||||
|
||||
|
||||
Structured types
|
||||
|
||||
78
doc/tut1.txt
78
doc/tut1.txt
@@ -31,9 +31,9 @@ We start the tour with a modified "hello world" program:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
# This is a comment
|
||||
Echo("What's your name? ")
|
||||
echo("What's your name? ")
|
||||
var name: string = readLine(stdin)
|
||||
Echo("Hi, ", name, "!")
|
||||
echo("Hi, ", name, "!")
|
||||
|
||||
|
||||
Save this code to the file "greetings.nim". Now compile and run it::
|
||||
@@ -65,12 +65,12 @@ done with spaces only, tabulators are not allowed.
|
||||
|
||||
String literals are enclosed in double quotes. The ``var`` statement declares
|
||||
a new variable named ``name`` of type ``string`` with the value that is
|
||||
returned by the ``readline`` procedure. Since the compiler knows that
|
||||
``readline`` returns a string, you can leave out the type in the declaration
|
||||
returned by the ``readLine`` procedure. Since the compiler knows that
|
||||
``readLine`` returns a string, you can leave out the type in the declaration
|
||||
(this is called `local type inference`:idx:). So this will work too:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
var name = readline(stdin)
|
||||
var name = readLine(stdin)
|
||||
|
||||
Note that this is basically the only form of type inference that exists in
|
||||
Nimrod: it is a good compromise between brevity and readability.
|
||||
@@ -140,10 +140,10 @@ which code snippet the comment refers to. Since comments are a proper part of
|
||||
the syntax, watch their indentation:
|
||||
|
||||
.. code-block::
|
||||
Echo("Hello!")
|
||||
echo("Hello!")
|
||||
# comment has the same indentation as above statement -> fine
|
||||
Echo("Hi!")
|
||||
# comment has not the right indentation -> syntax error!
|
||||
echo("Hi!")
|
||||
# comment has not the correct indentation level -> syntax error!
|
||||
|
||||
**Note**: To comment out a large piece of code, it is often better to use a
|
||||
``when false:`` statement.
|
||||
@@ -244,7 +244,7 @@ The if statement is one way to branch the control flow:
|
||||
elif name == "name":
|
||||
echo("Very funny, your name is name.")
|
||||
else:
|
||||
Echo("Hi, ", name, "!")
|
||||
echo("Hi, ", name, "!")
|
||||
|
||||
There can be zero or more elif parts, and the else part is optional. The
|
||||
keyword ``elif`` is short for ``else if``, and is useful to avoid excessive
|
||||
@@ -267,7 +267,7 @@ a multi-branch:
|
||||
of "Dave", "Frank":
|
||||
echo("Cool name!")
|
||||
else:
|
||||
Echo("Hi, ", name, "!")
|
||||
echo("Hi, ", name, "!")
|
||||
|
||||
As it can be seen, for an ``of`` branch a comma separated list of values is also
|
||||
allowed.
|
||||
@@ -280,11 +280,11 @@ For integers or other ordinal types value ranges are also possible:
|
||||
# this statement will be explained later:
|
||||
from strutils import parseInt
|
||||
|
||||
Echo("A number please: ")
|
||||
echo("A number please: ")
|
||||
let n = parseInt(readLine(stdin))
|
||||
case n
|
||||
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
||||
of 3, 8: Echo("The number is 3 or 8")
|
||||
of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
||||
of 3, 8: echo("The number is 3 or 8")
|
||||
|
||||
However, the above code does not compile: the reason is that you have to cover
|
||||
every value that ``n`` may contain, but the code only handles the values
|
||||
@@ -295,8 +295,8 @@ the compiler that for every other value nothing should be done:
|
||||
.. code-block:: nimrod
|
||||
...
|
||||
case n
|
||||
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
||||
of 3, 8: Echo("The number is 3 or 8")
|
||||
of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
||||
of 3, 8: echo("The number is 3 or 8")
|
||||
else: nil
|
||||
|
||||
The ``nil`` statement is a *do nothing* statement. The compiler knows that a
|
||||
@@ -316,10 +316,10 @@ The while statement is a simple looping construct:
|
||||
|
||||
.. code-block:: nimrod
|
||||
|
||||
Echo("What's your name? ")
|
||||
echo("What's your name? ")
|
||||
var name = readLine(stdin)
|
||||
while name == "":
|
||||
Echo("Please tell me your name: ")
|
||||
echo("Please tell me your name: ")
|
||||
name = readLine(stdin)
|
||||
# no ``var``, because we do not declare a new variable here
|
||||
|
||||
@@ -334,9 +334,9 @@ The `for`:idx: statement is a construct to loop over any element an *iterator*
|
||||
provides. The example uses the built-in ``countup`` iterator:
|
||||
|
||||
.. code-block:: nimrod
|
||||
Echo("Counting to ten: ")
|
||||
echo("Counting to ten: ")
|
||||
for i in countup(1, 10):
|
||||
Echo($i)
|
||||
echo($i)
|
||||
|
||||
The built-in ``$`` operator turns an integer (``int``) and many other types
|
||||
into a string. The variable ``i`` is implicitly declared by the ``for`` loop
|
||||
@@ -345,18 +345,18 @@ through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does
|
||||
the same:
|
||||
|
||||
.. code-block:: nimrod
|
||||
Echo("Counting to 10: ")
|
||||
echo("Counting to 10: ")
|
||||
var i = 1
|
||||
while i <= 10:
|
||||
Echo($i)
|
||||
echo($i)
|
||||
inc(i) # increment i by 1
|
||||
|
||||
Counting down can be achieved as easily (but is less often needed):
|
||||
|
||||
.. code-block:: nimrod
|
||||
Echo("Counting down from 10 to 1: ")
|
||||
echo("Counting down from 10 to 1: ")
|
||||
for i in countdown(10, 1):
|
||||
Echo($i)
|
||||
echo($i)
|
||||
|
||||
Since counting up occurs so often in programs, Nimrod has a special syntax that
|
||||
calls the ``countup`` iterator implicitly:
|
||||
@@ -400,18 +400,18 @@ unless a label of a block is given:
|
||||
|
||||
.. code-block:: nimrod
|
||||
block myblock:
|
||||
Echo("entering block")
|
||||
echo("entering block")
|
||||
while true:
|
||||
Echo("looping")
|
||||
echo("looping")
|
||||
break # leaves the loop, but not the block
|
||||
Echo("still in block")
|
||||
echo("still in block")
|
||||
|
||||
block myblock2:
|
||||
Echo("entering block")
|
||||
echo("entering block")
|
||||
while true:
|
||||
Echo("looping")
|
||||
echo("looping")
|
||||
break myblock2 # leaves the block (and the loop)
|
||||
Echo("still in block")
|
||||
echo("still in block")
|
||||
|
||||
|
||||
Continue statement
|
||||
@@ -423,7 +423,7 @@ the next iteration immediately:
|
||||
while true:
|
||||
let x = readLine(stdin)
|
||||
if x == "": continue
|
||||
Echo(x)
|
||||
echo(x)
|
||||
|
||||
|
||||
When statement
|
||||
@@ -516,17 +516,17 @@ of a `procedure` is needed. (Some languages call them *methods* or
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc yes(question: string): bool =
|
||||
Echo(question, " (y/n)")
|
||||
echo(question, " (y/n)")
|
||||
while true:
|
||||
case readLine(stdin)
|
||||
of "y", "Y", "yes", "Yes": return true
|
||||
of "n", "N", "no", "No": return false
|
||||
else: Echo("Please be clear: yes or no")
|
||||
else: echo("Please be clear: yes or no")
|
||||
|
||||
if yes("Should I delete all your important files?"):
|
||||
Echo("I'm sorry Dave, I'm afraid I can't do that.")
|
||||
echo("I'm sorry Dave, I'm afraid I can't do that.")
|
||||
else:
|
||||
Echo("I think you know what the problem is just as well as I do.")
|
||||
echo("I think you know what the problem is just as well as I do.")
|
||||
|
||||
This example shows a procedure named ``yes`` that asks the user a ``question``
|
||||
and returns true if he answered "yes" (or something similar) and returns
|
||||
@@ -662,8 +662,8 @@ Nimrod provides the ability to overload procedures similar to C++:
|
||||
if x: return "true"
|
||||
else: return "false"
|
||||
|
||||
Echo(toString(13)) # calls the toString(x: int) proc
|
||||
Echo(toString(true)) # calls the toString(x: bool) proc
|
||||
echo(toString(13)) # calls the toString(x: int) proc
|
||||
echo(toString(true)) # calls the toString(x: bool) proc
|
||||
|
||||
(Note that ``toString`` is usually the ``$`` operator in Nimrod.)
|
||||
The compiler chooses the most appropriate proc for the ``toString`` calls. How
|
||||
@@ -704,7 +704,7 @@ The "``" notation can also be used to call an operator just like a procedure
|
||||
with a real name:
|
||||
|
||||
.. code-block:: nimrod
|
||||
if `==`( `+`(3, 4), 7): Echo("True")
|
||||
if `==`( `+`(3, 4), 7): echo("True")
|
||||
|
||||
|
||||
Forward declarations
|
||||
@@ -738,9 +738,9 @@ Iterators
|
||||
Let's return to the boring counting example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
Echo("Counting to ten: ")
|
||||
echo("Counting to ten: ")
|
||||
for i in countup(1, 10):
|
||||
Echo($i)
|
||||
echo($i)
|
||||
|
||||
Can a ``countup`` proc be written that supports this loop? Lets try:
|
||||
|
||||
|
||||
14
doc/tut2.txt
14
doc/tut2.txt
@@ -387,17 +387,17 @@ The `try`:idx: statement handles exceptions:
|
||||
f: TFile
|
||||
if open(f, "numbers.txt"):
|
||||
try:
|
||||
var a = readLine(f)
|
||||
var b = readLine(f)
|
||||
echo("sum: " & $(parseInt(a) + parseInt(b)))
|
||||
let a = readLine(f)
|
||||
let b = readLine(f)
|
||||
echo "sum: ", parseInt(a) + parseInt(b)
|
||||
except EOverflow:
|
||||
echo("overflow!")
|
||||
echo "overflow!"
|
||||
except EInvalidValue:
|
||||
echo("could not convert string to integer")
|
||||
echo "could not convert string to integer"
|
||||
except EIO:
|
||||
echo("IO error!")
|
||||
echo "IO error!"
|
||||
except:
|
||||
echo("Unknown exception!")
|
||||
echo "Unknown exception!"
|
||||
# reraise the unknown exception:
|
||||
raise
|
||||
finally:
|
||||
|
||||
3
todo.txt
3
todo.txt
@@ -1,8 +1,8 @@
|
||||
version 0.8.14
|
||||
==============
|
||||
|
||||
- improve niminst
|
||||
- fix line info in assertions
|
||||
- bug: tsortdev does not run with native GC
|
||||
|
||||
version 0.9.0
|
||||
=============
|
||||
@@ -47,7 +47,6 @@ Bugs
|
||||
without ``-d:release`` leaks memory; good way to figure out how a
|
||||
fixed amount of stack can hold an arbitrary number of GC roots!
|
||||
- bug: temp2.nim triggers weird compiler and except.nim bug
|
||||
- bug: tsortdev does not run with native GC
|
||||
|
||||
|
||||
version 0.9.XX
|
||||
|
||||
@@ -15,7 +15,7 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}
|
||||
# linkCmd.add(" " & changeFileExt(f, "o"))
|
||||
# end for
|
||||
|
||||
ECHO %LINKER% %LINK_FLAGS% -o ?{c.binPaths[0]}\?{toLower(c.name)}.exe ?linkCmd
|
||||
%LINKER% %LINK_FLAGS% -o ?{c.binPaths[0]}\?{toLower(c.name)}.exe ?linkCmd
|
||||
ECHO %LINKER% %LINK_FLAGS% -o ?{firstBinPath(c)\toLower(c.name)}.exe ?linkCmd
|
||||
%LINKER% %LINK_FLAGS% -o ?{firstBinPath(c)\toLower(c.name)}.exe ?linkCmd
|
||||
|
||||
ECHO SUCCESS
|
||||
|
||||
@@ -90,8 +90,8 @@ case $myos in
|
||||
$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")} || exit 1
|
||||
# add(linkCmd, " \\\n" & changeFileExt(f, "o"))
|
||||
# end for
|
||||
echo "$LINKER $LINK_FLAGS -o ?{c.binPaths[0]}/?{toLower(c.name)} ?linkCmd"
|
||||
$LINKER $LINK_FLAGS -o ?{c.binPaths[0]}/?{toLower(c.name)} ?linkCmd || exit 1
|
||||
echo "$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd"
|
||||
$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd || exit 1
|
||||
;;
|
||||
# end for
|
||||
*)
|
||||
|
||||
@@ -86,6 +86,13 @@ proc initConfigData(c: var TConfigData) =
|
||||
c.uninstallScript = false
|
||||
c.vars = newStringTable(modeStyleInsensitive)
|
||||
|
||||
proc firstBinPath(c: TConfigData): string =
|
||||
if c.binPaths.len > 0: result = c.binPaths[0]
|
||||
else: result = ""
|
||||
|
||||
proc `\`(a, b: string): string =
|
||||
result = if a.len == 0: b else: a & '\\' & b
|
||||
|
||||
proc skipRoot(f: string): string =
|
||||
# "abc/def/xyz" --> "def/xyz"
|
||||
var i = 0
|
||||
|
||||
@@ -106,8 +106,14 @@ Roadmap to 1.0
|
||||
==============
|
||||
|
||||
Version 0.9.0
|
||||
* closures and anonymous procs
|
||||
* closures
|
||||
* recursive iterators/coroutines
|
||||
|
||||
Version 0.9.x
|
||||
* 2-phase type system for better interaction between macros, templates
|
||||
and overloading
|
||||
* term rewriting macros
|
||||
* the syntactic distinction between statements and expressions will be
|
||||
removed
|
||||
* forward declarations will likely be removed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user