Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq
2013-08-30 12:44:27 +02:00
22 changed files with 384 additions and 133 deletions

View File

@@ -626,6 +626,7 @@ type
case kind*: TSymKind
of skType:
typeInstCache*: seq[PType]
typScope*: PScope
of routineKinds:
procInstCache*: seq[PInstantiation]
scope*: PScope # the scope where the proc was defined
@@ -799,9 +800,9 @@ const
# imported via 'importc: "fullname"' and no format string.
# creator procs:
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym
proc NewType*(kind: TTypeKind, owner: PSym): PType
proc newType*(kind: TTypeKind, owner: PSym): PType
proc newNode*(kind: TNodeKind): PNode
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
@@ -1111,7 +1112,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
result.loc = s.loc
result.annex = s.annex # BUGFIX
proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too
new(result)

View File

@@ -904,18 +904,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
code.info.line.int)
#result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true
# by the type traits procs' signatures, but until the
# code is more mature it doesn't hurt to be extra safe
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
InternalAssert operand.kind == nkSym
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
case n.sons[0].sym.name.s.normalize
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferExported))
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = n.info
result.info = trait.info
else:
internalAssert false
@@ -1037,8 +1034,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
let operand = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n[0], operand, c.module)
of mIs:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalIsOp(n)

View File

@@ -156,6 +156,8 @@ var
const oKeepVariableNames* = true
const oUseLateInstantiation* = false
proc mainCommandArg*: string =
## This is intended for commands like check or parse
## which will work on the main project file unless

View File

@@ -225,14 +225,14 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
dest.owner = getCurrOwner()
dest.size = - 1
proc makeRangeType*(c: PContext, first, last: biggestInt,
info: TLineInfo): PType =
proc makeRangeType*(c: PContext; first, last: biggestInt;
info: TLineInfo; intType = getSysType(tyInt)): PType =
var n = newNodeI(nkRange, info)
addSon(n, newIntNode(nkIntLit, first))
addSon(n, newIntNode(nkIntLit, last))
addSon(n, newIntTypeNode(nkIntLit, first, intType))
addSon(n, newIntTypeNode(nkIntLit, last, intType))
result = newTypeS(tyRange, c)
result.n = n
rawAddSon(result, getSysType(tyInt)) # basetype of range
addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}:

View File

@@ -113,7 +113,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of skGenericParam:
if s.typ.kind == tyExpr:
result = newSymNode(s, n.info)
result.typ = s.typ.lastSon
result.typ = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:

View File

@@ -561,9 +561,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
case n.kind
of nkSym:
var s = n.sym
if s.kind == skEnumField:
case s.kind
of skEnumField:
result = newIntNodeT(s.position, n)
elif s.kind == skConst:
of skConst:
case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
@@ -581,10 +582,17 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mNegInf: result = newFloatNodeT(NegInf, n)
else:
if sfFakeConst notin s.flags: result = copyTree(s.ast)
elif s.kind in {skProc, skMethod}: # BUGFIX
of {skProc, skMethod}:
result = n
elif s.kind in {skType, skGenericParam}:
of skType:
result = newSymNodeTypeDesc(s, n.info)
of skGenericParam:
if s.typ.kind == tyExpr:
result = s.typ.n
result.typ = s.typ.sons[0]
else:
result = newSymNodeTypeDesc(s, n.info)
else: nil
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:

View File

@@ -130,13 +130,50 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType =
InternalAssert invocation.kind == tyGenericInvokation
let cacheHit = searchInstTypes(invocation)
if cacheHit != nil:
result = cacheHit
else:
let s = invocation.sons[0].sym
let oldScope = c.currentScope
c.currentScope = s.typScope
openScope(c)
pushInfoContext(info)
for i in 0 .. <s.typ.n.sons.len:
let genericParam = s.typ.n[i].sym
let symKind = if genericParam.typ.kind == tyExpr: skConst
else: skType
var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr})
boundSym.ast = invocation.sons[i+1].n
addDecl(c, boundSym)
# XXX: copyTree would have been unnecessary here if semTypeNode
# didn't modify its input parameters. Currently, it does modify
# at least the record lists of the passed object and tuple types
var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil)
popInfoContext()
closeScope(c)
c.currentScope = oldScope
if instantiated != nil:
result = invocation
result.kind = tyGenericInst
result.sons.add instantiated
cacheTypeInst result
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = info
cl.c = c
result = ReplaceTypeVarsT(cl, header)
when oUseLateInstantiation:
lateInstantiateGeneric(c, header, info)
else:
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = info
cl.c = c
result = ReplaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
result = instGenericContainer(c, n.info, header)

View File

@@ -40,7 +40,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n, GetCurrOwner())
result = evalTypeTrait(n[0], n[1], GetCurrOwner())
else:
# a typedesc variable, pass unmodified to evals
result = n

View File

@@ -729,12 +729,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# like: mydata.seq
rawAddSon(s.typ, newTypeS(tyEmpty, c))
s.ast = a
inc c.InGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.InGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
when oUseLateInstantiation:
var body: PType = nil
s.typScope = c.currentScope.parent
else:
inc c.InGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.InGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
popOwner()
closeScope(c)

View File

@@ -156,7 +156,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
LocalError(n.Info, errRangeIsEmpty)
var a = semConstExpr(c, n[1])
var b = semConstExpr(c, n[2])
if not sameType(a.typ, b.typ):
if not sameType(a.typ, b.typ):
LocalError(n.info, errPureTypeMismatch)
elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
tyFloat..tyFloat128,tyUInt8..tyUInt32}:
@@ -195,17 +195,19 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
else:
let e = semExprWithType(c, n.sons[1], {efDetermineType})
if e.kind in {nkIntLit..nkUInt64Lit}:
indx = newTypeS(tyRange, c)
indx.n = newNodeI(nkRange, n.info)
addSon(indx.n, newIntTypeNode(e.kind, 0, e.typ))
addSon(indx.n, newIntTypeNode(e.kind, e.intVal-1, e.typ))
addSonSkipIntLit(indx, e.typ)
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyExpr:
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
InternalAssert c.InGenericContext > 0
if not isOrdinalType(e.typ.lastSon):
localError(n[1].info, errOrdinalTypeExpected)
indx = e.typ
else:
indx = e.typ.skipTypes({tyTypeDesc})
addSonSkipIntLit(result, indx)
if indx.kind == tyGenericInst: indx = lastSon(indx)
if indx.kind != tyGenericParam:
if not isOrdinalType(indx):
if indx.kind notin {tyGenericParam, tyExpr}:
if not isOrdinalType(indx):
LocalError(n.sons[1].info, errOrdinalTypeExpected)
elif enumHasHoles(indx):
LocalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
@@ -587,6 +589,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else:
if sfGenSym notin param.flags: addDecl(c, param)
let typedescId = getIdent"typedesc"
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string,
info: TLineInfo, anon = false): PType =
@@ -634,6 +638,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
of tyTypeDesc:
if tfUnresolved notin paramType.flags:
# naked typedescs are not bindOnce types
if paramType.sonsLen == 0 and paramTypId != nil and
paramTypId.id == typedescId.id: paramTypId = nil
result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
of tyDistinct:
if paramType.sonsLen == 1:
@@ -760,7 +767,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
r.flags.incl tfRetType
result.sons[0] = skipIntLit(r)
res.typ = result.sons[0]
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1)
var length = sonsLen(n)
@@ -846,7 +853,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
LocalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyError, prev, c)
else:
result = instGenericContainer(c, n, result)
when oUseLateInstantiation:
result = lateInstantiateGeneric(c, result, n.info)
else:
result = instGenericContainer(c, n, result)
proc semTypeExpr(c: PContext, n: PNode): PType =
var n = semExprWithType(c, n, {efDetermineType})
@@ -1073,8 +1083,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if constraint.kind != nkEmpty:
typ = semTypeNode(c, constraint, nil)
if typ.kind != tyExpr or typ.len == 0:
if typ.len == 0 and typ.kind == tyTypeDesc:
typ = newTypeS(tyGenericParam, c)
if typ.kind == tyTypeDesc:
if typ.len == 0:
typ = newTypeS(tyTypeDesc, c)
else:
typ = semGenericConstraints(c, typ)

View File

@@ -31,7 +31,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
localError(info, errInheritanceOnlyWithNonFinalObjects)
proc searchInstTypes(key: PType): PType =
proc searchInstTypes*(key: PType): PType =
let genericTyp = key.sons[0]
InternalAssert genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and
@@ -55,7 +55,7 @@ proc searchInstTypes(key: PType): PType =
return inst
proc cacheTypeInst(inst: PType) =
proc cacheTypeInst*(inst: PType) =
# XXX: add to module's generics
# update the refcount
let genericTyp = inst.sons[0]
@@ -208,6 +208,12 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
of tyInt:
result = skipIntLit(t)
else:
if t.kind == tyArray:
let idxt = t.sons[0]
if idxt.kind == tyExpr and
idxt.sym != nil and idxt.sym.kind == skGenericParam:
let value = lookupTypeVar(cl, idxt).n
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
if containsGenericType(t):
result = copyType(t, t.owner, false)
incl(result.flags, tfFromGeneric)

View File

@@ -626,7 +626,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
of tyGenericParam, tyTypeClass:
var x = PType(idTableGet(c.bindings, f))
if x == nil:
if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
if c.calleeSym != nil and c.calleeSym.kind == skType and
f.kind == tyGenericParam and not c.typedescMatched:
# XXX: The fact that generic types currently use tyGenericParam for
# their parameters is really a misnomer. tyGenericParam means "match
# any value" and what we need is "match any type", which can be encoded
@@ -670,7 +671,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone
else:
InternalAssert prev.sonsLen == 1
result = typeRel(c, prev.sons[0], a)
let toMatch = if tfUnresolved in f.flags: a
else: a.sons[0]
result = typeRel(c, prev.sons[0], toMatch)
of tyExpr, tyStmt:
result = isGeneric
of tyProxy:
@@ -772,6 +775,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
if evaluated != nil:
r = isGeneric
arg.typ = newTypeS(tyExpr, c)
arg.typ.sons = @[evaluated.typ]
arg.typ.n = evaluated
if r == isGeneric:

View File

@@ -1451,7 +1451,7 @@ But it seems all this boilerplate code needs to be repeated for the ``TEuro``
currency. This can be solved with templates_.
.. code-block:: nimrod
template Additive(typ: typeDesc): stmt =
template Additive(typ: typedesc): stmt =
proc `+` *(x, y: typ): typ {.borrow.}
proc `-` *(x, y: typ): typ {.borrow.}
@@ -1459,13 +1459,13 @@ currency. This can be solved with templates_.
proc `+` *(x: typ): typ {.borrow.}
proc `-` *(x: typ): typ {.borrow.}
template Multiplicative(typ, base: typeDesc): stmt =
template Multiplicative(typ, base: typedesc): stmt =
proc `*` *(x: typ, y: base): typ {.borrow.}
proc `*` *(x: base, y: typ): typ {.borrow.}
proc `div` *(x: typ, y: base): typ {.borrow.}
proc `mod` *(x: typ, y: base): typ {.borrow.}
template Comparable(typ: typeDesc): stmt =
template Comparable(typ: typedesc): stmt =
proc `<` * (x, y: typ): bool {.borrow.}
proc `<=` * (x, y: typ): bool {.borrow.}
proc `==` * (x, y: typ): bool {.borrow.}
@@ -3323,10 +3323,10 @@ The template body does not open a new scope. To open a new scope a ``block``
statement can be used:
.. code-block:: nimrod
template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} =
template declareInScope(x: expr, t: typedesc): stmt {.immediate.} =
var x: t
template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} =
template declareInNewScope(x: expr, t: typedesc): stmt {.immediate.} =
# open a new scope:
block:
var x: t
@@ -3419,7 +3419,7 @@ In templates identifiers can be constructed with the backticks notation:
.. code-block:: nimrod
template typedef(name: expr, typ: typeDesc) {.immediate.} =
template typedef(name: expr, typ: typedesc) {.immediate.} =
type
`T name`* {.inject.} = typ
`P name`* {.inject.} = ref `T name`
@@ -3480,7 +3480,7 @@ template cannot be accessed in the instantiation context:
.. code-block:: nimrod
template newException*(exceptn: typeDesc, message: string): expr =
template newException*(exceptn: typedesc, message: string): expr =
var
e: ref exceptn # e is implicitly gensym'ed here
new(e)
@@ -3728,6 +3728,25 @@ instantiation type using the param name:
var n = TNode.new
var tree = new(TBinaryTree[int])
When multiple typedesc params are present, they act like a distinct type class
(i.e. they will bind freely to different types). To force a bind-once behavior
one can use a named alias or an explicit `typedesc` generic param:
.. code-block:: nimrod
# `type1` and `type2` are aliases for typedesc available from system.nim
proc acceptOnlyTypePairs(A, B: type1; C, D: type2)
proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U)
Once bound, typedesc params can appear in the rest of the proc signature:
.. code-block:: nimrod
template declareVariableWithType(T: typedesc, value: T) =
var x: T = value
declareVariableWithType int, 42
When used with macros and .compileTime. procs on the other hand, the compiler
does not need to instantiate the code multiple times, because types then can be
manipulated using the unified internal symbol representation. In such context

View File

@@ -62,46 +62,3 @@ Currently, the following C compilers are supported under Windows:
| http://www.digitalmars.com/download/freecompiler.html
However, most testing is done with GCC.
Bootstrapping from github
-------------------------
To get the source code you need either of these:
* A working web browser + tar(or equivalent):
https://github.com/Araq/Nimrod/tarball/master
* wget + tar:
``wget --no-check-certificate "https://github.com/Araq/Nimrod/tarball/master"``
* git: ``git clone git://github.com/Araq/Nimrod.git``
After downloading the source (and extracting it), you need to
extract ``build/csources.zip``:
* ``cd build``
* ``unzip csources.zip``
* ``cd ..``
and then you can bootstrap with:
On Windows
~~~~~~~~~~
* ``build.bat``
* ``bin\nimrod c koch``
* ``koch boot -d:release``
If you want a 64 bit build, make sure that you have a GCC built for Win64 and
execute ``build64.bat`` instead of ``build.bat``.
On UNIX
~~~~~~~
* ``./build.sh``
* ``bin/nimrod c koch``
* ``./koch boot -d:release``
Installation on UNIX can then be done with ``koch install [dir]``.

View File

@@ -10,6 +10,11 @@
## This module implements a simple HTTP client that can be used to retrieve
## webpages/other data.
##
##
## **Note**: This module is not ideal, connection is not kept alive so sites with
## many redirects are expensive. As such in the future this module may change,
## and the current procedures will be deprecated.
##
## Retrieving a website
## ====================
##
@@ -62,8 +67,15 @@
## that as long as the server is sending data an exception will not be raised,
## if however data does not reach client within the specified timeout an ETimeout
## exception will then be raised.
##
## Proxy
## =====
##
## A proxy can be specified as a param to any of these procedures, the ``newProxy``
## constructor should be used for this purpose. However,
## currently only basic authentication is supported.
import sockets, strutils, parseurl, parseutils, strtabs
import sockets, strutils, parseurl, parseutils, strtabs, base64
type
TResponse* = tuple[
@@ -72,6 +84,10 @@ type
headers: PStringTable,
body: string]
PProxy* = ref object
url*: TUrl
auth*: string
EInvalidProtocol* = object of ESynch ## exception that is raised when server
## does not conform to the implemented
## protocol
@@ -239,23 +255,34 @@ when not defined(ssl):
else:
let defaultSSLContext = newContext(verifyMode = CVerifyNone)
proc newProxy*(url: string, auth = ""): PProxy =
## Constructs a new ``TProxy`` object.
result = PProxy(url: parseUrl(url), auth: auth)
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
body = "",
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent): TResponse =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
## | Requests ``url`` with the specified ``httpMethod``.
## | Extra headers can be specified and must be seperated by ``\c\L``
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var r = parseUrl(url)
var r = if proxy == nil: parseUrl(url) else: proxy.url
var headers = substr($httpMethod, len("http"))
headers.add(" /" & r.path & r.query)
if proxy == nil:
headers.add(" /" & r.path & r.query)
else:
headers.add(" " & url)
headers.add(" HTTP/1.1\c\L")
add(headers, "Host: " & r.hostname & "\c\L")
if userAgent != "":
add(headers, "User-Agent: " & userAgent & "\c\L")
if proxy != nil and proxy.auth != "":
let auth = base64.encode(proxy.auth, newline = "")
add(headers, "Proxy-Authorization: basic " & auth & "\c\L")
add(headers, extraHeaders)
add(headers, "\c\L")
@@ -299,30 +326,34 @@ proc getNewLocation(lastUrl: string, headers: PStringTable): string =
proc get*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent): TResponse =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
## | GETs the ``url`` and returns a ``TResponse`` object
## | This proc also handles redirection
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
result = request(url, httpGET, extraHeaders, "", sslContext, timeout, userAgent)
result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
userAgent, proxy)
var lastURL = url
for i in 1..maxRedirects:
if result.status.redirection():
let redirectTo = getNewLocation(lastURL, result.headers)
result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
timeout, userAgent)
timeout, userAgent, proxy)
lastUrl = redirectTo
proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent): string =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): string =
## | GETs the body and returns it as a string.
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent)
var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
proxy)
if r.status[0] in {'4','5'}:
raise newException(EHTTPRequestErr, r.status)
else:
@@ -331,7 +362,8 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
proc post*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent): TResponse =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): TResponse =
## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
## | This proc adds the necessary Content-Length header.
## | This proc also handles redirection.
@@ -339,27 +371,29 @@ proc post*(url: string, extraHeaders = "", body = "",
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent)
result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent,
proxy)
var lastUrl = ""
for i in 1..maxRedirects:
if result.status.redirection():
let redirectTo = getNewLocation(lastURL, result.headers)
var meth = if result.status != "307": httpGet else: httpPost
result = request(redirectTo, meth, xh, body, sslContext, timeout,
userAgent)
userAgent, proxy)
lastUrl = redirectTo
proc postContent*(url: string, extraHeaders = "", body = "",
maxRedirects = 5,
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent): string =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil): string =
## | POSTs ``body`` to ``url`` and returns the response's body as a string
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
## | Extra headers can be specified and must be separated by ``\c\L``.
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
userAgent)
userAgent, proxy)
if r.status[0] in {'4','5'}:
raise newException(EHTTPRequestErr, r.status)
else:
@@ -367,14 +401,15 @@ proc postContent*(url: string, extraHeaders = "", body = "",
proc downloadFile*(url: string, outputFilename: string,
sslContext: PSSLContext = defaultSSLContext,
timeout = -1, userAgent = defUserAgent) =
timeout = -1, userAgent = defUserAgent,
proxy: PProxy = nil) =
## | Downloads ``url`` and saves it to ``outputFilename``
## | An optional timeout can be specified in miliseconds, if reading from the
## server takes longer than specified an ETimeout exception will be raised.
var f: TFile
if open(f, outputFilename, fmWrite):
f.write(getContent(url, sslContext = sslContext, timeout = timeout,
userAgent = userAgent))
userAgent = userAgent, proxy = proxy))
f.close()
else:
fileError("Unable to open file")

View File

@@ -54,7 +54,7 @@ type
`nil` {.magic: "Nil".}
expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
typeDesc* {.magic: TypeDesc.} ## meta type to denote a type description
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
void* {.magic: "VoidType".} ## meta type to denote the absense of any type
auto* = expr
any* = distinct auto
@@ -78,6 +78,17 @@ type
TNumber* = TInteger|TReal
## type class matching all number types
type
## helper types for writing implicitly generic procs
T1* = expr
T2* = expr
T3* = expr
T4* = expr
T5* = expr
type1* = typedesc
type2* = typedesc
type3* = typedesc
proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
## Special compile-time procedure that checks whether `x` is
## defined. `x` has to be an identifier or a qualified identifier.
@@ -1487,7 +1498,7 @@ when not defined(NimrodVM):
proc seqToPtr[T](x: seq[T]): pointer {.noStackFrame, nosideeffect.} =
asm """return `x`"""
proc `==` *[T: typeDesc](x, y: seq[T]): bool {.noSideEffect.} =
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
## Generic equals operator for sequences: relies on a equals operator for
## the element type `T`.
if seqToPtr(x) == seqToPtr(y):
@@ -1499,7 +1510,7 @@ when not defined(NimrodVM):
if x[i] != y[i]: return false
result = true
proc find*[T, S: typeDesc](a: T, item: S): int {.inline.}=
proc find*[T, S](a: T, item: S): int {.inline.}=
## Returns the first index of `item` in `a` or -1 if not found. This requires
## appropriate `items` and `==` operations to work.
for i in items(a):
@@ -1802,7 +1813,7 @@ proc debugEcho*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect,
## to be free of side effects, so that it can be used for debugging routines
## marked as ``noSideEffect``.
template newException*(exceptn: typeDesc, message: string): expr =
template newException*(exceptn: typedesc, message: string): expr =
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
## to `message`. Returns the new exception object.
var
@@ -1815,7 +1826,7 @@ when hostOS == "standalone":
include panicoverride
when not defined(sysFatal):
template sysFatal(exceptn: typeDesc, message: string) =
template sysFatal(exceptn: typedesc, message: string) =
when hostOS == "standalone":
panic(message)
else:
@@ -1824,7 +1835,7 @@ when not defined(sysFatal):
e.msg = message
raise e
template sysFatal(exceptn: typeDesc, message, arg: string) =
template sysFatal(exceptn: typedesc, message, arg: string) =
when hostOS == "standalone":
rawoutput(message)
panic(arg)

View File

@@ -6,8 +6,7 @@ documentation.
Compiling the Nimrod compiler is quite straightforward. Because
the Nimrod compiler itself is written in the Nimrod programming language
the C source of an older version of the compiler are needed to bootstrap the
latest version. The C sources are however included with this repository under
the build directory.
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
Pre-compiled snapshots of the compiler are also available on
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
@@ -53,7 +52,7 @@ and you can also get help in the IRC channel
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
## License
The compiler and the standard library is licensed under the MIT license,
The compiler and the standard library are licensed under the MIT license,
except for some modules where the documentation suggests otherwise. This means
that you can use any license for your own programs developed with Nimrod,
allowing you to create commercial applications.

View File

@@ -6,8 +6,7 @@ documentation.
Compiling the Nimrod compiler is quite straightforward. Because
the Nimrod compiler itself is written in the Nimrod programming language
the C source of an older version of the compiler are needed to bootstrap the
latest version. The C sources are however included with this repository under
the build directory.
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
Pre-compiled snapshots of the compiler are also available on
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
@@ -53,7 +52,7 @@ and you can also get help in the IRC channel
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
## License
The compiler and the standard library is licensed under the MIT license,
The compiler and the standard library are licensed under the MIT license,
except for some modules where the documentation suggests otherwise. This means
that you can use any license for your own programs developed with Nimrod,
allowing you to create commercial applications.

View File

@@ -0,0 +1,87 @@
discard """
msg: '''
int
float
TFoo
TFoo
'''
"""
import typetraits
type
TFoo = object
x, y: int
TBar = tuple
x, y: int
template good(e: expr) =
static: assert(compiles(e))
template bad(e: expr) =
static: assert(not compiles(e))
proc genericParamRepeated[T: typedesc](a: T, b: T) =
static:
echo a.name
echo b.name
good(genericParamRepeated(int, int))
good(genericParamRepeated(float, float))
bad(genericParamRepeated(string, int))
bad(genericParamRepeated(int, float))
proc genericParamOnce[T: typedesc](a, b: T) =
static:
echo a.name
echo b.name
good(genericParamOnce(int, int))
good(genericParamOnce(TFoo, TFoo))
bad(genericParamOnce(string, int))
bad(genericParamOnce(TFoo, float))
proc typePairs(A, B: type1; C, D: type2) = nil
good(typePairs(int, int, TFoo, TFOO))
good(typePairs(TBAR, TBar, TBAR, TBAR))
good(typePairs(int, int, string, string))
bad(typePairs(TBAR, TBar, TBar, TFoo))
bad(typePairs(string, int, TBAR, TBAR))
proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil
good(typePairs2(int, int, TFoo, TFOO))
good(typePairs2(TBAR, TBar, TBAR, TBAR))
good(typePairs2(int, int, string, string))
bad(typePairs2(TBAR, TBar, TBar, TFoo))
bad(typePairs2(string, int, TBAR, TBAR))
proc dontBind(a: typedesc, b: typedesc) =
static:
echo a.name
echo b.name
good(dontBind(int, float))
good(dontBind(TFoo, TFoo))
proc dontBind2(a, b: typedesc) = nil
good(dontBind2(int, float))
good(dontBind2(TBar, int))
proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil
good(bindArg(int, string, 10, 20, "test", "nest"))
good(bindArg(int, int, 10, 20, 30, 40))
bad(bindArg(int, string, 10, "test", "test", "nest"))
bad(bindArg(int, int, 10, 20, 30, "test"))
bad(bindArg(int, string, 10.0, 20, "test", "nest"))
bad(bindArg(int, string, "test", "nest", 10, 20))

View File

@@ -0,0 +1,30 @@
discard """
file: "tgenericshardcases.nim"
output: "int\nfloat\nint\nstring"
"""
import typetraits
proc typeNameLen(x: typedesc): int {.compileTime.} =
result = x.name.len
macro selectType(a, b: typedesc): typedesc =
result = a
type
Foo[T] = object
data1: array[high(T), int]
data2: array[1..typeNameLen(T), selectType(float, string)]
MyEnum = enum A, B, C,D
var f1: Foo[MyEnum]
var f2: Foo[int8]
static:
assert high(f1.data1) == D
assert high(f1.data2) == 6 # length of MyEnum
assert high(f2.data1) == 127
assert high(f2.data2) == 4 # length of int8

View File

@@ -0,0 +1,39 @@
discard """
file: "tmacrogenerics.nim"
msg: '''
instantiation 1 with int and float
instantiation 2 with float and string
instantiation 3 with string and string
counter: 3
'''
output: "int\nfloat\nint\nstring"
"""
import typetraits, macros
var counter {.compileTime.} = 0
macro makeBar(A, B: typedesc): typedesc =
inc counter
echo "instantiation ", counter, " with ", A.name, " and ", B.name
result = A
type
Bar[T, U] = makeBar(T, U)
var bb1: Bar[int, float]
var bb2: Bar[float, string]
var bb3: Bar[int, float]
var bb4: Bar[string, string]
proc match(a: int) = echo "int"
proc match(a: string) = echo "string"
proc match(a: float) = echo "float"
match(bb1)
match(bb2)
match(bb3)
match(bb4)
static:
echo "counter: ", counter

View File

@@ -1,17 +1,22 @@
discard """
file: "tstaticparams.nim"
output: "abracadabra\ntest"
output: "abracadabra\ntest\n3"
"""
type
TFoo[T; Val: expr[string]] = object
data: array[4, T]
TBar[T; I: expr[int]] = object
data: array[I, T]
proc takeFoo(x: TFoo) =
echo "abracadabra"
echo TFoo.Val
var x: TFoo[int, "test"]
takeFoo(x)
var y: TBar[float, 4]
echo high(y.data)