summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim5
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/ccgmerge.nim7
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/ccgthreadvars.nim4
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/cgen.nim24
-rw-r--r--compiler/cgendata.nim17
-rw-r--r--compiler/commands.nim12
-rw-r--r--compiler/evaltempl.nim8
-rw-r--r--compiler/hlo.nim2
-rw-r--r--compiler/importer.nim6
-rw-r--r--compiler/jsgen.nim8
-rw-r--r--compiler/lexer.nim23
-rw-r--r--compiler/main.nim3
-rw-r--r--compiler/modules.nim6
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/nim.cfg2
-rw-r--r--compiler/nim.nim4
-rw-r--r--compiler/options.nim15
-rw-r--r--compiler/parser.nim5
-rw-r--r--compiler/pragmas.nim23
-rw-r--r--compiler/renderer.nim6
-rw-r--r--compiler/scriptconfig.nim4
-rw-r--r--compiler/sem.nim7
-rw-r--r--compiler/semcall.nim6
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim97
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/seminst.nim6
-rw-r--r--compiler/semmacrosanity.nim16
-rw-r--r--compiler/semstmts.nim35
-rw-r--r--compiler/semtypes.nim19
-rw-r--r--compiler/sigmatch.nim8
-rw-r--r--compiler/vm.nim20
-rw-r--r--compiler/vmdeps.nim169
-rw-r--r--compiler/vmgen.nim19
-rw-r--r--compiler/vmops.nim68
38 files changed, 492 insertions, 176 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index fecbefd7e..7275aceb1 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -938,7 +938,7 @@ const
   genericParamsPos* = 2
   paramsPos* = 3
   pragmasPos* = 4
-  optimizedCodePos* = 5  # will be used for exception tracking
+  miscPos* = 5  # used for undocumented and hacky stuff
   bodyPos* = 6       # position of body; use rodread.getBody() instead!
   resultPos* = 7
   dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
@@ -961,6 +961,9 @@ const
                   skMethod, skConverter}
 
 var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
+var
+  gMainPackageId*: int
+  gMainPackageNotes*: TNoteKinds
 
 proc isCallExpr*(n: PNode): bool =
   result = n.kind in nkCallKinds
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index f892a3128..9f4beda9e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1235,7 +1235,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
   # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
   # have to call it here first:
   let ti = genTypeInfo(p.module, dest)
-  if tfFinal in dest.flags or (p.module.objHasKidsValid and
+  if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
                                tfObjHasKids notin dest.flags):
     result = "$1.m_type == $2" % [a, ti]
   else:
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index 2a37257b6..2e77cd2a6 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -107,8 +107,8 @@ proc genMergeInfo*(m: BModule): Rope =
   writeIntSet(m.typeInfoMarker, s)
   s.add("labels:")
   encodeVInt(m.labels, s)
-  s.add(" hasframe:")
-  encodeVInt(ord(m.frameDeclared), s)
+  s.add(" flags:")
+  encodeVInt(cast[int](m.flags), s)
   s.add(tnl)
   s.add("*/")
   result = s.rope
@@ -222,7 +222,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
     of "declared":  readIntSet(L, m.declaredThings)
     of "typeInfo":  readIntSet(L, m.typeInfoMarker)
     of "labels":    m.labels = decodeVInt(L.buf, L.bufpos)
-    of "hasframe":  m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
+    of "flags":
+      m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
     else: internalError("ccgmerge: unknown key: " & k)
 
 when not defined(nimhygiene):
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 988c923c8..61412ad67 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -16,7 +16,7 @@ const
     # above X strings a hash-switch for strings is generated
 
 proc registerGcRoot(p: BProc, v: PSym) =
-  if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2} and
+  if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
       containsGarbageCollectedRef(v.loc.t):
     # we register a specialized marked proc here; this has the advantage
     # that it works out of the box for thread local storage then :-)
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index ab771d240..81af89249 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -18,7 +18,7 @@ proc emulatedThreadVars(): bool =
 proc accessThreadLocalVar(p: BProc, s: PSym) =
   if emulatedThreadVars() and not p.threadVarAccessed:
     p.threadVarAccessed = true
-    p.module.usesThreadVars = true
+    incl p.module.flags, usesThreadVars
     addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
     add(p.procSec(cpsInit),
       ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
@@ -51,7 +51,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
     addf(m.s[cfsVars], " $1;$n", [s.loc.r])
 
 proc generateThreadLocalStorage(m: BModule) =
-  if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
+  if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
     for t in items(nimtvDeps): discard getTypeDesc(m, t)
     addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
 
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 700e6d148..6553deb66 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -752,7 +752,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope =
   genCLineDir(result, prc.info)
   # using static is needed for inline procs
   if lfExportLib in prc.loc.flags:
-    if m.isHeaderFile:
+    if isHeaderFile in m.flags:
       result.add "N_LIB_IMPORT "
     else:
       result.add "N_LIB_EXPORT "
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 0a8f89f2e..77be125b6 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -64,8 +64,8 @@ proc isSimpleConst(typ: PType): bool =
       (t.kind == tyProc and t.callConv == ccClosure)
 
 proc useStringh(m: BModule) =
-  if not m.includesStringh:
-    m.includesStringh = true
+  if includesStringh notin m.flags:
+    incl m.flags, includesStringh
     discard lists.includeStr(m.headerFiles, "<string.h>")
 
 proc useHeader(m: BModule, sym: PSym) =
@@ -1011,11 +1011,11 @@ proc genInitCode(m: BModule) =
   add(prc, m.postInitProc.s(cpsLocals))
   add(prc, genSectionEnd(cpsLocals))
 
-  if optStackTrace in m.initProc.options and not m.frameDeclared:
+  if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
     # BUT: the generated init code might depend on a current frame, so
     # declare it nevertheless:
-    m.frameDeclared = true
-    if not m.preventStackTrace:
+    incl m.flags, frameDeclared
+    if preventStackTrace notin m.flags:
       var procname = makeCString(m.module.name.s)
       add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
     else:
@@ -1032,7 +1032,7 @@ proc genInitCode(m: BModule) =
   add(prc, m.initProc.s(cpsStmts))
   add(prc, m.postInitProc.s(cpsStmts))
   add(prc, genSectionEnd(cpsStmts))
-  if optStackTrace in m.initProc.options and not m.preventStackTrace:
+  if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
     add(prc, deinitFrame(m.initProc))
   add(prc, deinitGCFrame(m.initProc))
   addf(prc, "}$N$N", [])
@@ -1105,7 +1105,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
   # no line tracing for the init sections of the system module so that we
   # don't generate a TFrame which can confuse the stack botton initialization:
   if sfSystemModule in module.flags:
-    result.preventStackTrace = true
+    incl result.flags, preventStackTrace
     excl(result.preInitProc.options, optStackTrace)
     excl(result.postInitProc.options, optStackTrace)
 
@@ -1128,9 +1128,11 @@ proc resetModule*(m: BModule) =
   m.forwardedProcs = @[]
   m.typeNodesName = getTempName()
   m.nimTypesName = getTempName()
-  m.preventStackTrace = sfSystemModule in m.module.flags
+  if sfSystemModule in m.module.flags:
+    incl m.flags, preventStackTrace
+  else:
+    excl m.flags, preventStackTrace
   nullify m.s
-  m.usesThreadVars = false
   m.typeNodes = 0
   m.nimTypes = 0
   nullify m.extensionLoaders
@@ -1175,7 +1177,7 @@ proc myOpen(module: PSym): PPassContext =
     let f = if headerFile.len > 0: headerFile else: gProjectFull
     generatedHeader = rawNewModule(module,
       changeFileExt(completeCFilePath(f), hExt))
-    generatedHeader.isHeaderFile = true
+    incl generatedHeader.flags, isHeaderFile
 
 proc writeHeader(m: BModule) =
   var result = getCopyright(m.filename)
@@ -1307,7 +1309,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
   registerModuleToMain(m.module)
 
   if sfMainModule in m.module.flags:
-    m.objHasKidsValid = true
+    incl m.flags, objHasKidsValid
     var disp = generateMethodDispatchers()
     for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
     genMainProc(m)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 187186373..c098902a6 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -92,17 +92,20 @@ type
     gcFrameType*: Rope       # the struct {} we put the GC markers into
 
   TTypeSeq* = seq[PType]
+
+  Codegenflag* = enum
+    preventStackTrace,  # true if stack traces need to be prevented
+    usesThreadVars,     # true if the module uses a thread var
+    frameDeclared,      # hack for ROD support so that we don't declare
+                        # a frame var twice in an init proc
+    isHeaderFile,       # C source file is the header file
+    includesStringh,    # C source file already includes ``<string.h>``
+    objHasKidsValid     # whether we can rely on tfObjHasKids
   TCGen = object of TPassContext # represents a C source file
     module*: PSym
     filename*: string
     s*: TCFileSections        # sections of the C file
-    preventStackTrace*: bool  # true if stack traces need to be prevented
-    usesThreadVars*: bool     # true if the module uses a thread var
-    frameDeclared*: bool      # hack for ROD support so that we don't declare
-                              # a frame var twice in an init proc
-    isHeaderFile*: bool       # C source file is the header file
-    includesStringh*: bool    # C source file already includes ``<string.h>``
-    objHasKidsValid*: bool    # whether we can rely on tfObjHasKids
+    flags*: set[Codegenflag]
     cfilename*: string        # filename of the module (including path,
                               # without extension)
     typeCache*: TIdTable      # cache the generated types
diff --git a/compiler/commands.nim b/compiler/commands.nim
index aa155ea88..3bc0b604a 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -213,6 +213,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
     of "size": result = contains(gOptions, optOptimizeSize)
     of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
     else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
+  of "verbosity": result = $gVerbosity == arg
   else: invalidCmdLineOption(passCmd1, switch, info)
 
 proc testCompileOption*(switch: string, info: TLineInfo): bool =
@@ -261,13 +262,7 @@ proc processPath(path: string, info: TLineInfo,
           else:
             options.gProjectPath / path
   try:
-    result = unixToNativePath(p % ["nimrod", getPrefixDir(),
-      "nim", getPrefixDir(),
-      "lib", libpath,
-      "home", removeTrailingDirSep(os.getHomeDir()),
-      "config", info.toFullPath().splitFile().dir,
-      "projectname", options.gProjectName,
-      "projectpath", options.gProjectPath])
+    result = pathSubs(p, info.toFullPath().splitFile().dir)
   except ValueError:
     localError(info, "invalid path: " & p)
     result = p
@@ -321,6 +316,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "nonimblepath", "nobabelpath":
     expectNoArg(switch, arg, pass, info)
     options.gNoNimblePath = true
+    options.lazyPaths.head = nil
+    options.lazyPaths.tail = nil
+    options.lazyPaths.counter = 0
   of "excludepath":
     expectArg(switch, arg, pass, info)
     let path = processPath(arg, info)
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index a5a132005..e136265da 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -59,7 +59,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
       evalTemplateAux(templ.sons[i], actual, c, res)
     result.add res
 
-proc evalTemplateArgs(n: PNode, s: PSym): PNode =
+proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
   # if the template has zero arguments, it can be called without ``()``
   # `n` is then a nkSym or something similar
   var totalParams = case n.kind
@@ -75,7 +75,7 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
     # their bodies. We could try to fix this, but it may be
     # wiser to just deprecate immediate templates and macros
     # now that we have working untyped parameters.
-    genericParams = if sfImmediate in s.flags: 0
+    genericParams = if sfImmediate in s.flags or fromHlo: 0
                     else: s.ast[genericParamsPos].len
     expectedRegularParams = <s.typ.len
     givenRegularParams = totalParams - genericParams
@@ -104,14 +104,14 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
 var evalTemplateCounter* = 0
   # to prevent endless recursion in templates instantiation
 
-proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
+proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100:
     globalError(n.info, errTemplateInstantiationTooNested)
     result = n
 
   # replace each param by the corresponding node:
-  var args = evalTemplateArgs(n, tmpl)
+  var args = evalTemplateArgs(n, tmpl, fromHlo)
   var ctx: TemplCtx
   ctx.owner = tmpl
   ctx.genSymOwner = genSymOwner
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
index 6cc9567af..de0fa6216 100644
--- a/compiler/hlo.nim
+++ b/compiler/hlo.nim
@@ -24,7 +24,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
   of skMacro:
     result = semMacroExpr(c, n, orig, s)
   of skTemplate:
-    result = semTemplateExpr(c, n, s)
+    result = semTemplateExpr(c, n, s, {efFromHlo})
   else:
     result = semDirectOp(c, n, {})
   if optHints in gOptions and hintPattern in gNotes:
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 86993358b..5ffe12728 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -22,7 +22,11 @@ proc getModuleName*(n: PNode): string =
   # The proc won't perform any checks that the path is actually valid
   case n.kind
   of nkStrLit, nkRStrLit, nkTripleStrLit:
-    result = unixToNativePath(n.strVal)
+    try:
+      result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
+    except ValueError:
+      localError(n.info, "invalid path: " & n.strVal)
+      result = n.strVal
   of nkIdent:
     result = n.ident.s
   of nkSym:
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 964752c16..124459306 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -71,7 +71,7 @@ type
     isLoop: bool             # whether it's a 'block' or 'while'
 
   TGlobals = object
-    typeInfo, code: Rope
+    typeInfo, constants, code: Rope
     forwarded: seq[PSym]
     generatedSyms: IntSet
     typeInfoGenerated: IntSet
@@ -237,7 +237,7 @@ proc useMagic(p: PProc, name: string) =
     internalAssert s.kind in {skProc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
       let code = genProc(p, s)
-      add(p.g.code, code)
+      add(p.g.constants, code)
   else:
     # we used to exclude the system module from this check, but for DLL
     # generation support this sloppyness leads to hard to detect bugs, so
@@ -1461,7 +1461,7 @@ proc genConstant(p: PProc, c: PSym) =
     p.body = nil
     #genLineDir(p, c.ast)
     genVarInit(p, c, c.ast)
-    add(p.g.code, p.body)
+    add(p.g.constants, p.body)
     p.body = oldBody
 
 proc genNew(p: PProc, n: PNode) =
@@ -2137,7 +2137,7 @@ proc wholeCode*(m: BModule): Rope =
       var p = newProc(globals, m, nil, m.module.options)
       attachProc(p, prc)
 
-  result = globals.typeInfo & globals.code
+  result = globals.typeInfo & globals.constants & globals.code
 
 proc getClassName(t: PType): Rope =
   var s = t.sym
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 0a4c01ba8..8b201431e 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -138,6 +138,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
 proc isKeyword*(kind: TTokType): bool =
   result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
 
+template ones(n: expr): expr = ((1 shl n)-1) # for utf-8 conversion
+
 proc isNimIdentifier*(s: string): bool =
   if s[0] in SymStartChars:
     var i = 1
@@ -589,12 +591,29 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
   of '\\':
     add(tok.literal, '\\')
     inc(L.bufpos)
-  of 'x', 'X':
+  of 'x', 'X', 'u', 'U':
+    var tp = L.buf[L.bufpos]
     inc(L.bufpos)
     var xi = 0
     handleHexChar(L, xi)
     handleHexChar(L, xi)
-    add(tok.literal, chr(xi))
+    if tp in {'u', 'U'}:
+      handleHexChar(L, xi)
+      handleHexChar(L, xi)
+      # inlined toUTF-8 to avoid unicode and strutils dependencies.
+      if xi <=% 127:
+        add(tok.literal, xi.char )
+      elif xi <=% 0x07FF:
+        add(tok.literal, ((xi shr 6) or 0b110_00000).char )
+        add(tok.literal, ((xi and ones(6)) or 0b10_0000_00).char )
+      elif xi <=% 0xFFFF:
+        add(tok.literal, (xi shr 12 or 0b1110_0000).char )
+        add(tok.literal, (xi shr 6 and ones(6) or 0b10_0000_00).char )
+        add(tok.literal, (xi and ones(6) or 0b10_0000_00).char )
+      else: # value is 0xFFFF
+        add(tok.literal, "\xef\xbf\xbf" )
+    else:
+      add(tok.literal, chr(xi))
   of '0'..'9':
     if matchTwoChars(L, '0', {'0'..'9'}):
       lexMessage(L, warnOctalEscape)
diff --git a/compiler/main.nim b/compiler/main.nim
index ece21a817..b1b9006bd 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -41,6 +41,7 @@ proc commandGenDepend =
 
 proc commandCheck =
   msgs.gErrorMax = high(int)  # do not stop after first error
+  defineSymbol("nimcheck")
   semanticPasses()            # use an empty backend for semantic checking only
   rodPass()
   compileProject()
@@ -241,7 +242,7 @@ proc mainCommand* =
   clearPasses()
   gLastCmdTime = epochTime()
   appendStr(searchPaths, options.libpath)
-  if gProjectFull.len != 0:
+  when false: # gProjectFull.len != 0:
     # current path is always looked first for modules
     prependStr(searchPaths, gProjectPath)
   setId(100)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index ef727e200..8ac964321 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -156,6 +156,9 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
     #var rd = handleSymbolFile(result)
     var rd: PRodReader
     result.flags = result.flags + flags
+    if sfMainModule in result.flags:
+      gMainPackageId = result.owner.id
+
     if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
       rd = handleSymbolFile(result)
       if result.id < 0:
@@ -183,6 +186,9 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
   if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
   if sfSystemModule in result.flags:
     localError(result.info, errAttemptToRedefine, result.name.s)
+  # restore the notes for outer module:
+  gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
+           else: ForeignPackageNotes
 
 proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index a556ad0c5..668d43bb3 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -500,12 +500,14 @@ type
   ESuggestDone* = object of Exception
 
 const
+  ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
+    hintQuitCalled}
   NotesVerbosity*: array[0..3, TNoteKinds] = [
     {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
                                          warnProveField, warnProveIndex,
                                          warnGcUnsafe,
                                          hintSuccessX, hintPath, hintConf,
-                                         hintProcessing,
+                                         hintProcessing, hintPattern,
                                          hintDependency,
                                          hintExecuting, hintLinking,
                                          hintCodeBegin, hintCodeEnd,
diff --git a/compiler/nim.cfg b/compiler/nim.cfg
index 4f9962ea8..0ff128ba3 100644
--- a/compiler/nim.cfg
+++ b/compiler/nim.cfg
@@ -7,7 +7,7 @@ path:"$projectPath/.."
 path:"$lib/packages/docutils"
 
 define:booting
-import:testability
+#import:"$projectpath/testability"
 
 @if windows:
   cincludes: "$lib/wrappers/libffi/common"
diff --git a/compiler/nim.nim b/compiler/nim.nim
index b242052ec..a58afd593 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -56,12 +56,12 @@ proc handleCmdLine() =
     loadConfigs(DefaultConfig) # load all config files
     let scriptFile = gProjectFull.changeFileExt("nims")
     if fileExists(scriptFile):
-      runNimScript(scriptFile)
+      runNimScript(scriptFile, freshDefines=false)
       # 'nim foo.nims' means to just run the NimScript file and do nothing more:
       if scriptFile == gProjectFull: return
     elif fileExists(gProjectPath / "config.nims"):
       # directory wide NimScript file
-      runNimScript(gProjectPath / "config.nims")
+      runNimScript(gProjectPath / "config.nims", freshDefines=false)
     # now process command line arguments again, because some options in the
     # command line can overwite the config file's settings
     extccomp.initVars()
diff --git a/compiler/options.nim b/compiler/options.nim
index 2716a98d3..3ef6c6c46 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -242,6 +242,21 @@ proc getNimcacheDir*: string =
   result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
                                                          genSubDir
 
+
+proc pathSubs*(p, config: string): string =
+  let home = removeTrailingDirSep(os.getHomeDir())
+  result = unixToNativePath(p % [
+    "nim", getPrefixDir(),
+    "lib", libpath,
+    "home", home,
+    "config", config,
+    "projectname", options.gProjectName,
+    "projectpath", options.gProjectPath,
+    "projectdir", options.gProjectPath,
+    "nimcache", getNimcacheDir()])
+  if '~' in result:
+    result = result.replace("~", home)
+
 template newPackageCache(): expr =
   newStringTable(when FileSystemCaseSensitive:
                    modeCaseInsensitive
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 1ba59b938..6132216e1 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -964,8 +964,9 @@ proc parseDoBlock(p: var TParser): PNode =
 proc parseDoBlocks(p: var TParser, call: PNode) =
   #| doBlocks = doBlock ^* IND{=}
   if p.tok.tokType == tkDo:
-    addSon(call, parseDoBlock(p))
-    while sameInd(p) and p.tok.tokType == tkDo:
+    #withInd(p):
+    #  addSon(call, parseDoBlock(p))
+    while sameOrNoInd(p) and p.tok.tokType == tkDo:
       addSon(call, parseDoBlock(p))
 
 proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 38d17eb62..dc618d9aa 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -277,6 +277,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
 proc processNote(c: PContext, n: PNode) =
   if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
       (n.sons[0].kind == nkBracketExpr) and
+      (n.sons[0].sons.len == 2) and
       (n.sons[0].sons[1].kind == nkIdent) and
       (n.sons[0].sons[0].kind == nkIdent):
       #and (n.sons[1].kind == nkIdent):
@@ -392,21 +393,23 @@ type
   TLinkFeature = enum
     linkNormal, linkSys
 
-proc processCompile(c: PContext, n: PNode) =
+proc relativeFile(c: PContext; n: PNode; ext=""): string =
   var s = expectStrLit(c, n)
-  var found = findFile(s)
-  if found == "": found = s
-  var trunc = changeFileExt(found, "")
-  if not isAbsolute(found):
-    found = parentDir(n.info.toFullPath) / found
+  if ext.len > 0 and splitFile(s).ext == "":
+    s = addFileExt(s, ext)
+  result = parentDir(n.info.toFullPath) / s
+  if not fileExists(result):
+    if isAbsolute(s): result = s
+    else: result = findFile(s)
+
+proc processCompile(c: PContext, n: PNode) =
+  let found = relativeFile(c, n)
+  let trunc = found.changeFileExt("")
   extccomp.addExternalFileToCompile(found)
   extccomp.addFileToLink(completeCFilePath(trunc, false))
 
 proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
-  var f = expectStrLit(c, n)
-  if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
-  var found = findFile(f)
-  if found == "": found = f # use the default
+  let found = relativeFile(c, n, CC[cCompiler].objExt)
   case feature
   of linkNormal: extccomp.addFileToLink(found)
   of linkSys:
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index f0ee137e9..e1db327f4 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -712,7 +712,11 @@ proc gproc(g: var TSrcGen, n: PNode) =
     gpattern(g, n.sons[patternPos])
   let oldCheckAnon = g.checkAnon
   g.checkAnon = true
-  gsub(g, n.sons[genericParamsPos])
+  if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
+      n[miscPos][1].kind != nkEmpty:
+    gsub(g, n[miscPos][1])
+  else:
+    gsub(g, n.sons[genericParamsPos])
   g.checkAnon = oldCheckAnon
   gsub(g, n.sons[paramsPos])
   gsub(g, n.sons[pragmasPos])
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index 22cd282fd..d04fd5231 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -118,10 +118,10 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
     processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
 
 
-proc runNimScript*(scriptName: string) =
+proc runNimScript*(scriptName: string; freshDefines=true) =
   passes.gIncludeFile = includeModule
   passes.gImportModule = importModule
-  initDefines()
+  if freshDefines: initDefines()
 
   defineSymbol("nimscript")
   defineSymbol("nimconfig")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index c29cbe384..a8ec2229f 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -354,7 +354,6 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
 
   #if c.evalContext == nil:
   #  c.evalContext = c.createEvalContext(emStatic)
-
   result = evalMacroCall(c.module, n, nOrig, sym)
   if efNoSemCheck notin flags:
     result = semAfterMacroCall(c, result, sym, flags)
@@ -414,6 +413,12 @@ proc myOpen(module: PSym): PPassContext =
     c.importTable.addSym magicsys.systemModule # import the "System" identifier
     importAllSymbols(c, magicsys.systemModule)
   c.topLevelScope = openScope(c)
+  # don't be verbose unless the module belongs to the main package:
+  if module.owner.id == gMainPackageId:
+    gNotes = gMainPackageNotes
+  else:
+    if gMainPackageNotes == {}: gMainPackageNotes = gNotes
+    gNotes = ForeignPackageNotes
   result = c
 
 proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 17dd39595..65aa5fd58 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -129,7 +129,11 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   add(result, ')')
   var candidates = ""
   for err in errors:
-    add(candidates, err.getProcHeader(prefer))
+    if err.kind in routineKinds and err.ast != nil:
+      add(candidates, renderTree(err.ast,
+            {renderNoBody, renderNoComments,renderNoPragmas}))
+    else:
+      add(candidates, err.getProcHeader(prefer))
     add(candidates, "\n")
   if candidates != "":
     add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index a13f2c232..91a1ebf86 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -47,7 +47,7 @@ type
     efLValue, efWantIterator, efInTypeof,
     efWantStmt, efAllowStmt, efDetermineType,
     efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
-    efNoProcvarCheck
+    efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo
   TExprFlags* = set[TExprFlag]
 
   TTypeAttachedOp* = enum
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 5aac1c2ac..57fb3ceed 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -15,7 +15,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
   markUsed(n.info, s)
   styleCheckUse(n.info, s)
   pushInfoContext(n.info)
-  result = evalTemplate(n, s, getCurrOwner())
+  result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags)
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
   popInfoContext()
 
@@ -717,6 +717,34 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
       initCandidate(c, result, t)
       matches(c, n, nOrig, result)
 
+proc bracketedMacro(n: PNode): PSym =
+  if n.len >= 1 and n[0].kind == nkSym:
+    result = n[0].sym
+    if result.kind notin {skMacro, skTemplate}:
+      result = nil
+
+proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
+                       flags: TExprFlags): PNode =
+  # We received untransformed bracket expression coming from macroOrTmpl[].
+  # Transform it to macro or template call, where first come normal
+  # arguments, next come generic template arguments.
+  var sons = newSeq[PNode]()
+  sons.add inner.sons[0]
+  # Normal arguments:
+  for i in 1..<outer.len:
+    sons.add outer.sons[i]
+  # Generic template arguments from bracket expression:
+  for i in 1..<inner.len:
+    sons.add inner.sons[i]
+  shallowCopy(outer.sons, sons)
+  # FIXME: Shouldn't we check sfImmediate and call semDirectOp?
+  # However passing to semDirectOp doesn't work here.
+  case s.kind
+  of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
+  of skTemplate: result = semTemplateExpr(c, outer, s, flags)
+  else: assert(false)
+  return
+
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = nil
   checkMinSonsLen(n, 1)
@@ -732,10 +760,15 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
       return semExpr(c, result, flags)
   else:
-    n.sons[0] = semExpr(c, n.sons[0])
+    n.sons[0] = semExpr(c, n.sons[0], {efInCall})
     let t = n.sons[0].typ
     if t != nil and t.kind == tyVar:
       n.sons[0] = newDeref(n.sons[0])
+    elif n.sons[0].kind == nkBracketExpr:
+      let s = bracketedMacro(n.sons[0])
+      if s != nil:
+        return semBracketedMacro(c, n, n.sons[0], s, flags)
+
   let nOrig = n.copyTree
   semOpAux(c, n)
   var t: PType = nil
@@ -965,8 +998,20 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       else: result = newSymNode(s, n.info)
     else:
       result = newSymNode(s, n.info)
-  of skMacro: result = semMacroExpr(c, n, n, s, flags)
-  of skTemplate: result = semTemplateExpr(c, n, s, flags)
+  of skMacro:
+    if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
+      markUsed(n.info, s)
+      styleCheckUse(n.info, s)
+      result = newSymNode(s, n.info)
+    else:
+      result = semMacroExpr(c, n, n, s, flags)
+  of skTemplate:
+    if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
+      markUsed(n.info, s)
+      styleCheckUse(n.info, s)
+      result = newSymNode(s, n.info)
+    else:
+      result = semTemplateExpr(c, n, s, flags)
   of skParam:
     markUsed(n.info, s)
     styleCheckUse(n.info, s)
@@ -1193,7 +1238,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result.add(x[0])
     return
   checkMinSonsLen(n, 2)
-  n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck})
+  # make sure we don't evaluate generic macros/templates
+  n.sons[0] = semExprWithType(c, n.sons[0],
+                              {efNoProcvarCheck, efNoEvaluateGeneric})
   let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
   of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
@@ -1236,12 +1283,30 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     let s = if n.sons[0].kind == nkSym: n.sons[0].sym
             elif n[0].kind in nkSymChoices: n.sons[0][0].sym
             else: nil
-    if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
-      # type parameters: partial generic specialization
-      n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
-      result = explicitGenericInstantiation(c, n, s)
-    elif s != nil and s.kind == skType:
-      result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+    if s != nil:
+      case s.kind
+      of skProc, skMethod, skConverter, skIterator:
+        # type parameters: partial generic specialization
+        n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
+        result = explicitGenericInstantiation(c, n, s)
+      of skMacro, skTemplate:
+        if efInCall in flags:
+          # We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
+          # Return as is, so it can be transformed into complete macro or
+          # template call in semIndirectOp caller.
+          result = n
+        else:
+          # We are processing macroOrTmpl[] not in call. Transform it to the
+          # macro or template call with generic arguments here.
+          n.kind = nkCall
+          case s.kind
+          of skMacro: result = semMacroExpr(c, n, n, s, flags)
+          of skTemplate: result = semTemplateExpr(c, n, s, flags)
+          else: discard
+      of skType:
+        result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+      else:
+        c.p.bracketExpr = n.sons[0]
     else:
       c.p.bracketExpr = n.sons[0]
 
@@ -1818,7 +1883,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   result = nil
 
   template setResult(e: expr) =
-    if semCheck: result = semStmt(c, e) # do not open a new scope!
+    if semCheck: result = semExpr(c, e) # do not open a new scope!
     else: result = e
 
   # Check if the node is "when nimvm"
@@ -1827,6 +1892,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   # else:
   #   ...
   var whenNimvm = false
+  var typ = commonTypeBegin
   if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
       n.sons[1].kind == nkElse:
     let exprNode = n.sons[0].sons[0]
@@ -1843,7 +1909,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
       checkSonsLen(it, 2)
       if whenNimvm:
         if semCheck:
-          it.sons[1] = semStmt(c, it.sons[1])
+          it.sons[1] = semExpr(c, it.sons[1])
+          typ = commonType(typ, it.sons[1].typ)
         result = n # when nimvm is not elimited until codegen
       else:
         var e = semConstExpr(c, it.sons[0])
@@ -1857,12 +1924,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
       checkSonsLen(it, 1)
       if result == nil or whenNimvm:
         if semCheck:
-          it.sons[0] = semStmt(c, it.sons[0])
+          it.sons[0] = semExpr(c, it.sons[0])
+          typ = commonType(typ, it.sons[0].typ)
         if result == nil:
           result = it.sons[0]
     else: illFormedAst(n)
   if result == nil:
     result = newNodeI(nkEmpty, n.info)
+  if whenNimvm: result.typ = typ
   # The ``when`` statement implements the mechanism for platform dependent
   # code. Thus we try to ensure here consistent ID allocation after the
   # ``when`` statement.
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c5a8cc2a2..feea6ce34 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -489,7 +489,7 @@ proc leValueConv(a, b: PNode): bool =
   of nkCharLit..nkUInt64Lit:
     case b.kind
     of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
-    of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
+    of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
     else: internalError(a.info, "leValueConv")
   of nkFloatLit..nkFloat128Lit:
     case b.kind
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 14631a590..e4ac56cd6 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -43,9 +43,11 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
       if arg.name.id == c.selfName.id:
         c.p.selfSym = arg
         arg.flags.incl sfIsSelf
-        let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
-        if t.kind == tyObject:
+        var t = c.p.selfSym.typ.skipTypes(abstractPtrs)
+        while t.kind == tyObject:
           addObjFieldsToLocalScope(c, t.n)
+          if t.sons[0] == nil: break
+          t = t.sons[0].skipTypes(abstractPtrs)
 
 proc pushProcCon*(c: PContext; owner: PSym) =
   rawPushProcCon(c, owner)
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index 150680af7..6cd5c4a3c 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -12,25 +12,26 @@
 
 import ast, astalgo, msgs, types
 
-proc ithField(n: PNode, field: int): PSym =
+proc ithField(n: PNode, field: var int): PSym =
   result = nil
   case n.kind
   of nkRecList:
     for i in countup(0, sonsLen(n) - 1):
-      result = ithField(n.sons[i], field-i)
+      result = ithField(n.sons[i], field)
       if result != nil: return
   of nkRecCase:
     if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
-    result = ithField(n.sons[0], field-1)
+    result = ithField(n.sons[0], field)
     if result != nil: return
     for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
       of nkOfBranch, nkElse:
-        result = ithField(lastSon(n.sons[i]), field-1)
+        result = ithField(lastSon(n.sons[i]), field)
         if result != nil: return
       else: internalError(n.info, "ithField(record case branch)")
   of nkSym:
     if field == 0: result = n.sym
+    else: dec(field)
   else: discard
 
 proc annotateType*(n: PNode, t: PType) =
@@ -39,10 +40,13 @@ proc annotateType*(n: PNode, t: PType) =
   # to not to skip tyGenericInst
   case n.kind
   of nkObjConstr:
+    let x = t.skipTypes(abstractPtrs)
     n.typ = t
     for i in 1 .. <n.len:
-      let field = x.n.ithField(i - 1)
-      if field.isNil: globalError n.info, "invalid field at index " & $i
+      var j = i-1
+      let field = x.n.ithField(j)
+      if field.isNil:
+        globalError n.info, "invalid field at index " & $i
       else:
         internalAssert(n.sons[i].kind == nkExprColonExpr)
         annotateType(n.sons[i].sons[1], field.typ)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index f6bfca955..0b2343c10 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -17,7 +17,8 @@ proc semDiscard(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
+    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone:
+      localError(n.info, errInvalidDiscard)
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
@@ -535,7 +536,7 @@ proc semConst(c: PContext, n: PNode): PNode =
       localError(a.sons[2].info, errConstExprExpected)
       continue
     if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
-      localError(a.info, errXisNoType, typeToString(typ))
+      localError(a.info, "invalid type for const: " & typeToString(typ))
       continue
     v.typ = typ
     v.ast = def               # no need to copy
@@ -781,9 +782,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
       var x = a[2]
       while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
         x = x.lastSon
-      if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty}:
+      if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
+          s.typ.kind notin {tyObject, tyEnum}:
         # type aliases are hard:
-        #MessageOut('for type ' + typeToString(s.typ));
         var t = semTypeNode(c, x, nil)
         assert t != nil
         if t.kind in {tyObject, tyEnum, tyDistinct}:
@@ -929,6 +930,17 @@ proc semProcAnnotation(c: PContext, prc: PNode;
       pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
     return
 
+proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
+  let orig = n.sons[genericParamsPos]
+  # we keep the original params around for better error messages, see
+  # issue https://github.com/nim-lang/Nim/issues/1713
+  result = semGenericParamList(c, orig)
+  if n.sons[miscPos].kind == nkEmpty:
+    n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig)
+  else:
+    n.sons[miscPos].sons[1] = orig
+  n.sons[genericParamsPos] = result
+
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # XXX semProcAux should be good enough for this now, we will eventually
   # remove semLambda
@@ -947,8 +959,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   openScope(c)
   var gp: PNode
   if n.sons[genericParamsPos].kind != nkEmpty:
-    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
-    gp = n.sons[genericParamsPos]
+    gp = setGenericParamsMisc(c, n)
   else:
     gp = newNodeI(nkGenericParams, n.info)
 
@@ -1170,8 +1181,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   openScope(c)
   var gp: PNode
   if n.sons[genericParamsPos].kind != nkEmpty:
-    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
-    gp = n.sons[genericParamsPos]
+    gp = setGenericParamsMisc(c, n)
   else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
@@ -1250,7 +1260,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
 
       c.p.wasForwarded = proto != nil
       maybeAddResult(c, s, n)
-      if sfImportc notin s.flags:
+      if lfDynamicLib notin s.loc.flags:
         # no semantic checking for importc:
         let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
         # unfortunately we cannot skip this step when in 'system.compiles'
@@ -1330,7 +1340,8 @@ proc finishMethod(c: PContext, s: PSym) =
 proc semMethod(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
-
+  # macros can transform methods to nothing:
+  if namePos >= result.safeLen: return result
   var s = result.sons[namePos].sym
   if not isGenericRoutine(s):
     # why check for the body? bug #2400 has none. Checking for sfForward makes
@@ -1345,6 +1356,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skConverter, converterPragmas)
+  # macros can transform converters to nothing:
+  if namePos >= result.safeLen: return result
   var s = result.sons[namePos].sym
   var t = s.typ
   if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
@@ -1354,6 +1367,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
 proc semMacroDef(c: PContext, n: PNode): PNode =
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skMacro, macroPragmas)
+  # macros can transform macros to nothing:
+  if namePos >= result.safeLen: return result
   var s = result.sons[namePos].sym
   var t = s.typ
   if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ba17cc307..13b283fe5 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -398,15 +398,18 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
                  allowed: TSymFlags): PSym =
   # identifier with visibility
   if n.kind == nkPostfix:
