summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/vm.nim2
-rw-r--r--compiler/vmgen.nim15
-rw-r--r--compiler/wordrecg.nim2
-rw-r--r--doc/manual/pragmas.txt18
-rw-r--r--examples/curlex.nim10
-rw-r--r--examples/iupex1.nim37
-rw-r--r--lib/pure/streams.nim11
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/alloc.nim11
-rw-r--r--tests/pragmas/tbitsize.nim22
-rw-r--r--tests/stdlib/tmemfiles2.nim2
-rw-r--r--tests/testament/categories.nim4
-rw-r--r--tests/testament/tester.nim6
-rw-r--r--tests/vm/tsimpleglobals.nim16
-rw-r--r--tests/vm/twrongconst.nim2
-rw-r--r--web/news.txt2
19 files changed, 104 insertions, 68 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 4001e896e..25958f580 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -784,6 +784,7 @@ type
       tab*: TStrTable         # interface table for modules
     of skLet, skVar, skField, skForVar:
       guard*: PSym
+      bitsize*: int
     else: nil
     magic*: TMagic
     typ*: PType
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 84d02d1da..1ed9ce113 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -441,6 +441,8 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
       elif fieldType.kind == tySequence:
         # we need to use a weak dependency here for trecursive_table.
         addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+      elif field.bitsize != 0:
+        addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
       else:
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1c51251fe..ba05b2792 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -56,7 +56,7 @@ const
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
     wBorrow, wGcSafe}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
-    wImportCpp, wImportObjC, wError, wGuard}
+    wImportCpp, wImportObjC, wError, wGuard, wBitsize}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
     wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
     wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
@@ -844,6 +844,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         if sym == nil: pragmaLockStmt(c, it)
         elif sym.typ == nil: invalidPragma(it)
         else: sym.typ.lockLevel = pragmaLocks(c, it)
+      of wBitsize:
+        if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr:
+          invalidPragma(it)
+        else:
+          sym.bitsize = expectIntLit(c, it)
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
           invalidPragma(it)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 4dd3b5232..ad4aa1017 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -311,7 +311,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
           if f.position == x:
             dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
             return
-        internalError("opConv for enum")
+        dest.node.strVal = styp.sym.name.s & " " & $x
     of tyInt..tyInt64:
       dest.node.strVal = $src.intVal
     of tyUInt..tyUInt64:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 0559acc88..92db0d513 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -37,7 +37,7 @@ when hasFFI:
   import evalffi
 
 type
-  TGenFlag = enum gfNone, gfAddrOf
+  TGenFlag = enum gfAddrOf, gfFieldAccess
   TGenFlags = set[TGenFlag]
 
 proc debugInfo(info: TLineInfo): string =
@@ -535,7 +535,7 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     c.gABC(le, opcWrArr, dest, idx, value)
     c.freeTemp(dest)
@@ -543,7 +543,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = genField(left.sons[1])
     c.gABC(left, opcWrObj, dest, idx, value)
     c.freeTemp(dest)
@@ -1216,7 +1216,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     let tmp = c.genx(ri)
     if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
@@ -1228,7 +1228,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = genField(left.sons[1])
     let tmp = c.genx(ri)
     c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
@@ -1321,7 +1321,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
       c.gABx(n, opcLdGlobal, cc, s.position)
       c.gABC(n, opcNodeToReg, dest, cc)
       c.freeTemp(cc)
-    elif gfAddrOf in flags:
+    elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}:
       c.gABx(n, opcLdGlobalAddr, dest, s.position)
     else:
       c.gABx(n, opcLdGlobal, dest, s.position)
@@ -1773,6 +1773,9 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
     d = 0
   c.gABC(n, opcEof, d)
 
+  #echo renderTree(n)
+  #c.echoCode(result)
+
 proc genParams(c: PCtx; params: PNode) =
   # res.sym.position is already 0
   c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 23f012ea5..d1e5438f3 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -82,6 +82,7 @@ type
     wStdIn, wStdOut, wStdErr,
 
     wInOut, wByCopy, wByRef, wOneWay,
+    wBitsize,
 
   TSpecialWords* = set[TSpecialWord]
 
@@ -168,6 +169,7 @@ const
     "stdin", "stdout", "stderr",
 
     "inout", "bycopy", "byref", "oneway",
+    "bitsize",
     ]
 
 proc findStr*(a: openArray[string], s: string): int =
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
index 68a88f865..f89194c9a 100644
--- a/doc/manual/pragmas.txt
+++ b/doc/manual/pragmas.txt
@@ -531,6 +531,24 @@ Implementation Specific Pragmas
 This section describes additional pragmas that the current Nim implementation
 supports but which should not be seen as part of the language specification.
 
