StringStream & more stdlib modules support for JS/NimScript (#14095)
* StringStream & more stdlib modules support for JS/NimScript * change back pegs test in line with #14134
This commit is contained in:
parent
d5ed4fba3e
commit
cd9af6b804
22 changed files with 852 additions and 356 deletions
11
changelog.md
11
changelog.md
|
|
@ -37,6 +37,17 @@
|
||||||
and this can now throw in edge cases where `getCurrentDir` throws.
|
and this can now throw in edge cases where `getCurrentDir` throws.
|
||||||
`relativePath` also now works for js with `-d:nodejs`.
|
`relativePath` also now works for js with `-d:nodejs`.
|
||||||
|
|
||||||
|
- JavaScript and NimScript standard library changes: `streams.StringStream` is
|
||||||
|
now supported in JavaScript, with the limitation that any buffer `pointer`s
|
||||||
|
used must be castable to `ptr string`, any incompatible pointer type will not
|
||||||
|
work. The `lexbase` and `streams` modules used to fail to compile on
|
||||||
|
NimScript due to a bug, but this has been fixed.
|
||||||
|
|
||||||
|
The following modules now compile on both JS and NimScript: `parsecsv`,
|
||||||
|
`parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally
|
||||||
|
supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for
|
||||||
|
NimScript: `json`, `parsejson`, `strtabs` and `unidecode`.
|
||||||
|
|
||||||
- Added `streams.readStr` and `streams.peekStr` overloads to
|
- Added `streams.readStr` and `streams.peekStr` overloads to
|
||||||
accept an existing string to modify, which avoids memory
|
accept an existing string to modify, which avoids memory
|
||||||
allocations, similar to `streams.readLine` (#13857).
|
allocations, similar to `streams.readLine` (#13857).
|
||||||
|
|
|
||||||
|
|
@ -76,13 +76,15 @@ available. This includes:
|
||||||
* manual memory management (``alloc``, etc.)
|
* manual memory management (``alloc``, etc.)
|
||||||
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||||
* file management
|
* file management
|
||||||
* most modules of the standard library
|
* OS-specific operations
|
||||||
|
* threading, coroutines
|
||||||
|
* some modules of the standard library
|
||||||
* proper 64 bit integer arithmetic
|
* proper 64 bit integer arithmetic
|
||||||
* unsigned integer arithmetic
|
|
||||||
|
|
||||||
However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and
|
To compensate, the standard library has modules `catered to the JS backend
|
||||||
`times <times.html>`_ are available! To access the DOM, use the `dom
|
<https://nim-lang.org/docs/lib.html#pure-libraries-modules-for-js-backend>`_
|
||||||
<dom.html>`_ module that is only available for the JavaScript platform.
|
and more support will come in the future (for instance, Node.js bindings
|
||||||
|
to get OS info).
|
||||||
|
|
||||||
To compile a Nim module into a ``.js`` file use the ``js`` command; the
|
To compile a Nim module into a ``.js`` file use the ``js`` command; the
|
||||||
default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,6 @@ NimScript is subject to some limitations caused by the implementation of the VM
|
||||||
|
|
||||||
* ``random.randomize()`` requires an ``int64`` explicitly passed as argument, you *must* pass a Seed integer.
|
* ``random.randomize()`` requires an ``int64`` explicitly passed as argument, you *must* pass a Seed integer.
|
||||||
|
|
||||||
* ``unicode`` can be imported, but not ``unidecode``.
|
|
||||||
|
|
||||||
|
|
||||||
Standard library modules
|
Standard library modules
|
||||||
========================
|
========================
|
||||||
|
|
|
||||||
|
|
@ -19,29 +19,43 @@ proc toLowerAscii(c: char): char {.inline.} =
|
||||||
else:
|
else:
|
||||||
result = c
|
result = c
|
||||||
|
|
||||||
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
when defined(js):
|
||||||
rtl, extern: "csuStartsWith".} =
|
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
||||||
## Returns true iff ``s`` starts with ``prefix``.
|
importjs: "#.startsWith(#)".}
|
||||||
##
|
|
||||||
## If ``prefix == ""`` true is returned.
|
|
||||||
var i = 0
|
|
||||||
while true:
|
|
||||||
if prefix[i] == '\0': return true
|
|
||||||
if s[i] != prefix[i]: return false
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
||||||
rtl, extern: "csuEndsWith".} =
|
importjs: "#.endsWith(#)".}
|
||||||
## Returns true iff ``s`` ends with ``suffix``.
|
|
||||||
##
|
# JS string has more operations that might warrant its own module:
|
||||||
## If ``suffix == ""`` true is returned.
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||||
let slen = s.len
|
else:
|
||||||
var i = 0
|
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
||||||
var j = slen - len(suffix)
|
rtl, extern: "csuStartsWith".} =
|
||||||
while i+j <% slen:
|
## Returns true iff ``s`` starts with ``prefix``.
|
||||||
if s[i+j] != suffix[i]: return false
|
##
|
||||||
inc(i)
|
## If ``prefix == ""`` true is returned.
|
||||||
if suffix[i] == '\0': return true
|
##
|
||||||
|
## JS backend uses native ``String.prototype.startsWith``.
|
||||||
|
var i = 0
|
||||||
|
while true:
|
||||||
|
if prefix[i] == '\0': return true
|
||||||
|
if s[i] != prefix[i]: return false
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
||||||
|
rtl, extern: "csuEndsWith".} =
|
||||||
|
## Returns true iff ``s`` ends with ``suffix``.
|
||||||
|
##
|
||||||
|
## If ``suffix == ""`` true is returned.
|
||||||
|
##
|
||||||
|
## JS backend uses native ``String.prototype.endsWith``.
|
||||||
|
let slen = s.len
|
||||||
|
var i = 0
|
||||||
|
var j = slen - len(suffix)
|
||||||
|
while i+j <% slen:
|
||||||
|
if s[i+j] != suffix[i]: return false
|
||||||
|
inc(i)
|
||||||
|
if suffix[i] == '\0': return true
|
||||||
|
|
||||||
proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
|
proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
|
||||||
rtl, extern: "csuCmpIgnoreStyle".} =
|
rtl, extern: "csuCmpIgnoreStyle".} =
|
||||||
|
|
@ -53,6 +67,9 @@ proc cmpIgnoreStyle*(a, b: cstring): int {.noSideEffect,
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
## | > 0 iff a > b
|
## | > 0 iff a > b
|
||||||
|
##
|
||||||
|
## Not supported for JS backend, use `strutils.cmpIgnoreStyle
|
||||||
|
## <https://nim-lang.org/docs/strutils.html#cmpIgnoreStyle%2Cstring%2Cstring>`_ instead.
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -72,6 +89,9 @@ proc cmpIgnoreCase*(a, b: cstring): int {.noSideEffect,
|
||||||
## | 0 iff a == b
|
## | 0 iff a == b
|
||||||
## | < 0 iff a < b
|
## | < 0 iff a < b
|
||||||
## | > 0 iff a > b
|
## | > 0 iff a > b
|
||||||
|
##
|
||||||
|
## Not supported for JS backend, use `strutils.cmpIgnoreCase
|
||||||
|
## <https://nim-lang.org/docs/strutils.html#cmpIgnoreCase%2Cstring%2Cstring>`_ instead.
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
var aa = toLowerAscii(a[i])
|
var aa = toLowerAscii(a[i])
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ proc fillBuffer(L: var BaseLexer) =
|
||||||
toCopy = L.buf.len - (L.sentinel + 1)
|
toCopy = L.buf.len - (L.sentinel + 1)
|
||||||
assert(toCopy >= 0)
|
assert(toCopy >= 0)
|
||||||
if toCopy > 0:
|
if toCopy > 0:
|
||||||
when defined(js):
|
when defined(js) or defined(nimscript):
|
||||||
|
# nimscript has to be here to avoid compiling other branch (moveMem)
|
||||||
for i in 0 ..< toCopy:
|
for i in 0 ..< toCopy:
|
||||||
L.buf[i] = L.buf[L.sentinel + 1 + i]
|
L.buf[i] = L.buf[L.sentinel + 1 + i]
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,14 @@
|
||||||
## * `streams module <streams.html>`_
|
## * `streams module <streams.html>`_
|
||||||
## * `json module <json.html>`_
|
## * `json module <json.html>`_
|
||||||
|
|
||||||
when defined(nimV2):
|
const unsupportedPlatform =
|
||||||
{.error: """marshal module is not supported in new runtime.
|
when defined(nimV2): "new runtime"
|
||||||
|
elif defined(js): "javascript"
|
||||||
|
elif defined(nimscript): "nimscript"
|
||||||
|
else: ""
|
||||||
|
|
||||||
|
when unsupportedPlatform != "":
|
||||||
|
{.error: "marshal module is not supported in " & unsupportedPlatform & """.
|
||||||
Please use alternative packages for serialization.
|
Please use alternative packages for serialization.
|
||||||
It is possible to reimplement this module using generics and type traits.
|
It is possible to reimplement this module using generics and type traits.
|
||||||
Please contribute new implementation.""".}
|
Please contribute new implementation.""".}
|
||||||
|
|
|
||||||
|
|
@ -557,7 +557,14 @@ type
|
||||||
tok: Token
|
tok: Token
|
||||||
|
|
||||||
proc newNode*(k: SqlNodeKind): SqlNode =
|
proc newNode*(k: SqlNodeKind): SqlNode =
|
||||||
result = SqlNode(kind: k)
|
when defined(js): # bug #14117
|
||||||
|
case k
|
||||||
|
of LiteralNodes:
|
||||||
|
result = SqlNode(kind: k, strVal: "")
|
||||||
|
else:
|
||||||
|
result = SqlNode(kind: k, sons: @[])
|
||||||
|
else:
|
||||||
|
result = SqlNode(kind: k)
|
||||||
|
|
||||||
proc newNode*(k: SqlNodeKind, s: string): SqlNode =
|
proc newNode*(k: SqlNodeKind, s: string): SqlNode =
|
||||||
result = SqlNode(kind: k)
|
result = SqlNode(kind: k)
|
||||||
|
|
@ -1469,34 +1476,33 @@ proc treeRepr*(s: SqlNode): string =
|
||||||
result = newStringOfCap(128)
|
result = newStringOfCap(128)
|
||||||
treeReprAux(s, 0, result)
|
treeReprAux(s, 0, result)
|
||||||
|
|
||||||
when not defined(js):
|
import streams
|
||||||
import streams
|
|
||||||
|
|
||||||
proc open(L: var SqlLexer, input: Stream, filename: string) =
|
proc open(L: var SqlLexer, input: Stream, filename: string) =
|
||||||
lexbase.open(L, input)
|
lexbase.open(L, input)
|
||||||
L.filename = filename
|
L.filename = filename
|
||||||
|
|
||||||
proc open(p: var SqlParser, input: Stream, filename: string) =
|
proc open(p: var SqlParser, input: Stream, filename: string) =
|
||||||
## opens the parser `p` and assigns the input stream `input` to it.
|
## opens the parser `p` and assigns the input stream `input` to it.
|
||||||
## `filename` is only used for error messages.
|
## `filename` is only used for error messages.
|
||||||
open(SqlLexer(p), input, filename)
|
open(SqlLexer(p), input, filename)
|
||||||
p.tok.kind = tkInvalid
|
p.tok.kind = tkInvalid
|
||||||
p.tok.literal = ""
|
p.tok.literal = ""
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
||||||
proc parseSQL*(input: Stream, filename: string): SqlNode =
|
proc parseSQL*(input: Stream, filename: string): SqlNode =
|
||||||
## parses the SQL from `input` into an AST and returns the AST.
|
## parses the SQL from `input` into an AST and returns the AST.
|
||||||
## `filename` is only used for error messages.
|
## `filename` is only used for error messages.
|
||||||
## Syntax errors raise an `SqlParseError` exception.
|
## Syntax errors raise an `SqlParseError` exception.
|
||||||
var p: SqlParser
|
var p: SqlParser
|
||||||
open(p, input, filename)
|
open(p, input, filename)
|
||||||
try:
|
try:
|
||||||
result = parse(p)
|
result = parse(p)
|
||||||
finally:
|
finally:
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
proc parseSQL*(input: string, filename = ""): SqlNode =
|
proc parseSQL*(input: string, filename = ""): SqlNode =
|
||||||
## parses the SQL from `input` into an AST and returns the AST.
|
## parses the SQL from `input` into an AST and returns the AST.
|
||||||
## `filename` is only used for error messages.
|
## `filename` is only used for error messages.
|
||||||
## Syntax errors raise an `SqlParseError` exception.
|
## Syntax errors raise an `SqlParseError` exception.
|
||||||
parseSQL(newStringStream(input), "")
|
parseSQL(newStringStream(input), "")
|
||||||
|
|
|
||||||
|
|
@ -287,46 +287,47 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
|
||||||
## shortcut for ``add(c, frmt % args)``.
|
## shortcut for ``add(c, frmt % args)``.
|
||||||
add(c, frmt % args)
|
add(c, frmt % args)
|
||||||
|
|
||||||
const
|
when not defined(js) and not defined(nimscript):
|
||||||
bufSize = 1024 # 1 KB is reasonable
|
const
|
||||||
|
bufSize = 1024 # 1 KB is reasonable
|
||||||
|
|
||||||
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
|
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
|
||||||
## returns true if the contents of the file `f` equal `r`.
|
## returns true if the contents of the file `f` equal `r`.
|
||||||
var
|
var
|
||||||
buf: array[bufSize, char]
|
buf: array[bufSize, char]
|
||||||
bpos = buf.len
|
bpos = buf.len
|
||||||
blen = buf.len
|
blen = buf.len
|
||||||
|
|
||||||
for s in leaves(r):
|
for s in leaves(r):
|
||||||
var spos = 0
|
var spos = 0
|
||||||
let slen = s.len
|
let slen = s.len
|
||||||
while spos < slen:
|
while spos < slen:
|
||||||
if bpos == blen:
|
if bpos == blen:
|
||||||
# Read more data
|
# Read more data
|
||||||
bpos = 0
|
bpos = 0
|
||||||
blen = readBuffer(f, addr(buf[0]), buf.len)
|
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||||
if blen == 0: # no more data in file
|
if blen == 0: # no more data in file
|
||||||
|
result = false
|
||||||
|
return
|
||||||
|
let n = min(blen - bpos, slen - spos)
|
||||||
|
# TODO There's gotta be a better way of comparing here...
|
||||||
|
if not equalMem(addr(buf[bpos]),
|
||||||
|
cast[pointer](cast[int](cstring(s))+spos), n):
|
||||||
result = false
|
result = false
|
||||||
return
|
return
|
||||||
let n = min(blen - bpos, slen - spos)
|
spos += n
|
||||||
# TODO There's gotta be a better way of comparing here...
|
bpos += n
|
||||||
if not equalMem(addr(buf[bpos]),
|
|
||||||
cast[pointer](cast[int](cstring(s))+spos), n):
|
|
||||||
result = false
|
|
||||||
return
|
|
||||||
spos += n
|
|
||||||
bpos += n
|
|
||||||
|
|
||||||
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
|
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
|
||||||
|
|
||||||
proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
|
proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
|
||||||
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
||||||
## exist, false is returned.
|
## exist, false is returned.
|
||||||
var f: File
|
var f: File
|
||||||
result = open(f, filename)
|
result = open(f, filename)
|
||||||
if result:
|
if result:
|
||||||
result = equalsFile(r, f)
|
result = equalsFile(r, f)
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
new(N) # init dummy node for splay algorithm
|
new(N) # init dummy node for splay algorithm
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,9 @@ proc getPosition*(s: Stream): int =
|
||||||
|
|
||||||
proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
|
proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
## Low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
## Low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||||
|
##
|
||||||
|
## **JS note:** `buffer` is treated as a ``ptr string`` and written to between
|
||||||
|
## ``0..<bufLen``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream("abcde")
|
var strm = newStringStream("abcde")
|
||||||
var buffer: array[6, char]
|
var buffer: array[6, char]
|
||||||
|
|
@ -241,11 +244,21 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int =
|
||||||
# fallback
|
# fallback
|
||||||
result = s.readData(addr buffer[0], buffer.len)
|
result = s.readData(addr buffer[0], buffer.len)
|
||||||
|
|
||||||
when not defined(js):
|
template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped =
|
||||||
|
when nimvm:
|
||||||
|
block:
|
||||||
|
caseJsOrVm
|
||||||
|
else:
|
||||||
|
block:
|
||||||
|
when defined(js) or defined(nimscript):
|
||||||
|
# nimscript has to be here to avoid semantic checking of caseElse
|
||||||
|
caseJsOrVm
|
||||||
|
else:
|
||||||
|
caseElse
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor) >= (1, 3) or not defined(js):
|
||||||
proc readAll*(s: Stream): string =
|
proc readAll*(s: Stream): string =
|
||||||
## Reads all available data.
|
## Reads all available data.
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream("The first line\nthe second line\nthe third line")
|
var strm = newStringStream("The first line\nthe second line\nthe third line")
|
||||||
doAssert strm.readAll() == "The first line\nthe second line\nthe third line"
|
doAssert strm.readAll() == "The first line\nthe second line\nthe third line"
|
||||||
|
|
@ -253,7 +266,7 @@ when not defined(js):
|
||||||
strm.close()
|
strm.close()
|
||||||
|
|
||||||
const bufferSize = 1024
|
const bufferSize = 1024
|
||||||
when nimvm:
|
jsOrVmBlock:
|
||||||
var buffer2: string
|
var buffer2: string
|
||||||
buffer2.setLen(bufferSize)
|
buffer2.setLen(bufferSize)
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -265,7 +278,7 @@ when not defined(js):
|
||||||
result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes]
|
result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes]
|
||||||
if readBytes < bufferSize:
|
if readBytes < bufferSize:
|
||||||
break
|
break
|
||||||
else:
|
do: # not JS or VM
|
||||||
var buffer {.noinit.}: array[bufferSize, char]
|
var buffer {.noinit.}: array[bufferSize, char]
|
||||||
while true:
|
while true:
|
||||||
let readBytes = readData(s, addr(buffer[0]), bufferSize)
|
let readBytes = readData(s, addr(buffer[0]), bufferSize)
|
||||||
|
|
@ -280,6 +293,9 @@ when not defined(js):
|
||||||
proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
|
proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
## Low level proc that reads data into an untyped `buffer` of `bufLen` size
|
## Low level proc that reads data into an untyped `buffer` of `bufLen` size
|
||||||
## without moving stream position.
|
## without moving stream position.
|
||||||
|
##
|
||||||
|
## **JS note:** `buffer` is treated as a ``ptr string`` and written to between
|
||||||
|
## ``0..<bufLen``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream("abcde")
|
var strm = newStringStream("abcde")
|
||||||
var buffer: array[6, char]
|
var buffer: array[6, char]
|
||||||
|
|
@ -293,6 +309,9 @@ proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
|
proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
## Low level proc that writes an untyped `buffer` of `bufLen` size
|
## Low level proc that writes an untyped `buffer` of `bufLen` size
|
||||||
## to the stream `s`.
|
## to the stream `s`.
|
||||||
|
##
|
||||||
|
## **JS note:** `buffer` is treated as a ``ptr string`` and read between
|
||||||
|
## ``0..<bufLen``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
## writeData
|
## writeData
|
||||||
var strm = newStringStream("")
|
var strm = newStringStream("")
|
||||||
|
|
@ -311,6 +330,9 @@ proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
proc write*[T](s: Stream, x: T) =
|
proc write*[T](s: Stream, x: T) =
|
||||||
## Generic write procedure. Writes `x` to the stream `s`. Implementation:
|
## Generic write procedure. Writes `x` to the stream `s`. Implementation:
|
||||||
##
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `write(Stream, string)
|
||||||
|
## <#write,Stream,string>`_ for now.
|
||||||
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
##
|
##
|
||||||
## s.writeData(s, unsafeAddr(x), sizeof(x))
|
## s.writeData(s, unsafeAddr(x), sizeof(x))
|
||||||
|
|
@ -336,7 +358,12 @@ proc write*(s: Stream, x: string) =
|
||||||
when nimvm:
|
when nimvm:
|
||||||
writeData(s, cstring(x), x.len)
|
writeData(s, cstring(x), x.len)
|
||||||
else:
|
else:
|
||||||
if x.len > 0: writeData(s, cstring(x), x.len)
|
if x.len > 0:
|
||||||
|
when defined(js):
|
||||||
|
var x = x
|
||||||
|
writeData(s, addr(x), x.len)
|
||||||
|
else:
|
||||||
|
writeData(s, cstring(x), x.len)
|
||||||
|
|
||||||
proc write*(s: Stream, args: varargs[string, `$`]) =
|
proc write*(s: Stream, args: varargs[string, `$`]) =
|
||||||
## Writes one or more strings to the the stream. No length fields or
|
## Writes one or more strings to the the stream. No length fields or
|
||||||
|
|
@ -366,6 +393,8 @@ proc writeLine*(s: Stream, args: varargs[string, `$`]) =
|
||||||
|
|
||||||
proc read*[T](s: Stream, result: var T) =
|
proc read*[T](s: Stream, result: var T) =
|
||||||
## Generic read procedure. Reads `result` from the stream `s`.
|
## Generic read procedure. Reads `result` from the stream `s`.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream("012")
|
var strm = newStringStream("012")
|
||||||
## readInt
|
## readInt
|
||||||
|
|
@ -383,6 +412,8 @@ proc read*[T](s: Stream, result: var T) =
|
||||||
|
|
||||||
proc peek*[T](s: Stream, result: var T) =
|
proc peek*[T](s: Stream, result: var T) =
|
||||||
## Generic peek procedure. Peeks `result` from the stream `s`.
|
## Generic peek procedure. Peeks `result` from the stream `s`.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream("012")
|
var strm = newStringStream("012")
|
||||||
## peekInt
|
## peekInt
|
||||||
|
|
@ -412,11 +443,11 @@ proc readChar*(s: Stream): char =
|
||||||
doAssert strm.readChar() == '\x00'
|
doAssert strm.readChar() == '\x00'
|
||||||
strm.close()
|
strm.close()
|
||||||
|
|
||||||
when nimvm:
|
jsOrVmBlock:
|
||||||
var str = " "
|
var str = " "
|
||||||
if readDataStr(s, str, 0..<sizeof(result)) != 1: result = '\0'
|
if readDataStr(s, str, 0..0) != 1: result = '\0'
|
||||||
else: result = str[0]
|
else: result = str[0]
|
||||||
else:
|
do:
|
||||||
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
||||||
|
|
||||||
proc peekChar*(s: Stream): char =
|
proc peekChar*(s: Stream): char =
|
||||||
|
|
@ -430,7 +461,12 @@ proc peekChar*(s: Stream): char =
|
||||||
doAssert strm.peekChar() == '\x00'
|
doAssert strm.peekChar() == '\x00'
|
||||||
strm.close()
|
strm.close()
|
||||||
|
|
||||||
if peekData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
when defined(js):
|
||||||
|
var str = " "
|
||||||
|
if peekData(s, addr(str), sizeof(result)) != 1: result = '\0'
|
||||||
|
else: result = str[0]
|
||||||
|
else:
|
||||||
|
if peekData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
||||||
|
|
||||||
proc readBool*(s: Stream): bool =
|
proc readBool*(s: Stream): bool =
|
||||||
## Reads a bool from the stream `s`.
|
## Reads a bool from the stream `s`.
|
||||||
|
|
@ -438,6 +474,8 @@ proc readBool*(s: Stream): bool =
|
||||||
## A bool is one byte long and it is `true` for every non-zero
|
## A bool is one byte long and it is `true` for every non-zero
|
||||||
## (`0000_0000`) value.
|
## (`0000_0000`) value.
|
||||||
## Raises `IOError` if an error occurred.
|
## Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -461,6 +499,8 @@ proc peekBool*(s: Stream): bool =
|
||||||
## A bool is one byte long and it is `true` for every non-zero
|
## A bool is one byte long and it is `true` for every non-zero
|
||||||
## (`0000_0000`) value.
|
## (`0000_0000`) value.
|
||||||
## Raises `IOError` if an error occurred.
|
## Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -482,6 +522,8 @@ proc peekBool*(s: Stream): bool =
|
||||||
|
|
||||||
proc readInt8*(s: Stream): int8 =
|
proc readInt8*(s: Stream): int8 =
|
||||||
## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -499,6 +541,8 @@ proc readInt8*(s: Stream): int8 =
|
||||||
|
|
||||||
proc peekInt8*(s: Stream): int8 =
|
proc peekInt8*(s: Stream): int8 =
|
||||||
## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -518,6 +562,8 @@ proc peekInt8*(s: Stream): int8 =
|
||||||
|
|
||||||
proc readInt16*(s: Stream): int16 =
|
proc readInt16*(s: Stream): int16 =
|
||||||
## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -535,6 +581,8 @@ proc readInt16*(s: Stream): int16 =
|
||||||
|
|
||||||
proc peekInt16*(s: Stream): int16 =
|
proc peekInt16*(s: Stream): int16 =
|
||||||
## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -554,6 +602,8 @@ proc peekInt16*(s: Stream): int16 =
|
||||||
|
|
||||||
proc readInt32*(s: Stream): int32 =
|
proc readInt32*(s: Stream): int32 =
|
||||||
## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -571,6 +621,8 @@ proc readInt32*(s: Stream): int32 =
|
||||||
|
|
||||||
proc peekInt32*(s: Stream): int32 =
|
proc peekInt32*(s: Stream): int32 =
|
||||||
## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -590,6 +642,8 @@ proc peekInt32*(s: Stream): int32 =
|
||||||
|
|
||||||
proc readInt64*(s: Stream): int64 =
|
proc readInt64*(s: Stream): int64 =
|
||||||
## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -607,6 +661,8 @@ proc readInt64*(s: Stream): int64 =
|
||||||
|
|
||||||
proc peekInt64*(s: Stream): int64 =
|
proc peekInt64*(s: Stream): int64 =
|
||||||
## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -626,6 +682,8 @@ proc peekInt64*(s: Stream): int64 =
|
||||||
|
|
||||||
proc readUint8*(s: Stream): uint8 =
|
proc readUint8*(s: Stream): uint8 =
|
||||||
## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -643,6 +701,8 @@ proc readUint8*(s: Stream): uint8 =
|
||||||
|
|
||||||
proc peekUint8*(s: Stream): uint8 =
|
proc peekUint8*(s: Stream): uint8 =
|
||||||
## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -662,6 +722,8 @@ proc peekUint8*(s: Stream): uint8 =
|
||||||
|
|
||||||
proc readUint16*(s: Stream): uint16 =
|
proc readUint16*(s: Stream): uint16 =
|
||||||
## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -679,6 +741,8 @@ proc readUint16*(s: Stream): uint16 =
|
||||||
|
|
||||||
proc peekUint16*(s: Stream): uint16 =
|
proc peekUint16*(s: Stream): uint16 =
|
||||||
## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -698,6 +762,8 @@ proc peekUint16*(s: Stream): uint16 =
|
||||||
|
|
||||||
proc readUint32*(s: Stream): uint32 =
|
proc readUint32*(s: Stream): uint32 =
|
||||||
## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -716,6 +782,8 @@ proc readUint32*(s: Stream): uint32 =
|
||||||
|
|
||||||
proc peekUint32*(s: Stream): uint32 =
|
proc peekUint32*(s: Stream): uint32 =
|
||||||
## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -735,6 +803,8 @@ proc peekUint32*(s: Stream): uint32 =
|
||||||
|
|
||||||
proc readUint64*(s: Stream): uint64 =
|
proc readUint64*(s: Stream): uint64 =
|
||||||
## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -752,6 +822,8 @@ proc readUint64*(s: Stream): uint64 =
|
||||||
|
|
||||||
proc peekUint64*(s: Stream): uint64 =
|
proc peekUint64*(s: Stream): uint64 =
|
||||||
## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -771,6 +843,8 @@ proc peekUint64*(s: Stream): uint64 =
|
||||||
|
|
||||||
proc readFloat32*(s: Stream): float32 =
|
proc readFloat32*(s: Stream): float32 =
|
||||||
## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -788,6 +862,8 @@ proc readFloat32*(s: Stream): float32 =
|
||||||
|
|
||||||
proc peekFloat32*(s: Stream): float32 =
|
proc peekFloat32*(s: Stream): float32 =
|
||||||
## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -807,6 +883,8 @@ proc peekFloat32*(s: Stream): float32 =
|
||||||
|
|
||||||
proc readFloat64*(s: Stream): float64 =
|
proc readFloat64*(s: Stream): float64 =
|
||||||
## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -824,6 +902,8 @@ proc readFloat64*(s: Stream): float64 =
|
||||||
|
|
||||||
proc peekFloat64*(s: Stream): float64 =
|
proc peekFloat64*(s: Stream): float64 =
|
||||||
## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var strm = newStringStream()
|
var strm = newStringStream()
|
||||||
## setup for reading data
|
## setup for reading data
|
||||||
|
|
@ -841,10 +921,19 @@ proc peekFloat64*(s: Stream): float64 =
|
||||||
|
|
||||||
peek(s, result)
|
peek(s, result)
|
||||||
|
|
||||||
|
template untaint(s: var TaintedString): var string =
|
||||||
|
when taintMode: # for VM, bug #12282
|
||||||
|
s.string
|
||||||
|
else:
|
||||||
|
s
|
||||||
|
|
||||||
proc readStrPrivate(s: Stream, length: int, str: var TaintedString) =
|
proc readStrPrivate(s: Stream, length: int, str: var TaintedString) =
|
||||||
if length > len(str): setLen(str.string, length)
|
if length > len(str): setLen(str.untaint, length)
|
||||||
var L = readData(s, cstring(str), length)
|
when defined(js):
|
||||||
if L != len(str): setLen(str.string, L)
|
let L = readData(s, addr(str), length)
|
||||||
|
else:
|
||||||
|
let L = readData(s, cstring(str.string), length)
|
||||||
|
if L != len(str): setLen(str.untaint, L)
|
||||||
|
|
||||||
proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} =
|
proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} =
|
||||||
## Reads a string of length `length` from the stream `s`. Raises `IOError` if
|
## Reads a string of length `length` from the stream `s`. Raises `IOError` if
|
||||||
|
|
@ -865,9 +954,12 @@ proc readStr*(s: Stream, length: int): TaintedString =
|
||||||
readStrPrivate(s, length, result)
|
readStrPrivate(s, length, result)
|
||||||
|
|
||||||
proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) =
|
proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) =
|
||||||
if length > len(str): setLen(str.string, length)
|
if length > len(str): setLen(str.untaint, length)
|
||||||
var L = peekData(s, cstring(str), length)
|
when defined(js):
|
||||||
if L != len(str): setLen(str.string, L)
|
let L = peekData(s, addr(str), length)
|
||||||
|
else:
|
||||||
|
let L = peekData(s, cstring(str.string), length)
|
||||||
|
if L != len(str): setLen(str.untaint, L)
|
||||||
|
|
||||||
proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} =
|
proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} =
|
||||||
## Peeks a string of length `length` from the stream `s`. Raises `IOError` if
|
## Peeks a string of length `length` from the stream `s`. Raises `IOError` if
|
||||||
|
|
@ -918,13 +1010,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||||
result = s.readLineImpl(s, line)
|
result = s.readLineImpl(s, line)
|
||||||
else:
|
else:
|
||||||
# fallback
|
# fallback
|
||||||
when nimvm: #Bug #12282
|
line.untaint.setLen(0)
|
||||||
when taintMode:
|
|
||||||
line.string.setLen(0)
|
|
||||||
else:
|
|
||||||
line.setLen(0)
|
|
||||||
else:
|
|
||||||
line.string.setLen(0)
|
|
||||||
while true:
|
while true:
|
||||||
var c = readChar(s)
|
var c = readChar(s)
|
||||||
if c == '\c':
|
if c == '\c':
|
||||||
|
|
@ -934,13 +1020,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||||
elif c == '\0':
|
elif c == '\0':
|
||||||
if line.len > 0: break
|
if line.len > 0: break
|
||||||
else: return false
|
else: return false
|
||||||
when nimvm: #Bug #12282
|
line.untaint.add(c)
|
||||||
when taintMode:
|
|
||||||
line.string.add(c)
|
|
||||||
else:
|
|
||||||
line.add(c)
|
|
||||||
else:
|
|
||||||
line.string.add(c)
|
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc peekLine*(s: Stream, line: var TaintedString): bool =
|
proc peekLine*(s: Stream, line: var TaintedString): bool =
|
||||||
|
|
@ -1002,7 +1082,7 @@ proc readLine*(s: Stream): TaintedString =
|
||||||
if c == '\L' or c == '\0':
|
if c == '\L' or c == '\0':
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
result.string.add(c)
|
result.untaint.add(c)
|
||||||
|
|
||||||
proc peekLine*(s: Stream): TaintedString =
|
proc peekLine*(s: Stream): TaintedString =
|
||||||
## Peeks a line from a stream `s`. Raises `IOError` if an error occurred.
|
## Peeks a line from a stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
|
@ -1048,17 +1128,13 @@ iterator lines*(s: Stream): TaintedString =
|
||||||
type
|
type
|
||||||
StringStream* = ref StringStreamObj
|
StringStream* = ref StringStreamObj
|
||||||
## A stream that encapsulates a string.
|
## A stream that encapsulates a string.
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
StringStreamObj* = object of StreamObj
|
StringStreamObj* = object of StreamObj
|
||||||
## A string stream object.
|
## A string stream object.
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
data*: string ## A string data.
|
data*: string ## A string data.
|
||||||
## This is updated when called `writeLine` etc.
|
## This is updated when called `writeLine` etc.
|
||||||
pos: int
|
pos: int
|
||||||
|
|
||||||
when defined(js): #This section exists so that string streams work at compile time for the js backend
|
when (NimMajor, NimMinor) < (1, 3) and defined(js):
|
||||||
proc ssAtEnd(s: Stream): bool {.compileTime.} =
|
proc ssAtEnd(s: Stream): bool {.compileTime.} =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
return s.pos >= s.data.len
|
return s.pos >= s.data.len
|
||||||
|
|
@ -1111,7 +1187,7 @@ when defined(js): #This section exists so that string streams work at compile ti
|
||||||
if readBytes < bufferSize:
|
if readBytes < bufferSize:
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else: # after 1.3 or JS not defined
|
||||||
proc ssAtEnd(s: Stream): bool =
|
proc ssAtEnd(s: Stream): bool =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
return s.pos >= s.data.len
|
return s.pos >= s.data.len
|
||||||
|
|
@ -1128,9 +1204,9 @@ else:
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
when nimvm:
|
jsOrVmBlock:
|
||||||
buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
|
buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
|
||||||
else:
|
do:
|
||||||
copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result)
|
copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result)
|
||||||
inc(s.pos, result)
|
inc(s.pos, result)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1140,7 +1216,14 @@ else:
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
result = min(bufLen, s.data.len - s.pos)
|
result = min(bufLen, s.data.len - s.pos)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
copyMem(buffer, addr(s.data[s.pos]), result)
|
when defined(js):
|
||||||
|
try:
|
||||||
|
cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result]
|
||||||
|
except:
|
||||||
|
raise newException(Defect, "could not read string stream, " &
|
||||||
|
"did you use a non-string buffer pointer?", getCurrentException())
|
||||||
|
elif not defined(nimscript):
|
||||||
|
copyMem(buffer, addr(s.data[s.pos]), result)
|
||||||
inc(s.pos, result)
|
inc(s.pos, result)
|
||||||
else:
|
else:
|
||||||
result = 0
|
result = 0
|
||||||
|
|
@ -1149,7 +1232,14 @@ else:
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
result = min(bufLen, s.data.len - s.pos)
|
result = min(bufLen, s.data.len - s.pos)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
copyMem(buffer, addr(s.data[s.pos]), result)
|
when defined(js):
|
||||||
|
try:
|
||||||
|
cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result]
|
||||||
|
except:
|
||||||
|
raise newException(Defect, "could not peek string stream, " &
|
||||||
|
"did you use a non-string buffer pointer?", getCurrentException())
|
||||||
|
elif not defined(nimscript):
|
||||||
|
copyMem(buffer, addr(s.data[s.pos]), result)
|
||||||
else:
|
else:
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
|
|
@ -1159,7 +1249,14 @@ else:
|
||||||
return
|
return
|
||||||
if s.pos + bufLen > s.data.len:
|
if s.pos + bufLen > s.data.len:
|
||||||
setLen(s.data, s.pos + bufLen)
|
setLen(s.data, s.pos + bufLen)
|
||||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
when defined(js):
|
||||||
|
try:
|
||||||
|
s.data[s.pos..<s.pos+bufLen] = cast[ptr string](buffer)[][0..<bufLen]
|
||||||
|
except:
|
||||||
|
raise newException(Defect, "could not write to string stream, " &
|
||||||
|
"did you use a non-string buffer pointer?", getCurrentException())
|
||||||
|
elif not defined(nimscript):
|
||||||
|
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||||
inc(s.pos, bufLen)
|
inc(s.pos, bufLen)
|
||||||
|
|
||||||
proc ssClose(s: Stream) =
|
proc ssClose(s: Stream) =
|
||||||
|
|
@ -1172,8 +1269,6 @@ else:
|
||||||
proc newStringStream*(s: string = ""): owned StringStream =
|
proc newStringStream*(s: string = ""): owned StringStream =
|
||||||
## Creates a new stream from the string `s`.
|
## Creates a new stream from the string `s`.
|
||||||
##
|
##
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
##
|
|
||||||
## See also:
|
## See also:
|
||||||
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
||||||
## opened File.
|
## opened File.
|
||||||
|
|
@ -1195,163 +1290,166 @@ else:
|
||||||
result.atEndImpl = ssAtEnd
|
result.atEndImpl = ssAtEnd
|
||||||
result.setPositionImpl = ssSetPosition
|
result.setPositionImpl = ssSetPosition
|
||||||
result.getPositionImpl = ssGetPosition
|
result.getPositionImpl = ssGetPosition
|
||||||
result.readDataImpl = ssReadData
|
|
||||||
result.peekDataImpl = ssPeekData
|
|
||||||
result.writeDataImpl = ssWriteData
|
|
||||||
result.readDataStrImpl = ssReadDataStr
|
result.readDataStrImpl = ssReadDataStr
|
||||||
|
when nimvm:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
result.readDataImpl = ssReadData
|
||||||
|
result.peekDataImpl = ssPeekData
|
||||||
|
result.writeDataImpl = ssWriteData
|
||||||
|
|
||||||
type
|
type
|
||||||
FileStream* = ref FileStreamObj
|
FileStream* = ref FileStreamObj
|
||||||
## A stream that encapsulates a `File`.
|
## A stream that encapsulates a `File`.
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
FileStreamObj* = object of Stream
|
|
||||||
## A file stream object.
|
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
f: File
|
|
||||||
|
|
||||||
proc fsClose(s: Stream) =
|
|
||||||
if FileStream(s).f != nil:
|
|
||||||
close(FileStream(s).f)
|
|
||||||
FileStream(s).f = nil
|
|
||||||
proc fsFlush(s: Stream) = flushFile(FileStream(s).f)
|
|
||||||
proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f)
|
|
||||||
proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos)
|
|
||||||
proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f))
|
|
||||||
|
|
||||||
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
|
||||||
result = readBuffer(FileStream(s).f, buffer, bufLen)
|
|
||||||
|
|
||||||
proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int =
|
|
||||||
result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a)
|
|
||||||
|
|
||||||
proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int =
|
|
||||||
let pos = fsGetPosition(s)
|
|
||||||
defer: fsSetPosition(s, pos)
|
|
||||||
result = readBuffer(FileStream(s).f, buffer, bufLen)
|
|
||||||
|
|
||||||
proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
|
||||||
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
|
|
||||||
raise newEIO("cannot write to stream")
|
|
||||||
|
|
||||||
proc fsReadLine(s: Stream, line: var TaintedString): bool =
|
|
||||||
result = readLine(FileStream(s).f, line)
|
|
||||||
|
|
||||||
proc newFileStream*(f: File): owned FileStream =
|
|
||||||
## Creates a new stream from the file `f`.
|
|
||||||
##
|
##
|
||||||
## **Note:** Not available for JS backend.
|
## **Note:** Not available for JS backend.
|
||||||
|
FileStreamObj* = object of Stream
|
||||||
|
## A file stream object.
|
||||||
##
|
##
|
||||||
## See also:
|
## **Note:** Not available for JS backend.
|
||||||
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
f: File
|
||||||
## from string.
|
|
||||||
## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same
|
proc fsClose(s: Stream) =
|
||||||
## as using `open proc <io.html#open,File,string,FileMode,int>`_
|
if FileStream(s).f != nil:
|
||||||
## on Examples.
|
close(FileStream(s).f)
|
||||||
## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
|
FileStream(s).f = nil
|
||||||
## file stream from the file name and the mode.
|
proc fsFlush(s: Stream) = flushFile(FileStream(s).f)
|
||||||
runnableExamples:
|
proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f)
|
||||||
|
proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos)
|
||||||
|
proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f))
|
||||||
|
|
||||||
|
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
|
result = readBuffer(FileStream(s).f, buffer, bufLen)
|
||||||
|
|
||||||
|
proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int =
|
||||||
|
result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a)
|
||||||
|
|
||||||
|
proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
|
let pos = fsGetPosition(s)
|
||||||
|
defer: fsSetPosition(s, pos)
|
||||||
|
result = readBuffer(FileStream(s).f, buffer, bufLen)
|
||||||
|
|
||||||
|
proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
|
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
|
||||||
|
raise newEIO("cannot write to stream")
|
||||||
|
|
||||||
|
proc fsReadLine(s: Stream, line: var TaintedString): bool =
|
||||||
|
result = readLine(FileStream(s).f, line)
|
||||||
|
|
||||||
|
proc newFileStream*(f: File): owned FileStream =
|
||||||
|
## Creates a new stream from the file `f`.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
||||||
|
## from string.
|
||||||
|
## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same
|
||||||
|
## as using `open proc <io.html#open,File,string,FileMode,int>`_
|
||||||
|
## on Examples.
|
||||||
|
## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
|
||||||
|
## file stream from the file name and the mode.
|
||||||
|
runnableExamples:
|
||||||
|
## Input (somefile.txt):
|
||||||
|
## The first line
|
||||||
|
## the second line
|
||||||
|
## the third line
|
||||||
|
var f: File
|
||||||
|
if open(f, "somefile.txt", fmRead, -1):
|
||||||
|
var strm = newFileStream(f)
|
||||||
|
var line = ""
|
||||||
|
while strm.readLine(line):
|
||||||
|
echo line
|
||||||
|
## Output:
|
||||||
|
## The first line
|
||||||
|
## the second line
|
||||||
|
## the third line
|
||||||
|
strm.close()
|
||||||
|
|
||||||
|
new(result)
|
||||||
|
result.f = f
|
||||||
|
result.closeImpl = fsClose
|
||||||
|
result.atEndImpl = fsAtEnd
|
||||||
|
result.setPositionImpl = fsSetPosition
|
||||||
|
result.getPositionImpl = fsGetPosition
|
||||||
|
result.readDataStrImpl = fsReadDataStr
|
||||||
|
result.readDataImpl = fsReadData
|
||||||
|
result.readLineImpl = fsReadLine
|
||||||
|
result.peekDataImpl = fsPeekData
|
||||||
|
result.writeDataImpl = fsWriteData
|
||||||
|
result.flushImpl = fsFlush
|
||||||
|
|
||||||
|
proc newFileStream*(filename: string, mode: FileMode = fmRead,
|
||||||
|
bufSize: int = -1): owned FileStream =
|
||||||
|
## Creates a new stream from the file named `filename` with the mode `mode`.
|
||||||
|
##
|
||||||
|
## If the file cannot be opened, `nil` is returned. See the `io module
|
||||||
|
## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_.
|
||||||
|
##
|
||||||
|
## **Note:**
|
||||||
|
## * **This function returns nil in case of failure.**
|
||||||
|
## To prevent unexpected behavior and ensure proper error handling,
|
||||||
|
## use `openFileStream proc <#openFileStream,string,FileMode,int>`_
|
||||||
|
## instead.
|
||||||
|
## * Not available for JS backend.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
||||||
|
## from string.
|
||||||
|
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
||||||
|
## opened File.
|
||||||
|
## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
|
||||||
|
## file stream from the file name and the mode.
|
||||||
|
runnableExamples:
|
||||||
|
from os import removeFile
|
||||||
|
var strm = newFileStream("somefile.txt", fmWrite)
|
||||||
|
if not isNil(strm):
|
||||||
|
strm.writeLine("The first line")
|
||||||
|
strm.writeLine("the second line")
|
||||||
|
strm.writeLine("the third line")
|
||||||
|
strm.close()
|
||||||
|
## Output (somefile.txt)
|
||||||
|
## The first line
|
||||||
|
## the second line
|
||||||
|
## the third line
|
||||||
|
removeFile("somefile.txt")
|
||||||
|
|
||||||
|
var f: File
|
||||||
|
if open(f, filename, mode, bufSize): result = newFileStream(f)
|
||||||
|
|
||||||
|
proc openFileStream*(filename: string, mode: FileMode = fmRead,
|
||||||
|
bufSize: int = -1): owned FileStream =
|
||||||
|
## Creates a new stream from the file named `filename` with the mode `mode`.
|
||||||
|
## If the file cannot be opened, an IO exception is raised.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
||||||
|
## from string.
|
||||||
|
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
||||||
|
## opened File.
|
||||||
|
## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a
|
||||||
|
## file stream from the file name and the mode.
|
||||||
|
runnableExamples:
|
||||||
|
try:
|
||||||
## Input (somefile.txt):
|
## Input (somefile.txt):
|
||||||
## The first line
|
## The first line
|
||||||
## the second line
|
## the second line
|
||||||
## the third line
|
## the third line
|
||||||
var f: File
|
var strm = openFileStream("somefile.txt")
|
||||||
if open(f, "somefile.txt", fmRead, -1):
|
echo strm.readLine()
|
||||||
var strm = newFileStream(f)
|
## Output:
|
||||||
var line = ""
|
## The first line
|
||||||
while strm.readLine(line):
|
strm.close()
|
||||||
echo line
|
except:
|
||||||
## Output:
|
stderr.write getCurrentExceptionMsg()
|
||||||
## The first line
|
|
||||||
## the second line
|
|
||||||
## the third line
|
|
||||||
strm.close()
|
|
||||||
|
|
||||||
new(result)
|
var f: File
|
||||||
result.f = f
|
if open(f, filename, mode, bufSize):
|
||||||
result.closeImpl = fsClose
|
return newFileStream(f)
|
||||||
result.atEndImpl = fsAtEnd
|
else:
|
||||||
result.setPositionImpl = fsSetPosition
|
raise newEIO("cannot open file stream: " & filename)
|
||||||
result.getPositionImpl = fsGetPosition
|
|
||||||
result.readDataStrImpl = fsReadDataStr
|
|
||||||
result.readDataImpl = fsReadData
|
|
||||||
result.readLineImpl = fsReadLine
|
|
||||||
result.peekDataImpl = fsPeekData
|
|
||||||
result.writeDataImpl = fsWriteData
|
|
||||||
result.flushImpl = fsFlush
|
|
||||||
|
|
||||||
proc newFileStream*(filename: string, mode: FileMode = fmRead,
|
|
||||||
bufSize: int = -1): owned FileStream =
|
|
||||||
## Creates a new stream from the file named `filename` with the mode `mode`.
|
|
||||||
##
|
|
||||||
## If the file cannot be opened, `nil` is returned. See the `io module
|
|
||||||
## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_.
|
|
||||||
##
|
|
||||||
## **Note:**
|
|
||||||
## * **This function returns nil in case of failure.**
|
|
||||||
## To prevent unexpected behavior and ensure proper error handling,
|
|
||||||
## use `openFileStream proc <#openFileStream,string,FileMode,int>`_
|
|
||||||
## instead.
|
|
||||||
## * Not available for JS backend.
|
|
||||||
##
|
|
||||||
## See also:
|
|
||||||
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
|
||||||
## from string.
|
|
||||||
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
|
||||||
## opened File.
|
|
||||||
## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
|
|
||||||
## file stream from the file name and the mode.
|
|
||||||
runnableExamples:
|
|
||||||
from os import removeFile
|
|
||||||
var strm = newFileStream("somefile.txt", fmWrite)
|
|
||||||
if not isNil(strm):
|
|
||||||
strm.writeLine("The first line")
|
|
||||||
strm.writeLine("the second line")
|
|
||||||
strm.writeLine("the third line")
|
|
||||||
strm.close()
|
|
||||||
## Output (somefile.txt)
|
|
||||||
## The first line
|
|
||||||
## the second line
|
|
||||||
## the third line
|
|
||||||
removeFile("somefile.txt")
|
|
||||||
|
|
||||||
var f: File
|
|
||||||
if open(f, filename, mode, bufSize): result = newFileStream(f)
|
|
||||||
|
|
||||||
proc openFileStream*(filename: string, mode: FileMode = fmRead,
|
|
||||||
bufSize: int = -1): owned FileStream =
|
|
||||||
## Creates a new stream from the file named `filename` with the mode `mode`.
|
|
||||||
## If the file cannot be opened, an IO exception is raised.
|
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
##
|
|
||||||
## See also:
|
|
||||||
## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
|
|
||||||
## from string.
|
|
||||||
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
|
||||||
## opened File.
|
|
||||||
## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a
|
|
||||||
## file stream from the file name and the mode.
|
|
||||||
runnableExamples:
|
|
||||||
try:
|
|
||||||
## Input (somefile.txt):
|
|
||||||
## The first line
|
|
||||||
## the second line
|
|
||||||
## the third line
|
|
||||||
var strm = openFileStream("somefile.txt")
|
|
||||||
echo strm.readLine()
|
|
||||||
## Output:
|
|
||||||
## The first line
|
|
||||||
strm.close()
|
|
||||||
except:
|
|
||||||
stderr.write getCurrentExceptionMsg()
|
|
||||||
|
|
||||||
var f: File
|
|
||||||
if open(f, filename, mode, bufSize):
|
|
||||||
return newFileStream(f)
|
|
||||||
else:
|
|
||||||
raise newEIO("cannot open file stream: " & filename)
|
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ runnableExamples:
|
||||||
import
|
import
|
||||||
hashes, strutils
|
hashes, strutils
|
||||||
|
|
||||||
when defined(js):
|
when defined(js) or defined(nimscript):
|
||||||
{.pragma: rtlFunc.}
|
{.pragma: rtlFunc.}
|
||||||
else:
|
else:
|
||||||
{.pragma: rtlFunc, rtl.}
|
{.pragma: rtlFunc, rtl.}
|
||||||
|
|
@ -298,7 +298,7 @@ proc raiseFormatException(s: string) =
|
||||||
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
||||||
if hasKey(t, key): return t.getOrDefault(key)
|
if hasKey(t, key): return t.getOrDefault(key)
|
||||||
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
||||||
when defined(js):
|
when defined(js) or defined(nimscript):
|
||||||
result = ""
|
result = ""
|
||||||
else:
|
else:
|
||||||
if useEnvironment in flags: result = os.getEnv(key).string
|
if useEnvironment in flags: result = os.getEnv(key).string
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) =
|
||||||
template rawPrint() = echo(prefix, "[", $testResult.status, "] ",
|
template rawPrint() = echo(prefix, "[", $testResult.status, "] ",
|
||||||
testResult.testName)
|
testResult.testName)
|
||||||
when not defined(ECMAScript):
|
when not defined(ECMAScript):
|
||||||
if formatter.colorOutput and not defined(ECMAScript):
|
if formatter.colorOutput:
|
||||||
var color = case testResult.status
|
var color = case testResult.status
|
||||||
of TestStatus.OK: fgGreen
|
of TestStatus.OK: fgGreen
|
||||||
of TestStatus.FAILED: fgRed
|
of TestStatus.FAILED: fgRed
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,24 @@
|
||||||
template volatileLoad*[T](src: ptr T): T =
|
template volatileLoad*[T](src: ptr T): T =
|
||||||
## Generates a volatile load of the value stored in the container `src`.
|
## Generates a volatile load of the value stored in the container `src`.
|
||||||
## Note that this only effects code generation on `C` like backends
|
## Note that this only effects code generation on `C` like backends
|
||||||
when defined(js):
|
when nimvm:
|
||||||
src[]
|
src[]
|
||||||
else:
|
else:
|
||||||
var res: T
|
when defined(js):
|
||||||
{.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].}
|
src[]
|
||||||
res
|
else:
|
||||||
|
var res: T
|
||||||
|
{.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].}
|
||||||
|
res
|
||||||
|
|
||||||
template volatileStore*[T](dest: ptr T, val: T) =
|
template volatileStore*[T](dest: ptr T, val: T) =
|
||||||
## Generates a volatile store into the container `dest` of the value
|
## Generates a volatile store into the container `dest` of the value
|
||||||
## `val`. Note that this only effects code generation on `C` like
|
## `val`. Note that this only effects code generation on `C` like
|
||||||
## backends
|
## backends
|
||||||
when defined(js):
|
when nimvm:
|
||||||
dest[] = val
|
dest[] = val
|
||||||
else:
|
else:
|
||||||
{.emit: ["*((", type(dest[]), " volatile*)(", dest, ")) = ", val, ";"].}
|
when defined(js):
|
||||||
|
dest[] = val
|
||||||
|
else:
|
||||||
|
{.emit: ["*((", type(dest[]), " volatile*)(", dest, ")) = ", val, ";"].}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
import system/indexerrors
|
include system/indexerrors
|
||||||
|
|
||||||
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
|
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
|
||||||
|
|
||||||
|
|
|
||||||
71
tests/js/tstdlib_imports.nim
Normal file
71
tests/js/tstdlib_imports.nim
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
discard """
|
||||||
|
action: compile
|
||||||
|
"""
|
||||||
|
|
||||||
|
{.warning[UnusedImport]: off.}
|
||||||
|
|
||||||
|
import std/[
|
||||||
|
# Core:
|
||||||
|
bitops, typetraits, lenientops, macros, volatile, typeinfo,
|
||||||
|
# fails: endians, rlocks
|
||||||
|
# works but shouldn't: cpuinfo, locks
|
||||||
|
|
||||||
|
# Algorithms:
|
||||||
|
algorithm, sequtils,
|
||||||
|
|
||||||
|
# Collections:
|
||||||
|
critbits, deques, heapqueue, intsets, lists, options, sets,
|
||||||
|
sharedlist, tables,
|
||||||
|
# fails: sharedtables
|
||||||
|
|
||||||
|
# Strings:
|
||||||
|
cstrutils, editdistance, wordwrap, parseutils, ropes,
|
||||||
|
pegs, punycode, strformat, strmisc, strscans, strtabs,
|
||||||
|
strutils, unicode, unidecode,
|
||||||
|
# fails: encodings
|
||||||
|
|
||||||
|
# Time handling:
|
||||||
|
monotimes, times,
|
||||||
|
|
||||||
|
# Generic operator system services:
|
||||||
|
os, streams,
|
||||||
|
# fails: distros, dynlib, marshal, memfiles, osproc, terminal
|
||||||
|
|
||||||
|
# Math libraries:
|
||||||
|
complex, math, mersenne, random, rationals, stats, sums,
|
||||||
|
# works but shouldn't: fenv
|
||||||
|
|
||||||
|
# Internet protocols:
|
||||||
|
cookies, httpcore, mimetypes, uri,
|
||||||
|
# fails: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver,
|
||||||
|
# asyncnet, cgi, httpclient, nativesockets, net, selectors, smtp
|
||||||
|
# works but shouldn't test: asyncstreams, asyncfutures
|
||||||
|
|
||||||
|
# Threading:
|
||||||
|
# fails: threadpool
|
||||||
|
|
||||||
|
# Parsers:
|
||||||
|
htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
|
||||||
|
# fails: parseopt
|
||||||
|
|
||||||
|
# XML processing:
|
||||||
|
xmltree, xmlparser,
|
||||||
|
|
||||||
|
# Generators:
|
||||||
|
htmlgen,
|
||||||
|
|
||||||
|
# Hashing:
|
||||||
|
base64, hashes,
|
||||||
|
# fails: md5, oids, sha1
|
||||||
|
|
||||||
|
# Miscellaneous:
|
||||||
|
colors, logging, sugar, unittest, varints,
|
||||||
|
# fails: browsers, coro
|
||||||
|
# works but shouldn't: segfaults
|
||||||
|
|
||||||
|
# Modules for JS backend:
|
||||||
|
asyncjs, dom, jsconsole, jscore, jsffi,
|
||||||
|
|
||||||
|
# Unlisted in lib.html:
|
||||||
|
decls, compilesettings, with, wrapnils
|
||||||
|
]
|
||||||
194
tests/js/tstdlib_various.nim
Normal file
194
tests/js/tstdlib_various.nim
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
abc
|
||||||
|
def
|
||||||
|
definition
|
||||||
|
prefix
|
||||||
|
xyz
|
||||||
|
def
|
||||||
|
definition
|
||||||
|
Hi Andreas! How do you feel, Rumpf?
|
||||||
|
|
||||||
|
@[0, 2, 1]
|
||||||
|
@[1, 0, 2]
|
||||||
|
@[1, 2, 0]
|
||||||
|
@[2, 0, 1]
|
||||||
|
@[2, 1, 0]
|
||||||
|
@[2, 0, 1]
|
||||||
|
@[1, 2, 0]
|
||||||
|
@[1, 0, 2]
|
||||||
|
@[0, 2, 1]
|
||||||
|
@[0, 1, 2]
|
||||||
|
[5]
|
||||||
|
[4, 5]
|
||||||
|
[3, 4, 5]
|
||||||
|
[2, 3, 4, 5]
|
||||||
|
[2, 3, 4, 5, 6]
|
||||||
|
[1, 2, 3, 4, 5, 6]
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import
|
||||||
|
critbits, cstrutils, sets, strutils, tables, random, algorithm, ropes,
|
||||||
|
lists, htmlgen, xmltree, strtabs
|
||||||
|
|
||||||
|
|
||||||
|
block tcritbits:
|
||||||
|
var r: CritBitTree[void]
|
||||||
|
r.incl "abc"
|
||||||
|
r.incl "xyz"
|
||||||
|
r.incl "def"
|
||||||
|
r.incl "definition"
|
||||||
|
r.incl "prefix"
|
||||||
|
doAssert r.contains"def"
|
||||||
|
#r.del "def"
|
||||||
|
|
||||||
|
for w in r.items:
|
||||||
|
echo w
|
||||||
|
for w in r.itemsWithPrefix("de"):
|
||||||
|
echo w
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block testequivalence:
|
||||||
|
doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
|
||||||
|
doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
|
||||||
|
doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
|
||||||
|
doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
|
||||||
|
doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
|
||||||
|
doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
|
||||||
|
doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
|
||||||
|
doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
|
||||||
|
doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block tformat:
|
||||||
|
echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block tnilecho:
|
||||||
|
var x = @["1", "", "3"]
|
||||||
|
doAssert $x == """@["1", "", "3"]"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block torderedtable:
|
||||||
|
var t = initOrderedTable[int,string]()
|
||||||
|
|
||||||
|
# this tests issue #5917
|
||||||
|
var data = newSeq[int]()
|
||||||
|
for i in 0..<1000:
|
||||||
|
var x = rand(1000)
|
||||||
|
if x notin t: data.add(x)
|
||||||
|
t[x] = "meh"
|
||||||
|
|
||||||
|
# this checks that keys are re-inserted
|
||||||
|
# in order when table is enlarged.
|
||||||
|
var i = 0
|
||||||
|
for k, v in t:
|
||||||
|
doAssert(k == data[i])
|
||||||
|
doAssert(v == "meh")
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block tpermutations:
|
||||||
|
var v = @[0, 1, 2]
|
||||||
|
while v.nextPermutation():
|
||||||
|
echo v
|
||||||
|
while v.prevPermutation():
|
||||||
|
echo v
|
||||||
|
|
||||||
|
|
||||||
|
block tropes:
|
||||||
|
var
|
||||||
|
r1 = rope("")
|
||||||
|
r2 = rope("123")
|
||||||
|
doAssert r1.len == 0
|
||||||
|
doAssert r2.len == 3
|
||||||
|
doAssert $r1 == ""
|
||||||
|
doAssert $r2 == "123"
|
||||||
|
|
||||||
|
r1.add("123")
|
||||||
|
r2.add("456")
|
||||||
|
doAssert r1.len == 3
|
||||||
|
doAssert r2.len == 6
|
||||||
|
doAssert $r1 == "123"
|
||||||
|
doAssert $r2 == "123456"
|
||||||
|
doAssert $r1[1] == "2"
|
||||||
|
doAssert $r2[2] == "3"
|
||||||
|
|
||||||
|
|
||||||
|
block tsinglylinkedring:
|
||||||
|
var r = initSinglyLinkedRing[int]()
|
||||||
|
r.prepend(5)
|
||||||
|
echo r
|
||||||
|
r.prepend(4)
|
||||||
|
echo r
|
||||||
|
r.prepend(3)
|
||||||
|
echo r
|
||||||
|
r.prepend(2)
|
||||||
|
echo r
|
||||||
|
r.append(6)
|
||||||
|
echo r
|
||||||
|
r.prepend(1)
|
||||||
|
echo r
|
||||||
|
|
||||||
|
block tsplit:
|
||||||
|
var s = ""
|
||||||
|
for w in split("|abc|xy|z", {'|'}):
|
||||||
|
s.add("#")
|
||||||
|
s.add(w)
|
||||||
|
|
||||||
|
doAssert s == "##abc#xy#z"
|
||||||
|
|
||||||
|
block tsplit2:
|
||||||
|
var s = ""
|
||||||
|
for w in split("|abc|xy|z", {'|'}):
|
||||||
|
s.add("#")
|
||||||
|
s.add(w)
|
||||||
|
|
||||||
|
var errored = false
|
||||||
|
try:
|
||||||
|
discard "hello".split("")
|
||||||
|
except AssertionError:
|
||||||
|
errored = true
|
||||||
|
doAssert errored
|
||||||
|
|
||||||
|
block txmlgen:
|
||||||
|
var nim = "Nim"
|
||||||
|
doAssert h1(a(href="http://force7.de/nim", nim)) ==
|
||||||
|
"<h1><a href=\"http://force7.de/nim\">Nim</a></h1>"
|
||||||
|
|
||||||
|
block txmltree:
|
||||||
|
var x = <>a(href="nim.de", newText("www.nim-test.de"))
|
||||||
|
|
||||||
|
doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>")
|
||||||
|
doAssert(newText("foo").innerText == "foo")
|
||||||
|
doAssert(newEntity("bar").innerText == "bar")
|
||||||
|
doAssert(newComment("baz").innerText == "")
|
||||||
|
|
||||||
|
let y = newXmlTree("x", [
|
||||||
|
newText("foo"),
|
||||||
|
newXmlTree("y", [
|
||||||
|
newText("bar")
|
||||||
|
])
|
||||||
|
])
|
||||||
|
doAssert(y.innerText == "foobar")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
block tcstrutils:
|
||||||
|
let s = cstring "abcdef"
|
||||||
|
doAssert s.startsWith("a")
|
||||||
|
doAssert not s.startsWith("b")
|
||||||
|
doAssert s.endsWith("f")
|
||||||
|
doAssert not s.endsWith("a")
|
||||||
|
|
||||||
|
let a = cstring "abracadabra"
|
||||||
|
doAssert a.startsWith("abra")
|
||||||
|
doAssert not a.startsWith("bra")
|
||||||
|
doAssert a.endsWith("abra")
|
||||||
|
doAssert not a.endsWith("dab")
|
||||||
22
tests/js/tstreams.nim
Normal file
22
tests/js/tstreams.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
I
|
||||||
|
AM
|
||||||
|
GROOT
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import streams
|
||||||
|
|
||||||
|
var s = newStringStream("I\nAM\nGROOT")
|
||||||
|
doAssert s.peekStr(1) == "I"
|
||||||
|
doAssert s.peekChar() == 'I'
|
||||||
|
for line in s.lines:
|
||||||
|
echo line
|
||||||
|
s.close
|
||||||
|
|
||||||
|
var s2 = newStringStream("abc")
|
||||||
|
doAssert s2.readAll == "abc"
|
||||||
|
s2.write("def")
|
||||||
|
doAssert s2.data == "abcdef"
|
||||||
|
s2.close
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
|
targets: "c js"
|
||||||
output: '''
|
output: '''
|
||||||
@[]
|
|
||||||
true
|
true
|
||||||
https://example.com/test?format=jpg&name=orig##
|
https://example.com/test?format=jpg&name=orig##
|
||||||
https://example.com/test?format=jpg&name=orig##text
|
https://example.com/test?format=jpg&name=orig##text
|
||||||
|
|
@ -40,7 +40,7 @@ block t2813:
|
||||||
"""
|
"""
|
||||||
var errors: seq[string] = @[]
|
var errors: seq[string] = @[]
|
||||||
let tree = parseHtml(newStringStream(html), "test.html", errors)
|
let tree = parseHtml(newStringStream(html), "test.html", errors)
|
||||||
echo errors # Errors: </thead> expected,...
|
doAssert errors.len == 0 # Errors: </thead> expected,...
|
||||||
|
|
||||||
var len = tree.findAll("tr").len # len = 6
|
var len = tree.findAll("tr").len # len = 6
|
||||||
var rows: seq[XmlNode] = @[]
|
var rows: seq[XmlNode] = @[]
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''
|
targets: "c js"
|
||||||
utf-8
|
|
||||||
on
|
|
||||||
hello
|
|
||||||
lihf8515
|
|
||||||
10214028
|
|
||||||
lihaifeng@wxm.com
|
|
||||||
===
|
|
||||||
charset=utf-8
|
|
||||||
[Package]
|
|
||||||
name=hello
|
|
||||||
--threads:on
|
|
||||||
[Author]
|
|
||||||
name=lhf
|
|
||||||
qq=10214028
|
|
||||||
email="lihaifeng@wxm.com"
|
|
||||||
===
|
|
||||||
charset=utf-8
|
|
||||||
[Package]
|
|
||||||
name=hello
|
|
||||||
--threads:on
|
|
||||||
[Author]
|
|
||||||
name=lihf8515
|
|
||||||
qq=10214028
|
|
||||||
'''
|
|
||||||
"""
|
"""
|
||||||
import parsecfg, streams
|
import parsecfg, streams
|
||||||
|
|
||||||
|
|
@ -46,24 +22,35 @@ var pname = dict2.getSectionValue("Package","name")
|
||||||
var name = dict2.getSectionValue("Author","name")
|
var name = dict2.getSectionValue("Author","name")
|
||||||
var qq = dict2.getSectionValue("Author","qq")
|
var qq = dict2.getSectionValue("Author","qq")
|
||||||
var email = dict2.getSectionValue("Author","email")
|
var email = dict2.getSectionValue("Author","email")
|
||||||
echo charset
|
doAssert charset == "utf-8"
|
||||||
echo threads
|
doAssert threads == "on"
|
||||||
echo pname
|
doAssert pname == "hello"
|
||||||
echo name
|
doAssert name == "lihf8515"
|
||||||
echo qq
|
doAssert qq == "10214028"
|
||||||
echo email
|
doAssert email == "lihaifeng@wxm.com"
|
||||||
|
|
||||||
echo "==="
|
|
||||||
|
|
||||||
## Modifying a configuration file.
|
## Modifying a configuration file.
|
||||||
var dict3 = loadConfig(newStringStream(ss.data))
|
var dict3 = loadConfig(newStringStream(ss.data))
|
||||||
dict3.setSectionKey("Author","name","lhf")
|
dict3.setSectionKey("Author","name","lhf")
|
||||||
write(stdout, $dict3)
|
doAssert $dict3 == """charset=utf-8
|
||||||
|
[Package]
|
||||||
echo "==="
|
name=hello
|
||||||
|
--threads:on
|
||||||
|
[Author]
|
||||||
|
name=lhf
|
||||||
|
qq=10214028
|
||||||
|
email="lihaifeng@wxm.com"
|
||||||
|
"""
|
||||||
|
|
||||||
## Deleting a section key in a configuration file.
|
## Deleting a section key in a configuration file.
|
||||||
var dict4 = loadConfig(newStringStream(ss.data))
|
var dict4 = loadConfig(newStringStream(ss.data))
|
||||||
dict4.delSectionKey("Author","email")
|
dict4.delSectionKey("Author","email")
|
||||||
write(stdout, $dict4)
|
doAssert $dict4 == """charset=utf-8
|
||||||
|
[Package]
|
||||||
|
name=hello
|
||||||
|
--threads:on
|
||||||
|
[Author]
|
||||||
|
name=lihf8515
|
||||||
|
qq=10214028
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
discard """
|
||||||
|
targets: "c js"
|
||||||
|
"""
|
||||||
import parsesql
|
import parsesql
|
||||||
|
|
||||||
doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
|
doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
|
targets: "c js"
|
||||||
output: '''
|
output: '''
|
||||||
PEG AST traversal output
|
PEG AST traversal output
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ true
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import
|
import
|
||||||
critbits, sets, strutils, tables, random, algorithm, re, ropes, segfaults,
|
critbits, cstrutils, sets, strutils, tables, random, algorithm, re, ropes,
|
||||||
lists, parsesql, streams, os, htmlgen, xmltree, strtabs
|
segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs
|
||||||
|
|
||||||
|
|
||||||
block tcritbits:
|
block tcritbits:
|
||||||
|
|
@ -245,3 +245,24 @@ block txmltree:
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
doAssert(y.innerText == "foobar")
|
doAssert(y.innerText == "foobar")
|
||||||
|
|
||||||
|
|
||||||
|
block tcstrutils:
|
||||||
|
let s = cstring "abcdef"
|
||||||
|
doAssert s.startsWith("a")
|
||||||
|
doAssert not s.startsWith("b")
|
||||||
|
doAssert s.endsWith("f")
|
||||||
|
doAssert not s.endsWith("a")
|
||||||
|
|
||||||
|
let a = cstring "abracadabra"
|
||||||
|
doAssert a.startsWith("abra")
|
||||||
|
doAssert not a.startsWith("bra")
|
||||||
|
doAssert a.endsWith("abra")
|
||||||
|
doAssert not a.endsWith("dab")
|
||||||
|
|
||||||
|
doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0
|
||||||
|
doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0
|
||||||
|
doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0
|
||||||
|
|
||||||
|
doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0
|
||||||
|
doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,74 @@
|
||||||
# This nimscript is used to test if the following modules can be imported
|
# This nimscript is used to test if the following modules can be imported
|
||||||
# http://nim-lang.org/docs/nims.html
|
# http://nim-lang.org/docs/nims.html
|
||||||
|
|
||||||
import algorithm
|
{.warning[UnusedImport]: off.}
|
||||||
import base64
|
|
||||||
import colors
|
import std/[
|
||||||
import hashes
|
# Core:
|
||||||
import lists
|
bitops, typetraits, lenientops, macros, volatile,
|
||||||
import math
|
# fails: typeinfo, endians
|
||||||
# import marshal
|
# works but shouldn't: cpuinfo, rlocks, locks
|
||||||
import options
|
|
||||||
import os
|
# Algorithms:
|
||||||
# import parsecfg
|
algorithm, sequtils,
|
||||||
# import parseopt
|
|
||||||
import parseutils
|
# Collections:
|
||||||
# import pegs
|
critbits, deques, heapqueue, intsets, lists, options, sets,
|
||||||
import deques
|
sharedlist, tables,
|
||||||
import sequtils
|
# fails: sharedtables
|
||||||
import strutils
|
|
||||||
import tables
|
# Strings:
|
||||||
import unicode
|
editdistance, wordwrap, parseutils, ropes,
|
||||||
import uri
|
pegs, punycode, strformat, strmisc, strscans, strtabs,
|
||||||
import macros
|
strutils, unicode, unidecode,
|
||||||
|
# works but shouldn't: cstrutils, encodings
|
||||||
|
|
||||||
|
# Time handling:
|
||||||
|
# fails: monotimes, times
|
||||||
|
# but times.getTime() implemented for VM
|
||||||
|
|
||||||
|
# Generic operator system services:
|
||||||
|
os, streams,
|
||||||
|
# fails: distros, dynlib, marshal, memfiles, osproc, terminal
|
||||||
|
|
||||||
|
# Math libraries:
|
||||||
|
complex, math, mersenne, random, rationals, stats, sums,
|
||||||
|
# works but shouldn't: fenv
|
||||||
|
|
||||||
|
# Internet protocols:
|
||||||
|
httpcore, mimetypes, uri,
|
||||||
|
# fails: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver,
|
||||||
|
# asyncnet, cgi, cookies, httpclient, nativesockets, net, selectors, smtp
|
||||||
|
# works but shouldn't test: asyncstreams, asyncfutures
|
||||||
|
|
||||||
|
# Threading:
|
||||||
|
# fails: threadpool
|
||||||
|
|
||||||
|
# Parsers:
|
||||||
|
htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
|
||||||
|
# fails: parseopt
|
||||||
|
|
||||||
|
# XML processing:
|
||||||
|
xmltree, xmlparser,
|
||||||
|
|
||||||
|
# Generators:
|
||||||
|
htmlgen,
|
||||||
|
|
||||||
|
# Hashing:
|
||||||
|
base64, hashes,
|
||||||
|
# fails: md5, oids, sha1
|
||||||
|
|
||||||
|
# Miscellaneous:
|
||||||
|
colors, sugar, varints,
|
||||||
|
# fails: browsers, coro, logging (times), segfaults, unittest (uses methods)
|
||||||
|
|
||||||
|
# Modules for JS backend:
|
||||||
|
# fails: asyncjs, dom, jsconsole, jscore, jsffi,
|
||||||
|
|
||||||
|
# Unlisted in lib.html:
|
||||||
|
decls, compilesettings, with, wrapnils
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
block:
|
block:
|
||||||
doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath
|
doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue