summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/suggest.nim1
-rw-r--r--compiler/vm.nim8
-rw-r--r--compiler/vmgen.nim20
-rw-r--r--doc/tut1.txt74
-rw-r--r--lib/pure/future.nim15
-rw-r--r--lib/pure/os.nim179
-rw-r--r--lib/system/sysstr.nim6
-rw-r--r--lib/windows/winlean.nim4
-rw-r--r--tests/closure/tclosuremacro.nim8
-rw-r--r--tests/macros/texprcolonexpr.nim19
-rw-r--r--tests/stdlib/tgetfileinfo.nim93
-rw-r--r--tests/system/tsysspawnbadarg.nim7
13 files changed, 373 insertions, 63 deletions
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index caaab2291..79abfaf4d 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -404,7 +404,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
      mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, 
      mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
      mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
-     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym: 
+     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn:
     discard
   of mRand:
     result = newIntNodeT(math.random(a.getInt.int), n)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 49611f649..fc6ba2f77 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -253,6 +253,7 @@ proc findUsages(node: PNode, s: PSym) =
     lastLineInfo = node.info
 
 proc findDefinition(node: PNode, s: PSym) =
+  if node.isNil or s.isNil: return
   if isTracked(node.info, s.name.s.len):
     suggestWriteln(symToStr(s, isLocal=false, sectionDef))
     suggestQuit()
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 1365abb86..836f90967 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -354,6 +354,11 @@ template handleJmpBack() {.dirty.} =
       globalError(c.debug[pc], errTooManyIterations)
   dec(c.loopIterations)
 
+proc skipColon(n: PNode): PNode =
+  result = n
+  if n.kind == nkExprColonExpr:
+    result = n.sons[1]
+
 proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
   var pc = start
   var tos = tos
@@ -454,7 +459,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeBC(rkNode)
       let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit}:
-        let n = src.sons[rc]
+        let n = src.sons[rc].skipColon
         regs[ra].node = n
       else:
         stackTrace(c, tos, pc, errNilAccess)
@@ -1099,6 +1104,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
                                      c.module)
     of opcGorge:
       decodeBC(rkNode)
+      createStr regs[ra]
       regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
                                      regs[rc].node.strVal)
     of opcNError:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 7c0c3d4f5..84577bb22 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -70,6 +70,9 @@ proc echoCode*(c: PCtx, start=0) {.deprecated.} =
   echo buf
 
 proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
