Switch to nanoc
This commit is contained in:
parent
64313ec3ce
commit
6bfe583522
24 changed files with 307 additions and 74 deletions
18
content/book.json
Normal file
18
content/book.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"title": "Nimrod by Example",
|
||||
"description": "A book of short examples of Nimrod features",
|
||||
"github": null,
|
||||
"githubHost": "https://github.com/",
|
||||
"plugins": [],
|
||||
"links": {
|
||||
"home": "http://nimrod-lang.org/",
|
||||
"about": false,
|
||||
"issues": null,
|
||||
"contribute": null,
|
||||
"sharing": {
|
||||
"google": false,
|
||||
"facebook": false,
|
||||
"twitter": false
|
||||
}
|
||||
}
|
||||
}
|
||||
48
content/case.md
Normal file
48
content/case.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Case Statements
|
||||
|
||||
Nimrod also supports case statements, which are like switches in other languages. There are several things to note here:
|
||||
|
||||
* You can use strings in the switch statement
|
||||
* Sets and ranges of ordinal types are also usable
|
||||
* case statements, like most things, are actually expressions
|
||||
* It is required that every possible case be covered
|
||||
|
||||
~~~ Nimrod
|
||||
case "charlie"
|
||||
of "alfa":
|
||||
echo "A"
|
||||
of "bravo":
|
||||
echo "B"
|
||||
of "charlie":
|
||||
echo "C"
|
||||
else:
|
||||
echo "Unrecognized letter"
|
||||
|
||||
case 'h':
|
||||
of 'a', 'e', 'i', 'o', 'u':
|
||||
echo "Vowel"
|
||||
of '\127'..'\255':
|
||||
echo "Maybe, but I only know English"
|
||||
else:
|
||||
echo "Consonant"
|
||||
|
||||
proc positiveOrNegative(num: int): string =
|
||||
result = case num
|
||||
of low(int)..-1:
|
||||
"negative"
|
||||
of 0:
|
||||
"zero"
|
||||
of 1..high(int):
|
||||
"positive"
|
||||
else:
|
||||
"impossible"
|
||||
|
||||
echo positiveOrNegative(-1)
|
||||
~~~
|
||||
|
||||
~~~
|
||||
$ nimrod c -r ./case_stmts.nim
|
||||
C
|
||||
Consonant
|
||||
negative
|
||||
~~~
|
||||
1
content/enums.md
Normal file
1
content/enums.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Enums
|
||||
1
content/exceptions.md
Normal file
1
content/exceptions.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Exceptions
|
||||
90
content/for_iterators.md
Normal file
90
content/for_iterators.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# For Loops & Iterators
|
||||
|
||||
Nimrod has first class iterators and syntax to use them, for loops. The `continue` and `break` keywords also work inside of for loops. There are two kinds of iterator, and two special methods that for loops work with.
|
||||
|
||||
## `items` and `pair`
|
||||
|
||||
When iterating over an object with one item, Nimrod will call an iterator called `items` with the first parameter the type you want to iterate over. The same thing happens when iterating with two items, but in that case, the `pairs` iterator is called.
|
||||
|
||||
~~~ nimrod
|
||||
type
|
||||
TRange = object
|
||||
low: int
|
||||
high: int
|
||||
|
||||
iterator items(range: TRange): int =
|
||||
var i = range.low
|
||||
while i <= range.high:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
iterator pairs(range: TRange): tuple[a: int, b: char] =
|
||||
for i in range:
|
||||
yield (i, char(i + ord('a')))
|
||||
|
||||
for i, c in TRange(low: 1, high: 3):
|
||||
echo c
|
||||
~~~
|
||||
~~~
|
||||
$ nimrod c -r items_pair.nim
|
||||
b
|
||||
c
|
||||
d
|
||||
~~~
|
||||
|
||||
## Inline Iterators
|
||||
Inline iterators basically take the body of the for loop and inline it into the iterator. This means that they do not have any overhead from function calling, but if carelessly created may increase code size dramatically.
|
||||
|
||||
~~~ nimrod
|
||||
iterator countTo(n: int): int =
|
||||
var i = 0
|
||||
while i <= n:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
for i in countTo(5):
|
||||
echo i
|
||||
~~~
|
||||
~~~
|
||||
$ nimrod c -r ./inline_iter.nim
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
~~~
|
||||
|
||||
|
||||
## Closure Iterators
|
||||
Closure iterators hold on to their state and can be resumed at any time. The `finished()` function can be used to check if there are any more elements available in the iterator.
|
||||
|
||||
~~~ nimrod
|
||||
proc countTo(n: int): iterator(): int =
|
||||
return iterator (): int =
|
||||
var i = 0
|
||||
while i <= n:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
let countTo20 = countTo(20)
|
||||
|
||||
echo countTo20()
|
||||
|
||||
var output = ""
|
||||
while not finished(countTo20):
|
||||
output.add($countTo20())
|
||||
echo output
|
||||
|
||||
output = ""
|
||||
let countTo9 = countTo(9)
|
||||
for i in countTo9:
|
||||
output.add($i)
|
||||
echo output
|
||||
~~~
|
||||
~~~
|
||||
$ nimrod c -r ./closure_iter.nim
|
||||
0
|
||||
12345678910111213141516171819200
|
||||
0123456789
|
||||
~~~
|
||||
33
content/getting_started.md
Normal file
33
content/getting_started.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Getting Started
|
||||
When installing Nimrod, you have two options: downloading a copy directly from git, or downloading a prepackaged distribution from the website
|
||||
|
||||
## Downloading a Nimrod Distribution
|
||||
To get started with Nimrod, head over to the [downloads page](http://nimrod-lang.org/download.html) and download the version you'd like.
|
||||
|
||||
The Windows distribution comes with the MinGW compiler, which is recommended, but if you'd like to use your own compiler, download the version without MinGW.
|
||||
|
||||
On Mac and Linux, it is recommended to use either GCC or Clang.
|
||||
|
||||
| | i386 | amd64 |
|
||||
| -- | ---- | ----- |
|
||||
| Windows | [Download](http://nimrod-lang.org/download/nimrod_0.9.4_windows_i386_full.zip) ([w/o MinGW](http://nimrod-lang.org/download/nimrod_0.9.4_windows_i386_slim.zip))| [Download](http://nimrod-lang.org/download/nimrod_0.9.4_windows_amd64_full.zip) ([w/o MinGW](http://nimrod-lang.org/download/nimrod_0.9.4_windows_amd64_slim.zip)) |
|
||||
| Mac | NA | [Download](http://nimrod-lang.org/download/nimrod_0.9.4_macosx_amd64.zip) |
|
||||
| Linux | [Download](http://nimrod-lang.org/download/nimrod_0.9.4_linux_i386.tar.gz) | [Download](http://nimrod-lang.org/download/nimrod_0.9.4_linux_amd64.tar.gz) |
|
||||
|
||||
Once you have downloaded the appropriate distribution and extracted the files somewhere convenient, feel free to place the `bin` directory in the path for easier access.
|
||||
|
||||
## Downloading from Git
|
||||
To install Nimrod from git, ensure that you have gcc installed on Windows, Linux, and BSDs and clang on Mac. Afterwards, run the following series of commands to download and bootstrap Nimrod:
|
||||
|
||||
~~~
|
||||
git clone -b master git://github.com/Araq/Nimrod.git
|
||||
cd Nimrod
|
||||
git clone --depth 1 git://github.com/nimrod-code/csources
|
||||
cd csources
|
||||
sh build.sh # Replace with build.bat on windows
|
||||
cd ..
|
||||
bin/nimrod c koch
|
||||
./koch boot -d:release
|
||||
~~~
|
||||
|
||||
Once compiled, you may want to add the `bin` directory to your path for easy access.
|
||||
21
content/hello_world.md
Normal file
21
content/hello_world.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Hello World
|
||||
|
||||
The code for a simple hello world program is as follows:
|
||||
|
||||
~~~ Nimrod
|
||||
echo "Hello World"
|
||||
~~~
|
||||
|
||||
To compile and execute the program, the following command should be run
|
||||
|
||||
~~~
|
||||
$ nimrod c -r --verbosity:0 ./helloworld.nim
|
||||
Hello World
|
||||
~~~
|
||||
|
||||
The command has several elements:
|
||||
|
||||
* `c` is an alias for `compile`, which compiles the Nimrod sources into C and then invokes the C compiler on them
|
||||
* `-r` is an alias for `--run`, which runs the program
|
||||
* `--verbosity:0` makes the compiler only output essential messages, since by default it also outputs some debugging messages. From now on, we assume that `--verbosity:0` is set
|
||||
* `./helloworld.nim` is the path to the source you want to compile
|
||||
28
content/if_else_while.md
Normal file
28
content/if_else_while.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# If, Else, While, Block
|
||||
|
||||
Nimrod many different control flow constructs, including the standard `if`s, `else`s, and `while`s.
|
||||
|
||||
When inside a loop or block, it is possible to use `continue` or `break` any point, where `continue` skips to the next iteration and `break` ends the loop. The break statement can also receive the name of the block to break out of, so it is possible to break out of nested loops.
|
||||
|
||||
~~~ Nimrod
|
||||
import strutils
|
||||
|
||||
let answer = 4 # Chosen by a fair dice roll,
|
||||
# guaranteed to be random
|
||||
while true:
|
||||
echo "I have a number from 1 to 10, what is it? "
|
||||
let guess = parseInt(stdin.readLine)
|
||||
|
||||
if guess < answer:
|
||||
echo "Too low, try again"
|
||||
elif guess > answer:
|
||||
echo "Too high, try again"
|
||||
else:
|
||||
echo "Correct!"
|
||||
break
|
||||
|
||||
block busyloops:
|
||||
while true:
|
||||
while true:
|
||||
break busyloops
|
||||
~~~
|
||||
20
content/index.md
Normal file
20
content/index.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Nimrod is a powerful statically typed language that allows the programmer expressiveness without compromising run-time performance.
|
||||
|
||||
~~~ nimrod
|
||||
import tables, strutils
|
||||
|
||||
var wordFrequencies = initTable[string, int]
|
||||
|
||||
for line in stdin.lines:
|
||||
for word in line.split(", "):
|
||||
wordFrequencies[word] += 1
|
||||
|
||||
var maxFrequency = 0
|
||||
var mostFrequentWord: string
|
||||
for word, frequency in wordFrequencies:
|
||||
if frequency > maxFrequency:
|
||||
maxFrequency = frequency
|
||||
mostFrequentWord = word
|
||||
|
||||
echo "The most frequent word is '", word, "'"
|
||||
~~~
|
||||
23
content/numbers.md
Normal file
23
content/numbers.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Numbers
|
||||
|
||||
Nimrod has several primitive types:
|
||||
|
||||
* signed integers: `int8`, `int16`, `int32`, `int64`, and `int`, where `int` is the same size as a pointer
|
||||
* unsigned integers are similar with `u` prepended to the type
|
||||
* floating points numbers: `float32`, `float64`, and `float`, where `float` is the processor's fastest type
|
||||
|
||||
To indicate the size of an integer literal, append `u` or `i` and the size you'd like to the end. However, this is not typically necessary.
|
||||
|
||||
Integers can also have `0[xX]`, `0o`, `0[Bb]` prepended to indicate a hex, octal, or binary literal, respectively. Underscores are also valid in literals, and can help with readability.
|
||||
|
||||
~~~ nimrod
|
||||
let
|
||||
a: int8 = 0x7F # Works
|
||||
b: uint8 = 0x1111_1111 # Works
|
||||
d = 0xFF # type is int
|
||||
c: uint8 = 256 # Compile time error
|
||||
~~~
|
||||
|
||||
Precedence rules are the same as most other languages, but instead of `^`, `&`, `|`, `>>`, `<<`, the `xor`, `and`, `or`, `shr`, `shl` operators are used, respectively.
|
||||
|
||||
Another difference that may be surprising is that the `/` operator returns a floating point result, even when the operands are integers. This means that `3/2` will return something like `0.33`. If integer division is needed, the `div` operator should be used.
|
||||
38
content/objects.md
Normal file
38
content/objects.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Objects
|
||||
|
||||
In Nimrod, objects are like structs from C family languages and define a grouping of fields.
|
||||
|
||||
~~~ nimrod
|
||||
type
|
||||
Animal* = object
|
||||
name*, genus*, species*: string
|
||||
age: int # None of your business!
|
||||
PAnimal* = ref Animal
|
||||
|
||||
proc sleep*(a: var Animal) =
|
||||
a.age += 1
|
||||
|
||||
# create a new Animal, not allocated on the heap
|
||||
var carl = Animal(name : "Carl",
|
||||
genus : "Lama",
|
||||
species : "glama",
|
||||
age : 12)
|
||||
|
||||
# Allocate an Animal on the heap
|
||||
# Note that the pointer is immutable, not the pointee
|
||||
let mittens: ref Animal = new(Animal)
|
||||
mittens.name = "Mittens"
|
||||
mittens.genus = "Panthera"
|
||||
mittens.species = "Leo"
|
||||
mittens.age = 6
|
||||
|
||||
# This also goes on the heap since PAnimal is a
|
||||
# reference type
|
||||
let spot = PAnimal(name: "Spot",
|
||||
genus: "Canis",
|
||||
species: "Lupus",
|
||||
age: 1)
|
||||
|
||||
# Same as before, only pointer value is unchangeable
|
||||
spot.age = 2
|
||||
~~~
|
||||
217
content/oop_macro.md
Normal file
217
content/oop_macro.md
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
<!--- Thanks to fowl for creating this page -->
|
||||
|
||||
# OOP Macro
|
||||
This is the code that we currently must write to use OOP in nimrod:
|
||||
~~~nimrod
|
||||
type Animal =
|
||||
ref object {.inheritable.}
|
||||
name: string
|
||||
method vocalize(self: Animal): string = "..."
|
||||
|
||||
type Dog =
|
||||
ref object of Animal
|
||||
lastRabiesDate: int
|
||||
method vocalize(self: Dog): string = "woof"
|
||||
|
||||
type Cat = ref object of Animal
|
||||
method vocalize(self: Cat): string = "meow"
|
||||
~~~
|
||||
|
||||
All these typedefs and `self: T` parameters are repetitive, so it'd be good to write a macro to mask them. Something like this would be best:
|
||||
|
||||
~~~nimrod
|
||||
class(Animal of TObject):
|
||||
var name: string
|
||||
method vocalize: string = "..."
|
||||
|
||||
class(Dog of Animal):
|
||||
var lastRabiesDate: int
|
||||
method vocalize: string = "woof"
|
||||
|
||||
class(Cat of Animal):
|
||||
method vocalize: string = "meow"
|
||||
|
||||
# a short test (used later)
|
||||
proc run_test() =
|
||||
var pets: seq[Animal] = @[]
|
||||
pets.add Cat(name: "meowth")
|
||||
pets.add Dog(name: "ruffles")
|
||||
assert(@["meow", "woof"] == @[pets[0].vocalize,
|
||||
pets[1].vocalize])
|
||||
~~~
|
||||
|
||||
~~~nimrod
|
||||
import macros
|
||||
|
||||
macro class*(): stmt {.immediate.} =
|
||||
# The macro is immediate so that it doesn't
|
||||
# resolve identifiers passed to it
|
||||
|
||||
let cs = callsite()
|
||||
var
|
||||
class_name, in_stmts: PNimrodNode
|
||||
superclass: PNimrodNode
|
||||
|
||||
# Manual parsing of arguments. Here we expect
|
||||
# a class name and attached stmts list
|
||||
if cs[1].kind == nnkInfix and $cs[1][0] == "of":
|
||||
# the expression is "class_name" of "superclass"
|
||||
# echo cs[1].treerepr
|
||||
# -------------------
|
||||
# Infix
|
||||
# Ident !"of"
|
||||
# Ident !"Animal"
|
||||
# Ident !"TObject"
|
||||
|
||||
class_name = cs[1][1]
|
||||
superclass = cs[1][2]
|
||||
else:
|
||||
class_name = cs[1]
|
||||
|
||||
in_stmts = cs[2]
|
||||
|
||||
if in_stmts.kind != nnkStmtList:
|
||||
quit "Malformed arguments for class() macro: expected nnkStmtList, got " &
|
||||
lisprepr(in_stmts)
|
||||
assert class_name.kind == nnkIdent
|
||||
|
||||
# echo treerepr(class_name)
|
||||
# -----------------------------------------
|
||||
# Ident !"Animal"
|
||||
|
||||
# echo treerepr(in_stmts)
|
||||
# ----------------------------------
|
||||
# StmtList
|
||||
# VarSection
|
||||
# IdentDefs
|
||||
# Ident !"name"
|
||||
# Ident !"string"
|
||||
# Empty
|
||||
# IdentDefs
|
||||
# Ident !"age"
|
||||
# Ident !"int"
|
||||
# Empty
|
||||
# MethodDef
|
||||
# Ident !"vocalize"
|
||||
# Empty
|
||||
# Empty
|
||||
# FormalParams
|
||||
# Ident !"string"
|
||||
# Empty
|
||||
# Empty
|
||||
# StmtList
|
||||
# StrLit ...
|
||||
# MethodDef
|
||||
# Ident !"age_human_yrs"
|
||||
# Empty
|
||||
# Empty
|
||||
# FormalParams
|
||||
# Ident !"int"
|
||||
# Empty
|
||||
# Empty
|
||||
# StmtList
|
||||
# DotExpr
|
||||
# Ident !"self"
|
||||
# Ident !"age"
|
||||
|
||||
result = newStmtList()
|
||||
result.add newEmptyNode()
|
||||
# create a new stmtList for the result,
|
||||
# the first slot is a placeholder
|
||||
# the type definition we generate
|
||||
|
||||
var rec_list = newNimNode(nnkRecList)
|
||||
# var declarations will be turned into object fields
|
||||
|
||||
# Iterate over the statements, adding `self: T`
|
||||
# to the parameters of functions
|
||||
for node in children(in_stmts):
|
||||
case node.kind
|
||||
of nnkMethodDef, nnkProcDef:
|
||||
# inject self:T into the arguments
|
||||
let p = node.params.copyNimTree
|
||||
p.insert(1, newIdentDefs(ident"self", class_name))
|
||||
node.params = p
|
||||
result.add node
|
||||
|
||||
of nnkVarSection:
|
||||
# variables get turned into fields on the type,
|
||||
# isn't that neat?
|
||||
# here we just collect them though
|
||||
for N in children(node):
|
||||
assert n.kind == nnkIdentDefs, "Invalid node " & lispRepr(N)
|
||||
rec_list.add N
|
||||
|
||||
else:
|
||||
result.add node
|
||||
|
||||
# The following prints out the AST structure:
|
||||
#
|
||||
# import macros
|
||||
# dumptree:
|
||||
# type X = ref object of Y
|
||||
# z: int
|
||||
# --------------------------
|
||||
# TypeSection
|
||||
# TypeDef
|
||||
# Ident !"X"
|
||||
# Empty
|
||||
# RefTy
|
||||
# ObjectTy
|
||||
# Empty
|
||||
# OfInherit
|
||||
# Ident !"Y"
|
||||
# RecList
|
||||
# IdentDefs
|
||||
# Ident !"z"
|
||||
# Ident !"int"
|
||||
# Empty
|
||||
|
||||
var obj_ty = newNimNode(nnkObjectTy).add(
|
||||
newEmptyNode(),
|
||||
(if superclass.isNil: newEmptyNode() else: newNimNode(nnkOfInherit).add(superclass)),
|
||||
rec_list
|
||||
)
|
||||
result[0] = newNimNode(nnkTypeSection).add(
|
||||
newNimNode(nnkTypeDef).add(
|
||||
class_name,
|
||||
newEmptyNode(),
|
||||
newNimNode(nnkRefTy).add(obj_ty)
|
||||
))
|
||||
|
||||
# Lets inspect the human-readable version of the output
|
||||
# echo repr(result)
|
||||
# Output:
|
||||
# type
|
||||
# Animal = ref object of TObject
|
||||
# name: string
|
||||
# age: int
|
||||
#
|
||||
# method vocalize(self: Animal): string =
|
||||
# "..."
|
||||
#
|
||||
# method age_human_yrs(self: Animal): int =
|
||||
# self.age
|
||||
|
||||
# more could be done here, it could be made an
|
||||
# option to use ref types, export type names, etc
|
||||
|
||||
|
||||
class(Animal of TObject):
|
||||
var
|
||||
name: string
|
||||
age: int
|
||||
method vocalize: string = "..."
|
||||
method age_human_yrs: int = self.age
|
||||
# self is injected
|
||||
|
||||
class(Dog of Animal):
|
||||
method vocalize: string = "woof"
|
||||
method age_human_yrs: int = self.age * 7
|
||||
|
||||
class(Cat of Animal) do:
|
||||
method vocalize: string = "meow"
|
||||
|
||||
run_test()
|
||||
echo "Tests passed!"
|
||||
~~~
|
||||
101
content/stylesheet.css
Normal file
101
content/stylesheet.css
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
font-family: Georgia, Palatino, serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
color: #f30;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #f90;
|
||||
}
|
||||
|
||||
#main {
|
||||
position: absolute;
|
||||
|
||||
top: 40px;
|
||||
left: 280px;
|
||||
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
#main h1 {
|
||||
font-size: 40px;
|
||||
font-weight: normal;
|
||||
|
||||
line-height: 40px;
|
||||
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
#main p {
|
||||
margin: 20px 0;
|
||||
|
||||
font-size: 15px;
|
||||
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#main ul, #main ol {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#main li {
|
||||
font-size: 15px;
|
||||
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#main ul li {
|
||||
list-style-type: square;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
position: absolute;
|
||||
|
||||
top: 40px;
|
||||
left: 20px;
|
||||
width: 200px;
|
||||
|
||||
padding: 20px 20px 0 0;
|
||||
|
||||
border-right: 1px solid #ccc;
|
||||
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#sidebar h2 {
|
||||
text-transform: uppercase;
|
||||
|
||||
font-size: 13px;
|
||||
|
||||
color: #333;
|
||||
|
||||
letter-spacing: 1px;
|
||||
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#sidebar ul {
|
||||
list-style-type: none;
|
||||
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#sidebar li {
|
||||
font-size: 14px;
|
||||
|
||||
line-height: 20px;
|
||||
}
|
||||
16
content/toc.md
Normal file
16
content/toc.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
## Summary
|
||||
|
||||
* [Getting Started](getting_started/)
|
||||
* [Hello World](hello_world/)
|
||||
* [Numbers](numbers/)
|
||||
* [Variables](variables/page/)
|
||||
* [Result](variables/result/)
|
||||
* [Objects](objects/)
|
||||
* [Enums](enums/)
|
||||
* [If, Else, While, Block](if_else_while/)
|
||||
* [Case Statements](case/)
|
||||
* [For Loops & Iterators](for_iterators/)
|
||||
* [Exceptions](exceptions/)
|
||||
* [Functions]()
|
||||
* [Varargs](varargs/)
|
||||
* [OOP Macro](oop_macro/)
|
||||
42
content/varargs.md
Normal file
42
content/varargs.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Varargs
|
||||
|
||||
Standard varargs simply allows you to pass multiple parameters to your function.
|
||||
|
||||
~~~ nimrod
|
||||
proc printThings(things: varargs[string]) =
|
||||
for thing in things:
|
||||
echo thing
|
||||
|
||||
printThings "words", "to", "print"
|
||||
~~~
|
||||
~~~
|
||||
$ nimrod c -r ./varargs1.nim
|
||||
words
|
||||
to
|
||||
print
|
||||
~~~
|
||||
|
||||
However, trying to run
|
||||
|
||||
~~~ nimrod
|
||||
printThings 1, "string", @[1, 2, 3]
|
||||
~~~
|
||||
|
||||
will fail to compile because the compiler won't coerce anything into strings. Luckily enough, there is a tool to fix this, the coercing varargs:
|
||||
|
||||
~~~ nimrod
|
||||
proc printThings(things: varargs[string, `$`]) =
|
||||
for thing in things:
|
||||
echo thing
|
||||
|
||||
printThings "thing 1", 2, @[4, 5, 6]
|
||||
~~~
|
||||
|
||||
~~~
|
||||
$ nimrod c -r ./varargs2.nim
|
||||
thing 1
|
||||
2
|
||||
@[4, 5, 6]
|
||||
~~~
|
||||
|
||||
It works by finding a function `` `$` `` that returns string for each argument type, and applying it to each argument.
|
||||
45
content/variables/page.md
Normal file
45
content/variables/page.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Variables
|
||||
|
||||
Nimrod supports three different types of variables, `let`, `var`, and `const`. As with most things, multiple variables can be declared in the same section.
|
||||
|
||||
~~~ nimrod
|
||||
proc getAlphabet(): string =
|
||||
result = ""
|
||||
for letter in 'a'..'z':
|
||||
result.add(letter)
|
||||
|
||||
const abcs = getAlphabet()
|
||||
|
||||
var
|
||||
a = "foo"
|
||||
b = 0
|
||||
|
||||
let
|
||||
c = "foo"
|
||||
d = 5
|
||||
|
||||
a.add "bar" # This is fine because ``a`` is mutable.
|
||||
b.inc # This is also fine.
|
||||
|
||||
c.add "bar" # This will result in an error.
|
||||
d.inc # As will this.
|
||||
~~~
|
||||
|
||||
~~~
|
||||
$ nimrod c --verbosity:2 ./assignment.nim
|
||||
a20.nim(19, 0) Error: for a 'var' type a variable needs to be passed
|
||||
c.add "bar" # This will result in an error.
|
||||
^
|
||||
~~~
|
||||
|
||||
Without `--verbosity:2` only the error will be shown.
|
||||
|
||||
A `const` variable's value will be evaluated at compile-time, so if you inspect the C sources, you'll see the following line:
|
||||
|
||||
~~~ C
|
||||
STRING_LITERAL(TMP129, "abcdefghijklmnopqrstuvwxyz", 26);
|
||||
~~~
|
||||
|
||||
The limitation with this is that procedures which are evaluated at compile-time cannot interface with C because there is no compile-time foreign function interface at this time.
|
||||
|
||||
As seen in the example, `var` variables are standard mutable variables, you can modify them after they've been assigned. `let` variables on the other hand are immutable variables. This means you can assign to them at creation time and can't change them later on. The difference between `let` and `const` is that a `const`'s expression must be evaluated at compile-time, a `let`'s expression doesn't have this requirement.
|
||||
20
content/variables/result.md
Normal file
20
content/variables/result.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Result
|
||||
|
||||
The `result` variable is a special variable that serves as an implicit return variable. This is useful because in most cases, the control flow semantics of the `return` statement are unneeded. `result` is initialized with the default value for a given return type, so the following code starts as `0`, before being initialized to `number`:
|
||||
|
||||
~~~ nimrod
|
||||
proc `**`(number, power: int): int =
|
||||
result = number
|
||||
for i in 1..power:
|
||||
result *= number
|
||||
~~~
|
||||
|
||||
A possible gotcha is declaring a variable called result and expecting it to have the same semantics.
|
||||
|
||||
~~~ nimrod
|
||||
proc unexpected(): int =
|
||||
var result = 5
|
||||
result += 5
|
||||
|
||||
echo unexpected() # Prints 0, not 10
|
||||
~~~
|
||||
Loading…
Add table
Add a link
Reference in a new issue