mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-05 03:14:08 +00:00
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:
11
changelog.md
11
changelog.md
@@ -37,6 +37,17 @@
|
||||
and this can now throw in edge cases where `getCurrentDir` throws.
|
||||
`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
|
||||
accept an existing string to modify, which avoids memory
|
||||
allocations, similar to `streams.readLine` (#13857).
|
||||
|
||||
@@ -76,13 +76,15 @@ available. This includes:
|
||||
* manual memory management (``alloc``, etc.)
|
||||
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||
* file management
|
||||
* most modules of the standard library
|
||||
* OS-specific operations
|
||||
* threading, coroutines
|
||||
* some modules of the standard library
|
||||
* proper 64 bit integer arithmetic
|
||||
* unsigned integer arithmetic
|
||||
|
||||
However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and
|
||||
`times <times.html>`_ are available! To access the DOM, use the `dom
|
||||
<dom.html>`_ module that is only available for the JavaScript platform.
|
||||
To compensate, the standard library has modules `catered to the JS backend
|
||||
<https://nim-lang.org/docs/lib.html#pure-libraries-modules-for-js-backend>`_
|
||||
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
|
||||
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.
|
||||
|
||||
* ``unicode`` can be imported, but not ``unidecode``.
|
||||
|
||||
|
||||
Standard library modules
|
||||
========================
|
||||
|
||||
@@ -19,29 +19,43 @@ proc toLowerAscii(c: char): char {.inline.} =
|
||||
else:
|
||||
result = c
|
||||
|
||||
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
||||
rtl, extern: "csuStartsWith".} =
|
||||
## Returns true iff ``s`` starts with ``prefix``.
|
||||
##
|
||||
## 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)
|
||||
when defined(js):
|
||||
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
||||
importjs: "#.startsWith(#)".}
|
||||
|
||||
proc endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
||||
rtl, extern: "csuEndsWith".} =
|
||||
## Returns true iff ``s`` ends with ``suffix``.
|
||||
##
|
||||
## If ``suffix == ""`` true is returned.
|
||||
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 endsWith*(s, suffix: cstring): bool {.noSideEffect,
|
||||
importjs: "#.endsWith(#)".}
|
||||
|
||||
# JS string has more operations that might warrant its own module:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||
else:
|
||||
proc startsWith*(s, prefix: cstring): bool {.noSideEffect,
|
||||
rtl, extern: "csuStartsWith".} =
|
||||
## Returns true iff ``s`` starts with ``prefix``.
|
||||
##
|
||||
## If ``prefix == ""`` true is returned.
|
||||
##
|
||||
## 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,
|
||||
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
|
||||
##
|
||||
## Not supported for JS backend, use `strutils.cmpIgnoreStyle
|
||||
## <https://nim-lang.org/docs/strutils.html#cmpIgnoreStyle%2Cstring%2Cstring>`_ instead.
|
||||
var i = 0
|
||||
var j = 0
|
||||
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
|
||||
##
|
||||
## Not supported for JS backend, use `strutils.cmpIgnoreCase
|
||||
## <https://nim-lang.org/docs/strutils.html#cmpIgnoreCase%2Cstring%2Cstring>`_ instead.
|
||||
var i = 0
|
||||
while true:
|
||||
var aa = toLowerAscii(a[i])
|
||||
|
||||
@@ -52,7 +52,8 @@ proc fillBuffer(L: var BaseLexer) =
|
||||
toCopy = L.buf.len - (L.sentinel + 1)
|
||||
assert(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:
|
||||
L.buf[i] = L.buf[L.sentinel + 1 + i]
|
||||
else:
|
||||
|
||||
@@ -50,8 +50,14 @@
|
||||
## * `streams module <streams.html>`_
|
||||
## * `json module <json.html>`_
|
||||
|
||||
when defined(nimV2):
|
||||
{.error: """marshal module is not supported in new runtime.
|
||||
const unsupportedPlatform =
|
||||
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.
|
||||
It is possible to reimplement this module using generics and type traits.
|
||||
Please contribute new implementation.""".}
|
||||
|
||||
@@ -557,7 +557,14 @@ type
|
||||
tok: Token
|
||||
|
||||
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 =
|
||||
result = SqlNode(kind: k)
|
||||
@@ -1469,34 +1476,33 @@ proc treeRepr*(s: SqlNode): string =
|
||||
result = newStringOfCap(128)
|
||||
treeReprAux(s, 0, result)
|
||||
|
||||
when not defined(js):
|
||||
import streams
|
||||
import streams
|
||||
|
||||
proc open(L: var SqlLexer, input: Stream, filename: string) =
|
||||
lexbase.open(L, input)
|
||||
L.filename = filename
|
||||
proc open(L: var SqlLexer, input: Stream, filename: string) =
|
||||
lexbase.open(L, input)
|
||||
L.filename = filename
|
||||
|
||||
proc open(p: var SqlParser, input: Stream, filename: string) =
|
||||
## opens the parser `p` and assigns the input stream `input` to it.
|
||||
## `filename` is only used for error messages.
|
||||
open(SqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
proc open(p: var SqlParser, input: Stream, filename: string) =
|
||||
## opens the parser `p` and assigns the input stream `input` to it.
|
||||
## `filename` is only used for error messages.
|
||||
open(SqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
|
||||
proc parseSQL*(input: Stream, filename: string): SqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `SqlParseError` exception.
|
||||
var p: SqlParser
|
||||
open(p, input, filename)
|
||||
try:
|
||||
result = parse(p)
|
||||
finally:
|
||||
close(p)
|
||||
proc parseSQL*(input: Stream, filename: string): SqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `SqlParseError` exception.
|
||||
var p: SqlParser
|
||||
open(p, input, filename)
|
||||
try:
|
||||
result = parse(p)
|
||||
finally:
|
||||
close(p)
|
||||
|
||||
proc parseSQL*(input: string, filename = ""): SqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `SqlParseError` exception.
|
||||
parseSQL(newStringStream(input), "")
|
||||
proc parseSQL*(input: string, filename = ""): SqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `SqlParseError` exception.
|
||||
parseSQL(newStringStream(input), "")
|
||||
|
||||
@@ -287,46 +287,47 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
|
||||
## shortcut for ``add(c, frmt % args)``.
|
||||
add(c, frmt % args)
|
||||
|
||||
const
|
||||
bufSize = 1024 # 1 KB is reasonable
|
||||
when not defined(js) and not defined(nimscript):
|
||||
const
|
||||
bufSize = 1024 # 1 KB is reasonable
|
||||
|
||||
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
|
||||
## returns true if the contents of the file `f` equal `r`.
|
||||
var
|
||||
buf: array[bufSize, char]
|
||||
bpos = buf.len
|
||||
blen = buf.len
|
||||
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
|
||||
## returns true if the contents of the file `f` equal `r`.
|
||||
var
|
||||
buf: array[bufSize, char]
|
||||
bpos = buf.len
|
||||
blen = buf.len
|
||||
|
||||
for s in leaves(r):
|
||||
var spos = 0
|
||||
let slen = s.len
|
||||
while spos < slen:
|
||||
if bpos == blen:
|
||||
# Read more data
|
||||
bpos = 0
|
||||
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||
if blen == 0: # no more data in file
|
||||
for s in leaves(r):
|
||||
var spos = 0
|
||||
let slen = s.len
|
||||
while spos < slen:
|
||||
if bpos == blen:
|
||||
# Read more data
|
||||
bpos = 0
|
||||
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||
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
|
||||
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
|
||||
return
|
||||
spos += n
|
||||
bpos += n
|
||||
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".} =
|
||||
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
||||
## exist, false is returned.
|
||||
var f: File
|
||||
result = open(f, filename)
|
||||
if result:
|
||||
result = equalsFile(r, f)
|
||||
close(f)
|
||||
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
|
||||
## exist, false is returned.
|
||||
var f: File
|
||||
result = open(f, filename)
|
||||
if result:
|
||||
result = equalsFile(r, f)
|
||||
close(f)
|
||||
|
||||
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 =
|
||||
## 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:
|
||||
var strm = newStringStream("abcde")
|
||||
var buffer: array[6, char]
|
||||
@@ -241,11 +244,21 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int =
|
||||
# fallback
|
||||
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 =
|
||||
## Reads all available data.
|
||||
##
|
||||
## **Note:** Not available for JS backend.
|
||||
runnableExamples:
|
||||
var strm = newStringStream("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()
|
||||
|
||||
const bufferSize = 1024
|
||||
when nimvm:
|
||||
jsOrVmBlock:
|
||||
var buffer2: string
|
||||
buffer2.setLen(bufferSize)
|
||||
while true:
|
||||
@@ -265,7 +278,7 @@ when not defined(js):
|
||||
result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes]
|
||||
if readBytes < bufferSize:
|
||||
break
|
||||
else:
|
||||
do: # not JS or VM
|
||||
var buffer {.noinit.}: array[bufferSize, char]
|
||||
while true:
|
||||
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 =
|
||||
## Low level proc that reads data into an untyped `buffer` of `bufLen` size
|
||||
## without moving stream position.
|
||||
##
|
||||
## **JS note:** `buffer` is treated as a ``ptr string`` and written to between
|
||||
## ``0..<bufLen``.
|
||||
runnableExamples:
|
||||
var strm = newStringStream("abcde")
|
||||
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) =
|
||||
## Low level proc that writes an untyped `buffer` of `bufLen` size
|
||||
## to the stream `s`.
|
||||
##
|
||||
## **JS note:** `buffer` is treated as a ``ptr string`` and read between
|
||||
## ``0..<bufLen``.
|
||||
runnableExamples:
|
||||
## writeData
|
||||
var strm = newStringStream("")
|
||||
@@ -311,6 +330,9 @@ proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
|
||||
proc write*[T](s: Stream, x: T) =
|
||||
## 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
|
||||
##
|
||||
## s.writeData(s, unsafeAddr(x), sizeof(x))
|
||||
@@ -336,7 +358,12 @@ proc write*(s: Stream, x: string) =
|
||||
when nimvm:
|
||||
writeData(s, cstring(x), x.len)
|
||||
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, `$`]) =
|
||||
## 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) =
|
||||
## Generic read procedure. Reads `result` from the stream `s`.
|
||||
##
|
||||
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||
runnableExamples:
|
||||
var strm = newStringStream("012")
|
||||
## readInt
|
||||
@@ -383,6 +412,8 @@ proc read*[T](s: Stream, result: var T) =
|
||||
|
||||
proc peek*[T](s: Stream, result: var T) =
|
||||
## Generic peek procedure. Peeks `result` from the stream `s`.
|
||||
##
|
||||
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||
runnableExamples:
|
||||
var strm = newStringStream("012")
|
||||
## peekInt
|
||||
@@ -412,11 +443,11 @@ proc readChar*(s: Stream): char =
|
||||
doAssert strm.readChar() == '\x00'
|
||||
strm.close()
|
||||
|
||||
when nimvm:
|
||||
jsOrVmBlock:
|
||||
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:
|
||||
do:
|
||||
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
||||
|
||||
proc peekChar*(s: Stream): char =
|
||||
@@ -430,7 +461,12 @@ proc peekChar*(s: Stream): char =
|
||||
doAssert strm.peekChar() == '\x00'
|
||||
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 =
|
||||
## 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
|
||||
## (`0000_0000`) value.
|
||||
## Raises `IOError` if an error occurred.
|
||||
##
|
||||
## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now.
|
||||
runnableExamples:
|
||||
var strm = newStringStream()
|
||||
## 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
|
||||
## (`0000_0000`) value.
|
||||
## Raises `IOError` if an error occurred.
|
||||
##
|
||||
## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now.
|
||||
runnableExamples:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -482,6 +522,8 @@ proc peekBool*(s: Stream): bool =
|
||||
|
||||
proc readInt8*(s: Stream): int8 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -499,6 +541,8 @@ proc readInt8*(s: Stream): int8 =
|
||||
|
||||
proc peekInt8*(s: Stream): int8 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -518,6 +562,8 @@ proc peekInt8*(s: Stream): int8 =
|
||||
|
||||
proc readInt16*(s: Stream): int16 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -535,6 +581,8 @@ proc readInt16*(s: Stream): int16 =
|
||||
|
||||
proc peekInt16*(s: Stream): int16 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -554,6 +602,8 @@ proc peekInt16*(s: Stream): int16 =
|
||||
|
||||
proc readInt32*(s: Stream): int32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -571,6 +621,8 @@ proc readInt32*(s: Stream): int32 =
|
||||
|
||||
proc peekInt32*(s: Stream): int32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -590,6 +642,8 @@ proc peekInt32*(s: Stream): int32 =
|
||||
|
||||
proc readInt64*(s: Stream): int64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -607,6 +661,8 @@ proc readInt64*(s: Stream): int64 =
|
||||
|
||||
proc peekInt64*(s: Stream): int64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -626,6 +682,8 @@ proc peekInt64*(s: Stream): int64 =
|
||||
|
||||
proc readUint8*(s: Stream): uint8 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -643,6 +701,8 @@ proc readUint8*(s: Stream): uint8 =
|
||||
|
||||
proc peekUint8*(s: Stream): uint8 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -662,6 +722,8 @@ proc peekUint8*(s: Stream): uint8 =
|
||||
|
||||
proc readUint16*(s: Stream): uint16 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -679,6 +741,8 @@ proc readUint16*(s: Stream): uint16 =
|
||||
|
||||
proc peekUint16*(s: Stream): uint16 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -698,6 +762,8 @@ proc peekUint16*(s: Stream): uint16 =
|
||||
|
||||
proc readUint32*(s: Stream): uint32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -716,6 +782,8 @@ proc readUint32*(s: Stream): uint32 =
|
||||
|
||||
proc peekUint32*(s: Stream): uint32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -735,6 +803,8 @@ proc peekUint32*(s: Stream): uint32 =
|
||||
|
||||
proc readUint64*(s: Stream): uint64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -752,6 +822,8 @@ proc readUint64*(s: Stream): uint64 =
|
||||
|
||||
proc peekUint64*(s: Stream): uint64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -771,6 +843,8 @@ proc peekUint64*(s: Stream): uint64 =
|
||||
|
||||
proc readFloat32*(s: Stream): float32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -788,6 +862,8 @@ proc readFloat32*(s: Stream): float32 =
|
||||
|
||||
proc peekFloat32*(s: Stream): float32 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -807,6 +883,8 @@ proc peekFloat32*(s: Stream): float32 =
|
||||
|
||||
proc readFloat64*(s: Stream): float64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -824,6 +902,8 @@ proc readFloat64*(s: Stream): float64 =
|
||||
|
||||
proc peekFloat64*(s: Stream): float64 =
|
||||
## 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:
|
||||
var strm = newStringStream()
|
||||
## setup for reading data
|
||||
@@ -841,10 +921,19 @@ proc peekFloat64*(s: Stream): float64 =
|
||||
|
||||
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) =
|
||||
if length > len(str): setLen(str.string, length)
|
||||
var L = readData(s, cstring(str), length)
|
||||
if L != len(str): setLen(str.string, L)
|
||||
if length > len(str): setLen(str.untaint, length)
|
||||
when defined(js):
|
||||
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).} =
|
||||
## 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)
|
||||
|
||||
proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) =
|
||||
if length > len(str): setLen(str.string, length)
|
||||
var L = peekData(s, cstring(str), length)
|
||||
if L != len(str): setLen(str.string, L)
|
||||
if length > len(str): setLen(str.untaint, length)
|
||||
when defined(js):
|
||||
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).} =
|
||||
## 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)
|
||||
else:
|
||||
# fallback
|
||||
when nimvm: #Bug #12282
|
||||
when taintMode:
|
||||
line.string.setLen(0)
|
||||
else:
|
||||
line.setLen(0)
|
||||
else:
|
||||
line.string.setLen(0)
|
||||
line.untaint.setLen(0)
|
||||
while true:
|
||||
var c = readChar(s)
|
||||
if c == '\c':
|
||||
@@ -934,13 +1020,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||
elif c == '\0':
|
||||
if line.len > 0: break
|
||||
else: return false
|
||||
when nimvm: #Bug #12282
|
||||
when taintMode:
|
||||
line.string.add(c)
|
||||
else:
|
||||
line.add(c)
|
||||
else:
|
||||
line.string.add(c)
|
||||
line.untaint.add(c)
|
||||
result = true
|
||||
|
||||
proc peekLine*(s: Stream, line: var TaintedString): bool =
|
||||
@@ -1002,7 +1082,7 @@ proc readLine*(s: Stream): TaintedString =
|
||||
if c == '\L' or c == '\0':
|
||||
break
|
||||
else:
|
||||
result.string.add(c)
|
||||
result.untaint.add(c)
|
||||
|
||||
proc peekLine*(s: Stream): TaintedString =
|
||||
## Peeks a line from a stream `s`. Raises `IOError` if an error occurred.
|
||||
@@ -1048,17 +1128,13 @@ iterator lines*(s: Stream): TaintedString =
|
||||
type
|
||||
StringStream* = ref StringStreamObj
|
||||
## A stream that encapsulates a string.
|
||||
##
|
||||
## **Note:** Not available for JS backend.
|
||||
StringStreamObj* = object of StreamObj
|
||||
## A string stream object.
|
||||
##
|
||||
## **Note:** Not available for JS backend.
|
||||
data*: string ## A string data.
|
||||
## This is updated when called `writeLine` etc.
|
||||
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.} =
|
||||
var s = StringStream(s)
|
||||
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:
|
||||
break
|
||||
|
||||
else:
|
||||
else: # after 1.3 or JS not defined
|
||||
proc ssAtEnd(s: Stream): bool =
|
||||
var s = StringStream(s)
|
||||
return s.pos >= s.data.len
|
||||
@@ -1128,9 +1204,9 @@ else:
|
||||
var s = StringStream(s)
|
||||
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
||||
if result > 0:
|
||||
when nimvm:
|
||||
jsOrVmBlock:
|
||||
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)
|
||||
inc(s.pos, result)
|
||||
else:
|
||||
@@ -1140,7 +1216,14 @@ else:
|
||||
var s = StringStream(s)
|
||||
result = min(bufLen, s.data.len - s.pos)
|
||||
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)
|
||||
else:
|
||||
result = 0
|
||||
@@ -1149,7 +1232,14 @@ else:
|
||||
var s = StringStream(s)
|
||||
result = min(bufLen, s.data.len - s.pos)
|
||||
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:
|
||||
result = 0
|
||||
|
||||
@@ -1159,7 +1249,14 @@ else:
|
||||
return
|
||||
if s.pos + bufLen > s.data.len:
|
||||
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)
|
||||
|
||||
proc ssClose(s: Stream) =
|
||||
@@ -1172,8 +1269,6 @@ else:
|
||||
proc newStringStream*(s: string = ""): owned StringStream =
|
||||
## Creates a new stream from the string `s`.
|
||||
##
|
||||
## **Note:** Not available for JS backend.
|
||||
##
|
||||
## See also:
|
||||
## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
|
||||
## opened File.
|
||||
@@ -1195,163 +1290,166 @@ else:
|
||||
result.atEndImpl = ssAtEnd
|
||||
result.setPositionImpl = ssSetPosition
|
||||
result.getPositionImpl = ssGetPosition
|
||||
result.readDataImpl = ssReadData
|
||||
result.peekDataImpl = ssPeekData
|
||||
result.writeDataImpl = ssWriteData
|
||||
result.readDataStrImpl = ssReadDataStr
|
||||
when nimvm:
|
||||
discard
|
||||
else:
|
||||
result.readDataImpl = ssReadData
|
||||
result.peekDataImpl = ssPeekData
|
||||
result.writeDataImpl = ssWriteData
|
||||
|
||||
type
|
||||
FileStream* = ref FileStreamObj
|
||||
## 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`.
|
||||
type
|
||||
FileStream* = ref FileStreamObj
|
||||
## A stream that encapsulates a `File`.
|
||||
##
|
||||
## **Note:** Not available for JS backend.
|
||||
FileStreamObj* = object of Stream
|
||||
## A file stream object.
|
||||
##
|
||||
## 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:
|
||||
## **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.
|
||||
##
|
||||
## 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):
|
||||
## 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()
|
||||
var strm = openFileStream("somefile.txt")
|
||||
echo strm.readLine()
|
||||
## Output:
|
||||
## The first line
|
||||
strm.close()
|
||||
except:
|
||||
stderr.write getCurrentExceptionMsg()
|
||||
|
||||
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):
|
||||
## 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)
|
||||
var f: File
|
||||
if open(f, filename, mode, bufSize):
|
||||
return newFileStream(f)
|
||||
else:
|
||||
raise newEIO("cannot open file stream: " & filename)
|
||||
|
||||
when false:
|
||||
type
|
||||
|
||||
@@ -52,7 +52,7 @@ runnableExamples:
|
||||
import
|
||||
hashes, strutils
|
||||
|
||||
when defined(js):
|
||||
when defined(js) or defined(nimscript):
|
||||
{.pragma: rtlFunc.}
|
||||
else:
|
||||
{.pragma: rtlFunc, rtl.}
|
||||
@@ -298,7 +298,7 @@ proc raiseFormatException(s: string) =
|
||||
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
||||
if hasKey(t, key): return t.getOrDefault(key)
|
||||
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
||||
when defined(js):
|
||||
when defined(js) or defined(nimscript):
|
||||
result = ""
|
||||
else:
|
||||
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, "] ",
|
||||
testResult.testName)
|
||||
when not defined(ECMAScript):
|
||||
if formatter.colorOutput and not defined(ECMAScript):
|
||||
if formatter.colorOutput:
|
||||
var color = case testResult.status
|
||||
of TestStatus.OK: fgGreen
|
||||
of TestStatus.FAILED: fgRed
|
||||
|
||||
@@ -13,18 +13,24 @@
|
||||
template volatileLoad*[T](src: ptr T): T =
|
||||
## Generates a volatile load of the value stored in the container `src`.
|
||||
## Note that this only effects code generation on `C` like backends
|
||||
when defined(js):
|
||||
when nimvm:
|
||||
src[]
|
||||
else:
|
||||
var res: T
|
||||
{.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].}
|
||||
res
|
||||
when defined(js):
|
||||
src[]
|
||||
else:
|
||||
var res: T
|
||||
{.emit: [res, " = (*(", type(src[]), " volatile*)", src, ");"].}
|
||||
res
|
||||
|
||||
template volatileStore*[T](dest: ptr T, val: T) =
|
||||
## Generates a volatile store into the container `dest` of the value
|
||||
## `val`. Note that this only effects code generation on `C` like
|
||||
## backends
|
||||
when defined(js):
|
||||
when nimvm:
|
||||
dest[] = val
|
||||
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.
|
||||
#
|
||||
|
||||
import system/indexerrors
|
||||
include system/indexerrors
|
||||
|
||||
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 """
|
||||
targets: "c js"
|
||||
output: '''
|
||||
@[]
|
||||
true
|
||||
https://example.com/test?format=jpg&name=orig##
|
||||
https://example.com/test?format=jpg&name=orig##text
|
||||
@@ -40,7 +40,7 @@ block t2813:
|
||||
"""
|
||||
var errors: seq[string] = @[]
|
||||
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 rows: seq[XmlNode] = @[]
|
||||
|
||||
@@ -1,29 +1,5 @@
|
||||
discard """
|
||||
output: '''
|
||||
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
|
||||
'''
|
||||
targets: "c js"
|
||||
"""
|
||||
import parsecfg, streams
|
||||
|
||||
@@ -46,24 +22,35 @@ var pname = dict2.getSectionValue("Package","name")
|
||||
var name = dict2.getSectionValue("Author","name")
|
||||
var qq = dict2.getSectionValue("Author","qq")
|
||||
var email = dict2.getSectionValue("Author","email")
|
||||
echo charset
|
||||
echo threads
|
||||
echo pname
|
||||
echo name
|
||||
echo qq
|
||||
echo email
|
||||
|
||||
echo "==="
|
||||
doAssert charset == "utf-8"
|
||||
doAssert threads == "on"
|
||||
doAssert pname == "hello"
|
||||
doAssert name == "lihf8515"
|
||||
doAssert qq == "10214028"
|
||||
doAssert email == "lihaifeng@wxm.com"
|
||||
|
||||
## Modifying a configuration file.
|
||||
var dict3 = loadConfig(newStringStream(ss.data))
|
||||
dict3.setSectionKey("Author","name","lhf")
|
||||
write(stdout, $dict3)
|
||||
|
||||
echo "==="
|
||||
doAssert $dict3 == """charset=utf-8
|
||||
[Package]
|
||||
name=hello
|
||||
--threads:on
|
||||
[Author]
|
||||
name=lhf
|
||||
qq=10214028
|
||||
email="lihaifeng@wxm.com"
|
||||
"""
|
||||
|
||||
## Deleting a section key in a configuration file.
|
||||
var dict4 = loadConfig(newStringStream(ss.data))
|
||||
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
|
||||
|
||||
doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discard """
|
||||
targets: "c js"
|
||||
output: '''
|
||||
PEG AST traversal output
|
||||
------------------------
|
||||
|
||||
@@ -38,8 +38,8 @@ true
|
||||
"""
|
||||
|
||||
import
|
||||
critbits, sets, strutils, tables, random, algorithm, re, ropes, segfaults,
|
||||
lists, parsesql, streams, os, htmlgen, xmltree, strtabs
|
||||
critbits, cstrutils, sets, strutils, tables, random, algorithm, re, ropes,
|
||||
segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs
|
||||
|
||||
|
||||
block tcritbits:
|
||||
@@ -245,3 +245,24 @@ block txmltree:
|
||||
])
|
||||
])
|
||||
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
|
||||
# http://nim-lang.org/docs/nims.html
|
||||
|
||||
import algorithm
|
||||
import base64
|
||||
import colors
|
||||
import hashes
|
||||
import lists
|
||||
import math
|
||||
# import marshal
|
||||
import options
|
||||
import os
|
||||
# import parsecfg
|
||||
# import parseopt
|
||||
import parseutils
|
||||
# import pegs
|
||||
import deques
|
||||
import sequtils
|
||||
import strutils
|
||||
import tables
|
||||
import unicode
|
||||
import uri
|
||||
import macros
|
||||
{.warning[UnusedImport]: off.}
|
||||
|
||||
import std/[
|
||||
# Core:
|
||||
bitops, typetraits, lenientops, macros, volatile,
|
||||
# fails: typeinfo, endians
|
||||
# works but shouldn't: cpuinfo, rlocks, locks
|
||||
|
||||
# Algorithms:
|
||||
algorithm, sequtils,
|
||||
|
||||
# Collections:
|
||||
critbits, deques, heapqueue, intsets, lists, options, sets,
|
||||
sharedlist, tables,
|
||||
# fails: sharedtables
|
||||
|
||||
# Strings:
|
||||
editdistance, wordwrap, parseutils, ropes,
|
||||
pegs, punycode, strformat, strmisc, strscans, strtabs,
|
||||
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:
|
||||
doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath
|
||||
|
||||
Reference in New Issue
Block a user