-    if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
+    if sonsLen(n) == 2:
       # for gensym'ed identifiers the identifier may already have been
       # transformed to a symbol and we need to use that here:
       result = newSymG(kind, n.sons[1], c)
-      var v = n.sons[0].ident
+      var v = considerQuotedIdent(n.sons[0])
       if sfExported in allowed and v.id == ord(wStar):
         incl(result.flags, sfExported)
       else:
-        localError(n.sons[0].info, errInvalidVisibilityX, v.s)
+        if not (sfExported in allowed):
+          localError(n.sons[0].info, errXOnlyAtModuleScope, "export")
+        else:
+          localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0]))
     else:
       illFormedAst(n)
   else:
@@ -1094,10 +1097,14 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
         result = instGenericContainer(c, n.info, result,
                                       allowMetaTypes = false)
 
-proc semTypeExpr(c: PContext, n: PNode): PType =
+proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
   var n = semExprWithType(c, n, {efDetermineType})
   if n.typ.kind == tyTypeDesc:
     result = n.typ.base
+    # fix types constructed by macros:
+    if prev != nil and prev.sym != nil and result.sym.isNil:
+      result.sym = prev.sym
+      result.sym.typ = result
   else:
     localError(n.info, errTypeExpected, n.renderTree)
     result = errorType(c)
@@ -1177,7 +1184,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       else:
         localError(n.info, errGenerated, "invalid type")
     elif n[0].kind notin nkIdentKinds:
-      result = semTypeExpr(c, n)
+      result = semTypeExpr(c, n, prev)
     else:
       let op = considerQuotedIdent(n.sons[0])
       if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
@@ -1218,7 +1225,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
         result = typExpr.typ
       else:
-        result = semTypeExpr(c, n)
+        result = semTypeExpr(c, n, prev)
   of nkWhenStmt:
     var whenResult = semWhen(c, n, false)
     if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index ecef11d13..e72db45e7 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -242,6 +242,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
     for i in 1 .. <arg.len:
       result.add(" | ")
       result.add typeToString(arg[i].typ, prefer)
+  elif arg.typ == nil:
+    result = "void"
   else:
     result = arg.typ.typeToString(prefer)
 
@@ -253,15 +255,15 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
     if n.sons[i].kind == nkExprEqExpr:
       add(result, renderTree(n.sons[i].sons[0]))
       add(result, ": ")
-      if arg.typ.isNil:
+      if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
         arg = c.semOperand(c, n.sons[i].sons[1])
         n.sons[i].typ = arg.typ
         n.sons[i].sons[1] = arg
     else:
-      if arg.typ.isNil:
+      if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
         arg = c.semOperand(c, n.sons[i])
         n.sons[i] = arg
-    if arg.typ.kind == tyError: return
+    if arg.typ != nil and arg.typ.kind == tyError: return
     add(result, argTypeToString(arg, prefer))
     if i != sonsLen(n) - 1: add(result, ", ")
 
diff --git a/compiler/vm.nim b/compiler/vm.nim
index f799334d6..f275b7b9b 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1185,19 +1185,35 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNGetType:
       let rb = instr.regB
       let rc = instr.regC
-      if rc == 0:
+      case rc:
+      of 0:
+        # getType opcode:
         ensureKind(rkNode)
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
         else:
           stackTrace(c, tos, pc, errGenerated, "node has no type")
-      else:
+      of 1:
         # typeKind opcode:
         ensureKind(rkInt)
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].intVal = ord(regs[rb].node.typ.kind)
         #else:
         #  stackTrace(c, tos, pc, errGenerated, "node has no type")
+      of 2:
+        # getTypeInst opcode:
+        ensureKind(rkNode)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
+        else:
+          stackTrace(c, tos, pc, errGenerated, "node has no type")
+      else:
+        # getTypeImpl opcode:
+        ensureKind(rkNode)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
+        else:
+          stackTrace(c, tos, pc, errGenerated, "node has no type")
     of opcNStrVal:
       decodeB(rkNode)
       createStr regs[ra]
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index a4f02092d..678a765f4 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-import ast, types, msgs, osproc, streams, options, idents, securehash
+import ast, types, msgs, os, osproc, streams, options, idents, securehash
 
 proc readOutput(p: Process): string =
   result = ""
@@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string =
 
 proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
   try:
-    let filename = file.findFile
+    var filename = parentDir(info.toFullPath) / file
+    if not fileExists(filename):
+      filename = file.findFile
     result = readFile(filename)
     # we produce a fake include statement for every slurped filename, so that
     # the module dependencies are accurate:
@@ -67,9 +69,11 @@ proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
   result = newSymNode(sym)
   result.typ = t
 
-proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
+proc mapTypeToAstX(t: PType; info: TLineInfo;
+                   inst=false; allowRecursionX=false): PNode
 
-proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
+proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo;
+                       inst=false): PNode =
   result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
   result.add atomicTypeX(name, t, info)
   for i in 0 .. < t.len:
@@ -78,10 +82,39 @@ proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
       void.typ = newType(tyEmpty, t.owner)
       result.add void
     else:
-      result.add mapTypeToAst(t.sons[i], info)
+      result.add mapTypeToAstX(t.sons[i], info, inst)
 
-proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
+proc mapTypeToAstX(t: PType; info: TLineInfo;
+                   inst=false; allowRecursionX=false): PNode =
+  var allowRecursion = allowRecursionX
   template atomicType(name): expr = atomicTypeX(name, t, info)
+  template mapTypeToAst(t,info): expr = mapTypeToAstX(t, info, inst)
+  template mapTypeToAstR(t,info): expr = mapTypeToAstX(t, info, inst, true)
+  template mapTypeToAst(t,i,info): expr =
+    if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst)
+    else: ast.emptyNode
+  template mapTypeToBracket(name,t,info): expr =
+    mapTypeToBracketX(name, t, info, inst)
+  template newNodeX(kind):expr =
+    newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
+  template newIdent(s):expr =
+    var r = newNodeX(nkIdent)
+    r.add !s
+    r
+  template newIdentDefs(n,t):expr =
+    var id = newNodeX(nkIdentDefs)
+    id.add n  # name
+    id.add mapTypeToAst(t, info)  # type
+    id.add ast.emptyNode  # no assigned value
+    id
+  template newIdentDefs(s):expr = newIdentDefs(s, s.typ)
+
+  if inst:
+    if t.sym != nil:  # if this node has a symbol
+      if allowRecursion:  # getTypeImpl behavior: turn off recursion
+        allowRecursion = false
+      else:  # getTypeInst behavior: return symbol
+        return atomicType(t.sym.name.s)
 
   case t.kind
   of tyNone: result = atomicType("none")
