From a101a0ecb36f21906e966440a4cf0f495fe39f36 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Thu, 10 Mar 2022 23:43:54 -0600 Subject: [PATCH] Generate dataspace patterns from Nim types --- preserves | 2 +- src/syndicate/patterns.nim | 87 +++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 21 deletions(-) diff --git a/preserves b/preserves index 1cf0df2..5f74670 160000 --- a/preserves +++ b/preserves @@ -1 +1 @@ -Subproject commit 1cf0df255f0f18d2e07fe43943f114a66ddb89e9 +Subproject commit 5f746706b6e36534c579a09d693924058325adf1 diff --git a/src/syndicate/patterns.nim b/src/syndicate/patterns.nim index 725c438..14a74f7 100644 --- a/src/syndicate/patterns.nim +++ b/src/syndicate/patterns.nim @@ -1,18 +1,19 @@ # SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[macros, tables, typetraits] +import std/[tables, typetraits] +import preserves/private/macros import preserves import ./protocols/dataspacePatterns from ./actors import Ref -export dataspacePatterns.`$` +export dataspacePatterns.`$`, PatternKind, DCompoundKind type - AnyAtom = dataspacePatterns.AnyAtom[Ref] + AnyAtom* = dataspacePatterns.AnyAtom[Ref] DBind = dataspacePatterns.DBind[Ref] - DCompound* = dataspacePatterns.DCompound[Ref] + DCompound = dataspacePatterns.DCompound[Ref] DCompoundArr = dataspacePatterns.DCompoundArr[Ref] DCompoundDict = dataspacePatterns.DCompoundDict[Ref] DCompoundRec = dataspacePatterns.DCompoundRec[Ref] @@ -74,40 +75,86 @@ proc `?`*(T: typedesc; bindings: sink openArray[(int, Pattern)]): Pattern = else: {.error: "no preserves pragma on " & $T.} -proc `?`*(T: typedesc): Pattern = +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. - when T.hasCustomPragma(preservesRecord): + when T is ref: + ?pointerBase(T) + elif T.hasCustomPragma(preservesRecord): var label = tosymbol(T.getCustomPragmaVal(preservesRecord), Ref) fields = newSeq[Pattern]() - dummy: ptr T - for key, val in fieldPairs(dummy[]): - fields.add grab() + for key, val in fieldPairs(default T): + fields.add ?(typeOf val) result = ?DCompound( orKind: DCompoundKind.rec, rec: DCompoundRec( label: label, fields: fields)) + elif T.hasCustomPragma(preservesTuple): + var arr = DCompoundArr() + for key, val in fieldPairs(default T): + arr.items.add grab() + ?DCompound( + orKind: DCompoundKind.arr, + arr: arr) + elif T.hasCustomPragma(preservesDictionary): + 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 is tuple: - var - arr = DCompoundArr() - dummy: ptr T - for key, val in fieldPairs(dummy[]): + var arr = DCompoundArr() + for key, val in fieldPairs(default T): arr.items.add ?(typeOf val) result = ?DCompound( orKind: DCompoundKind.arr, arr: arr) elif T is object: - var - dict = DCompoundDict() - dummy: ptr T - for key, val in fieldPairs(dummy[]): - dict.entries[key.toSymbol(Ref)] = grab() #?(typeOf val) + var dict = DCompoundDict() + for key, val in fieldPairs(default T): + dict.entries[key.toSymbol(Ref)] = ?(typeOf val) result = ?DCompound( orKind: DCompoundKind.dict, dict: dict) - elif T is ref: - ?pointerBase(T) else: grab() # capture any value + +type + Value = Preserve[Ref] + Path = seq[Value] + Analysis* = tuple + constPaths: seq[Path] + constValues: seq[Value] + capturePaths: seq[Path] + +func walk(result: var Analysis; path: var Path; p: Pattern) + +func walk(result: var Analysis; path: var Path; key: int|Value; pat: Pattern) = + path.add(key.toPreserve(Ref)) + walk(result, path, pat) + discard path.pop + +func walk(result: var Analysis; path: var Path; p: Pattern) = + case p.orKind + of PatternKind.DCompound: + case p.dcompound.orKind + of DCompoundKind.rec: + for k, e in p.dcompound.rec.fields: walk(result, path, k, e) + of DCompoundKind.arr: + for k, e in p.dcompound.arr.items: walk(result, path, k, e) + of DCompoundKind.dict: + for k, e in p.dcompound.dict.entries: walk(result, path, k, e) + of PatternKind.DBind: + result.capturePaths.add(path) + walk(result, path, p.dbind.pattern) + of PatternKind.DDiscard: discard + of PatternKind.DLit: + result.constPaths.add(path) + result.constValues.add(p.dlit.value.toPreserve(Ref)) + +func analyse*(p: Pattern): Analysis = + var path: Path + walk(result, path, p)