Merge remote-tracking branch 'upstream/devel' into version-0-20

This commit is contained in:
narimiran
2019-06-11 12:13:57 +02:00
32 changed files with 832 additions and 460 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: 'nim' # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: 'https://nim-lang.org/donate.html' # Replace with a single custom sponsorship URL

View File

@@ -1,294 +1,33 @@
## v0.20.0 - 2019-06-06
## v0.20.2 - XXXX-XX-XX
### Changes affecting backwards compatibility
- `shr` is now sign preserving. Use `-d:nimOldShiftRight` to enable
the old behavior globally.
- The ``isLower``, ``isUpper`` family of procs in strutils/unicode
operating on **strings** have been
deprecated since it was unclear what these do. Note that the much more
useful procs that operate on ``char`` or ``Rune`` are not affected.
- `strutils.editDistance` has been deprecated,
use `editdistance.editDistance` or `editdistance.editDistanceAscii`
instead.
- The OpenMP parallel iterator \``||`\` now supports any `#pragma omp directive`
and not just `#pragma omp parallel for`. See
[OpenMP documentation](https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf).
The default annotation is `parallel for`, if you used OpenMP without annotation
the change is transparent, if you used annotations you will have to prefix
your previous annotations with `parallel for`.
Furthermore, an overload with positive stepping is available.
- The `unchecked` pragma was removed, instead use `system.UncheckedArray`.
- The undocumented ``#? strongSpaces`` parsing mode has been removed.
- The `not` operator is now always a unary operator, this means that code like
``assert not isFalse(3)`` compiles.
- `getImpl` on a `var` or `let` symbol will now return the full `IdentDefs`
tree from the symbol declaration instead of just the initializer portion.
- Methods are now ordinary "single" methods, only the first parameter is
used to select the variant at runtime. For backwards compatibility
use the new `--multimethods:on` switch.
- Generic methods are now deprecated; they never worked well.
- Compile time checks for integer and float conversions are now stricter.
For example, `const x = uint32(-1)` now gives a compile time error instead
of being equivalent to `const x = 0xFFFFFFFF'u32`.
- Using `typed` as the result type in templates/macros now means
"expression with a type". The old meaning of `typed` is preserved
as `void` or no result type at all.
- A bug allowed `macro foo(): int = 123` to compile even though a
macro has to return a `NimNode`. This has been fixed.
- With the exception of `uint` and `uint64`, conversion to unsigned types
are now range checked during runtime.
- Macro arguments of type `typedesc` are now passed to the macro as
`NimNode` like every other type except `static`. Use `typed` for a
behavior that is identical in new and old
Nim. See the RFC [Pass typedesc as NimNode to macros](https://github.com/nim-lang/RFCs/issues/148)
for more details.
#### Breaking changes in the standard library
- `osproc.execProcess` now also takes a `workingDir` parameter.
- `std/sha1.secureHash` now accepts `openArray[char]`, not `string`. (Former
successful matches should keep working, though former failures will not.)
- `options.UnpackError` is no longer a ref type and inherits from `system.Defect`
instead of `system.ValueError`.
- `system.ValueError` now inherits from `system.CatchableError` instead of `system.Defect`.
- The procs `parseutils.parseBiggestInt`, `parseutils.parseInt`,
`parseutils.parseBiggestUInt` and `parseutils.parseUInt` now raise a
`ValueError` when the parsed integer is outside of the valid range.
Previously they sometimes raised an `OverflowError` and sometimes they
returned `0`.
- The procs `parseutils.parseBin`, `parseutils.parseOct` and `parseutils.parseHex`
were not clearing their `var` parameter `number` and used to push its value to
the left when storing the parsed string into it. Now they always set the value
of the parameter to `0` before storing the result of the parsing, unless the
string to parse is not valid (then the value of `number` is not changed).
- `streams.StreamObject` now restricts its fields to only raise `system.Defect`,
`system.IOError` and `system.OSError`.
This change only affects custom stream implementations.
- nre's `RegexMatch.{captureBounds,captures}[]` no longer return `Option` or
`nil`/`""`, respectively. Use the newly added `n in p.captures` method to
check if a group is captured, otherwise you'll receive an exception.
- nre's `RegexMatch.{captureBounds,captures}.toTable` no longer accept a
default parameter. Instead uncaptured entries are left empty. Use
`Table.getOrDefault()` if you need defaults.
- nre's `RegexMatch.captures.{items,toSeq}` now returns an `Option[string]`
instead of a `string`. With the removal of `nil` strings, this is the only
way to indicate a missing match. Inside your loops, instead
of `capture == ""` or `capture == nil`, use `capture.isSome` to check if a capture is
present, and `capture.get` to get its value.
- nre's `replace()` no longer throws `ValueError` when the replacement string
has missing captures. It instead throws `KeyError` for named captures, and
`IndexError` for unnamed captures. This is consistent with
`RegexMatch.{captureBounds,captures}[]`.
- `splitFile` now correctly handles edge cases, see #10047.
- `isNil` is no longer false for undefined in the JavaScript backend:
now it's true for both nil and undefined.
Use `isNull` or `isUndefined` if you need exact equality:
`isNil` is consistent with `===`, `isNull` and `isUndefined` with `==`.
- several deprecated modules were removed: `ssl`, `matchers`, `httpserver`,
`unsigned`, `actors`, `parseurl`
- two poorly documented and not used modules (`subexes`, `scgi`) were moved to
graveyard (they are available as Nimble packages)
- procs `string.add(int)` and `string.add(float)` which implicitly convert
ints and floats to string have been deprecated.
Use `string.addInt(int)` and `string.addFloat(float)` instead.
- ``case object`` branch transitions via ``system.reset`` are deprecated.
Compile your code with ``-d:nimOldCaseObjects`` for a transition period.
- base64 module: The default parameter `newLine` for the `encode` procs
was changed from `"\13\10"` to the empty string `""`.
#### Breaking changes in the compiler
- The compiler now implements the "generic symbol prepass" for `when` statements
in generics, see bug #8603. This means that code like this does not compile
anymore:
```nim
proc enumToString*(enums: openArray[enum]): string =
# typo: 'e' instead 'enums'
when e.low.ord >= 0 and e.high.ord < 256:
result = newString(enums.len)
else:
result = newString(enums.len * 2)
```
- ``discard x`` is now illegal when `x` is a function symbol.
- Implicit imports via ``--import: module`` in a config file are now restricted
to the main package.
### Library additions
- There is a new stdlib module `std/editdistance` as a replacement for the
deprecated `strutils.editDistance`.
- There is a new stdlib module `std/wordwrap` as a replacement for the
deprecated `strutils.wordwrap`.
- Added `split`, `splitWhitespace`, `size`, `alignLeft`, `align`,
`strip`, `repeat` procs and iterators to `unicode.nim`.
- Added `or` for `NimNode` in `macros`.
- Added `system.typeof` for more control over how `type` expressions
can be deduced.
- Added `macros.isInstantiationOf` for checking if the proc symbol
is instantiation of generic proc symbol.
- Added the parameter ``isSorted`` for the ``sequtils.deduplicate`` proc.
- There is a new stdlib module `std/diff` to compute the famous "diff"
of two texts by line.
- Added `os.relativePath`.
- Added `parseopt.remainingArgs`.
- Added `os.getCurrentCompilerExe` (implemented as `getAppFilename` at CT),
can be used to retrieve the currently executing compiler.
- Added `xmltree.toXmlAttributes`.
- Added ``std/sums`` module for fast summation functions.
- Added `Rusage`, `getrusage`, `wait4` to the posix interface.
- Added the `posix_utils` module.
- Added `system.default`.
- Added `sequtils.items` for closure iterators, allows closure iterators
to be used by the `mapIt`, `filterIt`, `allIt`, `anyIt`, etc.
### Library changes
- The string output of `macros.lispRepr` proc has been tweaked
slightly. The `dumpLisp` macro in this module now outputs an
indented proper Lisp, devoid of commas.
- Added `macros.signatureHash` that returns a stable identifier
derived from the signature of a symbol.
- In `strutils` empty strings now no longer matched as substrings
anymore.
- The `Complex` type is now a generic object and not a tuple anymore.
- The `ospaths` module is now deprecated, use `os` instead. Note that
`os` is available in a NimScript environment but unsupported
operations produce a compile-time error.
- The `parseopt` module now supports a new flag `allowWhitespaceAfterColon`
(default value: true) that can be set to `false` for better Posix
interoperability. (Bug #9619.)
- `os.joinPath` and `os.normalizePath` handle edge cases like ``"a/b/../../.."``
differently.
- `securehash` was moved to `lib/deprecated`.
- The switch ``-d:useWinAnsi`` is not supported anymore.
- In `times` module, procs `format` and `parse` accept a new optional
`DateTimeLocale` argument for formatting/parsing dates in other languages.
### Language additions
- Vm support for float32<->int32 and float64<->int64 casts was added.
- There is a new pragma block `noSideEffect` that works like
the `gcsafe` pragma block.
- added `os.getCurrentProcessId`.
- User defined pragmas are now allowed in the pragma blocks.
- Pragma blocks are no longer eliminated from the typed AST tree to preserve
pragmas for further analysis by macros.
- Custom pragmas are now supported for `var` and `let` symbols.
- Tuple unpacking is now supported for constants and for loop variables.
- Case object branches can be initialized with a runtime discriminator if
possible discriminator values are constrained within a case statement.
### Language changes
- The standard extension for SCF (source code filters) files was changed from
``.tmpl`` to ``.nimf``,
it's more recognizable and allows tools like Github to recognize it as Nim,
see [#9647](https://github.com/nim-lang/Nim/issues/9647).
The previous extension will continue to work.
- Pragma syntax is now consistent. Previous syntax where type pragmas did not
follow the type name is now deprecated. Also pragma before generic parameter
list is deprecated to be consistent with how pragmas are used with a proc. See
[#8514](https://github.com/nim-lang/Nim/issues/8514) and
[#1872](https://github.com/nim-lang/Nim/issues/1872) for further details.
- Hash sets and tables are initialized by default. The explicit `initHashSet`,
`initTable`, etc. are not needed anymore.
### Tool changes
- `jsondoc` now includes a `moduleDescription` field with the module
description. `jsondoc0` shows comments as its own objects as shown in the
documentation.
- `nimpretty`: --backup now defaults to `off` instead of `on` and the flag was
undocumented; use `git` instead of relying on backup files.
- `koch` now defaults to build the latest *stable* Nimble version unless you
explicitly ask for the latest master version via `--latest`.
### Compiler changes
- The deprecated `fmod` proc is now unavailable on the VM.
- A new `--outdir` option was added.
- The compiled JavaScript file for the project produced by executing `nim js`
will no longer be placed in the nimcache directory.
- The `--hotCodeReloading` has been implemented for the native targets.
The compiler also provides a new more flexible API for handling the
hot code reloading events in the code.
- The compiler now supports a ``--expandMacro:macroNameHere`` switch
for easy introspection into what a macro expands into.
- The `-d:release` switch now does not disable runtime checks anymore.
For a release build that also disables runtime checks
use `-d:release -d:danger` or simply `-d:danger`.
### Bugfixes

View File

@@ -12,10 +12,10 @@
import idents, lexer, lineinfos, llstream, options, msgs, strutils,
pathutils
from os import changeFileExt
from sequtils import delete
const
MaxLineLen = 80
LineCommentColumn = 30
type
SplitKind = enum
@@ -24,6 +24,12 @@ type
SemicolonKind = enum
detectSemicolonKind, useSemicolon, dontTouch
LayoutToken = enum
ltSpaces, ltNewline, ltTab,
ltComment, ltLit, ltKeyword, ltExportMarker, ltIdent,
ltOther, ltOpr,
ltBeginSection, ltEndSection
Emitter* = object
config: ConfigRef
fid: FileIndex
@@ -33,7 +39,8 @@ type
col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
keepIndents*: int
doIndentMore*: int
content: string
kinds: seq[LayoutToken]
tokens: seq[string]
indentStack: seq[int]
fixedUntil: int # marks where we must not go in the content
altSplitPos: array[SplitKind, int] # alternative split positions
@@ -50,21 +57,72 @@ proc openEmitter*(em: var Emitter, cache: IdentCache;
em.lastTok = tkInvalid
em.inquote = false
em.col = 0
em.content = newStringOfCap(16_000)
em.indentStack = newSeqOfCap[int](30)
em.indentStack.add 0
em.lastLineNumber = 1
proc computeMax(em: Emitter; pos: int): int =
var p = pos
result = 0
while p < em.tokens.len and em.kinds[p] != ltEndSection:
var lhs = 0
var lineLen = 0
var foundTab = false
while p < em.tokens.len and em.kinds[p] != ltEndSection:
if em.kinds[p] == ltNewline:
if foundTab and lineLen <= MaxLineLen: result = max(result, lhs)
inc p
break
if em.kinds[p] == ltTab:
foundTab = true
else:
if not foundTab:
inc lhs, em.tokens[p].len
inc lineLen, em.tokens[p].len
inc p
proc computeRhs(em: Emitter; pos: int): int =
var p = pos
result = 0
while p < em.tokens.len and em.kinds[p] != ltNewline:
inc result, em.tokens[p].len
inc p
proc closeEmitter*(em: var Emitter) =
let outFile = em.config.absOutFile
if fileExists(outFile) and readFile(outFile.string) == em.content:
var content = newStringOfCap(16_000)
var maxLhs = 0
var lineLen = 0
var lineBegin = 0
for i in 0..em.tokens.high:
case em.kinds[i]
of ltBeginSection:
maxLhs = computeMax(em, lineBegin)
of ltEndSection:
maxLhs = 0
of ltTab:
if maxLhs == 0 or computeRhs(em, i)+maxLhs > MaxLineLen:
content.add ' '
else:
let spaces = max(maxLhs - lineLen + 1, 1)
for j in 1..spaces: content.add ' '
of ltNewline:
content.add em.tokens[i]
lineLen = 0
lineBegin = i+1
else:
content.add em.tokens[i]
inc lineLen, em.tokens[i].len
if fileExists(outFile) and readFile(outFile.string) == content:
discard "do nothing, see #9499"
return
var f = llStreamOpen(outFile, fmWrite)
if f == nil:
rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string)
return
f.llStreamWrite em.content
f.llStreamWrite content
llStreamClose(f)
proc countNewlines(s: string): int =
@@ -79,9 +137,36 @@ proc calcCol(em: var Emitter; s: string) =
dec i
inc em.col
template wr(x) =
em.content.add x
proc wr(em: var Emitter; x: string; lt: LayoutToken) =
em.tokens.add x
em.kinds.add lt
inc em.col, x.len
assert em.tokens.len == em.kinds.len
proc wrNewline(em: var Emitter) =
em.tokens.add "\L"
em.kinds.add ltNewline
em.col = 0
proc wrSpaces(em: var Emitter; spaces: int) =
if spaces > 0:
wr(em, strutils.repeat(' ', spaces), ltSpaces)
proc wrSpace(em: var Emitter) =
wr(em, " ", ltSpaces)
proc wrTab(em: var Emitter) =
wr(em, " ", ltTab)
proc beginSection*(em: var Emitter) = wr(em, "", ltBeginSection)
proc endSection*(em: var Emitter) = wr(em, "", ltEndSection)
proc removeSpaces(em: var Emitter) =
while em.kinds.len > 0 and em.kinds[^1] == ltSpaces:
let tokenLen = em.tokens[^1].len
setLen(em.tokens, em.tokens.len-1)
setLen(em.kinds, em.kinds.len-1)
dec em.col, tokenLen
template goodCol(col): bool = col in 40..MaxLineLen
@@ -89,13 +174,17 @@ const
openPars = {tkParLe, tkParDotLe,
tkBracketLe, tkBracketLeColon, tkCurlyDotLe,
tkCurlyLe}
closedPars = {tkParRi, tkParDotRi,
tkBracketRi, tkCurlyDotRi,
tkCurlyRi}
splitters = openPars + {tkComma, tkSemicolon}
oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
template rememberSplit(kind) =
if goodCol(em.col):
em.altSplitPos[kind] = em.content.len
em.altSplitPos[kind] = em.tokens.len
template moreIndent(em): int =
(if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth)
@@ -106,54 +195,109 @@ proc softLinebreak(em: var Emitter, lit: string) =
# +2 because we blindly assume a comma or ' &' might follow
if not em.inquote and em.col+lit.len+2 >= MaxLineLen:
if em.lastTok in splitters:
while em.content.len > 0 and em.content[em.content.high] == ' ':
setLen(em.content, em.content.len-1)
wr("\L")
em.col = 0
for i in 1..em.indentLevel+moreIndent(em): wr(" ")
# bug #10295, check first if even more indentation would help:
let spaces = em.indentLevel+moreIndent(em)
if spaces < em.col:
removeSpaces em
wrNewline(em)
em.col = 0
wrSpaces em, spaces
else:
# search backwards for a good split position:
for a in mitems(em.altSplitPos):
if a > em.fixedUntil:
var spaces = 0
while a+spaces < em.content.len and em.content[a+spaces] == ' ':
while a+spaces < em.kinds.len and em.kinds[a+spaces] == ltSpaces:
inc spaces
if spaces > 0: delete(em.content, a, a+spaces-1)
em.col = em.content.len - a
let ws = "\L" & repeat(' ', em.indentLevel+moreIndent(em))
em.content.insert(ws, a)
if spaces > 0:
delete(em.tokens, a, a+spaces-1)
delete(em.kinds, a, a+spaces-1)
em.kinds.insert(ltNewline, a)
em.tokens.insert("\L", a)
em.kinds.insert(ltSpaces, a+1)
em.tokens.insert(repeat(' ', em.indentLevel+moreIndent(em)), a+1)
# recompute em.col:
var i = em.kinds.len-1
em.col = 0
while i >= 0 and em.kinds[i] != ltNewline:
inc em.col, em.tokens[i].len
dec i
# mark position as "already split here"
a = -1
break
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
proc emitMultilineComment(em: var Emitter, lit: string, col: int) =
# re-align every line in the multi-line comment:
var i = 0
var lastIndent = em.indentStack[^1]
var b = 0
for commentLine in splitLines(lit):
let stripped = commentLine.strip()
var a = 0
while a < commentLine.len and commentLine[a] == ' ': inc a
if i == 0:
discard
elif stripped.len == 0:
wrNewline em
else:
if a > lastIndent:
b += em.indWidth
lastIndent = a
elif a < lastIndent:
b -= em.indWidth
lastIndent = a
wrNewline em
wrSpaces em, col + b
wr em, stripped, ltComment
inc i
template endsInWhite(em): bool =
em.content.len == 0 or em.content[em.content.high] in {' ', '\L'}
template endsInAlpha(em): bool =
em.content.len > 0 and em.content[em.content.high] in SymChars+{'_'}
proc lastChar(s: string): char =
result = if s.len > 0: s[s.high] else: '\0'
proc emitComment(em: var Emitter; tok: TToken) =
let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
proc endsInWhite(em: Emitter): bool =
var i = em.tokens.len-1
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i)
result = if i >= 0: em.kinds[i] in {ltSpaces, ltNewline, ltTab} else: true
proc endsInNewline(em: Emitter): bool =
var i = em.tokens.len-1
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection, ltSpaces}: dec(i)
result = if i >= 0: em.kinds[i] in {ltNewline, ltTab} else: true
proc endsInAlpha(em: Emitter): bool =
var i = em.tokens.len-1
while i >= 0 and em.kinds[i] in {ltBeginSection, ltEndSection}: dec(i)
result = if i >= 0: em.tokens[i].lastChar in SymChars+{'_'} else: false
proc emitComment(em: var Emitter; tok: TToken) =
let col = em.col
let lit = strip fileSection(em.config, em.fid, tok.commentOffsetA, tok.commentOffsetB)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
if em.lineSpan == 0:
if not endsInNewline(em):
wrTab em
wr em, lit, ltComment
else:
if not endsInWhite(em):
wr(" ")
if em.lineSpan == 0 and max(em.col, LineCommentColumn) + lit.len <= MaxLineLen:
for i in 1 .. LineCommentColumn - em.col: wr(" ")
wr lit
wrTab em
emitMultilineComment(em, lit, col)
proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
template wasExportMarker(em): bool =
em.kinds.len > 0 and em.kinds[^1] == ltExportMarker
if tok.tokType == tkComment and tok.literal.startsWith("#!nimpretty"):
case tok.literal
of "#!nimpretty off":
inc em.keepIndents
wr("\L")
wrNewline em
em.lastLineNumber = tok.line + 1
of "#!nimpretty on":
dec em.keepIndents
em.lastLineNumber = tok.line
wr("\L")
#for i in 1 .. tok.indent: wr " "
wr tok.literal
wrNewline em
wr em, tok.literal, ltComment
em.col = 0
em.lineSpan = 0
return
@@ -163,11 +307,15 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
# we have an inline comment so handle it before the indentation token:
emitComment(em, tok)
preventComment = true
em.fixedUntil = em.content.high
em.fixedUntil = em.tokens.high
elif tok.indent >= 0:
if em.lastTok in (splitters + oprSet) or em.keepIndents > 0:
if em.keepIndents > 0:
em.indentLevel = tok.indent
elif (em.lastTok in (splitters + oprSet) and tok.tokType notin closedPars):
# aka: we are in an expression context:
let alignment = tok.indent - em.indentStack[^1]
em.indentLevel = alignment + em.indentStack.high * em.indWidth
else:
if tok.indent > em.indentStack[^1]:
em.indentStack.add tok.indent
@@ -186,51 +334,48 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
is not touched.
]#
# remove trailing whitespace:
while em.content.len > 0 and em.content[em.content.high] == ' ':
setLen(em.content, em.content.len-1)
wr("\L")
for i in 2..tok.line - em.lastLineNumber: wr("\L")
em.col = 0
for i in 1..em.indentLevel:
wr(" ")
em.fixedUntil = em.content.high
removeSpaces em
wrNewline em
for i in 2..tok.line - em.lastLineNumber: wrNewline(em)
wrSpaces em, em.indentLevel
em.fixedUntil = em.tokens.high
var lastTokWasTerse = false
case tok.tokType
of tokKeywordLow..tokKeywordHigh:
if endsInAlpha(em):
wr(" ")
wrSpace em
elif not em.inquote and not endsInWhite(em) and
em.lastTok notin openPars and not em.lastTokWasTerse:
#and tok.tokType in oprSet
wr(" ")
wrSpace em
if not em.inquote:
wr(TokTypeToStr[tok.tokType])
wr(em, TokTypeToStr[tok.tokType], ltKeyword)
case tok.tokType
of tkAnd: rememberSplit(splitAnd)
of tkOr: rememberSplit(splitOr)
of tkIn, tkNotin:
rememberSplit(splitIn)
wr(" ")
wrSpace em
else: discard
else:
# keywords in backticks are not normalized:
wr(tok.ident.s)
wr(em, tok.ident.s, ltIdent)
of tkColon:
wr(TokTypeToStr[tok.tokType])
wr(" ")
wr(em, TokTypeToStr[tok.tokType], ltOther)
wrSpace em
of tkSemicolon, tkComma:
wr(TokTypeToStr[tok.tokType])
wr(em, TokTypeToStr[tok.tokType], ltOther)
rememberSplit(splitComma)
wr(" ")
wrSpace em
of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe,
tkCurlyLe, tkCurlyDotLe, tkBracketLeColon:
if tok.strongSpaceA > 0 and not em.endsInWhite:
wr(" ")
wr(TokTypeToStr[tok.tokType])
if tok.strongSpaceA > 0 and not em.endsInWhite and not em.wasExportMarker:
wrSpace em
wr(em, TokTypeToStr[tok.tokType], ltOther)
rememberSplit(splitParLe)
of tkParRi,
tkBracketRi, tkCurlyRi,
@@ -238,33 +383,33 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
tkCurlyDotRi,
tkParDotRi,
tkColonColon:
wr(TokTypeToStr[tok.tokType])
wr(em, TokTypeToStr[tok.tokType], ltOther)
of tkDot:
lastTokWasTerse = true
wr(TokTypeToStr[tok.tokType])
wr(em, TokTypeToStr[tok.tokType], ltOther)
of tkEquals:
if not em.inquote and not em.endsInWhite: wr(" ")
wr(TokTypeToStr[tok.tokType])
if not em.inquote: wr(" ")
if not em.inquote and not em.endsInWhite: wrSpace(em)
wr(em, TokTypeToStr[tok.tokType], ltOther)
if not em.inquote: wrSpace(em)
of tkOpr, tkDotDot:
if ((tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote) and
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]:
# bug #9504: remember to not spacify a keyword:
lastTokWasTerse = true
# if not surrounded by whitespace, don't produce any whitespace either:
wr(tok.ident.s)
wr(em, tok.ident.s, ltOpr)
else:
if not em.endsInWhite: wr(" ")
wr(tok.ident.s)
if not em.endsInWhite: wrSpace(em)
wr(em, tok.ident.s, ltOpr)
template isUnary(tok): bool =
tok.strongSpaceB == 0 and tok.strongSpaceA > 0
if not isUnary(tok):
rememberSplit(splitBinary)
wr(" ")
wrSpace(em)
of tkAccent:
if not em.inquote and endsInAlpha(em): wr(" ")
wr(TokTypeToStr[tok.tokType])
if not em.inquote and endsInAlpha(em): wrSpace(em)
wr(em, TokTypeToStr[tok.tokType], ltOther)
em.inquote = not em.inquote
of tkComment:
if not preventComment:
@@ -272,36 +417,43 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit:
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
softLinebreak(em, lit)
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wr(" ")
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
wr lit
wr em, lit, ltLit
of tkEof: discard
else:
let lit = if tok.ident != nil: tok.ident.s else: tok.literal
softLinebreak(em, lit)
if endsInAlpha(em): wr(" ")
wr lit
if endsInAlpha(em): wrSpace(em)
wr em, lit, ltIdent
em.lastTok = tok.tokType
em.lastTokWasTerse = lastTokWasTerse
em.lastLineNumber = tok.line + em.lineSpan
em.lineSpan = 0
proc endsWith(em: Emitter; k: varargs[string]): bool =
if em.tokens.len < k.len: return false
for i in 0..high(k):
if em.tokens[em.tokens.len - k.len + i] != k[i]: return false
return true
proc starWasExportMarker*(em: var Emitter) =
if em.content.endsWith(" * "):
setLen(em.content, em.content.len-3)
em.content.add("*")
if em.endsWith(" ", "*", " "):
setLen(em.tokens, em.tokens.len-3)
setLen(em.kinds, em.kinds.len-3)
em.tokens.add("*")
em.kinds.add ltExportMarker
dec em.col, 2
proc commaWasSemicolon*(em: var Emitter) =
if em.semicolons == detectSemicolonKind:
em.semicolons = if em.content.endsWith(", "): dontTouch else: useSemicolon
if em.semicolons == useSemicolon and em.content.endsWith(", "):
setLen(em.content, em.content.len-2)
em.content.add("; ")
em.semicolons = if em.endsWith(",", " "): dontTouch else: useSemicolon
if em.semicolons == useSemicolon and em.endsWith(",", " "):
em.tokens[em.tokens.len-2] = ";"
proc curlyRiWasPragma*(em: var Emitter) =
if em.content.endsWith("}"):
setLen(em.content, em.content.len-1)
em.content.add(".}")
if em.endsWith("}"):
em.tokens[em.tokens.len-1] = ".}"
inc em.col

View File

@@ -30,7 +30,7 @@ import
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, lineinfos,
pathutils
when defined(nimpretty2):
when defined(nimpretty):
import layouter
type
@@ -44,7 +44,7 @@ type
inPragma*: int # Pragma level
inSemiStmtList*: int
emptyNode: PNode
when defined(nimpretty2):
when defined(nimpretty):
em*: Emitter
SymbolMode = enum
@@ -89,13 +89,20 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
# implementation
template prettySection(body) =
when defined(nimpretty): beginSection(p.em)
body
when defined(nimpretty): endSection(p.em)
proc getTok(p: var TParser) =
## Get the next token from the parser's lexer, and store it in the parser's
## `tok` member.
rawGetTok(p.lex, p.tok)
p.hasProgress = true
when defined(nimpretty2):
when defined(nimpretty):
emitTok(p.em, p.lex, p.tok)
# skip the additional tokens that nimpretty needs but the parser has no
# interest in:
while p.tok.tokType == tkComment:
rawGetTok(p.lex, p.tok)
emitTok(p.em, p.lex, p.tok)
@@ -106,7 +113,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
##
initToken(p.tok)
openLexer(p.lex, fileIdx, inputStream, cache, config)
when defined(nimpretty2):
when defined(nimpretty):
openEmitter(p.em, cache, config, fileIdx)
getTok(p) # read the first token
p.firstTok = true
@@ -119,7 +126,7 @@ proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream,
proc closeParser(p: var TParser) =
## Close a parser, freeing up its resources.
closeLexer(p.lex)
when defined(nimpretty2):
when defined(nimpretty):
closeEmitter(p.em)
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
@@ -382,7 +389,7 @@ proc exprColonEqExpr(p: var TParser): PNode =
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma
when defined(nimpretty2):
when defined(nimpretty):
inc p.em.doIndentMore
getTok(p)
optInd(p, result)
@@ -393,7 +400,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
when defined(nimpretty2):
when defined(nimpretty):
dec p.em.doIndentMore
proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
@@ -828,10 +835,10 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = parseOperators(p, result, limit, mode)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
when defined(nimpretty2):
when defined(nimpretty):
inc p.em.doIndentMore
result = simpleExprAux(p, -1, mode)
when defined(nimpretty2):
when defined(nimpretty):
dec p.em.doIndentMore
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
@@ -908,7 +915,7 @@ proc parsePragma(p: var TParser): PNode =
skipComment(p, a)
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}:
when defined(nimpretty2):
when defined(nimpretty):
if p.tok.tokType == tkCurlyRi: curlyRiWasPragma(p.em)
getTok(p)
else:
@@ -920,7 +927,7 @@ proc identVis(p: var TParser; allowDot=false): PNode =
#| identVisDot = symbol '.' optInd symbol opr?
var a = parseSymbol(p)
if p.tok.tokType == tkOpr:
when defined(nimpretty2):
when defined(nimpretty):
starWasExportMarker(p.em)
result = newNodeP(nkPostfix, p)
addSon(result, newIdentNodeP(p.tok.ident, p))
@@ -999,7 +1006,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
var a = parseIdentColonEquals(p, {})
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
when defined(nimpretty):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
@@ -1035,7 +1042,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
var a: PNode
result = newNodeP(nkFormalParams, p)
addSon(result, p.emptyNode) # return type
when defined(nimpretty2):
when defined(nimpretty):
inc p.em.doIndentMore
inc p.em.keepIndents
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
@@ -1057,7 +1064,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
break
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
when defined(nimpretty):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
@@ -1072,7 +1079,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
elif not retColon and not hasParle:
# Mark as "not there" in order to mark for deprecation in the semantic pass:
result = p.emptyNode
when defined(nimpretty2):
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents
@@ -1235,13 +1242,15 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
else: result.kind = nkIteratorTy
of tkEnum:
if mode == pmTypeDef:
result = parseEnum(p)
prettySection:
result = parseEnum(p)
else:
result = newNodeP(nkEnumTy, p)
getTok(p)
of tkObject:
if mode == pmTypeDef:
result = parseObject(p)
prettySection:
result = parseObject(p)
else:
result = newNodeP(nkObjectTy, p)
getTok(p)
@@ -1694,7 +1703,7 @@ proc parseGenericParamList(p: var TParser): PNode =
var a = parseGenericParam(p)
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
when defined(nimpretty2):
when defined(nimpretty):
commaWasSemicolon(p.em)
getTok(p)
skipComment(p, a)
@@ -2185,10 +2194,16 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
result = parseOperators(p, result, -1, pmNormal)
else:
result = parseSection(p, nkTypeSection, parseTypeDef)
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
of tkConst:
prettySection:
result = parseSection(p, nkConstSection, parseConstant)
of tkLet:
prettySection:
result = parseSection(p, nkLetSection, parseVariable)
of tkVar:
prettySection:
result = parseSection(p, nkVarSection, parseVariable)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p, nkBindStmt)
of tkMixin: result = parseBind(p, nkMixinStmt)
of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable)

View File

@@ -2031,12 +2031,29 @@ proc evalStaticStmt*(module: PSym; g: ModuleGraph; e: PNode, prc: PSym) =
proc setupCompileTimeVar*(module: PSym; g: ModuleGraph; n: PNode) =
discard evalConstExprAux(module, g, nil, n, emStaticStmt)
proc prepareVMValue(arg: PNode): PNode =
## strip nkExprColonExpr from tuple values recurively. That is how
## they are expected to be stored in the VM.
# Early abort without copy. No transformation takes place.
if arg.kind in nkLiterals:
return arg
result = copyNode(arg)
if arg.kind == nkTupleConstr:
for child in arg:
if child.kind == nkExprColonExpr:
result.add prepareVMValue(child[1])
else:
result.add prepareVMValue(child)
else:
for child in arg:
result.add prepareVMValue(child)
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind
of tyStatic:
putIntoReg(result, x)
#of tyTypeDesc:
# putIntoReg(result, x)
putIntoReg(result, prepareVMValue(x))
else:
result.kind = rkNode
var n = x

View File

@@ -813,44 +813,28 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
var signedIntegers = {tyInt8..tyInt32}
var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
var signedIntegers = {tyInt..tyInt64}
var unsignedIntegers = {tyUInt..tyUInt64, tyChar}
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
let src_size = getSize(c.config, src)
let dst_size = getSize(c.config, dst)
if c.config.target.intSize < 8:
signedIntegers.incl(tyInt)
unsignedIntegers.incl(tyUInt)
if src_size == dst_size and src.kind in allowedIntegers and
dst.kind in allowedIntegers:
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
let tmp = c.genx(n.sons[1])
var tmp2 = c.getTemp(n.sons[1].typ)
let tmp3 = c.getTemp(n.sons[1].typ)
if dest < 0: dest = c.getTemp(n[0].typ)
proc mkIntLit(ival: int): int =
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt)))
if src.kind in unsignedIntegers and dst.kind in signedIntegers:
# cast unsigned to signed integer of same size
# signedVal = (unsignedVal xor offset) -% offset
let offset = 1 shl (src_size * 8 - 1)
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
c.gABC(n, opcBitxorInt, tmp3, tmp, tmp2)
c.gABC(n, opcSubInt, dest, tmp3, tmp2)
elif src.kind in signedIntegers and dst.kind in unsignedIntegers:
# cast signed to unsigned integer of same size
# unsignedVal = (offset +% signedVal +% 1) and offset
let offset = (1 shl (src_size * 8)) - 1
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
c.gABx(n, opcLdConst, dest, mkIntLit(offset+1))
c.gABC(n, opcAddu, tmp3, tmp, dest)
c.gABC(n, opcNarrowU, tmp3, TRegister(src_size*8))
c.gABC(n, opcBitandInt, dest, tmp3, tmp2)
else:
c.gABC(n, opcAsgnInt, dest, tmp)
c.gABC(n, opcAsgnInt, dest, tmp)
if dst_size != sizeof(BiggestInt): # don't do anything on biggest int types
if dst.kind in signedIntegers: # we need to do sign extensions
if dst_size <= src_size:
# Sign extension can be omitted when the size increases.
c.gABC(n, opcSignExtend, dest, TRegister(dst_size*8))
elif dst.kind in unsignedIntegers:
if src.kind in signedIntegers or dst_size < src_size:
# Cast from signed to unsigned always needs narrowing. Cast
# from unsigned to unsigned only needs narrowing when target
# is smaller than source.
c.gABC(n, opcNarrowU, dest, TRegister(dst_size*8))
c.freeTemp(tmp)
c.freeTemp(tmp2)
c.freeTemp(tmp3)
elif src_size == dst_size and src.kind in allowedIntegers and
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
let tmp = c.genx(n[1])

View File

@@ -39,7 +39,7 @@ $content
"""
doc.file = """
% This file was generated by Nimrod.
% This file was generated by Nim.
% Generated: $date $time UTC
\documentclass[a4paper]{article}
\usepackage[left=2cm,right=3cm,top=3cm,bottom=3cm]{geometry}

View File

@@ -24,7 +24,7 @@ Options:
-a, --assertions:on|off turn assertions on|off
--opt:none|speed|size optimize not at all or for speed|size
Note: use -d:release for a release build!
--debugger:native|endb use native debugger (gdb) | ENDB (experimental)
--debugger:native Use native debugger (gdb)
--app:console|gui|lib|staticlib
generate a console app|GUI app|DLL|static library
-r, --run run the compiled program with given arguments

View File

@@ -343,12 +343,10 @@ The Git stuff
General commit rules
--------------------
1. Bugfixes that should be backported to the latest stable release should
contain the string ``[backport]`` in the commit message! There will be an
outmated process relying on these. However, bugfixes also have the inherent
risk of causing regressions which are worse for a "stable, bugfixes-only"
branch, so in doubt, leave out the ``[backport]``. Standard library bugfixes
are less critical than compiler bugfixes.
1. The commit message should contain either ``[bugfix]`` or ``[feature]``
or ``[refactoring]`` or ``[other]``. Refactorings and bugfixes and "other"
are backported to the latest stable release branch (currently 0.20.x).
Refactorings are backported because they often enable further bugfixes.
2. All changes introduced by the commit (diff lines) must be related to the
subject of the commit.

View File

@@ -132,8 +132,8 @@ Through the ``-d:x`` or ``--define:x`` switch you can define compile time
symbols for conditional compilation. The defined switches can be checked in
source code with the `when statement <manual.html#when-statement>`_ and
`defined proc <system.html#defined>`_. The typical use of this switch is to
enable builds in release mode (``-d:release``) where certain safety checks are
omitted for better performance. Another common use is the ``-d:ssl`` switch to
enable builds in release mode (``-d:release``) where optimizations are
enabled for better performance. Another common use is the ``-d:ssl`` switch to
activate SSL sockets.
Additionally, you may pass a value along with the symbol: ``-d:x=y``
@@ -169,6 +169,10 @@ The default build of a project is a `debug build`:idx:. To compile a
nim c -d:release myproject.nim
To compile a `dangerous release build`:idx: define the ``danger`` symbol::
nim c -d:danger myproject.nim
Search path handling
--------------------
@@ -344,10 +348,10 @@ complete list.
====================== =========================================================
Define Effect
====================== =========================================================
``release`` Turns off runtime checks and turns on the optimizer.
``release`` Turns on the optimizer.
More aggressive optimizations are possible, eg:
``--passC:-ffast-math`` (but see issue #10305)
``--stacktrace:off``
``danger`` Turns off all runtime checks and turns on the optimizer.
``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``.
``useNimRtl`` Compile and link against ``nimrtl.dll``.
``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's

View File

@@ -17,7 +17,7 @@ customize this style sheet.
*/
/*
Modified for the Nimrod Documenation by
Modified for the Nim Documenation by
Andreas Rumpf
*/

View File

@@ -111,7 +111,7 @@ proc overwriteFile(source, dest: string) =
proc copyExe(source, dest: string) =
safeRemove(dest)
copyFile(dest=dest, source=source)
inclFilePermissions(dest, {fpUserExec})
inclFilePermissions(dest, {fpUserExec, fpGroupExec, fpOthersExec})
const
compileNimInst = "tools/niminst/niminst"

View File

@@ -7,10 +7,6 @@
# distribution, for details about the copyright.
#
## This module implements complex numbers.
## Complex numbers are currently implemented as generic on a 64-bit or 32-bit float.
@@ -42,8 +38,8 @@ proc complex64*(re: float64; im: float64 = 0.0): Complex[float64] =
template im*(arg: typedesc[float32]): Complex32 = complex[float32](0, 1)
template im*(arg: typedesc[float64]): Complex64 = complex[float64](0, 1)
template im*(arg : float32): Complex32 = complex[float32](0, arg)
template im*(arg : float64): Complex64 = complex[float64](0, arg)
template im*(arg: float32): Complex32 = complex[float32](0, arg)
template im*(arg: float64): Complex64 = complex[float64](0, arg)
proc abs*[T](z: Complex[T]): T =
## Return the distance from (0,0) to ``z``.

View File

@@ -149,6 +149,12 @@ proc hash*(x: float): Hash {.inline.} =
var y = x + 1.0
result = cast[ptr Hash](addr(y))[]
# Forward declarations before methods that hash containers. This allows
# containers to contain other containers
proc hash*[A](x: openArray[A]): Hash
proc hash*[A](x: set[A]): Hash
template bytewiseHashing(result: Hash, x: typed, start, stop: int) =
for i in start .. stop:
result = result !& hash(x[i])
@@ -292,12 +298,6 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
result = !$h
# Forward declarations before methods that hash containers. This allows
# containers to contain other containers
proc hash*[A](x: openArray[A]): Hash
proc hash*[A](x: set[A]): Hash
proc hash*[T: tuple](x: T): Hash =
## Efficient hashing of tuples.
for f in fields(x):

View File

@@ -121,12 +121,59 @@
## if however data does not reach the client within the specified timeout a
## ``TimeoutError`` exception will be raised.
##
## Here is how to set a timeout when creating an ``HttpClient`` instance:
##
## .. code-block:: Nim
## import httpclient
##
## let client = newHttpClient(timeout = 42)
##
## Proxy
## =====
##
## A proxy can be specified as a param to any of the procedures defined in
## this module. To do this, use the ``newProxy`` constructor. Unfortunately,
## only basic authentication is supported at the moment.
##
## Some examples on how to configure a Proxy for ``HttpClient``:
##
## .. code-block:: Nim
## import httpclient
##
## let myProxy = newProxy("http://myproxy.network")
## let client = newHttpClient(proxy = myProxy)
##
## Get Proxy URL from environment variables:
##
## .. code-block:: Nim
## import httpclient
##
## var url = ""
## try:
## if existsEnv("http_proxy"):
## url = getEnv("http_proxy")
## elif existsEnv("https_proxy"):
## url = getEnv("https_proxy")
## except ValueError:
## echo "Unable to parse proxy from environment variables."
##
## let myProxy = newProxy(url = url)
## let client = newHttpClient(proxy = myProxy)
##
## Redirects
## =========
##
## The maximum redirects can be set with the ``maxRedirects`` of ``int`` type,
## it specifies the maximum amount of redirects to follow,
## it defaults to ``5``, you can set it to ``0`` to disable redirects.
##
## Here you can see an example about how to set the ``maxRedirects`` of ``HttpClient``:
##
## .. code-block:: Nim
## import httpclient
##
## let client = newHttpClient(maxRedirects = 0)
##
import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes,
math, random, httpcore, times, tables, streams
@@ -647,7 +694,7 @@ proc getSocket*(client: HttpClient): Socket =
##
## .. code-block:: Nim
## if client.connected:
## echo client.getSocket.getLocalAddr
## echo client.getSocket.getLocalAddr
## echo client.getSocket.getPeerAddr
##
return client.socket

View File

@@ -798,12 +798,16 @@ proc getTempDir*(): string {.rtl, extern: "nos$1",
## * `expandTilde proc <#expandTilde,string>`_
## * `getCurrentDir proc <#getCurrentDir>`_
## * `setCurrentDir proc <#setCurrentDir,string>`_
const tempDirDefault = "/tmp"
result = tempDirDefault
when defined(tempDir):
const tempDir {.strdefine.}: string = nil
return tempDir
elif defined(windows): return string(getEnv("TEMP")) & "\\"
elif defined(android): return getHomeDir()
else: return "/tmp/"
const tempDir {.strdefine.}: string = tempDirDefault
result = tempDir
elif defined(windows): result = string(getEnv("TEMP"))
elif defined(android): result = getHomeDir()
else:
if existsEnv("TMPDIR"): result = string(getEnv("TMPDIR"))
normalizePathEnd(result, trailingSep=true)
proc expandTilde*(path: string): string {.
tags: [ReadEnvEffect, ReadIOEffect].} =

View File

@@ -1241,7 +1241,7 @@ when not defined(js):
if open(f, filename, mode, bufSize):
return newFileStream(f)
else:
raise newEIO("cannot open file\n")
raise newEIO("cannot open file stream: " & filename)
when false:
type

View File

@@ -4450,9 +4450,8 @@ when defined(genode):
import system/widestrs
export widestrs
when not defined(nimnoio):
import system/io
export io
import system/io
export io
when not defined(createNimHcr):
include nimhcr

View File

@@ -1 +0,0 @@
--define: nimnoio

View File

@@ -50,15 +50,11 @@ proc prettyPrint(infile, outfile: string, opt: PrettyOptions) =
var conf = newConfigRef()
let fileIdx = fileInfoIdx(conf, AbsoluteFile infile)
conf.outFile = RelativeFile outfile
when defined(nimpretty2):
var p: TParsers
p.parser.em.indWidth = opt.indWidth
if setupParsers(p, fileIdx, newIdentCache(), conf):
discard parseAll(p)
closeParsers(p)
else:
let tree = parseFile(fileIdx, newIdentCache(), conf)
renderModule(tree, infile, outfile, {}, fileIdx, conf)
var p: TParsers
p.parser.em.indWidth = opt.indWidth
if setupParsers(p, fileIdx, newIdentCache(), conf):
discard parseAll(p)
closeParsers(p)
proc main =
var infile, outfile: string

View File

@@ -1,3 +1,2 @@
--define: nimpretty
--define: nimpretty2
--define: nimOldCaseObjects

View File

@@ -366,3 +366,46 @@ proc fun4() =
var i = 0
while i<a.len and i<a.len:
return
# bug #10295
import osproc
let res = execProcess(
"echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")
let res = execProcess("echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")
# bug #10177
proc foo * () =
discard
proc foo* [T]() =
discard
# bug #10159
proc fun() =
discard
proc main() =
echo "foo"; echo "bar";
discard
main()
type
TCallingConvention* = enum
ccDefault, # proc has no explicit calling convention
ccStdCall, # procedure is stdcall
ccCDecl, # cdecl
ccSafeCall, # safecall
ccSysCall, # system call
ccInline, # proc should be inlined
ccNoInline, # proc should not be inlined
ccFastCall, # fastcall (pass parameters in registers)
ccClosure, # proc has a closure
ccNoConvention # needed for generating proper C procs sometimes

View File

@@ -29,10 +29,10 @@ var x = 1
type
GeneralTokenizer* = object of RootObj ## comment here
kind*: TokenClass ## and here
start*, length*: int ## you know how it goes...
kind*: TokenClass ## and here
start*, length*: int ## you know how it goes...
buf: cstring
pos: int # other comment here.
pos: int # other comment here.
state: TokenClass
var x*: string
@@ -122,7 +122,7 @@ type
inquote {.pragmaHereWrongCurlyEnd.}: bool
col, lastLineNumber, lineSpan, indentLevel: int
content: string
fixedUntil: int # marks where we must not go in the content
fixedUntil: int # marks where we must not go in the content
altSplitPos: array[SplitKind, int] # alternative split positions
proc openEmitter*[T, S](em: var Emitter; config: ConfigRef;
@@ -375,3 +375,47 @@ proc fun4() =
var i = 0
while i < a.len and i < a.len:
return
# bug #10295
import osproc
let res = execProcess(
"echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")
let res = execProcess(
"echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates")
# bug #10177
proc foo*() =
discard
proc foo*[T]() =
discard
# bug #10159
proc fun() =
discard
proc main() =
echo "foo"; echo "bar";
discard
main()
type
TCallingConvention* = enum
ccDefault, # proc has no explicit calling convention
ccStdCall, # procedure is stdcall
ccCDecl, # cdecl
ccSafeCall, # safecall
ccSysCall, # system call
ccInline, # proc should be inlined
ccNoInline, # proc should not be inlined
ccFastCall, # fastcall (pass parameters in registers)
ccClosure, # proc has a closure
ccNoConvention # needed for generating proper C procs sometimes

View File

@@ -0,0 +1,73 @@
# bug #9505
import std/[
strutils, ospaths, os
]
import pkg/[
regex
]
proc fun() =
let a = [
1,
2,
]
discard
proc funB() =
let a = [
1,
2,
3
]
discard
# bug #10156
proc foo =
## Comment 1
## Comment 2
discard
proc bar =
## Comment 3
## Comment 4
## More here.
discard
proc barB =
# Comment 5
# Comment 6
discard
var x: int = 2
echo x
# bug #9144
proc a() =
if cond:
while true:
discard
# comment 1
# end while
#end if
# comment 2
#if
#case
#end case
#end if
discard
proc a() =
while true:
discard
# comment 1
# comment 2
discard

View File

@@ -0,0 +1,73 @@
# bug #9505
import std/[
strutils, ospaths, os
]
import pkg/[
regex
]
proc fun() =
let a = [
1,
2,
]
discard
proc funB() =
let a = [
1,
2,
3
]
discard
# bug #10156
proc foo =
## Comment 1
## Comment 2
discard
proc bar =
## Comment 3
## Comment 4
## More here.
discard
proc barB =
# Comment 5
# Comment 6
discard
var x: int = 2
echo x
# bug #9144
proc a() =
if cond:
while true:
discard
# comment 1
# end while
#end if
# comment 2
#if
#case
#end case
#end if
discard
proc a() =
while true:
discard
# comment 1
# comment 2
discard

View File

@@ -474,11 +474,7 @@ iterator listPackages(): tuple[name, url, cmd: string, hasDeps: bool] =
for n, cmd, hasDeps, url in important_packages.packages.items:
let cmd = if cmd.len == 0: defaultCmd else: cmd
if url.len != 0:
if hasDeps:
# use url instead of name, so we can do 'nimble install'
yield (url, url, cmd, hasDeps)
else:
yield (n, url, cmd, hasDeps)
yield (n, url, cmd, hasDeps)
else:
var found = false
for package in packageList.items:
@@ -515,7 +511,8 @@ proc testNimblePackages(r: var TResults, cat: Category) =
let buildPath = packagesDir / name
if not existsDir(buildPath):
if hasDep:
let (nimbleCmdLine, nimbleOutput, nimbleStatus) = execCmdEx2("nimble", ["install", "-y", name])
let installName = if url.len != 0: url else: name
let (nimbleCmdLine, nimbleOutput, nimbleStatus) = execCmdEx2("nimble", ["install", "-y", installName])
if nimbleStatus != QuitSuccess:
let message = "nimble install failed:\n$ " & nimbleCmdLine & "\n" & nimbleOutput
r.addResult(test, targetC, "", message, reInstallFailed)

View File

@@ -24,6 +24,7 @@ pkg "comprehension", "", false, "https://github.com/alehander42/comprehension"
pkg "criterion"
pkg "dashing", "nim c tests/functional.nim"
pkg "docopt"
pkg "easygl", "nim c -o:egl -r src/easygl.nim", true, "https://github.com/jackmott/easygl"
pkg "fragments", "nim c -r fragments/dsl.nim"
pkg "gara"
pkg "glob"
@@ -49,17 +50,17 @@ pkg "nimfp", "nim c -o:nfp -r src/fp.nim", true
pkg "nimgame2", "nim c nimgame2/nimgame.nim", true
pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim", true
# pkg "nimlsp", "", true
# pkg "nimly", "nim c -r tests/test_nimly", true
pkg "nimly", "nim c -r tests/test_nimly", true
# pkg "nimongo", "nimble test_ci", true
pkg "nimpy", "nim c -r tests/nimfrompy.nim"
pkg "nimquery"
pkg "nimsl", "", true
pkg "nimsvg"
pkg "nimx", "nim c --threads:on test/main.nim", true
pkg "norm", "nim c -o:normm src/norm.nim"
# pkg "norm", "nim c -o:normm src/norm.nim", true
pkg "npeg"
pkg "ormin", "nim c -o:orminn ormin.nim", true
#pkg "parsetoml"
pkg "parsetoml"
pkg "patty"
pkg "plotly", "nim c examples/all.nim", true
pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim", true
@@ -68,11 +69,15 @@ pkg "result", "nim c -r result.nim"
pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
pkg "sdl1", "nim c -r src/sdl.nim"
pkg "sdl2_nim", "nim c -r sdl2/sdl.nim"
pkg "snip", "", false, "https://github.com/genotrance/snip"
pkg "stint", "nim c -o:stintt -r stint.nim"
pkg "strunicode", "nim c -r src/strunicode.nim", true
pkg "telebot", "nim c -o:tbot -r telebot.nim", true
pkg "tiny_sqlite"
pkg "unicodedb"
pkg "unicodeplus", "", true
pkg "unpack"
pkg "with"
# pkg "winim", "", true
pkg "yaml"
pkg "zero_functional", "nim c -r test.nim"

View File

@@ -0,0 +1,24 @@
discard """
cmd: '''nim c --newruntime $file'''
output: '''(field: "value")
3 3 new: 0'''
"""
import core / allocators
import system / ansi_c
import tables
type
Node = ref object
field: string
proc main =
var w = newTable[string, owned Node]()
w["key"] = Node(field: "value")
echo w["key"][]
main()
let (a, d) = allocCounters()
discard cprintf("%ld %ld new: %ld\n", a, d, allocs)

View File

@@ -49,3 +49,15 @@ myEnums = enumerators2()
echo myEnums
myEnums = enumerators3()
echo myEnums
#10751
type Tuple = tuple
a: string
b: int
macro foo(t: static Tuple): untyped =
doAssert t.a == "foo"
doAssert t.b == 12345
foo((a: "foo", b: 12345))

View File

@@ -333,3 +333,15 @@ block ospaths:
doAssert joinPath("", "lib") == "lib"
doAssert joinPath("", "/lib") == unixToNativePath"/lib"
doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib"
block getTempDir:
block TMPDIR:
# TMPDIR env var is not used if either of these are defined.
when not (defined(tempDir) or defined(windows) or defined(android)):
if existsEnv("TMPDIR"):
let origTmpDir = getEnv("TMPDIR")
putEnv("TMPDIR", "/mytmp")
doAssert getTempDir() == "/mytmp/"
putEnv("TMPDIR", origTmpDir)
else:
doAssert getTempDir() == "/tmp/"

View File

@@ -2,6 +2,8 @@ discard """
output: "OK"
"""
import macros
type
Dollar = distinct int
XCoord = distinct int32
@@ -112,6 +114,130 @@ proc test() =
doAssert(not compiles(cast[uint32](I8)))
doAssert(not compiles(cast[uint64](I8)))
const prerecordedResults = [
# cast to char
"\0", "\255",
"\0", "\255",
"\0", "\255",
"\0", "\255",
"\0", "\255",
"\128", "\127",
"\0", "\255",
"\0", "\255",
"\0", "\255",
# cast to uint8
"0", "255",
"0", "255",
"0", "255",
"0", "255",
"0", "255",
"128", "127",
"0", "255",
"0", "255",
"0", "255",
# cast to uint16
"0", "255",
"0", "255",
"0", "65535",
"0", "65535",
"0", "65535",
"65408", "127",
"32768", "32767",
"0", "65535",
"0", "65535",
# cast to uint32
"0", "255",
"0", "255",
"0", "65535",
"0", "4294967295",
"0", "4294967295",
"4294967168", "127",
"4294934528", "32767",
"2147483648", "2147483647",
"0", "4294967295",
# cast to uint64
"0", "255",
"0", "255",
"0", "65535",
"0", "4294967295",
"0", "18446744073709551615",
"18446744073709551488", "127",
"18446744073709518848", "32767",
"18446744071562067968", "2147483647",
"9223372036854775808", "9223372036854775807",
# cast to int8
"0", "-1",
"0", "-1",
"0", "-1",
"0", "-1",
"0", "-1",
"-128", "127",
"0", "-1",
"0", "-1",
"0", "-1",
# cast to int16
"0", "255",
"0", "255",
"0", "-1",
"0", "-1",
"0", "-1",
"-128", "127",
"-32768", "32767",
"0", "-1",
"0", "-1",
# cast to int32
"0", "255",
"0", "255",
"0", "65535",
"0", "-1",
"0", "-1",
"-128", "127",
"-32768", "32767",
"-2147483648", "2147483647",
"0", "-1",
# cast to int64
"0", "255",
"0", "255",
"0", "65535",
"0", "4294967295",
"0", "-1",
"-128", "127",
"-32768", "32767",
"-2147483648", "2147483647",
"-9223372036854775808", "9223372036854775807",
]
proc free_integer_casting() =
# cast from every integer type to every type and ensure same
# behavior in vm and execution time.
macro bar(arg: untyped) =
result = newStmtList()
var i = 0
for it1 in arg:
let typA = it1[0]
for it2 in arg:
let lowB = it2[1]
let highB = it2[2]
let castExpr1 = nnkCast.newTree(typA, lowB)
let castExpr2 = nnkCast.newTree(typA, highB)
let lit1 = newLit(prerecordedResults[i*2])
let lit2 = newLit(prerecordedResults[i*2+1])
result.add quote do:
doAssert($(`castExpr1`) == `lit1`)
doAssert($(`castExpr2`) == `lit2`)
i += 1
bar([
(char, '\0', '\255'),
(uint8, 0'u8, 0xff'u8),
(uint16, 0'u16, 0xffff'u16),
(uint32, 0'u32, 0xffffffff'u32),
(uint64, 0'u64, 0xffffffffffffffff'u64),
(int8, 0x80'i8, 0x7f'i8),
(int16, 0x8000'i16, 0x7fff'i16),
(int32, 0x80000000'i32, 0x7fffffff'i32),
(int64, 0x8000000000000000'i64, 0x7fffffffffffffff'i64)
])
proc test_float_cast =
@@ -158,9 +284,11 @@ proc test_float32_cast =
test()
test_float_cast()
test_float32_cast()
free_integer_casting()
static:
test()
test_float_cast()
test_float32_cast()
free_integer_casting()
echo "OK"

View File

@@ -63,7 +63,7 @@ _nim() {
'*--opt=none[do not optimize]' \
'*--opt=speed[optimize for speed|size - use -d:release for a release build]' \
'*--opt=size[optimize for size]' \
'*--debugger:native|endb[use native debugger (gdb) | ENDB (experimental)]' \
'*--debugger:native[use native debugger (gdb)]' \
'*--app=console[generate a console app]' \
'*--app=gui[generate a GUI app]' \
'*--app=lib[generate a dynamic library]' \