preserves_schema_nim: merged And patterns with optionals

This commit is contained in:
Emery Hemingway 2024-01-02 20:54:22 +02:00
parent a52e84dd70
commit 501d6cc012
1 changed files with 110 additions and 11 deletions

View File

@ -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: