diff options
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/asyncdispatch.nim | 10 | ||||
-rw-r--r-- | lib/pure/collections/sets.nim | 4 | ||||
-rw-r--r-- | lib/pure/collections/tableimpl.nim | 8 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 13 | ||||
-rw-r--r-- | lib/pure/punycode.nim | 166 | ||||
-rw-r--r-- | lib/pure/strmisc.nim | 43 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 40 |
7 files changed, 224 insertions, 60 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 8ba4b5cca..455bebc7f 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1542,13 +1542,11 @@ proc processBody(node, retFutureSym: NimNode, case node[1].kind of nnkIdent, nnkInfix: # await x - result = newNimNode(nnkStmtList, node) - var futureValue: NimNode - result.useVar(node[1], futureValue, futureValue, node) - # -> yield x - # -> x.read() + # await x or y + result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x of nnkCall, nnkCommand: # await foo(p, x) + # await foo p, x var futureValue: NimNode result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue, futureValue, node) @@ -1754,7 +1752,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = result[6] = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "g": + #if prc[0].getName == "testInfix": # echo(toStrLit(result)) macro async*(prc: stmt): stmt {.immediate.} = diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 20f73ded3..e2081e5bf 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -261,6 +261,8 @@ template doWhile(a: expr, b: stmt): stmt = b if not a: break +proc default[T](t: typedesc[T]): T {.inline.} = discard + proc excl*[A](s: var HashSet[A], key: A) = ## Excludes `key` from the set `s`. ## @@ -277,11 +279,13 @@ proc excl*[A](s: var HashSet[A], key: A) = var msk = high(s.data) if i >= 0: s.data[i].hcode = 0 + s.data[i].key = default(type(s.data[i].key)) dec(s.counter) while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 var j = i # The correctness of this depends on (h+1) in nextTry, var r = j # though may be adaptable to other simple sequences. s.data[i].hcode = 0 # mark current EMPTY + s.data[i].key = default(type(s.data[i].key)) doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): i = (i + 1) and msk # increment mod table size if isEmpty(s.data[i].hcode): # end of collision cluster; So all done diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index cc32fbedc..1bbf19ee9 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -110,18 +110,24 @@ template hasKeyOrPutImpl(enlarge) {.dirty, immediate.} = maybeRehashPutImpl(enlarge) else: result = true +proc default[T](t: typedesc[T]): T {.inline.} = discard + template delImpl() {.dirty, immediate.} = var hc: Hash var i = rawGet(t, key, hc) let msk = maxHash(t) if i >= 0: t.data[i].hcode = 0 + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) dec(t.counter) block outer: while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 var j = i # The correctness of this depends on (h+1) in nextTry, var r = j # though may be adaptable to other simple sequences. t.data[i].hcode = 0 # mark current EMPTY + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) while true: i = (i + 1) and msk # increment mod table size if isEmpty(t.data[i].hcode): # end of collision cluster; So all done @@ -137,4 +143,6 @@ template delImpl() {.dirty, immediate.} = template clearImpl() {.dirty, immediate.} = for i in 0 .. <t.data.len: t.data[i].hcode = 0 + t.data[i].key = default(type(t.data[i].key)) + t.data[i].val = default(type(t.data[i].val)) t.counter = 0 diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index b3a59551d..bc964861d 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -167,7 +167,7 @@ proc parseChunks(s: Socket, timeout: int): string = # Trailer headers will only be sent if the request specifies that we want # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 -proc parseBody(s: Socket, headers: HttpHeaders, timeout: int): string = +proc parseBody(s: Socket, headers: HttpHeaders, httpVersion: string, timeout: int): string = result = "" if headers.getOrDefault"Transfer-Encoding" == "chunked": result = parseChunks(s, timeout) @@ -193,7 +193,7 @@ proc parseBody(s: Socket, headers: HttpHeaders, timeout: int): string = # -REGION- Connection: Close # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5 - if headers.getOrDefault"Connection" == "close": + if headers.getOrDefault"Connection" == "close" or httpVersion == "1.0": var buf = "" while true: buf = newString(4000) @@ -249,7 +249,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response = if not fullyRead: httpError("Connection was closed before full request has been made") if getBody: - result.body = parseBody(s, result.headers, timeout) + result.body = parseBody(s, result.headers, result.version, timeout) else: result.body = "" @@ -685,7 +685,8 @@ proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} = # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 proc parseBody(client: AsyncHttpClient, - headers: HttpHeaders): Future[string] {.async.} = + headers: HttpHeaders, + httpVersion: string): Future[string] {.async.} = result = "" if headers.getOrDefault"Transfer-Encoding" == "chunked": result = await parseChunks(client) @@ -707,7 +708,7 @@ proc parseBody(client: AsyncHttpClient, # -REGION- Connection: Close # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5 - if headers.getOrDefault"Connection" == "close": + if headers.getOrDefault"Connection" == "close" or httpVersion == "1.0": var buf = "" while true: buf = await client.socket.recvFull(4000) @@ -761,7 +762,7 @@ proc parseResponse(client: AsyncHttpClient, if not fullyRead: httpError("Connection was closed before full request has been made") if getBody: - result.body = await parseBody(client, result.headers) + result.body = await parseBody(client, result.headers, result.version) else: result.body = "" diff --git a/lib/pure/punycode.nim b/lib/pure/punycode.nim new file mode 100644 index 000000000..4f35de487 --- /dev/null +++ b/lib/pure/punycode.nim @@ -0,0 +1,166 @@ + +import strutils +import unicode + +# issue #3045 + +const + Base = 36 + TMin = 1 + TMax = 26 + Skew = 38 + Damp = 700 + InitialBias = 72 + InitialN = 128 + Delimiter = '-' + +type + PunyError* = object of Exception + +proc decodeDigit(x: char): int {.raises: [PunyError].} = + if '0' <= x and x <= '9': + result = ord(x) - (ord('0') - 26) + elif 'A' <= x and x <= 'Z': + result = ord(x) - ord('A') + elif 'a' <= x and x <= 'z': + result = ord(x) - ord('a') + else: + raise newException(PunyError, "Bad input") + +proc encodeDigit(digit: int): Rune {.raises: [PunyError].} = + if 0 <= digit and digit < 26: + result = Rune(digit + ord('a')) + elif 26 <= digit and digit < 36: + result = Rune(digit + (ord('0') - 26)) + else: + raise newException(PunyError, "internal error in punycode encoding") + +proc isBasic(c: char): bool = ord(c) < 0x80 +proc isBasic(r: Rune): bool = int(r) < 0x80 + +proc adapt(delta, numPoints: int, first: bool): int = + var d = if first: delta div Damp else: delta div 2 + d += d div numPoints + var k = 0 + while d > ((Base-TMin)*TMax) div 2: + d = d div (Base - TMin) + k += Base + result = k + (Base - TMin + 1) * d div (d + Skew) + +proc encode*(prefix, s: string): string {.raises: [PunyError].} = + ## Encode a string that may contain Unicode. + ## Prepend `prefix` to the result + result = prefix + var (d, n, bias) = (0, InitialN, InitialBias) + var (b, remaining) = (0, 0) + for r in s.runes: + if r.isBasic: + # basic Ascii character + inc b + result.add($r) + else: + # special character + inc remaining + + var h = b + if b > 0: + result.add(Delimiter) # we have some Ascii chars + while remaining != 0: + var m: int = high(int32) + for r in s.runes: + if m > int(r) and int(r) >= n: + m = int(r) + d += (m - n) * (h + 1) + if d < 0: + raise newException(PunyError, "invalid label " & s) + n = m + for r in s.runes: + if int(r) < n: + inc d + if d < 0: + raise newException(PunyError, "invalid label " & s) + continue + if int(r) > n: + continue + var q = d + var k = Base + while true: + var t = k - bias + if t < TMin: + t = TMin + elif t > TMax: + t = TMax + if q < t: + break + result.add($encodeDigit(t + (q - t) mod (Base - t))) + q = (q - t) div (Base - t) + k += Base + result.add($encodeDigit(q)) + bias = adapt(d, h + 1, h == b) + d = 0 + inc h + dec remaining + inc d + inc n + +proc encode*(s: string): string {.raises: [PunyError].} = + ## Encode a string that may contain Unicode. Prefix is empty. + result = encode("", s) + +proc decode*(encoded: string): string {.raises: [PunyError].} = + ## Decode a Punycode-encoded string + var + n = InitialN + i = 0 + bias = InitialBias + var d = rfind(encoded, Delimiter) + result = "" + + if d > 0: + # found Delimiter + for j in 0..<d: + var c = encoded[j] # char + if not c.isBasic: + raise newException(PunyError, "Encoded contains a non-basic char") + result.add(c) # add the character + inc d + else: + d = 0 # set to first index + + while (d < len(encoded)): + var oldi = i + var w = 1 + var k = Base + while true: + if d == len(encoded): + raise newException(PunyError, "Bad input: " & encoded) + var c = encoded[d]; inc d + var digit = int(decodeDigit(c)) + if digit > (high(int32) - i) div w: + raise newException(PunyError, "Too large a value: " & $digit) + i += digit * w + var t: int + if k <= bias: + t = TMin + elif k >= bias + TMax: + t = TMax + else: + t = k - bias + if digit < t: + break + w *= Base - t + k += Base + bias = adapt(i - oldi, runelen(result) + 1, oldi == 0) + + if i div (runelen(result) + 1) > high(int32) - n: + raise newException(PunyError, "Value too large") + + n += i div (runelen(result) + 1) + i = i mod (runelen(result) + 1) + insert(result, $Rune(n), i) + inc i + +when isMainModule: + assert(decode(encode("", "bücher")) == "bücher") + assert(decode(encode("münchen")) == "münchen") + assert encode("xn--", "münchen") == "xn--mnchen-3ya" diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 359014d8c..89ef2fcd2 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -14,6 +14,32 @@ import strutils {.deadCodeElim: on.} +proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, + procvar.} = + ## Expand tab characters in `s` by `tabSize` spaces + + result = newStringOfCap(s.len + s.len shr 2) + var pos = 0 + + template addSpaces(n) = + for j in 0 ..< n: + result.add(' ') + pos += 1 + + for i in 0 ..< len(s): + let c = s[i] + if c == '\t': + let + denominator = if tabSize > 0: tabSize else: 1 + numSpaces = tabSize - pos mod denominator + + addSpaces(numSpaces) + else: + result.add(c) + pos += 1 + if c == '\l': + pos = 0 + proc partition*(s: string, sep: string, right: bool = false): (string, string, string) {.noSideEffect, procvar.} = @@ -22,16 +48,9 @@ proc partition*(s: string, sep: string, ## Returns a 3 string tuple of (beforeSep, `sep`, afterSep) or ## (`s`, "", "") if `sep` is not found and `right` is false or ## ("", "", `s`) if `sep` is not found and `right` is true - let position = if right: s.rfind(sep) else: s.find(sep) - if position != -1: - let - beforeSep = s[0 ..< position] - afterSep = s[position + sep.len ..< s.len] - - return (beforeSep, sep, afterSep) - + return (s[0 ..< position], sep, s[position + sep.len ..< s.len]) return if right: ("", "", s) else: (s, "", "") proc rpartition*(s: string, sep: string): (string, string, string) @@ -43,6 +62,14 @@ proc rpartition*(s: string, sep: string): (string, string, string) return partition(s, sep, right = true) when isMainModule: + doAssert expandTabs("\t", 4) == " " + doAssert expandTabs("\tfoo\t", 4) == " foo " + doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" + doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " + doAssert expandTabs("", 4) == "" + doAssert expandTabs("", 0) == "" + doAssert expandTabs("\t\t\t", 0) == "" + doAssert partition("foo:bar", ":") == ("foo", ":", "bar") doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar") doAssert partition("foobarbar", "bank") == ("foobarbar", "", "") diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 708f9ed4b..b6edb834c 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1319,38 +1319,6 @@ proc replace*(s: string, sub, by: char): string {.noSideEffect, else: result[i] = s[i] inc(i) -proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, - procvar, rtl, extern: "nsuExpandTabsStr".} = - ## Expand tab characters in `s` by `tabSize` spaces - - if len(s) == 0: - return s - - result = newStringOfCap(s.len + s.len shr 2) - - var pos = 0 - - template addSpaces(n) = - for j in 0 ..< n: - result.add(' ') - pos += 1 - - for i in 0 ..< len(s): - let c = s[i] - - if c == '\t': - let - denominator = if tabSize > 0: tabSize else: 1 - numSpaces = tabSize - pos mod denominator - - addSpaces(numSpaces) - else: - result.add(c) - pos += 1 - - if c == '\l': - pos = 0 - proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, rtl, extern: "nsuReplaceWord".} = ## Replaces `sub` in `s` by the string `by`. @@ -2207,14 +2175,6 @@ when isMainModule: doAssert(not isUpper("AAcc")) doAssert(not isUpper("A#$")) - doAssert expandTabs("\t", 4) == " " - doAssert expandTabs("\tfoo\t", 4) == " foo " - doAssert expandTabs("\tfoo\tbar", 4) == " foo bar" - doAssert expandTabs("\tfoo\tbar\t", 4) == " foo bar " - doAssert expandTabs("", 4) == "" - doAssert expandTabs("", 0) == "" - doAssert expandTabs("\t\t\t", 0) == "" - doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""] |