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

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

View file

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

View file

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

View file

@ -158,7 +158,6 @@ proc hashType(c: var MD5Context, t: PType) =
if tfThread in t.flags: c &= ".thread" if tfThread in t.flags: c &= ".thread"
else: else:
for i in 0.. <t.len: c.hashType(t.sons[i]) 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" if tfNotNil in t.flags: c &= "not nil"
proc canonConst(n: PNode): TUid = proc canonConst(n: PNode): TUid =
@ -276,7 +275,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
return return
# we need no surrounding [] here because the type is in a line of its own # we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward") 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: # can easily be disambiguated:
add(result, '[') add(result, '[')
encodeVInt(ord(t.kind), 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): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: add(orExpr, "||") if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr, let isObjFormat = if not p.module.compileToCpp:
"#isObj(#getCurrentException()->Sup.m_type, $1)", "#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)]) [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
if i > 1: line(p, cpsStmts, "else ") if i > 1: line(p, cpsStmts, "else ")
startBlock(p, "if ($1) {$n", [orExpr]) startBlock(p, "if ($1) {$n", [orExpr])

View file

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

View file

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

View file

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

View file

@ -46,7 +46,7 @@ const
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt, wDeprecated, wExperimental} wInjectStmt, wDeprecated, wExperimental, wThis}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
@ -55,7 +55,7 @@ const
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wExportNims} wBorrow, wGcSafe, wExportNims, wPartial}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wGuard, wBitsize} wImportCpp, wImportObjC, wError, wGuard, wBitsize}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
@ -835,6 +835,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it) noVal(it)
if sym.kind != skType or sym.typ == nil: invalidPragma(it) if sym.kind != skType or sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfByCopy) 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: of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise # We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'. # 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 c.module.flags.incl sfExperimental
else: else:
localError(it.info, "'experimental' pragma only valid as toplevel statement") 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: of wNoRewrite:
noVal(it) noVal(it)
of wBase: of wBase:

View file

@ -463,6 +463,9 @@ proc lsub(n: PNode): int =
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection:
if sonsLen(n) > 1: result = MaxLineLen + 1 if sonsLen(n) > 1: result = MaxLineLen + 1
else: result = lsons(n) + len("var_") 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 nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_") of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_") of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_")
@ -1173,11 +1176,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
initContext(a) initContext(a)
incl(a.flags, rfInConstExpr) incl(a.flags, rfInConstExpr)
gsection(g, n, a, tkConst, "const") gsection(g, n, a, tkConst, "const")
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection, nkUsingStmt:
var L = sonsLen(n) var L = sonsLen(n)
if L == 0: return if L == 0: return
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var") 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: if L > 1:
gcoms(g) gcoms(g)
indentNL(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, proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym allowed: TSymFlags): PSym
# identifier with visability # identifier with visibility
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym allowed: TSymFlags): PSym
proc semStmtScope(c: PContext, n: PNode): PNode 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]] = @[] var syms: seq[tuple[a: PSym, b: int]] = @[]
while symx != nil: 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) symx = nextOverloadIter(o, c, headSymbol)
if syms.len == 0: return if syms.len == 0: return
@ -63,7 +64,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
let sym = syms[i][0] let sym = syms[i][0]
determineType(c, sym) determineType(c, sym)
initCandidate(c, z, sym, initialBinding, syms[i][1]) 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: #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# gDebug = true # gDebug = true
@ -138,11 +138,6 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
else: else:
localError(n.info, errGenerated, result) 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, proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds; filter: TSymKinds;
errors: var CandidateErrors): TCandidate = errors: var CandidateErrors): TCandidate =
@ -156,17 +151,20 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else: else:
initialBinding = nil initialBinding = nil
var usedSyms: seq[PNode] template pickBest(headSymbol) =
template pickBest(headSymbol: expr) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding, pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors) filter, result, alt, errors)
gatherUsedSyms(c, usedSyms)
if usedSyms != nil:
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
else: usedSyms[0]
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) n.sons.insert(hiddenArg, 1)
orig.sons.insert(hiddenArg, 1) orig.sons.insert(hiddenArg, 1)
@ -177,10 +175,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
orig.sons.delete(1) orig.sons.delete(1)
else: return else: return
pickBest(f)
let overloadsState = result.state
if overloadsState != csMatch:
if nfDotField in n.flags: if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2 internalAssert f.kind == nkIdent and n.sonsLen >= 2
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info) let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)

View file

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

View file

@ -77,88 +77,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result.typ = s.typ result.typ = s.typ
result.info = n.info 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 type
TConvStatus = enum TConvStatus = enum
convOK, convOK,
@ -1015,6 +933,116 @@ proc readTypeParameter(c: PContext, typ: PType,
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
#echo "came here: returned nil" #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 = proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access ## returns nil if it's not a built-in field access
checkSonsLen(n, 2) checkSonsLen(n, 2)
@ -1528,24 +1556,6 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
result = newSym(kind, idAnon, owner, info) result = newSym(kind, idAnon, owner, info)
result.flags = {sfGenSym} 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 = proc semExpandToAst(c: PContext, n: PNode): PNode =
var macroCall = n[1] var macroCall = n[1]
var expandedSym = expectMacroOrTemplateCall(c, macroCall) var expandedSym = expectMacroOrTemplateCall(c, macroCall)

View file

@ -10,6 +10,47 @@
# This module implements the instantiation of generic procs. # This module implements the instantiation of generic procs.
# included from sem.nim # 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 = iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert n.kind == nkGenericParams internalAssert n.kind == nkGenericParams
for i, a in n.pairs: for i, a in n.pairs:
@ -248,7 +289,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
addDecl(c, s) addDecl(c, s)
entry.concreteTypes[i] = s.typ entry.concreteTypes[i] = s.typ
inc i inc i
pushProcCon(c, result) rawPushProcCon(c, result)
instantiateProcType(c, pt, result, info) instantiateProcType(c, pt, result, info)
for j in 1 .. result.typ.len-1: for j in 1 .. result.typ.len-1:
entry.concreteTypes[i] = result.typ.sons[j] 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 # a ``compiles`` context but this is the lesser evil. See
# bug #1055 (tevilcompiles). # bug #1055 (tevilcompiles).
#if c.compilesContextId == 0: #if c.compilesContextId == 0:
rawHandleSelf(c, result)
entry.compilesId = c.compilesContextId entry.compilesId = c.compilesContextId
fn.procInstCache.safeAdd(entry) fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry)) c.generics.add(makeInstPair(fn, entry))

View file

@ -386,6 +386,30 @@ proc isDiscardUnderscore(v: PSym): bool =
v.flags.incl(sfGenSym) v.flags.incl(sfGenSym)
result = true 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 = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode var b: PNode
result = copyNode(n) result = copyNode(n)
@ -640,11 +664,18 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if a.kind != nkTypeDef: illFormedAst(a) if a.kind != nkTypeDef: illFormedAst(a)
checkSonsLen(a, 3) checkSonsLen(a, 3)
var s = semIdentDef(c, a.sons[0], skType) 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 = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas: s.typ.sym = s # process pragmas:
if a.sons[0].kind == nkPragmaExpr: if name.kind == nkPragmaExpr:
pragma(c, s, a.sons[0].sons[1], typePragmas) pragma(c, s, name.sons[1], typePragmas)
# add it here, so that recursive types are possible: # add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s) if sfGenSym notin s.flags: addInterfaceDecl(c, s)
a.sons[0] = newSymNode(s) a.sons[0] = newSymNode(s)
@ -655,8 +686,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a) if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3) checkSonsLen(a, 3)
if (a.sons[0].kind != nkSym): illFormedAst(a) let name = a.sons[0]
var s = a.sons[0].sym if (name.kind != nkSym): illFormedAst(a)
var s = name.sym
if s.magic == mNone and a.sons[2].kind == nkEmpty: if s.magic == mNone and a.sons[2].kind == nkEmpty:
localError(a.info, errImplOfXexpected, s.name.s) localError(a.info, errImplOfXexpected, s.name.s)
if s.magic != mNone: processMagicType(c, 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 # Macros and Templates can have generic parameters, but they are
# only used for overload resolution (there is no instantiation of # only used for overload resolution (there is no instantiation of
# the symbol, so we must process the body now) # the symbol, so we must process the body now)
pushProcCon(c, s)
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
if not usePseudoGenerics: paramsTypeCheck(c, s.typ) if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
pushProcCon(c, s)
c.p.wasForwarded = proto != nil c.p.wasForwarded = proto != nil
maybeAddResult(c, s, n) maybeAddResult(c, s, n)
if sfImportc notin s.flags: 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' # unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles': # context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.module, semBody, s) n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) 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: if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc: # so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode n.sons[bodyPos] = ast.emptyNode
popProcCon(c)
else: else:
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s) if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: 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") if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c) result = newOrPrevType(tyObject, prev, c)
rawAddSon(result, base) rawAddSon(result, base)
if result.n.isNil:
result.n = newNodeI(nkRecList, n.info) 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) semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# dummy symbol for `pragma`: # dummy symbol for `pragma`:
@ -934,14 +938,18 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
def = fitNode(c, typ, def) def = fitNode(c, typ, def)
if not hasType and not hasDefault: if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected") if isType: localError(a.info, "':' expected")
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything if kind in {skTemplate, skMacro}:
if tdef == tyAnything: typ = newTypeS(tyExpr, c)
message(a.info, warnTypelessParam, renderTree(n)) elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
typ = newTypeS(tdef, c) continue
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3): for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c) 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, let lifted = liftParamType(c, kind, genericParams, typ,
arg.name.s, arg.info) arg.name.s, arg.info)
let finalType = if lifted != nil: lifted else: typ.skipIntLit 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 nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev) of nkStmtListType: result = semStmtListType(c, n, prev)
of nkBlockType: result = semBlockType(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: else:
localError(n.info, errTypeExpected) localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
@ -1387,15 +1390,6 @@ proc processMagicType(c: PContext, m: PSym) =
rawAddSon(m.typ, newTypeS(tyNone, c)) rawAddSon(m.typ, newTypeS(tyNone, c))
of mPNimrodNode: of mPNimrodNode:
incl m.typ.flags, tfTriggersCompileTime 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) else: localError(m.info, errTypeExpected)
proc semGenericConstraints(c: PContext, x: PType): PType = proc semGenericConstraints(c: PContext, x: PType): PType =

View file

@ -14,22 +14,11 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer
const const
tfInstClearedFlags = {tfHasMeta} 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) = proc checkPartialConstructedType(info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic") localError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar: elif t.kind == tyVar and t.sons[0].kind == tyVar:
localError(info, errVarVarTypeNotAllowed) localError(info, errVarVarTypeNotAllowed)
else:
sharedPtrCheck(info, t)
proc checkConstructedType*(info: TLineInfo, typ: PType) = proc checkConstructedType*(info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct}) var t = typ.skipTypes({tyDistinct})
@ -40,8 +29,6 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
localError(info, errVarVarTypeNotAllowed) localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) == szIllegalRecursion: elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t)) localError(info, errIllegalRecursionInTypeX, typeToString(t))
else:
sharedPtrCheck(info, t)
when false: when false:
if t.kind == tyObject and t.sons[0] != nil: if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@ -216,11 +203,11 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
# symbol is not our business: # symbol is not our business:
if cl.owner != nil and s.owner != cl.owner: if cl.owner != nil and s.owner != cl.owner:
return s return s
result = PSym(idTableGet(cl.symMap, s)) #result = PSym(idTableGet(cl.symMap, s))
if result == nil: #if result == nil:
result = copySym(s, false) result = copySym(s, false)
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
idTablePut(cl.symMap, s, result) #idTablePut(cl.symMap, s, result)
result.owner = s.owner result.owner = s.owner
result.typ = replaceTypeVarsT(cl, s.typ) result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast) result.ast = replaceTypeVarsN(cl, s.ast)

View file

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

View file

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

View file

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

View file

@ -412,7 +412,6 @@ const
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
proc addTypeFlags(name: var string, typ: PType) {.inline.} = 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") if tfNotNil in typ.flags: name.add(" not nil")
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = 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) = 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`, # Takes the `b` register and the immediate `imm`, appies the operation `opc`,
# and stores the output value into `a`. # and stores the output value into `a`.
# `imm` is signed and must be within [-127, 128] # `imm` is signed and must be within [-128, 127]
if imm >= -127 and imm <= 128: if imm >= -128 and imm <= 127:
let ins = (opc.uint32 or (a.uint32 shl 8'u32) or let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
(b.uint32 shl 16'u32) or (b.uint32 shl 16'u32) or
(imm+byteExcess).uint32 shl 24'u32).TInstr (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) = proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
# Applies `opc` to `bx` and stores it into register `a` # Applies `opc` to `bx` and stores it into register `a`
# `bx` must be signed and in the range [-32767, 32768] # `bx` must be signed and in the range [-32768, 32767]
if bx >= -32767 and bx <= 32768: if bx >= -32768 and bx <= 32767:
let ins = (opc.uint32 or a.uint32 shl 8'u32 or let ins = (opc.uint32 or a.uint32 shl 8'u32 or
(bx+wordExcess).uint32 shl 16'u32).TInstr (bx+wordExcess).uint32 shl 16'u32).TInstr
c.code.add(ins) c.code.add(ins)

View file

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

View file

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

View file

@ -547,55 +547,36 @@ Instead of:
Using statement 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! explicitly enabled with the `experimental`:idx: pragma or command line option!
The using statement provides syntactic convenience for procs that The using statement provides syntactic convenience in modules where
heavily use a single contextual parameter. When applied to a variable or a the same parameter names and types are used over and over. Instead of:
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.
.. code-block:: nim .. 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() One can tell the compiler about the convention that a parameter of
using s name ``c`` should default to type ``Context``, ``n`` should default to
``Node`` etc.:
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.
.. code-block:: nim .. code-block:: nim
import windows, sdl {.experimental.}
using sdl.SetTimer using
c: Context
n: Node
counter: int
Note that ``using`` only *adds* to the current context, it doesn't remove or proc foo(c, n) = ...
replace, **neither** does it create a new scope. What this means is that if one proc bar(c, n, counter) = ...
applies this to multiple variables the compiler will find conflicts in what proc baz(c, n) = ...
variable to use:
.. 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 The ``using`` section uses the same indentation based grouping syntax as
be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or a ``var`` or ``let``` section.
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.
If expression If expression
------------- -------------

View file

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

View file

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

View file

