Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
1d842e8b75
21 changed files with 174 additions and 55 deletions
|
|
@ -624,6 +624,7 @@ type
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
annex*: PLib # additional fields (seldom used, so we use a
|
annex*: PLib # additional fields (seldom used, so we use a
|
||||||
# reference to another object to safe space)
|
# reference to another object to safe space)
|
||||||
|
constraint*: PNode # additional constraints like 'lit|result'
|
||||||
|
|
||||||
TTypeSeq* = seq[PType]
|
TTypeSeq* = seq[PType]
|
||||||
TType* = object of TIdObj # types are identical iff they have the
|
TType* = object of TIdObj # types are identical iff they have the
|
||||||
|
|
@ -650,7 +651,6 @@ type
|
||||||
align*: int # the type's alignment requirements
|
align*: int # the type's alignment requirements
|
||||||
containerID*: int # used for type checking of generics
|
containerID*: int # used for type checking of generics
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
constraint*: PNode # additional constraints like 'lit|result'
|
|
||||||
|
|
||||||
TPair*{.final.} = object
|
TPair*{.final.} = object
|
||||||
key*, val*: PObject
|
key*, val*: PObject
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,9 @@ proc isVisible(n: PNode): bool =
|
||||||
var v = n.sons[0].ident
|
var v = n.sons[0].ident
|
||||||
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
result = v.id == ord(wStar) or v.id == ord(wMinus)
|
||||||
elif n.kind == nkSym:
|
elif n.kind == nkSym:
|
||||||
|
# we cannot generate code for forwarded symbols here as we have no
|
||||||
|
# exception tracking information here. Instead we copy over the comment
|
||||||
|
# from the proc header.
|
||||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||||
elif n.kind == nkPragmaExpr:
|
elif n.kind == nkPragmaExpr:
|
||||||
result = isVisible(n.sons[0])
|
result = isVisible(n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
|
||||||
add(code, chr(ord(op)))
|
add(code, chr(ord(op)))
|
||||||
|
|
||||||
proc whichAlias*(p: PSym): TAliasRequest =
|
proc whichAlias*(p: PSym): TAliasRequest =
|
||||||
if p.typ.constraint != nil:
|
if p.constraint != nil:
|
||||||
result = TAliasRequest(p.typ.constraint.strVal[0].ord)
|
result = TAliasRequest(p.constraint.strVal[0].ord)
|
||||||
|
|
||||||
proc compileConstraints(p: PNode, result: var TPatternCode) =
|
proc compileConstraints(p: PNode, result: var TPatternCode) =
|
||||||
case p.kind
|
case p.kind
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ proc inSymChoice(sc, x: PNode): bool =
|
||||||
|
|
||||||
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||||
# check param constraints first here as this is quite optimized:
|
# check param constraints first here as this is quite optimized:
|
||||||
if p.typ.constraint != nil:
|
if p.constraint != nil:
|
||||||
result = matchNodeKinds(p.typ.constraint, n)
|
result = matchNodeKinds(p.constraint, n)
|
||||||
if not result: return
|
if not result: return
|
||||||
if isNil(n.typ):
|
if isNil(n.typ):
|
||||||
result = p.typ.kind in {tyEmpty, tyStmt}
|
result = p.typ.kind in {tyEmpty, tyStmt}
|
||||||
|
|
|
||||||
|
|
@ -330,9 +330,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||||
if r.s[r.pos] == '@':
|
if r.s[r.pos] == '@':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
result.containerID = decodeVInt(r.s, r.pos)
|
result.containerID = decodeVInt(r.s, r.pos)
|
||||||
if r.s[r.pos] == '`':
|
|
||||||
inc(r.pos)
|
|
||||||
result.constraint = decodeNode(r, UnknownLineInfo())
|
|
||||||
decodeLoc(r, result.loc, info)
|
decodeLoc(r, result.loc, info)
|
||||||
while r.s[r.pos] == '^':
|
while r.s[r.pos] == '^':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
|
|
@ -423,6 +420,9 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||||
result.offset = - 1
|
result.offset = - 1
|
||||||
decodeLoc(r, result.loc, result.info)
|
decodeLoc(r, result.loc, result.info)
|
||||||
result.annex = decodeLib(r, info)
|
result.annex = decodeLib(r, info)
|
||||||
|
if r.s[r.pos] == '#':
|
||||||
|
inc(r.pos)
|
||||||
|
result.constraint = decodeNode(r, UnknownLineInfo())
|
||||||
if r.s[r.pos] == '(':
|
if r.s[r.pos] == '(':
|
||||||
if result.kind in routineKinds:
|
if result.kind in routineKinds:
|
||||||
result.ast = decodeNodeLazyBody(r, result.info, result)
|
result.ast = decodeNodeLazyBody(r, result.info, result)
|
||||||
|
|
|
||||||
|
|
@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||||
if t.containerID != 0:
|
if t.containerID != 0:
|
||||||
add(result, '@')
|
add(result, '@')
|
||||||
encodeVInt(t.containerID, result)
|
encodeVInt(t.containerID, result)
|
||||||
if t.constraint != nil:
|
|
||||||
add(result, '`')
|
|
||||||
encodeNode(w, UnknownLineInfo(), t.constraint, result)
|
|
||||||
encodeLoc(w, t.loc, result)
|
encodeLoc(w, t.loc, result)
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
if t.sons[i] == nil:
|
if t.sons[i] == nil:
|
||||||
|
|
@ -295,6 +292,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
encodeVInt(s.offset, result)
|
encodeVInt(s.offset, result)
|
||||||
encodeLoc(w, s.loc, result)
|
encodeLoc(w, s.loc, result)
|
||||||
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
|
||||||
|
if s.constraint != nil:
|
||||||
|
add(result, '#')
|
||||||
|
encodeNode(w, UnknownLineInfo(), s.constraint, result)
|
||||||
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
# lazy loading will soon reload the ast lazily, so the ast needs to be
|
||||||
# the last entry of a symbol:
|
# the last entry of a symbol:
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||||
args])
|
args])
|
||||||
|
|
||||||
|
proc instantiateGenericConverters(c: PContext, n: PNode, x: TCandidate) {.
|
||||||
|
noinline.}=
|
||||||
|
for i in 1 .. <n.len:
|
||||||
|
var a = n.sons[i]
|
||||||
|
if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
|
||||||
|
isGenericRoutine(a.sons[0].sym):
|
||||||
|
let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, n.info)
|
||||||
|
a.sons[0].sym = finalCallee
|
||||||
|
a.sons[0].typ = finalCallee.typ
|
||||||
|
|
||||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
assert x.state == csMatch
|
assert x.state == csMatch
|
||||||
var finalCallee = x.calleeSym
|
var finalCallee = x.calleeSym
|
||||||
|
|
@ -101,6 +111,8 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||||
return
|
return
|
||||||
result = x.call
|
result = x.call
|
||||||
|
if x.genericConverter:
|
||||||
|
instantiateGenericConverters(c, result, x)
|
||||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||||
result.typ = finalCallee.typ.sons[0]
|
result.typ = finalCallee.typ.sons[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -780,6 +780,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
|
n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
|
||||||
if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
|
if n.sons[namePos].kind != nkSym: InternalError(n.info, "semProcAux")
|
||||||
n.sons[namePos].sym = proto
|
n.sons[namePos].sym = proto
|
||||||
|
if gCmd == cmdDoc and not isNil(proto.ast.comment):
|
||||||
|
n.comment = proto.ast.comment
|
||||||
proto.ast = n # needed for code generation
|
proto.ast = n # needed for code generation
|
||||||
popOwner()
|
popOwner()
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
|
|
@ -869,8 +871,6 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
|
||||||
LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
|
|
||||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
|
|
|
||||||
|
|
@ -635,6 +635,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
genericParams.addSon(newSymNode(s))
|
genericParams.addSon(newSymNode(s))
|
||||||
result = typeClass
|
result = typeClass
|
||||||
|
|
||||||
|
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||||
|
if n.kind == nkCurlyExpr:
|
||||||
|
result = semTypeNode(c, n.sons[0], nil)
|
||||||
|
constraint = semNodeKindConstraints(n)
|
||||||
|
else:
|
||||||
|
result = semTypeNode(c, n, nil)
|
||||||
|
|
||||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
var
|
var
|
||||||
|
|
@ -660,13 +667,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var
|
var
|
||||||
typ: PType = nil
|
typ: PType = nil
|
||||||
def: PNode = nil
|
def: PNode = nil
|
||||||
|
constraint: PNode = nil
|
||||||
length = sonsLen(a)
|
length = sonsLen(a)
|
||||||
hasType = a.sons[length-2].kind != nkEmpty
|
hasType = a.sons[length-2].kind != nkEmpty
|
||||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||||
|
|
||||||
if hasType:
|
if hasType:
|
||||||
typ = semTypeNode(c, a.sons[length-2], nil)
|
typ = semParamType(c, a.sons[length-2], constraint)
|
||||||
|
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1])
|
||||||
|
|
@ -689,6 +697,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
arg.name.s, arg.info).skipIntLit
|
arg.name.s, arg.info).skipIntLit
|
||||||
arg.typ = finalType
|
arg.typ = finalType
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
|
arg.constraint = constraint
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||||
if ContainsOrIncl(check, arg.name.id):
|
if ContainsOrIncl(check, arg.name.id):
|
||||||
|
|
@ -787,6 +796,12 @@ proc semTypeExpr(c: PContext, n: PNode): PType =
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errTypeExpected, n.renderTree)
|
LocalError(n.info, errTypeExpected, n.renderTree)
|
||||||
|
|
||||||
|
proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
|
if prev.isNil:
|
||||||
|
result = copyType(result, result.owner, keepId=false)
|
||||||
|
else:
|
||||||
|
result = res
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -825,7 +840,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkSonsLen(n, 3)
|
checkSonsLen(n, 3)
|
||||||
result = semTypeNode(c, n.sons[1], prev)
|
result = semTypeNode(c, n.sons[1], prev)
|
||||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||||
# XXX this is wrong for tyString at least
|
result = freshType(result, prev)
|
||||||
result.flags.incl(tfNotNil)
|
result.flags.incl(tfNotNil)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errGenerated, "invalid type")
|
LocalError(n.info, errGenerated, "invalid type")
|
||||||
|
|
@ -833,11 +848,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = semTypeExpr(c, n)
|
result = semTypeExpr(c, n)
|
||||||
else:
|
else:
|
||||||
result = semTypeExpr(c, n)
|
result = semTypeExpr(c, n)
|
||||||
of nkCurlyExpr:
|
|
||||||
result = semTypeNode(c, n.sons[0], nil)
|
|
||||||
if result != nil:
|
|
||||||
result = copyType(result, getCurrOwner(), true)
|
|
||||||
result.constraint = semNodeKindConstraints(n)
|
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
var whenResult = semWhen(c, n, false)
|
var whenResult = semWhen(c, n, false)
|
||||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||||
|
|
@ -920,6 +930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkSharedTy:
|
of nkSharedTy:
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
result = semTypeNode(c, n.sons[0], prev)
|
result = semTypeNode(c, n.sons[0], prev)
|
||||||
|
result = freshType(result, prev)
|
||||||
result.flags.incl(tfShared)
|
result.flags.incl(tfShared)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errTypeExpected)
|
LocalError(n.info, errTypeExpected)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ type
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
proxyMatch*: bool # to prevent instantiations
|
proxyMatch*: bool # to prevent instantiations
|
||||||
|
genericConverter*: bool # true if a generic converter needs to
|
||||||
|
# be instantiated
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.callee = callee
|
c.callee = callee
|
||||||
c.call = nil
|
c.call = nil
|
||||||
c.baseTypeMatch = false
|
c.baseTypeMatch = false
|
||||||
|
c.genericConverter = false
|
||||||
c.inheritancePenalty = 0
|
c.inheritancePenalty = 0
|
||||||
|
|
||||||
proc initCandidate*(c: var TCandidate, callee: PType) =
|
proc initCandidate*(c: var TCandidate, callee: PType) =
|
||||||
|
|
@ -571,16 +574,26 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
for i in countup(0, len(c.converters) - 1):
|
for i in countup(0, len(c.converters) - 1):
|
||||||
var src = c.converters[i].typ.sons[1]
|
var src = c.converters[i].typ.sons[1]
|
||||||
var dest = c.converters[i].typ.sons[0]
|
var dest = c.converters[i].typ.sons[0]
|
||||||
if (typeRel(m, f, dest) == isEqual) and
|
# for generic type converters we need to check 'src <- a' before
|
||||||
(typeRel(m, src, a) == isEqual):
|
# 'f <- dest' in order to not break the unification:
|
||||||
|
# see tests/tgenericconverter:
|
||||||
|
let srca = typeRel(m, src, a)
|
||||||
|
if srca notin {isEqual, isGeneric}: continue
|
||||||
|
|
||||||
|
let destIsGeneric = containsGenericType(dest)
|
||||||
|
if destIsGeneric:
|
||||||
|
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||||
|
let fdest = typeRel(m, f, dest)
|
||||||
|
if fdest in {isEqual, isGeneric}:
|
||||||
markUsed(arg, c.converters[i])
|
markUsed(arg, c.converters[i])
|
||||||
var s = newSymNode(c.converters[i])
|
var s = newSymNode(c.converters[i])
|
||||||
s.typ = c.converters[i].typ
|
s.typ = c.converters[i].typ
|
||||||
s.info = arg.info
|
s.info = arg.info
|
||||||
result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0])
|
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
|
||||||
addSon(result, s)
|
addSon(result, s)
|
||||||
addSon(result, copyTree(arg))
|
addSon(result, copyTree(arg))
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
|
m.genericConverter = srca == isGeneric or destIsGeneric
|
||||||
return
|
return
|
||||||
|
|
||||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
|
|
@ -837,10 +850,10 @@ proc matchesAux*(c: PContext, n, nOrig: PNode,
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||||
n.sons[a], nOrig.sons[a])
|
n.sons[a], nOrig.sons[a])
|
||||||
if arg == nil:
|
if arg == nil:
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
if m.baseTypeMatch:
|
if m.baseTypeMatch:
|
||||||
assert(container == nil)
|
assert(container == nil)
|
||||||
container = newNodeI(nkBracket, n.sons[a].info)
|
container = newNodeI(nkBracket, n.sons[a].info)
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ path="$lib/windows"
|
||||||
path="$lib/posix"
|
path="$lib/posix"
|
||||||
path="$lib/ecmas"
|
path="$lib/ecmas"
|
||||||
path="$lib/pure/unidecode"
|
path="$lib/pure/unidecode"
|
||||||
#recursivePath:"$home/.babel/lib"
|
path="$home/.babel/libs/"
|
||||||
|
|
||||||
@if release or quick:
|
@if release or quick:
|
||||||
obj_checks:off
|
obj_checks:off
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,7 @@
|
||||||
## module will therefore not work with any Linux kernel prior to that, unless
|
## module will therefore not work with any Linux kernel prior to that, unless
|
||||||
## it has been patched to support inotify.
|
## it has been patched to support inotify.
|
||||||
|
|
||||||
when defined(windows):
|
when defined(linux) or defined(nimdoc):
|
||||||
{.error: "Windows is not yet supported by this module.".}
|
|
||||||
elif defined(linux):
|
|
||||||
from posix import read
|
from posix import read
|
||||||
else:
|
else:
|
||||||
{.error: "Your platform is not supported.".}
|
{.error: "Your platform is not supported.".}
|
||||||
|
|
|
||||||
|
|
@ -238,8 +238,15 @@ type
|
||||||
httpCONNECT ## Converts the request connection to a transparent
|
httpCONNECT ## Converts the request connection to a transparent
|
||||||
## TCP/IP tunnel, usually used for proxies.
|
## TCP/IP tunnel, usually used for proxies.
|
||||||
|
|
||||||
|
when not defined(ssl):
|
||||||
|
type PSSLContext = ref object
|
||||||
|
let defaultSSLContext: PSSLContext = nil
|
||||||
|
else:
|
||||||
|
let defaultSSLContext = newContext(verifyMode = CVerifyNone)
|
||||||
|
|
||||||
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
body = ""): TResponse =
|
body = "",
|
||||||
|
sslContext: PSSLContext = defaultSSLContext): TResponse =
|
||||||
## | Requests ``url`` with the specified ``httpMethod``.
|
## | Requests ``url`` with the specified ``httpMethod``.
|
||||||
## | Extra headers can be specified and must be seperated by ``\c\L``
|
## | Extra headers can be specified and must be seperated by ``\c\L``
|
||||||
var r = parseUrl(url)
|
var r = parseUrl(url)
|
||||||
|
|
@ -257,7 +264,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
|
||||||
var port = TPort(80)
|
var port = TPort(80)
|
||||||
if r.scheme == "https":
|
if r.scheme == "https":
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
s.wrapSocket(verifyMode = CVerifyNone)
|
sslContext.wrapSocket(s)
|
||||||
else:
|
else:
|
||||||
raise newException(EHttpRequestErr, "SSL support was not compiled in. Cannot connect over SSL.")
|
raise newException(EHttpRequestErr, "SSL support was not compiled in. Cannot connect over SSL.")
|
||||||
port = TPort(443)
|
port = TPort(443)
|
||||||
|
|
@ -277,7 +284,7 @@ proc redirection(status: string): bool =
|
||||||
if status.startsWith(i):
|
if status.startsWith(i):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
proc get*(url: string, maxRedirects = 5): TResponse =
|
proc get*(url: string, maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse =
|
||||||
## | GET's the ``url`` and returns a ``TResponse`` object
|
## | GET's the ``url`` and returns a ``TResponse`` object
|
||||||
## | This proc also handles redirection
|
## | This proc also handles redirection
|
||||||
result = request(url)
|
result = request(url)
|
||||||
|
|
@ -285,24 +292,24 @@ proc get*(url: string, maxRedirects = 5): TResponse =
|
||||||
if result.status.redirection():
|
if result.status.redirection():
|
||||||
var locationHeader = result.headers["Location"]
|
var locationHeader = result.headers["Location"]
|
||||||
if locationHeader == "": httpError("location header expected")
|
if locationHeader == "": httpError("location header expected")
|
||||||
result = request(locationHeader)
|
result = request(locationHeader, sslContext = sslContext)
|
||||||
|
|
||||||
proc getContent*(url: string): string =
|
proc getContent*(url: string, sslContext: PSSLContext = defaultSSLContext): string =
|
||||||
## | GET's the body and returns it as a string.
|
## | GET's the body and returns it as a string.
|
||||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||||
var r = get(url)
|
var r = get(url, sslContext = sslContext)
|
||||||
if r.status[0] in {'4','5'}:
|
if r.status[0] in {'4','5'}:
|
||||||
raise newException(EHTTPRequestErr, r.status)
|
raise newException(EHTTPRequestErr, r.status)
|
||||||
else:
|
else:
|
||||||
return r.body
|
return r.body
|
||||||
|
|
||||||
proc post*(url: string, extraHeaders = "", body = "",
|
proc post*(url: string, extraHeaders = "", body = "",
|
||||||
maxRedirects = 5): TResponse =
|
maxRedirects = 5, sslContext: PSSLContext = defaultSSLContext): TResponse =
|
||||||
## | POST's ``body`` to the ``url`` and returns a ``TResponse`` object.
|
## | POST's ``body`` to the ``url`` and returns a ``TResponse`` object.
|
||||||
## | This proc adds the necessary Content-Length header.
|
## | This proc adds the necessary Content-Length header.
|
||||||
## | This proc also handles redirection.
|
## | This proc also handles redirection.
|
||||||
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
|
var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
|
||||||
result = request(url, httpPOST, xh, body)
|
result = request(url, httpPOST, xh, body, sslContext)
|
||||||
for i in 1..maxRedirects:
|
for i in 1..maxRedirects:
|
||||||
if result.status.redirection():
|
if result.status.redirection():
|
||||||
var locationHeader = result.headers["Location"]
|
var locationHeader = result.headers["Location"]
|
||||||
|
|
@ -310,7 +317,8 @@ proc post*(url: string, extraHeaders = "", body = "",
|
||||||
var meth = if result.status != "307": httpGet else: httpPost
|
var meth = if result.status != "307": httpGet else: httpPost
|
||||||
result = request(locationHeader, meth, xh, body)
|
result = request(locationHeader, meth, xh, body)
|
||||||
|
|
||||||
proc postContent*(url: string, extraHeaders = "", body = ""): string =
|
proc postContent*(url: string, extraHeaders = "", body = "",
|
||||||
|
sslContext: PSSLContext = defaultSSLContext): string =
|
||||||
## | POST's ``body`` to ``url`` and returns the response's body as a string
|
## | POST's ``body`` to ``url`` and returns the response's body as a string
|
||||||
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
## | Raises exceptions for the status codes ``4xx`` and ``5xx``
|
||||||
var r = post(url, extraHeaders, body)
|
var r = post(url, extraHeaders, body)
|
||||||
|
|
@ -319,11 +327,12 @@ proc postContent*(url: string, extraHeaders = "", body = ""): string =
|
||||||
else:
|
else:
|
||||||
return r.body
|
return r.body
|
||||||
|
|
||||||
proc downloadFile*(url: string, outputFilename: string) =
|
proc downloadFile*(url: string, outputFilename: string,
|
||||||
|
sslContext: PSSLContext = defaultSSLContext) =
|
||||||
## Downloads ``url`` and saves it to ``outputFilename``
|
## Downloads ``url`` and saves it to ``outputFilename``
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if open(f, outputFilename, fmWrite):
|
if open(f, outputFilename, fmWrite):
|
||||||
f.write(getContent(url))
|
f.write(getContent(url, sslContext))
|
||||||
f.close()
|
f.close()
|
||||||
else:
|
else:
|
||||||
fileError("Unable to open file")
|
fileError("Unable to open file")
|
||||||
|
|
|
||||||
|
|
@ -554,7 +554,8 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.
|
||||||
var dotPos = path.len
|
var dotPos = path.len
|
||||||
for i in countdown(len(path)-1, 0):
|
for i in countdown(len(path)-1, 0):
|
||||||
if path[i] == ExtSep:
|
if path[i] == ExtSep:
|
||||||
if dotPos == path.len and i > 0: dotPos = i
|
if dotPos == path.len and i > 0 and
|
||||||
|
path[i-1] notin {dirsep, altsep}: dotPos = i
|
||||||
elif path[i] in {dirsep, altsep}:
|
elif path[i] in {dirsep, altsep}:
|
||||||
sepPos = i
|
sepPos = i
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
## For OpenSSL support compile with ``-d:ssl``. When using SSL be aware that
|
## For OpenSSL support compile with ``-d:ssl``. When using SSL be aware that
|
||||||
## most functions will then raise ``ESSL`` on SSL errors.
|
## most functions will then raise ``ESSL`` on SSL errors.
|
||||||
|
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
when hostos == "solaris":
|
when hostos == "solaris":
|
||||||
{.passl: "-lsocket -lnsl".}
|
{.passl: "-lsocket -lnsl".}
|
||||||
|
|
||||||
|
|
@ -256,7 +258,10 @@ when defined(ssl):
|
||||||
of protSSLv23:
|
of protSSLv23:
|
||||||
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
|
newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
|
||||||
of protSSLv2:
|
of protSSLv2:
|
||||||
newCTX = SSL_CTX_new(SSLv2_method())
|
when not defined(linux):
|
||||||
|
newCTX = SSL_CTX_new(SSLv2_method())
|
||||||
|
else:
|
||||||
|
SSLError()
|
||||||
of protSSLv3:
|
of protSSLv3:
|
||||||
newCTX = SSL_CTX_new(SSLv3_method())
|
newCTX = SSL_CTX_new(SSLv3_method())
|
||||||
of protTLSv1:
|
of protTLSv1:
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@
|
||||||
|
|
||||||
## OpenSSL support
|
## OpenSSL support
|
||||||
|
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
when defined(WINDOWS):
|
when defined(WINDOWS):
|
||||||
const
|
const
|
||||||
DLLSSLName = "(ssleay32|libssl32).dll"
|
DLLSSLName = "(ssleay32|libssl32).dll"
|
||||||
|
|
|
||||||
28
tests/compile/tsecondarrayproperty.nim
Normal file
28
tests/compile/tsecondarrayproperty.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo = object
|
||||||
|
data: array[0..100, int]
|
||||||
|
TSecond = distinct TFoo
|
||||||
|
|
||||||
|
proc `[]` (self: var TFoo, x: int): var int =
|
||||||
|
return self.data[x]
|
||||||
|
|
||||||
|
proc `[]=` (self: var TFoo, x, y: int) =
|
||||||
|
# only `[]` returning a 'var T' seems to not work for now :-/
|
||||||
|
self.data[x] = y
|
||||||
|
|
||||||
|
proc second(self: var TFoo): var TSecond =
|
||||||
|
return TSecond(self)
|
||||||
|
|
||||||
|
proc `[]`(self: var TSecond, x: int): var int =
|
||||||
|
return TFoo(self).data[2*x]
|
||||||
|
|
||||||
|
var f: TFoo
|
||||||
|
|
||||||
|
for i in 0..f.data.high: f[i] = 2 * i
|
||||||
|
|
||||||
|
echo f.second[1]
|
||||||
|
|
||||||
|
#echo `second[]`(f,1)
|
||||||
|
# this is the only way I could use it, but not what I expected
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
line: 11
|
line: 22
|
||||||
errormgs: "type mismatch"
|
errormgs: "type mismatch"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -7,9 +7,17 @@ type
|
||||||
PObj = ref TObj not nil
|
PObj = ref TObj not nil
|
||||||
TObj = object
|
TObj = object
|
||||||
x: int
|
x: int
|
||||||
|
|
||||||
|
MyString = string not nil
|
||||||
|
|
||||||
var x: PObj = nil
|
#var x: PObj = nil
|
||||||
|
|
||||||
proc p(x: string not nil): int =
|
proc p(x: string not nil): int =
|
||||||
result = 45
|
result = 45
|
||||||
|
|
||||||
|
proc q(x: MyString) = nil
|
||||||
|
proc q2(x: string) = nil
|
||||||
|
|
||||||
|
q2(nil)
|
||||||
|
q(nil)
|
||||||
|
|
||||||
|
|
|
||||||
30
tests/run/tgenericconverter.nim
Normal file
30
tests/run/tgenericconverter.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
output: '''666
|
||||||
|
666'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# test the new generic converters:
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo2[T] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
TFoo[T] = object
|
||||||
|
data: array[0..100, T]
|
||||||
|
|
||||||
|
converter toFoo[T](a: TFoo2[T]): TFoo[T] =
|
||||||
|
result.data[0] = a.x
|
||||||
|
|
||||||
|
proc p(a: TFoo[int]) =
|
||||||
|
echo a.data[0]
|
||||||
|
|
||||||
|
proc q[T](a: TFoo[T]) =
|
||||||
|
echo a.data[0]
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
aa: TFoo2[int]
|
||||||
|
aa.x = 666
|
||||||
|
|
||||||
|
p aa
|
||||||
|
q aa
|
||||||
16
todo.txt
16
todo.txt
|
|
@ -1,20 +1,18 @@
|
||||||
version 0.9.2
|
version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- fix tfShared and tfNotNil
|
- overloading based on ASTs
|
||||||
- test&finish first class iterators:
|
|
||||||
* nested iterators
|
|
||||||
* test generic iterators
|
|
||||||
|
|
||||||
- fix closure bug finally
|
|
||||||
- overloading based on ASTs: 'constraint' should not be in PType but for the
|
|
||||||
parameter *symbol*
|
|
||||||
|
|
||||||
- implement ``partial`` pragma for partial evaluation: easily done with AST
|
- implement ``partial`` pragma for partial evaluation: easily done with AST
|
||||||
overloading
|
overloading
|
||||||
- ``hoist`` pragma for loop hoisting: can be easily done with
|
- ``hoist`` pragma for loop hoisting: can be easily done with
|
||||||
AST overloading + global
|
AST overloading + global
|
||||||
|
|
||||||
|
- test&finish first class iterators:
|
||||||
|
* nested iterators
|
||||||
|
* test generic iterators
|
||||||
|
- fix closure bug finally
|
||||||
|
- fix marshal bug
|
||||||
|
|
||||||
|
|
||||||
version 0.9.X
|
version 0.9.X
|
||||||
=============
|
=============
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ Compiler Additions
|
||||||
- The compiler can now warn about shadowed local variables. However, this needs
|
- The compiler can now warn about shadowed local variables. However, this needs
|
||||||
to be turned on explicitly via ``--warning[ShadowIdent]:on``.
|
to be turned on explicitly via ``--warning[ShadowIdent]:on``.
|
||||||
- The compiler now supports almost every pragma in a ``push`` pragma.
|
- The compiler now supports almost every pragma in a ``push`` pragma.
|
||||||
|
- Generic converters have been implemented.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue