Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
commit
f73fa61c98
61 changed files with 592 additions and 456 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,7 +654,8 @@ 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:
|
||||||
t.data[replaceSlot] = n # overwrite it with newer definition!
|
if not onConflictKeepOld:
|
||||||
|
t.data[replaceSlot] = n # overwrite it with newer definition!
|
||||||
return true # found it
|
return true # found it
|
||||||
elif mustRehash(len(t.data), t.counter):
|
elif mustRehash(len(t.data), t.counter):
|
||||||
strTableEnlarge(t)
|
strTableEnlarge(t)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,9 @@ 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)
|
||||||
add(result, "_")
|
if s.name.s != "this" and s.kind != skField:
|
||||||
add(result, rope(s.id))
|
add(result, "_")
|
||||||
|
add(result, rope(s.id))
|
||||||
s.loc.r = result
|
s.loc.r = result
|
||||||
|
|
||||||
proc escapeJSString(s: string): string =
|
proc escapeJSString(s: string): string =
|
||||||
|
|
@ -890,10 +891,12 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = "$1['$2']" % [r.res, f.loc.r]
|
r.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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,31 +151,30 @@ 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]
|
|
||||||
|
|
||||||
n.sons.insert(hiddenArg, 1)
|
|
||||||
orig.sons.insert(hiddenArg, 1)
|
|
||||||
|
|
||||||
pickBest(f)
|
|
||||||
|
|
||||||
if result.state != csMatch:
|
|
||||||
n.sons.delete(1)
|
|
||||||
orig.sons.delete(1)
|
|
||||||
else: return
|
|
||||||
|
|
||||||
pickBest(f)
|
pickBest(f)
|
||||||
|
|
||||||
let overloadsState = result.state
|
let overloadsState = result.state
|
||||||
if overloadsState != csMatch:
|
if overloadsState != csMatch:
|
||||||
|
if c.p != nil and c.p.selfSym != nil:
|
||||||
|
# we need to enforce semchecking of selfSym again because it
|
||||||
|
# might need auto-deref:
|
||||||
|
var hiddenArg = newSymNode(c.p.selfSym)
|
||||||
|
hiddenArg.typ = nil
|
||||||
|
n.sons.insert(hiddenArg, 1)
|
||||||
|
orig.sons.insert(hiddenArg, 1)
|
||||||
|
|
||||||
|
pickBest(f)
|
||||||
|
|
||||||
|
if result.state != csMatch:
|
||||||
|
n.sons.delete(1)
|
||||||
|
orig.sons.delete(1)
|
||||||
|
else: return
|
||||||
|
|
||||||
if nfDotField in n.flags:
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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,13 +664,20 @@ 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]
|
||||||
s.typ = newTypeS(tyForward, c)
|
var s: PSym
|
||||||
s.typ.sym = s # process pragmas:
|
if name.kind == nkDotExpr:
|
||||||
if a.sons[0].kind == nkPragmaExpr:
|
s = qualifiedLookUp(c, name)
|
||||||
pragma(c, s, a.sons[0].sons[1], typePragmas)
|
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
||||||
# add it here, so that recursive types are possible:
|
localError(name.info, "only .partial objects can be extended")
|
||||||
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
else:
|
||||||
|
s = semIdentDef(c, name, skType)
|
||||||
|
s.typ = newTypeS(tyForward, c)
|
||||||
|
s.typ.sym = s # process pragmas:
|
||||||
|
if name.kind == nkPragmaExpr:
|
||||||
|
pragma(c, s, name.sons[1], typePragmas)
|
||||||
|
# add it here, so that recursive types are possible:
|
||||||
|
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
||||||
a.sons[0] = newSymNode(s)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
if result.n.isNil:
|
||||||
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
|
else:
|
||||||
|
# partial object so add things to the check
|
||||||
|
addInheritedFields(c, check, pos, result)
|
||||||
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
|
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 =
|
||||||
|
|
|
||||||
|
|
@ -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,14 +203,14 @@ 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)
|
||||||
|
|
||||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
result = PType(idTableGet(cl.typeMap, t))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
-------------
|
-------------
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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: ----------- */
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
raise newException(IndexError, "key not in object")
|
||||||
obj.fields.delete(i)
|
obj.fields.del(key)
|
||||||
return
|
|
||||||
raise newException(IndexError, "key not in object")
|
|
||||||
|
|
||||||
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:
|
||||||
var parsed = parseFile("tests/testdata/jsontest.json")
|
when not defined(js):
|
||||||
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
var parsed = parseFile("tests/testdata/jsontest.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}]
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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] == '/':
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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>".}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
13
tests/concepts/tmonoid.nim
Normal file
13
tests/concepts/tmonoid.nim
Normal 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)
|
||||||
13
tests/generics/t2tables.nim
Normal file
13
tests/generics/t2tables.nim
Normal 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"]
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
39
tests/misc/tupcomingfeatures.nim
Normal file
39
tests/misc/tupcomingfeatures.nim
Normal 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"
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]"""
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 -------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -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())),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -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
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
|
||||||
24
web/news.txt
24
web/news.txt
|
|
@ -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!
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue