I read the Nimrod intro on drdobbs and built the provided code example.
But it does not compile, in proc matchAgainst I get error messages, they are all related to the template @:
# at n@kind
'kind' cannot be passed to a procvar
# at n@left
undeclared identifier: 'left'
Here is the full code, what did I do wrong?
from math import pow
import macros
type FormulaKind = enum
fkVar,
fkLit,
fkAdd,
fkMul,
fkExp
type Formula = ref object
case kind: FormulaKind
of fkVar: name: string
of fkLit: value: float
of fkAdd, fkMul, fkExp: left, right: Formula
proc pat2kind(pattern: string): FormulaKind =
case pattern
of "^": fkExp
of "*": fkMul
of "+": fkAdd
of "x": fkVar
of "c": fkLit
else: fkVar
proc matchAgainst(n, pattern: PNimrodNode): PNimrodNode {.compileTime.} =
template `@`(current, field: expr): expr =
newDotExpr(current, newIdentNode(astToStr(field)))
template `==@`(n, pattern: expr): expr =
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: expr): bool =
result = matchAgainst(n, pattern)
proc isPolyTerm(n: Formula): bool =
n =~ c * x^c
proc eval(n: Formula, varToVal: proc (name: string): float): float =
case n.kind
of fkVar: varToVal(n.name)
of fkLit: n.value
of fkAdd: eval(n.left, varToVal) + eval(n.right, varToVal)
of fkMul: eval(n.left, varToVal) * eval(n.right, varToVal)
of fkExp: pow(eval(n.left, varToVal), eval(n.right, varToVal))