summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-07-20 08:49:42 +0200
committerAraq <rumpf_a@web.de>2012-07-20 08:49:42 +0200
commit1c6f14deeeb3dc6acb41efba886e4999a8621a4a (patch)
treefc7d16bef573ed2423bc8961f9b6ebba681ea4ed
parent43f057c5aa23cf2cc441906737cd53fda90811c7 (diff)
downloadNim-1c6f14deeeb3dc6acb41efba886e4999a8621a4a.tar.gz
added system.compiles
-rwxr-xr-xcompiler/ast.nim3
-rwxr-xr-xcompiler/msgs.nim8
-rwxr-xr-xcompiler/semdata.nim3
-rwxr-xr-xcompiler/semexprs.nim30
-rwxr-xr-xlib/system.nim10
-rw-r--r--tests/compile/tcompiles.nim12
-rwxr-xr-xtodo.txt2
-rwxr-xr-xweb/news.txt2
8 files changed, 65 insertions, 5 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index c826dfad9..669b45159 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -381,7 +381,8 @@ const
 type
   TMagic* = enum # symbols that require compiler magic:
     mNone,
-    mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
+    mDefined, mDefinedInScope, mCompiles,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst,
     mUnaryLt, mSucc, 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index a661da0e1..30066d376 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -458,6 +458,7 @@ var
   gHintCounter*: int = 0
   gWarnCounter*: int = 0
   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
 # Borland and Freepascal use
@@ -528,12 +529,13 @@ proc addCheckpoint*(filename: string, line: int) =
 
 proc OutWriteln*(s: string) = 
   ## Writes to stdout. Always.
-  Writeln(stdout, s)
+  if gSilence == 0: Writeln(stdout, s)
  
 proc MsgWriteln*(s: string) = 
   ## Writes to stdout. If --stdout option is given, writes to stderr instead.
-  if optStdout in gGlobalOptions: Writeln(stderr, s)
-  else: Writeln(stdout, s)
+  if gSilence == 0:
+    if optStdout in gGlobalOptions: Writeln(stderr, s)
+    else: Writeln(stdout, s)
 
 proc coordToStr(coord: int): string = 
   if coord == -1: result = "???"
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 74e82db61..76ceafecf 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -63,6 +63,7 @@ type
                                # store this info in the syms themselves!)
     InGenericContext*: int     # > 0 if we are in a generic
     InUnrolledContext*: int    # > 0 if we are unrolling a loop
+    InCompilesContext*: int    # > 0 if we are in a ``compiles`` magic
     converters*: TSymSeq       # sequence of converters
     optionStack*: TLinkedList
     libs*: TLinkedList         # all libs used by this module
@@ -100,7 +101,7 @@ proc PushOwner*(owner: PSym)
 proc PopOwner*()
 # implementation
 
-var gOwners: seq[PSym] = @[]
+var gOwners*: seq[PSym] = @[]
 
 proc getCurrOwner(): PSym = 
   # owner stack (used for initializing the
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a0e7c329c..63a19c879 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1103,12 +1103,42 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
   else:
     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 = 
   # this is a hotspot in the compiler!
   result = n
   case s.magic # magics that need special treatment
   of mDefined: result = semDefined(c, setMs(n, s), false)
   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 mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
   of mSizeOf: result = semSizeof(c, setMs(n, s))
diff --git a/lib/system.nim b/lib/system.nim
index 32e338c5f..8f19f93f1 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2350,5 +2350,15 @@ proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
     x[j+i] = item[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):
   initDebugger()
diff --git a/tests/compile/tcompiles.nim b/tests/compile/tcompiles.nim
new file mode 100644
index 000000000..4b72d8bd8
--- /dev/null
+++ b/tests/compile/tcompiles.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''no'''
+"""
+
+# test the new 'compiles' feature:
+
+when compiles(4+5.0 * "hallo"):
+  echo "yes"
+else:
+  echo "no"
+  
+
diff --git a/todo.txt b/todo.txt
index 143775de7..4cd1eed4f 100755
--- a/todo.txt
+++ b/todo.txt
@@ -18,6 +18,8 @@ New pragmas:
   - fix evals.nim with closures
   - implement "closure tuple consists of a single 'ref'" optimization
   - 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
 - rethink the syntax: distinction between expr and stmt is unfortunate; 
diff --git a/web/news.txt b/web/news.txt
index fc879f474..b99d97f91 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -61,6 +61,8 @@ Library Additions
   for managing time.
 - Added ``system.@`` for converting an ``openarray`` to a ``seq`` (it used to
   only support fixed length arrays).
+- Added ``system.compiles`` which can be used to check whether a type supports
+  some operation.
 
 
 Changes affecting backwards compatibility