summary refs log tree commit diff stats
path: root/lib/core
diff options
context:
space:
mode:
authorDaniil Yarancev <21169548+Yardanico@users.noreply.github.com>2018-01-07 21:02:00 +0300
committerGitHub <noreply@github.com>2018-01-07 21:02:00 +0300
commitfb44c522e6173528efa8035ecc459c84887d0167 (patch)
treea2f5e98606be265981a5f72748896967033e23d7 /lib/core
parentccf99fa5ce4fe992fb80dc89271faa51456c3fa5 (diff)
parente23ea64c41e101d4e1d933f0b015f51cc6c2f7de (diff)
downloadNim-fb44c522e6173528efa8035ecc459c84887d0167.tar.gz
Merge pull request #1 from nim-lang/devel
upstream
Diffstat (limited to 'lib/core')
-rw-r--r--lib/core/allocators.nim35
-rw-r--r--lib/core/macros.nim121
-rw-r--r--lib/core/refs.nim97
-rw-r--r--lib/core/seqs.nim117
-rw-r--r--lib/core/strs.nim111
-rw-r--r--lib/core/typelayouts.nim19
6 files changed, 475 insertions, 25 deletions
diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim
new file mode 100644
index 000000000..d6608a203
--- /dev/null
+++ b/lib/core/allocators.nim
@@ -0,0 +1,35 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type
+  Allocator* {.inheritable.} = ptr object
+    alloc*: proc (a: Allocator; size: int; alignment = 8): pointer {.nimcall.}
+    dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.}
+    realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.}
+
+var
+  currentAllocator {.threadvar.}: Allocator
+
+proc getCurrentAllocator*(): Allocator =
+  result = currentAllocator
+
+proc setCurrentAllocator*(a: Allocator) =
+  currentAllocator = a
+
+proc alloc*(size: int): pointer =
+  let a = getCurrentAllocator()
+  result = a.alloc(a, size)
+
+proc dealloc*(p: pointer; size: int) =
+  let a = getCurrentAllocator()
+  a.dealloc(a, size)
+
+proc realloc*(p: pointer; oldSize, newSize: int): pointer =
+  let a = getCurrentAllocator()
+  result = a.realloc(a, oldSize, newSize)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 8c70d2b47..b08a2198e 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -21,7 +21,7 @@ type
     nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
     nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
     nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
-    nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
+    nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
     nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
     nnkPrefix, nnkPostfix, nnkHiddenCallConv,
     nnkExprEqExpr,
@@ -113,7 +113,9 @@ type
 
 type
   NimIdent* = object of RootObj
-    ## represents a Nim identifier in the AST
+    ## represents a Nim identifier in the AST. **Note**: This is only
+    ## rarely useful, for identifier construction from a string
+    ## use ``ident"abc"``.
 
   NimSymObj = object # hidden
   NimSym* = ref NimSymObj
@@ -129,14 +131,11 @@ const
   nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
                    nnkCallStrLit}
 
-proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
-  ## get `n`'s `i`'th child.
-
-proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
-  noSideEffect.}
-  ## set `n`'s `i`'th child to `child`.
+proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated.}
+  ## constructs an identifier from the string `s`
+  ## **Deprecated since version 0.18.0**: Use ``toNimIdent`` instead.
 
-proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
+proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
   ## constructs an identifier from the string `s`
 
 proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
@@ -162,6 +161,20 @@ proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
 proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
   ## returns the number of children of `n`.
 
+proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
+  ## get `n`'s `i`'th child.
+
+proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
+  ## get `n`'s `i`'th child.
+
+proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
+  noSideEffect.}
+  ## set `n`'s `i`'th child to `child`.
+
+proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
+  ## set `n`'s `i`'th child to `child`.
+  n[n.len - i.int] = child
+
 proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
   noSideEffect, locks: 0.}
   ## Adds the `child` to the `father` node. Returns the
@@ -230,7 +243,7 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
 proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
 
 proc newNimNode*(kind: NimNodeKind,
-                 lineInfoFrom: NimNode=nil): NimNode
+                 lineInfoFrom: NimNode = nil): NimNode
   {.magic: "NNewNimNode", noSideEffect.}
   ## Creates a new AST node of the specified kind.
   ##
@@ -283,7 +296,7 @@ proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} =
 proc newIdentNode*(i: string): NimNode {.compileTime.} =
   ## creates an identifier node from `i`
   result = newNimNode(nnkIdent)
-  result.ident = !i
+  result.ident = toNimIdent i
 
 
 type
@@ -393,7 +406,7 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
   ##
   ## .. code-block:: nim
   ##
-  ##   macro check(ex: expr): stmt =
+  ##   macro check(ex: untyped): typed =
   ##     # this is a simplified version of the check macro from the
   ##     # unittest module.
   ##
@@ -428,6 +441,13 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} =
   ## macros that check its number of arguments.
   if n.len != len: error("macro expects a node with " & $len & " children", n)
 
+proc expectLen*(n: NimNode, min, max: int) {.compileTime.} =
+  ## checks that `n` has a number of children in the range ``min..max``.
+  ## If this is not the case, compilation aborts with an error message.
+  ## This is useful for writing macros that check its number of arguments.
+  if n.len < min or n.len > max:
+    error("macro expects a node with " & $min & ".." & $max " children", n)
+
 proc newTree*(kind: NimNodeKind,
               children: varargs[NimNode]): NimNode {.compileTime.} =
   ## produces a new node with children.
@@ -463,7 +483,6 @@ proc newLit*(c: char): NimNode {.compileTime.} =
   result = newNimNode(nnkCharLit)
   result.intVal = ord(c)
 
-
 proc newLit*(i: int): NimNode {.compileTime.} =
   ## produces a new integer literal node.
   result = newNimNode(nnkIntLit)
@@ -567,7 +586,7 @@ proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} =
 proc newLit*(arg: tuple): NimNode {.compileTime.} =
   result = nnkPar.newTree
   for a,b in arg.fieldPairs:
-    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+    result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b))
 
 proc newLit*(s: string): NimNode {.compileTime.} =
   ## produces a new string literal node.
@@ -601,7 +620,7 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
     of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
     of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
-    of nnkIdent: res.add(" !\"" & $n.ident & '"')
+    of nnkIdent: res.add(" ident\"" & $n.ident & '"')
     of nnkSym: res.add(" \"" & $n.symbol & '"')
     of nnkNone: assert false
     else:
@@ -626,7 +645,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
   of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
   of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
-  of nnkIdent: add(result, "!\"" & $n.ident & '"')
+  of nnkIdent: add(result, "ident\"" & $n.ident & '"')
   of nnkSym: add(result, $n.symbol)
   of nnkNone: assert false
   else:
@@ -650,7 +669,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
   ## .. code-block:: nim
   ##   nnkStmtList.newTree(
   ##     nnkCommand.newTree(
-  ##       newIdentNode(!"echo"),
+  ##       newIdentNode("echo"),
   ##       newLit("Hello world")
   ##     )
   ##   )
@@ -704,7 +723,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
     of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
     of nnkStrLit..nnkTripleStrLit: res.add($n.strVal.escape())
-    of nnkIdent: res.add("!" & ($n.ident).escape())
+    of nnkIdent: res.add(($n.ident).escape())
     of nnkSym: res.add(($n.symbol).escape())
     of nnkNone: assert false
     else:
@@ -839,7 +858,7 @@ proc newNilLit*(): NimNode {.compileTime.} =
   ## New nil literal shortcut
   result = newNimNode(nnkNilLit)
 
-proc last*(node: NimNode): NimNode {.compileTime.} = node[<node.len]
+proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1]
   ## Return the last item in nodes children. Same as `node[^1]`
 
 
@@ -884,10 +903,52 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
   for i in branches:
     result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
 
+proc newEnum*(name: NimNode, fields: openArray[NimNode],
+              public, pure: bool): NimNode {.compileTime.} =
+
+  ## Creates a new enum. `name` must be an ident. Fields are allowed to be
+  ## either idents or EnumFieldDef
+  ##
+  ## .. code-block:: nim
+  ##
+  ##    newEnum(
+  ##      name    = ident("Colors"),
+  ##      fields  = [ident("Blue"), ident("Red")],
+  ##      public  = true, pure = false)
+  ##
+  ##    # type Colors* = Blue Red
+  ##
+
+  expectKind name, nnkIdent
+  doAssert len(fields) > 0, "Enum must contain at least one field"
+  for field in fields:
+    expectKind field, {nnkIdent, nnkEnumFieldDef}
+
+  let enumBody = newNimNode(nnkEnumTy).add(newEmptyNode()).add(fields)
+  var typeDefArgs = [name, newEmptyNode(), enumBody]
+
+  if public:
+    let postNode = newNimNode(nnkPostfix).add(
+      newIdentNode("*"), typeDefArgs[0])
+
+    typeDefArgs[0] = postNode
+
+  if pure:
+    let pragmaNode = newNimNode(nnkPragmaExpr).add(
+      typeDefArgs[0],
+      add(newNimNode(nnkPragma), newIdentNode("pure")))
+
+    typeDefArgs[0] = pragmaNode
+
+  let
+    typeDef   = add(newNimNode(nnkTypeDef), typeDefArgs)
+    typeSect  = add(newNimNode(nnkTypeSection), typeDef)
+
+  return typeSect
 
 proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
   ## Copy all children from `src` to `dest`
-  for i in 0 .. < src.len:
+  for i in 0 ..< src.len:
     dest.add src[i].copyNimTree
 
 template expectRoutine(node: NimNode) =
@@ -986,6 +1047,11 @@ iterator items*(n: NimNode): NimNode {.inline.} =
   for i in 0 ..< n.len:
     yield n[i]
 
+iterator pairs*(n: NimNode): (int, NimNode) {.inline.} =
+  ## Iterates over the children of the NimNode ``n`` and its indices.
+  for i in 0 ..< n.len:
+    yield (i, n[i])
+
 iterator children*(n: NimNode): NimNode {.inline.} =
   ## Iterates over the children of the NimNode ``n``.
   for i in 0 ..< n.len:
@@ -996,7 +1062,7 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} =
   ##
   ## .. code-block:: nim
   ##   var res = findChild(n, it.kind == nnkPostfix and
-  ##                          it.basename.ident == !"foo")
+  ##                          it.basename.ident == toNimIdent"foo")
   block:
     var res: NimNode
     for it in n.children:
@@ -1030,7 +1096,7 @@ proc basename*(a: NimNode): NimNode =
 
 proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
   case a.kind
-  of nnkIdent: macros.`ident=`(a,  !val)
+  of nnkIdent: macros.`ident=`(a, toNimIdent val)
   of nnkPostfix, nnkPrefix: a[1] = ident(val)
   else:
     quit "Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a)
@@ -1091,7 +1157,7 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
   ## other ways like ``node.ident`` are much more error-prone, unfortunately.
   case node.kind
   of nnkIdent:
-    result = node.ident == !s
+    result = node.ident == toNimIdent s
   of nnkSym:
     result = eqIdent($node.symbol, s)
   of nnkOpenSymChoice, nnkClosedSymChoice:
@@ -1099,10 +1165,10 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
   else:
     result = false
 
-proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
+proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}=
   ## Search nnkFormalParams for an argument.
   assert params.kind == nnkFormalParams
-  for i in 1 .. <params.len:
+  for i in 1 ..< params.len:
     template node: untyped = params[i]
     if name.eqIdent( $ node[0]):
       return true
@@ -1160,3 +1226,8 @@ when not defined(booting):
     macro payload: untyped {.gensym.} =
       result = parseStmt(e)
     payload()
+
+macro unpackVarargs*(callee: untyped; args: varargs[untyped]): untyped =
+  result = newCall(callee)
+  for i in 0 ..< args.len:
+    result.add args[i]
diff --git a/lib/core/refs.nim b/lib/core/refs.nim
new file mode 100644
index 000000000..e1575b68c
--- /dev/null
+++ b/lib/core/refs.nim
@@ -0,0 +1,97 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Default ref implementation used by Nim's core.
+
+# We cannot use the allocator interface here as we require a heap walker to
+# exist. Thus we import 'alloc' directly here to get our own heap that is
+# all under the GC's control and can use the ``allObjects`` iterator which
+# is crucial for the "sweep" phase.
+import typelayouts, alloc
+
+type
+  TracingGc = ptr object of Allocator
+    visit*: proc (fieldAddr: ptr pointer; a: Allocator) {.nimcall.}
+
+  GcColor = enum
+    white = 0, black = 1, grey = 2 ## to flip the meaning of white/black
+                                   ## perform (1 - col)
+
+  GcHeader = object
+    t: ptr TypeLayout
+    color: GcColor
+  Cell = ptr GcHeader
+
+  GcFrame {.core.} = object
+    prev: ptr GcFrame
+    marker: proc (self: GcFrame; a: Allocator)
+
+  Phase = enum
+    None, Marking, Sweeping
+
+  GcHeap = object
+    r: MemRegion
+    phase: Phase
+    currBlack, currWhite: GcColor
+    greyStack: seq[Cell]
+
+var
+  gch {.threadvar.}: GcHeap
+
+proc `=trace`[T](a: ref T) =
+  if not marked(a):
+    mark(a)
+    `=trace`(a[])
+
+template usrToCell(p: pointer): Cell =
+
+template cellToUsr(cell: Cell): pointer =
+  cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(GcHeader)))
+
+template usrToCell(usr: pointer): Cell =
+  cast[Cell](cast[ByteAddress](usr)-%ByteAddress(sizeof(GcHeader)))
+
+template markGrey(x: Cell) =
+  if x.color == gch.currWhite and phase == Marking:
+    x.color = grey
+    add(gch.greyStack, x)
+
+proc `=`[T](dest: var ref T; src: ref T) =
+  ## full write barrier implementation.
+  if src != nil:
+    let s = usrToCell(src)
+    markGrey(s)
+  system.`=`(dest, src)
+
+proc linkGcFrame(f: ptr GcFrame) {.core.}
+proc unlinkGcFrame() {.core.}
+
+proc setGcFrame(f: ptr GcFrame) {.core.}
+
+proc registerGlobal(p: pointer; t: ptr TypeLayout) {.core.}
+proc unregisterGlobal(p: pointer; t: ptr TypeLayout) {.core.}
+
+proc registerThreadvar(p: pointer; t: ptr TypeLayout) {.core.}
+proc unregisterThreadvar(p: pointer; t: ptr TypeLayout) {.core.}
+
+proc newImpl(t: ptr TypeLayout): pointer =
+  let r = cast[Cell](rawAlloc(t.size + sizeof(GcHeader)))
+  r.typ = t
+  result = r +! sizeof(GcHeader)
+
+template new*[T](x: var ref T) =
+  x = newImpl(getTypeLayout(x))
+
+
+when false:
+  # implement these if your GC requires them:
+  proc writeBarrierLocal() {.core.}
+  proc writeBarrierGlobal() {.core.}
+
+  proc writeBarrierGeneric() {.core.}
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
new file mode 100644
index 000000000..6be95a3bc
--- /dev/null
+++ b/lib/core/seqs.nim
@@ -0,0 +1,117 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import allocators
+
+## Default seq implementation used by Nim's core.
+type
+  seq*[T] = object
+    len, cap: int
+    data: ptr UncheckedArray[T]
+
+template frees(s) = dealloc(s.data, s.cap * sizeof(T))
+
+# XXX make code memory safe for overflows in '*'
+proc nimSeqLiteral[T](x: openArray[T]): seq[T] {.core.} =
+  seq[T](len: x.len, cap: x.len, data: x)
+
+when defined(nimHasTrace):
+  proc `=trace`[T](s: seq[T]; a: Allocator) =
+    for i in 0 ..< s.len: `=trace`(s.data[i], a)
+
+proc `=destroy`[T](x: var seq[T]) =
+  if x.data != nil:
+    when not supportsCopyMem(T):
+      for i in 0..<x.len: `=destroy`(x[i])
+    frees(x)
+    x.data = nil
+    x.len = 0
+    x.cap = 0
+
+proc `=`[T](a: var seq[T]; b: seq[T]) =
+  if a.data == b.data: return
+  if a.data != nil:
+    frees(a)
+    a.data = nil
+  a.len = b.len
+  a.cap = b.cap
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.cap * sizeof(T)))
+    when supportsCopyMem(T):
+      copyMem(a.data, b.data, a.cap * sizeof(T))
+    else:
+      for i in 0..<a.len:
+        a.data[i] = b.data[i]
+
+proc `=sink`[T](a: var seq[T]; b: seq[T]) =
+  if a.data != nil and a.data != b.data:
+    frees(a)
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc resize[T](s: var seq[T]) =
+  let old = s.cap
+  if old == 0: s.cap = 8
+  else: s.cap = (s.cap * 3) shr 1
+  s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T)))
+
+proc reserveSlot[T](x: var seq[T]): ptr T =
+  if x.len >= x.cap: resize(x)
+  result = addr(x.data[x.len])
+  inc x.len
+
+template add*[T](x: var seq[T]; y: T) =
+  reserveSlot(x)[] = y
+
+proc shrink*[T](x: var seq[T]; newLen: int) =
+  assert newLen <= x.len
+  assert newLen >= 0
+  when not supportsCopyMem(T):
+    for i in countdown(x.len - 1, newLen - 1):
+      `=destroy`(x.data[i])
+  x.len = newLen
+
+proc grow*[T](x: var seq[T]; newLen: int; value: T) =
+  if newLen <= x.len: return
+  assert newLen >= 0
+  if x.cap == 0: x.cap = newLen
+  else: x.cap = max(newLen, (x.cap * 3) shr 1)
+  x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T)))
+  for i in x.len..<newLen:
+    x.data[i] = value
+  x.len = newLen
+
+template default[T](t: typedesc[T]): T =
+  var v: T
+  v
+
+proc setLen*[T](x: var seq[T]; newLen: int) {.deprecated.} =
+  if newlen < x.len: shrink(x, newLen)
+  else: grow(x, newLen, default(T))
+
+template `[]`*[T](x: seq[T]; i: Natural): T =
+  assert i < x.len
+  x.data[i]
+
+template `[]=`*[T](x: seq[T]; i: Natural; y: T) =
+  assert i < x.len
+  x.data[i] = y
+
+proc `@`*[T](elems: openArray[T]): seq[T] =
+  result.cap = elems.len
+  result.len = elems.len
+  result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
+  when supportsCopyMem(T):
+    copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T))
+  else:
+    for i in 0..<result.len:
+      result.data[i] = elems[i]
+
+proc len*[T](x: seq[T]): int {.inline.} = x.len
diff --git a/lib/core/strs.nim b/lib/core/strs.nim
new file mode 100644
index 000000000..1958f4974
--- /dev/null
+++ b/lib/core/strs.nim
@@ -0,0 +1,111 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Default string implementation used by Nim's core.
+
+import allocators
+
+type
+  string {.core.} = object
+    len, cap: int
+    data: ptr UncheckedArray[char]
+
+proc nimStringLiteral(x: cstring; len: int): string {.core.} =
+  string(len: len, cap: len, data: x)
+
+template frees(s) = dealloc(s.data, s.cap + 1)
+
+proc `=destroy`(s: var string) =
+  if s.data != nil:
+    frees(s)
+    s.data = nil
+    s.len = 0
+    s.cap = 0
+
+proc `=sink`(a: var string, b: string) =
+  # we hope this is optimized away for not yet alive objects:
+  if a.data != nil and a.data != b.data:
+    frees(a)
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc `=`(a: var string; b: string) =
+  if a.data != nil and a.data != b.data:
+    frees(a)
+    a.data = nil
+  a.len = b.len
+  a.cap = b.cap
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.cap + 1))
+    copyMem(a.data, b.data, a.cap+1)
+
+proc resize(s: var string) =
+  let old = s.cap
+  if old == 0: s.cap = 8
+  else: s.cap = (s.cap * 3) shr 1
+  s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
+
+proc add*(s: var string; c: char) =
+  if s.len >= s.cap: resize(s)
+  s.data[s.len] = c
+  s.data[s.len+1] = '\0'
+  inc s.len
+
+proc ensure(s: var string; newLen: int) =
+  let old = s.cap
+  if newLen >= old:
+    s.cap = max((old * 3) shr 1, newLen)
+    if s.cap > 0:
+      s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
+
+proc add*(s: var string; y: string) =
+  if y.len != 0:
+    let newLen = s.len + y.len
+    ensure(s, newLen)
+    copyMem(addr s.data[len], y.data, y.data.len + 1)
+    s.len = newLen
+
+proc len*(s: string): int {.inline.} = s.len
+
+proc newString*(len: int): string =
+  result.len = len
+  result.cap = len
+  if len > 0:
+    result.data = alloc0(len+1)
+
+converter toCString(x: string): cstring {.core.} =
+  if x.len == 0: cstring"" else: cast[cstring](x.data)
+
+proc newStringOfCap*(cap: int): string =
+  result.len = 0
+  result.cap = cap
+  if cap > 0:
+    result.data = alloc(cap+1)
+
+proc `&`*(a, b: string): string =
+  let sum = a.len + b.len
+  result = newStringOfCap(sum)
+  result.len = sum
+  copyMem(addr result.data[0], a.data, a.len)
+  copyMem(addr result.data[a.len], b.data, b.len)
+  if sum > 0:
+    result.data[sum] = '\0'
+
+proc concat(x: openArray[string]): string {.core.} =
+  ## used be the code generator to optimize 'x & y & z ...'
+  var sum = 0
+  for i in 0 ..< x.len: inc(sum, x[i].len)
+  result = newStringOfCap(sum)
+  sum = 0
+  for i in 0 ..< x.len:
+    let L = x[i].len
+    copyMem(addr result.data[sum], x[i].data, L)
+    inc(sum, L)
+
diff --git a/lib/core/typelayouts.nim b/lib/core/typelayouts.nim
new file mode 100644
index 000000000..445ce77c4
--- /dev/null
+++ b/lib/core/typelayouts.nim
@@ -0,0 +1,19 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type
+  TypeLayout* = object
+    size*, alignment*: int
+    destructor*: proc (self: pointer; a: Allocator) {.nimcall.}
+    trace*: proc (self: pointer; a: Allocator) {.nimcall.}
+    when false:
+      construct*: proc (self: pointer; a: Allocator) {.nimcall.}
+      copy*, deepcopy*, sink*: proc (self, other: pointer; a: Allocator) {.nimcall.}
+
+proc getTypeLayout(t: typedesc): ptr TypeLayout {.magic: "getTypeLayout".}