added system.compiles

This commit is contained in:
Araq 2012-07-20 08:49:42 +02:00
commit 1c6f14deee
8 changed files with 65 additions and 5 deletions

View file

@ -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,

View file

@ -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 = "???"

View file

@ -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

View file

@ -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))

View file

@ -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()

View file

@ -0,0 +1,12 @@
discard """
output: '''no'''
"""
# test the new 'compiles' feature:
when compiles(4+5.0 * "hallo"):
echo "yes"
else:
echo "no"

View file

@ -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;

View file

@ -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