diff --git a/changelog.md b/changelog.md
index 847a36d841..5858ec28f8 100644
--- a/changelog.md
+++ b/changelog.md
@@ -108,3 +108,32 @@ This now needs to be written as:
- [``poly``](https://github.com/lcrees/polynumeric)
- [``pdcurses``](https://github.com/lcrees/pdcurses)
- [``romans``](https://github.com/lcrees/romans)
+
+- Added ``system.runnableExamples`` to make examples in Nim's documentation easier
+ to write and test. The examples are tested as the last step of
+ ``nim doc``.
+- Nim's ``rst2html`` command now supports the testing of code snippets via an RST
+ extension that we called ``:test:``::
+
+ .. code-block:: nim
+ :test:
+ # shows how the 'if' statement works
+ if true: echo "yes"
+- The ``[]`` proc for strings now raises an ``IndexError`` exception when
+ the specified slice is out of bounds. See issue
+ [#6223](https://github.com/nim-lang/Nim/issues/6223) for more details.
+- ``strutils.split`` and ``strutils.rsplit`` with an empty string and a
+ separator now returns that empty string.
+ See issue [#4377](https://github.com/nim-lang/Nim/issues/4377).
+- The experimental overloading of the dot ``.`` operators now take
+ an ``untyped``` parameter as the field name, it used to be
+ a ``static[string]``. You can use ``when defined(nimNewDot)`` to make
+ your code work with both old and new Nim versions.
+ See [special-operators](https://nim-lang.org/docs/manual.html#special-operators)
+ for more information.
+- Added ``macros.unpackVarargs``.
+- The memory manager now uses a variant of the TLSF algorithm that has much
+ better memory fragmentation behaviour. According
+ to [http://www.gii.upv.es/tlsf/](http://www.gii.upv.es/tlsf/) the maximum
+ fragmentation measured is lower than 25%. As a nice bonus ``alloc`` and
+ ``dealloc`` became O(1) operations.
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 787cb49977..5bf4184c95 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -639,7 +639,7 @@ type
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mNGenSym,
- mNimvm, mIntDefine, mStrDefine
+ mNimvm, mIntDefine, mStrDefine, mRunnableExamples
# things that we can evaluate safely at compile time, even if not asked for it:
const
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 571135fbb5..5f107f21f9 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1860,7 +1860,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[2], b)
genDeepCopy(p, a, b)
of mDotDot, mEqCString: genCall(p, e, d)
- else: internalError(e.info, "genMagicExpr: " & $op)
+ else:
+ when defined(debugMagics):
+ echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
+ internalError(e.info, "genMagicExpr: " & $op)
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
# example: { a..b, c, d, e, f..g }
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 8dfb82963d..cfa2afdd95 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -968,8 +968,11 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
discard cgsym(m, "TNimType")
if isDefined("nimTypeNames"):
+ var typename = typeToString(origType, preferName)
+ if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
+ typename = "anon ref object from " & $origType.skipTypes(skipPtrs).sym.info
addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
- [name, makeCstring typeToString(origType, preferName)])
+ [name, makeCstring typename])
discard cgsym(m, "nimTypeRoot")
addf(m.s[cfsTypeInit3], "$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
[name])
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 19ab2fe50a..0f8fa760e2 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -54,7 +54,7 @@ type
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
BModule* = ref TCGen
BProc* = ref TCProc
- TBlock*{.final.} = object
+ TBlock* = object
id*: int # the ID of the label; positive means that it
label*: Rope # generated text for the label
# nil if label is not used
@@ -64,7 +64,7 @@ type
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16
- TCProc{.final.} = object # represents C proc that is currently generated
+ TCProc = object # represents C proc that is currently generated
prc*: PSym # the Nim proc that this C proc belongs to
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 11a66cf55e..de474c6e68 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -654,6 +654,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
gListFullPaths = true
of "dynliboverride":
dynlibOverride(switch, arg, pass, info)
+ of "dynliboverrideall":
+ expectNoArg(switch, arg, pass, info)
+ gDynlibOverrideAll = true
of "cs":
# only supported for compatibility. Does nothing.
expectArg(switch, arg, pass, info)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 2050a746b4..a52214e734 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -110,3 +110,5 @@ proc initDefines*() =
when false: defineSymbol("nimHasOpt")
defineSymbol("nimNoArrayToCstringConversion")
defineSymbol("nimNewRoof")
+ defineSymbol("nimHasRunnableExamples")
+ defineSymbol("nimNewDot")
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index 36839bf0ba..caa18af92f 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -167,10 +167,13 @@ template interestingSym(s: PSym): bool =
proc patchHead(n: PNode) =
if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
let s = n[0].sym
- if sfFromGeneric in s.flags and s.name.s[0] == '=' and
- s.name.s in ["=sink", "=", "=destroy"]:
- excl(s.flags, sfFromGeneric)
- patchHead(s.getBody)
+ if s.name.s[0] == '=' and s.name.s in ["=sink", "=", "=destroy"]:
+ if sfFromGeneric in s.flags:
+ excl(s.flags, sfFromGeneric)
+ patchHead(s.getBody)
+ if n[1].typ.isNil:
+ # XXX toptree crashes without this workaround. Figure out why.
+ return
let t = n[1].typ.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred})
template patch(op, field) =
if s.name.s == op and field != nil and field != s:
@@ -181,24 +184,30 @@ proc patchHead(n: PNode) =
for x in n:
patchHead(x)
+proc patchHead(s: PSym) =
+ if sfFromGeneric in s.flags:
+ patchHead(s.ast[bodyPos])
+
+template genOp(opr, opname) =
+ let op = opr
+ if op == nil:
+ globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
+ elif op.ast[genericParamsPos].kind != nkEmpty:
+ globalError(dest.info, "internal error: '" & opname & "' operator is generic")
+ patchHead op
+ result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
+
proc genSink(t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias})
- let op = if t.sink != nil: t.sink else: t.assignment
- assert op != nil
- patchHead op.ast[bodyPos]
- result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
+ genOp(if t.sink != nil: t.sink else: t.assignment, "=sink")
proc genCopy(t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias})
- assert t.assignment != nil
- patchHead t.assignment.ast[bodyPos]
- result = newTree(nkCall, newSymNode(t.assignment), newTree(nkHiddenAddr, dest))
+ genOp(t.assignment, "=")
proc genDestroy(t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias})
- assert t.destructor != nil
- patchHead t.destructor.ast[bodyPos]
- result = newTree(nkCall, newSymNode(t.destructor), newTree(nkHiddenAddr, dest))
+ genOp(t.destructor, "=destroy")
proc addTopVar(c: var Con; v: PNode) =
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode)
@@ -210,7 +219,7 @@ template recurse(n, dest) =
dest.add p(n[i], c)
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
- if ri.kind in nkCallKinds:
+ if ri.kind in nkCallKinds+{nkObjConstr}:
result = genSink(ri.typ, dest)
# watch out and no not transform 'ri' twice if it's a call:
let ri2 = copyNode(ri)
@@ -287,6 +296,7 @@ proc p(n: PNode; c: var Con): PNode =
recurse(n, result)
proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
+ echo "injecting into ", n
var c: Con
c.owner = owner
c.tmp = newSym(skTemp, getIdent":d", owner, n.info)
@@ -312,7 +322,7 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
result.add body
when defined(nimDebugDestroys):
- if owner.name.s == "createSeq":
+ if owner.name.s == "main" or true:
echo "------------------------------------"
echo owner.name.s, " transformed to: "
echo result
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 8978052e2e..65dcb73c95 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -22,7 +22,6 @@ type
TSections = array[TSymKind, Rope]
TDocumentor = object of rstgen.RstGenerator
modDesc: Rope # module description
- id: int # for generating IDs
toc, section: TSections
indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist
@@ -109,6 +108,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.id = 100
result.jArray = newJArray()
initStrTable result.types
+ result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
+ localError(newLineInfo(d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: addf(dest, xml, args)
@@ -204,10 +205,87 @@ proc getPlainDocstring(n: PNode): string =
if n.comment != nil and startsWith(n.comment, "##"):
result = n.comment
if result.len < 1:
- if n.kind notin {nkEmpty..nkNilLit}:
- for i in countup(0, len(n)-1):
- result = getPlainDocstring(n.sons[i])
- if result.len > 0: return
+ for i in countup(0, safeLen(n)-1):
+ result = getPlainDocstring(n.sons[i])
+ if result.len > 0: return
+
+proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRenderFlags = {}) =
+ var r: TSrcGen
+ var literal = ""
+ initTokRender(r, n, renderFlags)
+ var kind = tkEof
+ while true:
+ getNextTok(r, kind, literal)
+ case kind
+ of tkEof:
+ break
+ of tkComment:
+ dispA(result, "$1", "\\spanComment{$1}",
+ [rope(esc(d.target, literal))])
+ of tokKeywordLow..tokKeywordHigh:
+ dispA(result, "$1", "\\spanKeyword{$1}",
+ [rope(literal)])
+ of tkOpr:
+ dispA(result, "$1", "\\spanOperator{$1}",
+ [rope(esc(d.target, literal))])
+ of tkStrLit..tkTripleStrLit:
+ dispA(result, "$1",
+ "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
+ of tkCharLit:
+ dispA(result, "$1", "\\spanCharLit{$1}",
+ [rope(esc(d.target, literal))])
+ of tkIntLit..tkUInt64Lit:
+ dispA(result, "$1",
+ "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
+ of tkFloatLit..tkFloat128Lit:
+ dispA(result, "$1",
+ "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
+ of tkSymbol:
+ dispA(result, "$1",
+ "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
+ of tkSpaces, tkInvalid:
+ add(result, literal)
+ of tkCurlyDotLe:
+ dispA(result, """$1
"""
+@end
doc.body_no_toc = """
$moduledesc
@@ -135,7 +184,7 @@ doc.file = """
-
+
@@ -168,18 +217,19 @@ html {
/* Where we want fancier font if available */
h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
- font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }
h1.title {
font-weight: 900; }
body {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-weight: 400;
- font-size: 14px;
+ font-size: 16px;
line-height: 20px;
- color: #666;
- background-color: rgba(252, 248, 244, 0.75); }
+ color: #444;
+ letter-spacing: 0.15px;
+ background-color: rgba(252, 248, 244, 0.45); }
/* Skeleton grid */
.container {
@@ -295,8 +345,8 @@ cite {
font-style: italic !important; }
dt > pre {
- border-color: rgba(0, 0, 0, 0.15);
- background-color: transparent;
+ border-color: rgba(0, 0, 0, 0.1);
+ background-color: rgba(255, 255, 255, 0.3);
margin: 15px 0px 5px; }
dd > pre {
@@ -313,6 +363,17 @@ dd > pre {
width: 100%;
table-layout: fixed; }
+/* Nim search input */
+div#searchInput {
+ margin-bottom: 8px;
+}
+div#searchInput input#searchInput {
+ width: 10em;
+}
+div.search-groupby {
+ margin-bottom: 8px;
+}
+
table.line-nums-table {
border-radius: 4px;
border: 1px solid #cccccc;
@@ -456,7 +517,7 @@ img {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }
p {
- margin: 0 0 12px; }
+ margin: 0 0 8px; }
small {
font-size: 85%; }
@@ -476,7 +537,7 @@ h3,
h4,
h5,
h6 {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-weight: 600;
line-height: 20px;
color: inherit;
@@ -484,6 +545,7 @@ h6 {
h1 {
font-size: 2em;
+ font-weight: 400;
padding-bottom: .15em;
border-bottom: 1px solid #aaaaaa;
margin-top: 1.0em;
@@ -614,13 +676,13 @@ pre {
box-sizing: border-box;
min-width: calc(100% - 19.5px);
padding: 9.5px;
- margin: 0.25em 10px 0.25em 10px;
- font-size: 14px;
+ margin: 0.25em 10px 10px 10px;
+ font-size: 15px;
line-height: 20px;
white-space: pre !important;
overflow-y: hidden;
overflow-x: visible;
- background-color: whitesmoke;
+ background-color: rgba(0, 0, 0, 0.01);
border: 1px solid #cccccc;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
@@ -899,14 +961,14 @@ div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold;
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: #b30000;
font-weight: bold;
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
@@ -953,7 +1015,7 @@ div.sidebar {
clear: right; }
div.sidebar p.rubric {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-size: medium; }
div.system-messages {
@@ -1060,12 +1122,12 @@ p.rubric {
text-align: center; }
p.sidebar-title {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-weight: bold;
font-size: larger; }
p.sidebar-subtitle {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-weight: bold; }
p.topic-title {
@@ -1107,15 +1169,15 @@ pre.code .inserted, code .inserted {
background-color: #A3D289; }
span.classifier {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-style: oblique; }
span.classifier-delimiter {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-weight: bold; }
span.interpreted {
- font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }
span.option {
white-space: nowrap; }
@@ -1138,7 +1200,7 @@ table.docinfo {
margin: 0em;
margin-top: 2em;
margin-bottom: 2em;
- font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
+ font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
color: #444444; }
table.docutils {
@@ -1268,15 +1330,15 @@ dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator
background-repeat: no-repeat;
background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
margin-bottom: -5px; }
- div.pragma {
- display: none;
- }
- span.pragmabegin {
- cursor: pointer;
- }
- span.pragmaend {
- cursor: pointer;
- }
+div.pragma {
+ display: none;
+}
+span.pragmabegin {
+ cursor: pointer;
+}
+span.pragmaend {
+ cursor: pointer;
+}
div.search_results {
background-color: antiquewhite;
@@ -1284,6 +1346,11 @@ div.search_results {
padding: 1em;
border: 1px solid #4d4d4d;
}
+
+div#global-links ul {
+ margin-left: 0;
+ list-style-type: none;
+}
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 60fd081b8a..ab10d65ba7 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -79,6 +79,7 @@ Advanced options:
symbol matching is fuzzy so
that --dynlibOverride:lua matches
dynlib: "liblua.so.3"
+ --dynlibOverrideAll makes the dynlib pragma have no effect
--listCmd list the commands used to execute external programs
--parallelBuild:0|1|... perform a parallel build
value = number of processors (0 for auto-detect)
diff --git a/doc/manual/special_ops.txt b/doc/manual/special_ops.txt
index 1c7136bec7..93977f81b8 100644
--- a/doc/manual/special_ops.txt
+++ b/doc/manual/special_ops.txt
@@ -17,8 +17,8 @@ or dynamic file formats such as JSON or XML.
When Nim encounters an expression that cannot be resolved by the
standard overload resolution rules, the current scope will be searched
for a dot operator that can be matched against a re-written form of
-the expression, where the unknown field or proc name is converted to
-an additional static string parameter:
+the expression, where the unknown field or proc name is passed to
+an ``untyped`` parameter:
.. code-block:: nim
a.b # becomes `.`(a, "b")
@@ -28,7 +28,7 @@ The matched dot operators can be symbols of any callable kind (procs,
templates and macros), depending on the desired effect:
.. code-block:: nim
- proc `.` (js: PJsonNode, field: string): JSON = js[field]
+ template `.` (js: PJsonNode, field: untyped): JSON = js[astToStr(field)]
var js = parseJson("{ x: 1, y: 2}")
echo js.x # outputs 1
diff --git a/doc/tut1.rst b/doc/tut1.rst
index 6731efde97..9e6f1ab3c2 100644
--- a/doc/tut1.rst
+++ b/doc/tut1.rst
@@ -30,6 +30,7 @@ The first program
We start the tour with a modified "hello world" program:
.. code-block:: Nim
+ :test: "nim c $1"
# This is a comment
echo "What's your name? "
var name: string = readLine(stdin)
@@ -72,6 +73,7 @@ you can leave out the type in the declaration (this is called `local type
inference`:idx:). So this will work too:
.. code-block:: Nim
+ :test: "nim c $1"
var name = readLine(stdin)
Note that this is basically the only form of type inference that exists in
@@ -116,6 +118,7 @@ Comments start anywhere outside a string or character literal with the
hash character ``#``. Documentation comments start with ``##``:
.. code-block:: nim
+ :test: "nim c $1"
# A comment.
var myVariable: int ## a documentation comment
@@ -129,6 +132,7 @@ Multiline comments are started with ``#[`` and terminated with ``]#``. Multilin
comments can also be nested.
.. code-block:: nim
+ :test: "nim c $1"
#[
You can have any Nim code text commented
out inside this with no indentation restrictions.
@@ -142,6 +146,7 @@ You can also use the `discard statement <#procedures-discard-statement>`_ togeth
literals* to create block comments:
.. code-block:: nim
+ :test: "nim c $1"
discard """ You can have any Nim code text commented
out inside this with no indentation restrictions.
yes("May I ask a pointless question?") """
@@ -169,6 +174,7 @@ Indentation can be used after the ``var`` keyword to list a whole section of
variables:
.. code-block::
+ :test: "nim c $1"
var
x, y: int
# a comment can occur here too
@@ -186,10 +192,11 @@ to a storage location:
x = "xyz" # assigns a new value to `x`
``=`` is the *assignment operator*. The assignment operator can be
-overloaded. You can declare multiple variables with a single assignment
+overloaded. You can declare multiple variables with a single assignment
statement and all the variables will have the same value:
.. code-block::
+ :test: "nim c $1"
var x, y = 3 # assigns 3 to the variables `x` and `y`
echo "x ", x # outputs "x 3"
echo "y ", y # outputs "y 3"
@@ -212,12 +219,14 @@ cannot change. The compiler must be able to evaluate the expression in a
constant declaration at compile time:
.. code-block:: nim
+ :test: "nim c $1"
const x = "abc" # the constant x contains the string "abc"
Indentation can be used after the ``const`` keyword to list a whole section of
constants:
.. code-block::
+ :test: "nim c $1"
const
x = 1
# a comment can occur here too
@@ -243,6 +252,7 @@ and put it into a data section":
const input = readLine(stdin) # Error: constant expression expected
.. code-block::
+ :test: "nim c $1"
let input = readLine(stdin) # works
@@ -260,6 +270,7 @@ If statement
The if statement is one way to branch the control flow:
.. code-block:: nim
+ :test: "nim c $1"
let name = readLine(stdin)
if name == "":
echo "Poor soul, you lost your name?"
@@ -281,6 +292,7 @@ Another way to branch is provided by the case statement. A case statement is
a multi-branch:
.. code-block:: nim
+ :test: "nim c $1"
let name = readLine(stdin)
case name
of "":
@@ -338,6 +350,7 @@ While statement
The while statement is a simple looping construct:
.. code-block:: nim
+ :test: "nim c $1"
echo "What's your name? "
var name = readLine(stdin)
@@ -358,6 +371,7 @@ provides. The example uses the built-in `countup `_
iterator:
.. code-block:: nim
+ :test: "nim c $1"
echo "Counting to ten: "
for i in countup(1, 10):
echo i
@@ -409,6 +423,7 @@ Other useful iterators for collections (like arrays and sequences) are
* ``pairs`` and ``mpairs`` which provides the element and an index number (immutable and mutable respectively)
.. code-block:: nim
+ :test: "nim c $1"
for index, item in ["a","b"].pairs:
echo item, " at index ", index
# => a at index 0
@@ -421,6 +436,8 @@ new scope. This means that in the following example, ``x`` is not accessible
outside the loop:
.. code-block:: nim
+ :test: "nim c $1"
+ :status: 1
while false:
var x = "hi"
echo x # does not work
@@ -430,6 +447,8 @@ are only visible within the block they have been declared. The ``block``
statement can be used to open a new block explicitly:
.. code-block:: nim
+ :test: "nim c $1"
+ :status: 1
block myblock:
var x = "hi"
echo x # does not work either
@@ -444,6 +463,7 @@ can leave a ``while``, ``for``, or a ``block`` statement. It leaves the
innermost construct, unless a label of a block is given:
.. code-block:: nim
+ :test: "nim c $1"
block myblock:
echo "entering block"
while true:
@@ -465,6 +485,7 @@ Like in many other programming languages, a ``continue`` statement starts
the next iteration immediately:
.. code-block:: nim
+ :test: "nim c $1"
while true:
let x = readLine(stdin)
if x == "": continue
@@ -477,6 +498,7 @@ When statement
Example:
.. code-block:: nim
+ :test: "nim c $1"
when system.hostOS == "windows":
echo "running on Windows!"
@@ -549,6 +571,7 @@ an expression is allowed:
.. code-block:: nim
# computes fac(4) at compile time:
+ :test: "nim c $1"
const fac4 = (var x = 1; for i in 1..4: x *= i; x)
@@ -561,6 +584,7 @@ is needed. (Some languages call them *methods* or *functions*.) In Nim new
procedures are defined with the ``proc`` keyword:
.. code-block:: nim
+ :test: "nim c $1"
proc yes(question: string): bool =
echo question, " (y/n)"
while true:
@@ -597,6 +621,7 @@ automatically at the end of a procedure if there is no ``return`` statement at
the exit.
.. code-block:: nim
+ :test: "nim c $1"
proc sumTillNegative(x: varargs[int]): int =
for i in x:
if i < 0:
@@ -624,6 +649,7 @@ to be declared with ``var`` in the procedure body. Shadowing the parameter name
is possible, and actually an idiom:
.. code-block:: nim
+ :test: "nim c $1"
proc printSeq(s: seq, nprinted: int = -1) =
var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
for i in 0 .. `_ returns the lowest valid index for the
array `a` and `high(a) `_ the highest valid index.
.. code-block:: nim
+ :test: "nim c $1"
type
Direction = enum
north, east, south, west
@@ -1228,6 +1270,7 @@ It is quite common to have arrays start at zero, so there's a shortcut syntax
to specify a range from zero to the specified index minus one:
.. code-block:: nim
+ :test: "nim c $1"
type
IntArray = array[0..5, int] # an array that is indexed with 0..5
QuickArray = array[6, int] # an array that is indexed with 0..5
@@ -1260,6 +1303,7 @@ A sequence may be passed to an openarray parameter.
Example:
.. code-block:: nim
+ :test: "nim c $1"
var
x: seq[int] # a reference to a sequence of integers
@@ -1282,6 +1326,7 @@ value. Here the ``for`` statement is looping over the results from the
`_ module. Examples:
.. code-block:: nim
+ :test: "nim c $1"
for value in @[3, 4, 5]:
echo value
# --> 3
@@ -1308,6 +1353,7 @@ with a compatible base type can be passed to an openarray parameter, the index
type does not matter.
.. code-block:: nim
+ :test: "nim c $1"
var
fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil'
capitals: array[3, string] # array of strings with a fixed size
@@ -1337,6 +1383,7 @@ arguments to a procedure. The compiler converts the list of arguments
to an array automatically:
.. code-block:: nim
+ :test: "nim c $1"
proc myWriteln(f: File, a: varargs[string]) =
for s in items(a):
write(f, s)
@@ -1351,6 +1398,7 @@ last parameter in the procedure header. It is also possible to perform
type conversions in this context:
.. code-block:: nim
+ :test: "nim c $1"
proc myWriteln(f: File, a: varargs[string, `$`]) =
for s in items(a):
write(f, s)
@@ -1374,6 +1422,7 @@ context. A slice is just an object of type Slice which contains two bounds,
define operators which accept Slice objects to define ranges.
.. code-block:: nim
+ :test: "nim c $1"
var
a = "Nim is a progamming language"
@@ -1388,27 +1437,31 @@ slice's bounds can hold any value supported by
their type, but it is the proc using the slice object which defines what values
are accepted.
- To understand some of the different ways of specifying the indices of strings, arrays, sequences, etc.,
- it must be remembered that Nim uses zero-based indices.
+To understand some of the different ways of specifying the indices of
+strings, arrays, sequences, etc., it must be remembered that Nim uses
+zero-based indices.
- So the string ``b`` is of length 19, and two different ways of specifying the indices are
+So the string ``b`` is of length 19, and two different ways of specifying the
+indices are
- .. code-block:: nim
+.. code-block:: nim
"Slices are useless."
| | |
0 11 17 using indices
^19 ^8 ^2 using ^ syntax
- where ``b[0..^1]`` is equivalent to ``b[0..b.len-1]`` and ``b[0..`_.
Distinct type
-------------
-A Distinct type allows for the creation of new type that "does not imply a subtype relationship between it and its base type".
+A Distinct type allows for the creation of new type that "does not imply a
+subtype relationship between it and its base type".
You must **explicitly** define all behaviour for the distinct type.
-To help with this, both the distinct type and its base type can cast from one type to the other.
+To help with this, both the distinct type and its base type can cast from one
+type to the other.
Examples are provided in the `manual `_.
Modules
@@ -1592,39 +1651,6 @@ Each module has a special magic constant ``isMainModule`` that is true if the
module is compiled as the main file. This is very useful to embed tests within
the module as shown by the above example.
-Modules that depend on each other are possible, but strongly discouraged,
-because then one module cannot be reused without the other.
-
-The algorithm for compiling modules is:
-
-- Compile the whole module as usual, following import statements recursively.
-- If there is a cycle only import the already parsed symbols (that are
- exported); if an unknown identifier occurs then abort.
-
-This is best illustrated by an example:
-
-.. code-block:: nim
- # Module A
- type
- T1* = int # Module A exports the type ``T1``
- import B # the compiler starts parsing B
-
- proc main() =
- var i = p(3) # works because B has been parsed completely here
-
- main()
-
-.. code-block:: nim
- # Module B
- import A # A is not parsed here! Only the already known symbols
- # of A are imported.
-
- proc p*(x: A.T1): A.T1 =
- # this works because the compiler has already
- # added T1 to A's interface symbol table
- result = x + 1
-
-
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. And if
a symbol is ambiguous, it *must* be qualified. A symbol is ambiguous
if it is defined in two (or more) different modules and both modules are
diff --git a/doc/tut2.rst b/doc/tut2.rst
index 0636c4ed6a..91cb528341 100644
--- a/doc/tut2.rst
+++ b/doc/tut2.rst
@@ -55,6 +55,7 @@ Objects have access to their type at runtime. There is an
``of`` operator that can be used to check the object's type:
.. code-block:: nim
+ :test: "nim c $1"
type
Person = ref object of RootObj
name*: string # the * means that `name` is accessible from other modules
@@ -103,6 +104,7 @@ would require arbitrary symbol lookahead which slows down compilation.)
Example:
.. code-block:: nim
+ :test: "nim c $1"
type
Node = ref object # a reference to an object with the following field:
le, ri: Node # left and right subtrees
@@ -144,6 +146,7 @@ variant types are needed.
An example:
.. code-block:: nim
+ :test: "nim c $1"
# This is an example how an abstract syntax tree could be modelled in Nim
type
@@ -201,9 +204,11 @@ This method call syntax is not restricted to objects, it can be used
for any type:
.. code-block:: nim
+ :test: "nim c $1"
+ import strutils
echo "abc".len # is the same as echo len("abc")
- echo "abc".toUpper()
+ echo "abc".toUpperAscii()
echo({'a', 'b', 'c'}.card)
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
@@ -213,6 +218,7 @@ postfix notation.)
So "pure object oriented" code is easy to write:
.. code-block:: nim
+ :test: "nim c $1"
import strutils, sequtils
stdout.writeLine("Give a list of numbers (separated by spaces): ")
@@ -228,6 +234,7 @@ the same. But setting a value is different; for this a special setter syntax
is needed:
.. code-block:: nim
+ :test: "nim c $1"
type
Socket* = ref object of RootObj
@@ -252,6 +259,7 @@ The ``[]`` array access operator can be overloaded to provide
`array properties`:idx:\ :
.. code-block:: nim
+ :test: "nim c $1"
type
Vector* = object
x, y, z: float
@@ -283,23 +291,24 @@ Procedures always use static dispatch. For dynamic dispatch replace the
``proc`` keyword by ``method``:
.. code-block:: nim
+ :test: "nim c $1"
type
- PExpr = ref object of RootObj ## abstract base class for an expression
- PLiteral = ref object of PExpr
+ Expression = ref object of RootObj ## abstract base class for an expression
+ Literal = ref object of Expression
x: int
- PPlusExpr = ref object of PExpr
- a, b: PExpr
+ PlusExpr = ref object of Expression
+ a, b: Expression
# watch out: 'eval' relies on dynamic binding
- method eval(e: PExpr): int =
+ method eval(e: Expression): int =
# override this base method
quit "to override!"
- method eval(e: PLiteral): int = e.x
- method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
+ method eval(e: Literal): int = e.x
+ method eval(e: PlusExpr): int = eval(e.a) + eval(e.b)
- proc newLit(x: int): PLiteral = PLiteral(x: x)
- proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
+ proc newLit(x: int): Literal = Literal(x: x)
+ proc newPlus(a, b: Expression): PlusExpr = PlusExpr(a: a, b: b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
@@ -311,6 +320,7 @@ In a multi-method all parameters that have an object type are used for the
dispatching:
.. code-block:: nim
+ :test: "nim c $1"
type
Thing = ref object of RootObj
@@ -365,6 +375,7 @@ Raise statement
Raising an exception is done with the ``raise`` statement:
.. code-block:: nim
+ :test: "nim c $1"
var
e: ref OSError
new(e)
@@ -385,6 +396,9 @@ Try statement
The ``try`` statement handles exceptions:
.. code-block:: nim
+ :test: "nim c $1"
+ from strutils import parseInt
+
# read the first two lines of a text file that should contain numbers
# and tries to add them
var
@@ -479,6 +493,7 @@ with `type parameters`:idx:. They are most useful for efficient type safe
containers:
.. code-block:: nim
+ :test: "nim c $1"
type
BinaryTree*[T] = ref object # BinaryTree is a generic type with
# generic param ``T``
@@ -573,6 +588,7 @@ Templates are especially useful for lazy evaluation purposes. Consider a
simple proc for logging:
.. code-block:: nim
+ :test: "nim c $1"
const
debug = true
@@ -590,6 +606,7 @@ evaluation for procedures is *eager*).
Turning the ``log`` proc into a template solves this problem:
.. code-block:: nim
+ :test: "nim c $1"
const
debug = true
@@ -611,6 +628,7 @@ If the template has no explicit return type,
To pass a block of statements to a template, use 'untyped' for the last parameter:
.. code-block:: nim
+ :test: "nim c $1"
template withFile(f: untyped, filename: string, mode: FileMode,
body: untyped): typed =
@@ -665,6 +683,7 @@ The following example implements a powerful ``debug`` command that accepts a
variable number of arguments:
.. code-block:: nim
+ :test: "nim c $1"
# to work with Nim syntax trees, we need an API that is defined in the
# ``macros`` module:
import macros
@@ -744,6 +763,7 @@ dynamic code into something that compiles statically. For the exercise we will
use the following snippet of code as the starting point:
.. code-block:: nim
+ :test: "nim c $1"
import strutils, tables
@@ -863,9 +883,9 @@ variables with ``cfg``. In essence, what the compiler is doing is replacing
the line calling the macro with the following snippet of code:
.. code-block:: nim
- const cfgversion= "1.1"
- const cfglicenseOwner= "Hyori Lee"
- const cfglicenseKey= "M1Tl3PjBWO2CC48m"
+ const cfgversion = "1.1"
+ const cfglicenseOwner = "Hyori Lee"
+ const cfglicenseKey = "M1Tl3PjBWO2CC48m"
You can verify this yourself adding the line ``echo source`` somewhere at the
end of the macro and compiling the program. Another difference is that instead
@@ -891,12 +911,13 @@ an expression macro. Since we know that we want to generate a bunch of
see what the compiler *expects* from us:
.. code-block:: nim
+ :test: "nim c $1"
import macros
dumpTree:
const cfgversion: string = "1.1"
- const cfglicenseOwner= "Hyori Lee"
- const cfglicenseKey= "M1Tl3PjBWO2CC48m"
+ const cfglicenseOwner = "Hyori Lee"
+ const cfglicenseKey = "M1Tl3PjBWO2CC48m"
During compilation of the source code we should see the following lines in the
output (again, since this is a macro, compilation is enough, you don't have to
@@ -996,6 +1017,7 @@ Lifting Procs
+++++++++++++
.. code-block:: nim
+ :test: "nim c $1"
import math
template liftScalarProc(fname) =
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index ebc9f77142..ee6c1a09ff 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1226,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/impure/re.nim b/lib/impure/re.nim
index 24fc83366d..c7f8f336bd 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -49,9 +49,6 @@ type
RegexError* = object of ValueError
## is raised if the pattern is no valid regular expression.
-{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
- EInvalidRegEx: RegexError].}
-
proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
var e: ref RegexError
new(e)
@@ -470,8 +467,8 @@ proc replacef*(s: string, sub: Regex, by: string): string =
prev = match.last + 1
add(result, substr(s, prev))
-proc parallelReplace*(s: string, subs: openArray[
- tuple[pattern: Regex, repl: string]]): string =
+proc multiReplace*(s: string, subs: openArray[
+ tuple[pattern: Regex, repl: string]]): string =
## Returns a modified copy of ``s`` with the substitutions in ``subs``
## applied in parallel.
result = ""
@@ -490,13 +487,20 @@ proc parallelReplace*(s: string, subs: openArray[
# copy the rest:
add(result, substr(s, i))
+proc parallelReplace*(s: string, subs: openArray[
+ tuple[pattern: Regex, repl: string]]): string {.deprecated.} =
+ ## Returns a modified copy of ``s`` with the substitutions in ``subs``
+ ## applied in parallel.
+ ## **Deprecated since version 0.18.0**: Use ``multiReplace`` instead.
+ result = multiReplace(s, subs)
+
proc transformFile*(infile, outfile: string,
subs: openArray[tuple[pattern: Regex, repl: string]]) =
## reads in the file ``infile``, performs a parallel replacement (calls
## ``parallelReplace``) and writes back to ``outfile``. Raises ``IOError`` if an
## error occurs. This is supposed to be used for quick scripting.
var x = readFile(infile).string
- writeFile(outfile, x.parallelReplace(subs))
+ writeFile(outfile, x.multiReplace(subs))
iterator split*(s: string, sep: Regex): string =
## Splits the string ``s`` into substrings.
@@ -579,12 +583,12 @@ const ## common regular expressions
## describes an URL
when isMainModule:
- doAssert match("(a b c)", re"\( .* \)")
+ doAssert match("(a b c)", rex"\( .* \)")
doAssert match("WHiLe", re("while", {reIgnoreCase}))
doAssert "0158787".match(re"\d+")
doAssert "ABC 0232".match(re"\w+\s+\d+")
- doAssert "ABC".match(re"\d+ | \w+")
+ doAssert "ABC".match(rex"\d+ | \w+")
{.push warnings:off.}
doAssert matchLen("key", re(reIdentifier)) == 3
diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim
index 13eb1e759e..f34efe9a29 100644
--- a/lib/js/jsffi.nim
+++ b/lib/js/jsffi.nim
@@ -177,7 +177,7 @@ proc `==`*(x, y: JsRoot): bool {. importcpp: "(# === #)" .}
## and not strings or numbers, this is a *comparison of references*.
{. experimental .}
-macro `.`*(obj: JsObject, field: static[cstring]): JsObject =
+macro `.`*(obj: JsObject, field: untyped): JsObject =
## Experimental dot accessor (get) for type JsObject.
## Returns the value of a property of name `field` from a JsObject `x`.
##
@@ -196,14 +196,14 @@ macro `.`*(obj: JsObject, field: static[cstring]): JsObject =
helper(`obj`)
else:
if not mangledNames.hasKey($field):
- mangledNames[$field] = $mangleJsName(field)
+ mangledNames[$field] = $mangleJsName($field)
let importString = "#." & mangledNames[$field]
result = quote do:
proc helper(o: JsObject): JsObject
{. importcpp: `importString`, gensym .}
helper(`obj`)
-macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
+macro `.=`*(obj: JsObject, field, value: untyped): untyped =
## Experimental dot accessor (set) for type JsObject.
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
if validJsName($field):
@@ -214,7 +214,7 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
helper(`obj`, `value`)
else:
if not mangledNames.hasKey($field):
- mangledNames[$field] = $mangleJsName(field)
+ mangledNames[$field] = $mangleJsName($field)
let importString = "#." & mangledNames[$field] & " = #"
result = quote do:
proc helper(o: JsObject, v: auto)
@@ -222,7 +222,7 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
helper(`obj`, `value`)
macro `.()`*(obj: JsObject,
- field: static[cstring],
+ field: untyped,
args: varargs[JsObject, jsFromAst]): JsObject =
## Experimental "method call" operator for type JsObject.
## Takes the name of a method of the JavaScript object (`field`) and calls
@@ -245,7 +245,7 @@ macro `.()`*(obj: JsObject,
importString = "#." & $field & "(@)"
else:
if not mangledNames.hasKey($field):
- mangledNames[$field] = $mangleJsName(field)
+ mangledNames[$field] = $mangleJsName($field)
importString = "#." & mangledNames[$field] & "(@)"
result = quote:
proc helper(o: JsObject): JsObject
@@ -257,7 +257,7 @@ macro `.()`*(obj: JsObject,
result[1].add args[idx].copyNimTree
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
- field: static[cstring]): V =
+ field: untyped): V =
## Experimental dot accessor (get) for type JsAssoc.
## Returns the value of a property of name `field` from a JsObject `x`.
var importString: string
@@ -265,7 +265,7 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
importString = "#." & $field
else:
if not mangledNames.hasKey($field):
- mangledNames[$field] = $mangleJsName(field)
+ mangledNames[$field] = $mangleJsName($field)
importString = "#." & mangledNames[$field]
result = quote do:
proc helper(o: type(`obj`)): `obj`.V
@@ -273,7 +273,7 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
helper(`obj`)
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
- field: static[cstring],
+ field: untyped,
value: V): untyped =
## Experimental dot accessor (set) for type JsAssoc.
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
@@ -282,7 +282,7 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
importString = "#." & $field & " = #"
else:
if not mangledNames.hasKey($field):
- mangledNames[$field] = $mangleJsName(field)
+ mangledNames[$field] = $mangleJsName($field)
importString = "#." & mangledNames[$field] & " = #"
result = quote do:
proc helper(o: type(`obj`), v: `obj`.V)
@@ -290,7 +290,7 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
helper(`obj`, `value`)
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
- field: static[cstring],
+ field: untyped,
args: varargs[untyped]): auto =
## Experimental "method call" operator for type JsAssoc.
## Takes the name of a method of the JavaScript object (`field`) and calls
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 76192713b9..ac2cc097c1 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -70,7 +70,7 @@ __clang__
#if defined(_MSC_VER)
# pragma warning(disable: 4005 4100 4101 4189 4191 4200 4244 4293 4296 4309)
# pragma warning(disable: 4310 4365 4456 4477 4514 4574 4611 4668 4702 4706)
-# pragma warning(disable: 4710 4711 4774 4800 4820 4996 4090)
+# pragma warning(disable: 4710 4711 4774 4800 4820 4996 4090 4297)
#endif
/* ------------------------------------------------------------------------- */
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index 70369b001d..2a58854a68 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -31,14 +31,12 @@ type
state: TokenClass
SourceLanguage* = enum
- langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava,
+ langNone, langNim, langCpp, langCsharp, langC, langJava,
langYaml
-{.deprecated: [TSourceLanguage: SourceLanguage, TTokenClass: TokenClass,
- TGeneralTokenizer: GeneralTokenizer].}
const
sourceLanguageToStr*: array[SourceLanguage, string] = ["none",
- "Nim", "Nimrod", "C++", "C#", "C", "Java", "Yaml"]
+ "Nim", "C++", "C#", "C", "Java", "Yaml"]
tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace",
"DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
"Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
@@ -398,7 +396,6 @@ type
TokenizerFlag = enum
hasPreprocessor, hasNestedComments
TokenizerFlags = set[TokenizerFlag]
-{.deprecated: [TTokenizerFlag: TokenizerFlag, TTokenizerFlags: TokenizerFlags].}
proc clikeNextToken(g: var GeneralTokenizer, keywords: openArray[string],
flags: TokenizerFlags) =
@@ -888,7 +885,7 @@ proc yamlNextToken(g: var GeneralTokenizer) =
proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) =
case lang
of langNone: assert false
- of langNim, langNimrod: nimNextToken(g)
+ of langNim: nimNextToken(g)
of langCpp: cppNextToken(g)
of langCsharp: csharpNextToken(g)
of langC: cNextToken(g)
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 53699166fb..223fc836a3 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -45,8 +45,6 @@ type
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
arg: string) {.nimcall.} ## what to do in case of an error
FindFileHandler* = proc (filename: string): string {.nimcall.}
-{.deprecated: [TRstParseOptions: RstParseOptions, TRstParseOption: RstParseOption,
- TMsgKind: MsgKind].}
const
messages: array[MsgKind, string] = [
@@ -127,8 +125,6 @@ type
bufpos*: int
line*, col*, baseIndent*: int
skipPounds*: bool
-{.deprecated: [TTokType: TokType, TToken: Token, TTokenSeq: TokenSeq,
- TLexer: Lexer].}
proc getThing(L: var Lexer, tok: var Token, s: set[char]) =
tok.kind = tkWord
@@ -288,10 +284,6 @@ type
hasToc*: bool
EParseError* = object of ValueError
-{.deprecated: [TLevelMap: LevelMap, TSubstitution: Substitution,
- TSharedState: SharedState, TRstParser: RstParser,
- TMsgHandler: MsgHandler, TFindFileHandler: FindFileHandler,
- TMsgClass: MsgClass].}
proc whichMsgClass*(k: MsgKind): MsgClass =
## returns which message class `k` belongs to.
@@ -341,11 +333,6 @@ proc rstMessage(p: RstParser, msgKind: MsgKind) =
p.col + p.tok[p.idx].col, msgKind,
p.tok[p.idx].symbol)
-when false:
- proc corrupt(p: RstParser) =
- assert p.indentStack[0] == 0
- for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
-
proc currInd(p: RstParser): int =
result = p.indentStack[high(p.indentStack)]
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 1272affdc8..e6c95b59ef 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -46,7 +46,7 @@ type
target*: OutputTarget
config*: StringTableRef
splitAfter*: int # split too long entries in the TOC
- listingCounter: int
+ listingCounter*: int
tocPart*: seq[TocEntry]
hasToc*: bool
theIndex: string # Contents of the index file to be dumped at the end.
@@ -61,6 +61,9 @@ type
seenIndexTerms: Table[string, int] ## \
## Keeps count of same text index terms to generate different identifiers
## for hyperlinks. See renderIndexTerm proc for details.
+ id*: int ## A counter useful for generating IDs.
+ onTestSnippet*: proc (d: var RstGenerator; filename, cmd: string; status: int;
+ content: string)
PDoc = var RstGenerator ## Alias to type less.
@@ -69,8 +72,9 @@ type
startLine: int ## The starting line of the code block, by default 1.
langStr: string ## Input string used to specify the language.
lang: SourceLanguage ## Type of highlighting, by default none.
-{.deprecated: [TRstGenerator: RstGenerator, TTocEntry: TocEntry,
- TOutputTarget: OutputTarget, TMetaEnum: MetaEnum].}
+ filename: string
+ testCmd: string
+ status: int
proc init(p: var CodeBlockParams) =
## Default initialisation of CodeBlockParams to sane values.
@@ -133,6 +137,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
g.options = options
g.findFile = findFile
g.currentSection = ""
+ g.id = 0
let fileParts = filename.splitFile
if fileParts.ext == ".nim":
g.currentSection = "Module " & fileParts.name
@@ -368,7 +373,6 @@ type
##
## The value indexed by this IndexEntry is a sequence with the real index
## entries found in the ``.idx`` file.
-{.deprecated: [TIndexEntry: IndexEntry, TIndexedDocs: IndexedDocs].}
proc cmp(a, b: IndexEntry): int =
## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`.
@@ -823,13 +827,20 @@ proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
var number: int
if parseInt(n.getFieldValue, number) > 0:
params.startLine = number
- of "file":
+ of "file", "filename":
# The ``file`` option is a Nim extension to the official spec, it acts
# like it would for other directives like ``raw`` or ``cvs-table``. This
# field is dealt with in ``rst.nim`` which replaces the existing block with
# the referenced file, so we only need to ignore it here to avoid incorrect
# warning messages.
- discard
+ params.filename = n.getFieldValue.strip
+ of "test":
+ params.testCmd = n.getFieldValue.strip
+ if params.testCmd.len == 0: params.testCmd = "nim c -r $1"
+ of "status":
+ var status: int
+ if parseInt(n.getFieldValue, status) > 0:
+ params.status = status
of "default-language":
params.langStr = n.getFieldValue.strip
params.lang = params.langStr.getSourceLanguage
@@ -901,6 +912,9 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
var m = n.sons[2].sons[0]
assert m.kind == rnLeaf
+ if params.testCmd.len > 0 and d.onTestSnippet != nil:
+ d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text)
+
let (blockStart, blockEnd) = buildLinesHTMLTable(d, params, m.text)
dispA(d.target, result, blockStart, "\\begin{rstpre}\n", [])
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 65004cbe0e..d48274bb99 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -59,9 +59,10 @@ export asyncfutures, asyncstreams
##
## .. code-block::nim
## var future = socket.recv(100)
-## future.callback =
+## future.addCallback(
## proc () =
## echo(future.read)
+## )
##
## All asynchronous functions returning a ``Future`` will not block. They
## will not however return immediately. An asynchronous function will have
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index 8941dca6ed..82bc53aaff 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -334,7 +334,7 @@ proc all*[T](futs: varargs[Future[T]]): auto =
let totalFutures = len(futs)
for fut in futs:
- fut.callback = proc(f: Future[T]) =
+ fut.addCallback proc (f: Future[T]) =
inc(completedFutures)
if not retFuture.finished:
if f.failed:
@@ -356,7 +356,7 @@ proc all*[T](futs: varargs[Future[T]]): auto =
for i, fut in futs:
proc setCallback(i: int) =
- fut.callback = proc(f: Future[T]) =
+ fut.addCallback proc (f: Future[T]) =
inc(completedFutures)
if not retFuture.finished:
if f.failed:
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 433931c9de..ba16156515 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -275,10 +275,7 @@ proc processClient(server: AsyncHttpServer, client: AsyncSocket, address: string
lineFut.mget() = newStringOfCap(80)
while not client.isClosed:
- try:
- await processRequest(server, request, client, address, lineFut, callback)
- except:
- asyncCheck request.mget().respondError(Http500)
+ await processRequest(server, request, client, address, lineFut, callback)
proc serve*(server: AsyncHttpServer, port: Port,
callback: proc (request: Request): Future[void] {.closure,gcsafe.},
diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim
index d1207603d2..3f213c5ea3 100644
--- a/lib/pure/bitops.nim
+++ b/lib/pure/bitops.nim
@@ -181,7 +181,7 @@ elif useICC_builtins:
proc countSetBits*(x: SomeInteger): int {.inline, nosideeffect.} =
- ## Counts the set bits in integer. (also called Hamming weight.)
+ ## Counts the set bits in integer. (also called `Hamming weight`:idx:.)
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
# like GCC and MSVC
when nimvm:
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index fcf2cf99f5..5de6aa4870 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -29,21 +29,8 @@
## writeLine(stdout, "your password: " & myData["password"])
## writeLine(stdout, "