I tried to program a Lisp-like sexpr for writing macros, as suggested by mratsim (Mamy Ratsimbazafy). Since I used symbol for tagging symbols, as in Ratsimbazafy's DSL, the compiler issued a warning that symbol is deprecated. It seems that the Nim compiler confused my use of the symbol identifier with something else that existed in a previous avatar of Nim. I am not sure how to fix this kind of bug, but I hoped it can be done, in order to liberate the symbol keyword for the user. By the way, my program is far from satisfactory, and I hope that you people can help me to improve its design and functionality, since it can help people with Lisp mind settings to write macros in Nim.
First, the misplaced warning:
› make APP=cons
nim c -o:cons.x -d:danger --hints:off --nimcache:lixo cons.nim
/Users/ed/nim/tutorial/src/cons.nim(18, 20) Warning: Deprecated since version 0.18.1; All functionality is defined on 'NimNode'.; symbol is deprecated [Deprecated]
CC: stdlib_formatfloat.nim
CC: stdlib_system.nim
CC: stdlib_parseutils.nim
CC: stdlib_strutils.nim
CC: stdlib_os.nim
CC: cons.nim
Now, the program that caused the warning:
import os, strutils, macros
type
SExprKind = enum
IntScalar, FloatScalar, St, Sym, consp
SExpr = ref object
case kind: SExprKind
of IntScalar: intVal: int
of FloatScalar: floatVal: float
of Sym: symbol: string
of St: str: string
of consp: car, cdr: SExpr
template mI(a:int): SExpr=
SExpr(kind: IntScalar, intVal: a)
template sy(s: string): SExpr=
SExpr(kind: Sym, symbol: `s`)
template mS(s:string): SExpr=
SExpr(kind: St, str: s)
template car(s:SExpr) : SExpr=
if s == nil: s
else: s.car
template cdr(s:SExpr) : Sexpr=
if s == nil: s
else: s.cdr
template cons(x:SExpr, y:SExpr) : SExpr=
SExpr(kind: consp, car: x, cdr: y)
proc `$`*(se: SExpr): string =
case se.kind
of IntScalar: result= $se.intVal
of FloatScalar: result = $se.floatVal
of ST: result = '"' & se.str & '"'
of Sym: result = se.symbol
of consp:
result.add("(")
var r = se
if r != nil:
result.add($r.car)
r= r.cdr
while r != nil:
result.add(indent($r.car, 2))
r= r.cdr
result.add(")")
let plus{.compileTime.}= "+".sy
proc walkAST(e:SExpr): NimNode =
case e.kind:
of Sym: return newIdentNode e.symbol
of IntScalar: return newLit e.intVal
of consp:
if car(e) == plus:
var callTree = nnkCall.newTree()
callTree.add newIdentNode"+"
callTree.add e.cdr.car.walkAST
callTree.add e.cdr.cdr.car.walkAST
return callTree
else: return newLit "Erro"
macro def(id:untyped, x:untyped, y:untyped): untyped=
let ix= x.strVal.sy
let iy= y.strVal.sy
let body= cons(plus, cons(ix, cons(iy, nil))).walkAST
quote do:
proc `id`(`x`: int, `y`: int): int=
`body`
def(sum, cx, cy)
proc main() =
echo cons("hi".sy, cons(cons("world".sy, nil), nil))
echo sum(paramStr(1).parseInt, 8)
main()