@ -91,10 +91,25 @@ __clang__
# define NIM_CONST const # define NIM_CONST const
#endif #endif
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) /*
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) # define NIM_THREADVAR __declspec(thread)
#else /* note that ICC (linux) and Clang are covered by __GNUC__ */
#elif defined __GNUC__ || \
defined __SUNPRO_C || \
defined __xlC__
# define NIM_THREADVAR __thread # define NIM_THREADVAR __thread
#else
# error "Cannot define NIM_THREADVAR"
#endif #endif
/* --------------- how int64 constants should be declared: ----------- */ /* --------------- 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 hc: Hash
var index = rawGet(s, key, hc) var index = rawGet(s, key, hc)
if index >= 0: result = s.data[index].key 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.} = 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 ## returns the element that is actually stored in 's' which has the same

View file

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

View file

@ -288,19 +288,19 @@ proc rawGetTok(c: var CfgParser, tok: var Token) =
else: getSymbol(c, tok) else: getSymbol(c, tok)
proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = 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. ## column information.
result = `%`("$1($2, $3) Error: $4", result = `%`("$1($2, $3) Error: $4",
[c.filename, $getLine(c), $getColumn(c), msg]) [c.filename, $getLine(c), $getColumn(c), msg])
proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = 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. ## column information.
result = `%`("$1($2, $3) Warning: $4", result = `%`("$1($2, $3) Warning: $4",
[c.filename, $getLine(c), $getColumn(c), msg]) [c.filename, $getLine(c), $getColumn(c), msg])
proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} = 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. ## an entry is ignored.
case e.kind case e.kind
of cfgSectionStart: result = c.warningStr("section ignored: " & e.section) 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. ## `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 ## `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. ## 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. ## `maxiter` can be used to limit the number of iterations for each root.
## Returns a (possibly empty) sorted sequence with the solutions. ## Returns a (possibly empty) sorted sequence with the solutions.
var deg=p.degree var deg=p.degree

View file

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

View file

@ -189,7 +189,7 @@ proc readBool*(s: Stream): bool =
read(s, result) read(s, result)
proc peekBool*(s: Stream): bool = 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) peek(s, result)
proc readInt8*(s: Stream): int8 = proc readInt8*(s: Stream): int8 =

View file

@ -635,7 +635,7 @@ elif defined(JS):
proc toSeconds(time: Time): float = result = time.getTime() / 1000 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() proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
@ -1245,7 +1245,7 @@ proc getDayOfWeek*(day, month, year: int): WeekDay =
result = (d-1).WeekDay result = (d-1).WeekDay
proc getDayOfWeekJulian*(day, month, year: int): 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. # Day & month start from one.
let let
a = (14 - month) div 12 a = (14 - month) div 12

View file

@ -255,13 +255,13 @@ proc `/`*(x: Uri, path: string): Uri =
## Examples: ## Examples:
## ##
## .. code-block:: ## .. 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" ## 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" ## 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" ## assert bar.path == "/foo/bar/baz"
result = x result = x
if result.path[result.path.len-1] == '/': if result.path[result.path.len-1] == '/':

View file

@ -279,11 +279,6 @@ when not defined(niminheritable):
when not defined(nimunion): when not defined(nimunion):
{.pragma: unchecked.} {.pragma: unchecked.}
when defined(nimNewShared):
type
`shared`* {.magic: "Shared".}
guarded* {.magic: "Guarded".}
# comparison operators: # comparison operators:
proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.}
## Checks whether values within the *same enum* have the same underlying value ## 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 elif x > y: result = 1
else: result = 0 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 not defined(nimscript) and hostOS != "standalone":
when defined(windows): when defined(windows):
# work-around C's sucking abstraction: # work-around C's sucking abstraction:

View file

@ -103,9 +103,9 @@ else:
proc c_setjmp(jmpb: C_JmpBuf): cint {. proc c_setjmp(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "setjmp".} 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>".} 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", proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs",
header: "<stdio.h>".} header: "<stdio.h>".}

View file

@ -316,7 +316,7 @@ when defined(endb):
dbgAborting: bool # whether the debugger wants to abort dbgAborting: bool # whether the debugger wants to abort
when not defined(noSignalHandler): 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.} = template processSignal(s, action: expr) {.immediate, dirty.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n") if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
elif s == SIGSEGV: elif s == SIGSEGV:
@ -342,13 +342,13 @@ when not defined(noSignalHandler):
GC_disable() GC_disable()
var buf = newStringOfCap(2000) var buf = newStringOfCap(2000)
rawWriteStackTrace(buf) rawWriteStackTrace(buf)
processSignal(sig, buf.add) # nice hu? currying a la Nim :-) processSignal(sign, buf.add) # nice hu? currying a la Nim :-)
showErrorMessage(buf) showErrorMessage(buf)
GC_enable() GC_enable()
else: else:
var msg: cstring var msg: cstring
template asgn(y: expr) = msg = y template asgn(y: expr) = msg = y
processSignal(sig, asgn) processSignal(sign, asgn)
showErrorMessage(msg) showErrorMessage(msg)
when defined(endb): dbgAborting = true when defined(endb): dbgAborting = true
quit(1) # always quit when SIGABRT quit(1) # always quit when SIGABRT
@ -367,6 +367,6 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) = proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures: # 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].} {.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook)) 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 ## this thread will only be initialized once per thread, no matter how often
## it is called. ## 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 ## switches are used
if not localGcInitialized: if not localGcInitialized:
localGcInitialized = true localGcInitialized = true
@ -100,7 +100,7 @@ when allowForeignThreadGc:
initGC() initGC()
else: else:
template setupForeignThreadGc*(): stmt = 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 -------------------------------------- # ----------------- stack management --------------------------------------
# inspired from Smart Eiffel # inspired from Smart Eiffel

View file

@ -74,7 +74,7 @@ proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
builtin builtin
proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} = 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 builtin
proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} = proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} =
@ -189,7 +189,7 @@ proc get*(key: string): string =
builtin builtin
proc exists*(key: string): bool = 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'. ## like 'gcc.options.always'.
builtin builtin

View file

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

View file

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

View file

@ -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 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 #bug #1366
proc reversed(x) = proc reversed(x: auto) =
for i in countdown(x.low, x.high): for i in countdown(x.low, x.high):
echo i echo i

View file

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

View file

@ -26,7 +26,7 @@ proc noReturn(x: () -> void) =
proc doWithOneAndTwo(f: (int, int) -> int): int = proc doWithOneAndTwo(f: (int, int) -> int): int =
f(1,2) 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 twoParams((x, y) => x + y)
echo oneParam(x => x+5) 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 include nre
suite "Test NRE initialization": suite "Test NRE initialization":
test "correct intialization": test "correct initialization":
check(re("[0-9]+") != nil) check(re("[0-9]+") != nil)
check(re("(?i)[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] [11, 12, 13]
[11, 12, 13] [11, 12, 13]
{"key1":11,"key2":12,"key3":13} 11 12 13
[11,12,13] [11,12,13]
<Students> <Students>
<Student Name="Aprilfoo" /> <Student Name="Aprilfoo" />
@ -115,7 +115,7 @@ block:
var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}""" var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
for key,val in j.pairs: for key,val in j.pairs:
val.num += 10 val.num += 10
echo j echo j["key1"], " ", j["key2"], " ", j["key3"]
block: block:
var j = parseJson """[1, 2, 3]""" var j = parseJson """[1, 2, 3]"""

View file

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

View file

@ -223,7 +223,7 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
"varres/tvartup", "misc/tints", "misc/tunsignedinc"]: "varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
test "tests/" & testfile & ".nim" test "tests/" & testfile & ".nim"
for testfile in ["pure/strutils"]: for testfile in ["pure/strutils", "pure/json"]:
test "lib/" & testfile & ".nim" test "lib/" & testfile & ".nim"
# ------------------------- manyloc ------------------------------------------- # ------------------------- 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 ## Write pointer `i` according to format `fmt` using output object
## `o` and output function `add`. ## `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. ## with prefix unless specified otherwise.
var f = fmt var f = fmt
if f.typ == 0.char: 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 ## Each part is either a literal string or a format specification. A
## format specification is a substring of the form ## format specification is a substring of the form
## "{[arg][:format]}" where `arg` is either empty or a number ## "{[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`. ## index. The format string is a string accepted by `parse`.
let subpeg = sequence(capture(digits()), let subpeg = sequence(capture(digits()),
capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())), capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),

View file

@ -5,8 +5,8 @@ discard """
import typetraits import typetraits
proc plus(a, b): auto = a + b proc plus(a, b: auto): auto = a + b
proc makePair(a, b): auto = (first: a, second: b) proc makePair(a, b: auto): auto = (first: a, second: b)
proc `+`(a, b: string): seq[string] = @[a, 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 i.type.name
echo s.type.name echo s.type.name
proc inst(a): auto = proc inst(a: auto): auto =
static: echo "instantiated for ", a.type.name static: echo "instantiated for ", a.type.name
result = a result = a

View file

@ -1,6 +1,9 @@
nim c --gc:v2 -r -d:useSysAssert -d:useGcAssert -d:smokeCycles -d:useRealtimeGc tests/gc/gcbench 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 essential for 1.0
================= =================

View file

@ -10,19 +10,39 @@ Changes affecting backwards compatibility
- ``--out`` and ``--nimcache`` command line arguments are now relative to - ``--out`` and ``--nimcache`` command line arguments are now relative to
current directory. Previously they were relative to project directory. current directory. Previously they were relative to project directory.
- The json module now stores the name/value pairs in objects internally as a
hash table of type ``fields*: Table[string, JsonNode]`` instead of a
sequence. This means that order is no longer preserved. When using the
``table.mpairs`` iterator only the returned values can be modified, no
longer the keys.
- 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 Library Additions
----------------- -----------------
- The rlocks module has been added providing reentrant lock synchronization - The rlocks module has been added providing reentrant lock synchronization
primitive primitive.
Compiler Additions Compiler Additions
------------------ ------------------
- Added a new ``--noCppExceptions`` switch that allows to use default exception - Added a new ``--noCppExceptions`` switch that allows to use default exception
handling (no ``throw`` or ``try``/``catch`` generated) when compiling to C++ 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! 2016-01-27 Nim in Action is now available!

View file

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