Merge remote-tracking branch 'upstream/devel' into devel

This commit is contained in:
Konstantin Zaitsev
2016-03-03 17:47:36 +06:00
61 changed files with 592 additions and 456 deletions

View File

@@ -298,6 +298,7 @@ const
sfWrittenTo* = sfBorrow # param is assigned to
sfEscapes* = sfProcvar # param escapes
sfBase* = sfDiscriminant
sfIsSelf* = sfOverriden # param is 'self'
const
# getting ready for the future expr/stmt merge
@@ -458,11 +459,11 @@ type
tfByCopy, # pass object/tuple by copy (C backend)
tfByRef, # pass object/tuple by reference (C backend)
tfIterator, # type is really an iterator, not a tyProc
tfShared, # type is 'shared'
tfPartial, # type is declared as 'partial'
tfNotNil, # type cannot be 'nil'
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires initalization
# other type so that it requires initialization
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
tfHasMeta, # type contains "wildcard" sub-types such as generic params
# or other type classes
@@ -533,7 +534,7 @@ const
skError* = skUnknown
# type flags that are essential for type equality:
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr}
type
TMagic* = enum # symbols that require compiler magic:
@@ -753,7 +754,6 @@ type
TScope* = object
depthLevel*: int
symbols*: TStrTable
usingSyms*: seq[PNode]
parent*: PScope
PScope* = ref TScope

View File

@@ -448,20 +448,20 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
proc debug(n: PSym) =
if n == nil:
msgWriteln("null")
echo("null")
elif n.kind == skUnknown:
msgWriteln("skUnknown")
echo("skUnknown")
else:
#writeLine(stdout, $symToYaml(n, 0, 1))
msgWriteln("$1_$2: $3, $4, $5, $6" % [
echo("$1_$2: $3, $4, $5, $6" % [
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
$lineInfoToStr(n.info), $n.kind])
proc debug(n: PType) =
msgWriteln($debugType(n))
echo($debugType(n))
proc debug(n: PNode) =
msgWriteln($debugTree(n, 0, 100))
echo($debugTree(n, 0, 100))
const
EmptySeq = @[]
@@ -635,7 +635,7 @@ proc reallySameIdent(a, b: string): bool {.inline.} =
else:
result = true
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
# returns true if n is already in the string table:
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
@@ -654,7 +654,8 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
replaceSlot = h
h = nextTry(h, high(t.data))
if replaceSlot >= 0:
t.data[replaceSlot] = n # overwrite it with newer definition!
if not onConflictKeepOld:
t.data[replaceSlot] = n # overwrite it with newer definition!
return true # found it
elif mustRehash(len(t.data), t.counter):
strTableEnlarge(t)

View File

@@ -158,7 +158,6 @@ proc hashType(c: var MD5Context, t: PType) =
if tfThread in t.flags: c &= ".thread"
else:
for i in 0.. <t.len: c.hashType(t.sons[i])
if tfShared in t.flags: c &= "shared"
if tfNotNil in t.flags: c &= "not nil"
proc canonConst(n: PNode): TUid =
@@ -276,7 +275,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# for the new rodfile viewer we use a preceding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result)

View File

@@ -928,8 +928,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)",
let isObjFormat = if not p.module.compileToCpp:
"#isObj(#getCurrentException()->Sup.m_type, $1)"
else: "#isObj(#getCurrentException()->m_type, $1)"
appcg(p.module, orExpr, isObjFormat,
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
if i > 1: line(p, cpsStmts, "else ")
startBlock(p, "if ($1) {$n", [orExpr])

View File

@@ -192,8 +192,9 @@ proc mangleName(s: PSym; target: TTarget): Rope =
x.add("HEX" & toHex(ord(c), 2))
inc i
result = rope(x)
add(result, "_")
add(result, rope(s.id))
if s.name.s != "this" and s.kind != skField:
add(result, "_")
add(result, rope(s.id))
s.loc.r = result
proc escapeJSString(s: string): string =
@@ -890,10 +891,12 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
r.res = "$1['$2']" % [r.res, f.loc.r]
r.kind = resExpr
proc genAddr(p: PProc, n: PNode, r: var TCompRes)
proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
internalAssert m.kind == nkCheckedFieldExpr
genFieldAddr(p, m.sons[0], r) # XXX
genAddr(p, m, r) # XXX
proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
genFieldAccess(p, n.sons[0], r) # XXX
@@ -2089,7 +2092,8 @@ proc getClassName(t: PType): Rope =
s = skipTypes(t, abstractPtrs).sym
if s.isNil or sfAnon in s.flags:
internalError("cannot retrieve class name")
result = mangleName(s, targetPHP)
if s.loc.r != nil: result = s.loc.r
else: result = rope(s.name.s)
proc genClass(obj: PType; content: Rope; ext: string) =
let cls = getClassName(obj)
@@ -2100,6 +2104,7 @@ proc genClass(obj: PType; content: Rope; ext: string) =
let result = ("<?php$n" &
"/* Generated by the Nim Compiler v$# */$n" &
"/* (c) 2016 Andreas Rumpf */$n$n" &
"require_once \"nimsystem.php\";$n" &
"class $#$# {$n$#$n}$n") %
[rope(VersionAsString), cls, extends, content]
@@ -2112,13 +2117,15 @@ proc myClose(b: PPassContext, n: PNode): PNode =
var m = BModule(b)
if sfMainModule in m.module.flags:
let ext = if m.target == targetJS: "js" else: "php"
let f = if globals.classes.len == 0: m.module.filename
else: "nimsystem"
let code = wholeCode(m)
let outfile =
if options.outFile.len > 0:
if options.outFile.isAbsolute: options.outFile
else: getCurrentDir() / options.outFile
else:
changeFileExt(completeCFilePath(m.module.filename), ext)
changeFileExt(completeCFilePath(f), ext)
discard writeRopeIfNotEqual(genHeader(m.target) & code, outfile)
for obj, content in items(globals.classes):
genClass(obj, content, ext)

View File

@@ -44,7 +44,8 @@ type
tkLet,
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
tkObject, tkOf, tkOr, tkOut,
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
tkProc, tkPtr, tkRaise, tkRef, tkReturn,
tkShl, tkShr, tkStatic,
tkTemplate,
tkTry, tkTuple, tkType, tkUsing,
tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,

View File

@@ -804,20 +804,24 @@ proc parsePragma(p: var TParser): PNode =
else: parMessage(p, errTokenExpected, ".}")
dec p.inPragma
proc identVis(p: var TParser): PNode =
proc identVis(p: var TParser; allowDot=false): PNode =
#| identVis = symbol opr? # postfix position
#| identVisDot = symbol '.' optInd symbol opr?
var a = parseSymbol(p)
if p.tok.tokType == tkOpr:
result = newNodeP(nkPostfix, p)
addSon(result, newIdentNodeP(p.tok.ident, p))
addSon(result, a)
getTok(p)
elif p.tok.tokType == tkDot and allowDot:
result = dotExpr(p, a)
else:
result = a
proc identWithPragma(p: var TParser): PNode =
proc identWithPragma(p: var TParser; allowDot=false): PNode =
#| identWithPragma = identVis pragma?
var a = identVis(p)
#| identWithPragmaDot = identVisDot pragma?
var a = identVis(p, allowDot)
if p.tok.tokType == tkCurlyDotLe:
result = newNodeP(nkPragmaExpr, p)
addSon(result, a)
@@ -1803,10 +1807,11 @@ proc parseTypeClass(p: var TParser): PNode =
addSon(result, parseStmt(p))
proc parseTypeDef(p: var TParser): PNode =
#| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
#|
#| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
#| indAndComment?
result = newNodeP(nkTypeDef, p)
addSon(result, identWithPragma(p))
addSon(result, identWithPragma(p, allowDot=true))
if p.tok.tokType == tkBracketLe and p.validInd:
addSon(result, parseGenericParamList(p))
else:
@@ -1903,7 +1908,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
#| | 'converter' routine
#| | 'type' section(typeDef)
#| | 'const' section(constant)
#| | ('let' | 'var') section(variable)
#| | ('let' | 'var' | 'using') section(variable)
#| | bindStmt | mixinStmt)
#| / simpleStmt
case p.tok.tokType
@@ -1940,7 +1945,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p, nkBindStmt)
of tkMixin: result = parseBind(p, nkMixinStmt)
of tkUsing: result = parseBind(p, nkUsingStmt)
of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable)
else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode =

