-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently CPS simply left the procedures untouched during docgen. This causes problems when code for `whelp` gets sem-ed, breaking docgen. This commit implements a couple docgen shims: - `cps` now result in a `{.cps: baseType.}` pragma tagged to the resulting procedure and will show up in the generated documentation. - `whelp` will generate `nil` continuation for the base type of a cps proc. - `whelp` will generate a `Callback` with a factory type that yields a the base continuation type, not the environment type. This should work for most cases when docgen are concerned. This worked well enough for `insideout` docs to be generated successfully under NimSkull.
- Loading branch information
Showing
2 changed files
with
99 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
when defined(nimdoc): | ||
import std/macros except newTree, newStmtList | ||
import callbacks, normalizedast, spec | ||
|
||
template cps(tipe: typed) {.pragma.} | ||
|
||
proc cpsDocAnnotate*(tipe, n: NimNode): NimNode = | ||
## Annotate `n` with a `cps` pragma that will show up in doc | ||
n.addPragma: | ||
nnkExprColonExpr.newTree(bindSym"cps", tipe) | ||
result = n | ||
|
||
proc getCpsBase(n: NormNode, origin: NormNode = n): NormNode = | ||
## recover the symbol of the cps base type or generate error ast | ||
case n.kind | ||
of NormalCallNodes: | ||
getCpsBase(n[0], origin) | ||
of nnkSym: | ||
getCpsBase(n.getImpl, origin) | ||
of nnkProcDef: | ||
if n.hasPragma "borrow": | ||
getCpsBase(n.last) | ||
elif n.hasPragma "cps": | ||
pragmaArgument(n, "cps") | ||
else: | ||
error "procedure " & n.name.strVal & " doesn't seem to be a cps call", origin | ||
normalizedast.newCall("typeOf", n) | ||
else: | ||
error "procedure doesn't seem to be a cps call", origin | ||
## XXX: darn ambiguous calls | ||
normalizedast.newCall("typeOf", n) | ||
|
||
proc whelpCall(call: Call): NormNode = | ||
let base = getCpsBase(call) | ||
result = newStmtList() | ||
for param in call[1..^1]: | ||
# Generate a let statement for every param. | ||
# This makes sure that effects generated by those params will be recorded | ||
# by docgen. | ||
result.add: | ||
nnkLetSection.newTree( | ||
nnkIdentDefs.newTree( | ||
nnkPragmaExpr.newTree( | ||
nskLet.genSym"forEffectsOnly", | ||
nnkPragma.newTree(ident"used") | ||
), | ||
newEmptyNode(), | ||
param | ||
) | ||
) | ||
|
||
result.add: | ||
newCall(base, newNilLit()) # Add the "supposed" whelp result | ||
|
||
proc whelpCallback(sym: Sym): NormNode = | ||
let | ||
impl = sym.getImpl.ProcDef | ||
base = getCpsBase(impl) | ||
|
||
var params = nnkFormalParams.newTree(copy base) | ||
for param in impl.callingParams: | ||
var idefs = nnkIdentDefs.newTree() | ||
|
||
# Add names | ||
for names in param[0..^3]: | ||
idefs.add desym(names.Sym) | ||
|
||
# Add type | ||
if param[^2].kind == nnkEmpty: | ||
idefs.add getTypeInst(param[^1]) | ||
else: | ||
idefs.add param[^2] | ||
|
||
# Make sure no "default" params are here | ||
idefs.add newEmptyNode() | ||
params.add idefs | ||
|
||
let factory = nnkProcTy.newTree(params, nnkPragma.newTree ident"nimcall") | ||
let returnType = NormNode: copyOrVoid(NimNode impl.returnParam) | ||
|
||
result = newCall( | ||
nnkBracketExpr.newTree( | ||
bindSym"Callback", | ||
copy base, | ||
returnType, | ||
factory | ||
) | ||
) | ||
|
||
proc docWhelp*(call: NimNode): NimNode = | ||
## Fake `whelp` implementation for docgen | ||
if call.kind == nnkSym: | ||
whelpCallback(call.Sym) | ||
else: | ||
whelpCall(normalizeCall call) |