+Bitsize pragma
+--------------
+
+The ``bitsize`` pragma is for object field members. It declares the field as
+a bitfield in C/C++.
+
+.. code-block:: Nim
+  type
+    mybitfield = object
+      flag {.bitsize:1.}: cuint
+
+generates:
+
+.. code-block:: C
+  struct mybitfield {
+    unsigned int flag:1;
+  };
+
 
 Volatile pragma
 ---------------
diff --git a/examples/curlex.nim b/examples/curlex.nim
deleted file mode 100644
index 21786a6ee..000000000
--- a/examples/curlex.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-import
-  libcurl
-
-var hCurl = easy_init()
-if hCurl != nil:
-  discard easy_setopt(hCurl, OPT_VERBOSE, true)
-  discard easy_setopt(hCurl, OPT_URL, "http://nim-lang.org/")
-  discard easy_perform(hCurl)
-  easy_cleanup(hCurl)
-
diff --git a/examples/iupex1.nim b/examples/iupex1.nim
deleted file mode 100644
index f768fb23f..000000000
--- a/examples/iupex1.nim
+++ /dev/null
@@ -1,37 +0,0 @@
-# Example IUP program
-
-# iupTabs: Creates a iupTabs control.
-
-import iup
-
-discard iup.open(nil, nil)
-
-var vbox1 = iup.vbox(iup.label("Inside Tab A"), iup.button("Button A", ""), nil)
-var vbox2 = iup.vbox(iup.label("Inside Tab B"), iup.button("Button B", ""), nil)
-
-iup.setAttribute(vbox1, "TABTITLE", "Tab A")
-iup.setAttribute(vbox2, "TABTITLE", "Tab B")
-
-var tabs1 = iup.tabs(vbox1, vbox2, nil)
-
-vbox1 = iup.vbox(iup.label("Inside Tab C"), iup.button("Button C", ""), nil)
-vbox2 = iup.vbox(iup.label("Inside Tab D"), iup.button("Button D", ""), nil)
-
-iup.setAttribute(vbox1, "TABTITLE", "Tab C")
-iup.setAttribute(vbox2, "TABTITLE", "Tab D")
-
-var tabs2 = iup.tabs(vbox1, vbox2, nil)
-iup.setAttribute(tabs2, "TABTYPE", "LEFT")
-
-var box = iup.hbox(tabs1, tabs2, nil)
-iup.setAttribute(box, "MARGIN", "10x10")
-iup.setAttribute(box, "GAP", "10")
-
-var dlg = iup.dialog(box)
-iup.setAttribute(dlg, "TITLE", "iupTabs")
-iup.setAttribute(dlg, "SIZE", "200x100")
-
-discard showXY(dlg, IUP_CENTER, IUP_CENTER)
-discard mainLoop()
-close()
-
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 68f31e9fe..38e91fee4 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -103,15 +103,16 @@ proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
 
 proc readAll*(s: Stream): string =
   ## Reads all available data.
-  result = newString(1000)
+  const bufferSize = 1000
+  result = newString(bufferSize)
   var r = 0
   while true:
-    let readBytes = readData(s, addr(result[r]), 1000)
-    if readBytes < 1000:
+    let readBytes = readData(s, addr(result[r]), bufferSize)
+    if readBytes < bufferSize:
       setLen(result, r+readBytes)
       break
-    inc r, 1000
-    setLen(result, r+1000)
+    inc r, bufferSize
+    setLen(result, r+bufferSize)
 
 proc readData*(s, unused: Stream, buffer: pointer,
                bufLen: int): int {.deprecated.} =
diff --git a/lib/system.nim b/lib/system.nim
index 59d0d04b7..1d2ca6a9a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1256,7 +1256,7 @@ proc compileOption*(option, arg: string): bool {.
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
-  hasThreadSupport = compileOption("threads")
+  hasThreadSupport = compileOption("threads") and not defined(nimscript)
   hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
   taintMode = compileOption("taintmode")
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 13a10e46f..3a1d7b666 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -27,8 +27,11 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
 # some platforms have really weird unmap behaviour: unmap(blockStart, PageSize)
 # really frees the whole block. Happens for Linux/PowerPC for example. Amd64
 # and x86 are safe though; Windows is special because MEM_RELEASE can only be
-# used with a size of 0:
-const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
+# used with a size of 0. We also allow unmapping to be turned off with
+# -d:nimAllocNoUnmap:
+const doNotUnmap = not (defined(amd64) or defined(i386)) or
+                   defined(windows) or defined(nimAllocNoUnmap)
+
 
 when defined(posix):
   const
@@ -478,7 +481,7 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
           excl(a.chunkStarts, pageIndex(c))
           c = cast[PBigChunk](le)
 
-  if c.size < ChunkOsReturn or weirdUnmap:
+  if c.size < ChunkOsReturn or doNotUnmap:
     incl(a, a.chunkStarts, pageIndex(c))
     updatePrevSize(a, c, c.size)
     listAdd(a.freeChunksList, c)
@@ -762,7 +765,7 @@ proc deallocOsPages(a: var MemRegion) =
   # we free every 'ordinarily' allocated page by iterating over the page bits:
   for p in elements(a.chunkStarts):
     var page = cast[PChunk](p shl PageShift)
-    when not weirdUnmap:
+    when not doNotUnmap:
       var size = if page.size < PageSize: PageSize else: page.size
       osDeallocPages(page, size)
     else:
diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim
new file mode 100644
index 000000000..7a44944d2
--- /dev/null
+++ b/tests/pragmas/tbitsize.nim
@@ -0,0 +1,22 @@
+discard """
+ccodeCheck: "\\i @'unsigned int flag:1;' .*"
+"""
+
+type
+  bits* = object
+    flag* {.bitsize: 1.}: cuint
+    opts* {.bitsize: 4.}: cint
+
+var
+  b: bits
+
+assert b.flag == 0
+b.flag = 1
+assert b.flag == 1
+b.flag = 2
+assert b.flag == 0
+
+b.opts = 7
+assert b.opts == 7
+b.opts = 9
+assert b.opts == -7
diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim
index 28af3296a..026443e93 100644
--- a/tests/stdlib/tmemfiles2.nim
+++ b/tests/stdlib/tmemfiles2.nim
@@ -1,8 +1,10 @@
 discard """
   file: "tmemfiles2.nim"
+  disabled: true
   output: '''Full read size: 20
 Half read size: 10 Data: Hello'''
 """
+# doesn't work on windows. fmReadWrite doesn't create a file.
 import memfiles, os
 var
   mm, mm_full, mm_half: MemFile
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 4de1edeee..afc4a616f 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -339,7 +339,7 @@ proc `&?.`(a, b: string): string =
   # candidate for the stdlib?
   result = if a.endswith(b): a else: a & b
 
-proc processCategory(r: var TResults, cat: Category, options: string) =
+proc processCategory(r: var TResults, cat: Category, options: string, fileGlob: string = "t*.nim") =
   case cat.string.normalize
   of "rodfiles":
     discard # Disabled for now
@@ -376,5 +376,5 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
   of "nimble-all":
     testNimblePackages(r, cat, pfAll)
   else:
-    for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
+    for name in os.walkFiles("tests" & DirSep &.? cat.string / fileGlob):
       testSpec r, makeTest(name, options, cat)
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index b138c9909..3961f15c4 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -23,6 +23,7 @@ const
 Command:
   all                         run all tests
   c|category <category>       run all the tests of a certain category
+  r|run <test>                run single test file
   html [commit]               generate $1 from the database; uses the latest
                               commit or a specific one (use -1 for the commit
                               before latest etc)
@@ -376,6 +377,11 @@ proc main() =
     var cat = Category(p.key)
     p.next
     processCategory(r, cat, p.cmdLineRest.string)
+  of "r", "run":
+    let (dir, file) = splitPath(p.key.string)
+    let (_, subdir) = splitPath(dir)
+    var cat = Category(subdir)
+    processCategory(r, cat, p.cmdLineRest.string, file)
   of "html":
     var commit = 0
     discard parseInt(p.cmdLineRest.string, commit)
diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim
new file mode 100644
index 000000000..27bfdce50
--- /dev/null
+++ b/tests/vm/tsimpleglobals.nim
@@ -0,0 +1,16 @@
+discard """
+  msg: "abc xyz bb"
+"""
+
+# bug #2473
+type
+  Test = tuple[a,b: string]
+
+static:
+  var s:seq[Test] = @[(a:"a", b:"b")]
+  s[0] = (a:"aa", b:"bb")
+
+  var x: Test
+  x.a = "abc"
+  x.b = "xyz"
+  echo x.a, " ", x.b, " ", s[0].b
diff --git a/tests/vm/twrongconst.nim b/tests/vm/twrongconst.nim
index 68ab2757c..424ed080e 100644
--- a/tests/vm/twrongconst.nim
+++ b/tests/vm/twrongconst.nim
@@ -1,6 +1,6 @@
 discard """
   errormsg: "cannot evaluate at compile time: x"
-  line: 9
+  line: 7
 """
 
 var x: array[100, char]
diff --git a/web/news.txt b/web/news.txt
index cfa40c65c..33ceac49e 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -108,6 +108,8 @@ News
   - The compiler finally considers symbol binding rules in templates and
     generics for overloaded ``[]``, ``[]=``, ``{}``, ``{}=`` operators
     (issue `#2599 <https://github.com/nim-lang/Nim/issues/2599>`_).
+  - The compiler now supports a `bitsize pragma <docs/manual.html#pragmas-bitsize-pragma>`_
+    for constructing bitfields.
 
 
   Language Additions