Refactor preserves_schema_nim

This commit is contained in:
Emery Hemingway 2021-09-08 18:02:08 +02:00
parent efd5cf62df
commit 7edc05a35d
2 changed files with 193 additions and 44 deletions

View File

@ -40,16 +40,17 @@ proc ident(sn: SchemaNode): PNode =
case sn.kind
of snkAlt:
s = sn.altLabel.nimIdentNormalize
s[0] = s[0].toLowerAscii
of snkLiteral: s = $sn.value
of snkRecord:
s = $sn.nodes[0]
s = sn.nodes[0].value.symbol
of snkNamed:
s = sn.name
of snkDictionary, snkVariableTuple:
s = "data"
else:
raiseAssert("no ident for " & $sn.kind & " " & $sn)
ident(s)
s.ident.accQuote
proc typeIdent(sn: SchemaNode): PNode =
case sn.kind
@ -85,6 +86,17 @@ proc isConst(scm: Schema; sn: SchemaNode): bool =
result = isConst(scm, scm.definitions[sn.refPath[0]])
else: discard
proc literal(scm: Schema; sn: SchemaNode): Preserve =
case sn.kind
of snkLiteral: result = sn.value
of snkRef:
if sn.refPath.len == 1:
result = literal(scm, scm.definitions[sn.refPath[0]])
else:
raiseAssert("not convertable to a literal: " & $sn)
else:
raiseAssert("not convertable to a literal: " & $sn)
proc isSymbolEnum(sn: SchemaNode): bool =
if sn.kind == snkOr:
for bn in sn.nodes:
@ -133,7 +145,7 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
if not isConst(scm, bn.altBranch.nodes[1]):
let label = bn.ident
recList.add nkIdentDefs.newNode.add(
label.accQuote.toExport,
label.toExport,
nimTypeOf(scm, known, bn.altBranch.nodes[1], $label),
newEmpty())
else:
@ -141,7 +153,7 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
if i > 0 and (not isConst(scm, field)):
let label = field.ident
recList.add nkIdentDefs.newNode.add(
label.accQuote.toExport,
label.toExport,
nimTypeOf(scm, known, field, $label),
newEmpty())
else:
@ -150,7 +162,7 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
else:
let label = bn.ident
recList.add(nkIdentDefs.newNode.add(
label.accQuote,
label,
nimTypeOf(scm, known, bn.altBranch, $label),
newEmpty()))
let disc = nkDotExpr.newNode.add(
@ -186,7 +198,6 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
nkBracketExpr, ident"HashSet", ident"Preserve")
of pkDictionary: nn(
nkBracketExpr, ident"Table", ident"Preserve", ident"Preserve")
of pkEmbedded: nn(nkDiscardStmt, newEmpty()) # TODO: is this possible?
of snkSequenceOf:
result = nkBracketExpr.newNode.add(
ident"seq",
@ -197,7 +208,7 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
nimTypeOf(scm, known, sn.child))
of snkDictOf:
result = nkBracketExpr.newNode.add(
ident"TableRef",
ident"Table",
nimTypeOf(scm, known, sn.nodes[0]),
nimTypeOf(scm, known, sn.nodes[1]))
of snkRecord:
@ -213,31 +224,53 @@ proc nimTypeOf(scm: Schema; known: var TypeTable; sn: SchemaNode; name = ""): PN
if i > 0:
let id = field.ident
recList.add nkIdentDefs.newNode.add(
id.accQuote.toExport,
id.toExport,
nimTypeOf(scm, known, field, $id),
newEmpty())
result = nn(nkRefTy, nn(nkObjectTy,
newEmpty(),
newEmpty(),
recList))
of snkTuple, snkVariableTuple:
of snkTuple:
# TODO: the variable part
result = nkTupleTy.newNode
for tn in sn.nodes:
result.add nkIdentDefs.newNode.add(
tn.ident.accQuote, nimTypeOf(scm, known, tn), newEmpty())
if not isConst(scm, sn):
result.add nkIdentDefs.newNode.add(
tn.ident, nimTypeOf(scm, known, tn), newEmpty())
of snkVariableTuple:
result = nkTupleTy.newNode
for i, tn in sn.nodes:
if not isConst(scm, sn):
if i == sn.nodes.high:
result.add nkIdentDefs.newNode.add(
tn.ident,
nn(nkBracketExpr, ident"seq", nimTypeOf(scm, known, tn)),
newEmpty())
else:
result.add nkIdentDefs.newNode.add(
tn.ident, nimTypeOf(scm, known, tn), newEmpty())
of snkDictionary:
result = nkTupleTy.newNode
for i in countup(0, sn.nodes.high, 2):
let id = ident(sn.nodes[i+0])
result.add nkIdentDefs.newNode.add(
id.accQuote,
id,
nimTypeOf(scm, known, sn.nodes[i+1], $id),
newEmpty())
of snkNamed:
result = nimTypeOf(scm, known, sn.pattern, name)
of snkRef:
result = typeIdent(sn)
if sn.refPath.len == 1:
let
refName = sn.refPath[0]
refDef = scm.definitions[refName]
case refDef.kind
of snkDictOf:
result = nimTypeOf(scm, known, refDef, refName)
else: result = typeIdent(sn)
else:
result = typeIdent(sn)
else:
result = nkCommentStmt.newNode
result.comment.add("Missing type generator for " & $sn.kind & " " & $sn)
@ -254,9 +287,7 @@ proc generateConstProcs(result: var seq[PNode]; name: string; def: SchemaNode) =
of pkSymbol:
discard stmts.add nn(nkCall,
ident"symbol",
PNode(kind: nkStrLit,
strVal: def.value.symbol),
ident"EmbeddedType")
PNode(kind: nkStrLit, strVal: def.value.symbol))
else:
raiseAssert("conversion of " & $def & " to a Nim literal is not implemented")
var procId = name
@ -279,23 +310,126 @@ proc toNimLit(sn: SchemaNode): PNode =
of pkSymbol:
nkCall.newNode.add(
ident"symbol",
PNode(kind: nkStrLit, strVal: sn.value.symbol),
ident"EmbeddedType")
PNode(kind: nkStrLit, strVal: sn.value.symbol))
else:
raiseAssert("no Nim literal for " & $sn)
proc generateProcs(result: var seq[PNode]; name: string; sn: SchemaNode) =
proc literalToPreserveCall(pr: Preserve): PNode =
var prConstr = nn(nkObjConstr, ident"Preserve")
proc constr(kind, field: string; lit: PNode) =
prConstr.add nn(nkExprColonExpr, ident"kind", ident(kind))
prConstr.add nn(nkExprColonExpr, ident(field), lit)
case pr.kind
of pkBoolean:
constr($pr.kind, "bool", if pr.bool: ident"true" else: ident"false")
of pkFloat:
constr($pr.kind, "float", newFloatNode(nkFloat32Lit, pr.float))
of pkDouble:
constr($pr.kind, "double", newFloatNode(nkFloat64Lit, pr.double))
of pkSignedInteger:
constr($pr.kind, "int", newIntNode(nkInt64Lit, pr.int))
of pkString:
constr($pr.kind, "string", newStrNode(nkTripleStrLit, pr.string))
of pkByteString:
return nn(nkCall, ident"parsePreserves", newStrNode(nkTripleStrLit, $pr))
of pkSymbol:
constr($pr.kind, "symbol", newStrNode(nkStrLit, pr.symbol))
else:
raise newException(ValueError, "refusing to convert to a literal: " & $pr)
prConstr
proc tupleConstructor(scm: Schema; sn: SchemaNode; ident: PNode): Pnode =
let seqBracket = nn(nkBracket)
for i, field in sn.nodes:
if isConst(scm, field):
seqBracket.add literalToPreserveCall(literal(scm, field))
elif sn.kind == snkTuple or i < sn.nodes.high:
seqBracket.add nn(nkCall,
ident"toPreserve",
nn(nkDotExpr, ident, field.ident))
let seqConstr = nn(nkPrefix, ident"@", seqBracket)
let colonExpr = nn(nkExprColonExpr, ident"sequence")
if sn.kind == snkTuple:
colonExpr.add seqConstr
else:
colonExpr.add nn(nkInfix,
ident"&",
seqConstr,
nn(nkDotExpr,
nn(nkCall, ident"toPreserve",
nn(nkDotExpr,
ident, sn.nodes[sn.nodes.high].ident)),
ident"sequence"))
nn(nkObjConstr,
ident"Preserve",
nn(nkExprColonExpr, ident"kind", ident"pkSequence"),
colonExpr)
proc generateProcs(result: var seq[PNode]; scm: Schema; name: string; sn: SchemaNode) =
case sn.kind
of snkOr:
var
enumId = name.ident
paramId = name.toLowerAscii.ident.accQuote
orStmts = nn(nkStmtList)
if sn.isSymbolEnum:
let caseStmt = nn(nkCaseStmt, paramId)
for bn in sn.nodes:
caseStmt.add nn(nkOfBranch,
nn(nkDotExpr,
enumId,
bn.altLabel.nimIdentNormalize.ident.accQuote),
nn(nkCall,
ident"symbol", PNode(kind: nkStrLit, strVal: $bn.altLabel)))
orStmts.add caseStmt
else:
let caseStmt = nn(nkCaseStmt, nn(nkDotExpr, paramId, ident"kind"))
proc genStmts(stmts: PNode; fieldId: PNode; sn: SchemaNode) =
case sn.kind
of snkLiteral:
stmts.add literalToPreserveCall(literal(scm, sn))
of snkOr, snkRecord, snkRef:
if sn.kind == snkRef and sn.refPath.len == 1:
let refDef = scm.definitions[sn.refPath[0]]
genStmts(stmts, fieldId, refDef)
else:
stmts.add nn(nkCall,
ident"toPreserve",
nn(nkDotExpr, paramId, fieldId))
of snkTuple, snkVariableTuple:
stmts.add tupleConstructor(scm, sn, nn(nkDotExpr, paramId, fieldId))
else:
raiseAssert("no case statement for " & $sn.kind & " " & $sn)
for bn in sn.nodes:
let stmts = nn(nkStmtList)
genStmts(stmts, bn.ident, bn.altBranch)
caseStmt.add nn(nkOfBranch,
nn(nkDotExpr,
ident(name & "Kind"),
bn.altLabel.nimIdentNormalize.ident.accQuote),
stmts)
orStmts.add caseStmt
result.add nn(nkProcDef,
exportIdent("toPreserveHook"),
newEmpty(),
newEmpty(),
nn(nkFormalParams,
ident"Preserve",
nn(nkIdentDefs,
paramId, ident(name), newEmpty())),
newEmpty(),
newEmpty(),
orStmts)
of snkRecord:
var
params = nn(nkFormalParams, ident"Preserve")
initRecordCall = nn(nkCall,
nn(nkBracketExpr, ident"initRecord", ident"EmbeddedType"),
ident"initRecord",
sn.nodes[0].toNimLit)
for i, field in sn.nodes:
if i > 0:
let
id = field.ident.accQuote
id = field.ident
var fieldType = field.typeIdent
if fieldType.kind != nkIdent or fieldType.ident.s != "Preserve":
fieldType =
@ -306,7 +440,7 @@ proc generateProcs(result: var seq[PNode]; name: string; sn: SchemaNode) =
params.add nn(nkIdentDefs,
id, fieldType, newEmpty())
initRecordCall.add(
nn(nkCall, ident"toPreserve", id, ident"EmbeddedType"))
nn(nkCall, ident"toPreserve", id))
var procId = name
procId[0] = procId[0].toLowerAscii
result.add nn(nkProcDef,
@ -321,6 +455,40 @@ proc generateProcs(result: var seq[PNode]; name: string; sn: SchemaNode) =
kind: nkCommentStmt,
comment: "Preserves constructor for ``" & name & "``."),
initRecordCall))
block:
let paramId = name.toLowerAscii.ident.accQuote
initRecordCall = nn(nkCall,
ident"initRecord",
sn.nodes[0].toNimLit)
for i, field in sn.nodes:
if i > 0:
initRecordCall.add nn(nkCall,
ident"toPreserve",
nn(nkDotExpr, paramId, field.ident))
result.add nn(nkProcDef,
exportIdent("toPreserveHook"),
newEmpty(),
newEmpty(),
nn(nkFormalParams,
ident"Preserve",
nn(nkIdentDefs,
paramId, ident(name), newEmpty())),
newEmpty(),
newEmpty(),
nn(nkStmtList, initRecordCall))
of snkTuple, snkVariableTuple:
let paramId = name.toLowerAscii.ident.accQuote
result.add nn(nkProcDef,
exportIdent("toPreserveHook"),
newEmpty(),
newEmpty(),
nn(nkFormalParams,
ident"Preserve",
nn(nkIdentDefs,
paramId, ident(name), newEmpty())),
newEmpty(),
newEmpty(),
nn(nkStmtList, tupleConstructor(scm, sn, paramId)))
else: discard
proc collectRefImports(imports: PNode; sn: SchemaNode) =
@ -350,22 +518,6 @@ proc generateNimFile*(scm: Schema; path: string) =
typeSection = newNode nkTypeSection
procs: seq[PNode]
megaType: PNode
if scm.embeddedType == "":
typeSection.add nn(nkTypeDef,
exportIdent"EmbeddedType",
newEmpty(),
ident"void")
else:
typeSection.add nn(nkTypeDef,
exportIdent"EmbeddedType",
newEmpty(),
scm.embeddedType.ident)
typeSection.add nn(nkTypeDef,
ident"Preserve",
newEmpty(),
nn(nkBracketExpr,
ident"PreserveGen",
ident"EmbeddedType"))
for name, def in scm.definitions.pairs:
if isConst(scm, def):
generateConstProcs(procs, name, def)
@ -416,7 +568,7 @@ proc generateNimFile*(scm: Schema; path: string) =
else:
knownTypes[name] = nn(nkTypeDef,
name.ident.toExport, newEmpty(), t)
generateProcs(procs, name, def)
generateProcs(procs, scm, name, def)
for typeDef in knownTypes.values:
typeSection.add typeDef
var imports = nkImportStmt.newNode.add(
@ -436,7 +588,7 @@ proc generateNimFile*(scm: Schema; path: string) =
newEmpty(),
newEmpty(),
nn(nkStmtList,
nn(nkCall, ident"$", nn(nkCall, ident"toPreserve", ident"x", ident"EmbeddedType"))))
nn(nkCall, ident"$", nn(nkCall, ident"toPreserve", ident"x"))))
procs.add nn(nkProcDef,
"encode".ident.accQuote.toExport,
newEmpty(),
@ -450,7 +602,7 @@ proc generateNimFile*(scm: Schema; path: string) =
newEmpty(),
newEmpty(),
nn(nkStmtList,
nn(nkCall, ident"encode", nn(nkCall, ident"toPreserve", ident"x", ident"EmbeddedType"))))
nn(nkCall, ident"encode", nn(nkCall, ident"toPreserve", ident"x"))))
var module = newNode(nkStmtList).add(
imports,
typeSection

View File

@ -116,9 +116,6 @@ proc `$`*(n: SchemaNode): string =
case n.value.kind
of pkBoolean, pkFloat, pkDouble, pkSignedInteger, pkString, pkByteString:
result.add $n.value
of pkSymbol:
result.add '='
result.add n.value.symbol
else:
result.add "<<lit>" & $n.value & ">"
of snkSequenceOf: