From 416af8ff5f88301f965092b65b3206d14ea67f81 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 6 Jan 2024 19:28:14 +0200 Subject: [PATCH] preserves_schema_nim: represent embeds with EmbeddedRef Use EmbeddedRef for embbeded values, unless a schema does not name an embedded type. --- preserves.nimble | 2 +- src/preserves/preserves_schema_nim.nim | 90 +++++++++++--------------- 2 files changed, 40 insertions(+), 52 deletions(-) diff --git a/preserves.nimble b/preserves.nimble index fc782d3..e79da16 100644 --- a/preserves.nimble +++ b/preserves.nimble @@ -1,6 +1,6 @@ # Package -version = "20240106" +version = "20240107" author = "Emery Hemingway" description = "data model and serialization format" license = "Unlicense" diff --git a/src/preserves/preserves_schema_nim.nim b/src/preserves/preserves_schema_nim.nim index e289d36..fa683db 100644 --- a/src/preserves/preserves_schema_nim.nim +++ b/src/preserves/preserves_schema_nim.nim @@ -6,10 +6,7 @@ # the schema module must be regenerated! # nim c --path:../../../nim --path:.. -r ./preserves_schema_nim ../../../preserves/schema/schema.bin -# This module formally parameterized types wherever embedded values were found. -# This is no longer the case but some of that code is lingering around. - -import std/[hashes, strutils, sets, tables] +import std/[hashes, sets, strutils, tables] # Cannot use std/macros, must use compiler modules because # we are generating code at run-time. @@ -126,6 +123,23 @@ proc deref(loc: Location; r: Ref): (Location, Definition) = except KeyError: raise newException(KeyError, "reference not found in bundle: " & $r) +proc hasEmbeddedType(scm: Schema): bool = + case scm.field0.embeddedType.orKind + of EmbeddedtypenameKind.false: false + of EmbeddedtypenameKind.Ref: true + +proc embeddedIdentString(scm: Schema): string = + doAssert $scm.field0.embeddedType.ref.name != "" + "Value" + +proc embeddedIdent(scm: Schema): PNode = + ident(embeddedIdentString(scm)) + +proc parameterize(loc: Location; node: PNode; embeddable: bool): PNode = node + +proc parameterize(loc: Location; spec: TypeSpec): PNode = + parameterize(loc, spec.node, spec.isEmbedded) + proc hash(r: Ref): Hash = r.toPreserves.hash type RefSet = HashSet[Ref] @@ -138,8 +152,7 @@ proc attrs(loc: Location; n: NamedAlternative|NamedPattern; seen: RefSet): Attri proc attrs(loc: Location; sp: SimplePattern; seen: RefSet): Attributes = case sp.orKind of SimplepatternKind.atom, SimplepatternKind.lit, SimplepatternKind.any: {} - of SimplepatternKind.embedded: - attrs(loc, sp.embedded.interface, seen) + of SimplepatternKind.embedded: {embedded} of SimplepatternKind.seqof: attrs(loc, sp.seqof.pattern, seen) of SimplepatternKind.setof: @@ -297,7 +310,8 @@ proc isLiteral(loc: Location; sp: SimplePattern): bool = of SimplepatternKind.lit: result = true of SimplepatternKind.embedded: - result = isLiteral(loc, sp.embedded.interface) + if not loc.schema.hasEmbeddedType: + result = isLiteral(loc, sp.embedded.interface) else: discard proc isLiteral(loc: Location; np: NamedPattern): bool = @@ -436,8 +450,12 @@ proc typeIdent(loc: Location; sp: SimplePattern): TypeSpec = result.attrs = key.attrs + val.attrs of SimplepatternKind.Ref: result = TypeSpec(node: ident(sp.ref), attrs: attrs(loc, sp)) + result.node = parameterize(loc, result) of SimplepatternKind.embedded: - result = typeIdent(loc, sp.embedded.interface) + if loc.schema.hasEmbeddedType: + result = TypeSpec(node: ident"EmbeddedRef") + else: + result = TypeSpec(node: ident"Value") incl(result.attrs, embedded) of SimplepatternKind.any, SimplepatternKind.lit: result = TypeSpec(node: ident"Value") @@ -466,6 +484,7 @@ proc toStrLit(loc: Location; sp: SimplePattern): PNode = var (loc, def) = deref(loc, sp.ref) result = toStrLit(loc, def) of SimplePatternKind.embedded: + doAssert not loc.schema.hasEmbeddedType result = PNode(kind: nkStrLit, strVal: "#!" & toStrLit(loc, sp.embedded.interface).strVal) else: raiseAssert $sp @@ -484,6 +503,9 @@ proc toFieldIdent(loc: Location, label: string; pat: Pattern): PNode = proc newEmpty(): PNode = newNode(nkEmpty) +proc embeddingParams(loc: Location; embeddable: bool): PNode = + newEmpty() + proc identDef(scm: Schema; a, b: PNode; embeddable: bool): PNode = nkIdentDefs.newTree(a, b, newEmpty()) @@ -534,7 +556,7 @@ proc typeDef(loc: Location; name: string; pat: SimplePattern; ty: PNode): PNode proc typeDef(loc: Location; name: string; pat: Pattern; ty: PNode): PNode = let - embedParams = newEmpty() + embedParams = embeddingParams(loc, isEmbedded(loc, pat)) id = name.ident.toExport case pat.orKind of PatternKind.CompoundPattern: @@ -576,7 +598,7 @@ proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode = nkPragmaExpr.newTree( name.ident.accQuote.toExport, pragma), - newEmpty(), + embeddingParams(loc, isEmbedded(loc, def)), ty) of DefinitionKind.and: var pragma = nkPragma.newNode @@ -586,7 +608,7 @@ proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode = nkPragmaExpr.newTree( name.ident.accQuote.toExport, pragma), - newEmpty(), + embeddingParams(loc, isEmbedded(loc, def)), ty) of DefinitionKind.Pattern: typeDef(loc, name, def.pattern, ty) @@ -682,7 +704,7 @@ proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: nkPragmaExpr.newTree( ident(cp.tuplePrefix.variable, parentName).accQuote.toExport, nkPragma.newTree(ident"preservesTupleTail")), - variableType.node, + parameterize(loc, variableType), variableType.isEmbedded) of CompoundPatternKind.dict: for nameVal, nsp in cp.dict.entries: @@ -794,6 +816,8 @@ proc nimTypeOf(loc: Location; known: var TypeTable; name: string; orDef: Definit known[memberPath] = typeDef(loc, memberTypeName, na.pattern, ty.node) addAttrs(result, memberType) + memberType.node = parameterize( + loc, memberType.node, isEmbedded(loc, na.pattern)) branchRecList.add nkIdentDefs.newTree( toFieldIdent(loc, na.variantLabel.normalize, na.pattern), memberType.node, newEmpty()) @@ -982,19 +1006,16 @@ proc renderNimBundle*(bundle: Bundle): Table[string, string] = var typeSection = newNode nkTypeSection procs: seq[PNode] - unembeddableType, embeddableType: PNode + unembeddableType: PNode for name, def in scm.field0.definitions.pairs: if isLiteral(loc, def): generateConstProcs(procs, scm, string name, def) else: var name = string name name[0] = name[0].toUpperAscii - var defIdent = ident(name) + var defIdent = parameterize(loc, ident(name), isEmbedded(loc, def)) if not isSymbolEnum(loc, def) and not isAny(loc, def): - if isEmbedded(loc, def): - mergeType(embeddableType, defIdent) - else: - mergeType(unembeddableType, defIdent) + mergeType(unembeddableType, defIdent) let typeSpec = nimTypeOf(loc, typeDefs, name, def) typeDefs[scmPath & @[Symbol name]] = typeDef(loc, name, def, typeSpec.node) generateProcs(procs, scm, name, def) @@ -1003,45 +1024,12 @@ proc renderNimBundle*(bundle: Bundle): Table[string, string] = if typepath.hasPrefix(scmPath): add(typeSection, typeDef) - let imports = nkImportStmt.newNode.add(ident"preserves") block: var importSet: HashSet[string] collectRefImports(importSet, loc, scm) for module in importSet: add(imports, ident(module)) - if not embeddableType.isNil: - let genericParams = newEmpty() - procs.add nkProcDef.newTree( - "$".toFieldIdent, - newEmpty(), - genericParams, - nkFormalParams.newTree( - ident"string", - nkIdentDefs.newTree( - ident"x", - embeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nkStmtList.newTree( - nkCall.newTree(ident"$", - nkCall.newTree(ident"toPreserves", ident"x")))) - procs.add nkProcDef.newTree( - "encode".ident.toExport, - newEmpty(), - genericParams, - nkFormalParams.newTree( - nkBracketExpr.newTree(ident"seq", ident"byte"), - nkIdentDefs.newTree( - ident"x", - embeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nkStmtList.newTree( - nkCall.newTree(ident"encode", - nkCall.newTree(ident"toPreserves", ident"x")))) if not unembeddableType.isNil: procs.add nkProcDef.newTree( "$".toFieldIdent,