Skip to content

Commit

Permalink
rename, reorganize, new modules, slight cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Feb 19, 2022
1 parent 39ed69a commit 36e6019
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 270 deletions.
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
# unions
# variantsugar

Object variants utilities. Due for a cleanup and rename. See tests for current modules
Utility macros mostly for object variants

```nim
import variantsugar
type Value {.sum, equals.} = object
case kind: _
of None: discard
of Integer, Boolean:
_: int
of Unsigned:
_: uint
of Float:
_: float
# == for case objects generated by equals
assert Value(kind: Integer, integer: 1) == Integer(1)
assert Value(kind: Boolean, integer: 1) == Boolean(1)
assert Value(kind: Unsigned, unsigned: 1) == Unsigned(1)
assert Value(kind: Float, float: 1) == Float(1)
```
2 changes: 0 additions & 2 deletions src/unions.nim

This file was deleted.

207 changes: 0 additions & 207 deletions src/unions/flatbranch.nim

This file was deleted.

2 changes: 2 additions & 0 deletions src/variantsugar.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import variantsugar/[conditional, sum, unionfield, equals]
export conditional, sum, unionfield, equals
35 changes: 15 additions & 20 deletions src/unions/conditional.nim → src/variantsugar/conditional.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
## object variants generalized to any condition for each possible union value

runnableExamples:
conditionalUnion:
type Foo = ref object
num: int
case branch: _ # type has to be _, all types without a case branch with _ as discriminator type are kept in the type section
# the name "branch" can be changed or made _ in which case it defaults to "branch" for now
of Odd, num mod 2 == 1: # branch names can also be _
name: string
of DoubleEven, num mod 4 == 0:
a, b: int
of Even:
a: int # duplicate names are allowed, only the accessors care that they have the same type
type Foo {.conditional.} = ref object
num: int
case branch: _ # type has to be _, all types without a case branch with _ as discriminator type are kept in the type section
# the name "branch" can be changed or made _ in which case it defaults to "branch" for now
of Odd, num mod 2 == 1: # branch names can also be _
name: string
of DoubleEven, num mod 4 == 0:
a, b: int
of Even:
a: int # duplicate names are allowed, only the accessors care that they have the same type