+  ## Takes the registers `b` and `c`, applies the operation `opc` to them, and
+  ## stores the result into register `a`
+  ## The node is needed for debug information
   assert opc.ord < 255
   let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
                            (b.uint32 shl 16'u32) or
@@ -78,6 +81,10 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
   ctx.debug.add(n.info)
 
 proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
+  # Takes the `b` register and the immediate `imm`, appies the operation `opc`,
+  # and stores the output value into `a`.
+  # `imm` is signed and must be within [-127, 128]
+  assert(imm >= -127 and imm <= 128)
   let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
                            (b.uint32 shl 16'u32) or
                            (imm+byteExcess).uint32 shl 24'u32).TInstr
@@ -85,6 +92,9 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
   c.debug.add(n.info)
 
 proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
+  # Applies `opc` to `bx` and stores it into register `a`
+  # `bx` must be signed and in the range [-32767, 32768]
+  assert(bx >= -32767 and bx <= 32768)
   let ins = (opc.uint32 or a.uint32 shl 8'u32 or 
             (bx+wordExcess).uint32 shl 16'u32).TInstr
   c.code.add(ins)
@@ -316,15 +326,7 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
   c.patch(L1)
 
 proc canonValue*(n: PNode): PNode =
-  if n.kind == nkExprColonExpr:
-    result = n.sons[1]
-  elif n.hasSubnodeWith(nkExprColonExpr):
-    result = n.copyNode
-    newSeq(result.sons, n.len)
-    for i in 0.. <n.len:
-      result.sons[i] = canonValue(n.sons[i])
-  else:
-    result = n
+  result = n
 
 proc rawGenLiteral(c: PCtx; n: PNode): int =
   result = c.constants.len
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 5a20629a2..46eda7ae3 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -132,7 +132,7 @@ a backslash:
     TMyObject {.final, pure, acyclic.} = object  # comment continues: \
       # we have lots of space here to comment 'TMyObject'.
       # This line belongs to the comment as it's properly aligned.
-

+
 
 Comments are tokens; they are only allowed at certain places in the input file
 as they belong to the syntax tree! This feature enables perfect source-to-source
@@ -150,6 +150,18 @@ the syntax, watch their indentation:
 **Note**: To comment out a large piece of code, it is often better to use a
 ``when false:`` statement.
 
+.. code-block:: nimrod
+  when false:
+    brokenCode()
+
+Another option is to use the `discard`_ statement together with
+*long string literals* to create block comments:
+
+.. code-block:: nimrod
+  discard """ You can have any nimrod code text commented 
+  out inside this with no indentation restrictions.
+        yes("May I ask a pointless question?") """
+
 
 Numbers
 -------
@@ -575,27 +587,46 @@ Some terminology: in the example ``question`` is called a (formal) *parameter*,
 
 Result variable
 ---------------
-A procedure that returns a value has an implicit ``result`` variable that
-represents the return value. A ``return`` statement with no expression is a
-shorthand for ``return result``. So all three code snippets are equivalent:
-
-.. code-block:: nimrod
-  return 42
-
-.. code-block:: nimrod
-  result = 42
-  return
-
-.. code-block:: nimrod
-  result = 42
-  return result
-
-
+A procedure that returns a value has an implicit ``result`` variable declared 
+that represents the return value. A ``return`` statement with no expression is a
+shorthand for ``return result``. The ``result`` value is always returned 
+automatically at the end a procedure if there is no ``return`` statement at
+the exit.
+
+.. code-block:: nimrod
+  proc sumTillNegative(x: varargs[int]): int = 
+    for i in x:
+      if i < 0:
+        return
+      result = result + i  
+      
+  echo sumTillNegative() # echos 0
+  echo sumTillNegative(3, 4, 5) # echos 12
+  echo sumTillNegative(3, 4 , -1 , 6) # echos 7
+
+The ``result`` variable is already implicitly declared at the start of the 
+function, so declaring it again with 'var result', for example, would shadow it
+with a normal variable of the same name. The result variable is also already
+initialised with the type's default value. Note that referential data types will
+be ``nil`` at the start of the procedure, and thus may require manual
+initialisation.
+
+      
 Parameters
 ----------
-Parameters are constant in the procedure body. Their value cannot be changed
-because this allows the compiler to implement parameter passing in the most
-efficient way. If the procedure needs to modify the argument for the
+Parameters are constant in the procedure body. By default, their value cannot be
+changed because this allows the compiler to implement parameter passing in the 
+most efficient way. If a mutable variable is needed inside the procedure, it has
+to be declared with ``var`` in the procedure body. Shadowing the parameter name
+is possible, and actually an idiom: 
+
+.. code-block:: nimrod
+  proc printSeq(s: seq, nprinted: int = -1) =
+    var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
+    for i in 0 .. <nprinted:
+      echo s[i]
+    
+If the procedure needs to modify the argument for the
 caller, a ``var`` parameter can be used:
 
 .. code-block:: nimrod
@@ -634,6 +665,9 @@ been declared with the ``discardable`` pragma:
     
   p(3, 4) # now valid
 
+The discard statement can also be used to create block comments as described
+in the `Comments`_.
+
 
 Named arguments
 ---------------
diff --git a/lib/pure/future.nim b/lib/pure/future.nim
index 2401c4f72..73c20e708 100644
--- a/lib/pure/future.nim
+++ b/lib/pure/future.nim
@@ -26,8 +26,15 @@ proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} =
     for i in 0 .. <p.len:
       let ident = p[i]
       var identDefs = newNimNode(nnkIdentDefs)
-      identDefs.add newIdentNode("i" & $i)
-      identDefs.add(ident)
+      case ident.kind
+      of nnkExprColonExpr:
+        identDefs.add ident[0]
+        identDefs.add ident[1]
+      of nnkIdent:
+        identDefs.add newIdentNode("i" & $i)
+        identDefs.add(ident)
+      else:
+        error("Incorrect type list in proc type declaration.")
       identDefs.add newEmptyNode()
       formalParams.add identDefs
   of nnkIdent:
@@ -47,7 +54,7 @@ proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} =
 macro `=>`*(p, b: expr): expr {.immediate.} =
   ## Syntax sugar for anonymous procedures.
   ##
-  ## ..code-block:: nimrod
+  ## .. code-block:: nimrod
   ##
   ##   proc passTwoAndTwo(f: (int, int) -> int): int =
   ##     f(2, 2)
@@ -98,7 +105,7 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
 macro `->`*(p, b: expr): expr {.immediate.} =
   ## Syntax sugar for procedure types.
   ##
-  ## ..code-block:: nimrod
+  ## .. code-block:: nimrod
   ##
   ##   proc pass2(f: (float, float) -> float): float =
   ##     f(2, 2)
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 62261753f..00a33db75 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -448,6 +448,8 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
 
 proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s creation time.
+  ## Note that under posix OS's, the returned time may actually be the time at
+  ## which the file's attribute's were last modified.
   when defined(posix):
     var res: TStat
     if stat(file, res) < 0'i32: osError(osLastError())
@@ -777,6 +779,25 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
   elif defined(posix):
     result = path[0] == '/'
 
+when defined(Windows):
+  proc openHandle(path: string, followSymlink=true): THandle =
+    var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
+    if not followSymlink:
+      flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
+
+    when useWinUnicode:
+      result = createFileW(
+        newWideCString(path), 0'i32, 
+        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
+        nil, OPEN_EXISTING, flags, 0
+        )
+    else:
+      result = createFileA(
+        path, 0'i32, 
+        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
+        nil, OPEN_EXISTING, flags, 0
+        )
+
 proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
   tags: [FReadDir].} =
   ## Returns True if both pathname arguments refer to the same physical