View File

@@ -46,7 +46,7 @@ const
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt, wDeprecated, wExperimental}
wInjectStmt, wDeprecated, wExperimental, wThis}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
@@ -55,7 +55,7 @@ const
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wExportNims}
wBorrow, wGcSafe, wExportNims, wPartial}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wGuard, wBitsize}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
@@ -835,6 +835,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy)
of wPartial:
noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else:
incl(sym.typ.flags, tfPartial)
# .partial types can only work with dead code elimination
# to prevent the codegen from doing anything before we compiled
# the whole program:
incl gGlobalOptions, optDeadCodeElim
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
@@ -875,6 +884,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
c.module.flags.incl sfExperimental
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
of wThis:
if it.kind == nkExprColonExpr:
c.selfName = considerQuotedIdent(it[1])
else:
c.selfName = getIdent("self")
of wNoRewrite:
noVal(it)
of wBase:

View File

@@ -463,6 +463,9 @@ proc lsub(n: PNode): int =
of nkVarSection, nkLetSection:
if sonsLen(n) > 1: result = MaxLineLen + 1
else: result = lsons(n) + len("var_")
of nkUsingStmt:
if sonsLen(n) > 1: result = MaxLineLen + 1
else: result = lsons(n) + len("using_")
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_")
@@ -1173,11 +1176,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
initContext(a)
incl(a.flags, rfInConstExpr)
gsection(g, n, a, tkConst, "const")
of nkVarSection, nkLetSection:
of nkVarSection, nkLetSection, nkUsingStmt:
var L = sonsLen(n)
if L == 0: return
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
else: putWithSpace(g, tkLet, "let")
elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let")
else: putWithSpace(g, tkUsing, "using")
if L > 1:
gcoms(g)
indentNL(g)

View File

@@ -191,7 +191,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
# identifier with visability
# identifier with visibility
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode

View File

@@ -50,7 +50,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
var syms: seq[tuple[a: PSym, b: int]] = @[]
while symx != nil:
if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
if symx.kind in filter:
syms.add((symx, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol)
if syms.len == 0: return
@@ -63,7 +64,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
let sym = syms[i][0]
determineType(c, sym)
initCandidate(c, z, sym, initialBinding, syms[i][1])
z.calleeSym = sym
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# gDebug = true
@@ -138,11 +138,6 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
else:
localError(n.info, errGenerated, result)
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
for scope in walkScopes(c.currentScope):
if scope.usingSyms != nil:
for s in scope.usingSyms: usedSyms.safeAdd(s)
proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds;
errors: var CandidateErrors): TCandidate =
@@ -156,31 +151,30 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else:
initialBinding = nil
var usedSyms: seq[PNode]
template pickBest(headSymbol: expr) =
template pickBest(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors)
gatherUsedSyms(c, usedSyms)
if usedSyms != nil:
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
else: usedSyms[0]
n.sons.insert(hiddenArg, 1)
orig.sons.insert(hiddenArg, 1)
pickBest(f)
if result.state != csMatch:
n.sons.delete(1)
orig.sons.delete(1)
else: return
pickBest(f)
let overloadsState = result.state
if overloadsState != csMatch:
if c.p != nil and c.p.selfSym != nil:
# we need to enforce semchecking of selfSym again because it
# might need auto-deref:
var hiddenArg = newSymNode(c.p.selfSym)
hiddenArg.typ = nil
n.sons.insert(hiddenArg, 1)
orig.sons.insert(hiddenArg, 1)
pickBest(f)
if result.state != csMatch:
n.sons.delete(1)
orig.sons.delete(1)
else: return
if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)

View File

@@ -30,6 +30,7 @@ type
# statements
owner*: PSym # the symbol this context belongs to
resultSym*: PSym # the result symbol (if we are in a proc)
selfSym*: PSym # the 'self' symbol (if available)
nestedLoopCounter*: int # whether we are in a loop or not
nestedBlockCounter*: int # whether we are in a block or not
inTryStmt*: int # whether we are in a try statement; works also
@@ -103,7 +104,8 @@ type
inParallelStmt*: int
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.nimcall.}
selfName*: PIdent
signatures*: TStrTable
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s
@@ -154,16 +156,6 @@ proc popOwner() =
proc lastOptionEntry(c: PContext): POptionEntry =
result = POptionEntry(c.optionStack.tail)
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
if owner == nil:
internalError("owner is nil")
return
var x: PProcCon
new(x)
x.owner = owner
x.next = c.p
c.p = x
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
proc newOptionEntry(): POptionEntry =
@@ -187,6 +179,8 @@ proc newContext(module: PSym): PContext =
initStrTable(result.userPragmas)
result.generics = @[]
result.unknownIdents = initIntSet()
initStrTable(result.signatures)
proc inclSym(sq: var TSymSeq, s: PSym) =
var L = len(sq)

View File

@@ -77,88 +77,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result.typ = s.typ
result.info = n.info
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind
of skConst:
markUsed(n.info, s)
styleCheckUse(n.info, s)
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64:
if s.magic == mNone: result = inlineConst(n, s)
else: result = newSymNode(s, n.info)
of tyArrayConstr, tySequence:
# Consider::
# const x = []
# proc p(a: openarray[int])
# proc q(a: openarray[char])
# p(x)
# q(x)
#
# It is clear that ``[]`` means two totally different things. Thus, we
# copy `x`'s AST into each context, so that the type fixup phase can
# deal with two different ``[]``.
if s.ast.len == 0: result = inlineConst(n, s)
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
of skParam:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ...
return s.typ.n
elif sfGenSym in s.flags:
if c.p.wasForwarded:
# gensym'ed parameters that nevertheless have been forward declared
# need a special fixup:
let realParam = c.p.owner.typ.n[s.position+1]
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
elif c.p.owner.kind == skMacro:
# gensym'ed macro parameters need a similar hack (see bug #1944):
var u = searchInScopes(c, s.name)
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
return newSymNode(u, n.info)
result = newSymNode(s, n.info)
of skVar, skLet, skResult, skForVar:
if s.magic == mNimvm:
localError(n.info, "illegal context for 'nimvm' magic")
markUsed(n.info, s)
styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect)
result = newSymNode(s, n.info)
# We cannot check for access to outer vars for example because it's still
# not sure the symbol really ends up being used:
# var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam:
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic:
result = newSymNode(s, n.info)
result.typ = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:
n.typ = s.typ
return n
of skType:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
else:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
type
TConvStatus = enum
convOK,
@@ -1015,6 +933,116 @@ proc readTypeParameter(c: PContext, typ: PType,
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
#echo "came here: returned nil"
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind
of skConst:
markUsed(n.info, s)
styleCheckUse(n.info, s)
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64:
if s.magic == mNone: result = inlineConst(n, s)
else: result = newSymNode(s, n.info)
of tyArrayConstr, tySequence:
# Consider::
# const x = []
# proc p(a: openarray[int])
# proc q(a: openarray[char])
# p(x)
# q(x)
#
# It is clear that ``[]`` means two totally different things. Thus, we
# copy `x`'s AST into each context, so that the type fixup phase can
# deal with two different ``[]``.
if s.ast.len == 0: result = inlineConst(n, s)
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
of skParam:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ...
return s.typ.n
elif sfGenSym in s.flags:
if c.p.wasForwarded:
# gensym'ed parameters that nevertheless have been forward declared
# need a special fixup:
let realParam = c.p.owner.typ.n[s.position+1]
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
elif c.p.owner.kind == skMacro:
# gensym'ed macro parameters need a similar hack (see bug #1944):
var u = searchInScopes(c, s.name)
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
return newSymNode(u, n.info)
result = newSymNode(s, n.info)
of skVar, skLet, skResult, skForVar:
if s.magic == mNimvm:
localError(n.info, "illegal context for 'nimvm' magic")
markUsed(n.info, s)
styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect)
result = newSymNode(s, n.info)
# We cannot check for access to outer vars for example because it's still
# not sure the symbol really ends up being used:
# var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam:
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic:
result = newSymNode(s, n.info)
result.typ = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:
n.typ = s.typ
return n
of skType:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
of skField:
if c.p != nil and c.p.selfSym != nil:
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
var check: PNode = nil
if ty.kind == tyObject:
while true:
check = nil
let f = lookupInRecordAndBuildCheck(c, n, ty.n, s.name, check)
if f != nil and fieldVisible(c, f):
# is the access to a public field or in the same module or in a friend?
doAssert f == s
markUsed(n.info, f)
styleCheckUse(n.info, f)
result = newNodeIT(nkDotExpr, n.info, f.typ)
result.add makeDeref(newSymNode(c.p.selfSym))
result.add newSymNode(f) # we now have the correct field
if check != nil:
check.sons[0] = result
check.typ = result.typ
result = check
return result
if ty.sons[0] == nil: break
ty = skipTypes(ty.sons[0], {tyGenericInst})
# old code, not sure if it's live code:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
else:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access
checkSonsLen(n, 2)
@@ -1528,24 +1556,6 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
result = newSym(kind, idAnon, owner, info)
result.flags = {sfGenSym}
proc semUsing(c: PContext, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info)
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
for e in n.sons:
let usedSym = semExpr(c, e)
if usedSym.kind == nkSym:
case usedSym.sym.kind
of skLocalVars + {skConst}:
c.currentScope.usingSyms.safeAdd(usedSym)
continue
of skProcKinds:
addDeclAt(c.currentScope, usedSym.sym)
continue
else: discard
localError(e.info, errUsingNoSymbol, e.renderTree)
proc semExpandToAst(c: PContext, n: PNode): PNode =
var macroCall = n[1]
var expandedSym = expectMacroOrTemplateCall(c, macroCall)

View File

@@ -10,6 +10,47 @@
# This module implements the instantiation of generic procs.
# included from sem.nim
proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
template rec(n) = addObjFieldsToLocalScope(c, n)
case n.kind
of nkRecList:
for i in countup(0, len(n)-1):
rec n[i]
of nkRecCase:
if n.len > 0: rec n.sons[0]
for i in countup(1, len(n)-1):
if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i])
of nkSym:
let f = n.sym
if f.kind == skField and fieldVisible(c, f):
c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
incl(f.flags, sfUsed)
# it is not an error to shadow fields via parameters
else: discard
proc rawPushProcCon(c: PContext, owner: PSym) =
var x: PProcCon
new(x)
x.owner = owner
x.next = c.p
c.p = x
proc rawHandleSelf(c: PContext; owner: PSym) =
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
let params = owner.typ.n
if params.len > 1:
let arg = params[1].sym
if arg.name.id == c.selfName.id:
c.p.selfSym = arg
arg.flags.incl sfIsSelf
let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
if t.kind == tyObject:
addObjFieldsToLocalScope(c, t.n)
proc pushProcCon*(c: PContext; owner: PSym) =
rawPushProcCon(c, owner)
rawHandleSelf(c, owner)
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert n.kind == nkGenericParams
for i, a in n.pairs:
@@ -248,7 +289,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
pushProcCon(c, result)
rawPushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for j in 1 .. result.typ.len-1:
entry.concreteTypes[i] = result.typ.sons[j]
@@ -263,6 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# a ``compiles`` context but this is the lesser evil. See
# bug #1055 (tevilcompiles).
#if c.compilesContextId == 0:
rawHandleSelf(c, result)
entry.compilesId = c.compilesContextId
fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry))

View File

@@ -386,6 +386,30 @@ proc isDiscardUnderscore(v: PSym): bool =
v.flags.incl(sfGenSym)
result = true
proc semUsing(c: PContext; n: PNode): PNode =
result = ast.emptyNode
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using")
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
checkMinSonsLen(a, 3)
var length = sonsLen(a)
if a.sons[length-2].kind != nkEmpty:
let typ = semTypeNode(c, a.sons[length-2], nil)
for j in countup(0, length-3):
let v = semIdentDef(c, a.sons[j], skParam)
v.typ = typ
strTableIncl(c.signatures, v)
else:
localError(a.info, "'using' section must have a type")
var def: PNode
if a.sons[length-1].kind != nkEmpty:
localError(a.info, "'using' sections cannot contain assignments")
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
@@ -640,13 +664,20 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
if a.kind == nkCommentStmt: continue
if a.kind != nkTypeDef: illFormedAst(a)
checkSonsLen(a, 3)
var s = semIdentDef(c, a.sons[0], skType)
s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas:
if a.sons[0].kind == nkPragmaExpr:
pragma(c, s, a.sons[0].sons[1], typePragmas)
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
let name = a.sons[0]
var s: PSym
if name.kind == nkDotExpr:
s = qualifiedLookUp(c, name)
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
localError(name.info, "only .partial objects can be extended")
else:
s = semIdentDef(c, name, skType)
s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr:
pragma(c, s, name.sons[1], typePragmas)
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
a.sons[0] = newSymNode(s)
proc typeSectionRightSidePass(c: PContext, n: PNode) =
@@ -655,8 +686,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.sons[0].kind != nkSym): illFormedAst(a)
var s = a.sons[0].sym
let name = a.sons[0]
if (name.kind != nkSym): illFormedAst(a)
var s = name.sym
if s.magic == mNone and a.sons[2].kind == nkEmpty:
localError(a.info, errImplOfXexpected, s.name.s)
if s.magic != mNone: processMagicType(c, s)
@@ -1206,9 +1238,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# Macros and Templates can have generic parameters, but they are
# only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now)
pushProcCon(c, s)
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
pushProcCon(c, s)
c.p.wasForwarded = proto != nil
maybeAddResult(c, s, n)
if sfImportc notin s.flags:
@@ -1217,7 +1250,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c)
else:
if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
@@ -1228,6 +1260,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode
popProcCon(c)
else:
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:

View File

@@ -673,7 +673,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c)
rawAddSon(result, base)
result.n = newNodeI(nkRecList, n.info)
if result.n.isNil:
result.n = newNodeI(nkRecList, n.info)
else:
# partial object so add things to the check
addInheritedFields(c, check, pos, result)
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
if n.sons[0].kind != nkEmpty:
# dummy symbol for `pragma`:
@@ -934,14 +938,18 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
def = fitNode(c, typ, def)
if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected")
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
if tdef == tyAnything:
message(a.info, warnTypelessParam, renderTree(n))
typ = newTypeS(tdef, c)
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
if kind in {skTemplate, skMacro}:
typ = newTypeS(tyExpr, c)
elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
continue
for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c)
if not hasType and not hasDefault and kind notin {skTemplate, skMacro}:
let param = strTableGet(c.signatures, arg.name)
if param != nil: typ = param.typ
else:
localError(a.info, "typeless parameters are obsolete")
typ = errorType(c)
let lifted = liftParamType(c, kind, genericParams, typ,
arg.name.s, arg.info)
let finalType = if lifted != nil: lifted else: typ.skipIntLit
@@ -1307,11 +1315,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev)
of nkBlockType: result = semBlockType(c, n, prev)
of nkSharedTy:
checkSonsLen(n, 1)
result = semTypeNode(c, n.sons[0], prev)
result = freshType(result, prev)
result.flags.incl(tfShared)
else:
localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
@@ -1387,15 +1390,6 @@ proc processMagicType(c: PContext, m: PSym) =
rawAddSon(m.typ, newTypeS(tyNone, c))
of mPNimrodNode:
incl m.typ.flags, tfTriggersCompileTime
of mShared:
setMagicType(m, tyObject, 0)
m.typ.n = newNodeI(nkRecList, m.info)
incl m.typ.flags, tfShared
of mGuarded:
setMagicType(m, tyObject, 0)
m.typ.n = newNodeI(nkRecList, m.info)
incl m.typ.flags, tfShared
rawAddSon(m.typ, sysTypeFromName"shared")
else: localError(m.info, errTypeExpected)
proc semGenericConstraints(c: PContext, x: PType): PType =

View File

@@ -14,22 +14,11 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer
const
tfInstClearedFlags = {tfHasMeta}
proc sharedPtrCheck(info: TLineInfo, t: PType) =
if t.kind == tyPtr and t.len > 1:
if t.sons[0].sym.magic == mShared:
incl(t.flags, tfShared)
#if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
if tfHasGCedMem in t.flags or t.isGCedMem:
localError(info, errGenerated,
"shared memory may not refer to GC'ed thread local memory")
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar:
localError(info, errVarVarTypeNotAllowed)
else:
sharedPtrCheck(info, t)
proc checkConstructedType*(info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct})
@@ -40,8 +29,6 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t))
else:
sharedPtrCheck(info, t)
when false:
if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@@ -216,14 +203,14 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
# symbol is not our business:
if cl.owner != nil and s.owner != cl.owner:
return s
result = PSym(idTableGet(cl.symMap, s))
if result == nil:
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result)
result.owner = s.owner
result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast)
#result = PSym(idTableGet(cl.symMap, s))
#if result == nil:
result = copySym(s, false)
incl(result.flags, sfFromGeneric)
#idTablePut(cl.symMap, s, result)
result.owner = s.owner
result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))

View File

@@ -37,6 +37,7 @@ type
# is this a top-level symbol or a nested proc?
call*: PNode # modified call
bindings*: TIdTable # maps types to types
magic*: TMagic # magic of operation
baseTypeMatch: bool # needed for conversions from T to openarray[T]
# for example
fauxMatch*: TTypeKind # the match was successful only due to the use
@@ -114,6 +115,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
c.calleeScope = 1
else:
c.calleeScope = calleeScope
c.magic = c.calleeSym.magic
initIdTable(c.bindings)
c.errors = nil
if binding != nil and callee.kind in routineKinds:
@@ -1299,11 +1301,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg.typ.n = evaluated
argType = arg.typ
var
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
else: argType
r = typeRel(m, f, a)
var a = argType
var r = typeRel(m, f, a)
if r != isNone and m.calleeSym != nil and
m.calleeSym.kind in {skMacro, skTemplate}:
@@ -1691,7 +1690,7 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
matchesAux(c, n, nOrig, m, marker)
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}:
if m.magic in {mArrGet, mArrPut}:
m.state = csMatch
m.call = n
return

View File

@@ -97,10 +97,7 @@ proc parsePipe(filename: string, inputStream: PLLStream): PNode =
discard llStreamReadLine(s, line)
i = 0
inc linenumber
if line[i] == '#' and line[i+1] in {'?', '!'}:
if line[i+1] == '!':
message(newLineInfo(filename, linenumber, 1),
warnDeprecated, "use '#?' instead; '#!'")
if line[i] == '#' and line[i+1] == '?':
inc(i, 2)
while line[i] in Whitespace: inc(i)
var q: TParser

View File

@@ -12,7 +12,7 @@
#
# * inlines iterators
# * inlines constants
# * performes constant folding
# * performs constant folding
# * converts "continue" to "break"; disambiguates "break"
# * introduces method dispatchers
# * performs lambda lifting for closure support

View File

@@ -412,7 +412,6 @@ const
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
proc addTypeFlags(name: var string, typ: PType) {.inline.} =
if tfShared in typ.flags: name = "shared " & name
if tfNotNil in typ.flags: name.add(" not nil")
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =

View File

@@ -108,8 +108,8 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
# Takes the `b` register and the immediate `imm`, appies the operation `opc`,
# and stores the output value into `a`.
# `imm` is signed and must be within [-127, 128]
if imm >= -127 and imm <= 128:
# `imm` is signed and must be within [-128, 127]
if imm >= -128 and imm <= 127:
let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
(b.uint32 shl 16'u32) or
(imm+byteExcess).uint32 shl 24'u32).TInstr
@@ -121,8 +121,8 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
# Applies `opc` to `bx` and stores it into register `a`
# `bx` must be signed and in the range [-32767, 32768]
if bx >= -32767 and bx <= 32768:
# `bx` must be signed and in the range [-32768, 32767]
if bx >= -32768 and bx <= 32767:
let ins = (opc.uint32 or a.uint32 shl 8'u32 or
(bx+wordExcess).uint32 shl 16'u32).TInstr
c.code.add(ins)

View File

@@ -66,6 +66,7 @@ type
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wAsmNoStackFrame,
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
wPartial,
wAuto, wBool, wCatch, wChar, wClass,
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
@@ -151,7 +152,7 @@ const
"computedgoto", "injectstmt", "experimental",
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
"guard", "locks",
"guard", "locks", "partial",
"auto", "bool", "catch", "char", "class",
"const_cast", "default", "delete", "double",

View File

@@ -67,7 +67,9 @@ ifExpr = 'if' condExpr
whenExpr = 'when' condExpr
pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
identVis = symbol opr? # postfix position
identVisDot = symbol '.' optInd symbol opr?
identWithPragma = identVis pragma?
identWithPragmaDot = identVisDot pragma?
declColonEquals = identWithPragma (comma identWithPragma)* comma?
(':' optInd typeDesc)? ('=' optInd expr)?
identColonEquals = ident (comma ident)* comma?
@@ -171,7 +173,7 @@ object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
typeClassParam = ('var' | 'out')? symbol
typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
&IND{>} stmt
typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
indAndComment?
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
variable = (varTuple / identColonEquals) indAndComment

View File

@@ -547,55 +547,36 @@ Instead of:
Using statement
---------------
**Warning**: The ``using`` statement is highly experimental and has to be
**Warning**: The ``using`` statement is experimental and has to be
explicitly enabled with the `experimental`:idx: pragma or command line option!
The using statement provides syntactic convenience for procs that
heavily use a single contextual parameter. When applied to a variable or a
constant, it will instruct Nim to automatically consider the used symbol as
a hidden leading parameter for any procedure calls, following the using
statement in the current scope. Thus, it behaves much like the hidden `this`
parameter available in some object-oriented programming languages.
The using statement provides syntactic convenience in modules where
the same parameter names and types are used over and over. Instead of:
.. code-block:: nim
proc foo(c: Context; n: Node) = ...
proc bar(c: Context; n: Node, counter: int) = ...
proc baz(c: Context; n: Node) = ...
var s = socket()
using s
connect(host, port)
send(data)
while true:
let line = readLine(timeout)
...
When applied to a callable symbol, it brings the designated symbol in the
current scope. Thus, it can be used to disambiguate between imported symbols
from different modules having the same name.
One can tell the compiler about the convention that a parameter of
name ``c`` should default to type ``Context``, ``n`` should default to
``Node`` etc.:
.. code-block:: nim
import windows, sdl
using sdl.SetTimer
{.experimental.}
using
c: Context
n: Node
counter: int
Note that ``using`` only *adds* to the current context, it doesn't remove or
replace, **neither** does it create a new scope. What this means is that if one
applies this to multiple variables the compiler will find conflicts in what
variable to use:
proc foo(c, n) = ...
proc bar(c, n, counter) = ...
proc baz(c, n) = ...
.. code-block:: nim
var a, b = "kill it"
using a
add(" with fire")
using b
add(" with water")
echo a
echo b
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
is ambiguous)``. To solve this one would need to nest ``using`` with a
``block`` statement so as to control the reach of the ``using`` statement.
The ``using`` section uses the same indentation based grouping syntax as
a ``var`` or ``let``` section.
If expression
-------------

View File

@@ -71,7 +71,12 @@ type
nnkEnumTy,
nnkEnumFieldDef,
nnkArglist, nnkPattern
nnkReturnToken
nnkReturnToken,
nnkClosure,
nnkGotoState,
nnkState,
nnkBreakState
NimNodeKinds* = set[NimNodeKind]
NimTypeKind* = enum
ntyNone, ntyBool, ntyChar, ntyEmpty,

View File

@@ -1,6 +1,6 @@
#
# Nim's Runtime Library
# (c) Copyright 2015 Nim Contributers
# (c) Copyright 2015 Nim Contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -508,7 +508,7 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = int.high): R
## Variants:
##
## - ``proc findAll(...)`` returns a ``seq[string]``
# see pcredemo for explaination
# see pcredemo for explanation
let matchesCrLf = pattern.matchesCrLf()
let unicode = uint32(getinfo[culong](pattern, pcre.INFO_OPTIONS) and
pcre.UTF8) > 0u32

View File

@@ -91,10 +91,25 @@ __clang__
# define NIM_CONST const
#endif
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
# define NIM_THREADVAR __declspec(thread)
#else
/*
NIM_THREADVAR declaration based on
http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably
*/
#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
# define NIM_THREADVAR _Thread_local
#elif defined _WIN32 && ( \
defined _MSC_VER || \
defined __ICL || \
defined __DMC__ || \
defined __BORLANDC__ )
# define NIM_THREADVAR __declspec(thread)
/* note that ICC (linux) and Clang are covered by __GNUC__ */
#elif defined __GNUC__ || \
defined __SUNPRO_C || \
defined __xlC__
# define NIM_THREADVAR __thread
#else
# error "Cannot define NIM_THREADVAR"
#endif
/* --------------- how int64 constants should be declared: ----------- */

View File

@@ -1,50 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## PHP compatibility layer.
type
PhpArray*[Key, Val] = ref object
PhpObj* = ref object ## can be a string, an int etc.
proc explode*(sep, x: string): seq[string] {.importc: "explode".}
template split*(x, sep: string): seq[string] = explode(sep, x)
proc `$`*(x: PhpObj): string {.importcpp: "(#)".}
proc `++`*(x: PhpObj) {.importcpp: "++(#)".}
proc `==`*(x, y: PhpObj): string {.importcpp: "((#) == (#))".}
proc `<=`*(x, y: PhpObj): string {.importcpp: "((#) <= (#))".}
proc `<`*(x, y: PhpObj): string {.importcpp: "((#) < (#))".}
proc toUpper*(x: string): string {.importc: "strtoupper".}
proc toLower*(x: string): string {.importc: "strtolower".}
proc strtr*(s: string, replacePairs: PhpArray[string, string]): string {.importc.}
proc strtr*(s, fromm, to: string): string {.importc.}
proc toArray*[K,V](pairs: openarray[(K,V)]): PhpArray[K,V] {.magic:
"Array".}
template strtr*(s: string, replacePairs: openarray[(string, string)]): string =
strtr(toArray(replacePairs))
iterator pairs*[K,V](d: PhpArray[K,V]): (K,V) =
var k: K
var v: V
{.emit: "foreach (`d` as `k`=>`v`) {".}
yield (k, v)
{.emit: "}".}
proc `[]`*[K,V](d: PhpArray[K,V]; k: K): V {.importcpp: "#[#]".}
proc `[]=`*[K,V](d: PhpArray[K,V]; k: K; v: V) {.importcpp: "#[#] = #".}
proc ksort*[K,V](d: PhpArray[K,V]) {.importc.}
proc krsort*[K,V](d: PhpArray[K,V]) {.importc.}
proc keys*[K,V](d: PhpArray[K,V]): seq[K] {.importc.}

View File

@@ -163,7 +163,11 @@ proc `[]`*[A](s: var HashSet[A], key: A): var A =
var hc: Hash
var index = rawGet(s, key, hc)
if index >= 0: result = s.data[index].key
else: raise newException(KeyError, "key not found: " & $key)
else:
when compiles($key):
raise newException(KeyError, "key not found: " & $key)
else:
raise newException(KeyError, "key not found")
proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} =
## returns the element that is actually stored in 's' which has the same

View File

@@ -51,7 +51,10 @@
## ]
import
hashes, strutils, lexbase, streams, unicode, macros
hashes, tables, strutils, lexbase, streams, unicode, macros
export
tables.`$`
type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
@@ -567,7 +570,7 @@ type
of JNull:
nil
of JObject:
fields*: seq[tuple[key: string, val: JsonNode]]
fields*: Table[string, JsonNode]
of JArray:
elems*: seq[JsonNode]
@@ -617,7 +620,7 @@ proc newJObject*(): JsonNode =
## Creates a new `JObject JsonNode`
new(result)
result.kind = JObject
result.fields = @[]
result.fields = initTable[string, JsonNode](4)
proc newJArray*(): JsonNode =
## Creates a new `JArray JsonNode`
@@ -657,8 +660,8 @@ proc getBVal*(n: JsonNode, default: bool = false): bool =
else: return n.bval
proc getFields*(n: JsonNode,
default: seq[tuple[key: string, val: JsonNode]] = @[]):
seq[tuple[key: string, val: JsonNode]] =
default = initTable[string, JsonNode](4)):
Table[string, JsonNode] =
## Retrieves the key, value pairs of a `JObject JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
@@ -700,8 +703,8 @@ proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
## Generic constructor for JSON data. Creates a new `JObject JsonNode`
new(result)
result.kind = JObject
newSeq(result.fields, keyVals.len)
for i, p in pairs(keyVals): result.fields[i] = p
result.fields = initTable[string, JsonNode](4)
for key, val in items(keyVals): result.fields[key] = val
proc `%`*(elements: openArray[JsonNode]): JsonNode =
## Generic constructor for JSON data. Creates a new `JArray JsonNode`
@@ -761,7 +764,9 @@ proc `==`* (a,b: JsonNode): bool =
of JObject:
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
case n.kind
of JArray:
@@ -779,6 +784,11 @@ proc hash* (n:JsonNode): Hash =
of JNull:
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 =
## If `n` is a `JArray`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs.
@@ -793,10 +803,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
## If the value at `name` does not exist, returns nil
assert(not isNil(node))
assert(node.kind == JObject)
for key, item in items(node.fields):
if key == name:
return item
return nil
result = node.fields.getOrDefault(name)
proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
## Gets the node at `index` in an Array. Result is undefined if `index`
@@ -808,8 +815,7 @@ proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
proc hasKey*(node: JsonNode, key: string): bool =
## Checks if `key` exists in `node`.
assert(node.kind == JObject)
for k, item in items(node.fields):
if k == key: return true
result = node.fields.hasKey(key)
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
## Deprecated for `hasKey`
@@ -820,20 +826,14 @@ proc add*(father, child: JsonNode) =
father.elems.add(child)
proc add*(obj: JsonNode, key: string, val: JsonNode) =
## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
## reasons no check for duplicate keys is performed!
## But ``[]=`` performs the check.
## Sets a field from a `JObject`.
assert obj.kind == JObject
obj.fields.add((key, val))
obj.fields[key] = val
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)
for i in 0..obj.fields.len-1:
if obj.fields[i].key == key:
obj.fields[i].val = val
return
obj.fields.add((key, val))
obj.fields[key] = val
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
## Traverses the node and gets the given value. If any of the
@@ -856,13 +856,11 @@ proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
node[keys[keys.len-1]] = value
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)
for i in 0..obj.fields.len-1:
if obj.fields[i].key == key:
obj.fields.delete(i)
return
raise newException(IndexError, "key not in object")
if not obj.fields.hasKey(key):
raise newException(IndexError, "key not in object")
obj.fields.del(key)
proc copy*(p: JsonNode): JsonNode =
## Performs a deep copy of `a`.
@@ -879,8 +877,8 @@ proc copy*(p: JsonNode): JsonNode =
result = newJNull()
of JObject:
result = newJObject()
for key, field in items(p.fields):
result.fields.add((key, copy(field)))
for key, val in pairs(p.fields):
result.fields[key] = copy(val)
of JArray:
result = newJArray()
for i in items(p.elems):
@@ -924,15 +922,17 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
if node.fields.len > 0:
result.add("{")
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:
result.add(", ")
result.nl(ml) # New Line
inc i
# Need to indent more than {
result.indent(newIndent(currIndent, indent, ml))
result.add(escapeJson(node.fields[i].key))
result.add(escapeJson(key))
result.add(": ")
toPretty(result, node.fields[i].val, indent, ml, false,
toPretty(result, val, indent, ml, false,
newIndent(currIndent, indent, ml))
result.nl(ml)
result.indent(currIndent) # indent the same as {
@@ -994,7 +994,7 @@ proc toUgly*(result: var string, node: JsonNode) =
result.add "]"
of JObject:
result.add "{"
for key, value in items(node.fields):
for key, value in pairs(node.fields):
if comma: result.add ","
else: comma = true
result.add key.escapeJson()
@@ -1033,15 +1033,15 @@ iterator mitems*(node: var JsonNode): var JsonNode =
iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject.
assert node.kind == JObject
for key, val in items(node.fields):
for key, val in pairs(node.fields):
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.
## Items can be modified
## Values can be modified
assert node.kind == JObject
for keyVal in mitems(node.fields):
yield keyVal
for key, val in mpairs(node.fields):
yield (key, val)
proc eat(p: var JsonParser, tok: TokKind) =
if p.tok == tok: discard getTok(p)
@@ -1123,9 +1123,9 @@ else:
proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".}
proc getVarType(x): JsonNodeKind =
proc getVarType(x: JSObject): JsonNodeKind =
result = JNull
proc getProtoName(y): cstring
proc getProtoName(y: JSObject): cstring
{.importc: "Object.prototype.toString.call".}
case $getProtoName(x) # TODO: Implicit returns fail here.
of "[object Array]": return JArray
@@ -1216,23 +1216,27 @@ when false:
# To get that we shall use, obj["json"]
when isMainModule:
var parsed = parseFile("tests/testdata/jsontest.json")
var parsed2 = parseFile("tests/testdata/jsontest2.json")
when not defined(js):
var parsed = parseFile("tests/testdata/jsontest.json")
try:
discard parsed["key2"][12123]
assert(false)
except IndexError: assert(true)
try:
discard parsed["key2"][12123]
doAssert(false)
except IndexError: doAssert(true)
var parsed2 = parseFile("tests/testdata/jsontest2.json")
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
# nil passthrough
assert(testJson{"doesnt_exist"}{"anything"}.isNil)
doAssert(testJson{"doesnt_exist"}{"anything"}.isNil)
testJson{["e", "f"]} = %true
assert(testJson["e"]["f"].bval)
doAssert(testJson["e"]["f"].bval)
# make sure UTF-16 decoding works.
assert(testJson["c"].str == "🎃")
assert(testJson["d"].str == "æ")
when not defined(js): # TODO: The following line asserts in JS
doAssert(testJson["c"].str == "🎃")
doAssert(testJson["d"].str == "æ")
# make sure no memory leek when parsing invalid string
let startMemory = getOccupiedMem()
@@ -1242,41 +1246,43 @@ when isMainModule:
except:
discard
# memory diff should less than 2M
assert(abs(getOccupiedMem() - startMemory) < 2 * 1024 * 1024)
doAssert(abs(getOccupiedMem() - startMemory) < 2 * 1024 * 1024)
# test `$`
let stringified = $testJson
let parsedAgain = parseJson(stringified)
assert(parsedAgain["b"].str == "asd")
doAssert(parsedAgain["b"].str == "asd")
parsedAgain["abc"] = %5
doAssert parsedAgain["abc"].num == 5
# Bounds checking
try:
let a = testJson["a"][9]
assert(false, "EInvalidIndex not thrown")
doAssert(false, "EInvalidIndex not thrown")
except IndexError:
discard
try:
let a = testJson["a"][-1]
assert(false, "EInvalidIndex not thrown")
doAssert(false, "EInvalidIndex not thrown")
except IndexError:
discard
try:
assert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
except:
assert(false, "EInvalidIndex thrown for valid index")
doAssert(false, "EInvalidIndex thrown for valid index")
assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
doAssert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
doAssert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
# Generator:
var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
var j2 = %*
[
@@ -1289,7 +1295,7 @@ when isMainModule:
"age": 31
}
]
assert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
var name = "John"
let herAge = 30
@@ -1303,4 +1309,4 @@ when isMainModule:
, "age": hisAge
}
]
assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]

View File

@@ -616,7 +616,7 @@ proc readIntoBuf(socket: Socket, flags: int32): int =
else:
result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
if result < 0:
# Save it in case it gets reset (the Nim codegen occassionally may call
# Save it in case it gets reset (the Nim codegen occasionally may call
# Win API functions which reset it).
socket.lastError = osLastError()
if result <= 0:

View File

@@ -288,19 +288,19 @@ proc rawGetTok(c: var CfgParser, tok: var Token) =
else: getSymbol(c, tok)
proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
## returns a properly formated error message containing current line and
## returns a properly formatted error message containing current line and
## column information.
result = `%`("$1($2, $3) Error: $4",
[c.filename, $getLine(c), $getColumn(c), msg])
proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
## returns a properly formated warning message containing current line and
## returns a properly formatted warning message containing current line and
## column information.
result = `%`("$1($2, $3) Warning: $4",
[c.filename, $getLine(c), $getColumn(c), msg])
proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
## returns a properly formated warning message containing that
## returns a properly formatted warning message containing that
## an entry is ignored.
case e.kind
of cfgSectionStart: result = c.warningStr("section ignored: " & e.section)

View File

@@ -344,7 +344,7 @@ proc roots*(p:Poly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq[
## `tol` is the tolerance used to break searching for each root when reached.
## `zerotol` is the tolerance, which is 'close enough' to zero to be considered a root
## and is used to find roots for curves that only 'touch' the x-axis.
## `mergetol` is the tolerance, of which two x-values are considered beeing the same root.
## `mergetol` is the tolerance, of which two x-values are considered being the same root.
## `maxiter` can be used to limit the number of iterations for each root.
## Returns a (possibly empty) sorted sequence with the solutions.
var deg=p.degree

View File

@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Nim Contributers
# (c) Copyright 2015 Nim Contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.

View File

@@ -189,7 +189,7 @@ proc readBool*(s: Stream): bool =
read(s, result)
proc peekBool*(s: Stream): bool =
## peeks a bool from the stream `s`. Raises `EIO` if an error occured.
## peeks a bool from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readInt8*(s: Stream): int8 =

View File

@@ -635,7 +635,7 @@ elif defined(JS):
proc toSeconds(time: Time): float = result = time.getTime() / 1000
proc getTimezone(): int = result = newDate().getTimezoneOffset()
proc getTimezone(): int = result = newDate().getTimezoneOffset() * 60
proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
@@ -1245,7 +1245,7 @@ proc getDayOfWeek*(day, month, year: int): WeekDay =
result = (d-1).WeekDay
proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
## Returns the day of the week enum from day, month and year, according to the Julian calender.
## Returns the day of the week enum from day, month and year, according to the Julian calendar.
# Day & month start from one.
let
a = (14 - month) div 12

View File

@@ -255,13 +255,13 @@ proc `/`*(x: Uri, path: string): Uri =
## Examples:
##
## .. code-block::
## let foo = parseUri("http://example.com/foo/bar") / parseUri("/baz")
## let foo = parseUri("http://example.com/foo/bar") / "/baz"
## assert foo.path == "/foo/bar/baz"
##
## let bar = parseUri("http://example.com/foo/bar") / parseUri("baz")
## let bar = parseUri("http://example.com/foo/bar") / "baz"
## assert bar.path == "/foo/bar/baz"
##
## let bar = parseUri("http://example.com/foo/bar/") / parseUri("baz")
## let bar = parseUri("http://example.com/foo/bar/") / "baz"
## assert bar.path == "/foo/bar/baz"
result = x
if result.path[result.path.len-1] == '/':

View File

@@ -279,11 +279,6 @@ when not defined(niminheritable):
when not defined(nimunion):
{.pragma: unchecked.}
when defined(nimNewShared):
type
`shared`* {.magic: "Shared".}
guarded* {.magic: "Guarded".}
# comparison operators:
proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.}
## Checks whether values within the *same enum* have the same underlying value
@@ -2624,6 +2619,12 @@ when not defined(JS): #and not defined(nimscript):
elif x > y: result = 1
else: result = 0
when defined(nimscript):
proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
## Opens a file named `filename` for writing. Then writes the
## `content` completely to the file and closes the file afterwards.
## Raises an IO exception in case of an error.
when not defined(nimscript) and hostOS != "standalone":
when defined(windows):
# work-around C's sucking abstraction:

View File

@@ -103,9 +103,9 @@ else:
proc c_setjmp(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "setjmp".}
proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
proc c_signal(sign: cint, handler: proc (a: cint) {.noconv.}) {.
importc: "signal", header: "<signal.h>".}
proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
proc c_raise(sign: cint) {.importc: "raise", header: "<signal.h>".}
proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs",
header: "<stdio.h>".}

View File

@@ -316,7 +316,7 @@ when defined(endb):
dbgAborting: bool # whether the debugger wants to abort
when not defined(noSignalHandler):
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
proc signalHandler(sign: cint) {.exportc: "signalHandler", noconv.} =
template processSignal(s, action: expr) {.immediate, dirty.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
elif s == SIGSEGV:
@@ -342,13 +342,13 @@ when not defined(noSignalHandler):
GC_disable()
var buf = newStringOfCap(2000)
rawWriteStackTrace(buf)
processSignal(sig, buf.add) # nice hu? currying a la Nim :-)
processSignal(sign, buf.add) # nice hu? currying a la Nim :-)
showErrorMessage(buf)
GC_enable()
else:
var msg: cstring
template asgn(y: expr) = msg = y
processSignal(sig, asgn)
processSignal(sign, asgn)
showErrorMessage(msg)
when defined(endb): dbgAborting = true
quit(1) # always quit when SIGABRT
@@ -367,6 +367,6 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures:
type SignalHandler = proc (sig: cint) {.noconv, benign.}
type SignalHandler = proc (sign: cint) {.noconv, benign.}
{.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook))

View File

@@ -91,7 +91,7 @@ when allowForeignThreadGc:
## this thread will only be initialized once per thread, no matter how often
## it is called.
##
## This function is availble only when ``--threads:on`` and ``--tlsEmulation:off``
## This function is available only when ``--threads:on`` and ``--tlsEmulation:off``
## switches are used
if not localGcInitialized:
localGcInitialized = true
@@ -100,7 +100,7 @@ when allowForeignThreadGc:
initGC()
else:
template setupForeignThreadGc*(): stmt =
{.error: "setupForeignThreadGc is availble only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
{.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".}
# ----------------- stack management --------------------------------------
# inspired from Smart Eiffel

View File

@@ -74,7 +74,7 @@ proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
builtin
proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} =
## Checks for the existance of an environment variable named `key`.
## Checks for the existence of an environment variable named `key`.
builtin
proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} =
@@ -189,7 +189,7 @@ proc get*(key: string): string =
builtin
proc exists*(key: string): bool =
## Checks for the existance of a configuration 'key'
## Checks for the existence of a configuration 'key'
## like 'gcc.options.always'.
builtin

