Different ?? pattern operator
Make the ?? operator convert a pattern to a pattern of itself and inject other patterns into it.
This commit is contained in:
parent
831b7194a9
commit
b0f5ff98e2
|
@ -27,158 +27,16 @@ runnableExamples:
|
||||||
import std/[macros, tables, typetraits]
|
import std/[macros, tables, typetraits]
|
||||||
import preserves
|
import preserves
|
||||||
import ./syndicate/[actors, dataspaces, durings, patterns]
|
import ./syndicate/[actors, dataspaces, durings, patterns]
|
||||||
|
import ./syndicate/protocols/dataspace
|
||||||
|
|
||||||
from ./syndicate/relays import connectStdio, connectUnix
|
from ./syndicate/relays import connectStdio, connectUnix
|
||||||
|
|
||||||
export Actor, Assertion, Facet, Handle, Ref, Symbol, Turn, TurnAction,
|
export Actor, Assertion, Facet, Handle, Ref, Symbol, Turn, TurnAction,
|
||||||
`$`, `?`, `??`, bootDataspace, connectStdio, connectUnix, drop, facet,
|
`$`, `?`, analyse, bootDataspace, connectStdio, connectUnix, drop, facet,
|
||||||
future, grab, message, newDataspace, publish, retract, replace, run, stop, unembed
|
future, grab, message, newDataspace, publish, retract, replace, run, stop, unembed
|
||||||
|
|
||||||
proc `?`*[T](val: T): Pattern =
|
|
||||||
## Construct a `Pattern` from value of type `T`.
|
|
||||||
when T is Pattern: result = val
|
|
||||||
elif T is Ref:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.embedded,
|
|
||||||
embedded: embed(val))))
|
|
||||||
elif T is ptr | ref:
|
|
||||||
if system.`==`(val, nil): result = ?(Symbol "null")
|
|
||||||
else: result = ?(val[])
|
|
||||||
elif T is bool:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.bool,
|
|
||||||
bool: val)))
|
|
||||||
elif T is float32:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.float,
|
|
||||||
float: val)))
|
|
||||||
elif T is float64:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.double,
|
|
||||||
double: val)))
|
|
||||||
elif T is SomeInteger:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.int,
|
|
||||||
int: AnyAtomInt val)))
|
|
||||||
elif T is string:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.string,
|
|
||||||
string: val)))
|
|
||||||
elif T is seq[byte]:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.bytes,
|
|
||||||
bytes: val)))
|
|
||||||
elif T is enum or T is Symbol:
|
|
||||||
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
|
||||||
value: AnyAtom(
|
|
||||||
orKind: AnyAtomKind.symbol,
|
|
||||||
symbol: Symbol $val)))
|
|
||||||
elif T.hasPreservesRecordPragma:
|
|
||||||
var
|
|
||||||
label = T.recordLabel.tosymbol(Ref)
|
|
||||||
fields = newSeq[Pattern]()
|
|
||||||
for f in fields(val):
|
|
||||||
fields.add ?f
|
|
||||||
result = ?DCompound(
|
|
||||||
orKind: DCompoundKind.rec,
|
|
||||||
rec: DCompoundRec(
|
|
||||||
label: label, fields: fields))
|
|
||||||
else:
|
|
||||||
?(toPreserve(val, Ref))
|
|
||||||
|
|
||||||
proc `?`*(T: static typedesc): Pattern =
|
|
||||||
## Construct a `Pattern` from type `T`.
|
|
||||||
runnableExamples:
|
|
||||||
import preserves
|
|
||||||
|
|
||||||
type Point = tuple[x: int; y: int]
|
|
||||||
assert $(?Point) == "<arr [<bind <_>> <bind <_>>]>"
|
|
||||||
|
|
||||||
type Rect {.preservesRecord: "rect".} = tuple[a: Point; B: Point]
|
|
||||||
assert $(?Rect) == "<rec rect [<arr [<bind <_>> <bind <_>>]> <arr [<bind <_>> <bind <_>>]>]>"
|
|
||||||
|
|
||||||
type ColoredRect {.preservesDictionary.} = tuple[color: string; rect: Rect]
|
|
||||||
assert $(?ColoredRect) == "<dict {color: <bind <_>>, rect: <rec rect [<arr [<bind <_>> <bind <_>>]> <arr [<bind <_>> <bind <_>>]>]>}>"
|
|
||||||
|
|
||||||
## Derive a `Pattern` from type `T`.
|
|
||||||
## This works for `tuple` and `object` types but in the
|
|
||||||
## general case will return a wildcard binding.
|
|
||||||
when T is ref:
|
|
||||||
?pointerBase(T)
|
|
||||||
elif T.hasPreservesRecordPragma:
|
|
||||||
var
|
|
||||||
label = T.recordLabel.tosymbol(Ref)
|
|
||||||
fields = newSeq[Pattern]()
|
|
||||||
for key, val in fieldPairs(default T):
|
|
||||||
fields.add ?(typeOf val)
|
|
||||||
result = ?DCompound(
|
|
||||||
orKind: DCompoundKind.rec,
|
|
||||||
rec: DCompoundRec(
|
|
||||||
label: label, fields: fields))
|
|
||||||
elif T.hasPreservesDictionaryPragma:
|
|
||||||
var dict = DCompoundDict()
|
|
||||||
for key, val in fieldPairs(default T):
|
|
||||||
dict.entries[key.toSymbol(Ref)] = ?(typeOf val)
|
|
||||||
?DCompound(
|
|
||||||
orKind: DCompoundKind.dict,
|
|
||||||
dict: dict)
|
|
||||||
elif T.hasPreservesTuplePragma or T is tuple:
|
|
||||||
var arr = DCompoundArr()
|
|
||||||
for key, val in fieldPairs(default T):
|
|
||||||
arr.items.add ?(typeOf val)
|
|
||||||
?DCompound(
|
|
||||||
orKind: DCompoundKind.arr,
|
|
||||||
arr: arr)
|
|
||||||
else:
|
|
||||||
grab() # otherwise an abritrary capture
|
|
||||||
|
|
||||||
proc fieldCount(T: typedesc): int =
|
|
||||||
for _, _ in fieldPairs(default T):
|
|
||||||
inc result
|
|
||||||
|
|
||||||
proc `?`*(T: static typedesc; bindings: sink openArray[(int, Pattern)]): Pattern =
|
|
||||||
## Construct a `Pattern` from type `T` that selectively captures fields.
|
|
||||||
runnableExamples:
|
|
||||||
import preserves
|
|
||||||
|
|
||||||
type Point = tuple[x: int; y: int; z: int]
|
|
||||||
assert $(Point ? {2: grab()}) == "<arr [<_> <_> <bind <_>>]>"
|
|
||||||
|
|
||||||
when T is ref:
|
|
||||||
`?`(pointerBase(T), bindings)
|
|
||||||
elif T.hasPreservesRecordPragma:
|
|
||||||
var
|
|
||||||
label = T.recordLabel.tosymbol(Ref)
|
|
||||||
fields = newSeq[Pattern](fieldCount T)
|
|
||||||
for (i, pat) in bindings:
|
|
||||||
fields[i] = pat
|
|
||||||
for pat in fields.mitems:
|
|
||||||
if pat.isNil: pat = drop()
|
|
||||||
result = ?DCompound(
|
|
||||||
orKind: DCompoundKind.rec,
|
|
||||||
rec: DCompoundRec(
|
|
||||||
label: label, fields: fields))
|
|
||||||
elif T is tuple:
|
|
||||||
var arr = DCompoundArr()
|
|
||||||
for (i, pat) in bindings:
|
|
||||||
if i > arr.items.high: arr.items.setLen(succ i)
|
|
||||||
arr.items[i] = pat
|
|
||||||
for pat in arr.items.mitems:
|
|
||||||
if pat.isNil: pat = drop()
|
|
||||||
result = ?DCompound(
|
|
||||||
orKind: DCompoundKind.arr,
|
|
||||||
arr: arr)
|
|
||||||
else:
|
|
||||||
{.error: "no preserves pragma on " & $T.}
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
Observe* = dataspace.Observe[Ref]
|
||||||
PublishProc = proc (turn: var Turn; v: Assertion; h: Handle) {.closure.}
|
PublishProc = proc (turn: var Turn; v: Assertion; h: Handle) {.closure.}
|
||||||
RetractProc = proc (turn: var Turn; h: Handle) {.closure.}
|
RetractProc = proc (turn: var Turn; h: Handle) {.closure.}
|
||||||
MessageProc = proc (turn: var Turn; v: Assertion) {.closure.}
|
MessageProc = proc (turn: var Turn; v: Assertion) {.closure.}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import preserves
|
||||||
import ./protocols/dataspacePatterns
|
import ./protocols/dataspacePatterns
|
||||||
from ./actors import Ref
|
from ./actors import Ref
|
||||||
|
|
||||||
export dataspacePatterns.`$`, PatternKind, DCompoundKind
|
export dataspacePatterns.`$`, PatternKind, DCompoundKind, AnyAtomKind
|
||||||
|
|
||||||
type
|
type
|
||||||
Assertion = Preserve[Ref]
|
Assertion = Preserve[Ref]
|
||||||
|
@ -63,6 +63,7 @@ proc `?`*(x: sink Symbol): Pattern =
|
||||||
?AnyAtom(orKind: AnyAtomKind.`symbol`, symbol: x)
|
?AnyAtom(orKind: AnyAtomKind.`symbol`, symbol: x)
|
||||||
|
|
||||||
proc `?`*[T](pr: Preserve[T]): Pattern =
|
proc `?`*[T](pr: Preserve[T]): Pattern =
|
||||||
|
## Convert a `Preserve` value to a `Pattern`.
|
||||||
assert not pr.embedded
|
assert not pr.embedded
|
||||||
case pr.kind
|
case pr.kind
|
||||||
of pkBoolean: ?pr.bool
|
of pkBoolean: ?pr.bool
|
||||||
|
@ -75,9 +76,9 @@ proc `?`*[T](pr: Preserve[T]): Pattern =
|
||||||
of pkRecord:
|
of pkRecord:
|
||||||
?DCompoundRec(
|
?DCompoundRec(
|
||||||
label: pr.label,
|
label: pr.label,
|
||||||
fields: map[Preserve[T], Pattern](pr.fields, `?`[T]))
|
fields: map[Preserve[T], Pattern](pr.fields, `?`))
|
||||||
of pkSequence:
|
of pkSequence:
|
||||||
?DCompoundArr(items: map(pr.sequence, `?`[T]))
|
?DCompoundArr(items: map(pr.sequence, `?`))
|
||||||
of pkSet: raise newException(
|
of pkSet: raise newException(
|
||||||
ValueError, "cannot construct a pattern over a set literal")
|
ValueError, "cannot construct a pattern over a set literal")
|
||||||
of pkDictionary:
|
of pkDictionary:
|
||||||
|
@ -87,38 +88,311 @@ proc `?`*[T](pr: Preserve[T]): Pattern =
|
||||||
of pkEmbedded:
|
of pkEmbedded:
|
||||||
raiseAssert "cannot construct a pattern over a embedded literal"
|
raiseAssert "cannot construct a pattern over a embedded literal"
|
||||||
|
|
||||||
proc `??`*(pat: Pattern): Pattern =
|
|
||||||
## Construct a `Pattern` that matches a `Pattern`.
|
|
||||||
case pat.orKind
|
|
||||||
of PatternKind.DDiscard, PatternKind.DBind:
|
|
||||||
result = pat
|
|
||||||
of PatternKind.DLit:
|
|
||||||
result = ?(pat.toPreserve(Ref))
|
|
||||||
of PatternKind.DCompound:
|
|
||||||
case pat.dcompound.orKind
|
|
||||||
of DCompoundKind.rec:
|
|
||||||
var fields = move pat.dcompound.rec.fields
|
|
||||||
result = ?(pat.toPreserve(Ref))
|
|
||||||
result.dcompound.rec.fields[1].dcompound.arr.items = fields
|
|
||||||
of DCompoundKind.arr:
|
|
||||||
var items = move pat.dcompound.arr.items
|
|
||||||
result = ?(pat.toPreserve(Ref))
|
|
||||||
result.dcompound.rec.fields[0].dcompound.arr.items = items
|
|
||||||
of DCompoundKind.dict:
|
|
||||||
# var entries = move pat.dcompound.dict.entries
|
|
||||||
# result = ?(pat.toPreserve(Ref))
|
|
||||||
stderr.writeLine "pattern construction from DCompoundKind not implemented"
|
|
||||||
raiseAssert "not implemented"
|
|
||||||
|
|
||||||
proc drop*(): Pattern = Pattern(orKind: PatternKind.DDiscard)
|
proc drop*(): Pattern = Pattern(orKind: PatternKind.DDiscard)
|
||||||
proc grab*(): Pattern = ?DBind(pattern: drop())
|
## Create a pattern to match any value without capture.
|
||||||
|
|
||||||
proc `?_`*(): Pattern = drop()
|
proc grab*(): Pattern = ?DBind(pattern: drop())
|
||||||
proc `?*`*(): Pattern = grab()
|
## Create a pattern to capture any value.
|
||||||
|
|
||||||
proc `?`*[A, B](table: TableRef[A,B]): Pattern =
|
proc `?`*[A, B](table: TableRef[A,B]): Pattern =
|
||||||
raiseAssert "not implemented"
|
raiseAssert "not implemented"
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc `?`*(pat: sink Pattern): Pattern =
|
||||||
|
## Construct a `Pattern` that matches a `Pattern`.
|
||||||
|
case pat.orKind
|
||||||
|
of PatternKind.DDiscard: result = pat
|
||||||
|
of PatternKind.DBind: result = drop()
|
||||||
|
of PatternKind.DLit: result = ?pat.toPreserve(Ref)
|
||||||
|
of PatternKind.DCompound:
|
||||||
|
case pat.dcompound.orKind:
|
||||||
|
of DCompoundKind.rec:
|
||||||
|
var fields = move pat.dcompound.rec.fields
|
||||||
|
for f in fields.mitems: f = ?(move f)
|
||||||
|
result = ?pat.toPreserve(Ref)
|
||||||
|
# echo "need to stuff fields into ", result, " at ", result.dcompound.rec.fields[1].dcompound.arr.items
|
||||||
|
result.dcompound.rec.fields[1].dcompound.arr.items = fields
|
||||||
|
#[
|
||||||
|
of DCompoundKind.arr
|
||||||
|
pat.dcompound.arr
|
||||||
|
of DCompoundKind.dict
|
||||||
|
pat.dcompound.dict
|
||||||
|
]#
|
||||||
|
else: raiseAssert "`?` not implemented for pattern " & $pat
|
||||||
|
]#
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc `?`*(patterns: openArray[Pattern]): Pattern =
|
||||||
|
raiseAssert "got it in the right place"
|
||||||
|
#[
|
||||||
|
result = DCompoundArr()
|
||||||
|
for e in val:
|
||||||
|
if i > arr.items.high: arr.items.setLen(succ i)
|
||||||
|
arr.items[i] = pat
|
||||||
|
for pat in arr.items.mitems:
|
||||||
|
if pat.isNil: pat = drop()
|
||||||
|
result = ?DCompound(
|
||||||
|
orKind: DCompoundKind.arr,
|
||||||
|
arr: arr)
|
||||||
|
]#
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc `?`*[T](val: sink T): Pattern =
|
||||||
|
## Construct a `Pattern` from value of type `T`.
|
||||||
|
#[
|
||||||
|
when T is Pattern:
|
||||||
|
case val.orKind
|
||||||
|
of PatternKind.DDiscard, PatternKind.DBind: result = val
|
||||||
|
of PatternKind.DLit: result = ?val.toPreserve(Ref)
|
||||||
|
of PatternKind.DCompound:
|
||||||
|
case val.dcompound.orKind:
|
||||||
|
of DCompoundKind.rec:
|
||||||
|
var fields = move val.dcompound.rec.fields
|
||||||
|
for f in fields.mitems: f = ?(move f)
|
||||||
|
result = ?val.toPreserve(Ref)
|
||||||
|
# echo "need to stuff fields into ", result, " at ", result.dcompound.rec.fields[1].dcompound.arr.items
|
||||||
|
result.dcompound.rec.fields[1].dcompound.arr.items = fields
|
||||||
|
#[
|
||||||
|
of DCompoundKind.arr
|
||||||
|
val.dcompound.arr
|
||||||
|
of DCompoundKind.dict
|
||||||
|
val.dcompound.dict
|
||||||
|
]#
|
||||||
|
else: raiseAssert "`?` not implemented for pattern " & $val
|
||||||
|
]#
|
||||||
|
when T is Ref:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.embedded,
|
||||||
|
embedded: embed(val))))
|
||||||
|
elif T is ptr | ref:
|
||||||
|
if system.`==`(val, nil): result = ?(Symbol "null")
|
||||||
|
else: result = ?(val[])
|
||||||
|
elif T is bool:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.bool,
|
||||||
|
bool: val)))
|
||||||
|
elif T is float32:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.float,
|
||||||
|
float: val)))
|
||||||
|
elif T is float64:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.double,
|
||||||
|
double: val)))
|
||||||
|
elif T is SomeInteger:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.int,
|
||||||
|
int: AnyAtomInt val)))
|
||||||
|
elif T is string:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.string,
|
||||||
|
string: val)))
|
||||||
|
elif T is seq[byte]:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.bytes,
|
||||||
|
bytes: val)))
|
||||||
|
elif T is array | seq:
|
||||||
|
let arr = DCompoundArr(items: newSeq[Pattern](val.len))
|
||||||
|
for i, e in val.mitems: arr.items[i] = ?(move e)
|
||||||
|
result = ?arr
|
||||||
|
elif T is Symbol:
|
||||||
|
result = Pattern(orKind: PatternKind.DLit, dlit: DLit(
|
||||||
|
value: AnyAtom(
|
||||||
|
orKind: AnyAtomKind.symbol,
|
||||||
|
symbol: Symbol $val)))
|
||||||
|
elif T.hasPreservesRecordPragma:
|
||||||
|
var
|
||||||
|
label = T.recordLabel.tosymbol(Ref)
|
||||||
|
fields = newSeq[Pattern]()
|
||||||
|
for f in fields(val):
|
||||||
|
fields.add ?f
|
||||||
|
result = ?DCompound(
|
||||||
|
orKind: DCompoundKind.rec,
|
||||||
|
rec: DCompoundRec(
|
||||||
|
label: label, fields: fields))
|
||||||
|
else:
|
||||||
|
?(toPreserve(val, Ref))
|
||||||
|
|
||||||
|
proc `?`*(T: static typedesc): Pattern =
|
||||||
|
## Derive a `Pattern` from type `T`.
|
||||||
|
## This works for `tuple` and `object` types but in the
|
||||||
|
## general case will return a wildcard binding.
|
||||||
|
runnableExamples:
|
||||||
|
import preserves
|
||||||
|
|
||||||
|
type Point = tuple[x: int; y: int]
|
||||||
|
assert $(?Point) == "<arr [<bind <_>> <bind <_>>]>"
|
||||||
|
|
||||||
|
type Rect {.preservesRecord: "rect".} = tuple[a: Point; B: Point]
|
||||||
|
assert $(?Rect) == "<rec rect [<arr [<bind <_>> <bind <_>>]> <arr [<bind <_>> <bind <_>>]>]>"
|
||||||
|
|
||||||
|
type ColoredRect {.preservesDictionary.} = tuple[color: string; rect: Rect]
|
||||||
|
assert $(?ColoredRect) == "<dict {color: <bind <_>>, rect: <rec rect [<arr [<bind <_>> <bind <_>>]> <arr [<bind <_>> <bind <_>>]>]>}>"
|
||||||
|
when T is Pattern:
|
||||||
|
raiseAssert "? for pattern"
|
||||||
|
elif T is ref:
|
||||||
|
?pointerBase(T)
|
||||||
|
elif T is array:
|
||||||
|
var arr = DCompoundArr(items: newSeq[Pattern](len(T)))
|
||||||
|
for p in arr.items.mitems: p = grab()
|
||||||
|
result = ?arr
|
||||||
|
elif T.hasPreservesRecordPragma:
|
||||||
|
var
|
||||||
|
label = T.recordLabel.tosymbol(Ref)
|
||||||
|
fields = newSeq[Pattern]()
|
||||||
|
for key, val in fieldPairs(default T):
|
||||||
|
when typeOf(val) is Pattern:
|
||||||
|
fields.add drop()
|
||||||
|
else:
|
||||||
|
fields.add ?(typeOf val)
|
||||||
|
result = ?DCompound(
|
||||||
|
orKind: DCompoundKind.rec,
|
||||||
|
rec: DCompoundRec(
|
||||||
|
label: label, fields: fields))
|
||||||
|
elif T.hasPreservesDictionaryPragma:
|
||||||
|
var dict = DCompoundDict()
|
||||||
|
for key, val in fieldPairs(default T):
|
||||||
|
dict.entries[key.toSymbol(Ref)] = ?(typeOf val)
|
||||||
|
?DCompound(
|
||||||
|
orKind: DCompoundKind.dict,
|
||||||
|
dict: dict)
|
||||||
|
elif T.hasPreservesTuplePragma or T is tuple:
|
||||||
|
raiseAssert "got a tuple"
|
||||||
|
var arr = DCompoundArr()
|
||||||
|
for key, val in fieldPairs(default T):
|
||||||
|
arr.items.add ?(typeOf val)
|
||||||
|
?DCompound(
|
||||||
|
orKind: DCompoundKind.arr,
|
||||||
|
arr: arr)
|
||||||
|
else:
|
||||||
|
grab() # otherwise an abritrary capture
|
||||||
|
|
||||||
|
proc fieldCount(T: typedesc): int =
|
||||||
|
for _, _ in fieldPairs(default T):
|
||||||
|
inc result
|
||||||
|
|
||||||
|
proc `?`*(T: static typedesc; bindings: sink openArray[(int, Pattern)]): Pattern =
|
||||||
|
## Construct a `Pattern` from type `T` that selectively captures fields.
|
||||||
|
runnableExamples:
|
||||||
|
import preserves
|
||||||
|
|
||||||
|
type Point = tuple[x: int; y: int; z: int]
|
||||||
|
assert $(Point ? { 2: grab() }) == "<arr [<_> <_> <bind <_>>]>"
|
||||||
|
|
||||||
|
when T is ref:
|
||||||
|
`?`(pointerBase(T), bindings)
|
||||||
|
elif T.hasPreservesRecordPragma:
|
||||||
|
var
|
||||||
|
label = T.recordLabel.tosymbol(Ref)
|
||||||
|
fields = newSeq[Pattern](fieldCount T)
|
||||||
|
for (i, pat) in bindings:
|
||||||
|
fields[i] = pat
|
||||||
|
for pat in fields.mitems:
|
||||||
|
if pat.isNil: pat = drop()
|
||||||
|
result = ?DCompound(
|
||||||
|
orKind: DCompoundKind.rec,
|
||||||
|
rec: DCompoundRec(
|
||||||
|
label: label, fields: fields))
|
||||||
|
elif T is tuple:
|
||||||
|
var arr = DCompoundArr()
|
||||||
|
for (i, pat) in bindings:
|
||||||
|
if i > arr.items.high: arr.items.setLen(succ i)
|
||||||
|
arr.items[i] = pat
|
||||||
|
for pat in arr.items.mitems:
|
||||||
|
if pat.isNil: pat = drop()
|
||||||
|
result = ?DCompound(
|
||||||
|
orKind: DCompoundKind.arr,
|
||||||
|
arr: arr)
|
||||||
|
else:
|
||||||
|
raiseAssert("no preserves pragma on " & $T)
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc `?`*(pat: sink Pattern; bindings: sink openArray[(int, Pattern)]): Pattern =
|
||||||
|
## Construct a `Pattern` from `pat` with overrides from `bindings`.
|
||||||
|
result = pat
|
||||||
|
assert not result.isNil
|
||||||
|
case result.orKind
|
||||||
|
of PatternKind.DDiscard, PatternKind.DBind: discard
|
||||||
|
of PatternKind.DCompound:
|
||||||
|
case result.dcompound.orKind
|
||||||
|
|
||||||
|
of `rec`:
|
||||||
|
echo "need to override record fields ", result.dcompound.rec.fields, " with ", bindings
|
||||||
|
var foo = result.dcompound.rec.fields[1] ? bindings
|
||||||
|
echo "recursing into fields returned ", foo
|
||||||
|
result.dcompound.rec.fields[1] = foo
|
||||||
|
|
||||||
|
|
||||||
|
of `arr`:
|
||||||
|
echo "need to override array items ", result.dcompound.arr.items, " with ", bindings
|
||||||
|
for i in result.dcompound.arr.items.mitems:
|
||||||
|
i = drop()
|
||||||
|
for (i, pat) in bindings:
|
||||||
|
result.dcompound.arr.items[i] = pat
|
||||||
|
|
||||||
|
else:
|
||||||
|
raiseAssert $result.dcompound.orKind
|
||||||
|
else:
|
||||||
|
raiseAssert $result.orKind
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc `??`*(pat: sink Pattern; bindings: sink openArray[(int, Pattern)]): Pattern =
|
||||||
|
## Create a `Pattern` that matches or captures from a `Pattern` over `pat`.
|
||||||
|
runnableExamples:
|
||||||
|
import preserves
|
||||||
|
|
||||||
|
type Point* {.preservesRecord: "point".} = object
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
assert $(?Point) == "<rec point [<bind <_>> <bind <_>>]>"
|
||||||
|
# Capture two values from a value of `Point`.
|
||||||
|
|
||||||
|
assert $(?Point ?? { 0: ?DLit }) == "<rec rec [<lit point> <arr [<rec lit [<bind <_>>]> <_>]>]>"
|
||||||
|
# Match a pattern of `Point` with a literal value set in the first field and capture that value.
|
||||||
|
|
||||||
|
assert $(?tuple[x: int, y: int] ?? { 1: ?DLit }) == "<rec arr [<arr [<_> <rec lit [<bind <_>>]>]>]>"
|
||||||
|
# Match a pattern over a tuple with a literal value set in the second field and capture that value.
|
||||||
|
|
||||||
|
case pat.orKind
|
||||||
|
of PatternKind.DCompound:
|
||||||
|
case pat.dcompound.orKind:
|
||||||
|
|
||||||
|
of DCompoundKind.rec:
|
||||||
|
let fieldsLen = pat.dcompound.rec.fields.len
|
||||||
|
pat.dcompound.rec.fields.setLen 0
|
||||||
|
result = ?pat
|
||||||
|
result.dcompound.rec.fields[1].dcompound.arr.items.setLen fieldsLen
|
||||||
|
for (i, p) in bindings:
|
||||||
|
result.dcompound.rec.fields[1].dcompound.arr.items[i] = p
|
||||||
|
for e in result.dcompound.rec.fields[1].dcompound.arr.items.mitems:
|
||||||
|
if e.isNil: e = drop()
|
||||||
|
|
||||||
|
of DCompoundKind.arr:
|
||||||
|
let itemsLen = pat.dcompound.arr.items.len
|
||||||
|
pat.dcompound.arr.items.setLen 0
|
||||||
|
result = ?pat
|
||||||
|
echo "override ", result.dcompound.rec.fields[0].dcompound.arr.items
|
||||||
|
result.dcompound.rec.fields[0].dcompound.arr.items.setLen itemsLen
|
||||||
|
for (i, p) in bindings:
|
||||||
|
result.dcompound.rec.fields[0].dcompound.arr.items[i] = p
|
||||||
|
for e in result.dcompound.rec.fields[0].dcompound.arr.items.mitems:
|
||||||
|
if e.isNil: e = drop()
|
||||||
|
|
||||||
|
of DCompoundKind.dict:
|
||||||
|
let keys = pat.dcompound.dict.entries.keys.toSeq
|
||||||
|
clear pat.dcompound.dict.entries
|
||||||
|
result = ?pat
|
||||||
|
|
||||||
|
else:
|
||||||
|
raiseAssert "cannot override " & $pat
|
||||||
|
|
||||||
proc recordPattern*(label: Preserve[Ref], fields: varargs[Pattern]): Pattern =
|
proc recordPattern*(label: Preserve[Ref], fields: varargs[Pattern]): Pattern =
|
||||||
?DCompoundRec(label: label, fields: fields.toSeq)
|
?DCompoundRec(label: label, fields: fields.toSeq)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue