Merge remote-tracking branch 'nim-lang/devel' into emscripten-support

This commit is contained in:
Andrey Sobolev 2015-09-18 11:15:16 +06:00
commit 02bf3ba6d7
16 changed files with 208 additions and 52 deletions

View file

@ -99,7 +99,10 @@ proc getUniqueType*(key: PType): PType =
gCanonicalTypes[k] = key gCanonicalTypes[k] = key
result = key result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor: of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
internalError("getUniqueType") if key.sym != nil:
internalError(key.sym.info, "metatype not eliminated")
else:
internalError("metatype not eliminated")
of tyDistinct: of tyDistinct:
if key.deepCopy != nil: result = key if key.deepCopy != nil: result = key
else: result = getUniqueType(lastSon(key)) else: result = getUniqueType(lastSon(key))

View file

@ -234,7 +234,7 @@ proc semGenericStmt(c: PContext, n: PNode,
discard discard
of skProc, skMethod, skIterators, skConverter, skModule: of skProc, skMethod, skIterators, skConverter, skModule:
result.sons[0] = symChoice(c, fn, s, scOption) result.sons[0] = symChoice(c, fn, s, scOption)
# do check of 's.magic==mRoof' here because it might be some # do not check of 's.magic==mRoof' here because it might be some
# other '^' but after overload resolution the proper one: # other '^' but after overload resolution the proper one:
if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^": if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
result.add ctx.bracketExpr result.add ctx.bracketExpr

View file

@ -164,7 +164,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
addDecl(c, prc) addDecl(c, prc)
pushInfoContext(info) pushInfoContext(info)
var cl = initTypeVars(c, pt, info) var cl = initTypeVars(c, pt, info, nil)
var result = instCopyType(cl, prc.typ) var result = instCopyType(cl, prc.typ)
let originalParams = result.n let originalParams = result.n
result.n = originalParams.shallowCopy result.n = originalParams.shallowCopy

View file

@ -957,27 +957,35 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n var n = n
n = replaceTypesInBody(c, pt, n) let original = n.sons[namePos].sym
let s = copySym(original, false)
incl(s.flags, sfFromGeneric)
n = replaceTypesInBody(c, pt, n, original)
result = n result = n
s.ast = result
n.sons[namePos].sym = s
n.sons[genericParamsPos] = emptyNode n.sons[genericParamsPos] = emptyNode
n.sons[paramsPos] = n.typ.n let params = n.typ.n
n.sons[paramsPos] = params
s.typ = n.typ
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
tyFromExpr, tyFieldAccessor}+tyTypeClasses:
localError(params[i].info, "cannot infer type of parameter: " &
params[i].sym.name.s)
openScope(c) openScope(c)
var s = n.sons[namePos].sym
pushOwner(s) pushOwner(s)
addParams(c, n.typ.n, skProc) addParams(c, params, skProc)
pushProcCon(c, s) pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc) addResult(c, n.typ.sons[0], n.info, skProc)
addResultNode(c, n) addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym) n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c) popProcCon(c)
popOwner() popOwner()
closeScope(c) closeScope(c)
s.ast = result
# alternative variant (not quite working): # alternative variant (not quite working):
# var prc = arg[0].sym # var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info) # let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)

View file

