diff --git a/src/preserves/preserves_schema_nim.nim b/src/preserves/preserves_schema_nim.nim index 952c502..778c9a8 100644 --- a/src/preserves/preserves_schema_nim.nim +++ b/src/preserves/preserves_schema_nim.nim @@ -20,10 +20,7 @@ import ../preserves, ./schema type Attribute = enum embedded - ## type contains an embedded value and - ## must take an parameter - recursive - ## type is recursive and therefore must be a ref + ## type contains an embedded value Attributes = set[Attribute] TypeSpec = object node: PNode @@ -119,12 +116,15 @@ proc ident(`ref`: Ref): PNode = dotExtend(result, `ref`.name.string.capitalizeAscii) proc deref(loc: Location; r: Ref): (Location, Definition) = - result[0] = loc - if r.module == @[]: - result[1] = loc.bundle.modules[loc.schemaPath].field0.definitions[r.name] - else: - result[0].schemaPath = r.module - result[1] = loc.bundle.modules[r.module].field0.definitions[r.name] + try: + result[0] = loc + if r.module == @[]: + result[1] = loc.bundle.modules[loc.schemaPath].field0.definitions[r.name] + else: + result[0].schemaPath = r.module + result[1] = loc.bundle.modules[r.module].field0.definitions[r.name] + except KeyError: + raise newException(KeyError, "reference not found in bundle: " & $r) proc hasEmbeddedType(scm: Schema): bool = case scm.field0.embeddedType.orKind @@ -152,8 +152,7 @@ proc attrs(loc: Location; sp: SimplePattern; seen: RefSet): Attributes = of SimplepatternKind.dictof: attrs(loc, sp.dictof.key, seen) + attrs(loc, sp.dictof.value, seen) of SimplepatternKind.Ref: - if sp.ref in seen: {recursive} - elif sp.ref.isAtomic: {} + if (sp.ref in seen) or sp.ref.isAtomic: {} else: var (loc, def) = deref(loc, sp.ref) @@ -211,8 +210,85 @@ proc attrs(loc: Location; p: Definition|DefinitionOr|DefinitionAnd|Pattern|Compo proc isEmbedded(loc: Location; p: Definition|DefinitionOr|DefinitionAnd|Pattern|CompoundPattern|SimplePattern): bool = embedded in attrs(loc, p) -proc isRecursive(loc: Location; p: Definition|DefinitionOr|DefinitionAnd|Pattern|CompoundPattern): bool = - recursive in attrs(loc, p) +proc isRecursive(loc: Location; name: string; pat: Pattern; seen: RefSet): bool {.gcsafe.} + +proc isRecursive(loc: Location; name: string; def: Definition; seen: RefSet): bool {.gcsafe.} + +proc isRecursive(loc: Location; name: string; n: NamedAlternative|NamedPattern; seen: RefSet): bool = + isRecursive(loc, name, n.pattern, seen) + +proc isRecursive(loc: Location; name: string; sp: SimplePattern; seen: RefSet): bool = + case sp.orKind + of SimplepatternKind.embedded: + isRecursive(loc, name, sp.embedded.interface, seen) + of SimplepatternKind.Ref: + if sp.ref.name.string == name: true + elif sp.ref in seen: false + else: + var + (loc, def) = deref(loc, sp.ref) + seen = seen + incl(seen, sp.ref) + isRecursive(loc, name, def, seen) + else: + false + # seqof, setof, and dictof are not processed + # because they imply pointer indirection + +proc isRecursive(loc: Location; name: string; np: NamedSimplePattern; seen: RefSet): bool = + case np.orKind + of NamedSimplePatternKind.named: + isRecursive(loc, name, np.named.pattern, seen) + of NamedSimplePatternKind.anonymous: + isRecursive(loc, name, np.anonymous, seen) + +proc isRecursive(loc: Location; name: string; cp: CompoundPattern; seen: RefSet): bool = + case cp.orKind + of CompoundPatternKind.rec: + result = + isRecursive(loc, name, cp.rec.label.pattern, seen) or + isRecursive(loc, name, cp.rec.fields.pattern, seen) + of CompoundPatternKind.tuple: + for np in cp.tuple.patterns: + if result: return + result = isRecursive(loc, name, np.pattern, seen) + of CompoundPatternKind.tupleprefix: + result = isRecursive(loc, name, cp.tupleprefix.variable, seen) + for p in cp.tupleprefix.fixed: + if result: return + result = isRecursive(loc, name, p, seen) + of CompoundPatternKind.dict: + for nsp in cp.dict.entries.values: + if result: return + result = isRecursive(loc, name, nsp, seen) + +proc isRecursive(loc: Location; name: string; pat: Pattern; seen: RefSet): bool = + case pat.orKind + of PatternKind.SimplePattern: + isRecursive(loc, name, pat.simplePattern, seen) + of PatternKind.CompoundPattern: + isRecursive(loc, name, pat.compoundPattern, seen) + +proc isRecursive(loc: Location; name: string; def: DefinitionOr|DefinitionAnd; seen: RefSet): bool = + result = + isRecursive(loc, name, def.field0.pattern0, seen) or + isRecursive(loc, name, def.field0.pattern1, seen) + for p in def.field0.patternN: + if result: return + result = isRecursive(loc, name, p, seen) + +proc isRecursive(loc: Location; name: string; def: Definition; seen: RefSet): bool = + case def.orKind + of DefinitionKind.or: + isRecursive(loc, name, def.or, seen) + of DefinitionKind.and: + isRecursive(loc, name, def.and, seen) + of DefinitionKind.Pattern: + isRecursive(loc, name, def.pattern, seen) + +proc isRecursive(loc: Location; name: string; def: Definition): bool = + var seen: RefSet + isRecursive(loc, name, def, seen) proc isLiteral(loc: Location; def: Definition): bool {.gcsafe.} proc isLiteral(loc: Location; pat: Pattern): bool {.gcsafe.} @@ -466,7 +542,6 @@ proc typeDef(loc: Location; name: string; pat: Pattern; ty: PNode): PNode = case pat.orKind of PatternKind.CompoundPattern: let pragma = newNode(nkPragma) - if isRecursive(loc, pat): pragma.add(ident"acyclic") case pat.compoundPattern.orKind of CompoundPatternKind.rec: if isLiteral(loc, pat.compoundPattern.rec.label): @@ -491,8 +566,12 @@ proc typeDef(loc: Location; name: string; pat: Pattern; ty: PNode): PNode = proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode = case def.orKind of DefinitionKind.or: + var ty = ty let pragma = newNode(nkPragma) - if isRecursive(loc, def): pragma.add(ident"acyclic") + if isRecursive(loc, name, def): + doAssert ty.kind == nkObjectTy + pragma.add(ident"acyclic") + ty = nkRefTy.newTree(ty) pragma.add(ident"preservesOr") if isSymbolEnum(loc, def): pragma.add ident"pure" @@ -656,8 +735,6 @@ proc nimTypeOf(loc: Location; known: var TypeTable; name: string; cp: CompoundPa of CompoundPatternKind.`dict`: result.node = nkObjectTy.newTree(newEmpty(), newEmpty(), newNode(nkRecList).addFields(loc, known, name, cp.dict.entries)) - if result.node.kind == nkObjectTy and isRecursive(loc, cp): - result.node = nkRefTy.newTree(result.node) proc nimTypeOf(loc: Location; known: var TypeTable; name: string; pat: Pattern): TypeSpec = case pat.orKind @@ -727,9 +804,6 @@ proc nimTypeOf(loc: Location; known: var TypeTable; name: string; orDef: Definit newEmpty(), newEmpty(), nkRecList.newTree(recCase)) - # result.attrs = attrs(loc, orDef) - if result.node.kind == nkObjectTy and (recursive in attrs(loc, orDef)): - result.node = nkRefTy.newTree(result.node) proc nimTypeOf(loc: Location; known: var TypeTable; name: string; def: DefinitionAnd): TypeSpec = if isDictionary(loc, def): @@ -953,7 +1027,6 @@ when isMainModule: for inputPath in inputs: var bundle: Bundle if dirExists inputPath: - new bundle for filePath in walkDirRec(inputPath, relative = true): var (dirPath, fileName, fileExt) = splitFile(filePath) if fileExt == ".prs": @@ -974,10 +1047,9 @@ when isMainModule: if fromPreserves(schema, pr): bundle.modules[@[Symbol fileName]] = schema else: - new bundle var scm = parsePreservesSchema(readFile(inputPath), dirPath) bundle.modules[@[Symbol fileName]] = scm - if bundle.isNil or bundle.modules.len == 0: + if bundle.modules.len == 0: quit "Failed to recognize " & inputPath else: writeModules(bundle) diff --git a/src/preserves/preserves_schemac.nim b/src/preserves/preserves_schemac.nim index 18960aa..a26bdc4 100644 --- a/src/preserves/preserves_schemac.nim +++ b/src/preserves/preserves_schemac.nim @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: ☭ Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[hashes, options, os, parseopt, streams, strutils, tables] +import std/[hashes, os, parseopt, streams, strutils, tables] import ../preserves, ./schema, ./schemaparse @@ -36,7 +36,7 @@ when isMainModule: write(outStream, schema.toPreserves) else: - let bundle = Bundle() + var bundle: Bundle if not dirExists inputPath: quit "not a directory of schemas: " & inputPath else: diff --git a/src/preserves/schema.nim b/src/preserves/schema.nim index 11adf49..14227d5 100644 --- a/src/preserves/schema.nim +++ b/src/preserves/schema.nim @@ -8,23 +8,23 @@ type `name`*: Symbol ModulePath* = seq[Symbol] - Bundle* {.acyclic, preservesRecord: "bundle".} = ref object + Bundle* {.preservesRecord: "bundle".} = object `modules`*: Modules CompoundPatternKind* {.pure.} = enum `rec`, `tuple`, `tuplePrefix`, `dict` - CompoundPatternRec* {.acyclic, preservesRecord: "rec".} = ref object + CompoundPatternRec* {.preservesRecord: "rec".} = object `label`*: NamedPattern `fields`*: NamedPattern - CompoundPatternTuple* {.acyclic, preservesRecord: "tuple".} = ref object + CompoundPatternTuple* {.preservesRecord: "tuple".} = object `patterns`*: seq[NamedPattern] - CompoundPatternTuplePrefix* {.acyclic, preservesRecord: "tuplePrefix".} = ref object + CompoundPatternTuplePrefix* {.preservesRecord: "tuplePrefix".} = object `fixed`*: seq[NamedPattern] `variable`*: NamedSimplePattern - CompoundPatternDict* {.acyclic, preservesRecord: "dict".} = ref object + CompoundPatternDict* {.preservesRecord: "dict".} = object `entries`*: DictionaryEntries `CompoundPattern`* {.acyclic, preservesOr.} = ref object @@ -75,19 +75,19 @@ type SimplePatternAtom* {.preservesRecord: "atom".} = object `atomKind`*: AtomKind - SimplePatternEmbedded* {.acyclic, preservesRecord: "embedded".} = ref object + SimplePatternEmbedded* {.preservesRecord: "embedded".} = object `interface`*: SimplePattern SimplePatternLit* {.preservesRecord: "lit".} = object `value`*: Value - SimplePatternSeqof* {.acyclic, preservesRecord: "seqof".} = ref object + SimplePatternSeqof* {.preservesRecord: "seqof".} = object `pattern`*: SimplePattern - SimplePatternSetof* {.acyclic, preservesRecord: "setof".} = ref object + SimplePatternSetof* {.preservesRecord: "setof".} = object `pattern`*: SimplePattern - SimplePatternDictof* {.acyclic, preservesRecord: "dictof".} = ref object + SimplePatternDictof* {.preservesRecord: "dictof".} = object `key`*: SimplePattern `value`*: SimplePattern @@ -120,7 +120,7 @@ type NamedSimplePatternKind* {.pure.} = enum `named`, `anonymous` - `NamedSimplePattern`* {.acyclic, preservesOr.} = ref object + `NamedSimplePattern`* {.preservesOr.} = object case orKind*: NamedSimplePatternKind of NamedSimplePatternKind.`named`: `named`*: Binding @@ -131,23 +131,23 @@ type DefinitionKind* {.pure.} = enum `or`, `and`, `Pattern` - DefinitionOrField0* {.acyclic, preservesTuple.} = ref object + DefinitionOrField0* {.preservesTuple.} = object `pattern0`*: NamedAlternative `pattern1`*: NamedAlternative `patternN`* {.preservesTupleTail.}: seq[NamedAlternative] - DefinitionOr* {.acyclic, preservesRecord: "or".} = ref object + DefinitionOr* {.preservesRecord: "or".} = object `field0`*: DefinitionOrField0 - DefinitionAndField0* {.acyclic, preservesTuple.} = ref object + DefinitionAndField0* {.preservesTuple.} = object `pattern0`*: NamedPattern `pattern1`*: NamedPattern `patternN`* {.preservesTupleTail.}: seq[NamedPattern] - DefinitionAnd* {.acyclic, preservesRecord: "and".} = ref object + DefinitionAnd* {.preservesRecord: "and".} = object `field0`*: DefinitionAndField0 - `Definition`* {.acyclic, preservesOr.} = ref object + `Definition`* {.preservesOr.} = object case orKind*: DefinitionKind of DefinitionKind.`or`: `or`*: DefinitionOr @@ -159,16 +159,16 @@ type `pattern`*: Pattern - NamedAlternative* {.acyclic, preservesTuple.} = ref object + NamedAlternative* {.preservesTuple.} = object `variantLabel`*: string `pattern`*: Pattern - SchemaField0* {.acyclic, preservesDictionary.} = ref object + SchemaField0* {.preservesDictionary.} = object `definitions`*: Definitions `embeddedType`*: EmbeddedTypeName `version`* {.preservesLiteral: "1".}: tuple[] - Schema* {.acyclic, preservesRecord: "schema".} = ref object + Schema* {.preservesRecord: "schema".} = object `field0`*: SchemaField0 PatternKind* {.pure.} = enum @@ -182,7 +182,7 @@ type `compoundpattern`*: CompoundPattern - Binding* {.acyclic, preservesRecord: "named".} = ref object + Binding* {.preservesRecord: "named".} = object `name`*: Symbol `pattern`*: SimplePattern