Added equality

This commit is contained in:
Andrea Ferretti 2015-07-03 21:04:28 +02:00
commit 35fef5c605
2 changed files with 50 additions and 3 deletions

View file

@ -115,7 +115,7 @@ A couple of limitations fo the `adt` macro:
* field names must be unique across branches (that is, different variants cannot have two fields with the same name). This is actually a limitation of Nim. * field names must be unique across branches (that is, different variants cannot have two fields with the same name). This is actually a limitation of Nim.
* the shortcut that groups field names by type does not seem to work, that is, in the above example one could not write `Rectangle(w, h: float)`. * the shortcut that groups field names by type does not seem to work, that is, in the above example one could not write `Rectangle(w, h: float)`.
In the future, Patty will also add a proper definition of equality and copy constructors. Also, some work needs to be done to make it easier to use the generated contructors with `ref` types, in particular for the important case of recursive algebraic data types. In the future, Patty may also add copy constructors. Also, some work needs to be done to make it easier to use the generated contructors with `ref` types, in particular for the important case of recursive algebraic data types.
Things that do not work (yet) Things that do not work (yet)
----------------------------- -----------------------------

View file

@ -1,4 +1,4 @@
import macros import macros, sequtils
const enumSuffix = "E" const enumSuffix = "E"
@ -109,14 +109,61 @@ proc defineConstructor(e, n: NimNode): NimNode {. compileTime .} =
else: else:
error("Invalid ADT case: " & $(toStrLit(n))) error("Invalid ADT case: " & $(toStrLit(n)))
proc eqFor(n: NimNode): NimNode {. compileTime .} =
if n.kind == nnkObjConstr:
result = newNimNode(nnkOfBranch).add(n[0] & enumSuffix)
var comparisons: seq[NimNode] = @[]
for c in tail(n):
comparisons.add(infix(newDotExpr(ident("a"), c[0]), "==", newDotExpr(ident("b"), c[0])))
let body = foldr(comparisons, infix(a, "and", b))
result.add(newStmtList(newNimNode(nnkReturnStmt).add(body)))
elif n.kind == nnkIdent:
result = newNimNode(nnkOfBranch).add(n & enumSuffix)
result.add(newStmtList(newNimNode(nnkReturnStmt).add(ident("true"))))
else:
error("Invalid ADT case: " & $(toStrLit(n)))
proc defineEquality(tp, body: NimNode): NimNode {. compileTime .} =
# template compare(content, tp: NimNode) =
# proc `==`(a, b: tp): bool =
# if a.kind == b.kind: content
# else: false
var condition = newNimNode(nnkCaseStmt).add(newDotExpr(ident("a"), ident("kind")))
for child in children(body):
condition.add(eqFor(child))
var body = newNimNode(nnkIfExpr).add(
newNimNode(nnkElifBranch).add(
infix(newDotExpr(ident("a"), ident("kind")), "==", newDotExpr(ident("b"), ident("kind"))),
condition
),
newNimNode(nnkElse).add(newStmtList(newNimNode(nnkReturnStmt).add(ident("false"))))
)
result = newProc(
name = ident("`==`"),
params = [ident("bool"), newIdentDefs(ident("a"), tp), newIdentDefs(ident("b"), tp)],
body = body
)
# result = getAst(compare(condition, tp))
macro adt*(e: expr, body: stmt): stmt {. immediate .} = macro adt*(e: expr, body: stmt): stmt {. immediate .} =
result = newStmtList(defineTypes(e, body)) result = newStmtList(defineTypes(e, body), defineEquality(e, body))
for child in children(body): for child in children(body):
result.add(defineConstructor(e, child)) result.add(defineConstructor(e, child))
when defined(pattydebug): when defined(pattydebug):
echo toStrLit(result) echo toStrLit(result)
adt Shape:
Circle(r: float, x: float, y: float)
Rectangle(w: float, h: float)
Square(side: int)
macro match*(e: expr, body: stmt): stmt {. immediate .} = macro match*(e: expr, body: stmt): stmt {. immediate .} =
# A fresh symbol used to hold the evaluation of e # A fresh symbol used to hold the evaluation of e
let sym = genSym() let sym = genSym()