@ -90,6 +90,7 @@ type
allowMetaTypes*: bool # allow types such as seq[Number] allowMetaTypes*: bool # allow types such as seq[Number]
# i.e. the result contains unresolved generics # i.e. the result contains unresolved generics
skipTypedesc*: bool # wether we should skip typeDescs skipTypedesc*: bool # wether we should skip typeDescs
owner*: PSym # where this instantiation comes from
recursionLimit: int recursionLimit: int
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
@ -208,6 +209,9 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: return nil if s == nil: return nil
# symbol is not our business:
if cl.owner != nil and s.owner != cl.owner:
return s
result = PSym(idTableGet(cl.symMap, s)) result = PSym(idTableGet(cl.symMap, s))
if result == nil: if result == nil:
result = copySym(s, false) result = copySym(s, false)
@ -477,22 +481,33 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
else: discard else: discard
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars = proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
owner: PSym): TReplTypeVars =
initIdTable(result.symMap) initIdTable(result.symMap)
copyIdTable(result.typeMap, pt) copyIdTable(result.typeMap, pt)
initIdTable(result.localCache) initIdTable(result.localCache)
result.info = info result.info = info
result.c = p result.c = p
result.owner = owner
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode = proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
var cl = initTypeVars(p, pt, n.info) owner: PSym): PNode =
var cl = initTypeVars(p, pt, n.info, owner)
pushInfoContext(n.info)
result = replaceTypeVarsN(cl, n)
popInfoContext()
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
original, new: PSym): PNode =
var cl = initTypeVars(p, pt, n.info, original)
idTablePut(cl.symMap, original, new)
pushInfoContext(n.info) pushInfoContext(n.info)
result = replaceTypeVarsN(cl, n) result = replaceTypeVarsN(cl, n)
popInfoContext() popInfoContext()
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo, proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType = t: PType): PType =
var cl = initTypeVars(p, pt, info) var cl = initTypeVars(p, pt, info, nil)
pushInfoContext(info) pushInfoContext(info)
result = replaceTypeVarsT(cl, t) result = replaceTypeVarsT(cl, t)
popInfoContext() popInfoContext()

View file

@ -511,6 +511,9 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
proc matchUserTypeClass*(c: PContext, m: var TCandidate, proc matchUserTypeClass*(c: PContext, m: var TCandidate,
ff, a: PType): TTypeRelation = ff, a: PType): TTypeRelation =
var body = ff.skipTypes({tyUserTypeClassInst}) var body = ff.skipTypes({tyUserTypeClassInst})
if c.inTypeClass > 20:
localError(body.n[3].info, $body.n[3] & " too nested for type matching")
return isNone
openScope(c) openScope(c)
inc c.inTypeClass inc c.inTypeClass
@ -590,7 +593,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
# Here, N-1 will be initially nkStaticExpr that can be evaluated only after # Here, N-1 will be initially nkStaticExpr that can be evaluated only after
# N is bound to a concrete value during the matching of the first param. # N is bound to a concrete value during the matching of the first param.
# This proc is used to evaluate such static expressions. # This proc is used to evaluate such static expressions.
let instantiated = replaceTypesInBody(c.c, c.bindings, n) let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
result = c.c.semExpr(c.c, instantiated) result = c.c.semExpr(c.c, instantiated)
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =

View file

@ -145,7 +145,7 @@ body {
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
color: #2d2d2d; color: #666;
background-color: rgba(252, 248, 244, 0.75); } background-color: rgba(252, 248, 244, 0.75); }
/* Skeleton grid */ /* Skeleton grid */

View file

@ -6,23 +6,74 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## This module implement an asynchronous FTP client. ## This module implements an asynchronous FTP client. It allows you to connect
## to an FTP server and perform operations on it such as for example:
## ##
## Examples ## * The upload of new files.
## -------- ## * The removal of existing files.
## * Download of files.
## * Changing of files' permissions.
## * Navigation through the FTP server's directories.
##
## Connecting to an FTP server
## ------------------------
##
## In order to begin any sort of transfer of files you must first
## connect to an FTP server. You can do so with the ``connect`` procedure.
## ##
## .. code-block::nim ## .. code-block::nim
## ## import asyncdispatch, asyncftpclient
## proc main() {.async.} =
## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") ## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
## proc main(ftp: AsyncFtpClient) {.async.} =
## await ftp.connect() ## await ftp.connect()
## echo await ftp.pwd() ## echo("Connected")
## echo await ftp.listDirs() ## waitFor(main())
## await ftp.store("payload.jpg", "payload.jpg")
## await ftp.retrFile("payload.jpg", "payload2.jpg")
## echo("Finished")
## ##
## waitFor main(ftp) ## A new ``main`` async procedure must be declared to allow the use of the
## ``await`` keyword. The connection will complete asynchronously and the
## client will be connected after the ``await ftp.connect()`` call.
##
## Uploading a new file
## --------------------
##
## After a connection is made you can use the ``store`` procedure to upload
## a new file to the FTP server. Make sure to check you are in the correct
## working directory before you do so with the ``pwd`` procedure, you can also
## instead specify an absolute path.
##
## .. code-block::nim
## import asyncdispatch, asyncftpclient
## proc main() {.async.} =
## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
## await ftp.connect()
## let currentDir = await ftp.pwd()
## assert currentDir == "/home/user/"
## await ftp.store("file.txt", "file.txt")
## echo("File finished uploading")
## waitFor(main())
##
## Checking the progress of a file transfer
## ----------------------------------------
##
## The progress of either a file upload or a file download can be checked
## by specifying a ``onProgressChanged`` procedure to the ``store`` or
## ``retrFile`` procedures.
##
## .. code-block::nim
## import asyncdispatch, asyncftpclient
##
## proc onProgressChanged(total, progress: BiggestInt,
## speed: float): Future[void] =
## echo("Uploaded ", progress, " of ", total, " bytes")
## echo("Current speed: ", speed, " kb/s")
##
## proc main() {.async.} =
## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
## await ftp.connect()
## await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged)
## echo("File finished uploading")
## waitFor(main())
import asyncdispatch, asyncnet, strutils, parseutils, os, times import asyncdispatch, asyncnet, strutils, parseutils, os, times

View file

@ -67,6 +67,12 @@ type
Http409 = "409 Conflict", Http409 = "409 Conflict",
Http410 = "410 Gone", Http410 = "410 Gone",
Http411 = "411 Length Required", Http411 = "411 Length Required",
Http412 = "412 Precondition Failed",
Http413 = "413 Request Entity Too Large",
Http414 = "414 Request-URI Too Long",
Http415 = "415 Unsupported Media Type",
Http416 = "416 Requested Range Not Satisfiable",
Http417 = "417 Expectation Failed",
Http418 = "418 I'm a teapot", Http418 = "418 I'm a teapot",
Http500 = "500 Internal Server Error", Http500 = "500 Internal Server Error",
Http501 = "501 Not Implemented", Http501 = "501 Not Implemented",

View file

@ -8,6 +8,38 @@
# #
## This module implements a base64 encoder and decoder. ## This module implements a base64 encoder and decoder.
##
## Encoding data
## -------------
##
## In order to encode some text simply call the ``encode`` procedure:
##
## .. code-block::nim
## import base64
## let encoded = encode("Hello World")
## echo(encoded) # SGVsbG8gV29ybGQ=
##
## Apart from strings you can also encode lists of integers or characters:
##
## .. code-block::nim
## import base64
## let encodedInts = encode([1,2,3])
## echo(encodedInts) # AQID
## let encodedChars = encode(['h','e','y'])
## echo(encodedChars) # aGV5
##
## The ``encode`` procedure takes an ``openarray`` so both arrays and sequences
## can be passed as parameters.
##
## Decoding data
## -------------
##
## To decode a base64 encoded data string simply call the ``decode``
## procedure:
##
## .. code-block::nim
## import base64
## echo(decode("SGVsbG8gV29ybGQ=")) # Hello World
const const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
@ -64,11 +96,16 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string = proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a ## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added. ## `newline` is added.
##
## This procedure encodes an openarray (array or sequence) of either integers
## or characters.
encodeInternal(s, lineLen, newLine) encodeInternal(s, lineLen, newLine)
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a ## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added. ## `newline` is added.
##
## This procedure encodes a string.
encodeInternal(s, lineLen, newLine) encodeInternal(s, lineLen, newLine)
proc decodeByte(b: char): int {.inline.} = proc decodeByte(b: char): int {.inline.} =

View file

@ -13,7 +13,12 @@ import sockets, strutils, parseutils, times, os, asyncio
from asyncnet import nil from asyncnet import nil
from rawsockets import nil from rawsockets import nil
from asyncdispatch import PFuture from asyncdispatch import PFuture
## **Note**: This module is deprecated since version 0.11.3.
## You should use the async version of this module
## `asyncftpclient <asyncftpclient.html>`_.
##
## ----
##
## This module **partially** implements an FTP client as specified ## This module **partially** implements an FTP client as specified
## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_. ## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
## ##
@ -36,6 +41,8 @@ from asyncdispatch import PFuture
## **Warning:** The API of this module is unstable, and therefore is subject ## **Warning:** The API of this module is unstable, and therefore is subject
## to change. ## to change.
{.deprecated.}
type type
FtpBase*[SockType] = ref FtpBaseObj[SockType] FtpBase*[SockType] = ref FtpBaseObj[SockType]
FtpBaseObj*[SockType] = object FtpBaseObj*[SockType] = object

View file

@ -622,9 +622,12 @@ proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
proc getFNum*(n: JsonNode, default: float = 0.0): float = proc getFNum*(n: JsonNode, default: float = 0.0): float =
## Retrieves the float value of a `JFloat JsonNode`. ## Retrieves the float value of a `JFloat JsonNode`.
## ##
## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil. ## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil.
if n.isNil or n.kind != JFloat: return default if n.isNil: return default
else: return n.fnum case n.kind
of JFloat: return n.fnum
of JInt: return float(n.num)
else: return default
proc getBVal*(n: JsonNode, default: bool = false): bool = proc getBVal*(n: JsonNode, default: bool = false): bool =
## Retrieves the bool value of a `JBool JsonNode`. ## Retrieves the bool value of a `JBool JsonNode`.

View file

@ -21,6 +21,20 @@ include "system/inclrtl"
{.push debugger:off .} # the user does not want to trace a part {.push debugger:off .} # the user does not want to trace a part
# of the standard library! # of the standard library!
proc binom*(n, k: int): int {.noSideEffect.} =
## Computes the binomial coefficient
if k <= 0: return 1
if 2*k > n: return binom(n, n-k)
result = n
for i in countup(2, k):
result = (result * (n + 1 - i)) div i
proc fac*(n: int): int {.noSideEffect.} =
## Computes the faculty/factorial function.
result = 1
for i in countup(2, n):
result = result * i
{.push checks:off, line_dir:off, stack_trace:off.} {.push checks:off, line_dir:off, stack_trace:off.}
when defined(Posix) and not defined(haiku): when defined(Posix) and not defined(haiku):
@ -72,21 +86,6 @@ proc classify*(x: float): FloatClass =
return fcNormal return fcNormal
# XXX: fcSubnormal is not detected! # XXX: fcSubnormal is not detected!
proc binom*(n, k: int): int {.noSideEffect.} =
## Computes the binomial coefficient
if k <= 0: return 1
if 2*k > n: return binom(n, n-k)
result = n
for i in countup(2, k):
result = (result * (n + 1 - i)) div i
proc fac*(n: int): int {.noSideEffect.} =
## Computes the faculty/factorial function.
result = 1
for i in countup(2, n):
result = result * i
proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
## Returns true, if `x` is a power of two, false otherwise. ## Returns true, if `x` is a power of two, false otherwise.
## Zero and negative numbers are not a power of two. ## Zero and negative numbers are not a power of two.

22
tests/typerel/t2plus.nim Normal file
View file

@ -0,0 +1,22 @@
discard """
output: "2.0"
"""
{.warning[TypelessParam]: off.}
import future
# bug #3329
proc foldRight[T,U](lst: seq[T], v: U, f: (T, U) -> U): U =
result = v
for x in lst:
result = f(x, result)
proc mean[T: SomeNumber](xs: seq[T]): T =
xs.foldRight(0.T, (xBAZ: auto, yBAZ: auto) => xBAZ + yBAZ) / T(xs.len)
when isMainModule:
let x = mean(@[1.float, 2, 3])
echo x

View file

@ -82,6 +82,8 @@ News
result = $x & y result = $x & y
echo f(0, "abc") echo f(0, "abc")
- The ``ftpclient`` module is now deprecated in favour of the
``asyncdispatch`` module.
Library Additions Library Additions

View file

@ -94,9 +94,9 @@ General FAQ
What about JVM/CLR backends? What about JVM/CLR backends?
---------------------------- ----------------------------
A JVM backend is almost impossible. The JVM is not expressive enough. It has JVM/CLR support is not in the nearest plans. However, since these VMs support FFI to C
never been designed as a general purpose VM anyway. A CLR backend is possible it should be possible to create native Nim bridges, that transparenlty generate all the
but would require much work. glue code thanks to powerful metaprogramming capabilities of Nim.
.. container:: standout .. container:: standout