discard """ output: '''108 11 -1 1936 0.4 true truefalse''' """ proc `++`(x: var int; y: int = 1; z: int = 0) = x = x + y + z var g = 70 ++g g ++ 7 g.`++`(10, 20) echo g #let lv = stdin.readline #var vv = stdin.readline #vv = "abc" # valid, reassignment allowed #lv = "abc" # fails at compile time #proc square(x: int): int = x*x template square(x: int): int = # ensure 'x' is only evaluated once: let y = x y * y proc mostSignificantBit(n: int): int = # naive algorithm: var n = n while n != 0: n = n shr 1 result += 1 result -= 1 const msb3999 = mostSignificantBit(3999) echo msb3999, " ", mostSignificantBit(0), " ", square(44) proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] = result = @[] # @[] constructs the empty seq for x in a: if predicate(x): result.add(x) proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] = newSeq(result, a.len) for i in 0 ..< a.len: result[i] = fn(a[i]) type FormulaKind = enum fkVar, ## element is a variable like 'X' fkLit, ## element is a literal like 0.1 fkAdd, ## element is an addition operation fkMul, ## element is a multiplication operation fkExp ## element is an exponentiation operation type Formula = ref object case kind: FormulaKind of fkVar: name: string of fkLit: value: float of fkAdd, fkMul, fkExp: left, right: Formula from math import pow proc evaluate(n: Formula, varToVal: proc (name: string): float): float = case n.kind of fkVar: varToVal(n.name) of fkLit: n.value of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal) of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal) of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal)) echo evaluate(Formula(kind: fkLit, value: 0.4), nil) proc isPolyTerm(n: Formula): bool = n.kind == fkMul and n.left.kind == fkLit and (let e = n.right; e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit) proc isPolynomial(n: Formula): bool = isPolyTerm(n) or (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right)) let myFormula = Formula(kind: fkMul, left: Formula(kind: fkLit, value: 2.0), right: Formula(kind: fkExp, left: Formula(kind: fkVar, name: "x"), right: Formula(kind: fkLit, value: 5.0))) echo isPolyTerm(myFormula) proc pat2kind(pattern: string): FormulaKind = case pattern of "^": fkExp of "*": fkMul of "+": fkAdd of "x": fkVar of "c": fkLit else: fkVar # no error reporting for reasons of simplicity import macros proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} = template `@`(current, field: untyped): untyped = newDotExpr(current, newIdentNode(astToStr(field))) template `==@`(n, pattern: untyped): untyped = newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident))) case pattern.kind of CallNodes: result = newCall("and", n ==@ pattern[0], matchAgainst(n@left, pattern[1])) if pattern.len == 3: result = newCall("and", result.copy, matchAgainst(n@right, pattern[2])) of nnkIdent: result = n ==@ pattern of nnkPar: result = matchAgainst(n, pattern[0]) else: error "invalid pattern" macro `=~` (n: Formula, pattern: untyped): bool = result = matchAgainst(n, pattern) proc isPolyTerm2(n: Formula): bool = n =~ c * x^c echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))