@@ -787,26 +808,8 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
   ## sym-linked paths to the same file or directory.
   when defined(Windows):
     var success = true
-
-    when useWinUnicode:
-      var p1 = newWideCString(path1)
-      var p2 = newWideCString(path2)
-      template openHandle(path: expr): expr =
-        createFileW(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or
-          FILE_SHARE_WRITE, nil, OPEN_EXISTING,
-          FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0)
-
-      var f1 = openHandle(p1)
-      var f2 = openHandle(p2)
-
-    else:
-      template openHandle(path: expr): expr =
-        createFileA(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or
-          FILE_SHARE_WRITE, nil, OPEN_EXISTING,
-          FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0)
-
-      var f1 = openHandle(path1)
-      var f2 = openHandle(path2)
+    var f1 = openHandle(path1)
+    var f2 = openHandle(path2)
 
     var lastErr: TOSErrorCode
     if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
@@ -1747,4 +1750,140 @@ proc expandTilde*(path: string): string =
   else:
     result = path
 
+when defined(Windows):
+  type
+    DeviceId = int32
+    FileId = int64
+else:
+  type
+    DeviceId = TDev
+    FileId = TIno
+
+type
+  FileInfo = object
+    ## Contains information associated with a file object.
+    id: tuple[device: DeviceId, file: FileId] # Device and file id.
+    kind: TPathComponent # Kind of file object - directory, symlink, etc.
+    size: BiggestInt # Size of file.
+    permissions: set[TFilePermission] # File permissions
+    linkCount: BiggestInt # Number of hard links the file object has.
+    lastAccessTime: TTime # Time file was last accessed.
+    lastWriteTime: TTime # Time file was last modified/written to.
+    creationTime: TTime # Time file was created. Not supported on all systems!
+
+template rawToFormalFileInfo(rawInfo, formalInfo): expr =
+  ## Transforms the native file info structure into the one nimrod uses.
+  ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
+  ## or a 'TStat' structure on posix
+  when defined(Windows):
+    template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
+    template merge(a, b): expr = a or (b shl 32)
+    formalInfo.id.device = rawInfo.dwVolumeSerialNumber
+    formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
+    formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
+    formalInfo.linkCount = rawInfo.nNumberOfLinks
+    formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
+    formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
+    formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
+    
+    # Retrieve basic permissions
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
+      formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec, 
+                                fpGroupRead, fpOthersExec, fpOthersRead}
+    else:
+      result.permissions = {fpUserExec..fpOthersRead}
+
+    # Retrieve basic file kind
+    result.kind = pcFile
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
+      formalInfo.kind = pcDir
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+      formalInfo.kind = succ(result.kind)
+
+  else:
+    template checkAndIncludeMode(rawMode, formalMode: expr) = 
+      if (rawInfo.st_mode and rawMode) != 0'i32:
+        formalInfo.permissions.incl(formalMode)
+    formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
+    formalInfo.size = rawInfo.st_size
+    formalInfo.linkCount = rawInfo.st_Nlink
+    formalInfo.lastAccessTime = rawInfo.st_atime
+    formalInfo.lastWriteTime = rawInfo.st_mtime
+    formalInfo.creationTime = rawInfo.st_ctime
+
+    result.permissions = {}
+    checkAndIncludeMode(S_IRUSR, fpUserRead)
+    checkAndIncludeMode(S_IWUSR, fpUserWrite)
+    checkAndIncludeMode(S_IXUSR, fpUserExec)
+
+    checkAndIncludeMode(S_IRGRP, fpGroupRead)
+    checkAndIncludeMode(S_IWGRP, fpGroupWrite)
+    checkAndIncludeMode(S_IXGRP, fpGroupExec)
+
+    checkAndIncludeMode(S_IROTH, fpOthersRead)
+    checkAndIncludeMode(S_IWOTH, fpOthersWrite)
+    checkAndIncludeMode(S_IXOTH, fpOthersExec)
+
+    formalInfo.kind = pcFile
+    if S_ISDIR(rawInfo.st_mode): formalInfo.kind = pcDir
+    if S_ISLNK(rawInfo.st_mode): formalInfo.kind.inc()
+
+proc getFileInfo*(handle: TFileHandle): FileInfo =
+  ## Retrieves file information for the file object represented by the given
+  ## handle.
+  ##
+  ## If the information cannot be retrieved, such as when the file handle
+  ## is invalid, an error will be thrown.
+  # Done: ID, Kind, Size, Permissions, Link Count
+  when defined(Windows):
+    var rawInfo: TBY_HANDLE_FILE_INFORMATION
+    # We have to use the super special '_get_osfhandle' call (wrapped above)
+    # To transform the C file descripter to a native file handle.
+    var realHandle = get_osfhandle(handle)
+    if getFileInformationByHandle(realHandle, addr rawInfo) == 0:
+      osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+  else:
+    var rawInfo: TStat
+    if fstat(handle, rawInfo) < 0'i32:
+      osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+
+proc getFileInfo*(file: TFile): FileInfo =
+  result = getFileInfo(file.fileHandle())
+
+proc getFileInfo*(path: string, followSymlink = true): FileInfo =
+  ## Retrieves file information for the file object pointed to by `path`.
+  ## 
+  ## Due to intrinsic differences between operating systems, the information
+  ## contained by the returned `FileInfo` structure will be slightly different
+  ## across platforms, and in some cases, incomplete or inaccurate.
+  ## 
+  ## When `followSymlink` is true, symlinks are followed and the information
+  ## retrieved is information related to the symlink's target. Otherwise,
+  ## information on the symlink itself is retrieved.
+  ## 
+  ## If the information cannot be retrieved, such as when the path doesn't
+  ## exist, or when permission restrictions prevent the program from retrieving
+  ## file information, an error will be thrown.
+  when defined(Windows):
+    var 
+      handle = openHandle(path, followSymlink)
+      rawInfo: TBY_HANDLE_FILE_INFORMATION
+    if handle == INVALID_HANDLE_VALUE:
+      osError(osLastError())
+    if getFileInformationByHandle(handle, addr rawInfo) == 0:
+      osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+    discard closeHandle(handle)
+  else:
+    var rawInfo: TStat
+    if followSymlink:
+      if lstat(path, rawInfo) < 0'i32:
+        osError(osLastError())
+    else:
+      if stat(path, rawInfo) < 0'i32:
+        osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+
 {.pop.}
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index eb9d2000b..4244bae4c 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -252,10 +252,8 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
 
 proc nimFloatToStr(x: float): string {.compilerproc.} =
   var buf: array [0..59, char]