var foo = Foo(num: 1)
foo.name = "abc"
Expand Down Expand Up @@ -216,17 +215,15 @@ proc patchTypeSection(typesec: NimNode, poststmts: var seq[NimNode]) =
newLit("object is not of branch " & names.join(" or ") & " and therefore does not have field `" & fieldName & "`"))))
ifstmt.add(raiser)
setter.add(raiser)
let gettername = if (r[i].kind == nnkPragmaExpr and r[i][0].kind == nnkPostfix) or r[i].kind == nnkPostfix:
postfix(ident(fieldName), "*") else: ident(fieldName)
let gettername = ident(fieldName).exportIf(r[i].isNodeExported)
poststmts.add(newProc(
name = gettername,
params = [r[^2], newIdentDefs(ident"self", ident(typeName))],
body = ifstmt,
procType = nnkProcDef,
pragmas = used
))
let settername = if (r[i].kind == nnkPragmaExpr and r[i][0].kind == nnkPostfix) or r[i].kind == nnkPostfix:
postfix(newTree(nnkAccQuoted, ident(fieldName), ident"="), "*") else: newTree(nnkAccQuoted, ident(fieldName), ident"=")
let settername = newTree(nnkAccQuoted, ident(fieldName), ident"=").exportIf(r[i].isNodeExported)
poststmts.add(newProc(
name = settername,
params = [newEmptyNode(), newIdentDefs(ident"self", newTree(nnkVarTy, ident(typeName))), newIdentDefs(setterValue, r[^2])],
Expand All @@ -248,8 +245,7 @@ proc patchTypeSection(typesec: NimNode, poststmts: var seq[NimNode]) =
for i in 0 .. r.len - 3:
let fieldName = r[i].realBasename
if fieldName notin doneFields:
let gettername = if (r[i].kind == nnkPragmaExpr and r[i][0].kind == nnkPostfix) or r[i].kind == nnkPostfix:
postfix(ident(fieldName), "*") else: ident(fieldName)
let gettername = ident(fieldName).exportIf(r[i].isNodeExported)
# somewhat unsafe
let body = newDotExpr(newDotExpr(newDotExpr(ident"self", unionFieldName), defaultBranch.fieldname), ident(fieldName))
poststmts.add(newProc(
Expand All @@ -261,8 +257,7 @@ proc patchTypeSection(typesec: NimNode, poststmts: var seq[NimNode]) =
))
let setterValue = genSym(nskParam, "value")
let setter = body.newAssignment(setterValue)
let settername = if (r[i].kind == nnkPragmaExpr and r[i][0].kind == nnkPostfix) or r[i].kind == nnkPostfix:
postfix(newTree(nnkAccQuoted, ident(fieldName), ident"="), "*") else: newTree(nnkAccQuoted, ident(fieldName), ident"=")
let settername = newTree(nnkAccQuoted, ident(fieldName), ident"=").exportIf(r[i].isNodeExported)
poststmts.add(newProc(
name = settername,
params = [newEmptyNode(), newIdentDefs(ident"self", newTree(nnkVarTy, ident(typeName))), newIdentDefs(setterValue, r[^2])],
Expand All @@ -272,5 +267,5 @@ proc patchTypeSection(typesec: NimNode, poststmts: var seq[NimNode]) =
))
inc typedefIndex

macro conditionalUnion*(body) =
macro conditional*(body) =
result = applyTypeMacro(body, patchTypeSection)
69 changes: 69 additions & 0 deletions src/variantsugar/equals.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## generates == for objects including case objects

runnableExamples:
type Foo {.equals.} = object
name: string
case kind: bool
of false:
a: int
of true:
b: float

assert Foo(name: "abc", kind: false, a: 1) == Foo(name: "abc", kind: false, a: 1)
assert Foo(name: "abc", kind: false, a: 1) != Foo(name: "abc", kind: true, b: 1)
assert Foo(name: "abc", kind: false, a: 1) != Foo(name: "def", kind: false, a: 1)

import macros, private/utils

proc patchTypeSection(typeSec: NimNode, poststmts: var seq[NimNode]) =
for td in typeSec:
var objectNode = td[^1]
while objectNode.kind in {nnkRefTy, nnkPtrTy}:
objectNode = objectNode[0]
if objectNode.kind == nnkObjectTy:
let doExport = td[0].isNodeExported
let typeName = td[0].realBasename
# ==
proc generateEquals(sl: NimNode, field: NimNode) =
case field.kind
of nnkIdentDefs:
for f in field[0 .. ^3]:
sl.add quote do:
if a.`f` != b.`f`:
return false
of nnkRecCase:
let kf = field[0][0]
sl.add quote do:
if a.`kf` != b.`kf`:
return false
let cs = newTree(nnkCaseStmt, newDotExpr(ident"a", kf))
for b in field[1 .. ^1]:
let branch = copy b
branch[^1] = newStmtList()
for r in b[^1]:
generateEquals(branch[^1], r)
cs.add(branch)
sl.add(cs)
of nnkRecWhen:
let ws = newTree(nnkWhenStmt)
for b in field:
let branch = copy b
branch[^1] = newStmtList()
for r in b[^1]:
generateEquals(branch[^1], r)
ws.add(branch)
sl.add(ws)
else: discard
let equalsBody = newStmtList()
for r in objectNode[^1]:
generateEquals(equalsBody, r)
equalsBody.add(newTree(nnkReturnStmt, ident"true"))
poststmts.add(newProc(
name = ident"==".exportIf(doExport),
params = [ident"bool", newTree(nnkIdentDefs, ident"a", ident"b", ident(typeName), newEmptyNode())],
body = equalsBody,
pragmas = newTree(nnkPragma, ident"used")
))

macro equals*(body) =
result = applyTypeMacro(body, patchTypeSection)
Loading

0 comments on commit 36e6019

Please sign in to comment.