View File

@@ -11,7 +11,7 @@ discard """
type
E = enum A, B, C
proc foo(x): auto =
proc foo(x: int): auto =
return case x
of 1..9: "digit"
else: "number"

View File

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

View File

@@ -0,0 +1,13 @@
discard """
output: '''true'''
"""
# bug #3686
type Monoid = concept x, y
x + y is type(x)
type(z(type(x))) is type(x)
proc z(x: typedesc[int]): int = 0
echo(int is Monoid)

View File

@@ -0,0 +1,13 @@
# bug #3669
import tables
type
G[T] = object
inodes: Table[int, T]
rnodes: Table[T, int]
var g: G[string]
echo g.rnodes["foo"]

View File

@@ -3,5 +3,5 @@ discard """
line: 6
"""
let x = proc (x, y): auto = x + y
let x = proc (x, y: auto): auto = x + y

View File

@@ -18,7 +18,7 @@ proc foo[T](p: TType[T, range[0..2]]) =
#bug #1366
proc reversed(x) =
proc reversed(x: auto) =
for i in countdown(x.low, x.high):
echo i

View File

@@ -5,15 +5,15 @@ discard """
proc test(x: proc (a, b: int): int) =
echo x(5, 5)
test(proc (a, b): auto = a + b)
test(proc (a, b: auto): auto = a + b)
test do (a, b) -> auto: a + b
test do (a, b: auto) -> auto: a + b
proc foreach[T](s: seq[T], body: proc(x: T)) =
for e in s:
body(e)
foreach(@[1,2,3]) do (x):
foreach(@[1,2,3]) do (x: auto):
echo x
proc foo =

View File

@@ -26,7 +26,7 @@ proc noReturn(x: () -> void) =
proc doWithOneAndTwo(f: (int, int) -> int): int =
f(1,2)
echo twoParams(proc (a, b): auto = a + b)
echo twoParams(proc (a, b: auto): auto = a + b)
echo twoParams((x, y) => x + y)
echo oneParam(x => x+5)

View File

@@ -0,0 +1,39 @@
discard """
output: '''0 -2 0
0 -2'''
"""
{.this: self.}
type
Foo {.partial.} = object
a, b: int
type
tupcomingfeatures.Foo = object
x: int
proc yay(self: Foo) =
echo a, " ", b, " ", x
proc footest[T](self: var Foo, a: T) =
b = 1+a
yay()
proc nongeneric(self: Foo) =
echo a, " ", b
var ff: Foo
footest(ff, -3)
ff.nongeneric
{.experimental.}
using
c: Foo
x, y: int
proc usesSig(c) =
echo "yummy"
proc foobar(c, y) =
echo "yay"

View File

@@ -2,7 +2,7 @@ import unittest
include nre
suite "Test NRE initialization":
test "correct intialization":
test "correct initialization":
check(re("[0-9]+") != nil)
check(re("(?i)[0-9]+") != nil)

View File

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

View File

@@ -5,7 +5,7 @@ template someIt(a, pred: expr): expr =
var it {.inject.} = 0
pred
proc aProc(n) =
proc aProc(n: auto) =
n.someIt(echo(it))
aProc(89)

View File

@@ -223,7 +223,7 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
"varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
test "tests/" & testfile & ".nim"
for testfile in ["pure/strutils"]:
for testfile in ["pure/strutils", "pure/json"]:
test "lib/" & testfile & ".nim"
# ------------------------- manyloc -------------------------------------------

View File

@@ -345,7 +345,7 @@ proc writeformat(o: var Writer; p: pointer; fmt: Format) =
## Write pointer `i` according to format `fmt` using output object
## `o` and output function `add`.
##
## Pointers are casted to unsigned int and formated as hexadecimal
## Pointers are casted to unsigned int and formatted as hexadecimal
## with prefix unless specified otherwise.
var f = fmt
if f.typ == 0.char:
@@ -584,7 +584,7 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
## Each part is either a literal string or a format specification. A
## format specification is a substring of the form
## "{[arg][:format]}" where `arg` is either empty or a number
## refering to the arg-th argument and an additional field or array
## referring to the arg-th argument and an additional field or array
## index. The format string is a string accepted by `parse`.
let subpeg = sequence(capture(digits()),
capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),

View File

@@ -5,8 +5,8 @@ discard """
import typetraits
proc plus(a, b): auto = a + b
proc makePair(a, b): auto = (first: a, second: b)
proc plus(a, b: auto): auto = a + b
proc makePair(a, b: auto): auto = (first: a, second: b)
proc `+`(a, b: string): seq[string] = @[a, b]
@@ -19,7 +19,7 @@ static: assert p[0].type is string
echo i.type.name
echo s.type.name
proc inst(a): auto =
proc inst(a: auto): auto =
static: echo "instantiated for ", a.type.name
result = a

View File

@@ -1,6 +1,9 @@
nim c --gc:v2 -r -d:useSysAssert -d:useGcAssert -d:smokeCycles -d:useRealtimeGc tests/gc/gcbench
- document ``this`` pragma
- document and stress test ``.partial`` object declarations
essential for 1.0
=================

View File

@@ -10,19 +10,39 @@ Changes affecting backwards compatibility
- ``--out`` and ``--nimcache`` command line arguments are now relative to
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.
- The deprecated Nim shebang notation ``#!`` was removed from the language. Use ``#?`` instead.
- The ``using`` statement now means something completely different. You can use the
new experimental ``this`` pragma to achieve a similar effect to what the old ``using`` statement tried to achieve.
- Typeless parameters have been removed from the language since it would
clash with ``using``.
Library Additions
-----------------
- The rlocks module has been added providing reentrant lock synchronization
primitive
primitive.
Compiler Additions
------------------
- Added a new ``--noCppExceptions`` switch that allows to use default exception
handling (no ``throw`` or ``try``/``catch`` generated) when compiling to C++
code
code.
Language Additions
------------------
- Nim now supports a ``.this`` pragma for more notational convenience.
- Nim now supports a different ``using`` statement for more convenience.
- Nim now supports ``partial`` object declarations to mitigate the problems
that arise when types are mutually dependent and yet should be kept in
different modules.
2016-01-27 Nim in Action is now available!

View File

@@ -135,7 +135,8 @@ General FAQ
- Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_)
- LiClipse: http://www.liclipse.com/ (Eclipse based plugin)
- Howl: Included
- Notepad++: Available via `plugin <https://github.com/jangko/nppnim/releases>`_
.. container:: standout