@@ -94,7 +127,14 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
   of tyArrayConstr, tyArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
     result.add atomicType("array")
-    result.add mapTypeToAst(t.sons[0], info)
+    if inst and t.sons[0].kind == tyRange:
+      var rng = newNodeX(nkInfix)
+      rng.add newIdentNode(getIdent(".."), info)
+      rng.add t.sons[0].n.sons[0].copyTree
+      rng.add t.sons[0].n.sons[1].copyTree
+      result.add rng
+    else:
+      result.add mapTypeToAst(t.sons[0], info)
     result.add mapTypeToAst(t.sons[1], info)
   of tyTypeDesc:
     if t.base != nil:
@@ -107,34 +147,95 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
     for i in 0 .. < t.len:
       result.add mapTypeToAst(t.sons[i], info)
-  of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
+  of tyGenericInst:
+    if inst:
+      if allowRecursion:
+        result = mapTypeToAstR(t.lastSon, info)
+      else:
+        result = newNodeX(nkBracketExpr)
+        result.add mapTypeToAst(t.lastSon, info)
+        for i in 1 .. < t.len-1:
+          result.add mapTypeToAst(t.sons[i], info)
+    else:
+      result = mapTypeToAst(t.lastSon, info)
+  of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
     result = mapTypeToAst(t.lastSon, info)
   of tyDistinct:
-    if allowRecursion:
-      result = mapTypeToBracket("distinct", t, info)
+    if inst:
+      result = newNodeX(nkDistinctTy)
+      result.add mapTypeToAst(t.sons[0], info)
     else:
-      result = atomicType(t.sym.name.s)
+      if allowRecursion or t.sym==nil:
+        result = mapTypeToBracket("distinct", t, info)
+      else:
+        result = atomicType(t.sym.name.s)
   of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
   of tyObject:
-    if allowRecursion:
-      result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
-      if t.sons[0] == nil:
-        result.add ast.emptyNode
+    if inst:
+      result = newNodeX(nkObjectTy)
+      result.add ast.emptyNode  # pragmas not reconstructed yet
+      if t.sons[0]==nil: result.add ast.emptyNode  # handle parent object
+      else:
+        var nn = newNodeX(nkOfInherit)
+        nn.add mapTypeToAst(t.sons[0], info)
+        result.add nn
+      if t.n.sons.len>0:
+        var rl = copyNode(t.n)  # handle nkRecList
+        for s in t.n.sons:
+          rl.add newIdentDefs(s)
+        result.add rl
       else:
-        result.add mapTypeToAst(t.sons[0], info)
-      result.add copyTree(t.n)
+        result.add ast.emptyNode
     else:
-      result = atomicType(t.sym.name.s)
+      if allowRecursion or t.sym == nil:
+        result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
+        result.add ast.emptyNode
+        if t.sons[0] == nil:
+          result.add ast.emptyNode
+        else:
+          result.add mapTypeToAst(t.sons[0], info)
+        result.add copyTree(t.n)
+      else:
+        result = atomicType(t.sym.name.s)
   of tyEnum:
     result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t)
     result.add copyTree(t.n)
-  of tyTuple: result = mapTypeToBracket("tuple", t, info)
+  of tyTuple:
+    if inst:
+      result = newNodeX(nkTupleTy)
+      for s in t.n.sons:
+        result.add newIdentDefs(s)
+    else:
+      result = mapTypeToBracket("tuple", t, info)
   of tySet: result = mapTypeToBracket("set", t, info)
-  of tyPtr: result = mapTypeToBracket("ptr", t, info)
-  of tyRef: result = mapTypeToBracket("ref", t, info)
+  of tyPtr:
+    if inst:
+      result = newNodeX(nkPtrTy)
+      result.add mapTypeToAst(t.sons[0], info)
+    else:
+      result = mapTypeToBracket("ptr", t, info)
+  of tyRef:
+    if inst:
+      result = newNodeX(nkRefTy)
+      result.add mapTypeToAst(t.sons[0], info)
+    else:
+      result = mapTypeToBracket("ref", t, info)
   of tyVar: result = mapTypeToBracket("var", t, info)
   of tySequence: result = mapTypeToBracket("seq", t, info)
-  of tyProc: result = mapTypeToBracket("proc", t, info)
+  of tyProc:
+    if inst:
+      result = newNodeX(nkProcTy)
+      var fp = newNodeX(nkFormalParams)
+      if t.sons[0] == nil:
+        fp.add ast.emptyNode
+      else:
+        fp.add mapTypeToAst(t.sons[0], t.n[0].info)
+      for i in 1..<t.sons.len:
+        fp.add newIdentDefs(t.n[i], t.sons[i])
+      result.add fp
+      result.add ast.emptyNode  # pragmas aren't reconstructed yet
+    else:
+      result = mapTypeToBracket("proc", t, info)
   of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
   of tyRange:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
@@ -174,10 +275,24 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
   of tyNot: result = mapTypeToBracket("not", t, info)
   of tyAnything: result = atomicType"anything"
   of tyStatic, tyFromExpr, tyFieldAccessor:
-    result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-    result.add atomicType("static")
-    if t.n != nil:
-      result.add t.n.copyTree
+    if inst:
+      if t.n != nil: result = t.n.copyTree
+      else: result = atomicType "void"
+    else:
+      result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
+      result.add atomicType "static"
+      if t.n != nil:
+        result.add t.n.copyTree
 
 proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
-  result = mapTypeToAst(t, info, true)
+  result = mapTypeToAstX(t, info, false, true)
+
+# the "Inst" version includes generic parameters in the resulting type tree
+# and also tries to look like the corresponding Nim type declaration
+proc opMapTypeInstToAst*(t: PType; info: TLineInfo): PNode =
+  result = mapTypeToAstX(t, info, true, false)
+
+# the "Impl" version includes generic parameters in the resulting type tree
+# and also tries to look like the corresponding Nim type implementation
+proc opMapTypeImplToAst*(t: PType; info: TLineInfo): PNode =
+  result = mapTypeToAstX(t, info, true, true)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index bd32ccc17..675fb2dc2 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -983,7 +983,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mNGetType:
     let tmp = c.genx(n.sons[1])
     if dest < 0: dest = c.getTemp(n.typ)
-    c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
+    let rc = case n[0].sym.name.s:
+      of "getType": 0
+      of "typeKind": 1
+      of "getTypeInst": 2
+      else: 3  # "getTypeImpl"
+    c.gABC(n, opcNGetType, dest, tmp, rc)
     c.freeTemp(tmp)
     #genUnaryABC(c, n, dest, opcNGetType)
   of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
@@ -1882,8 +1887,8 @@ proc optimizeJumps(c: PCtx; start: int) =
     else: discard
 
 proc genProc(c: PCtx; s: PSym): int =
-  let x = s.ast.sons[optimizedCodePos]
-  if x.kind == nkEmpty:
+  var x = s.ast.sons[miscPos]
+  if x.kind == nkEmpty or x[0].kind == nkEmpty:
     #if s.name.s == "outterMacro" or s.name.s == "innerProc":
     #  echo "GENERATING CODE FOR ", s.name.s
     let last = c.code.len-1
@@ -1894,7 +1899,11 @@ proc genProc(c: PCtx; s: PSym): int =
       c.debug.setLen(last)
     #c.removeLastEof
     result = c.code.len+1 # skip the jump instruction
-    s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
+    if x.kind == nkEmpty:
+      x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode)
+    else:
+      x.sons[0] = newIntNode(nkIntLit, result)
+    s.ast.sons[miscPos] = x
     # thanks to the jmp we can add top level statements easily and also nest
     # procs easily:
     let body = s.getBody
@@ -1929,4 +1938,4 @@ proc genProc(c: PCtx; s: PSym): int =
     c.prc = oldPrc
   else:
     c.prc.maxSlots = s.offset
-    result = x.intVal.int
+    result = x[0].intVal.int
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index e40e05eff..d0b3119e2 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -24,22 +24,27 @@ template osop(op) {.immediate, dirty.} =
 template systemop(op) {.immediate, dirty.} =
   registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
 
-template wrap1f(op) {.immediate, dirty.} =
+template wrap1f_math(op) {.immediate, dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, op(getFloat(a, 0)))
   mathop op
 
-template wrap2f(op) {.immediate, dirty.} =
+template wrap2f_math(op) {.immediate, dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
   mathop op
 
-template wrap1s(op) {.immediate, dirty.} =
+template wrap1s_os(op) {.immediate, dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, op(getString(a, 0)))
   osop op
 
-template wrap2svoid(op) {.immediate, dirty.} =
+template wrap1s_system(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getString(a, 0)))
+  systemop op
+
+template wrap2svoid_system(op) {.immediate, dirty.} =
   proc `op Wrapper`(a: VmArgs) {.nimcall.} =
     op(getString(a, 0), getString(a, 1))
   systemop op
@@ -55,34 +60,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
                               newStrNode(nkStrLit, f))
 
 proc registerAdditionalOps*(c: PCtx) =
-  wrap1f(sqrt)
-  wrap1f(ln)
-  wrap1f(log10)
-  wrap1f(log2)
-  wrap1f(exp)
-  wrap1f(round)
-  wrap1f(arccos)
-  wrap1f(arcsin)
-  wrap1f(arctan)
-  wrap2f(arctan2)
-  wrap1f(cos)
-  wrap1f(cosh)
-  wrap2f(hypot)
-  wrap1f(sinh)
-  wrap1f(sin)
-  wrap1f(tan)
-  wrap1f(tanh)
-  wrap2f(pow)
-  wrap1f(trunc)
-  wrap1f(floor)
-  wrap1f(ceil)
-  wrap2f(fmod)
+  wrap1f_math(sqrt)
+  wrap1f_math(ln)
+  wrap1f_math(log10)
+  wrap1f_math(log2)
+  wrap1f_math(exp)
+  wrap1f_math(round)
+  wrap1f_math(arccos)
+  wrap1f_math(arcsin)
+  wrap1f_math(arctan)
+  wrap2f_math(arctan2)
+  wrap1f_math(cos)
+  wrap1f_math(cosh)
+  wrap2f_math(hypot)
+  wrap1f_math(sinh)
+  wrap1f_math(sin)
+  wrap1f_math(tan)
+  wrap1f_math(tanh)
+  wrap2f_math(pow)
+  wrap1f_math(trunc)
+  wrap1f_math(floor)
+  wrap1f_math(ceil)
+  wrap2f_math(fmod)
 
-  wrap1s(getEnv)
-  wrap1s(existsEnv)
-  wrap1s(dirExists)
-  wrap1s(fileExists)
-  wrap2svoid(writeFile)
+  wrap1s_os(getEnv)
+  wrap1s_os(existsEnv)
+  wrap1s_os(dirExists)
+  wrap1s_os(fileExists)
+  wrap2svoid_system(writeFile)
+  wrap1s_system(readFile)
   systemop getCurrentExceptionMsg
   registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
     setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))