2023-05-14 21:55:27 +00:00
|
|
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
2021-09-27 13:58:36 +00:00
|
|
|
# SPDX-License-Identifier: Unlicense
|
|
|
|
|
|
|
|
## 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!
|
2023-10-26 14:28:52 +00:00
|
|
|
# nim c --path:../../../nim --path:.. -r ./preserves_schema_nim ../../../preserves/schema/schema.bin
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2024-01-06 17:28:14 +00:00
|
|
|
import std/[hashes, sets, strutils, tables]
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:23:14 +00:00
|
|
|
# Cannot use std/macros, must use compiler modules because
|
|
|
|
# we are generating code at run-time.
|
2021-09-27 13:58:36 +00:00
|
|
|
import compiler/[ast, idents, renderer, lineinfos]
|
|
|
|
|
2022-03-19 14:13:23 +00:00
|
|
|
import ../preserves, ./schema
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
type
|
2022-12-08 07:53:11 +00:00
|
|
|
Attribute = enum
|
|
|
|
embedded
|
2023-12-29 11:47:25 +00:00
|
|
|
## type contains an embedded value
|
2022-12-08 07:53:11 +00:00
|
|
|
Attributes = set[Attribute]
|
|
|
|
TypeSpec = object
|
|
|
|
node: PNode
|
|
|
|
attrs: Attributes
|
|
|
|
TypeTable = OrderedTable[schema.ModulePath, PNode]
|
|
|
|
Location = tuple[bundle: Bundle, schemaPath: ModulePath]
|
2023-05-14 21:55:27 +00:00
|
|
|
StringSet = HashSet[string]
|
2022-12-08 07:53:11 +00:00
|
|
|
|
|
|
|
proc schema(loc: Location): Schema = loc.bundle.modules[loc.schemaPath]
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc add(parent, child: PNode): PNode {.discardable.} =
|
|
|
|
parent.sons.add child
|
|
|
|
parent
|
|
|
|
|
|
|
|
proc add(parent: PNode; children: varargs[PNode]): PNode {.discardable.} =
|
|
|
|
parent.sons.add children
|
|
|
|
parent
|
|
|
|
|
|
|
|
proc ident(s: string): PNode =
|
|
|
|
newIdentNode(PIdent(s: s), TLineInfo())
|
|
|
|
|
|
|
|
proc accQuote(n: PNode): Pnode =
|
|
|
|
nkAccQuoted.newNode.add(n)
|
|
|
|
|
|
|
|
proc pattern(np: NamedPattern): Pattern =
|
|
|
|
case np.orKind
|
|
|
|
of NamedPatternKind.named:
|
|
|
|
Pattern(orKind: PatternKind.SimplePattern, simplePattern: np.named.pattern)
|
|
|
|
of NamedPatternKind.anonymous:
|
|
|
|
np.anonymous
|
|
|
|
|
|
|
|
proc pattern(np: NamedSimplePattern): SimplePattern =
|
|
|
|
case np.orKind
|
|
|
|
of NamedSimplePatternKind.named:
|
|
|
|
np.named.pattern
|
|
|
|
of NamedSimplePatternKind.anonymous:
|
|
|
|
np.anonymous
|
|
|
|
|
|
|
|
proc ident(sp: SimplePattern): PNode =
|
2021-10-17 12:50:27 +00:00
|
|
|
raiseAssert "need ident from " #& $sp
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc ident(cp: CompoundPattern; fallback: string): PNode =
|
|
|
|
case cp.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.rec:
|
2021-09-27 13:58:36 +00:00
|
|
|
ident($cp.rec.label)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tuple,
|
|
|
|
CompoundPatternKind.tuplePrefix,
|
|
|
|
CompoundPatternKind.dict:
|
2021-09-27 13:58:36 +00:00
|
|
|
ident(fallback)
|
|
|
|
|
|
|
|
proc ident(pat: Pattern; fallback = string): PNode =
|
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.simplePattern:
|
|
|
|
ident(pat.simplePattern, fallback)
|
|
|
|
of PatternKind.compoundPattern:
|
|
|
|
ident(pat.compoundPattern, fallback)
|
|
|
|
|
|
|
|
proc ident(np: NamedPattern; fallback: string): PNode =
|
|
|
|
case np.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.named:
|
2022-02-20 04:33:15 +00:00
|
|
|
ident(string np.named.name)
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.anonymous:
|
2021-09-27 13:58:36 +00:00
|
|
|
ident(fallback)
|
|
|
|
|
|
|
|
proc ident(np: NamedSimplePattern; fallback: string): PNode =
|
|
|
|
case np.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedSimplePatternKind.named:
|
2022-02-20 04:33:15 +00:00
|
|
|
ident(string np.named.name)
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedSimplePatternKind.anonymous:
|
2021-09-27 13:58:36 +00:00
|
|
|
ident(fallback)
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isEmbedded(ts: TypeSpec): bool =
|
|
|
|
embedded in ts.attrs
|
|
|
|
|
2023-06-07 10:45:00 +00:00
|
|
|
func isAtomic(r: Ref): bool =
|
|
|
|
case r.name.string
|
2024-01-06 17:26:26 +00:00
|
|
|
of "bool", "float", "double", "int", "string", "bytes", "symbol": true
|
2023-06-07 10:45:00 +00:00
|
|
|
else: false
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc addAttrs(x: var TypeSpec; y: TypeSpec) =
|
|
|
|
x.attrs = x.attrs + y.attrs
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc dotExtend(result: var PNode; label: string) =
|
|
|
|
var id = ident(label)
|
|
|
|
if result.isNil: result = id
|
2023-08-05 19:22:43 +00:00
|
|
|
else: result = nkDotExpr.newTree(result, id)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc ident(`ref`: Ref): PNode =
|
2023-03-01 17:03:22 +00:00
|
|
|
for m in `ref`.module: dotExtend(result, string m)
|
2023-06-07 10:45:00 +00:00
|
|
|
if `ref`.isAtomic:
|
|
|
|
dotExtend(result, `ref`.name.string)
|
|
|
|
else:
|
|
|
|
dotExtend(result, `ref`.name.string.capitalizeAscii)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc deref(loc: Location; r: Ref): (Location, Definition) =
|
2023-12-29 11:47:25 +00:00
|
|
|
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)
|
2022-12-08 07:53:11 +00:00
|
|
|
|
2024-01-06 17:28:14 +00:00
|
|
|
proc hasEmbeddedType(scm: Schema): bool =
|
|
|
|
case scm.field0.embeddedType.orKind
|
|
|
|
of EmbeddedtypenameKind.false: false
|
|
|
|
of EmbeddedtypenameKind.Ref: true
|
|
|
|
|
|
|
|
proc parameterize(loc: Location; node: PNode; embeddable: bool): PNode = node
|
|
|
|
|
|
|
|
proc parameterize(loc: Location; spec: TypeSpec): PNode =
|
|
|
|
parameterize(loc, spec.node, spec.isEmbedded)
|
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
proc hash(r: Ref): Hash = r.toPreserves.hash
|
2021-09-27 13:58:36 +00:00
|
|
|
type RefSet = HashSet[Ref]
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc attrs(loc: Location; pat: Pattern; seen: RefSet): Attributes {.gcsafe.}
|
|
|
|
proc attrs(loc: Location; def: Definition; seen: RefSet): Attributes {.gcsafe.}
|
|
|
|
|
|
|
|
proc attrs(loc: Location; n: NamedAlternative|NamedPattern; seen: RefSet): Attributes =
|
|
|
|
attrs(loc, n.pattern, seen)
|
|
|
|
|
|
|
|
proc attrs(loc: Location; sp: SimplePattern; seen: RefSet): Attributes =
|
2021-10-17 12:50:27 +00:00
|
|
|
case sp.orKind
|
2023-12-28 16:23:14 +00:00
|
|
|
of SimplepatternKind.atom, SimplepatternKind.lit, SimplepatternKind.any: {}
|
2024-01-06 17:28:14 +00:00
|
|
|
of SimplepatternKind.embedded: {embedded}
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.seqof:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, sp.seqof.pattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.setof:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, sp.setof.pattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.dictof:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, sp.dictof.key, seen) + attrs(loc, sp.dictof.value, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.Ref:
|
2023-12-29 11:47:25 +00:00
|
|
|
if (sp.ref in seen) or sp.ref.isAtomic: {}
|
2021-10-17 12:50:27 +00:00
|
|
|
else:
|
2022-12-08 07:53:11 +00:00
|
|
|
var
|
|
|
|
(loc, def) = deref(loc, sp.ref)
|
|
|
|
seen = seen
|
|
|
|
incl(seen, sp.ref)
|
|
|
|
attrs(loc, def, seen)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc attrs(loc: Location; np: NamedSimplePattern; seen: RefSet): Attributes =
|
2021-09-27 13:58:36 +00:00
|
|
|
case np.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedSimplePatternKind.named:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, np.named.pattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedSimplePatternKind.anonymous:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, np.anonymous, seen)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc attrs(loc: Location; cp: CompoundPattern; seen: RefSet): Attributes =
|
2021-10-17 12:50:27 +00:00
|
|
|
case cp.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.rec:
|
2022-12-08 07:53:11 +00:00
|
|
|
result =
|
|
|
|
attrs(loc, cp.rec.label.pattern, seen) +
|
|
|
|
attrs(loc, cp.rec.fields.pattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tuple:
|
2022-12-08 07:53:11 +00:00
|
|
|
for np in cp.tuple.patterns:
|
|
|
|
result = result + attrs(loc, np.pattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tupleprefix:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = attrs(loc, cp.tupleprefix.variable, seen)
|
|
|
|
for p in cp.tupleprefix.fixed:
|
|
|
|
result = result + attrs(loc, p, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.dict:
|
2023-03-01 17:12:47 +00:00
|
|
|
for nsp in cp.dict.entries.values:
|
|
|
|
result = result + attrs(loc, nsp, seen)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc attrs(loc: Location; pat: Pattern; seen: RefSet): Attributes =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of PatternKind.SimplePattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, pat.simplePattern, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, pat.compoundPattern, seen)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:34:40 +00:00
|
|
|
proc attrs(loc: Location; def: DefinitionOr|DefinitionAnd; seen: RefSet): Attributes =
|
|
|
|
result = attrs(loc, def.field0.pattern0, seen) + attrs(loc, def.field0.pattern1, seen)
|
|
|
|
for p in def.field0.patternN:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = result + attrs(loc, p, seen)
|
2021-10-17 12:50:27 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc attrs(loc: Location; def: Definition; seen: RefSet): Attributes =
|
2021-10-17 12:50:27 +00:00
|
|
|
case def.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of DefinitionKind.or: result = attrs(loc, def.or, seen)
|
2023-12-28 16:34:40 +00:00
|
|
|
of DefinitionKind.and: result = attrs(loc, def.and, seen)
|
2023-03-01 17:03:22 +00:00
|
|
|
of DefinitionKind.Pattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = attrs(loc, def.pattern, seen)
|
2021-10-17 12:50:27 +00:00
|
|
|
|
2023-12-28 16:34:40 +00:00
|
|
|
proc attrs(loc: Location; p: Definition|DefinitionOr|DefinitionAnd|Pattern|CompoundPattern|SimplePattern): Attributes =
|
2021-09-27 13:58:36 +00:00
|
|
|
var seen: RefSet
|
2022-12-08 07:53:11 +00:00
|
|
|
attrs(loc, p, seen)
|
|
|
|
|
2023-12-28 16:34:40 +00:00
|
|
|
proc isEmbedded(loc: Location; p: Definition|DefinitionOr|DefinitionAnd|Pattern|CompoundPattern|SimplePattern): bool =
|
2022-12-08 07:53:11 +00:00
|
|
|
embedded in attrs(loc, p)
|
|
|
|
|
2023-12-29 11:47:25 +00:00
|
|
|
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)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isLiteral(loc: Location; def: Definition): bool {.gcsafe.}
|
2023-05-17 08:12:08 +00:00
|
|
|
proc isLiteral(loc: Location; pat: Pattern): bool {.gcsafe.}
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isLiteral(loc: Location; sp: SimplePattern): bool =
|
2021-09-27 13:58:36 +00:00
|
|
|
case sp.orKind
|
2022-12-08 07:53:11 +00:00
|
|
|
of SimplepatternKind.Ref:
|
2023-06-07 10:45:00 +00:00
|
|
|
if sp.ref.module.len == 0 and not sp.ref.isAtomic:
|
2022-12-08 07:53:11 +00:00
|
|
|
var (loc, def) = deref(loc, sp.ref)
|
|
|
|
result = isLiteral(loc, def)
|
2021-09-27 13:58:36 +00:00
|
|
|
of SimplepatternKind.lit:
|
|
|
|
result = true
|
|
|
|
else: discard
|
|
|
|
|
2023-05-17 08:12:08 +00:00
|
|
|
proc isLiteral(loc: Location; np: NamedPattern): bool =
|
|
|
|
case np.orKind
|
|
|
|
of NamedPatternKind.named:
|
|
|
|
isLiteral(loc, np.named.pattern)
|
|
|
|
of NamedPatternKind.anonymous:
|
|
|
|
isLiteral(loc, np.anonymous)
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isLiteral(loc: Location; pat: Pattern): bool =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
isLiteral(loc, pat.simplePattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
|
|
|
false # TODO it could be a compound of all literals
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isLiteral(loc: Location; def: Definition): bool =
|
2021-09-27 13:58:36 +00:00
|
|
|
if def.orKind == DefinitionKind.Pattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = isLiteral(loc, def.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc isRef(sp: SimplePattern): bool =
|
2023-03-01 17:03:22 +00:00
|
|
|
sp.orKind == SimplePatternKind.Ref
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc isSimple(pat: Pattern): bool =
|
|
|
|
pat.orKind == PatternKind.SimplePattern
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isLiteral(loc: Location; na: NamedAlternative): bool = isLiteral(loc, na.pattern)
|
|
|
|
|
2023-12-28 16:23:14 +00:00
|
|
|
proc isSymbolEnum(loc: Location; def: DefinitionOr): bool =
|
|
|
|
result = isLiteral(loc, def.field0.pattern0) and isLiteral(loc, def.field0.pattern1)
|
|
|
|
for na in def.field0.patternN:
|
2021-09-27 13:58:36 +00:00
|
|
|
if not result: break
|
2022-12-08 07:53:11 +00:00
|
|
|
result = isLiteral(loc, na)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isSymbolEnum(loc: Location; def: Definition): bool =
|
2021-09-27 13:58:36 +00:00
|
|
|
case def.orKind
|
|
|
|
of DefinitionKind.Pattern:
|
|
|
|
if def.pattern.orKind == PatternKind.SimplePattern and
|
2023-03-01 17:03:22 +00:00
|
|
|
def.pattern.simplePattern.orKind == SimplepatternKind.Ref:
|
|
|
|
var (loc, def) = deref(loc, def.pattern.simplePattern.ref)
|
|
|
|
result = isSymbolEnum(loc, def)
|
2021-09-27 13:58:36 +00:00
|
|
|
of DefinitionKind.or:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = isSymbolEnum(loc, def.or)
|
2021-09-27 13:58:36 +00:00
|
|
|
else: discard
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isSymbolEnum(loc: Location; sp: SimplePattern): bool =
|
2022-07-09 13:08:52 +00:00
|
|
|
# HashSet
|
2023-03-01 17:03:22 +00:00
|
|
|
if sp.orKind == SimplepatternKind.Ref:
|
2022-12-08 07:53:11 +00:00
|
|
|
var (loc, def) = deref(loc, sp.ref)
|
|
|
|
result = isSymbolEnum(loc, def)
|
2022-07-09 13:08:52 +00:00
|
|
|
else: discard
|
|
|
|
|
2023-12-28 16:34:40 +00:00
|
|
|
proc isDictionary(loc: Location; def: Definition): bool {.gcsafe.}
|
|
|
|
|
|
|
|
proc isDictionary(loc: Location; pat: Pattern): bool =
|
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
|
|
|
case pat.simplePattern.orKind
|
|
|
|
of SimplePatternKind.Ref:
|
|
|
|
var (loc, def) = deref(loc, pat.simplePattern.ref)
|
|
|
|
result = isDictionary(loc, def)
|
|
|
|
of SimplePatternKind.dictof:
|
|
|
|
result = true
|
|
|
|
else: discard
|
|
|
|
of PatternKind.CompoundPattern:
|
|
|
|
case pat.compoundpattern.orKind
|
|
|
|
of CompoundPatternKind.dict:
|
|
|
|
result = true
|
|
|
|
else: discard
|
|
|
|
|
|
|
|
proc isDictionary(loc: Location; def: Definition): bool =
|
|
|
|
case def.orKind
|
|
|
|
of DefinitionKind.Pattern:
|
|
|
|
result = isDictionary(loc, def.pattern)
|
2024-01-02 18:54:22 +00:00
|
|
|
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)
|
2023-12-28 16:34:40 +00:00
|
|
|
of DefinitionKind.and:
|
2024-01-02 18:54:22 +00:00
|
|
|
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)
|
2023-12-28 16:34:40 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc isAny(loc: Location; def: Definition): bool =
|
2023-05-14 21:55:27 +00:00
|
|
|
case def.orKind
|
|
|
|
of DefinitionKind.Pattern:
|
2023-05-17 08:12:08 +00:00
|
|
|
case def.pattern.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
2021-10-20 11:59:48 +00:00
|
|
|
case def.pattern.simplePattern.orKind
|
|
|
|
of SimplePatternKind.Ref:
|
2023-03-01 17:03:22 +00:00
|
|
|
var (loc, def) = deref(loc, def.pattern.simplePattern.ref)
|
2022-12-08 07:53:11 +00:00
|
|
|
result = isAny(loc, def)
|
2021-10-20 11:59:48 +00:00
|
|
|
of SimplePatternKind.any:
|
|
|
|
result = true
|
|
|
|
else: discard
|
2023-05-17 08:12:08 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
|
|
|
case def.pattern.compoundpattern.orKind
|
|
|
|
of CompoundPatternKind.rec:
|
|
|
|
result = not isLiteral(loc, def.pattern.compoundpattern.rec.label)
|
|
|
|
else: discard
|
2023-05-14 21:55:27 +00:00
|
|
|
else: discard
|
2021-10-20 11:59:48 +00:00
|
|
|
|
2021-09-27 13:58:36 +00:00
|
|
|
proc typeIdent(atom: AtomKind): PNode =
|
|
|
|
case atom
|
2023-03-01 17:03:22 +00:00
|
|
|
of AtomKind.Boolean: ident"bool"
|
2024-02-06 14:24:55 +00:00
|
|
|
of AtomKind.Double: ident"float"
|
2023-03-01 17:03:22 +00:00
|
|
|
of AtomKind.Signedinteger: ident"BiggestInt"
|
|
|
|
of AtomKind.String: ident"string"
|
2023-08-05 19:22:43 +00:00
|
|
|
of AtomKind.Bytestring: nkBracketExpr.newTree(ident"seq", ident"byte")
|
2023-03-01 17:03:22 +00:00
|
|
|
of AtomKind.Symbol: ident"Symbol"
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc typeIdent(loc: Location; sp: SimplePattern): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case sp.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.atom:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = TypeSpec(node: typeIdent(sp.atom.atomKind))
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.seqof:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = typeIdent(loc, sp.seqof.pattern)
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkBracketExpr.newTree(ident"seq", result.node)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.setof:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = typeIdent(loc, sp.setof.pattern)
|
2022-07-09 13:08:52 +00:00
|
|
|
result.node =
|
2022-12-08 07:53:11 +00:00
|
|
|
if isSymbolEnum(loc, sp.setof.pattern):
|
2023-08-05 19:22:43 +00:00
|
|
|
nkBracketExpr.newTree(ident"set", result.node)
|
2022-07-09 13:08:52 +00:00
|
|
|
else:
|
2023-08-05 19:22:43 +00:00
|
|
|
nkBracketExpr.newTree(ident"HashSet", result.node)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.dictof:
|
2021-09-27 13:58:36 +00:00
|
|
|
let
|
2022-12-08 07:53:11 +00:00
|
|
|
key = typeIdent(loc, sp.dictof.key)
|
|
|
|
val = typeIdent(loc, sp.dictof.value)
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkBracketExpr.newTree(ident"Table", key.node, val.node)
|
2022-12-08 07:53:11 +00:00
|
|
|
result.attrs = key.attrs + val.attrs
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.Ref:
|
2022-12-08 07:53:11 +00:00
|
|
|
result = TypeSpec(node: ident(sp.ref), attrs: attrs(loc, sp))
|
2024-01-06 17:28:14 +00:00
|
|
|
result.node = parameterize(loc, result)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.embedded:
|
2024-01-06 17:28:14 +00:00
|
|
|
if loc.schema.hasEmbeddedType:
|
|
|
|
result = TypeSpec(node: ident"EmbeddedRef")
|
|
|
|
else:
|
|
|
|
result = TypeSpec(node: ident"Value")
|
2022-12-08 07:53:11 +00:00
|
|
|
incl(result.attrs, embedded)
|
2023-03-01 17:03:22 +00:00
|
|
|
of SimplepatternKind.any, SimplepatternKind.lit:
|
2023-12-28 16:23:14 +00:00
|
|
|
result = TypeSpec(node: ident"Value")
|
2022-12-08 07:53:11 +00:00
|
|
|
|
|
|
|
proc typeIdent(loc: Location; pat: Pattern): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
2022-12-08 07:53:11 +00:00
|
|
|
of PatternKind.SimplePattern: typeIdent(loc, pat.simplePattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
else: raiseAssert "no typeIdent for " & $pat
|
|
|
|
|
|
|
|
proc toExport(n: sink PNode): PNode =
|
|
|
|
nkPostFix.newNode.add(ident"*", n)
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
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 =
|
2021-09-27 13:58:36 +00:00
|
|
|
case sp.orKind
|
2022-12-08 07:53:11 +00:00
|
|
|
of SimplePatternKind.lit:
|
2021-09-27 13:58:36 +00:00
|
|
|
result = PNode(kind: nkStrLit, strVal: $sp.lit.value)
|
2022-12-08 07:53:11 +00:00
|
|
|
of SimplePatternKind.Ref:
|
|
|
|
var (loc, def) = deref(loc, sp.ref)
|
|
|
|
result = toStrLit(loc, def)
|
|
|
|
of SimplePatternKind.embedded:
|
2024-01-06 17:28:14 +00:00
|
|
|
doAssert not loc.schema.hasEmbeddedType
|
2024-02-08 14:22:18 +00:00
|
|
|
result = PNode(kind: nkStrLit, strVal: "#:" & toStrLit(loc, sp.embedded.interface).strVal)
|
2022-12-08 07:53:11 +00:00
|
|
|
else: raiseAssert $sp
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc toFieldIdent(s: string): PNode =
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPostFix.newTree(ident("*"), nkAccQuoted.newTree(ident(s)))
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc toFieldIdent(loc: Location, label: string; pat: Pattern): PNode =
|
2021-09-27 13:58:36 +00:00
|
|
|
result = label.toFieldIdent
|
2022-12-08 07:53:11 +00:00
|
|
|
if isLiteral(loc, pat):
|
2023-08-05 19:22:43 +00:00
|
|
|
result = nkPragmaExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
result,
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPragma.newTree(
|
|
|
|
nkExprColonExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
ident"preservesLiteral",
|
2022-12-08 07:53:11 +00:00
|
|
|
toStrLit(loc, pat.simplePattern))))
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc newEmpty(): PNode = newNode(nkEmpty)
|
|
|
|
|
2024-01-06 17:28:14 +00:00
|
|
|
proc embeddingParams(loc: Location; embeddable: bool): PNode =
|
|
|
|
newEmpty()
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc identDef(scm: Schema; a, b: PNode; embeddable: bool): PNode =
|
2023-12-28 16:23:14 +00:00
|
|
|
nkIdentDefs.newTree(a, b, newEmpty())
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc identDef(scm: Schema; l: PNode; ts: TypeSpec): PNode =
|
|
|
|
identDef(scm, l, ts.node, ts.isEmbedded)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc label(pat: Pattern): string =
|
|
|
|
raiseAssert "need to derive record label for " & $pat
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc label(na: NamedPattern; parentLabel: string; index: int): string =
|
2021-09-27 13:58:36 +00:00
|
|
|
case na.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.named:
|
2022-02-20 04:33:15 +00:00
|
|
|
string na.named.name
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.anonymous:
|
2023-05-03 15:02:48 +00:00
|
|
|
"field" & $index
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc label(nsp: NamedSimplePattern; parentLabel: string; index: int): string =
|
|
|
|
case nsp.orKind
|
|
|
|
of NamedSimplePatternKind.named:
|
|
|
|
string nsp.named.name
|
|
|
|
of NamedSimplePatternKind.anonymous:
|
|
|
|
parentLabel & $index
|
|
|
|
|
2021-09-27 13:58:36 +00:00
|
|
|
proc idStr(sp: SimplePattern): string =
|
|
|
|
if sp.orKind == SimplepatternKind.lit:
|
|
|
|
case sp.lit.value.kind
|
|
|
|
of pkString:
|
|
|
|
result = sp.lit.value.string
|
|
|
|
of pkSymbol:
|
2022-02-20 04:33:15 +00:00
|
|
|
result = string sp.lit.value.symbol
|
2021-09-27 13:58:36 +00:00
|
|
|
else: discard
|
2023-03-01 17:03:22 +00:00
|
|
|
doAssert(result != "", "no idStr for " & $sp)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc idStr(pat: Pattern): string =
|
|
|
|
doAssert(pat.orKind == PatternKind.SimplePattern)
|
|
|
|
pat.simplePattern.idStr
|
|
|
|
|
|
|
|
proc idStr(np: NamedPattern): string =
|
|
|
|
case np.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.named:
|
2022-02-20 04:33:15 +00:00
|
|
|
string np.named.name
|
2023-03-01 17:03:22 +00:00
|
|
|
of NamedPatternKind.anonymous:
|
2021-09-27 13:58:36 +00:00
|
|
|
np.anonymous.idStr
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc typeDef(loc: Location; name: string; pat: SimplePattern; ty: PNode): PNode =
|
|
|
|
let id = name.ident.toExport
|
|
|
|
nkTypeDef.newTree(id, newEmpty(), ty)
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc typeDef(loc: Location; name: string; pat: Pattern; ty: PNode): PNode =
|
2021-09-27 13:58:36 +00:00
|
|
|
let
|
2024-01-06 17:28:14 +00:00
|
|
|
embedParams = embeddingParams(loc, isEmbedded(loc, pat))
|
2021-09-27 13:58:36 +00:00
|
|
|
id = name.ident.toExport
|
2022-12-08 07:53:11 +00:00
|
|
|
case pat.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
2023-08-06 09:37:07 +00:00
|
|
|
let pragma = newNode(nkPragma)
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.compoundPattern.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.rec:
|
2023-05-17 08:12:08 +00:00
|
|
|
if isLiteral(loc, pat.compoundPattern.rec.label):
|
2023-08-06 09:37:07 +00:00
|
|
|
pragma.add(
|
|
|
|
nkExprColonExpr.newTree(
|
|
|
|
ident"preservesRecord",
|
|
|
|
PNode(kind: nkStrLit, strVal: pat.compoundPattern.rec.label.idStr)))
|
|
|
|
nkTypeDef.newTree(nkPragmaExpr.newTree(id, pragma), embedParams, ty)
|
|
|
|
elif pragma.len > 0:
|
|
|
|
nkTypeDef.newTree(nkPragmaExpr.newTree(id, pragma), embedParams, ty)
|
2023-05-17 08:12:08 +00:00
|
|
|
else:
|
2023-08-06 09:37:07 +00:00
|
|
|
nkTypeDef.newTree(id, embedParams, ty)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tuple, CompoundPatternKind.tuplePrefix:
|
2023-08-06 09:37:07 +00:00
|
|
|
pragma.add(ident"preservesTuple")
|
|
|
|
nkTypeDef.newTree(nkPragmaExpr.newTree(id, pragma), embedParams, ty)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.dict:
|
2023-08-06 09:37:07 +00:00
|
|
|
pragma.add(ident"preservesDictionary")
|
|
|
|
nkTypeDef.newTree(nkPragmaExpr.newTree(id, pragma), embedParams, ty)
|
2021-09-27 13:58:36 +00:00
|
|
|
else:
|
2023-08-06 09:37:07 +00:00
|
|
|
nkTypeDef.newTree(id, embedParams, ty)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc typeDef(loc: Location; name: string; def: Definition; ty: PNode): PNode =
|
2021-09-27 13:58:36 +00:00
|
|
|
case def.orKind
|
|
|
|
of DefinitionKind.or:
|
2023-12-29 11:47:25 +00:00
|
|
|
var ty = ty
|
2023-08-06 09:37:07 +00:00
|
|
|
let pragma = newNode(nkPragma)
|
2023-12-29 11:47:25 +00:00
|
|
|
if isRecursive(loc, name, def):
|
|
|
|
doAssert ty.kind == nkObjectTy
|
|
|
|
pragma.add(ident"acyclic")
|
|
|
|
ty = nkRefTy.newTree(ty)
|
2023-08-06 09:37:07 +00:00
|
|
|
pragma.add(ident"preservesOr")
|
2022-12-08 07:53:11 +00:00
|
|
|
if isSymbolEnum(loc, def):
|
2021-12-04 11:44:18 +00:00
|
|
|
pragma.add ident"pure"
|
2023-08-05 19:22:43 +00:00
|
|
|
nkTypeDef.newTree(
|
|
|
|
nkPragmaExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
name.ident.accQuote.toExport,
|
2021-12-04 11:44:18 +00:00
|
|
|
pragma),
|
2024-01-06 17:28:14 +00:00
|
|
|
embeddingParams(loc, isEmbedded(loc, def)),
|
2021-09-27 13:58:36 +00:00
|
|
|
ty)
|
|
|
|
of DefinitionKind.and:
|
2024-01-02 18:54:22 +00:00
|
|
|
var pragma = nkPragma.newNode
|
|
|
|
if isDictionary(loc, def):
|
|
|
|
pragma.add(ident"preservesDictionary")
|
2023-08-05 19:22:43 +00:00
|
|
|
nkTypeDef.newTree(
|
2023-12-28 16:34:40 +00:00
|
|
|
nkPragmaExpr.newTree(
|
|
|
|
name.ident.accQuote.toExport,
|
|
|
|
pragma),
|
2024-01-06 17:28:14 +00:00
|
|
|
embeddingParams(loc, isEmbedded(loc, def)),
|
2023-12-28 16:34:40 +00:00
|
|
|
ty)
|
2021-09-27 13:58:36 +00:00
|
|
|
of DefinitionKind.Pattern:
|
2022-12-08 07:53:11 +00:00
|
|
|
typeDef(loc, name, def.pattern, ty)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; nsp: NamedSimplePattern): TypeSpec
|
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; pat: Pattern): TypeSpec
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; cp: CompoundPattern): TypeSpec
|
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; sp: SimplePattern): TypeSpec =
|
2022-12-08 07:53:11 +00:00
|
|
|
typeIdent(loc, sp)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
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):
|
2023-08-05 19:22:43 +00:00
|
|
|
let id = nkPragmaExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
id,
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPragma.newTree(
|
|
|
|
nkExprColonExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
ident"preservesLiteral",
|
2022-12-08 07:53:11 +00:00
|
|
|
toStrLit(loc, sp))))
|
2023-05-04 09:55:09 +00:00
|
|
|
recList.add identDef(scm, id, TypeSpec(node: ident"tuple[]"))
|
2024-01-01 12:11:50 +00:00
|
|
|
elif sp.orKind == SimplePatternKind.embedded:
|
2023-08-05 19:22:43 +00:00
|
|
|
let id = nkPragmaExpr.newTree(
|
|
|
|
id, nkPragma.newTree(ident"preservesEmbedded"))
|
2023-12-28 16:30:27 +00:00
|
|
|
recList.add identDef(scm, id, nimTypeOf(loc, known, "", sp))
|
2021-09-27 13:58:36 +00:00
|
|
|
else:
|
2023-12-28 16:30:27 +00:00
|
|
|
recList.add identDef(scm, id, nimTypeOf(loc, known, "", sp))
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc addField(recList: PNode; loc: Location; known: var TypeTable; parentName: string; np: NamedPattern; index = 0) =
|
|
|
|
let
|
|
|
|
label = label(np, parentName, index)
|
|
|
|
id = label.toFieldIdent
|
|
|
|
pattern = np.pattern
|
2024-01-06 17:27:06 +00:00
|
|
|
if pattern.isSimple:
|
2023-12-28 16:30:27 +00:00
|
|
|
addField(recList, loc, known, pattern.simplePattern, label)
|
|
|
|
else:
|
|
|
|
var
|
|
|
|
typeName = parentName & capitalizeAscii(label)
|
|
|
|
typePath = loc.schemaPath & @[Symbol typeName]
|
|
|
|
fieldSpec = nimTypeOf(loc, known, label, pattern)
|
|
|
|
known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node)
|
|
|
|
recList.add identDef(loc.schema, id, ident(typeName), isEmbedded(loc, pattern))
|
|
|
|
|
2024-01-02 18:54:22 +00:00
|
|
|
proc addField(recList: PNode; loc: Location; known: var TypeTable; parentName: string; nsp: NamedSimplePattern; index: int; optional: bool) =
|
2023-12-28 16:30:27 +00:00
|
|
|
let
|
|
|
|
label = label(nsp, parentName, index)
|
|
|
|
id = label.toFieldIdent
|
|
|
|
pattern = nsp.pattern
|
|
|
|
if pattern.isRef:
|
2024-01-02 18:54:22 +00:00
|
|
|
var node = typeIdent(loc, pattern).node
|
|
|
|
if optional:
|
|
|
|
node = nkBracketExpr.newTree(ident"Option", node)
|
|
|
|
recList.add identDef(loc.schema, id, node, false)
|
2023-12-28 16:30:27 +00:00
|
|
|
else:
|
|
|
|
var
|
|
|
|
typeName = parentName & capitalizeAscii(label)
|
|
|
|
typePath = loc.schemaPath & @[Symbol typeName]
|
|
|
|
fieldSpec = nimTypeOf(loc, known, label, pattern)
|
2024-01-02 18:54:22 +00:00
|
|
|
if optional:
|
|
|
|
fieldSpec.node = nkBracketExpr.newTree(ident"Option", fieldSpec.node)
|
2023-12-28 16:30:27 +00:00
|
|
|
known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node)
|
2024-01-02 18:54:22 +00:00
|
|
|
recList.add identDef(loc.schema, id, fieldSpec.node, false)
|
2023-12-28 16:30:27 +00:00
|
|
|
|
|
|
|
proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: string; cp: CompoundPattern): PNode {.discardable.} =
|
2022-12-08 07:53:11 +00:00
|
|
|
let scm = loc.schema
|
2023-05-03 15:02:48 +00:00
|
|
|
template addField(np: NamedPattern; index: int) =
|
2021-10-24 12:00:18 +00:00
|
|
|
let
|
2023-12-28 16:30:27 +00:00
|
|
|
label = label(np, parentName, index)
|
2021-10-24 12:00:18 +00:00
|
|
|
id = label.toFieldIdent
|
|
|
|
pattern = np.pattern
|
2024-01-06 17:27:06 +00:00
|
|
|
if pattern.isSimple:
|
2022-12-08 07:53:11 +00:00
|
|
|
addField(recList, loc, known, pattern.simplePattern, label)
|
2021-10-24 12:00:18 +00:00
|
|
|
else:
|
|
|
|
var
|
|
|
|
typeName = parentName & capitalizeAscii(label)
|
2022-12-08 07:53:11 +00:00
|
|
|
typePath = loc.schemaPath & @[Symbol typeName]
|
2023-12-28 16:30:27 +00:00
|
|
|
fieldSpec = nimTypeOf(loc, known, label, pattern)
|
2022-12-08 07:53:11 +00:00
|
|
|
known[typePath] = typeDef(loc, typeName, pattern, fieldSpec.node)
|
|
|
|
recList.add identDef(scm, id, ident(typeName), isEmbedded(loc, pattern))
|
2021-09-27 13:58:36 +00:00
|
|
|
case cp.orKind
|
|
|
|
of CompoundPatternKind.rec:
|
2023-12-28 16:30:27 +00:00
|
|
|
# recList.add identDef(scm, ident(label), nimTypeOf(loc, known, "", cp))
|
2021-10-17 12:50:27 +00:00
|
|
|
raiseassert "unexpected record of fields " #& $cp.rec
|
2021-09-27 13:58:36 +00:00
|
|
|
of CompoundPatternKind.tuple:
|
2023-05-03 15:02:48 +00:00
|
|
|
for i, np in cp.tuple.patterns: addField(np, i)
|
2021-10-24 12:00:18 +00:00
|
|
|
of CompoundPatternKind.tuplePrefix:
|
2023-05-03 15:02:48 +00:00
|
|
|
for i, np in cp.tuplePrefix.fixed: addField(np, i)
|
2023-12-28 16:30:27 +00:00
|
|
|
let variableType = nimTypeOf(loc, known, "", cp.tuplePrefix.variable)
|
2021-10-24 12:00:18 +00:00
|
|
|
recList.add identDef(
|
2022-12-08 07:53:11 +00:00
|
|
|
scm,
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPragmaExpr.newTree(
|
2021-10-24 12:00:18 +00:00
|
|
|
ident(cp.tuplePrefix.variable, parentName).accQuote.toExport,
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPragma.newTree(ident"preservesTupleTail")),
|
2024-01-06 17:28:14 +00:00
|
|
|
parameterize(loc, variableType),
|
2022-12-08 07:53:11 +00:00
|
|
|
variableType.isEmbedded)
|
2023-12-28 16:34:40 +00:00
|
|
|
of CompoundPatternKind.dict:
|
|
|
|
for nameVal, nsp in cp.dict.entries:
|
2024-01-02 18:54:22 +00:00
|
|
|
recList.addField(loc, known, $nameVal, nsp, 0, false)
|
2021-09-27 13:58:36 +00:00
|
|
|
reclist
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc addFields(recList: PNode; loc: Location; known: var TypeTable; name: string; pat: SimplePattern): PNode {.discardable.} =
|
|
|
|
addField(recList, loc, known, pat, name)
|
|
|
|
|
|
|
|
proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: string; pat: Pattern): PNode {.discardable.} =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
2023-12-28 16:30:27 +00:00
|
|
|
discard addFields(recList, loc, known, parentName, pat.simplePattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
2023-12-28 16:30:27 +00:00
|
|
|
discard addFields(recList, loc, known, parentName, pat.compoundPattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
reclist
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc addFields(recList: PNode; loc: Location; known: var TypeTable; parentName: string; entries: DictionaryEntries): PNode {.discardable.} =
|
2023-06-11 20:34:16 +00:00
|
|
|
var sortedEntries =
|
2023-12-27 15:05:30 +00:00
|
|
|
initOrderedTable[Value, NamedSimplePattern](entries.len)
|
2021-09-27 13:58:36 +00:00
|
|
|
for key, val in entries.pairs:
|
2023-06-11 20:34:16 +00:00
|
|
|
sortedEntries[key] = val
|
2023-12-27 15:05:30 +00:00
|
|
|
sort(sortedEntries) do (x, y: (Value, NamedSimplePattern)) -> int:
|
2023-06-11 20:34:16 +00:00
|
|
|
cmp(x[0], y[0])
|
|
|
|
for key, val in sortedEntries.pairs:
|
2021-09-27 13:58:36 +00:00
|
|
|
doAssert(key.isSymbol)
|
2022-02-20 04:33:15 +00:00
|
|
|
let label = string key.symbol
|
2022-12-08 07:53:11 +00:00
|
|
|
addField(recList, loc, known, val.pattern, label)
|
2021-09-27 13:58:36 +00:00
|
|
|
recList
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; nsp: NamedSimplePattern): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case nsp.orKind
|
|
|
|
of NamedsimplepatternKind.named:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, string nsp.named.name, nsp.named.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of NamedsimplepatternKind.anonymous:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, nsp.anonymous)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; rec: CompoundPatternRec): TypeSpec =
|
2023-05-17 08:12:08 +00:00
|
|
|
if isLiteral(loc, rec.label):
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkObjectTy.newTree(
|
2023-05-17 08:12:08 +00:00
|
|
|
newEmpty(), newEmpty(),
|
2023-12-28 16:30:27 +00:00
|
|
|
newNode(nkRecList).addFields(loc, known, name, rec.fields.pattern))
|
2023-05-17 08:12:08 +00:00
|
|
|
else:
|
2023-12-28 16:23:14 +00:00
|
|
|
result.node = ident"Value"
|
2023-05-17 08:12:08 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; cp: CompoundPattern): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case cp.orKind
|
|
|
|
of CompoundPatternKind.`rec`:
|
2023-12-28 16:30:27 +00:00
|
|
|
result = nimTypeOf(loc, known, name, cp.rec)
|
2021-10-24 12:00:18 +00:00
|
|
|
of CompoundPatternKind.`tuple`, CompoundPatternKind.`tupleprefix`:
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkObjectTy.newTree(
|
2021-10-24 12:00:18 +00:00
|
|
|
newEmpty(), newEmpty(),
|
2023-12-28 16:30:27 +00:00
|
|
|
newNode(nkRecList).addFields(loc, known, name, cp))
|
2021-09-27 13:58:36 +00:00
|
|
|
of CompoundPatternKind.`dict`:
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkObjectTy.newTree(newEmpty(), newEmpty(),
|
2023-12-28 16:30:27 +00:00
|
|
|
newNode(nkRecList).addFields(loc, known, name, cp.dict.entries))
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; pat: Pattern): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, pat.simplePattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, pat.compoundPattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; orDef: DefinitionOr): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
proc toEnumTy(): PNode =
|
|
|
|
let ty = nkEnumTy.newNode.add newEmpty()
|
|
|
|
proc add (na: NamedAlternative) =
|
|
|
|
ty.add na.variantLabel.ident.accQuote
|
2023-05-16 22:06:52 +00:00
|
|
|
add(orDef.field0.pattern0)
|
|
|
|
add(orDef.field0.pattern1)
|
|
|
|
for na in orDef.field0.patternN:
|
2021-09-27 13:58:36 +00:00
|
|
|
add(na)
|
|
|
|
ty
|
2022-12-08 07:53:11 +00:00
|
|
|
if isSymbolEnum(loc, orDef):
|
2021-09-27 13:58:36 +00:00
|
|
|
result.node = toEnumTy()
|
|
|
|
else:
|
|
|
|
let
|
|
|
|
enumName = name & "Kind"
|
2022-12-08 07:53:11 +00:00
|
|
|
enumPath = loc.schemaPath & @[Symbol enumName]
|
2021-09-27 13:58:36 +00:00
|
|
|
enumIdent = ident(enumName)
|
2022-12-08 07:53:11 +00:00
|
|
|
if enumPath notin known:
|
2023-08-05 19:22:43 +00:00
|
|
|
known[enumPath] = nkTypeDef.newTree(
|
|
|
|
nkPragmaExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
enumName.ident.toExport,
|
2023-08-05 19:22:43 +00:00
|
|
|
nkPragma.newTree(ident"pure")),
|
2021-09-27 13:58:36 +00:00
|
|
|
newEmpty(),
|
|
|
|
toEnumTy())
|
|
|
|
let recCase = nkRecCase.newNode.add(
|
|
|
|
nkIdentDefs.newNode.add(
|
|
|
|
"orKind".ident.toExport,
|
|
|
|
enumName.ident,
|
|
|
|
newEmpty()))
|
|
|
|
template addCase(na: NamedAlternative) =
|
2023-08-05 19:22:43 +00:00
|
|
|
let branchRecList = newNode(nkRecList)
|
2021-09-27 13:58:36 +00:00
|
|
|
var memberType: TypeSpec
|
2022-12-08 07:53:11 +00:00
|
|
|
if isLiteral(loc, na.pattern):
|
2021-09-27 13:58:36 +00:00
|
|
|
memberType.node = ident"bool"
|
2024-01-06 17:27:06 +00:00
|
|
|
elif na.pattern.isSimple:
|
|
|
|
memberType = typeIdent(loc, na.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
else:
|
2022-12-08 07:53:11 +00:00
|
|
|
let
|
|
|
|
memberTypeName = name & na.variantLabel.capitalizeAscii
|
|
|
|
memberPath = loc.schemaPath & @[Symbol memberTypeName]
|
2021-09-27 13:58:36 +00:00
|
|
|
memberType.node = ident memberTypeName
|
2023-12-28 16:30:27 +00:00
|
|
|
let ty = nimTypeOf(loc, known, memberTypeName, na.pattern)
|
2022-12-08 07:53:11 +00:00
|
|
|
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)
|
2024-01-06 17:28:14 +00:00
|
|
|
memberType.node = parameterize(
|
|
|
|
loc, memberType.node, isEmbedded(loc, na.pattern))
|
2024-01-07 22:06:09 +00:00
|
|
|
var memberId = toFieldIdent(loc, na.variantLabel.normalize, na.pattern)
|
|
|
|
if isEmbedded(loc, na.pattern):
|
|
|
|
memberId = nkPragmaExpr.newTree(
|
|
|
|
memberId, nkPragma.newTree(ident"preservesEmbedded"))
|
2023-08-05 19:22:43 +00:00
|
|
|
branchRecList.add nkIdentDefs.newTree(
|
2024-01-07 22:06:09 +00:00
|
|
|
memberId,
|
2021-09-27 13:58:36 +00:00
|
|
|
memberType.node, newEmpty())
|
2023-08-05 19:22:43 +00:00
|
|
|
recCase.add nkOfBranch.newTree(
|
|
|
|
nkDotExpr.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
enumIdent, na.variantLabel.ident.accQuote),
|
|
|
|
branchRecList)
|
2023-05-16 22:06:52 +00:00
|
|
|
addCase(orDef.field0.pattern0)
|
|
|
|
addCase(orDef.field0.pattern1)
|
|
|
|
for na in orDef.field0.patternN: addCase(na)
|
2023-08-05 19:22:43 +00:00
|
|
|
result.node = nkObjectTy.newTree(
|
2021-09-27 13:58:36 +00:00
|
|
|
newEmpty(),
|
|
|
|
newEmpty(),
|
2023-08-05 19:22:43 +00:00
|
|
|
nkRecList.newTree(recCase))
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2024-01-02 18:54:22 +00:00
|
|
|
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
|
2023-12-28 16:34:40 +00:00
|
|
|
if isDictionary(loc, def):
|
2024-01-02 18:54:22 +00:00
|
|
|
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)
|
2023-12-28 16:34:40 +00:00
|
|
|
else:
|
|
|
|
result.node = ident"Value"
|
|
|
|
|
2023-12-28 16:30:27 +00:00
|
|
|
proc nimTypeOf(loc: Location; known: var TypeTable; name: string; def: Definition): TypeSpec =
|
2021-09-27 13:58:36 +00:00
|
|
|
case def.orKind
|
|
|
|
of DefinitionKind.or:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, def.or)
|
2023-03-01 04:03:19 +00:00
|
|
|
of DefinitionKind.and:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, def.and)
|
2021-09-27 13:58:36 +00:00
|
|
|
of DefinitionKind.Pattern:
|
2023-12-28 16:30:27 +00:00
|
|
|
nimTypeOf(loc, known, name, def.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
proc generateConstProcs(result: var seq[PNode]; scm: Schema, name: string; def: Definition) =
|
|
|
|
discard
|
|
|
|
|
|
|
|
proc generateProcs(result: var seq[PNode]; scm: Schema; name: string; def: Definition) =
|
|
|
|
discard
|
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; pat: Pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; sp: SimplePattern) =
|
2021-09-27 13:58:36 +00:00
|
|
|
case sp.orKind
|
2024-02-08 14:21:11 +00:00
|
|
|
of SimplePatternKind.seqof:
|
|
|
|
collectRefImports(imports, loc, sp.seqof.pattern)
|
2023-06-07 10:00:24 +00:00
|
|
|
of SimplePatternKind.setof:
|
|
|
|
incl(imports, "std/sets")
|
2024-02-08 14:21:11 +00:00
|
|
|
collectRefImports(imports, loc, sp.setof.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of SimplePatternKind.dictof:
|
2023-05-14 21:55:27 +00:00
|
|
|
incl(imports, "std/tables")
|
2024-02-08 14:21:11 +00:00
|
|
|
collectRefImports(imports, loc, sp.dictof.key)
|
|
|
|
collectRefImports(imports, loc, sp.dictof.value)
|
2021-09-27 13:58:36 +00:00
|
|
|
of SimplePatternKind.Ref:
|
2023-03-01 17:03:22 +00:00
|
|
|
if sp.ref.module != @[] and sp.ref.module != loc.schemaPath:
|
2023-05-14 21:55:27 +00:00
|
|
|
incl(imports, string sp.ref.module[0])
|
2021-09-27 13:58:36 +00:00
|
|
|
else: discard
|
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; cp: CompoundPattern) =
|
2021-09-27 13:58:36 +00:00
|
|
|
case cp.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.rec:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, cp.rec.label.pattern)
|
|
|
|
collectRefImports(imports, loc, cp.rec.fields.pattern)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tuple:
|
2023-05-14 21:55:27 +00:00
|
|
|
for p in cp.tuple.patterns: collectRefImports(imports, loc, p.pattern)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.tupleprefix:
|
2023-05-14 21:55:27 +00:00
|
|
|
for np in cp.tupleprefix.fixed: collectRefImports(imports, loc, np.pattern)
|
|
|
|
collectRefImports(imports, loc, cp.tupleprefix.variable.pattern)
|
2023-03-01 17:03:22 +00:00
|
|
|
of CompoundPatternKind.dict:
|
2021-09-27 13:58:36 +00:00
|
|
|
for nsp in cp.dict.entries.values:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, nsp.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; pat: Pattern) =
|
2021-09-27 13:58:36 +00:00
|
|
|
case pat.orKind
|
|
|
|
of PatternKind.SimplePattern:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, pat.simplePattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of PatternKind.CompoundPattern:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, pat.compoundPattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; def: Definition) =
|
2021-09-27 13:58:36 +00:00
|
|
|
case def.orKind
|
2023-03-01 17:03:22 +00:00
|
|
|
of DefinitionKind.or:
|
2023-05-16 22:06:52 +00:00
|
|
|
collectRefImports(imports, loc, def.or.field0.pattern0.pattern)
|
|
|
|
collectRefImports(imports, loc, def.or.field0.pattern1.pattern)
|
|
|
|
for na in def.or.field0.patternN:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, na.pattern)
|
2023-03-01 17:03:22 +00:00
|
|
|
of DefinitionKind.and:
|
2023-12-28 16:34:40 +00:00
|
|
|
if isDictionary(loc, def):
|
2024-01-02 18:54:22 +00:00
|
|
|
incl(imports, "std/options")
|
2023-05-16 22:06:52 +00:00
|
|
|
collectRefImports(imports, loc, def.and.field0.pattern0.pattern)
|
|
|
|
collectRefImports(imports, loc, def.and.field0.pattern1.pattern)
|
|
|
|
for np in def.and.field0.patternN:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, np.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
of DefinitionKind.Pattern:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, def.pattern)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
proc collectRefImports(imports: var StringSet; loc: Location; scm: Schema) =
|
2023-05-16 22:06:52 +00:00
|
|
|
for _, def in scm.field0.definitions:
|
2023-05-14 21:55:27 +00:00
|
|
|
collectRefImports(imports, loc, def)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc mergeType(x: var PNode; y: PNode) =
|
|
|
|
if x.isNil: x = y
|
2023-08-05 19:22:43 +00:00
|
|
|
else: x = nkInfix.newTree(ident"|", x, y)
|
2022-12-08 07:53:11 +00:00
|
|
|
|
|
|
|
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:
|
2023-03-01 04:05:44 +00:00
|
|
|
let loc = (bundle, scmPath)
|
2022-12-08 07:53:11 +00:00
|
|
|
var
|
|
|
|
typeSection = newNode nkTypeSection
|
|
|
|
procs: seq[PNode]
|
2024-01-06 17:28:14 +00:00
|
|
|
unembeddableType: PNode
|
2023-05-16 22:06:52 +00:00
|
|
|
for name, def in scm.field0.definitions.pairs:
|
2022-12-08 07:53:11 +00:00
|
|
|
if isLiteral(loc, def):
|
|
|
|
generateConstProcs(procs, scm, string name, def)
|
|
|
|
else:
|
|
|
|
var name = string name
|
|
|
|
name[0] = name[0].toUpperAscii
|
2024-01-06 17:28:14 +00:00
|
|
|
var defIdent = parameterize(loc, ident(name), isEmbedded(loc, def))
|
2022-12-08 07:53:11 +00:00
|
|
|
if not isSymbolEnum(loc, def) and not isAny(loc, def):
|
2024-01-06 17:28:14 +00:00
|
|
|
mergeType(unembeddableType, defIdent)
|
2023-12-28 16:30:27 +00:00
|
|
|
let typeSpec = nimTypeOf(loc, typeDefs, name, def)
|
2022-12-08 07:53:11 +00:00
|
|
|
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)
|
|
|
|
|
2023-05-14 21:55:27 +00:00
|
|
|
let imports = nkImportStmt.newNode.add(ident"preserves")
|
|
|
|
block:
|
|
|
|
var importSet: HashSet[string]
|
|
|
|
collectRefImports(importSet, loc, scm)
|
|
|
|
for module in importSet:
|
|
|
|
add(imports, ident(module))
|
2022-12-08 07:53:11 +00:00
|
|
|
if not unembeddableType.isNil:
|
2023-08-05 19:22:43 +00:00
|
|
|
procs.add nkProcDef.newTree(
|
2022-12-08 07:53:11 +00:00
|
|
|
"$".toFieldIdent,
|
|
|
|
newEmpty(),
|
|
|
|
newEmpty(),
|
2023-08-05 19:22:43 +00:00
|
|
|
nkFormalParams.newTree(
|
2022-12-08 07:53:11 +00:00
|
|
|
ident"string",
|
2023-08-05 19:22:43 +00:00
|
|
|
nkIdentDefs.newTree(
|
2022-12-08 07:53:11 +00:00
|
|
|
ident"x",
|
|
|
|
unembeddableType,
|
|
|
|
newEmpty())),
|
|
|
|
newEmpty(),
|
|
|
|
newEmpty(),
|
2023-08-05 19:22:43 +00:00
|
|
|
nkStmtList.newTree(
|
|
|
|
nkCall.newTree(ident"$",
|
2023-12-27 15:05:30 +00:00
|
|
|
nkCall.newTree(ident"toPreserves", ident"x"))))
|
2023-08-05 19:22:43 +00:00
|
|
|
procs.add nkProcDef.newTree(
|
2022-12-08 07:53:11 +00:00
|
|
|
"encode".ident.toExport,
|
|
|
|
newEmpty(),
|
|
|
|
newEmpty(),
|
2023-08-05 19:22:43 +00:00
|
|
|
nkFormalParams.newTree(
|
|
|
|
nkBracketExpr.newTree(ident"seq", ident"byte"),
|
|
|
|
nkIdentDefs.newTree(
|
2022-12-08 07:53:11 +00:00
|
|
|
ident"x",
|
|
|
|
unembeddableType,
|
|
|
|
newEmpty())),
|
|
|
|
newEmpty(),
|
|
|
|
newEmpty(),
|
2023-08-05 19:22:43 +00:00
|
|
|
nkStmtList.newTree(
|
|
|
|
nkCall.newTree(ident"encode", nkCall.newTree(
|
2023-12-27 15:05:30 +00:00
|
|
|
ident"toPreserves", ident"x"))))
|
2022-12-08 07:53:11 +00:00
|
|
|
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")
|
2023-08-05 19:22:43 +00:00
|
|
|
result[filePath] = renderTree(module, {renderIds, renderSyms, renderIr, renderNonExportedFields, renderExpandUsing})
|
|
|
|
# not sure what all these flags do
|
2021-09-27 13:58:36 +00:00
|
|
|
|
|
|
|
when isMainModule:
|
2021-11-11 10:11:40 +00:00
|
|
|
import ./schemaparse
|
|
|
|
|
2022-12-08 07:53:11 +00:00
|
|
|
proc writeModules(bundle: Bundle) =
|
|
|
|
let modules = renderNimBundle(bundle)
|
|
|
|
for path, txt in modules.pairs:
|
|
|
|
writeFile(path, txt)
|
|
|
|
stdout.writeLine(path)
|
2021-09-27 13:58:36 +00:00
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
import std/[os, parseopt]
|
2021-09-27 13:58:36 +00:00
|
|
|
var inputs: seq[string]
|
|
|
|
for kind, key, val in getopt():
|
|
|
|
case kind
|
|
|
|
of cmdLongOption:
|
|
|
|
case key
|
|
|
|
else: quit("unhandled option " & key)
|
|
|
|
of cmdShortOption:
|
|
|
|
case key
|
|
|
|
else: quit("unhandled option " & key)
|
|
|
|
of cmdArgument:
|
|
|
|
inputs.add absolutePath(key)
|
|
|
|
of cmdEnd: discard
|
2022-12-08 07:53:11 +00:00
|
|
|
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:
|
2023-04-01 17:33:15 +00:00
|
|
|
var (dirPath, fileName, _) = splitFile inputPath
|
2022-12-08 07:53:11 +00:00
|
|
|
let raw = readFile inputPath
|
|
|
|
if raw[0] == 0xb4.char:
|
|
|
|
var pr = decodePreserves raw
|
2023-12-27 15:05:30 +00:00
|
|
|
if not fromPreserves(bundle, pr):
|
2022-12-08 07:53:11 +00:00
|
|
|
var schema: Schema
|
2023-12-27 15:05:30 +00:00
|
|
|
if fromPreserves(schema, pr):
|
2022-12-08 07:53:11 +00:00
|
|
|
bundle.modules[@[Symbol fileName]] = schema
|
|
|
|
else:
|
|
|
|
var scm = parsePreservesSchema(readFile(inputPath), dirPath)
|
|
|
|
bundle.modules[@[Symbol fileName]] = scm
|
2023-12-29 11:47:25 +00:00
|
|
|
if bundle.modules.len == 0:
|
2022-12-08 07:53:11 +00:00
|
|
|
quit "Failed to recognize " & inputPath
|
2021-11-11 10:11:40 +00:00
|
|
|
else:
|
2022-12-08 07:53:11 +00:00
|
|
|
writeModules(bundle)
|