From 501d6cc01286c54bb7b12e98395fcb6194981807 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 2 Jan 2024 20:54:22 +0200 Subject: [PATCH] preserves_schema_nim: merged And patterns with optionals --- src/preserves/preserves_schema_nim.nim | 121 ++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 11 deletions(-) diff --git a/src/preserves/preserves_schema_nim.nim b/src/preserves/preserves_schema_nim.nim index 3d32a55..67e119d 100644 --- a/src/preserves/preserves_schema_nim.nim +++ b/src/preserves/preserves_schema_nim.nim @@ -373,15 +373,28 @@ proc isDictionary(loc: Location; pat: Pattern): bool = else: discard proc isDictionary(loc: Location; defAnd: DefinitionAnd): bool = - result = isDictionary(loc, defAnd.field0.pattern0.pattern) + result = + isDictionary(loc, defAnd.field0.pattern0.pattern) and + isDictionary(loc, defAnd.field0.pattern1.pattern) + for np in defAnd.field0.patternN: + if result: result = isDictionary(loc, np.pattern) proc isDictionary(loc: Location; def: Definition): bool = case def.orKind of DefinitionKind.Pattern: result = isDictionary(loc, def.pattern) + of DefinitionKind.or: + result = + isDictionary(loc, def.or.field0.pattern0.pattern) and + isDictionary(loc, def.or.field0.pattern1.pattern) + for np in def.or.field0.patternN: + if result: result = isDictionary(loc, np.pattern) of DefinitionKind.and: - result = isDictionary(loc, def.and) - else: discard + result = + isDictionary(loc, def.and.field0.pattern0.pattern) and + isDictionary(loc, def.and.field0.pattern1.pattern) + for np in def.and.field0.patternN: + if result: result = isDictionary(loc, np.pattern) proc isAny(loc: Location; def: Definition): bool = case def.orKind @@ -577,7 +590,9 @@ proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode = newEmpty(), ty) of DefinitionKind.and: - let pragma = newEmpty() + var pragma = nkPragma.newNode + if isDictionary(loc, def): + pragma.add(ident"preservesDictionary") nkTypeDef.newTree( nkPragmaExpr.newTree( name.ident.accQuote.toExport, @@ -628,20 +643,25 @@ proc addField(recList: PNode; loc: Location; known: var TypeTable; parentName: s known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node) recList.add identDef(loc.schema, id, ident(typeName), isEmbedded(loc, pattern)) -proc addField(recList: PNode; loc: Location; known: var TypeTable; parentName: string; nsp: NamedSimplePattern; index = 0) = +proc addField(recList: PNode; loc: Location; known: var TypeTable; parentName: string; nsp: NamedSimplePattern; index: int; optional: bool) = let label = label(nsp, parentName, index) id = label.toFieldIdent pattern = nsp.pattern if pattern.isRef: - addField(recList, loc, known, pattern, label) + var node = typeIdent(loc, pattern).node + if optional: + node = nkBracketExpr.newTree(ident"Option", node) + recList.add identDef(loc.schema, id, node, false) else: var typeName = parentName & capitalizeAscii(label) typePath = loc.schemaPath & @[Symbol typeName] fieldSpec = nimTypeOf(loc, known, label, pattern) + if optional: + fieldSpec.node = nkBracketExpr.newTree(ident"Option", fieldSpec.node) known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node) - recList.add identDef(loc.schema, id, ident(typeName), false) + recList.add identDef(loc.schema, id, fieldSpec.node, false) proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: string; cp: CompoundPattern): PNode {.discardable.} = let scm = loc.schema @@ -677,7 +697,7 @@ proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: variableType.isEmbedded) of CompoundPatternKind.dict: for nameVal, nsp in cp.dict.entries: - recList.addField(loc, known, $nameVal, nsp) + recList.addField(loc, known, $nameVal, nsp, 0, false) reclist proc addFields(recList: PNode; loc: Location; known: var TypeTable; name: string; pat: SimplePattern): PNode {.discardable.} = @@ -800,9 +820,88 @@ proc nimTypeOf(loc: Location; known: var TypeTable; name: string; orDef: Definit newEmpty(), nkRecList.newTree(recCase)) -proc nimTypeOf(loc: Location; known: var TypeTable; name: string; def: DefinitionAnd): TypeSpec = +proc isAny(sp: SimplePattern): bool = + sp.orKind == SimplePatternKind.any + +proc initSimpleAny: SimplePattern = + SimplePattern(orKind: SimplePatternKind.any) + +proc asAny(nsp: NamedSimplePattern): NamedSimplePattern = + result = nsp + case result.orKind + of NamedSimplePatternKind.named: + if not result.named.pattern.isAny: + result.named.pattern = initSimpleAny() + of NamedSimplePatternKind.anonymous: + if not result.anonymous.isAny: + result.anonymous = initSimpleAny() + +type + AndEntry = tuple[pattern: NamedSimplePattern, optional: bool] + AndEntries = OrderedTable[Value, AndEntry] + +proc collect(entries: var AndEntries; loc: Location; def: Definition; optional: bool) {.gcsafe.} + +proc collect(entries: var AndEntries; loc: Location; pat: SimplePattern; optional: bool) = + case pat.orKind + of SimplePatternKind.Ref: + let (loc, def) = deref(loc, pat.ref) + collect(entries, loc, def, optional) + else: + raiseAssert "cannot collect dictionary entries from " & $pat + +proc collect(entries: var AndEntries; loc: Location; comp: CompoundPattern; optional: bool) = + case comp.orKind + of CompoundPatternKind.dict: + for key, nsp in comp.dict.entries.pairs: + if entries.hasKey(key): + entries[key] = (asAny nsp, optional) + else: + entries[key] = (nsp, optional) + else: + raiseAssert "cannot collect dictionary entries from " & $comp + +proc collect(entries: var AndEntries; loc: Location; pat: Pattern; optional: bool) = + case pat.orKind + of PatternKind.SimplePattern: + collect(entries, loc, pat.simplepattern, optional) + of PatternKind.CompoundPattern: + collect(entries, loc, pat.compoundpattern, optional) + +proc collect(entries: var AndEntries; loc: Location; def: Definition; optional: bool) = + case def.orKind + of DefinitionKind.or: + collect(entries, loc, def.or.field0.pattern0.pattern, true) + collect(entries, loc, def.or.field0.pattern1.pattern, true) + for np in def.or.field0.patternN: + collect(entries, loc, np.pattern, true) + of DefinitionKind.and: + collect(entries, loc, def.and.field0.pattern0.pattern, optional) + collect(entries, loc, def.and.field0.pattern1.pattern, optional) + for np in def.and.field0.patternN: + collect(entries, loc, np.pattern, optional) + of DefinitionKind.Pattern: + collect(entries, loc, def.pattern, optional) + +proc toDef(a: DefinitionAnd): Definition = + Definition(orKind: DefinitionKind.and, `and`: a) + +proc nimTypeOf(loc: Location; known: var TypeTable; name: string; andDef: DefinitionAnd): TypeSpec = + var def = andDef.toDef if isDictionary(loc, def): - result.node = nkBracketExpr.newTree(ident"Table", ident"Symbol", ident"Value") + var + recList = nkRecList.newNode + entries: AndEntries + collect(entries, loc, def, false) + sort(entries) do (x, y: (Value, AndEntry)) -> int: + preserves.cmp(x[0], y[0]) + # TODO: sort the entries + var i = 0 + for key, (nsp, opt) in entries.pairs: + recList.addField(loc, known, name, nsp, i, opt) + inc(i) + result.node = nkObjectTy.newTree( + newEmpty(), newEmpty(), recList) else: result.node = ident"Value" @@ -864,7 +963,7 @@ proc collectRefImports(imports: var StringSet; loc: Location; def: Definition) = collectRefImports(imports, loc, na.pattern) of DefinitionKind.and: if isDictionary(loc, def): - incl(imports, "std/tables") + incl(imports, "std/options") collectRefImports(imports, loc, def.and.field0.pattern0.pattern) collectRefImports(imports, loc, def.and.field0.pattern1.pattern) for np in def.and.field0.patternN: