# Nim Sample file # Obtained form: https://nim-by-example.github.io/ # Comment ALERT NOTE FIXME #[ Multi-line comment ]# ## Documentation comment ##[ Multi-line documentation comment ]## import strformat type Person = object name: string age: Natural # Ensures the age is positive let people = [ Person(name: "John", age: 45), Person(name: "Kate", age: 30) ] for person in people: # Type-safe string interpolation, # evaluated at compile time. echo(fmt"{person.name} is {person.age} years old") # Thanks to Nim's 'iterator' and 'yield' constructs, # iterators are as easy to write as ordinary # functions. They are compiled to inline loops. iterator oddNumbers[Idx, T](a: array[Idx, T]): T = for x in a: if x mod 2 == 1: yield x for odd in oddNumbers([3, 6, 9, 12, 15, 18]): echo odd # Use Nim's macro system to transform a dense # data-centric description of x86 instructions # into lookup tables that are used by # assemblers and JITs. import macros, strutils macro toLookupTable(data: static[string]): untyped = result = newTree(nnkBracket) for w in data.split(';'): result.add newLit(w) const data = "mov;btc;cli;xor" opcodes = toLookupTable(data) for o in opcodes: echo o # Variables proc getAlphabet(): string = var accm = "" for letter in 'a'..'z': # see iterators accm.add(letter) return accm # Computed at compilation time const alphabet = getAlphabet() # Mutable variables var a = "foo" b = 0 # Works fine, initialized to 0 c: int # Immutable variables let d = "foo" e = 5 # Compile-time error, must be initialized at creation f: float # Works fine, `a` is mutable a.add("bar") b += 1 c = 3 # Compile-time error, const cannot be modified at run-time alphabet = "abc" # Compile-time error, `d` and `e` are immutable d.add("bar") e += 1 # Const STRING_LITERAL(TMP129, "abcdefghijklmnopqrstuvwxyz", 26); # Loops import strutils, random randomize() let answer = random(10) + 1 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 # Case Statements 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 "Unknown" 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) # items and pairs type CustomRange = object low: int high: int iterator items(range: CustomRange): int = var i = range.low while i <= range.high: yield i inc i iterator pairs(range: CustomRange): tuple[a: int, b: char] = for i in range: # uses CustomRange.items yield (i, char(i + ord('a'))) for i, c in CustomRange(low: 1, high: 3): echo c # Operators iterator `...`*[T](a: T, b: T): T = var res: T = T(a) while res <= b: yield res inc res for i in 0...5: echo i # Inline Iterators iterator countTo(n: int): int = var i = 0 while i <= n: yield i inc i for i in countTo(5): echo i # Closure Iterators 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 = "" # Raw iterator usage: while true: # 1. grab an element let next = countTo20() # 2. Is the element bogus? It's the end of the loop, discard it if finished(countTo20): break # 3. Loop body goes here: output.add($next & " ") echo output output = "" let countTo9 = countTo(9) for i in countTo9(): output.add($i) echo output # Procs proc fibonacci(n: int): int = if n < 2: result = n else: result = fibonacci(n - 1) + (n - 2).fibonacci # Operators proc `$`(a: array[2, array[2, int]]): string = result = "" for v in a: for vx in v: result.add($vx & ", ") result.add("\n") echo([[1, 2], [3, 4]]) # See varargs for # how echo works proc `^&*^@%`(a, b: string): string = ## A confusingly named useless operator result = a[0] & b[high(b)] assert("foo" ^&*^@% "bar" == "fr") # Generic Functions # Not really good idea for obvious reasons let zero = "" proc `+`(a, b: string): string = a & b proc `*`[T](a: T, b: int): T = result = zero for i in 0..b-1: result = result + a # calls `+` from line 3 assert("a" * 10 == "aaaaaaaaaa") # Blocks block outer: for i in 0..2000: for j in 0..2000: if i+j == 3145: echo i, ", ", j break outer let b = 3 block: let b = "3" # shadowing is probably a dumb idea # Primitive types let a: int8 = 0x7F # Works b: uint8 = 0b1111_1111 # Works d = 0xFF # type is int c: uint8 = 256 # Compile time error let a: int = 2 b: int = 4 echo 4/2 # Types Aliases type MyInteger* = int let a: int = 2 discard a + MyInteger(4) # Objects type Animal* = object name*, species*: string age: int proc sleep*(a: var Animal) = a.age += 1 proc dead*(a: Animal): bool = result = a.age > 20 var carl: Animal carl = Animal(name : "Carl", species : "L. glama", age : 12) let joe = Animal(name : "Joe", species : "H. sapiens", age : 23) assert(not carl.dead) for i in 0..10: carl.sleep() assert carl.dead # Enums type CompassDirections = enum cdNorth, cdEast, cdSouth, cdWest Colors {.pure.} = enum Red = "FF0000", Green = (1, "00FF00"), Blue = "0000FF" Signals = enum sigQuit = 3, sigAbort = 6, sigKill = 9 # Distinct Types type Dollars* = distinct float var a = 20.Dollars a = 25 # Doesn't compile a = 25.Dollars # Works fine # Strings echo "words words words ⚑" echo """ \n\n """ proc re(s: string): string = s echo r"."".\s\" # Raw string echo re"\b[a-z]++\b" # Regular expression echo function"text" # Tagged string # Arrays type ThreeStringAddress = array[3, string] let names: ThreeStringAddress = ["Jasmine", "Ktisztina", "Kristof"] let addresses: ThreeStringAddress = ["101 Betburweg", "66 Bellion Drive", "194 Laarderweg"] type Matrix[W, H: static[int]] = array[1..W, array[1..H, int]] let mat1: Matrix[2, 2] = [[1, 0], [0, 1]] let mat2: Matrix[2, 2] = [[0, 1], [1, 0]] proc `+`[W, H](a, b: Matrix[W, H]): Matrix[W, H] = for i in 1..high(a): for j in 1..high(a[0]): result[i][j] = a[i][j] + b[i][j] # Seqs var a = @[1, 2, 3] b = newSeq[int](3) for i, v in a: b[i] = v*v for i in 4..100: b.add(i * i) b.delete(0) # takes O(n) time b = a[0] & b # Same as original b # JSON import json let element = "Hydrogen" let atomicNumber = 1 let jsonObject = %* {"element": element, "atomicNumber": atomicNumber} # This will print {"element":"Hydrogen", "atomicNumber": 1} echo $jsonObject # We start with a string representation of a JSON object let jsonObject = """{"name": "Sky", "age": 32}""" let jsonArray = """[7, 8, 9]""" let parsedObject = parseJson(jsonObject) let name = parsedObject["name"].getStr() # This will print Sky echo name let parsedArray = parseJson(jsonArray) let eight = parsedArray[1].getInt() # This will print 8 echo eight # First we'll define our types type Element = object name: string atomicNumber: int # Let's say this is the JSON we want to convert let jsonObject = parseJson("""{"name": "Carbon", "atomicNumber": 6}""") let element = to(jsonObject, Element) # This will print Carbon echo element.name # This will print 6 echo element.atomicNumber # Object Oriented Programming type Animal = ref object of RootObj name: string age: int method vocalize(this: Animal): string {.base.} = "..." method ageHumanYrs(this: Animal): int {.base.} = this.age type Dog = ref object of Animal method vocalize(this: Dog): string = "woof" method ageHumanYrs(this: Dog): int = this.age * 7 type Cat = ref object of Animal method vocalize(this: Cat): string = "meow" var animals: seq[Animal] = @[] animals.add(Dog(name: "Sparky", age: 10)) animals.add(Cat(name: "Mitten", age: 10)) for a in animals: echo a.vocalize() echo a.ageHumanYrs() let slash = "\\"