Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Andreas Rumpf 2016-02-26 14:49:07 +01:00
commit 4b3f164368
16 changed files with 70 additions and 68 deletions

View file

@ -104,6 +104,7 @@ Files: "lib/pure/concurrency/*.cfg"
Files: "lib/impure/*.nim" Files: "lib/impure/*.nim"
Files: "lib/impure/nre/private/*.nim" Files: "lib/impure/nre/private/*.nim"
Files: "lib/wrappers/*.nim" Files: "lib/wrappers/*.nim"
Files: "lib/arch/*.nim"
Files: "lib/wrappers/readline/*.nim" Files: "lib/wrappers/readline/*.nim"
Files: "lib/wrappers/linenoise/*.nim" Files: "lib/wrappers/linenoise/*.nim"

View file

@ -178,10 +178,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result.typ = n[1].typ result.typ = n[1].typ
of mDotDot: of mDotDot:
result = n result = n
# disallow negative indexing for now:
if not c.p.bracketExpr.isNil:
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
of mRoof: of mRoof:
let bracketExpr = if n.len == 3: n.sons[2] else: c.p.bracketExpr let bracketExpr = if n.len == 3: n.sons[2] else: c.p.bracketExpr
if bracketExpr.isNil: if bracketExpr.isNil:

View file

@ -60,7 +60,7 @@ proc searchInstTypes*(key: PType): PType =
if inst.id == key.id: return inst if inst.id == key.id: return inst
if inst.sons.len < key.sons.len: if inst.sons.len < key.sons.len:
# XXX: This happens for prematurely cached # XXX: This happens for prematurely cached
# types such as TChannel[empty]. Why? # types such as Channel[empty]. Why?
# See the notes for PActor in handleGenericInvocation # See the notes for PActor in handleGenericInvocation
return return
block matchType: block matchType:

View file

@ -9,7 +9,7 @@
## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``. ## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``.
## Note: For inter thread communication use ## Note: For inter thread communication use
## a `TChannel <channels.html>`_ instead. ## a `Channel <channels.html>`_ instead.
import math import math

View file

@ -7,7 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
when not defined(nimCoroutines): when not defined(nimCoroutines) and not defined(nimdoc):
{.error: "Coroutines require -d:nimCoroutines".} {.error: "Coroutines require -d:nimCoroutines".}
import os, times import os, times

View file

