allow .experimental in a .push/pop environment; refs #8676
This commit is contained in:
parent
57a291db33
commit
c0c8828d9f
4 changed files with 61 additions and 18 deletions
|
|
@ -343,6 +343,20 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
|
||||||
of wPatterns: {optPatterns}
|
of wPatterns: {optPatterns}
|
||||||
else: {}
|
else: {}
|
||||||
|
|
||||||
|
proc processExperimental(c: PContext; n: PNode) =
|
||||||
|
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
||||||
|
c.features.incl oldExperimentalFeatures
|
||||||
|
else:
|
||||||
|
n[1] = c.semConstExpr(c, n[1])
|
||||||
|
case n[1].kind
|
||||||
|
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||||
|
try:
|
||||||
|
c.features.incl parseEnum[Feature](n[1].strVal)
|
||||||
|
except ValueError:
|
||||||
|
localError(c.config, n[1].info, "unknown experimental feature")
|
||||||
|
else:
|
||||||
|
localError(c.config, n.info, errStringLiteralExpected)
|
||||||
|
|
||||||
proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
|
proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
|
||||||
result = true
|
result = true
|
||||||
if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
|
if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
|
||||||
|
|
@ -350,6 +364,9 @@ proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
|
||||||
elif n.sons[0].kind != nkIdent: result = false
|
elif n.sons[0].kind != nkIdent: result = false
|
||||||
else:
|
else:
|
||||||
let sw = whichKeyword(n.sons[0].ident)
|
let sw = whichKeyword(n.sons[0].ident)
|
||||||
|
if sw == wExperimental:
|
||||||
|
processExperimental(c, n)
|
||||||
|
return true
|
||||||
let opts = pragmaToOptions(sw)
|
let opts = pragmaToOptions(sw)
|
||||||
if opts != {}:
|
if opts != {}:
|
||||||
onOff(c, n, opts, resOptions)
|
onOff(c, n, opts, resOptions)
|
||||||
|
|
@ -388,6 +405,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||||
x.defaultCC = y.defaultCC
|
x.defaultCC = y.defaultCC
|
||||||
x.dynlib = y.dynlib
|
x.dynlib = y.dynlib
|
||||||
x.notes = c.config.notes
|
x.notes = c.config.notes
|
||||||
|
x.features = c.features
|
||||||
c.optionStack.add(x)
|
c.optionStack.add(x)
|
||||||
for i in countup(start, sonsLen(n) - 1):
|
for i in countup(start, sonsLen(n) - 1):
|
||||||
if not tryProcessOption(c, n.sons[i], c.config.options):
|
if not tryProcessOption(c, n.sons[i], c.config.options):
|
||||||
|
|
@ -407,6 +425,7 @@ proc processPop(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
c.config.options = c.optionStack[^1].options
|
c.config.options = c.optionStack[^1].options
|
||||||
c.config.notes = c.optionStack[^1].notes
|
c.config.notes = c.optionStack[^1].notes
|
||||||
|
c.features = c.optionStack[^1].features
|
||||||
c.optionStack.setLen(c.optionStack.len - 1)
|
c.optionStack.setLen(c.optionStack.len - 1)
|
||||||
|
|
||||||
proc processDefine(c: PContext, n: PNode) =
|
proc processDefine(c: PContext, n: PNode) =
|
||||||
|
|
@ -717,22 +736,6 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||||
elif n.kind == nkExprColonExpr:
|
elif n.kind == nkExprColonExpr:
|
||||||
result.kind = n.kind # pragma(arg) -> pragma: arg
|
result.kind = n.kind # pragma(arg) -> pragma: arg
|
||||||
|
|
||||||
proc processExperimental(c: PContext; n: PNode; s: PSym) =
|
|
||||||
if not isTopLevel(c):
|
|
||||||
localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement")
|
|
||||||
if n.kind notin nkPragmaCallKinds or n.len != 2:
|
|
||||||
c.features.incl oldExperimentalFeatures
|
|
||||||
else:
|
|
||||||
n[1] = c.semConstExpr(c, n[1])
|
|
||||||
case n[1].kind
|
|
||||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
|
||||||
try:
|
|
||||||
c.features.incl parseEnum[Feature](n[1].strVal)
|
|
||||||
except ValueError:
|
|
||||||
localError(c.config, n[1].info, "unknown experimental feature")
|
|
||||||
else:
|
|
||||||
localError(c.config, n.info, errStringLiteralExpected)
|
|
||||||
|
|
||||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
validPragmas: TSpecialWords): bool =
|
validPragmas: TSpecialWords): bool =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
|
|
@ -1071,7 +1074,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
else:
|
else:
|
||||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||||
of wExperimental:
|
of wExperimental:
|
||||||
processExperimental(c, it, sym)
|
if not isTopLevel(c):
|
||||||
|
localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement or in a 'push' environment")
|
||||||
|
processExperimental(c, it)
|
||||||
of wThis:
|
of wThis:
|
||||||
if it.kind in nkPragmaCallKinds and it.len == 2:
|
if it.kind in nkPragmaCallKinds and it.len == 2:
|
||||||
c.selfName = considerQuotedIdent(c, it[1])
|
c.selfName = considerQuotedIdent(c, it[1])
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ type
|
||||||
defaultCC*: TCallingConvention
|
defaultCC*: TCallingConvention
|
||||||
dynlib*: PLib
|
dynlib*: PLib
|
||||||
notes*: TNoteKinds
|
notes*: TNoteKinds
|
||||||
|
features*: set[Feature]
|
||||||
otherPragmas*: PNode # every pragma can be pushed
|
otherPragmas*: PNode # every pragma can be pushed
|
||||||
|
|
||||||
POptionEntry* = ref TOptionEntry
|
POptionEntry* = ref TOptionEntry
|
||||||
|
|
|
||||||
|
|
@ -6946,12 +6946,36 @@ Example:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
{.experimental: "parallel".}
|
{.experimental: "parallel".}
|
||||||
|
|
||||||
proc useUsing(bar, foo) =
|
proc useParallel() =
|
||||||
parallel:
|
parallel:
|
||||||
for i in 0..4:
|
for i in 0..4:
|
||||||
echo "echo in parallel"
|
echo "echo in parallel"
|
||||||
|
|
||||||
|
|
||||||
|
As a top level statement, the experimental pragma enables a feature for the
|
||||||
|
rest of the module it's enabled in. This is problematic for macro and generic
|
||||||
|
instantiations that cross a module scope. Currently these usages have to be
|
||||||
|
put into a ``.push/pop`` environment:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
# client.nim
|
||||||
|
proc useParallel*[T](unused: T) =
|
||||||
|
# use a generic T here to show the problem.
|
||||||
|
{.push experimental: "parallel".}
|
||||||
|
parallel:
|
||||||
|
for i in 0..4:
|
||||||
|
echo "echo in parallel"
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
import client
|
||||||
|
useParallel(1)
|
||||||
|
|
||||||
|
|
||||||
Implementation Specific Pragmas
|
Implementation Specific Pragmas
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
|
|
|
||||||
13
tests/pragmas/tpushexperimental.nim
Normal file
13
tests/pragmas/tpushexperimental.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: '''0 1
|
||||||
|
1 2
|
||||||
|
2 3
|
||||||
|
0 1
|
||||||
|
1 2
|
||||||
|
2 3
|
||||||
|
3 5'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import mpushexperimental
|
||||||
|
|
||||||
|
main(12)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue