Merge branch 'araq-strings-v1' into devel

This commit is contained in:
Araq
2018-04-30 19:25:04 +02:00
30 changed files with 156 additions and 1928 deletions

View File

@@ -83,6 +83,9 @@
- ``nil`` for strings/seqs is finally gone. Instead the default value for
these is ``"" / @[]``.
- Accessing the binary zero terminator in Nim's native strings
is now invalid. Internally a Nim string still has the trailing zero for
zero-copy interoperability with ``cstring``.
### Tool changes

View File

@@ -1471,7 +1471,7 @@ mysterious crashes.
**Note**: The example only works because the memory is initialized to zero
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
``nil`` which the string assignment can handle. One needs to know low level
binary zero which the string assignment can handle. One needs to know low level
details like this when mixing garbage collected data with unmanaged memory.
.. XXX finalizers for traced objects
@@ -2512,8 +2512,8 @@ char '\\0'
bool false
ref or pointer type nil
procedural type nil
sequence nil (*not* ``@[]``)
string nil (*not* "")
sequence ``@[]``
string ``""``
tuple[x: A, y: B, ...] (default(A), default(B), ...)
(analogous for objects)
array[0..., T] [default(T), ...]
@@ -4270,7 +4270,7 @@ therefore very useful for type specialization within generic code:
Table[Key, Value] = object
keys: seq[Key]
values: seq[Value]
when not (Key is string): # nil value for strings used for optimization
when not (Key is string): # empty value for strings used for optimization
deletedKeys: seq[bool]
@@ -7434,8 +7434,8 @@ code generation directly, but their presence can be detected by macros.
Custom pragmas are defined using templates annotated with pragma ``pragma``:
.. code-block:: nim
template dbTable(name: string, table_space: string = nil) {.pragma.}
template dbKey(name: string = nil, primary_key: bool = false) {.pragma.}
template dbTable(name: string, table_space: string = "") {.pragma.}
template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
template dbForeignKey(t: typedesc) {.pragma.}
template dbIgnore {.pragma.}

View File

@@ -960,11 +960,7 @@ enforced. For example, when reading strings from binary files, they are merely
a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of
``s``, not the i-th *unichar*.
String variables are initialized with a special value, called ``nil``. However,
most string operations cannot deal with ``nil`` (leading to an exception being
raised) for performance reasons. It is best to use empty strings ``""``
rather than ``nil`` as the *empty* value. But ``""`` often creates a string
object on the heap, so there is a trade-off to be made here.
String variables are initialized with the empty strings ``""``.
Integers
@@ -1309,11 +1305,7 @@ Example:
x: seq[int] # a reference to a sequence of integers
x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap
Sequence variables are initialized with ``nil``. However, most sequence
operations cannot deal with ``nil`` (leading to an exception being
raised) for performance reasons. Thus one should use empty sequences ``@[]``
rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence
object on the heap, so there is a trade-off to be made here.
Sequence variables are initialized with ``@[]``.
The ``for`` statement can be used with one or two variables when used with a
sequence. When you use the one variable form, the variable will hold the value
@@ -1355,11 +1347,9 @@ type does not matter.
.. code-block:: nim
:test: "nim c $1"
var
fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil'
fruits: seq[string] # reference to a sequence of strings that is initialized with '@[]'
capitals: array[3, string] # array of strings with a fixed size
fruits = @[] # creates an empty sequence on the heap that will be referenced by 'fruits'
capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements
fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime
fruits.add("Mango")
@@ -1691,7 +1681,7 @@ rules apply:
write(stdout, x(3)) # no error: A.x is called
write(stdout, x("")) # no error: B.x is called
proc x*(a: int): string = nil
proc x*(a: int): string = discard
write(stdout, x(3)) # ambiguous: which `x` is to call?

View File

@@ -107,7 +107,7 @@ proc executeCgi(server: var TServer, client: Socket, path, query: string,
dataAvail = recvLine(client, buf)
if buf.len == 0:
break
var L = toLower(buf)
var L = toLowerAscii(buf)
if L.startsWith("content-length:"):
var i = len("content-length:")
while L[i] in Whitespace: inc(i)
@@ -205,7 +205,7 @@ proc acceptRequest(server: var TServer, client: Socket) =
client.close()
else:
when defined(Windows):
var ext = splitFile(path).ext.toLower
var ext = splitFile(path).ext.toLowerAscii
if ext == ".exe" or ext == ".cgi":
# XXX: extract interpreter information here?
cgi = true

View File

@@ -10,7 +10,7 @@
from pcre import nil
import nre.private.util
import tables
from strutils import toLower, `%`
from strutils import `%`
from math import ceil
import options
from unicode import runeLenAt
@@ -326,15 +326,15 @@ proc `$`*(pattern: RegexMatch): string =
proc `==`*(a, b: Regex): bool =
if not a.isNil and not b.isNil:
return a.pattern == b.pattern and
a.pcreObj == b.pcreObj and
return a.pattern == b.pattern and
a.pcreObj == b.pcreObj and
a.pcreExtra == b.pcreExtra
else:
return system.`==`(a, b)
proc `==`*(a, b: RegexMatch): bool =
return a.pattern == b.pattern and
a.str == b.str
a.str == b.str
# }}}
# Creation & Destruction {{{

View File

@@ -201,7 +201,7 @@ when defineSsl:
flags: set[SocketFlag]) {.async.} =
let len = bioCtrlPending(socket.bioOut)
if len > 0:
var data = newStringOfCap(len)
var data = newString(len)
let read = bioRead(socket.bioOut, addr data[0], len)
assert read != 0
if read < 0:

View File

@@ -52,7 +52,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
if numLines > 0: inc(total, (numLines - 1) * newLine.len)
result = newString(total)
var
var
i = 0
r = 0
currLine = 0
@@ -76,7 +76,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
currLine = 0
if i < s.len-1:
let
let
a = ord(s[i])
b = ord(s[i+1])
result[r] = cb64[a shr 2]
@@ -130,11 +130,11 @@ proc decode*(s: string): string =
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var
var
i = 0
r = 0
while true:
while s[i] in Whitespace: inc(i)
while i < s.len and s[i] in Whitespace: inc(i)
if i < s.len-3:
let
a = s[i].decodeByte

View File

@@ -74,18 +74,19 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
var newByte = 0
block blockX:
while newbyte < key.len:
if it.key[newbyte] != key[newbyte]:
newotherbits = it.key[newbyte].ord xor key[newbyte].ord
let ch = if newbyte < it.key.len: it.key[newbyte] else: '\0'
if ch != key[newbyte]:
newotherbits = ch.ord xor key[newbyte].ord
break blockX
inc newbyte
if it.key[newbyte] != '\0':
if newbyte < it.key.len:
newotherbits = it.key[newbyte].ord
else:
return it
while (newOtherBits and (newOtherBits-1)) != 0:
newOtherBits = newOtherBits and (newOtherBits-1)
newOtherBits = newOtherBits xor 255
let ch = it.key[newByte]
let ch = if newByte < it.key.len: it.key[newByte] else: '\0'
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
var inner: Node[T]

View File

@@ -25,16 +25,16 @@ proc parseCookies*(s: string): StringTableRef =
result = newStringTable(modeCaseInsensitive)
var i = 0
while true:
while s[i] == ' ' or s[i] == '\t': inc(i)
while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i)
var keystart = i
while s[i] != '=' and s[i] != '\0': inc(i)
while i < s.len and s[i] != '=': inc(i)
var keyend = i-1
if s[i] == '\0': break
if i >= s.len: break
inc(i) # skip '='
var valstart = i
while s[i] != ';' and s[i] != '\0': inc(i)
while i < s.len and s[i] != ';': inc(i)
result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
if s[i] == '\0': break
if i >= s.len: break
inc(i) # skip ';'
proc setCookie*(key, value: string, domain = "", path = "",

View File

@@ -36,7 +36,7 @@ when defined(windows):
while i < a.len and j < b.len:
if a[i] in {'-', '_'}: inc i
if b[j] in {'-', '_'}: inc j
if a[i].toLower != b[j].toLower: return false
if i < a.len and j < b.len and a[i].toLowerAscii != b[j].toLowerAscii: return false
inc i
inc j
result = i == a.len and j == b.len

View File

@@ -74,7 +74,7 @@
##
## .. code-block:: Nim
## import asyncdispatch, httpclient
##
##
## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
## echo("Downloaded ", progress, " of ", total)
## echo("Current rate: ", speed div 1000, "kb/s")
@@ -247,7 +247,7 @@ proc parseChunks(s: Socket, timeout: int): string =
var i = 0
if chunkSizeStr == "":
httpError("Server terminated connection prematurely")
while true:
while i < chunkSizeStr.len:
case chunkSizeStr[i]
of '0'..'9':
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
@@ -255,8 +255,6 @@ proc parseChunks(s: Socket, timeout: int): string =
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
of 'A'..'F':
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
of '\0':
break
of ';':
# http://tools.ietf.org/html/rfc2616#section-3.6.1
# We don't care about chunk-extensions.
@@ -938,7 +936,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
var i = 0
if chunkSizeStr == "":
httpError("Server terminated connection prematurely")
while true:
while i < chunkSizeStr.len:
case chunkSizeStr[i]
of '0'..'9':
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
@@ -946,8 +944,6 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
of 'A'..'F':
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
of '\0':
break
of ';':
# http://tools.ietf.org/html/rfc2616#section-3.6.1
# We don't care about chunk-extensions.

View File

@@ -190,11 +190,11 @@ proc len*(headers: HttpHeaders): int = return headers.table.len
proc parseList(line: string, list: var seq[string], start: int): int =
var i = 0
var current = ""
while line[start + i] notin {'\c', '\l', '\0'}:
while start+i < line.len and line[start + i] notin {'\c', '\l'}:
i += line.skipWhitespace(start + i)
i += line.parseUntil(current, {'\c', '\l', ','}, start + i)
list.add(current)
if line[start + i] == ',':
if start+i < line.len and line[start + i] == ',':
i.inc # Skip ,
current.setLen(0)

View File

@@ -126,7 +126,7 @@ when false:
var dataAvail = false
while dataAvail:
dataAvail = recvLine(client, buf) # TODO: This is incorrect.
var L = toLower(buf.string)
var L = toLowerAscii(buf.string)
if L.startsWith("content-length:"):
var i = len("content-length:")
while L[i] in Whitespace: inc(i)
@@ -199,7 +199,7 @@ when false:
notFound(client)
else:
when defined(Windows):
var ext = splitFile(path).ext.toLower
var ext = splitFile(path).ext.toLowerAscii
if ext == ".exe" or ext == ".cgi":
# XXX: extract interpreter information here?
cgi = true
@@ -303,7 +303,7 @@ proc next*(s: var Server) =
if s.reqMethod == "POST":
# Check for Expect header
if s.headers.hasKey("Expect"):
if s.headers["Expect"].toLower == "100-continue":
if s.headers["Expect"].toLowerAscii == "100-continue":
s.client.sendStatus("100 Continue")
else:
s.client.sendStatus("417 Expectation Failed")
@@ -427,7 +427,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
if s.reqMethod == "POST":
# Check for Expect header
if s.headers.hasKey("Expect"):
if s.headers["Expect"].toLower == "100-continue":
if s.headers["Expect"].toLowerAscii == "100-continue":
s.client.sendStatus("100 Continue")
else:
s.client.sendStatus("417 Expectation Failed")

View File

@@ -126,7 +126,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
var v = ""
let app = when defined(js): "" else: getAppFilename()
while frmt[i] in IdentChars:
v.add(toLower(frmt[i]))
v.add(toLowerAscii(frmt[i]))
inc(i)
case v
of "date": result.add(getDateStr())

View File

@@ -29,21 +29,21 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
chars = Letters + Digits + {'!','#','$','%','&',
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
var i = 0
if s[i] notin chars or s[i] == '.': return false
while s[i] in chars:
if s[i] == '.' and s[i+1] == '.': return false
if i >= s.len or s[i] notin chars or s[i] == '.': return false
while i < s.len and s[i] in chars:
if i+1 < s.len and s[i] == '.' and s[i+1] == '.': return false
inc(i)
if s[i] != '@': return false
if i >= s.len or s[i] != '@': return false
var j = len(s)-1
if s[j] notin Letters: return false
if j >= 0 and s[j] notin Letters: return false
while j >= i and s[j] in Letters: dec(j)
inc(i) # skip '@'
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
if s[i] != '\0': return false
while i < s.len and s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
if i != s.len: return false
var x = substr(s, j+1)
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
case toLower(x)
case toLowerAscii(x)
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
"aero", "jobs", "museum": return true
else: return false

View File

@@ -1060,18 +1060,17 @@ proc parseCmdLine*(c: string): seq[string] {.
while true:
setLen(a, 0)
# eat all delimiting whitespace
while c[i] == ' ' or c[i] == '\t' or c[i] == '\l' or c[i] == '\r' : inc(i)
while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i)
if i >= c.len: break
when defined(windows):
# parse a single argument according to the above rules:
if c[i] == '\0': break
var inQuote = false
while true:
while i < c.len:
case c[i]
of '\0': break
of '\\':
var j = i
while c[j] == '\\': inc(j)
if c[j] == '"':
while j < c.len and c[j] == '\\': inc(j)
if j < c.len and c[j] == '"':
for k in 1..(j-i) div 2: a.add('\\')
if (j-i) mod 2 == 0:
i = j
@@ -1084,7 +1083,7 @@ proc parseCmdLine*(c: string): seq[string] {.
of '"':
inc(i)
if not inQuote: inQuote = true
elif c[i] == '"':
elif i < c.len and c[i] == '"':
a.add(c[i])
inc(i)
else:
@@ -1102,13 +1101,12 @@ proc parseCmdLine*(c: string): seq[string] {.
of '\'', '\"':
var delim = c[i]
inc(i) # skip ' or "
while c[i] != '\0' and c[i] != delim:
while i < c.len and c[i] != delim:
add a, c[i]
inc(i)
if c[i] != '\0': inc(i)
of '\0': break
if i < c.len: inc(i)
else:
while c[i] > ' ':
while i < c.len and c[i] > ' ':
add(a, c[i])
inc(i)
add(result, a)

View File

@@ -196,7 +196,7 @@ proc joinPath*(head, tail: string): string {.
else:
result = head & tail
else:
if tail[0] in {DirSep, AltSep}:
if tail.len > 0 and tail[0] in {DirSep, AltSep}:
result = head & tail
else:
result = head & DirSep & tail
@@ -477,7 +477,7 @@ proc unixToNativePath*(path: string, drive=""): string {.
var i = start
while i < len(path): # ../../../ --> ::::
if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
# parent directory
when defined(macos):
if result[high(result)] == ':':

View File

@@ -534,15 +534,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
case p.kind
of pkEmpty: result = 0 # match of length 0
of pkAny:
if s[start] != '\0': result = 1
if start < s.len: result = 1
else: result = -1
of pkAnyRune:
if s[start] != '\0':
if start < s.len:
result = runeLenAt(s, start)
else:
result = -1
of pkLetter:
if s[start] != '\0':
if start < s.len:
var a: Rune
result = start
fastRuneAt(s, result, a)
@@ -551,7 +551,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
else:
result = -1
of pkLower:
if s[start] != '\0':
if start < s.len:
var a: Rune
result = start
fastRuneAt(s, result, a)
@@ -560,7 +560,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
else:
result = -1
of pkUpper:
if s[start] != '\0':
if start < s.len:
var a: Rune
result = start
fastRuneAt(s, result, a)
@@ -569,7 +569,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
else:
result = -1
of pkTitle:
if s[start] != '\0':
if start < s.len:
var a: Rune
result = start
fastRuneAt(s, result, a)
@@ -578,7 +578,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
else:
result = -1
of pkWhitespace:
if s[start] != '\0':
if start < s.len:
var a: Rune
result = start
fastRuneAt(s, result, a)
@@ -589,15 +589,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
of pkGreedyAny:
result = len(s) - start
of pkNewLine:
if s[start] == '\L': result = 1
elif s[start] == '\C':
if s[start+1] == '\L': result = 2
if start < s.len and s[start] == '\L': result = 1
elif start < s.len and s[start] == '\C':
if start+1 < s.len and s[start+1] == '\L': result = 2
else: result = 1
else: result = -1
of pkTerminal:
result = len(p.term)
for i in 0..result-1:
if p.term[i] != s[start+i]:
if start+i >= s.len or p.term[i] != s[start+i]:
result = -1
break
of pkTerminalIgnoreCase:
@@ -606,6 +606,9 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
a, b: Rune
result = start
while i < len(p.term):
if result >= s.len:
result = -1
break
fastRuneAt(p.term, i, a)
fastRuneAt(s, result, b)
if toLower(a) != toLower(b):
@@ -621,18 +624,23 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
while true:
fastRuneAt(p.term, i, a)
if a != Rune('_'): break
while true:
while result < s.len:
fastRuneAt(s, result, b)
if b != Rune('_'): break
if toLower(a) != toLower(b):
if result >= s.len:
if i >= p.term.len: break
else:
result = -1
break
elif toLower(a) != toLower(b):
result = -1
break
dec(result, start)
of pkChar:
if p.ch == s[start]: result = 1
if start < s.len and p.ch == s[start]: result = 1
else: result = -1
of pkCharChoice:
if contains(p.charChoice[], s[start]): result = 1
if start < s.len and contains(p.charChoice[], s[start]): result = 1
else: result = -1
of pkNonTerminal:
var oldMl = c.ml
@@ -695,10 +703,10 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
of pkGreedyRepChar:
result = 0
var ch = p.ch
while ch == s[start+result]: inc(result)
while start+result < s.len and ch == s[start+result]: inc(result)
of pkGreedyRepSet:
result = 0
while contains(p.charChoice[], s[start+result]): inc(result)
while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result)
of pkOption:
result = max(0, rawMatch(s, p.sons[0], start, c))
of pkAndPredicate:

View File

@@ -1126,7 +1126,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
var indentCount = 0
for j in 0..<count.int:
indentCount.inc
if line[j .. j + padding.len-1] != padding:
if j + padding.len-1 >= line.len or line[j .. j + padding.len-1] != padding:
indentCount = j
break
result.add(line[indentCount*padding.len .. ^1])

View File

@@ -1318,24 +1318,23 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
result = ""
var i = 0
var currentF = ""
while true:
while i < f.len:
case f[i]
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
formatToken(dt, currentF, result)
currentF = ""
if f[i] == '\0': break
if f[i] == '\'':
inc(i) # Skip '
while f[i] != '\'' and f.len-1 > i:
while i < f.len-1 and f[i] != '\'':
result.add(f[i])
inc(i)
else: result.add(f[i])
else:
# Check if the letter being added matches previous accumulated buffer.
if currentF.len < 1 or currentF[high(currentF)] == f[i]:
if currentF.len == 0 or currentF[high(currentF)] == f[i]:
currentF.add(f[i])
else:
formatToken(dt, currentF, result)
@@ -1343,6 +1342,7 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
currentF = ""
inc(i)
formatToken(dt, currentF, result)
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
## Converts a `DateTime` object to a string representation.
@@ -1439,58 +1439,58 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
dt.month = month.Month
of "MMM":
case value[j..j+2].toLowerAscii():
of "jan": dt.month = mJan
of "feb": dt.month = mFeb
of "mar": dt.month = mMar
of "apr": dt.month = mApr
of "may": dt.month = mMay
of "jun": dt.month = mJun
of "jul": dt.month = mJul
of "aug": dt.month = mAug
of "sep": dt.month = mSep
of "oct": dt.month = mOct
of "nov": dt.month = mNov
of "dec": dt.month = mDec
of "jan": dt.month = mJan
of "feb": dt.month = mFeb
of "mar": dt.month = mMar
of "apr": dt.month = mApr
of "may": dt.month = mMay
of "jun": dt.month = mJun
of "jul": dt.month = mJul
of "aug": dt.month = mAug
of "sep": dt.month = mSep
of "oct": dt.month = mOct
of "nov": dt.month = mNov
of "dec": dt.month = mDec
else:
raise newException(ValueError,
"Couldn't parse month (MMM), got: " & value)
j += 3
of "MMMM":
if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
dt.month = mJan
dt.month = mJan
j += 7
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
dt.month = mFeb
dt.month = mFeb
j += 8
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
dt.month = mMar
dt.month = mMar
j += 5
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
dt.month = mApr
dt.month = mApr
j += 5
elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
dt.month = mMay
dt.month = mMay
j += 3
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
dt.month = mJun
dt.month = mJun
j += 4
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
dt.month = mJul
dt.month = mJul
j += 4
elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
dt.month = mAug
dt.month = mAug
j += 6
elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
dt.month = mSep
dt.month = mSep
j += 9
elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
dt.month = mOct
dt.month = mOct
j += 7
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
dt.month = mNov
dt.month = mNov
j += 8
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
dt.month = mDec
dt.month = mDec
j += 8
else:
raise newException(ValueError,
@@ -1521,44 +1521,47 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
j += 4
of "z":
dt.isDst = false
if value[j] == '+':
let ch = if j < value.len: value[j] else: '\0'
if ch == '+':
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
elif value[j] == '-':
elif ch == '-':
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
elif value[j] == 'Z':
elif ch == 'Z':
dt.utcOffset = 0
j += 1
return
else:
raise newException(ValueError,
"Couldn't parse timezone offset (z), got: " & value[j])
"Couldn't parse timezone offset (z), got: " & ch)
j += 2
of "zz":
dt.isDst = false
if value[j] == '+':
let ch = if j < value.len: value[j] else: '\0'
if ch == '+':
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
elif value[j] == '-':
elif ch == '-':
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
elif value[j] == 'Z':
elif ch == 'Z':
dt.utcOffset = 0
j += 1
return
else:
raise newException(ValueError,
"Couldn't parse timezone offset (zz), got: " & value[j])
"Couldn't parse timezone offset (zz), got: " & ch)
j += 3
of "zzz":
dt.isDst = false
var factor = 0
if value[j] == '+': factor = -1
elif value[j] == '-': factor = 1
elif value[j] == 'Z':
let ch = if j < value.len: value[j] else: '\0'
if ch == '+': factor = -1
elif ch == '-': factor = 1
elif ch == 'Z':
dt.utcOffset = 0
j += 1
return
else:
raise newException(ValueError,
"Couldn't parse timezone offset (zzz), got: " & value[j])
"Couldn't parse timezone offset (zzz), got: " & ch)
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
j += 4
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
@@ -1620,20 +1623,18 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
dt.nanosecond = 0
dt.isDst = true # using this is flag for checking whether a timezone has \
# been read (because DST is always false when a tz is parsed)
while true:
while i < layout.len:
case layout[i]
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
if token.len > 0:
parseToken(dt, token, value, j)
# Reset token
token = ""
# Break if at end of line
if layout[i] == '\0': break
# Skip separator and everything between single quotes
# These are literals in both the layout and the value string
if layout[i] == '\'':
inc(i)
while layout[i] != '\'' and layout.len-1 > i:
while i < layout.len-1 and layout[i] != '\'':
inc(i)
inc(j)
inc(i)
@@ -1642,13 +1643,15 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
inc(j)
else:
# Check if the letter being added matches previous accumulated buffer.
if token.len < 1 or token[high(token)] == layout[i]:
if token.len == 0 or token[high(token)] == layout[i]:
token.add(layout[i])
inc(i)
else:
parseToken(dt, token, value, j)
token = ""
if i >= layout.len and token.len > 0:
parseToken(dt, token, value, j)
if dt.isDst:
# No timezone parsed - assume timezone is `zone`
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)

View File

@@ -232,10 +232,10 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
raise newException(EInvalidCharacterErr, "Invalid character")
# Exceptions
if qualifiedName.contains(':'):
let qfnamespaces = qualifiedName.toLower().split(':')
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
if isNil(namespaceURI):
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
elif qfnamespaces[0] == "xml" and
elif qfnamespaces[0] == "xml" and
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
qfnamespaces[1] notin stdattrnames:
raise newException(ENamespaceErr,
@@ -311,10 +311,10 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
## Creates an element of the given qualified name and namespace URI.
if qualifiedName.contains(':'):
let qfnamespaces = qualifiedName.toLower().split(':')
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
if isNil(namespaceURI):
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
elif qfnamespaces[0] == "xml" and
elif qfnamespaces[0] == "xml" and
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
qfnamespaces[1] notin stdattrnames:
raise newException(ENamespaceErr,
@@ -533,13 +533,13 @@ proc `prefix=`*(n: PNode, value: string) =
if isNil(n.fNamespaceURI):
raise newException(ENamespaceErr, "namespaceURI cannot be nil")
elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
raise newException(ENamespaceErr,
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
elif value.toLowerAscii() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
raise newException(ENamespaceErr,
"When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode:
elif value.toLowerAscii() == "xmlns" and n.fNodeType == AttributeNode:
raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"")
n.fNodeName = value & ":" & n.fLocalName

View File

@@ -1,7 +1,7 @@
# bug 2007
import asyncdispatch, asyncnet, logging, json, uri, strutils, future
import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar
type
Builder = ref object
@@ -27,7 +27,7 @@ proc newBuild*(onProgress: ProgressCB): Build =
result.onProgress = onProgress
proc start(build: Build, repo, hash: string) {.async.} =
let path = repo.parseUri().path.toLower()
let path = repo.parseUri().path.toLowerAscii()
proc onProgress(builder: Builder, message: string) {.async.} =
debug($message)

View File

@@ -31,7 +31,7 @@ type
s.pop() is T
type ValueType = T
const ValueTypeName = T.name.toUpper
const ValueTypeName = T.name.toUpperAscii
proc genericAlgorithm[T](s: var Stack[T], y: T) =
static:

View File

@@ -7,7 +7,7 @@ task "install", "compile and install nake binary":
for index, dir in pairs(path):
echo " ", index, ". ", dir
echo "Where to install nake binary? (quit with ^C or quit or exit)"
let ans = stdin.readLine().toLower
let ans = stdin.readLine().toLowerAscii
var index = 0
case ans
of "q", "quit", "x", "exit":

View File

@@ -562,7 +562,7 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
result.useSound = importSound(data[2], errors, "useSound")
case data[1].str.toLower
case data[1].str.toLowerAscii
of "projectile":
result.kind = Projectile
if data[2]["bullet"].kind == JString:

View File

@@ -88,7 +88,7 @@ task "download", "download game assets":
if existsFile(path):
echo "The file already exists\n",
"[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets
case stdin.readLine.toLower
case stdin.readLine.toLowerAscii
of "r":
removeFile path
of "m":
@@ -120,7 +120,7 @@ task "download", "download game assets":
echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
"[Y]es [N]o Source: ", BinLibs
case stdin.readline.toLower
case stdin.readline.toLowerAscii
of "y", "yes":
discard ## o_O
else:

View File

@@ -6,7 +6,7 @@ discard """
import strutils
var x = "hello world!".toLower.toUpper
var x = "hello world!".toLowerAscii.toUpperAscii
x.echo()
#OUT HELLO WORLD!

View File

@@ -8,7 +8,7 @@ import strutils
proc foo(s: static[string]): string =
static: echo s
const R = s.toUpper
const R = s.toUpperAscii
return R
echo foo("test 1")

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,6 @@ else:
result = newString(size)
let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
cstring(result), size, cstring(nil), LPBOOL(nil))
result[size] = chr(0)
doAssert size == res
proc testCP(wc: WideCString, lo, hi: int) =