added system.compiles
This commit is contained in:
parent
43f057c5aa
commit
1c6f14deee
8 changed files with 65 additions and 5 deletions
|
|
@ -381,7 +381,8 @@ const
|
||||||
type
|
type
|
||||||
TMagic* = enum # symbols that require compiler magic:
|
TMagic* = enum # symbols that require compiler magic:
|
||||||
mNone,
|
mNone,
|
||||||
mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
mDefined, mDefinedInScope, mCompiles,
|
||||||
|
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||||
mUnaryLt, mSucc,
|
mUnaryLt, mSucc,
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,7 @@ var
|
||||||
gHintCounter*: int = 0
|
gHintCounter*: int = 0
|
||||||
gWarnCounter*: int = 0
|
gWarnCounter*: int = 0
|
||||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||||
|
gSilence*: int # == 0 if we produce any output at all
|
||||||
|
|
||||||
# this format is understood by many text editors: it is the same that
|
# this format is understood by many text editors: it is the same that
|
||||||
# Borland and Freepascal use
|
# Borland and Freepascal use
|
||||||
|
|
@ -528,12 +529,13 @@ proc addCheckpoint*(filename: string, line: int) =
|
||||||
|
|
||||||
proc OutWriteln*(s: string) =
|
proc OutWriteln*(s: string) =
|
||||||
## Writes to stdout. Always.
|
## Writes to stdout. Always.
|
||||||
Writeln(stdout, s)
|
if gSilence == 0: Writeln(stdout, s)
|
||||||
|
|
||||||
proc MsgWriteln*(s: string) =
|
proc MsgWriteln*(s: string) =
|
||||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
if gSilence == 0:
|
||||||
else: Writeln(stdout, s)
|
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
||||||
|
else: Writeln(stdout, s)
|
||||||
|
|
||||||
proc coordToStr(coord: int): string =
|
proc coordToStr(coord: int): string =
|
||||||
if coord == -1: result = "???"
|
if coord == -1: result = "???"
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ type
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
InGenericContext*: int # > 0 if we are in a generic
|
InGenericContext*: int # > 0 if we are in a generic
|
||||||
InUnrolledContext*: int # > 0 if we are unrolling a loop
|
InUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||||
|
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
||||||
converters*: TSymSeq # sequence of converters
|
converters*: TSymSeq # sequence of converters
|
||||||
optionStack*: TLinkedList
|
optionStack*: TLinkedList
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
|
|
@ -100,7 +101,7 @@ proc PushOwner*(owner: PSym)
|
||||||
proc PopOwner*()
|
proc PopOwner*()
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
var gOwners: seq[PSym] = @[]
|
var gOwners*: seq[PSym] = @[]
|
||||||
|
|
||||||
proc getCurrOwner(): PSym =
|
proc getCurrOwner(): PSym =
|
||||||
# owner stack (used for initializing the
|
# owner stack (used for initializing the
|
||||||
|
|
|
||||||
|
|
@ -1103,12 +1103,42 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
# we replace this node by a 'true' or 'false' node:
|
||||||
|
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
||||||
|
result = newIntNode(nkIntLit, 0)
|
||||||
|
result.info = n.info
|
||||||
|
result.typ = getSysType(tyBool)
|
||||||
|
# watch out, hacks ahead:
|
||||||
|
let oldErrorCount = msgs.gErrorCounter
|
||||||
|
let oldErrorMax = msgs.gErrorMax
|
||||||
|
inc c.InCompilesContext
|
||||||
|
inc msgs.gSilence
|
||||||
|
# do not halt after first error:
|
||||||
|
msgs.gErrorMax = high(int)
|
||||||
|
|
||||||
|
let oldTos = c.tab.tos
|
||||||
|
let oldOwnerLen = len(gOwners)
|
||||||
|
try:
|
||||||
|
discard semExpr(c, n.sons[1])
|
||||||
|
result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
|
||||||
|
except ERecoverableError:
|
||||||
|
nil
|
||||||
|
# undo symbol table changes (as far as it's possible):
|
||||||
|
setlen(gOwners, oldOwnerLen)
|
||||||
|
while c.tab.tos > oldTos: rawCloseScope(c.tab)
|
||||||
|
dec c.InCompilesContext
|
||||||
|
dec msgs.gSilence
|
||||||
|
msgs.gErrorCounter = oldErrorCount
|
||||||
|
msgs.gErrorMax = oldErrorMax
|
||||||
|
|
||||||
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
# this is a hotspot in the compiler!
|
# this is a hotspot in the compiler!
|
||||||
result = n
|
result = n
|
||||||
case s.magic # magics that need special treatment
|
case s.magic # magics that need special treatment
|
||||||
of mDefined: result = semDefined(c, setMs(n, s), false)
|
of mDefined: result = semDefined(c, setMs(n, s), false)
|
||||||
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
||||||
|
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
||||||
of mLow: result = semLowHigh(c, setMs(n, s), mLow)
|
of mLow: result = semLowHigh(c, setMs(n, s), mLow)
|
||||||
of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
|
of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
|
||||||
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
||||||
|
|
|
||||||
|
|
@ -2350,5 +2350,15 @@ proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
||||||
x[j+i] = item[j]
|
x[j+i] = item[j]
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
|
proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
|
||||||
|
## Special compile-time procedure that checks whether `x` can be compiled
|
||||||
|
## without any semantic error.
|
||||||
|
## This can be used to check whether a type supports some operation:
|
||||||
|
##
|
||||||
|
## .. code-block:: Nimrod
|
||||||
|
## when not compiles(3 + 4):
|
||||||
|
## echo "'+' for integers is available"
|
||||||
|
nil
|
||||||
|
|
||||||
when defined(initDebugger):
|
when defined(initDebugger):
|
||||||
initDebugger()
|
initDebugger()
|
||||||
|
|
|
||||||
12
tests/compile/tcompiles.nim
Normal file
12
tests/compile/tcompiles.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: '''no'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# test the new 'compiles' feature:
|
||||||
|
|
||||||
|
when compiles(4+5.0 * "hallo"):
|
||||||
|
echo "yes"
|
||||||
|
else:
|
||||||
|
echo "no"
|
||||||
|
|
||||||
|
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -18,6 +18,8 @@ New pragmas:
|
||||||
- fix evals.nim with closures
|
- fix evals.nim with closures
|
||||||
- implement "closure tuple consists of a single 'ref'" optimization
|
- implement "closure tuple consists of a single 'ref'" optimization
|
||||||
- make closure default calling convention for proc types
|
- make closure default calling convention for proc types
|
||||||
|
- make 'raiseHook' take a closure and provide push and pop for this
|
||||||
|
--> Lisp-style exception system
|
||||||
|
|
||||||
- document 'do' notation
|
- document 'do' notation
|
||||||
- rethink the syntax: distinction between expr and stmt is unfortunate;
|
- rethink the syntax: distinction between expr and stmt is unfortunate;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ Library Additions
|
||||||
for managing time.
|
for managing time.
|
||||||
- Added ``system.@`` for converting an ``openarray`` to a ``seq`` (it used to
|
- Added ``system.@`` for converting an ``openarray`` to a ``seq`` (it used to
|
||||||
only support fixed length arrays).
|
only support fixed length arrays).
|
||||||
|
- Added ``system.compiles`` which can be used to check whether a type supports
|
||||||
|
some operation.
|
||||||
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue