diff --git a/preserves.nimble b/preserves.nimble index f7ccdd6..97bf736 100644 --- a/preserves.nimble +++ b/preserves.nimble @@ -1,6 +1,6 @@ # Package -version = "20221205" +version = "20221208" author = "Emery Hemingway" description = "data model and serialization format" license = "Unlicense" diff --git a/src/preserves/Tupfile b/src/preserves/Tupfile index bf94229..aadee18 100644 --- a/src/preserves/Tupfile +++ b/src/preserves/Tupfile @@ -1,2 +1,3 @@ include_rules +NIM_PATH += --path:$(TUP_CWD)/.. : foreach *.nim |> !nim_run |> diff --git a/src/preserves/preserves_schema_nim.nim b/src/preserves/preserves_schema_nim.nim index 67542b2..f2f224b 100644 --- a/src/preserves/preserves_schema_nim.nim +++ b/src/preserves/preserves_schema_nim.nim @@ -4,31 +4,30 @@ ## This module implements Nim code generation from Preserves schemas. # This module imports code that it generates! After making any changes here # the schema module must be regenerated! -# nim c -r ./preserves_schema_nim ../../schema.bin +# nim c --path:.. -r ./preserves_schema_nim ../../../preserves/schema/schema.bin -import std/[hashes, sequtils, strutils, sets, tables] +import std/[hashes, strutils, sets, tables] import compiler/[ast, idents, renderer, lineinfos] import ../preserves, ./schema type - Bundle = schema.Bundle[void] - Modules = schema.Modules[void] - Schema = schema.Schema[void] - Definitions = schema.Definitions[void] - Definition = schema.Definition[void] - Pattern = schema.Pattern[void] - SimplePattern = schema.SimplePattern[void] - CompoundPattern = schema.CompoundPattern[void] - DictionaryEntries = schema.DictionaryEntries[void] - NamedAlternative = schema.NamedAlternative[void] - NamedSimplePattern = schema.NamedSimplePattern[void] - NamedPattern = schema.NamedPattern[void] - Binding = schema.Binding[void] + Value = Preserve[void] + Attribute = enum + embedded + ## type contains an embedded value and + ## must take an parameter + recursive + ## type is recursive and therefore must be a ref + Attributes = set[Attribute] + TypeSpec = object + node: PNode + attrs: Attributes + TypeTable = OrderedTable[schema.ModulePath, PNode] + Location = tuple[bundle: Bundle, schemaPath: ModulePath] - TypeSpec = tuple[node: PNode, embeddable: bool] - TypeTable = OrderedTable[string, PNode] +proc schema(loc: Location): Schema = loc.bundle.modules[loc.schemaPath] proc add(parent, child: PNode): PNode {.discardable.} = parent.sons.add child @@ -99,20 +98,18 @@ proc ident(np: NamedSimplePattern; fallback: string): PNode = of NamedSimplePatternKind.`anonymous`: ident(fallback) -proc parameterize(node: PNode; embeddable: bool): PNode = - if embeddable and node.kind notin {nkBracketExpr}: - nn(nkBracketExpr, node, ident"E") - else: node - -proc parameterize(spec: TypeSpec): PNode = - parameterize(spec.node, spec.embeddable) - proc isPreserve(n: PNode): bool = n.kind == nkBracketExpr and - n.renderTree == "Preserve[E]" + n.renderTree == "preserves.Value" -proc orEmbed(x: var TypeSpec; y: TypeSpec) = - x.embeddable = x.embeddable or y.embeddable +proc isEmbedded(ts: TypeSpec): bool = + embedded in ts.attrs + +proc isRecursive(ts: TypeSpec): bool = + recursive in ts.attrs + +proc addAttrs(x: var TypeSpec; y: TypeSpec) = + x.attrs = x.attrs + y.attrs proc dotExtend(result: var PNode; label: string) = var id = ident(label) @@ -123,119 +120,155 @@ proc ident(`ref`: Ref): PNode = for m in`ref`.module: dotExtend(result, string m) dotExtend(result, `ref`.name.string.capitalizeAscii) -proc deref(scm: Schema; r: Ref): Definition = - assert r.module == @[] - scm.data.definitions[r.name] +proc deref(loc: Location; r: Ref): (Location, Definition) = + result[0] = loc + if r.module == @[]: + result[1] = loc.bundle.modules[loc.schemaPath].data.definitions[r.name] + else: + result[0].schemaPath = r.module + result[1] = loc.bundle.modules[r.module].data.definitions[r.name] -proc preserveIdent(scm: Schema): Pnode = - nn(nkBracketExpr, ident"Preserve", ident("E")) +proc hasEmbeddedType(scm: Schema): bool = + case scm.data.embeddedType.orKind + of EmbeddedtypenameKind.`false`: false + of EmbeddedtypenameKind.`Ref`: true + +proc embeddedIdentString(scm: Schema): string = + case scm.data.embeddedType.orKind + of EmbeddedtypenameKind.`false`: + raiseAssert "no embedded type for this module" + of EmbeddedtypenameKind.`Ref`: + doAssert $scm.data.embeddedType.ref.name != "" + $scm.data.embeddedType.ref.name proc embeddedIdent(scm: Schema): PNode = - case scm.data.embeddedType.orKind - of EmbeddedtypenameKind.`false`: ident"void" - of EmbeddedtypenameKind.`Ref`: preserveIdent(scm) + ident(embeddedIdentString(scm)) + +proc preserveIdent(scm: Schema): Pnode = + if scm.hasEmbeddedType: + nn(nkBracketExpr, ident"Preserve", embeddedIdent(scm)) + else: + nn(nkBracketExpr, ident"Preserve", ident"void") + +proc parameterize(scm: Schema; node: PNode; embeddable: bool): PNode = + if embeddable and node.kind notin {nkBracketExpr}: + nn(nkBracketExpr, node, scm.embeddedIdent) + else: node + +proc parameterize(scm: Schema; spec: TypeSpec): PNode = + parameterize(scm, spec.node, spec.isEmbedded) proc hash(r: Ref): Hash = r.toPreserve.hash type RefSet = HashSet[Ref] -proc isEmbeddable(scm: Schema; pat: Pattern; seen: RefSet): bool {.gcsafe.} -proc isEmbeddable(scm: Schema; def: Definition; seen: RefSet): bool {.gcsafe.} +proc attrs(loc: Location; pat: Pattern; seen: RefSet): Attributes {.gcsafe.} +proc attrs(loc: Location; def: Definition; seen: RefSet): Attributes {.gcsafe.} -proc isEmbeddable(scm: Schema; sp: SimplePattern; seen: RefSet): bool = +proc attrs(loc: Location; n: NamedAlternative|NamedPattern; seen: RefSet): Attributes = + attrs(loc, n.pattern, seen) + +proc step(loc: Location; r: Ref): Location = (loc.bundle, r.module) + +proc attrs(loc: Location; sp: SimplePattern; seen: RefSet): Attributes = case sp.orKind - of SimplepatternKind.`atom`, SimplepatternKind.`lit`: false - of SimplepatternKind.`any`: true - of SimplepatternKind.`embedded`: true + of SimplepatternKind.`atom`, SimplepatternKind.`lit`: {} + of SimplepatternKind.`any`, SimplepatternKind.`embedded`: + if loc.schema.hasEmbeddedType: {embedded} + else: {} of SimplepatternKind.`seqof`: - isEmbeddable(scm, sp.seqof.pattern, seen) + attrs(loc, sp.seqof.pattern, seen) of SimplepatternKind.`setof`: - isEmbeddable(scm, sp.setof.pattern, seen) + attrs(loc, sp.setof.pattern, seen) of SimplepatternKind.`dictof`: - isEmbeddable(scm, sp.dictof.key, seen) or - isEmbeddable(scm, sp.dictof.value, seen) + attrs(loc, sp.dictof.key, seen) + attrs(loc, sp.dictof.value, seen) of SimplepatternKind.`Ref`: - if sp.ref.module != @[]: true + if sp.ref in seen: {recursive} else: - if sp.ref in seen: false - else: - var seen = seen - seen.incl sp.ref - isEmbeddable(scm, deref(scm, sp.ref), seen) + var + (loc, def) = deref(loc, sp.ref) + seen = seen + incl(seen, sp.ref) + attrs(loc, def, seen) -proc isEmbeddable(scm: Schema; np: NamedSimplePattern; seen: RefSet): bool = +proc attrs(loc: Location; np: NamedSimplePattern; seen: RefSet): Attributes = case np.orKind of NamedSimplePatternKind.`named`: - isEmbeddable(scm, np.named.pattern, seen) + attrs(loc, np.named.pattern, seen) of NamedSimplePatternKind.`anonymous`: - isEmbeddable(scm, np.anonymous, seen) + attrs(loc, np.anonymous, seen) -proc isEmbeddable(scm: Schema; cp: CompoundPattern; seen: RefSet): bool = +proc attrs(loc: Location; cp: CompoundPattern; seen: RefSet): Attributes = case cp.orKind of CompoundPatternKind.`rec`: - isEmbeddable(scm, cp.rec.label.pattern, seen) or - isEmbeddable(scm, cp.rec.fields.pattern, seen) + result = + attrs(loc, cp.rec.label.pattern, seen) + + attrs(loc, cp.rec.fields.pattern, seen) of CompoundPatternKind.`tuple`: - any(cp.tuple.patterns) do (np: NamedPattern) -> bool: - isEmbeddable(scm, np.pattern, seen) + for np in cp.tuple.patterns: + result = result + attrs(loc, np.pattern, seen) of CompoundPatternKind.`tupleprefix`: - proc pred(np: NamedPattern): bool = - isEmbeddable(scm, np.pattern, seen) - isEmbeddable(scm, cp.tupleprefix.variable, seen) or - any(cp.tupleprefix.fixed, pred) + result = attrs(loc, cp.tupleprefix.variable, seen) + for p in cp.tupleprefix.fixed: + result = result + attrs(loc, p, seen) of CompoundPatternKind.`dict`: - true # the key type is `Preserve` + discard -proc isEmbeddable(scm: Schema; pat: Pattern; seen: RefSet): bool = +proc attrs(loc: Location; pat: Pattern; seen: RefSet): Attributes = case pat.orKind of PatternKind.`SimplePattern`: - isEmbeddable(scm, pat.simplePattern, seen) + attrs(loc, pat.simplePattern, seen) of PatternKind.`CompoundPattern`: - isEmbeddable(scm, pat.compoundPattern, seen) + attrs(loc, pat.compoundPattern, seen) -proc isEmbeddable(scm: Schema; orDef: DefinitionOr; seen: RefSet): bool = - proc isEmbeddable(na: NamedAlternative): bool = - isEmbeddable(scm, na.pattern, seen) - isEmbeddable(orDef.data.pattern0) or - isEmbeddable(orDef.data.pattern1) or - sequtils.any(orDef.data.patternN, isEmbeddable) +proc attrs(loc: Location; orDef: DefinitionOr; seen: RefSet): Attributes = + result = attrs(loc, orDef.data.pattern0, seen) + attrs(loc, orDef.data.pattern1, seen) + for p in orDef.data.patternN: + result = result + attrs(loc, p, seen) -proc isEmbeddable(scm: Schema; def: Definition; seen: RefSet): bool = +proc attrs(loc: Location; def: Definition; seen: RefSet): Attributes = case def.orKind - of DefinitionKind.`or`: isEmbeddable(scm, def.or, seen) + of DefinitionKind.`or`: result = attrs(loc, def.or, seen) of DefinitionKind.`and`: - proc isEmbeddable(np: NamedPattern): bool = - isEmbeddable(scm, np.pattern, seen) - isEmbeddable(def.and.data.pattern0) or - isEmbeddable(def.and.data.pattern1) or - any(def.and.data.patternN, isEmbeddable) + result = attrs(loc, def.and.data.pattern0, seen) + attrs(loc, def.and.data.pattern1, seen) + for p in def.and.data.patternN: + result = result + attrs(loc, p, seen) of DefinitionKind.`Pattern`: - isEmbeddable(scm, def.pattern, seen) + result = attrs(loc, def.pattern, seen) -proc isEmbeddable(scm: Schema; p: Definition|DefinitionOr|Pattern|CompoundPattern|SimplePattern): bool = +proc attrs(loc: Location; p: Definition|DefinitionOr|Pattern|CompoundPattern|SimplePattern): Attributes = var seen: RefSet - isEmbeddable(scm, p, seen) + attrs(loc, p, seen) -proc isLiteral(scm: Schema; def: Definition): bool {.gcsafe.} +proc isEmbedded(loc: Location; p: Definition|DefinitionOr|Pattern|CompoundPattern): bool = + embedded in attrs(loc, p) -proc isLiteral(scm: Schema; sp: SimplePattern): bool = +proc isRecursive(loc: Location; p: Definition|DefinitionOr|Pattern|CompoundPattern): bool = + recursive in attrs(loc, p) + +proc isLiteral(loc: Location; def: Definition): bool {.gcsafe.} + +proc isLiteral(loc: Location; sp: SimplePattern): bool = case sp.orKind - of SimplepatternKind.`Ref`: + of SimplepatternKind.Ref: if sp.ref.module.len == 0: - result = isLiteral(scm, deref(scm, sp.ref)) + var (loc, def) = deref(loc, sp.ref) + result = isLiteral(loc, def) of SimplepatternKind.lit: result = true + of SimplepatternKind.embedded: + result = isLiteral(loc, sp.embedded.interface) else: discard -proc isLiteral(scm: Schema; pat: Pattern): bool = +proc isLiteral(loc: Location; pat: Pattern): bool = case pat.orKind of PatternKind.SimplePattern: - isLiteral(scm, pat.simplePattern) + isLiteral(loc, pat.simplePattern) of PatternKind.CompoundPattern: false # TODO it could be a compound of all literals -proc isLiteral(scm: Schema; def: Definition): bool = +proc isLiteral(loc: Location; def: Definition): bool = if def.orKind == DefinitionKind.Pattern: - result = isLiteral(scm, def.pattern) + result = isLiteral(loc, def.pattern) proc isRef(sp: SimplePattern): bool = sp.orKind == SimplePatternKind.`Ref` @@ -247,37 +280,39 @@ proc isRef(pat: Pattern): bool = proc isSimple(pat: Pattern): bool = pat.orKind == PatternKind.SimplePattern -proc isSymbolEnum(scm: Schema; orDef: DefinitionOr): bool = - proc isLiteral(na: NamedAlternative): bool = isLiteral(scm, na.pattern) - result = isLiteral(orDef.data.pattern0) and isLiteral(orDef.data.pattern1) +proc isLiteral(loc: Location; na: NamedAlternative): bool = isLiteral(loc, na.pattern) + +proc isSymbolEnum(loc: Location; orDef: DefinitionOr): bool = + result = isLiteral(loc, orDef.data.pattern0) and isLiteral(loc, orDef.data.pattern1) for na in orDef.data.patternN: if not result: break - result = isLiteral(na) + result = isLiteral(loc, na) -proc isSymbolEnum(scm: Schema; def: Definition): bool = +proc isSymbolEnum(loc: Location; def: Definition): bool = case def.orKind of DefinitionKind.Pattern: if def.pattern.orKind == PatternKind.SimplePattern and - def.pattern.simplePattern.orKind == SimplepatternKind.`Ref` and - def.pattern.simplePattern.ref.module.len == 0: - result = isSymbolEnum(scm, deref(scm, def.pattern.simplePattern.ref)) - # TODO: no need to de-ref this + def.pattern.simplePattern.orKind == SimplepatternKind.`Ref`: + var (loc, def) = deref(loc, def.pattern.simplePattern.ref) + result = isSymbolEnum(loc, def) of DefinitionKind.or: - result = isSymbolEnum(scm, def.or) + result = isSymbolEnum(loc, def.or) else: discard -proc isSymbolEnum(scm: Schema; sp: SimplePattern): bool = +proc isSymbolEnum(loc: Location; sp: SimplePattern): bool = # HashSet - if sp.orKind == SimplepatternKind.`Ref` and sp.ref.module.len == 0: - result = isSymbolEnum(scm, deref(scm, sp.ref)) + if sp.orKind == SimplepatternKind.`Ref`: + var (loc, def) = deref(loc, sp.ref) + result = isSymbolEnum(loc, def) else: discard -proc isAny(scm: Schema; def: Definition): bool = +proc isAny(loc: Location; def: Definition): bool = if def.orKind == DefinitionKind.Pattern: if def.pattern.orKind == PatternKind.SimplePattern: case def.pattern.simplePattern.orKind of SimplePatternKind.Ref: - result = isAny(scm, deref(scm, def.pattern.simplePattern.`ref`)) + var (loc, def) = deref(loc, def.pattern.simplePattern.`ref`) + result = isAny(loc, def) of SimplePatternKind.any: result = true else: discard @@ -292,79 +327,97 @@ proc typeIdent(atom: AtomKind): PNode = of AtomKind.`Bytestring`: nn(nkBracketExpr, ident"seq", ident"byte") of AtomKind.`Symbol`: ident"Symbol" -proc typeIdent(scm: Schema; sp: SimplePattern): TypeSpec = +proc typeIdent(loc: Location; sp: SimplePattern): TypeSpec = + let scm = loc.schema case sp.orKind of SimplepatternKind.`atom`: - result = (typeIdent(sp.atom.atomKind), false) + result = TypeSpec(node: typeIdent(sp.atom.atomKind)) of SimplepatternKind.`seqof`: - result = typeIdent(scm, sp.seqof.pattern) + result = typeIdent(loc, sp.seqof.pattern) result.node = nn(nkBracketExpr, ident"seq", result.node) of SimplepatternKind.`setof`: - result = typeIdent(scm, sp.setof.pattern) + result = typeIdent(loc, sp.setof.pattern) result.node = - if isSymbolEnum(scm, sp.setof.pattern): + if isSymbolEnum(loc, sp.setof.pattern): nn(nkBracketExpr, ident"set", result.node) else: nn(nkBracketExpr, ident"HashSet", result.node) of SimplepatternKind.`dictof`: let - key = typeIdent(scm, sp.dictof.key) - val = typeIdent(scm, sp.dictof.value) + key = typeIdent(loc, sp.dictof.key) + val = typeIdent(loc, sp.dictof.value) result.node = nn(nkBracketExpr, ident"Table", key.node, val.node) - result.embeddable = key.embeddable or val.embeddable + result.attrs = key.attrs + val.attrs of SimplepatternKind.`Ref`: - result = (ident(sp.ref), isEmbeddable(scm, sp)) - result.node = parameterize(result) - else: - result = (preserveIdent(scm), true) + result = TypeSpec(node: ident(sp.ref), attrs: attrs(loc, sp)) + result.node = parameterize(scm, result) + of SimplepatternKind.`embedded`: + case scm.data.embeddedType.orKind + of EmbeddedtypenameKind.`false`: + result = typeIdent(loc, sp.embedded.interface) + of EmbeddedtypenameKind.`Ref`: + result = TypeSpec(node: scm.embeddedIdent()) + incl(result.attrs, embedded) + of SimplepatternKind.`any`, SimplepatternKind.`lit`: + result = TypeSpec(node: preserveIdent(scm)) -proc typeIdent(scm: Schema; pat: Pattern): TypeSpec = +proc typeIdent(loc: Location; pat: Pattern): TypeSpec = case pat.orKind - of PatternKind.SimplePattern: typeIdent(scm, pat.simplePattern) + of PatternKind.SimplePattern: typeIdent(loc, pat.simplePattern) else: raiseAssert "no typeIdent for " & $pat proc toExport(n: sink PNode): PNode = nkPostFix.newNode.add(ident"*", n) -proc toStrLit(scm: Schema; sp: SimplePattern): PNode = +proc toStrLit(loc: Location; sp: SimplePattern): PNode {.gcsafe.} + +proc toStrLit(loc: Location; def: Definition): PNode = + if def.orKind == DefinitionKind.Pattern: + if def.pattern.orKind == PatternKind.SimplePattern: + return toStrLit(loc, def.pattern.simplepattern) + raiseAssert "not a string literal" + +proc toStrLit(loc: Location; sp: SimplePattern): PNode = case sp.orKind - of SimplePatternKind.`lit`: + of SimplePatternKind.lit: result = PNode(kind: nkStrLit, strVal: $sp.lit.value) - of SimplePatternKind.`Ref`: - let def = deref(scm, sp.ref) - result = toStrLit(scm, def.pattern.simplePattern) - else: assert false + of SimplePatternKind.Ref: + var (loc, def) = deref(loc, sp.ref) + result = toStrLit(loc, def) + of SimplePatternKind.embedded: + result = PNode(kind: nkStrLit, strVal: "#!" & $sp.embedded.interface) + else: raiseAssert $sp proc toFieldIdent(s: string): PNode = nn(nkPostFix, ident("*"), nn(nkAccQuoted, ident(s))) -proc toFieldIdent(scm: Schema, label: string; pat: Pattern): PNode = +proc toFieldIdent(loc: Location, label: string; pat: Pattern): PNode = result = label.toFieldIdent - if isLiteral(scm, pat): + if isLiteral(loc, pat): result = nn(nkPragmaExpr, result, nn(nkPragma, nn(nkExprColonExpr, ident"preservesLiteral", - toStrLit(scm, pat.simplePattern)))) + toStrLit(loc, pat.simplePattern)))) proc newEmpty(): PNode = newNode(nkEmpty) -proc embeddingParams(embeddable: bool): PNode = +proc embeddingParams(scm: Schema; embeddable: bool): PNode = if embeddable: - nn(nkGenericParams, nn(nkIdentDefs, ident"E", newEmpty(), newEmpty())) + nn(nkGenericParams, nn(nkIdentDefs, embeddedIdent(scm), newEmpty(), newEmpty())) else: newEmpty() -proc identDef(a, b: PNode; embeddable: bool): PNode = - if embeddable and b.kind notin {nkBracketExpr, nkTupleTy}: - # TODO: probably not a sufficient check - nn(nkIdentDefs, a, nn(nkBracketExpr, b, ident"E"), newEmpty()) +proc identDef(scm: Schema; a, b: PNode; embeddable: bool): PNode = + if embeddable and b.kind notin {nkBracketExpr, nkTupleTy} and + (b.kind != nkIdent or b.ident.s != scm.embeddedIdentString): + nn(nkIdentDefs, a, nn(nkBracketExpr, b, embeddedIdent(scm)), newEmpty()) else: nn(nkIdentDefs, a, b, newEmpty()) -proc identDef(l: PNode; ts: TypeSpec): PNode = - identDef(l, ts.node, ts.embeddable) +proc identDef(scm: Schema; l: PNode; ts: TypeSpec): PNode = + identDef(scm, l, ts.node, ts.isEmbedded) proc label(pat: Pattern): string = raiseAssert "need to derive record label for " & $pat @@ -397,11 +450,13 @@ proc idStr(np: NamedPattern): string = of NamedPatternKind.`anonymous`: np.anonymous.idStr -proc typeDef(scm: Schema; name: string; pat: Pattern; ty: PNode): PNode = +proc typeDef(loc: Location; name: string; pat: Pattern; ty: PNode): PNode = let - embedParams = embeddingParams(isEmbeddable(scm, pat)) + scm = loc.schema + embedParams = embeddingParams(scm, isEmbedded(loc, pat)) id = name.ident.toExport - if pat.orKind == PatternKind.`CompoundPattern`: + case pat.orKind + of PatternKind.`CompoundPattern`: case pat.compoundPattern.orKind of CompoundPatternKind.`rec`: nn(nkTypeDef, @@ -425,121 +480,131 @@ proc typeDef(scm: Schema; name: string; pat: Pattern; ty: PNode): PNode = else: nn(nkTypeDef, name.ident.toExport, embedParams, ty) -proc typeDef(scm: Schema; name: string; def: Definition; ty: PNode): PNode = +proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode = case def.orKind of DefinitionKind.or: let pragma = nn(nkPragma, ident"preservesOr") - if isSymbolEnum(scm, def): + if isSymbolEnum(loc, def): pragma.add ident"pure" nn(nkTypeDef, nn(nkPragmaExpr, name.ident.accQuote.toExport, pragma), - embeddingParams(isEmbeddable(scm, def)), + embeddingParams(loc.schema, isEmbedded(loc, def)), ty) of DefinitionKind.and: raiseAssert "And variants not suported" of DefinitionKind.Pattern: - typeDef(scm, name, def.pattern, ty) + typeDef(loc, name, def.pattern, ty) -proc nimTypeOf(scm: Schema; known: var TypeTable; nsp: NamedSimplePattern; name = ""): TypeSpec -proc nimTypeOf(scm: Schema; known: var TypeTable; pat: Pattern; name = ""): TypeSpec +proc nimTypeOf(loc: Location; known: var TypeTable; nsp: NamedSimplePattern; name = ""): TypeSpec +proc nimTypeOf(loc: Location; known: var TypeTable; pat: Pattern; name = ""): TypeSpec -proc nimTypeOf(scm: Schema; known: var TypeTable; cp: CompoundPattern; name = ""): TypeSpec -proc nimTypeOf(scm: Schema; known: var TypeTable; sp: SimplePattern; name = ""): TypeSpec = - typeIdent(scm, sp) +proc nimTypeOf(loc: Location; known: var TypeTable; cp: CompoundPattern; name = ""): TypeSpec +proc nimTypeOf(loc: Location; known: var TypeTable; sp: SimplePattern; name = ""): TypeSpec = + typeIdent(loc, sp) -proc addField(recList: PNode; scm: Schema; known: var TypeTable; sp: SimplePattern; label: string): PNode {.discardable.} = - let id = label.toFieldIdent - if isLiteral(scm, sp): +proc addField(recList: PNode; loc: Location; known: var TypeTable; sp: SimplePattern; label: string): PNode {.discardable.} = + let + scm = loc.schema + id = label.toFieldIdent + if isLiteral(loc, sp): let id = nn(nkPragmaExpr, id, nn(nkPragma, nn(nkExprColonExpr, ident"preservesLiteral", - toStrLit(scm, sp)))) - recList.add identDef(id, (ident"bool", false)) + toStrLit(loc, sp)))) + recList.add identDef(scm, id, TypeSpec(node: ident"bool")) + elif sp.orKind == SimplePatternKind.embedded and not scm.hasEmbeddedType: + let id = nn(nkPragmaExpr, + id, nn(nkPragma, ident"preservesEmbedded")) + recList.add identDef(scm, id, nimTypeOf(loc, known, sp)) else: - recList.add identDef(id, nimTypeOf(scm, known, sp)) + recList.add identDef(scm, id, nimTypeOf(loc, known, sp)) -proc addFields(recList: PNode; scm: Schema; known: var TypeTable; cp: CompoundPattern; parentName: string): PNode {.discardable.} = +proc addFields(recList: PNode; loc: Location; known: var TypeTable; cp: CompoundPattern; parentName: string): PNode {.discardable.} = + let scm = loc.schema template addField(np: NamedPattern) = let label = np.label id = label.toFieldIdent pattern = np.pattern if pattern.isRef or pattern.isSimple: - addField(recList, scm, known, pattern.simplePattern, label) + addField(recList, loc, known, pattern.simplePattern, label) else: var typeName = parentName & capitalizeAscii(label) - fieldSpec = nimTypeOf(scm, known, pattern, label) - known[typeName] = typeDef(scm, typeName, pattern, fieldSpec.node) - recList.add identDef(id, ident(typeName), isEmbeddable(scm, pattern)) + typePath = loc.schemaPath & @[Symbol typeName] + fieldSpec = nimTypeOf(loc, known, pattern, label) + known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node) + recList.add identDef(scm, id, ident(typeName), isEmbedded(loc, pattern)) case cp.orKind of CompoundPatternKind.rec: - # recList.add identDef(ident(label), nimTypeOf(scm, known, cp, "")) + # recList.add identDef(scm, ident(label), nimTypeOf(loc, known, cp, "")) raiseassert "unexpected record of fields " #& $cp.rec of CompoundPatternKind.tuple: for np in cp.tuple.patterns: addField(np) of CompoundPatternKind.tuplePrefix: for np in cp.tuplePrefix.fixed: addField(np) - let variableType = nimTypeOf(scm, known, cp.tuplePrefix.variable) + let variableType = nimTypeOf(loc, known, cp.tuplePrefix.variable) recList.add identDef( + scm, nn(nkPragmaExpr, ident(cp.tuplePrefix.variable, parentName).accQuote.toExport, nn(nkPragma, ident"preservesTupleTail")), - variableType.parameterize, - variableType.embeddable) + parameterize(scm, variableType), + variableType.isEmbedded) else: raiseAssert "not adding fields for " #& $cp reclist -proc addFields(recList: PNode; scm: Schema; known: var TypeTable; pat: Pattern; parentName: string): PNode {.discardable.} = +proc addFields(recList: PNode; loc: Location; known: var TypeTable; pat: Pattern; parentName: string): PNode {.discardable.} = case pat.orKind of PatternKind.SimplePattern: - addField(recList, scm, known, pat.simplePattern, "data") + addField(recList, loc, known, pat.simplePattern, "data") of PatternKind.CompoundPattern: - discard addFields(recList, scm, known, pat.compoundPattern, parentName) + discard addFields(recList, loc, known, pat.compoundPattern, parentName) reclist -proc addFields(recList: PNode; scm: Schema; known: var TypeTable; entries: DictionaryEntries; parentName: string): PNode {.discardable.} = +proc addFields(recList: PNode; loc: Location; known: var TypeTable; entries: DictionaryEntries; parentName: string): PNode {.discardable.} = for key, val in entries.pairs: doAssert(key.isSymbol) let label = string key.symbol - addField(recList, scm, known, val.pattern, label) + addField(recList, loc, known, val.pattern, label) recList -proc nimTypeOf(scm: Schema; known: var TypeTable; nsp: NamedSimplePattern; name: string): TypeSpec = +proc nimTypeOf(loc: Location; known: var TypeTable; nsp: NamedSimplePattern; name: string): TypeSpec = case nsp.orKind of NamedsimplepatternKind.named: - nimTypeOf(scm, known, nsp.named.pattern, string nsp.named.name) + nimTypeOf(loc, known, nsp.named.pattern, string nsp.named.name) of NamedsimplepatternKind.anonymous: - nimTypeOf(scm, known, nsp.anonymous, name) + nimTypeOf(loc, known, nsp.anonymous, name) -proc nimTypeOf(scm: Schema; known: var TypeTable; cp: CompoundPattern; name: string): TypeSpec = +proc nimTypeOf(loc: Location; known: var TypeTable; cp: CompoundPattern; name: string): TypeSpec = case cp.orKind of CompoundPatternKind.`rec`: result.node = nn(nkObjectTy, newEmpty(), newEmpty(), - nn(nkRecList).addFields(scm, known, cp.rec.fields.pattern, name)) + nn(nkRecList).addFields(loc, known, cp.rec.fields.pattern, name)) of CompoundPatternKind.`tuple`, CompoundPatternKind.`tupleprefix`: result.node = nn(nkObjectTy, newEmpty(), newEmpty(), - nn(nkRecList).addFields(scm, known, cp, name)) + nn(nkRecList).addFields(loc, known, cp, name)) of CompoundPatternKind.`dict`: result.node = nn(nkObjectTy, newEmpty(), newEmpty(), - nn(nkRecList).addFields(scm, known, cp.dict.entries, name)) - if result.node.kind == nkObjectTy and isEmbeddable(scm, cp): + nn(nkRecList).addFields(loc, known, cp.dict.entries, name)) + if result.node.kind == nkObjectTy and isRecursive(loc, cp): result.node = nn(nkRefTy, result.node) -proc nimTypeOf(scm: Schema; known: var TypeTable; pat: Pattern; name: string): TypeSpec = +proc nimTypeOf(loc: Location; known: var TypeTable; pat: Pattern; name: string): TypeSpec = case pat.orKind of PatternKind.SimplePattern: - nimTypeOf(scm, known, pat.simplePattern, name) + nimTypeOf(loc, known, pat.simplePattern, name) of PatternKind.CompoundPattern: - nimTypeOf(scm, known, pat.compoundPattern, name) + nimTypeOf(loc, known, pat.compoundPattern, name) -proc nimTypeOf(scm: Schema; known: var TypeTable; orDef: DefinitionOr; name: string): TypeSpec = +proc nimTypeOf(loc: Location; known: var TypeTable; orDef: DefinitionOr; name: string): TypeSpec = + let scm = loc.schema proc toEnumTy(): PNode = let ty = nkEnumTy.newNode.add newEmpty() proc add (na: NamedAlternative) = @@ -549,14 +614,15 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; orDef: DefinitionOr; name: str for na in orDef.data.patternN: add(na) ty - if isSymbolEnum(scm, orDef): + if isSymbolEnum(loc, orDef): result.node = toEnumTy() else: let enumName = name & "Kind" + enumPath = loc.schemaPath & @[Symbol enumName] enumIdent = ident(enumName) - if enumName notin known: - known[enumName] = nn(nkTypeDef, + if enumPath notin known: + known[enumPath] = nn(nkTypeDef, nn(nkPragmaExpr, enumName.ident.toExport, nn(nkPragma, ident"pure")), @@ -570,23 +636,25 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; orDef: DefinitionOr; name: str template addCase(na: NamedAlternative) = let branchRecList = nn(nkRecList) var memberType: TypeSpec - if isLiteral(scm, na.pattern): + if isLiteral(loc, na.pattern): memberType.node = ident"bool" elif na.pattern.isRef: - memberType = typeIdent(scm, na.pattern) + memberType = typeIdent(loc, na.pattern) else: - let memberTypeName = name & na.variantLabel.capitalizeAscii + let + memberTypeName = name & na.variantLabel.capitalizeAscii + memberPath = loc.schemaPath & @[Symbol memberTypeName] memberType.node = ident memberTypeName - let ty = nimTypeOf(scm, known, na.pattern, memberTypeName) - orEmbed memberType, ty - if memberTypeName notin known and not isLiteral(scm, na.pattern): - known[memberTypeName] = - typeDef(scm, memberTypeName, na.pattern, ty.node) - orEmbed result, memberType + let ty = nimTypeOf(loc, known, na.pattern, memberTypeName) + addAttrs(memberType, ty) + if memberPath notin known and not isLiteral(loc, na.pattern): + known[memberPath] = + typeDef(loc, memberTypeName, na.pattern, ty.node) + addAttrs(result, memberType) memberType.node = parameterize( - memberType.node, isEmbeddable(scm, na.pattern)) + scm, memberType.node, isEmbedded(loc, na.pattern)) branchRecList.add nn(nkIdentDefs, - toFieldIdent(scm, na.variantLabel.normalize, na.pattern), + toFieldIdent(loc, na.variantLabel.normalize, na.pattern), memberType.node, newEmpty()) recCase.add nn(nkOfBranch, nn(nkDotExpr, @@ -599,40 +667,41 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; orDef: DefinitionOr; name: str newEmpty(), newEmpty(), nn(nkRecList, recCase)) - if result.node.kind == nkObjectTy and isEmbeddable(scm, orDef): + # result.attrs = attrs(loc, orDef) + if result.node.kind == nkObjectTy and (recursive in attrs(loc, orDef)): result.node = nn(nkRefTy, result.node) -proc nimTypeOf(scm: Schema; known: var TypeTable; def: Definition; name: string): TypeSpec = +proc nimTypeOf(loc: Location; known: var TypeTable; def: Definition; name: string): TypeSpec = case def.orKind of DefinitionKind.or: - nimTypeOf(scm, known, def.or, name) - of DefinitionKind.and: raiseAssert "And definitions are unsupported" + nimTypeOf(loc, known, def.or, name) + of DefinitionKind.and: raiseAssert """"And" definitions are unsupported""" of DefinitionKind.Pattern: - nimTypeOf(scm, known, def.pattern, name) + nimTypeOf(loc, known, def.pattern, name) proc generateConstProcs(result: var seq[PNode]; scm: Schema, name: string; def: Definition) = discard -proc literalToPreserveCall(scm: Schema; pr: Preserve): PNode = +proc literalToPreserveCall(scm: Schema; pr: Value): PNode = var prConstr = nn(nkObjConstr, preserveIdent(scm)) proc constr(kind, field: string; lit: PNode) = prConstr.add nn(nkExprColonExpr, ident"kind", ident(kind)) prConstr.add nn(nkExprColonExpr, ident(field), lit) - case pr.orKind + case pr.kind of pkBoolean: - constr($pr.orKind, "bool", if pr.bool: ident"true" else: ident"false") + constr($pr.kind, "bool", if pr.bool: ident"true" else: ident"false") of pkFloat: - constr($pr.orKind, "float", newFloatNode(nkFloat32Lit, pr.float)) + constr($pr.kind, "float", newFloatNode(nkFloat32Lit, pr.float)) of pkDouble: - constr($pr.orKind, "double", newFloatNode(nkFloat64Lit, pr.double)) + constr($pr.kind, "double", newFloatNode(nkFloat64Lit, pr.double)) of pkSignedInteger: - constr($pr.orKind, "BiggestInt", newIntNode(nkInt64Lit, pr.int)) + constr($pr.kind, "BiggestInt", newIntNode(nkInt64Lit, pr.int)) of pkString: - constr($pr.orKind, "string", newStrNode(nkTripleStrLit, pr.string)) + constr($pr.kind, "string", newStrNode(nkTripleStrLit, pr.string)) of pkByteString: return nn(nkCall, ident"parsePreserves", newStrNode(nkTripleStrLit, $pr)) of pkSymbol: - constr($pr.orKind, "symbol", newStrNode(nkStrLit, string pr.symbol)) + constr($pr.kind, "symbol", newStrNode(nkStrLit, string pr.symbol)) else: raise newException(ValueError, "refusing to convert to a literal: " & $pr) prConstr @@ -694,114 +763,132 @@ proc collectRefImports(imports: PNode; scm: Schema) = for _, def in scm.data.definitions: collectRefImports(imports, def) -proc renderNimModule*(scm: Schema): string = - ## Construct and render a Nim module from a `Schema`. - proc mergeType(x: var PNode; y: PNode) = - if x.isNil: x = y - else: x = nn(nkInfix, ident"|", x, y) - var - typeDefs: TypeTable - typeSection = newNode nkTypeSection - procs: seq[PNode] - unembeddableType, embeddableType: PNode - for name, def in scm.data.definitions.pairs: - if isLiteral(scm, def): - generateConstProcs(procs, scm, string name, def) - else: - var name = string name - name[0] = name[0].toUpperAscii - var defIdent = parameterize(ident(name), isEmbeddable(scm, def)) - if not isSymbolEnum(scm, def) and not isAny(scm, def): - if isEmbeddable(scm, def): - mergeType(embeddableType, defIdent) - else: - mergeType(unembeddableType, defIdent) - let typeSpec = nimTypeOf(scm, typeDefs, def, name) - typeDefs[name] = typeDef(scm, name, def, typeSpec.node) - generateProcs(procs, scm, name, def) - for td in typeDefs.values: - typeSection.add td - var imports = nkImportStmt.newNode.add( - ident"std/typetraits", - ident"preserves") - collectRefImports(imports, scm) - let genericParams = - nn(nkGenericParams, nn(nkIdentDefs, ident"E", newEmpty(), newEmpty())) - if not embeddableType.isNil: - procs.add nn(nkProcDef, - "$".toFieldIdent, - newEmpty(), - genericParams, - nn(nkFormalParams, - ident"string", - nn(nkIdentDefs, - ident"x", - embeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nn(nkStmtList, - nn(nkCall, ident"$", - nn(nkCall, ident"toPreserve", ident"x", ident"E")))) - procs.add nn(nkProcDef, - "encode".ident.toExport, - newEmpty(), - genericParams, - nn(nkFormalParams, - nn(nkBracketExpr, ident"seq", ident"byte"), - nn(nkIdentDefs, - ident"x", - embeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nn(nkStmtList, - nn(nkCall, ident"encode", - nn(nkCall, ident"toPreserve", ident"x", ident"E")))) - if not unembeddableType.isNil: - procs.add nn(nkProcDef, - "$".toFieldIdent, - newEmpty(), - newEmpty(), - nn(nkFormalParams, - ident"string", - nn(nkIdentDefs, - ident"x", - unembeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nn(nkStmtList, - nn(nkCall, ident"$", - nn(nkCall, ident"toPreserve", ident"x")))) - procs.add nn(nkProcDef, - "encode".ident.toExport, - newEmpty(), - newEmpty(), - nn(nkFormalParams, - nn(nkBracketExpr, ident"seq", ident"byte"), - nn(nkIdentDefs, - ident"x", - unembeddableType, - newEmpty())), - newEmpty(), - newEmpty(), - nn(nkStmtList, - nn(nkCall, ident"encode", nn(nkCall, - ident"toPreserve", ident"x")))) - var module = newNode(nkStmtList).add( - imports, - typeSection - ).add(procs) - renderTree(module, {renderNone, renderIr}) +proc mergeType(x: var PNode; y: PNode) = + if x.isNil: x = y + else: x = nn(nkInfix, ident"|", x, y) + +proc hasPrefix(a, b: ModulePath): bool = + for i, e in b: + if i > a.high or a[i] != e: return false + true + +proc renderNimBundle*(bundle: Bundle): Table[string, string] = + ## Render Nim modules from a `Bundle`. + result = initTable[string, string](bundle.modules.len) + var typeDefs: TypeTable + for scmPath, scm in bundle.modules: + var + typeSection = newNode nkTypeSection + procs: seq[PNode] + unembeddableType, embeddableType: PNode + for name, def in scm.data.definitions.pairs: + let loc = (bundle, scmPath) + if isLiteral(loc, def): + generateConstProcs(procs, scm, string name, def) + else: + var name = string name + name[0] = name[0].toUpperAscii + var defIdent = parameterize(scm, 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) + let typeSpec = nimTypeOf(loc, typeDefs, def, name) + typeDefs[scmPath & @[Symbol name]] = typeDef(loc, name, def, typeSpec.node) + generateProcs(procs, scm, name, def) + + for typePath, typeDef in typeDefs.pairs: + if typepath.hasPrefix(scmPath): + add(typeSection, typeDef) + + var imports = nkImportStmt.newNode.add( + ident"std/typetraits", + ident"preserves") + collectRefImports(imports, scm) + if not embeddableType.isNil: + let genericParams = + nn(nkGenericParams, nn(nkIdentDefs, embeddedIdent(scm), newEmpty(), newEmpty())) + procs.add nn(nkProcDef, + "$".toFieldIdent, + newEmpty(), + genericParams, + nn(nkFormalParams, + ident"string", + nn(nkIdentDefs, + ident"x", + embeddableType, + newEmpty())), + newEmpty(), + newEmpty(), + nn(nkStmtList, + nn(nkCall, ident"$", + nn(nkCall, ident"toPreserve", ident"x", embeddedIdent(scm))))) + procs.add nn(nkProcDef, + "encode".ident.toExport, + newEmpty(), + genericParams, + nn(nkFormalParams, + nn(nkBracketExpr, ident"seq", ident"byte"), + nn(nkIdentDefs, + ident"x", + embeddableType, + newEmpty())), + newEmpty(), + newEmpty(), + nn(nkStmtList, + nn(nkCall, ident"encode", + nn(nkCall, ident"toPreserve", ident"x", embeddedIdent(scm))))) + if not unembeddableType.isNil: + procs.add nn(nkProcDef, + "$".toFieldIdent, + newEmpty(), + newEmpty(), + nn(nkFormalParams, + ident"string", + nn(nkIdentDefs, + ident"x", + unembeddableType, + newEmpty())), + newEmpty(), + newEmpty(), + nn(nkStmtList, + nn(nkCall, ident"$", + nn(nkCall, ident"toPreserve", ident"x")))) + procs.add nn(nkProcDef, + "encode".ident.toExport, + newEmpty(), + newEmpty(), + nn(nkFormalParams, + nn(nkBracketExpr, ident"seq", ident"byte"), + nn(nkIdentDefs, + ident"x", + unembeddableType, + newEmpty())), + newEmpty(), + newEmpty(), + nn(nkStmtList, + nn(nkCall, ident"encode", nn(nkCall, + ident"toPreserve", ident"x")))) + var module = newNode(nkStmtList).add( + imports, + typeSection + ).add(procs) + var filePath = "" + for p in scmPath: + if filePath != "": add(filePath, '/') + add(filePath, string p) + add(filePath, ".nim") + result[filePath] = renderTree(module, {renderNone, renderIr}) when isMainModule: import ./schemaparse - proc writeModule(scm: Schema; path: string) = - let txt = renderNimModule(scm) - writeFile(path, txt) - stdout.writeLine(path) + proc writeModules(bundle: Bundle) = + let modules = renderNimBundle(bundle) + for path, txt in modules.pairs: + writeFile(path, txt) + stdout.writeLine(path) import std/[options, os, parseopt] var inputs: seq[string] @@ -816,28 +903,32 @@ when isMainModule: of cmdArgument: inputs.add absolutePath(key) of cmdEnd: discard - for filepath in inputs: - var useful: bool - let raw = readFile filepath - if raw[0] == 0xb4.char: - let pr = decodePreserves raw - preserveTo(pr, Schema).map do (scm: Schema): - useful = true - let - (_, name, _) = splitFile(filepath) - outputPath = name & ".nim" - writeModule(scm, outputPath) - preserveTo(pr, Bundle).map do (bundle: Bundle): - useful = true - for modPath, scm in bundle.modules: - let path = joinPath(cast[seq[string]](modPath)) & ".nim" - writeModule(scm, path) + for inputPath in inputs: + var bundle: Bundle + if dirExists inputPath: + for filePath in walkDirRec(inputPath, relative = true): + var (dirPath, fileName, fileExt) = splitFile(filePath) + if fileExt == ".prs": + var + scm = parsePreservesSchema(readFile(inputPath / filePath), inputPath / dirPath) + path: ModulePath + for e in split(dirPath, '/'): + add(path, Symbol e) + add(path, Symbol fileName) + bundle.modules[path] = scm + elif fileExists inputPath: + var (dirPath, fileName, fileExt) = splitFile inputPath + let raw = readFile inputPath + if raw[0] == 0xb4.char: + var pr = decodePreserves raw + if not fromPreserve(bundle, pr): + var schema: Schema + if fromPreserve(schema, pr): + bundle.modules[@[Symbol fileName]] = schema + else: + var scm = parsePreservesSchema(readFile(inputPath), dirPath) + bundle.modules[@[Symbol fileName]] = scm + if bundle.modules.len == 0: + quit "Failed to recognize " & inputPath else: - let - (dir, name, _) = splitFile filepath - scm = parsePreservesSchema(raw, dir) - modpath = name & ".nim" - writeModule(scm, modpath) - useful = true - if not useful: - quit "Failed to recognized " & filepath + writeModules(bundle) diff --git a/src/preserves/private/preserves_encode.nim b/src/preserves/private/preserves_encode.nim index c529e1b..8291b5f 100644 --- a/src/preserves/private/preserves_encode.nim +++ b/src/preserves/private/preserves_encode.nim @@ -37,7 +37,7 @@ when isMainModule: of "preserves_to_xml": let pr = stdin.readAll.decodePreserves var xn: XmlNode - if fromPreserveHook(xn, pr): + if fromPreserve(xn, pr): stdout.writeLine(xn) else: quit("Preserves not convertable to XML") diff --git a/src/preserves/schema.nim b/src/preserves/schema.nim index 4649ef2..5fcd971 100644 --- a/src/preserves/schema.nim +++ b/src/preserves/schema.nim @@ -1,5 +1,5 @@ -import ../preserves, std/typetraits, std/tables +import ../preserves, std/tables type Ref* {.preservesRecord: "ref".} = object @@ -7,89 +7,90 @@ type `name`*: Symbol ModulePath* = seq[Symbol] - Bundle*[E] {.preservesRecord: "bundle".} = ref object - `modules`*: Modules[E] + Bundle* {.preservesRecord: "bundle".} = object + `modules`*: Modules CompoundPatternKind* {.pure.} = enum `rec`, `tuple`, `tuplePrefix`, `dict` - CompoundPatternRec*[E] {.preservesRecord: "rec".} = ref object - `label`*: NamedPattern[E] - `fields`*: NamedPattern[E] + CompoundPatternRec* {.preservesRecord: "rec".} = ref object + `label`*: NamedPattern + `fields`*: NamedPattern - CompoundPatternTuple*[E] {.preservesRecord: "tuple".} = ref object - `patterns`*: seq[NamedPattern[E]] + CompoundPatternTuple* {.preservesRecord: "tuple".} = ref object + `patterns`*: seq[NamedPattern] - CompoundPatternTuplePrefix*[E] {.preservesRecord: "tuplePrefix".} = ref object - `fixed`*: seq[NamedPattern[E]] - `variable`*: NamedSimplePattern[E] + CompoundPatternTuplePrefix* {.preservesRecord: "tuplePrefix".} = ref object + `fixed`*: seq[NamedPattern] + `variable`*: NamedSimplePattern - CompoundPatternDict*[E] {.preservesRecord: "dict".} = ref object - `entries`*: DictionaryEntries[E] + CompoundPatternDict* {.preservesRecord: "dict".} = ref object + `entries`*: DictionaryEntries - `CompoundPattern`*[E] {.preservesOr.} = ref object + `CompoundPattern`* {.preservesOr.} = ref object case orKind*: CompoundPatternKind of CompoundPatternKind.`rec`: - `rec`*: CompoundPatternRec[E] + `rec`*: CompoundPatternRec of CompoundPatternKind.`tuple`: - `tuple`*: CompoundPatternTuple[E] + `tuple`*: CompoundPatternTuple of CompoundPatternKind.`tuplePrefix`: - `tupleprefix`*: CompoundPatternTuplePrefix[E] + `tupleprefix`*: CompoundPatternTuplePrefix of CompoundPatternKind.`dict`: - `dict`*: CompoundPatternDict[E] + `dict`*: CompoundPatternDict - - Modules*[E] = Table[ModulePath, Schema[E]] + + Modules* = Table[ModulePath, Schema] EmbeddedTypeNameKind* {.pure.} = enum - `false`, `Ref` + `false`, `Ref` `EmbeddedTypeName`* {.preservesOr.} = object case orKind*: EmbeddedTypeNameKind of EmbeddedTypeNameKind.`false`: `false`* {.preservesLiteral: "#f".}: bool + of EmbeddedTypeNameKind.`Ref`: `ref`*: Ref - + `AtomKind`* {.preservesOr, pure.} = enum `Boolean`, `Float`, `Double`, `SignedInteger`, `String`, `ByteString`, `Symbol` - Definitions*[E] = Table[Symbol, Definition[E]] - DictionaryEntries*[E] = Table[Preserve[E], NamedSimplePattern[E]] + Definitions* = Table[Symbol, Definition] + DictionaryEntries* = Table[Preserve[void], NamedSimplePattern] NamedPatternKind* {.pure.} = enum `named`, `anonymous` - `NamedPattern`*[E] {.preservesOr.} = ref object + `NamedPattern`* {.preservesOr.} = ref object case orKind*: NamedPatternKind of NamedPatternKind.`named`: - `named`*: Binding[E] + `named`*: Binding of NamedPatternKind.`anonymous`: - `anonymous`*: Pattern[E] - + `anonymous`*: Pattern + SimplePatternKind* {.pure.} = enum `any`, `atom`, `embedded`, `lit`, `seqof`, `setof`, `dictof`, `Ref` SimplePatternAtom* {.preservesRecord: "atom".} = object `atomKind`*: AtomKind - SimplePatternEmbedded*[E] {.preservesRecord: "embedded".} = ref object - `interface`*: SimplePattern[E] + SimplePatternEmbedded* {.preservesRecord: "embedded".} = ref object + `interface`*: SimplePattern - SimplePatternLit*[E] {.preservesRecord: "lit".} = ref object - `value`*: Preserve[E] + SimplePatternLit* {.preservesRecord: "lit".} = object + `value`*: Preserve[void] - SimplePatternSeqof*[E] {.preservesRecord: "seqof".} = ref object - `pattern`*: SimplePattern[E] + SimplePatternSeqof* {.preservesRecord: "seqof".} = ref object + `pattern`*: SimplePattern - SimplePatternSetof*[E] {.preservesRecord: "setof".} = ref object - `pattern`*: SimplePattern[E] + SimplePatternSetof* {.preservesRecord: "setof".} = ref object + `pattern`*: SimplePattern - SimplePatternDictof*[E] {.preservesRecord: "dictof".} = ref object - `key`*: SimplePattern[E] - `value`*: SimplePattern[E] + SimplePatternDictof* {.preservesRecord: "dictof".} = ref object + `key`*: SimplePattern + `value`*: SimplePattern - `SimplePattern`*[E] {.preservesOr.} = ref object + `SimplePattern`* {.preservesOr.} = ref object case orKind*: SimplePatternKind of SimplePatternKind.`any`: `any`* {.preservesLiteral: "any".}: bool @@ -98,119 +99,116 @@ type `atom`*: SimplePatternAtom of SimplePatternKind.`embedded`: - `embedded`*: SimplePatternEmbedded[E] + `embedded`*: SimplePatternEmbedded of SimplePatternKind.`lit`: - `lit`*: SimplePatternLit[E] + `lit`*: SimplePatternLit of SimplePatternKind.`seqof`: - `seqof`*: SimplePatternSeqof[E] + `seqof`*: SimplePatternSeqof of SimplePatternKind.`setof`: - `setof`*: SimplePatternSetof[E] + `setof`*: SimplePatternSetof of SimplePatternKind.`dictof`: - `dictof`*: SimplePatternDictof[E] + `dictof`*: SimplePatternDictof of SimplePatternKind.`Ref`: `ref`*: Ref - + NamedSimplePatternKind* {.pure.} = enum `named`, `anonymous` - `NamedSimplePattern`*[E] {.preservesOr.} = ref object + `NamedSimplePattern`* {.preservesOr.} = ref object case orKind*: NamedSimplePatternKind of NamedSimplePatternKind.`named`: - `named`*: Binding[E] + `named`*: Binding of NamedSimplePatternKind.`anonymous`: - `anonymous`*: SimplePattern[E] - + `anonymous`*: SimplePattern + DefinitionKind* {.pure.} = enum `or`, `and`, `Pattern` - DefinitionOrData*[E] {.preservesTuple.} = ref object - `pattern0`*: NamedAlternative[E] - `pattern1`*: NamedAlternative[E] - `patternN`* {.preservesTupleTail.}: seq[NamedAlternative[E]] + DefinitionOrData* {.preservesTuple.} = ref object + `pattern0`*: NamedAlternative + `pattern1`*: NamedAlternative + `patternN`* {.preservesTupleTail.}: seq[NamedAlternative] - DefinitionOr*[E] {.preservesRecord: "or".} = ref object - `data`*: DefinitionOrData[E] + DefinitionOr* {.preservesRecord: "or".} = ref object + `data`*: DefinitionOrData - DefinitionAndData*[E] {.preservesTuple.} = ref object - `pattern0`*: NamedPattern[E] - `pattern1`*: NamedPattern[E] - `patternN`* {.preservesTupleTail.}: seq[NamedPattern[E]] + DefinitionAndData* {.preservesTuple.} = ref object + `pattern0`*: NamedPattern + `pattern1`*: NamedPattern + `patternN`* {.preservesTupleTail.}: seq[NamedPattern] - DefinitionAnd*[E] {.preservesRecord: "and".} = ref object - `data`*: DefinitionAndData[E] + DefinitionAnd* {.preservesRecord: "and".} = ref object + `data`*: DefinitionAndData - `Definition`*[E] {.preservesOr.} = ref object + `Definition`* {.preservesOr.} = ref object case orKind*: DefinitionKind of DefinitionKind.`or`: - `or`*: DefinitionOr[E] + `or`*: DefinitionOr of DefinitionKind.`and`: - `and`*: DefinitionAnd[E] - # doesn't build with C++ + `and`*: DefinitionAnd of DefinitionKind.`Pattern`: - `pattern`*: Pattern[E] + `pattern`*: Pattern - - NamedAlternative*[E] {.preservesTuple.} = ref object + + NamedAlternative* {.preservesTuple.} = ref object `variantLabel`*: string - `pattern`*: Pattern[E] + `pattern`*: Pattern - SchemaData*[E] {.preservesDictionary.} = ref object + SchemaData* {.preservesDictionary.} = object `version`* {.preservesLiteral: "1".}: bool `embeddedType`*: EmbeddedTypeName - `definitions`*: Definitions[E] + `definitions`*: Definitions - Schema*[E] {.preservesRecord: "schema".} = ref object - `data`*: SchemaData[E] + Schema* {.preservesRecord: "schema".} = object + `data`*: SchemaData PatternKind* {.pure.} = enum `SimplePattern`, `CompoundPattern` - `Pattern`*[E] {.preservesOr.} = ref object + `Pattern`* {.preservesOr.} = ref object case orKind*: PatternKind of PatternKind.`SimplePattern`: - `simplepattern`*: SimplePattern[E] + `simplepattern`*: SimplePattern of PatternKind.`CompoundPattern`: - `compoundpattern`*: CompoundPattern[E] + `compoundpattern`*: CompoundPattern - - Binding*[E] {.preservesRecord: "named".} = ref object + + Binding* {.preservesRecord: "named".} = ref object `name`*: Symbol - `pattern`*: SimplePattern[E] + `pattern`*: SimplePattern -proc `$`*[E](x: Bundle[E] | CompoundPattern[E] | Modules[E] | Definitions[E] | - DictionaryEntries[E] | - NamedPattern[E] | - SimplePattern[E] | - NamedSimplePattern[E] | - Definition[E] | - NamedAlternative[E] | - Schema[E] | - Pattern[E] | - Binding[E]): string = - `$`(toPreserve(x, E)) - -proc encode*[E](x: Bundle[E] | CompoundPattern[E] | Modules[E] | Definitions[E] | - DictionaryEntries[E] | - NamedPattern[E] | - SimplePattern[E] | - NamedSimplePattern[E] | - Definition[E] | - NamedAlternative[E] | - Schema[E] | - Pattern[E] | - Binding[E]): seq[byte] = - encode(toPreserve(x, E)) - -proc `$`*(x: Ref | ModulePath | EmbeddedTypeName): string = +proc `$`*(x: Ref | ModulePath | Bundle | CompoundPattern | Modules | + EmbeddedTypeName | + Definitions | + DictionaryEntries | + NamedPattern | + SimplePattern | + NamedSimplePattern | + Definition | + NamedAlternative | + Schema | + Pattern | + Binding): string = `$`(toPreserve(x)) -proc encode*(x: Ref | ModulePath | EmbeddedTypeName): seq[byte] = +proc encode*(x: Ref | ModulePath | Bundle | CompoundPattern | Modules | + EmbeddedTypeName | + Definitions | + DictionaryEntries | + NamedPattern | + SimplePattern | + NamedSimplePattern | + Definition | + NamedAlternative | + Schema | + Pattern | + Binding): seq[byte] = encode(toPreserve(x)) diff --git a/src/preserves/schemac.nim b/src/preserves/schemac.nim index 02f0ade..02d30b8 100644 --- a/src/preserves/schemac.nim +++ b/src/preserves/schemac.nim @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2022 ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[hashes, options, os, parseopt, streams, strutils, sets, tables] +import std/[hashes, options, os, parseopt, streams, strutils, tables] import ../preserves, ./schema, ./schemaparse @@ -23,7 +23,7 @@ when isMainModule: write(outStream, schema.toPreserve) of "bundle": - var bundle: Bundle[void] + var bundle: Bundle if not dirExists inputPath: quit "not a directory of schemas: " & inputPath else: diff --git a/src/preserves/schemaparse.nim b/src/preserves/schemaparse.nim index 728acc5..37b0b7f 100644 --- a/src/preserves/schemaparse.nim +++ b/src/preserves/schemaparse.nim @@ -10,9 +10,6 @@ import ../preserves, ./schema, ./pegs type Value = Preserve[void] - Definition = schema.Definition[void] - SchemaData = schema.SchemaData[void] - Schema = schema.Schema[void] Stack = seq[tuple[node: Value, pos: int]] ParseState = object schema: SchemaData @@ -60,7 +57,7 @@ template pushStack(n: Value) = assert(p.stack.len > 0, capture[0].s) proc toSymbolLit(s: string): Value = - initRecord(toSymbol"lit", toSymbol s) + initRecord[void](toSymbol"lit", toSymbol s) proc match(text: string; p: var ParseState) {.gcsafe.} @@ -205,10 +202,10 @@ const parser = peg("Schema", p: ParseState): pushStack n Ref <- >(Alpha * *Alnum) * *('.' * >(*Alnum)): - var path: seq[string] - for i in 1..