@ -455,14 +455,15 @@ proc redirection(status: string): bool =
if status.startsWith(i): if status.startsWith(i):
return true return true
proc getNewLocation(lastUrl: string, headers: StringTableRef): string = proc getNewLocation(lastURL: string, headers: StringTableRef): string =
result = headers.getOrDefault"Location" result = headers.getOrDefault"Location"
if result == "": httpError("location header expected") if result == "": httpError("location header expected")
# Relative URLs. (Not part of the spec, but soon will be.) # Relative URLs. (Not part of the spec, but soon will be.)
let r = parseUri(result) let r = parseUri(result)
if r.hostname == "" and r.path != "": if r.hostname == "" and r.path != "":
let origParsed = parseUri(lastUrl) var parsed = parseUri(lastURL)
result = origParsed.hostname & "/" & r.path parsed.path = r.path
result = $parsed
proc get*(url: string, extraHeaders = "", maxRedirects = 5, proc get*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: SSLContext = defaultSSLContext, sslContext: SSLContext = defaultSSLContext,
@ -481,7 +482,7 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
let redirectTo = getNewLocation(lastURL, result.headers) let redirectTo = getNewLocation(lastURL, result.headers)
result = request(redirectTo, httpGET, extraHeaders, "", sslContext, result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
timeout, userAgent, proxy) timeout, userAgent, proxy)
lastUrl = redirectTo lastURL = redirectTo
proc getContent*(url: string, extraHeaders = "", maxRedirects = 5, proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: SSLContext = defaultSSLContext, sslContext: SSLContext = defaultSSLContext,
@ -528,14 +529,14 @@ proc post*(url: string, extraHeaders = "", body = "",
result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent, result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
proxy) proxy)
var lastUrl = "" var lastURL = url
for i in 1..maxRedirects: for i in 1..maxRedirects:
if result.status.redirection(): if result.status.redirection():
let redirectTo = getNewLocation(lastURL, result.headers) let redirectTo = getNewLocation(lastURL, result.headers)
var meth = if result.status != "307": httpGet else: httpPost var meth = if result.status != "307": httpGet else: httpPost
result = request(redirectTo, meth, xh, xb, sslContext, timeout, result = request(redirectTo, meth, xh, xb, sslContext, timeout,
userAgent, proxy) userAgent, proxy)
lastUrl = redirectTo lastURL = redirectTo
proc postContent*(url: string, extraHeaders = "", body = "", proc postContent*(url: string, extraHeaders = "", body = "",
maxRedirects = 5, maxRedirects = 5,
@ -827,7 +828,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
if result.status.redirection(): if result.status.redirection():
let redirectTo = getNewLocation(lastURL, result.headers) let redirectTo = getNewLocation(lastURL, result.headers)
result = await client.request(redirectTo, httpGET) result = await client.request(redirectTo, httpGET)
lastUrl = redirectTo lastURL = redirectTo
proc post*(client: AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[Response] {.async.} = proc post*(client: AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[Response] {.async.} =
## Connects to the hostname specified by the URL and performs a POST request. ## Connects to the hostname specified by the URL and performs a POST request.

View file

@ -51,7 +51,7 @@
## ] ## ]
import import
hashes, strutils, lexbase, streams, unicode, macros hashes, tables, strutils, lexbase, streams, unicode, macros
type type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing JsonEventKind* = enum ## enumeration of all events that may occur when parsing
@ -567,7 +567,7 @@ type
of JNull: of JNull:
nil nil
of JObject: of JObject:
fields*: seq[tuple[key: string, val: JsonNode]] fields*: Table[string, JsonNode]
of JArray: of JArray:
elems*: seq[JsonNode] elems*: seq[JsonNode]
@ -617,7 +617,7 @@ proc newJObject*(): JsonNode =
## Creates a new `JObject JsonNode` ## Creates a new `JObject JsonNode`
new(result) new(result)
result.kind = JObject result.kind = JObject
result.fields = @[] result.fields = initTable[string, JsonNode](4)
proc newJArray*(): JsonNode = proc newJArray*(): JsonNode =
## Creates a new `JArray JsonNode` ## Creates a new `JArray JsonNode`
@ -657,8 +657,8 @@ proc getBVal*(n: JsonNode, default: bool = false): bool =
else: return n.bval else: return n.bval
proc getFields*(n: JsonNode, proc getFields*(n: JsonNode,
default: seq[tuple[key: string, val: JsonNode]] = @[]): default = initTable[string, JsonNode](4)):
seq[tuple[key: string, val: JsonNode]] = Table[string, JsonNode] =
## Retrieves the key, value pairs of a `JObject JsonNode`. ## Retrieves the key, value pairs of a `JObject JsonNode`.
## ##
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil. ## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
@ -700,8 +700,8 @@ proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
## Generic constructor for JSON data. Creates a new `JObject JsonNode` ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
new(result) new(result)
result.kind = JObject result.kind = JObject
newSeq(result.fields, keyVals.len) result.fields = initTable[string, JsonNode](4)
for i, p in pairs(keyVals): result.fields[i] = p for key, val in items(keyVals): result.fields[key] = val
proc `%`*(elements: openArray[JsonNode]): JsonNode = proc `%`*(elements: openArray[JsonNode]): JsonNode =
## Generic constructor for JSON data. Creates a new `JArray JsonNode` ## Generic constructor for JSON data. Creates a new `JArray JsonNode`
@ -761,7 +761,9 @@ proc `==`* (a,b: JsonNode): bool =
of JObject: of JObject:
a.fields == b.fields a.fields == b.fields
proc hash* (n:JsonNode): Hash = proc hash*(n: Table[string, JsonNode]): Hash {.noSideEffect.}
proc hash*(n: JsonNode): Hash =
## Compute the hash for a JSON node ## Compute the hash for a JSON node
case n.kind case n.kind
of JArray: of JArray:
@ -779,6 +781,11 @@ proc hash* (n:JsonNode): Hash =
of JNull: of JNull:
result = hash(0) result = hash(0)
proc hash*(n: Table[string, JsonNode]): Hash =
for key, val in n:
result = result !& hash(key) !& hash(val)
result = !$result
proc len*(n: JsonNode): int = proc len*(n: JsonNode): int =
## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JArray`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs. ## If `n` is a `JObject`, it returns the number of pairs.
@ -793,10 +800,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
## If the value at `name` does not exist, returns nil ## If the value at `name` does not exist, returns nil
assert(not isNil(node)) assert(not isNil(node))
assert(node.kind == JObject) assert(node.kind == JObject)
for key, item in items(node.fields): result = node.fields.getOrDefault(name)
if key == name:
return item
return nil
proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
## Gets the node at `index` in an Array. Result is undefined if `index` ## Gets the node at `index` in an Array. Result is undefined if `index`
@ -808,8 +812,7 @@ proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
proc hasKey*(node: JsonNode, key: string): bool = proc hasKey*(node: JsonNode, key: string): bool =
## Checks if `key` exists in `node`. ## Checks if `key` exists in `node`.
assert(node.kind == JObject) assert(node.kind == JObject)
for k, item in items(node.fields): result = node.fields.hasKey(key)
if k == key: return true
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
## Deprecated for `hasKey` ## Deprecated for `hasKey`
@ -820,20 +823,14 @@ proc add*(father, child: JsonNode) =
father.elems.add(child) father.elems.add(child)
proc add*(obj: JsonNode, key: string, val: JsonNode) = proc add*(obj: JsonNode, key: string, val: JsonNode) =
## Adds ``(key, val)`` pair to the JObject node `obj`. For speed ## Sets a field from a `JObject`.
## reasons no check for duplicate keys is performed!
## But ``[]=`` performs the check.
assert obj.kind == JObject assert obj.kind == JObject
obj.fields.add((key, val)) obj.fields[key] = val
proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
## Sets a field from a `JObject`. Performs a check for duplicate keys. ## Sets a field from a `JObject`.
assert(obj.kind == JObject) assert(obj.kind == JObject)
for i in 0..obj.fields.len-1: obj.fields[key] = val
if obj.fields[i].key == key:
obj.fields[i].val = val
return
obj.fields.add((key, val))
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
## Traverses the node and gets the given value. If any of the ## Traverses the node and gets the given value. If any of the
@ -856,13 +853,11 @@ proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
node[keys[keys.len-1]] = value node[keys[keys.len-1]] = value
proc delete*(obj: JsonNode, key: string) = proc delete*(obj: JsonNode, key: string) =
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs. ## Deletes ``obj[key]``.
assert(obj.kind == JObject) assert(obj.kind == JObject)
for i in 0..obj.fields.len-1: if not obj.fields.hasKey(key):
if obj.fields[i].key == key: raise newException(IndexError, "key not in object")
obj.fields.delete(i) obj.fields.del(key)
return
raise newException(IndexError, "key not in object")
proc copy*(p: JsonNode): JsonNode = proc copy*(p: JsonNode): JsonNode =
## Performs a deep copy of `a`. ## Performs a deep copy of `a`.
@ -879,8 +874,8 @@ proc copy*(p: JsonNode): JsonNode =
result = newJNull() result = newJNull()
of JObject: of JObject:
result = newJObject() result = newJObject()
for key, field in items(p.fields): for key, val in pairs(p.fields):
result.fields.add((key, copy(field))) result.fields[key] = copy(val)
of JArray: of JArray:
result = newJArray() result = newJArray()
for i in items(p.elems): for i in items(p.elems):
@ -924,15 +919,17 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
if node.fields.len > 0: if node.fields.len > 0:
result.add("{") result.add("{")
result.nl(ml) # New line result.nl(ml) # New line
for i in 0..len(node.fields)-1: var i = 0
for key, val in pairs(node.fields):
if i > 0: if i > 0:
result.add(", ") result.add(", ")
result.nl(ml) # New Line result.nl(ml) # New Line
inc i
# Need to indent more than { # Need to indent more than {
result.indent(newIndent(currIndent, indent, ml)) result.indent(newIndent(currIndent, indent, ml))
result.add(escapeJson(node.fields[i].key)) result.add(escapeJson(key))
result.add(": ") result.add(": ")
toPretty(result, node.fields[i].val, indent, ml, false, toPretty(result, val, indent, ml, false,
newIndent(currIndent, indent, ml)) newIndent(currIndent, indent, ml))
result.nl(ml) result.nl(ml)
result.indent(currIndent) # indent the same as { result.indent(currIndent) # indent the same as {
@ -994,7 +991,7 @@ proc toUgly*(result: var string, node: JsonNode) =
result.add "]" result.add "]"
of JObject: of JObject:
result.add "{" result.add "{"
for key, value in items(node.fields): for key, value in pairs(node.fields):
if comma: result.add "," if comma: result.add ","
else: comma = true else: comma = true
result.add key.escapeJson() result.add key.escapeJson()
@ -1033,15 +1030,15 @@ iterator mitems*(node: var JsonNode): var JsonNode =
iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] = iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject. ## Iterator for the child elements of `node`. `node` has to be a JObject.
assert node.kind == JObject assert node.kind == JObject
for key, val in items(node.fields): for key, val in pairs(node.fields):
yield (key, val) yield (key, val)
iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] = iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject. ## Iterator for the child elements of `node`. `node` has to be a JObject.
## Items can be modified ## Values can be modified
assert node.kind == JObject assert node.kind == JObject
for keyVal in mitems(node.fields): for key, val in mpairs(node.fields):
yield keyVal yield (key, val)
proc eat(p: var JsonParser, tok: TokKind) = proc eat(p: var JsonParser, tok: TokKind) =
if p.tok == tok: discard getTok(p) if p.tok == tok: discard getTok(p)

View file

@ -14,6 +14,9 @@
import dynlib import dynlib
when defined(vcc):
{.passC: "-DWIN32_LEAN_AND_MEAN".}
const const
useWinUnicode* = not defined(useWinAnsi) useWinUnicode* = not defined(useWinAnsi)

View file

@ -1,13 +1,13 @@
import json, tables, sequtils import json, tables, sequtils
proc run(json_params: TTable) = proc run(json_params: Table) =
let json_elems = json_params["files"].elems let json_elems = json_params["files"].elems
# These fail compilation. # These fail compilation.
var files = map(json_elems, proc (x: PJsonNode): string = x.str) var files = map(json_elems, proc (x: JsonNode): string = x.str)
#var files = json_elems.map do (x: PJsonNode) -> string: x.str #var files = json_elems.map do (x: JsonNode) -> string: x.str
echo "Hey!" echo "Hey!"
when isMainModule: when isMainModule:
let text = """{"files": ["a", "b", "c"]}""" let text = """{"files": ["a", "b", "c"]}"""
run(toTable((text.parseJson).fields)) run((text.parseJson).fields)

View file

@ -1,7 +1,7 @@
# bug #2257 # bug #2257
import threadpool import threadpool
type StringChannel = TChannel[string] type StringChannel = Channel[string]
var channels: array[1..3, StringChannel] var channels: array[1..3, StringChannel]
type type

View file

@ -6,7 +6,7 @@ discard """
# bug #2257 # bug #2257
import threadpool import threadpool
type StringChannel = TChannel[string] type StringChannel = Channel[string]
var channels: array[1..3, StringChannel] var channels: array[1..3, StringChannel]
type type

View file

@ -9,7 +9,7 @@ tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
import threadpool import threadpool
type StringChannel = TChannel[string] type StringChannel = Channel[string]
var channels: array[1..3, StringChannel] var channels: array[1..3, StringChannel]
type type

View file

@ -11,7 +11,7 @@ fpqeew
[11, 12, 13] [11, 12, 13]
[11, 12, 13] [11, 12, 13]
[11, 12, 13] [11, 12, 13]
{"key1":11,"key2":12,"key3":13} 11 12 13
[11,12,13] [11,12,13]
<Students> <Students>
<Student Name="Aprilfoo" /> <Student Name="Aprilfoo" />
@ -115,7 +115,7 @@ block:
var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}""" var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
for key,val in j.pairs: for key,val in j.pairs:
val.num += 10 val.num += 10
echo j echo j["key1"], " ", j["key2"], " ", j["key3"]
block: block:
var j = parseJson """[1, 2, 3]""" var j = parseJson """[1, 2, 3]"""

View file

@ -12,7 +12,7 @@ type
var var
producer, consumer: Thread[void] producer, consumer: Thread[void]
chan: TChannel[TMsg] chan: Channel[TMsg]
printedLines = 0 printedLines = 0
proc consume() {.thread.} = proc consume() {.thread.} =

View file

@ -7,7 +7,7 @@ discard """
from math import random from math import random
from os import sleep from os import sleep
type PComm = ptr TChannel[int] type PComm = ptr Channel[int]
proc doAction(outC: PComm) {.thread.} = proc doAction(outC: PComm) {.thread.} =
for i in 0.. <5: for i in 0.. <5:
@ -16,7 +16,7 @@ proc doAction(outC: PComm) {.thread.} =
var var
thr: Thread[PComm] thr: Thread[PComm]
chan: TChannel[int] chan: Channel[int]
open(chan) open(chan)
createThread[PComm](thr, doAction, addr(chan)) createThread[PComm](thr, doAction, addr(chan))

View file

@ -10,6 +10,11 @@ Changes affecting backwards compatibility
- ``--out`` and ``--nimcache`` command line arguments are now relative to - ``--out`` and ``--nimcache`` command line arguments are now relative to
current directory. Previously they were relative to project directory. current directory. Previously they were relative to project directory.
- The json module now stores the name/value pairs in objects internally as a
hash table of type ``fields*: Table[string, JsonNode]`` instead of a
sequence. This means that order is no longer preserved. When using the
``table.mpairs`` iterator only the returned values can be modified, no
longer the keys.
Library Additions Library Additions
----------------- -----------------
@ -24,7 +29,6 @@ Compiler Additions
handling (no ``throw`` or ``try``/``catch`` generated) when compiling to C++ handling (no ``throw`` or ``try``/``catch`` generated) when compiling to C++
code code
2016-01-27 Nim in Action is now available! 2016-01-27 Nim in Action is now available!
========================================== ==========================================