-  c_sprintf(buf, "%#.f", x)
-  result = $buf
-  if result[len(result)-1] == '.':
-    result.add("0")
+  c_sprintf(buf, "%#.16e", x)
+  return $buf
 
 proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
   result = newString(sizeof(x)*4)
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 7024943b3..4ce2f11b4 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -581,6 +581,7 @@ const
   INVALID_FILE_SIZE* = -1'i32
 
   FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
+  FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'i32
 
 # Error Constants
 const
@@ -715,3 +716,6 @@ proc WSASend*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
   bytesSent: PDWord, flags: DWORD, lpOverlapped: POverlapped,
   completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
   stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
+
+proc get_osfhandle*(fd:TFileHandle): THandle {.
+  importc:"_get_osfhandle", header:"<io.h>".}
diff --git a/tests/closure/tclosuremacro.nim b/tests/closure/tclosuremacro.nim
index 008078bbb..12e463316 100644
--- a/tests/closure/tclosuremacro.nim
+++ b/tests/closure/tclosuremacro.nim
@@ -5,6 +5,7 @@ discard """
 3
 3
 noReturn
+6
 '''
 """
 
@@ -36,8 +37,7 @@ echo doWithOneAndTwo((x, y) => x + y)
 
 noReturn(() -> void => echo("noReturn"))
 
-when false:
-  proc pass2(f: (int, int) -> int): (int) -> int =
-    (x: int) -> int => f(2, x)
+proc pass2(f: (int, int) -> int): (int) -> int =
+  (x: int) -> int => f(2, x)
 
-  #echo pass2((x, y) => x + y)
+echo pass2((x, y) => x + y)(4)
diff --git a/tests/macros/texprcolonexpr.nim b/tests/macros/texprcolonexpr.nim
new file mode 100644
index 000000000..3b2c86b77
--- /dev/null
+++ b/tests/macros/texprcolonexpr.nim
@@ -0,0 +1,19 @@
+discard """
+  msg: '''
+Infix
+  Ident !"=>"
+  Call
+    Ident !"name"
+    Ident !"a"
+    ExprColonExpr
+      Ident !"b"
+      Ident !"cint"
+  NilLit nil
+'''
+"""
+import macros
+
+macro def(x: stmt): stmt {.immediate.} =
+  echo treeRepr(x)
+
+def name(a, b:cint) => nil
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
new file mode 100644
index 000000000..49a019061
--- /dev/null
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -0,0 +1,93 @@
+discard """
+  output: ""
+"""
+
+import os, strutils
+# Cases
+#  1 - String : Existing File : Symlink true
+#  2 - String : Existing File : Symlink false
+#  3 - String : Non-existing File : Symlink true
+#  4 - String : Non-existing File : Symlink false
+#  5 - Handle : Valid File
+#  6 - Handle : Invalid File
+#  7 - Handle : Valid Handle
+#  8 - Handle : Invalid Handle
+
+proc genBadFileName(limit = 100): string =
+    ## Generates a filename of a nonexistant file.
+    ## Returns "" if generation fails.
+    result = "a"
+    var hitLimit = true
+
+    for i in 0..100:
+      if existsFile(result):
+        result.add("a")
+      else:
+        hitLimit = false
+        break
+    if hitLimit:
+      result = ""
+
+proc caseOneAndTwo(followLink: bool) =
+  try:
+    discard getFileInfo(getAppFilename(), followLink)
+    #echo("String : Existing File : Symlink $# : Success" % $followLink)
+  except EOS:
+    echo("String : Existing File : Symlink $# : Failure" % $followLink)
+
+proc caseThreeAndFour(followLink: bool) =
+  var invalidName = genBadFileName()
+  try:
+    discard getFileInfo(invalidName, true)
+    echo("String : Non-existing File : Symlink $# : Failure" % $followLink)
+  except EOS:
+    #echo("String : Non-existing File : Symlink $# : Success" % $followLink)
+
+proc testGetFileInfo =
+  # Case 1
+  caseOneAndTwo(true)
+
+  # Case 2
+  caseOneAndTwo(false)
+
+  # Case 3
+  caseThreeAndFour(true)
+
+  # Case 4
+  caseThreeAndFour(false)
+
+  # Case 5 and 7
+  block:
+    let
+      testFile = open(getAppFilename())
+      testHandle = fileHandle(testFile)
+    try:
+      discard getFileInfo(testFile)
+      #echo("Handle : Valid File : Success")
+    except EIO:
+      echo("Handle : Valid File : Failure")
+
+    try:
+      discard getFileInfo(testHandle)
+      #echo("Handle : Valid File : Success")
+    except EIO:
+      echo("Handle : Valid File : Failure")
+
+  # Case 6 and 8
+  block:
+    let
+      testFile: TFile = nil
+      testHandle = TFileHandle(-1)
+    try:
+      discard getFileInfo(testFile)
+      echo("Handle : Invalid File : Failure")
+    except EIO, EOS:
+      #echo("Handle : Invalid File : Success")
+
+    try:
+      discard getFileInfo(testHandle)
+      echo("Handle : Invalid File : Failure")
+    except EIO, EOS:
+      #echo("Handle : Invalid File : Success")
+
+testGetFileInfo()
\ No newline at end of file
diff --git a/tests/system/tsysspawnbadarg.nim b/tests/system/tsysspawnbadarg.nim
new file mode 100644
index 000000000..ace074602
--- /dev/null
+++ b/tests/system/tsysspawnbadarg.nim
@@ -0,0 +1,7 @@
+discard """
+  line: 7
+  errormsg: "'spawn' takes a call expression of type void"
+  cmd: "nimrod $target --threads:on $options $file"
+"""
+
+spawn(1)