fixes testament compilation
This commit is contained in:
commit
5526252fa0
41 changed files with 985 additions and 297 deletions
|
|
@ -72,6 +72,8 @@
|
||||||
- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is
|
- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is
|
||||||
now joined in ``binarySearch``. ``smartbinarySearch`` is now
|
now joined in ``binarySearch``. ``smartbinarySearch`` is now
|
||||||
deprecated.
|
deprecated.
|
||||||
|
- The `terminal` module now exports additional procs for generating ANSI color
|
||||||
|
codes as strings.
|
||||||
|
|
||||||
### Language additions
|
### Language additions
|
||||||
|
|
||||||
|
|
@ -95,11 +97,18 @@
|
||||||
|
|
||||||
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||||
these is ``"" / @[]``.
|
these is ``"" / @[]``.
|
||||||
|
|
||||||
- Accessing the binary zero terminator in Nim's native strings
|
- Accessing the binary zero terminator in Nim's native strings
|
||||||
is now invalid. Internally a Nim string still has the trailing zero for
|
is now invalid. Internally a Nim string still has the trailing zero for
|
||||||
zero-copy interoperability with ``cstring``. Compile your code with the
|
zero-copy interoperability with ``cstring``. Compile your code with the
|
||||||
new switch ``--laxStrings:on`` if you need a transition period.
|
new switch ``--laxStrings:on`` if you need a transition period.
|
||||||
|
|
||||||
|
- The command syntax now supports keyword arguments after the first comma.
|
||||||
|
|
||||||
|
- Thread-local variables can now be declared inside procs. This implies all
|
||||||
|
the effects of the `global` pragma.
|
||||||
|
|
||||||
|
- Nim now supports `except` clause in the export statement.
|
||||||
|
|
||||||
### Tool changes
|
### Tool changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1620,6 +1620,19 @@ proc originatingModule*(s: PSym): PSym =
|
||||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||||
result = s.kind in skProcKinds
|
result = s.kind in skProcKinds
|
||||||
|
|
||||||
|
proc isCompileTimeProc*(s: PSym): bool {.inline.} =
|
||||||
|
result = s.kind == skMacro or
|
||||||
|
s.kind == skProc and sfCompileTime in s.flags
|
||||||
|
|
||||||
|
proc requiredParams*(s: PSym): int =
|
||||||
|
# Returns the number of required params (without default values)
|
||||||
|
# XXX: Perhaps we can store this in the `offset` field of the
|
||||||
|
# symbol instead?
|
||||||
|
for i in 1 ..< s.typ.len:
|
||||||
|
if s.typ.n[i].sym.ast != nil:
|
||||||
|
return i - 1
|
||||||
|
return s.typ.len - 1
|
||||||
|
|
||||||
proc hasPattern*(s: PSym): bool {.inline.} =
|
proc hasPattern*(s: PSym): bool {.inline.} =
|
||||||
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
|
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
|
||||||
|
|
||||||
|
|
@ -1676,7 +1689,7 @@ proc isException*(t: PType): bool =
|
||||||
|
|
||||||
var base = t
|
var base = t
|
||||||
while base != nil:
|
while base != nil:
|
||||||
if base.sym.magic == mException:
|
if base.sym != nil and base.sym.magic == mException:
|
||||||
return true
|
return true
|
||||||
base = base.lastSon
|
base = base.lastSon
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -69,22 +69,22 @@ proc debug*(n: PNode) {.deprecated.}
|
||||||
|
|
||||||
template mdbg*: bool {.dirty.} =
|
template mdbg*: bool {.dirty.} =
|
||||||
when compiles(c.module):
|
when compiles(c.module):
|
||||||
c.module.fileIdx == gProjectMainIdx
|
c.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(c.c.module):
|
elif compiles(c.c.module):
|
||||||
c.c.module.fileIdx == gProjectMainIdx
|
c.c.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(m.c.module):
|
elif compiles(m.c.module):
|
||||||
m.c.module.fileIdx == gProjectMainIdx
|
m.c.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(cl.c.module):
|
elif compiles(cl.c.module):
|
||||||
cl.c.module.fileIdx == gProjectMainIdx
|
cl.c.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(p):
|
elif compiles(p):
|
||||||
when compiles(p.lex):
|
when compiles(p.lex):
|
||||||
p.lex.fileIdx == gProjectMainIdx
|
p.lex.fileIdx.int32 == gProjectMainIdx
|
||||||
else:
|
else:
|
||||||
p.module.module.fileIdx == gProjectMainIdx
|
p.module.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(m.module.fileIdx):
|
elif compiles(m.module.fileIdx):
|
||||||
m.module.fileIdx == gProjectMainIdx
|
m.module.fileIdx.int32 == gProjectMainIdx
|
||||||
elif compiles(L.fileIdx):
|
elif compiles(L.fileIdx):
|
||||||
L.fileIdx == gProjectMainIdx
|
L.fileIdx.int32 == gProjectMainIdx
|
||||||
else:
|
else:
|
||||||
error()
|
error()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
|
||||||
# if the template has zero arguments, it can be called without ``()``
|
# if the template has zero arguments, it can be called without ``()``
|
||||||
# `n` is then a nkSym or something similar
|
# `n` is then a nkSym or something similar
|
||||||
var totalParams = case n.kind
|
var totalParams = case n.kind
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1
|
of nkCallKinds: n.len-1
|
||||||
else: 0
|
else: 0
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -70,9 +70,9 @@ proc parseLine(p: var TTmplParser) =
|
||||||
|
|
||||||
while j <= hi and p.x[j] == ' ': inc(j)
|
while j <= hi and p.x[j] == ' ': inc(j)
|
||||||
|
|
||||||
if p.x[0] == p.nimDirective and p.x[1] == '?':
|
if p.x.len >= 2 and p.x[0] == p.nimDirective and p.x[1] == '?':
|
||||||
newLine(p)
|
newLine(p)
|
||||||
elif p.x[j] == p.nimDirective:
|
elif j < p.x.len and p.x[j] == p.nimDirective:
|
||||||
newLine(p)
|
newLine(p)
|
||||||
inc(j)
|
inc(j)
|
||||||
while j <= hi and p.x[j] == ' ': inc(j)
|
while j <= hi and p.x[j] == ' ': inc(j)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@ import
|
||||||
proc evalImport*(c: PContext, n: PNode): PNode
|
proc evalImport*(c: PContext, n: PNode): PNode
|
||||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
|
proc readExceptSet*(c: PContext, n: PNode): IntSet =
|
||||||
|
assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
|
||||||
|
result = initIntSet()
|
||||||
|
for i in 1 ..< n.len:
|
||||||
|
let ident = lookups.considerQuotedIdent(c.config, n[i])
|
||||||
|
result.incl(ident.id)
|
||||||
|
|
||||||
proc importPureEnumField*(c: PContext; s: PSym) =
|
proc importPureEnumField*(c: PContext; s: PSym) =
|
||||||
var check = strTableGet(c.importTable.symbols, s.name)
|
var check = strTableGet(c.importTable.symbols, s.name)
|
||||||
if check == nil:
|
if check == nil:
|
||||||
|
|
@ -199,9 +206,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||||
if m != nil:
|
if m != nil:
|
||||||
n.sons[0] = newSymNode(m)
|
n.sons[0] = newSymNode(m)
|
||||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||||
var exceptSet = initIntSet()
|
importAllSymbolsExcept(c, m, readExceptSet(c, n))
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
|
||||||
let ident = lookups.considerQuotedIdent(c.config, n.sons[i])
|
|
||||||
exceptSet.incl(ident.id)
|
|
||||||
importAllSymbolsExcept(c, m, exceptSet)
|
|
||||||
#importForwarded(c, m.ast, exceptSet)
|
#importForwarded(c, m.ast, exceptSet)
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
|
||||||
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
|
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
|
||||||
cache: IdentCache): PSym {.procvar.} =
|
cache: IdentCache): PSym {.procvar.} =
|
||||||
# this is called by the semantic checking phase
|
# this is called by the semantic checking phase
|
||||||
|
assert graph.config != nil
|
||||||
result = compileModule(graph, fileIdx, cache, {})
|
result = compileModule(graph, fileIdx, cache, {})
|
||||||
graph.addDep(s, fileIdx)
|
graph.addDep(s, fileIdx)
|
||||||
#if sfSystemModule in result.flags:
|
#if sfSystemModule in result.flags:
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import strutils, lexbase, streams
|
import strutils, lexbase, streams
|
||||||
import "../compiler" / [ast, msgs, idents]
|
import ".." / [ast, msgs, idents]
|
||||||
from os import splitFile
|
from os import splitFile
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -713,10 +713,17 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
exprColonEqExprListAux(p, endTok, result)
|
exprColonEqExprListAux(p, endTok, result)
|
||||||
|
|
||||||
proc commandParam(p: var TParser): PNode =
|
proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
|
||||||
result = parseExpr(p)
|
result = parseExpr(p)
|
||||||
if p.tok.tokType == tkDo:
|
if p.tok.tokType == tkDo:
|
||||||
result = postExprBlocks(p, result)
|
result = postExprBlocks(p, result)
|
||||||
|
elif p.tok.tokType == tkEquals and not isFirstParam:
|
||||||
|
let lhs = result
|
||||||
|
result = newNodeP(nkExprEqExpr, p)
|
||||||
|
getTok(p)
|
||||||
|
addSon(result, lhs)
|
||||||
|
addSon(result, parseExpr(p))
|
||||||
|
isFirstParam = false
|
||||||
|
|
||||||
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
|
|
@ -759,10 +766,11 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||||
let a = result
|
let a = result
|
||||||
result = newNodeP(nkCommand, p)
|
result = newNodeP(nkCommand, p)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
|
var isFirstParam = true
|
||||||
when true:
|
when true:
|
||||||
# progress NOT guaranteed
|
# progress NOT guaranteed
|
||||||
p.hasProgress = false
|
p.hasProgress = false
|
||||||
addSon result, commandParam(p)
|
addSon result, commandParam(p, isFirstParam)
|
||||||
if not p.hasProgress: break
|
if not p.hasProgress: break
|
||||||
else:
|
else:
|
||||||
while p.tok.tokType != tkEof:
|
while p.tok.tokType != tkEof:
|
||||||
|
|
@ -1314,17 +1322,18 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
else:
|
else:
|
||||||
# simpleExpr parsed 'p a' from 'p a, b'?
|
# simpleExpr parsed 'p a' from 'p a, b'?
|
||||||
|
var isFirstParam = false
|
||||||
if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
|
if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
|
||||||
result = a
|
result = a
|
||||||
while true:
|
while true:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
addSon(result, commandParam(p))
|
addSon(result, commandParam(p, isFirstParam))
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
elif p.tok.indent < 0 and isExprStart(p):
|
elif p.tok.indent < 0 and isExprStart(p):
|
||||||
result = newNode(nkCommand, a.info, @[a])
|
result = newNode(nkCommand, a.info, @[a])
|
||||||
while true:
|
while true:
|
||||||
addSon(result, commandParam(p))
|
addSon(result, commandParam(p, isFirstParam))
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
|
|
|
||||||
|
|
@ -781,7 +781,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
incl(sym.flags, sfRegister)
|
incl(sym.flags, sfRegister)
|
||||||
of wThreadVar:
|
of wThreadVar:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
incl(sym.flags, sfThread)
|
incl(sym.flags, {sfThread, sfGlobal})
|
||||||
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
||||||
of wNoForward: pragmaNoForward(c, it)
|
of wNoForward: pragmaNoForward(c, it)
|
||||||
of wReorder: pragmaNoForward(c, it, sfReorder)
|
of wReorder: pragmaNoForward(c, it, sfReorder)
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ type
|
||||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
inGenericContext*: int # > 0 if we are in a generic type
|
inGenericContext*: int # > 0 if we are in a generic type
|
||||||
|
inStaticContext*: int # > 0 if we are inside a static: block
|
||||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||||
compilesContextIdGenerator*: int
|
compilesContextIdGenerator*: int
|
||||||
|
|
|
||||||
|
|
@ -972,18 +972,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
|
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||||
|
(n.kind notin nkCallKinds and s.requiredParams > 0):
|
||||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
result = newSymNode(s, n.info)
|
result = symChoice(c, n, s, scClosed)
|
||||||
else:
|
else:
|
||||||
result = semMacroExpr(c, n, n, s, flags)
|
result = semMacroExpr(c, n, n, s, flags)
|
||||||
of skTemplate:
|
of skTemplate:
|
||||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||||
|
(n.kind notin nkCallKinds and s.requiredParams > 0) or
|
||||||
sfCustomPragma in sym.flags:
|
sfCustomPragma in sym.flags:
|
||||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
result = newSymNode(s, n.info)
|
result = symChoice(c, n, s, scClosed)
|
||||||
else:
|
else:
|
||||||
result = semTemplateExpr(c, n, s, flags)
|
result = semTemplateExpr(c, n, s, flags)
|
||||||
of skParam:
|
of skParam:
|
||||||
|
|
@ -1785,6 +1787,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
let oldInGenericContext = c.inGenericContext
|
let oldInGenericContext = c.inGenericContext
|
||||||
let oldInUnrolledContext = c.inUnrolledContext
|
let oldInUnrolledContext = c.inUnrolledContext
|
||||||
let oldInGenericInst = c.inGenericInst
|
let oldInGenericInst = c.inGenericInst
|
||||||
|
let oldInStaticContext = c.inStaticContext
|
||||||
let oldProcCon = c.p
|
let oldProcCon = c.p
|
||||||
c.generics = @[]
|
c.generics = @[]
|
||||||
var err: string
|
var err: string
|
||||||
|
|
@ -1799,6 +1802,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
c.inGenericContext = oldInGenericContext
|
c.inGenericContext = oldInGenericContext
|
||||||
c.inUnrolledContext = oldInUnrolledContext
|
c.inUnrolledContext = oldInUnrolledContext
|
||||||
c.inGenericInst = oldInGenericInst
|
c.inGenericInst = oldInGenericInst
|
||||||
|
c.inStaticContext = oldInStaticContext
|
||||||
c.p = oldProcCon
|
c.p = oldProcCon
|
||||||
msgs.setInfoContextLen(oldContextLen)
|
msgs.setInfoContextLen(oldContextLen)
|
||||||
setLen(c.graph.owners, oldOwnerLen)
|
setLen(c.graph.owners, oldOwnerLen)
|
||||||
|
|
@ -2163,9 +2167,25 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedBlockCounter)
|
dec(c.p.nestedBlockCounter)
|
||||||
|
|
||||||
|
proc semExportExcept(c: PContext, n: PNode): PNode =
|
||||||
|
let moduleName = semExpr(c, n[0])
|
||||||
|
if moduleName.kind != nkSym or moduleName.sym.kind != skModule:
|
||||||
|
localError(c.config, n.info, "The export/except syntax expects a module name")
|
||||||
|
return n
|
||||||
|
let exceptSet = readExceptSet(c, n)
|
||||||
|
let exported = moduleName.sym
|
||||||
|
strTableAdd(c.module.tab, exported)
|
||||||
|
var i: TTabIter
|
||||||
|
var s = initTabIter(i, exported.tab)
|
||||||
|
while s != nil:
|
||||||
|
if s.kind in ExportableSymKinds+{skModule} and
|
||||||
|
s.name.id notin exceptSet:
|
||||||
|
strTableAdd(c.module.tab, s)
|
||||||
|
s = nextIter(i, exported.tab)
|
||||||
|
result = n
|
||||||
|
|
||||||
proc semExport(c: PContext, n: PNode): PNode =
|
proc semExport(c: PContext, n: PNode): PNode =
|
||||||
var x = newNodeI(n.kind, n.info)
|
var x = newNodeI(n.kind, n.info)
|
||||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
let a = n.sons[i]
|
let a = n.sons[i]
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
|
|
@ -2451,9 +2471,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkIncludeStmt:
|
of nkIncludeStmt:
|
||||||
#if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include")
|
#if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include")
|
||||||
result = evalInclude(c, n)
|
result = evalInclude(c, n)
|
||||||
of nkExportStmt, nkExportExceptStmt:
|
of nkExportStmt:
|
||||||
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
||||||
result = semExport(c, n)
|
result = semExport(c, n)
|
||||||
|
of nkExportExceptStmt:
|
||||||
|
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
||||||
|
result = semExportExcept(c, n)
|
||||||
of nkPragmaBlock:
|
of nkPragmaBlock:
|
||||||
result = semPragmaBlock(c, n)
|
result = semPragmaBlock(c, n)
|
||||||
of nkStaticStmt:
|
of nkStaticStmt:
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,10 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||||
if s != nil:
|
if s != nil:
|
||||||
# we need to mark all symbols:
|
# we need to mark all symbols:
|
||||||
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
||||||
|
if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc):
|
||||||
|
# inside regular code, bindSym resolves to the sym-choice
|
||||||
|
# nodes (see tinspectsymbol)
|
||||||
|
return sc
|
||||||
result.add(sc)
|
result.add(sc)
|
||||||
else:
|
else:
|
||||||
errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
|
errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
|
||||||
|
|
|
||||||
|
|
@ -1765,7 +1765,9 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
#echo "semStaticStmt"
|
#echo "semStaticStmt"
|
||||||
#writeStackTrace()
|
#writeStackTrace()
|
||||||
|
inc c.inStaticContext
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0])
|
||||||
|
dec c.inStaticContext
|
||||||
n.sons[0] = a
|
n.sons[0] = a
|
||||||
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner)
|
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner)
|
||||||
result = newNodeI(nkDiscardStmt, n.info, 1)
|
result = newNodeI(nkDiscardStmt, n.info, 1)
|
||||||
|
|
|
||||||
|
|
@ -1964,7 +1964,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
if arg.typ == nil:
|
if arg.typ == nil:
|
||||||
result = arg
|
result = arg
|
||||||
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
|
||||||
|
m.inheritancePenalty > 0:
|
||||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||||
elif arg.typ.isEmptyContainer:
|
elif arg.typ.isEmptyContainer:
|
||||||
result = arg.copyTree
|
result = arg.copyTree
|
||||||
|
|
@ -2034,8 +2035,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
y.calleeSym = m.calleeSym
|
y.calleeSym = m.calleeSym
|
||||||
z.calleeSym = m.calleeSym
|
z.calleeSym = m.calleeSym
|
||||||
var best = -1
|
var best = -1
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in 0 ..< arg.len:
|
||||||
if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
|
if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
|
||||||
|
skIterator, skMacro, skTemplate}:
|
||||||
copyCandidate(z, m)
|
copyCandidate(z, m)
|
||||||
z.callee = arg.sons[i].typ
|
z.callee = arg.sons[i].typ
|
||||||
if tfUnresolved in z.callee.flags: continue
|
if tfUnresolved in z.callee.flags: continue
|
||||||
|
|
@ -2064,6 +2066,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
x = z
|
x = z
|
||||||
elif cmp == 0:
|
elif cmp == 0:
|
||||||
y = z # z is as good as x
|
y = z # z is as good as x
|
||||||
|
|
||||||
if x.state == csEmpty:
|
if x.state == csEmpty:
|
||||||
result = nil
|
result = nil
|
||||||
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
||||||
|
|
@ -2072,7 +2075,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
# ambiguous: more than one symbol fits!
|
# ambiguous: more than one symbol fits!
|
||||||
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
||||||
# anyway:
|
# anyway:
|
||||||
if f.kind == tyExpr: result = arg
|
if f.kind in {tyExpr, tyStmt}: result = arg
|
||||||
else: result = nil
|
else: result = nil
|
||||||
else:
|
else:
|
||||||
# only one valid interpretation found:
|
# only one valid interpretation found:
|
||||||
|
|
@ -2172,7 +2175,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil
|
var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil
|
||||||
|
|
||||||
while a < n.len:
|
while a < n.len:
|
||||||
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
|
if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped:
|
||||||
|
formal = m.callee.n.sons[f].sym
|
||||||
incl(marker, formal.position)
|
incl(marker, formal.position)
|
||||||
if container.isNil:
|
if container.isNil:
|
||||||
container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
|
container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||||
of filtReplace:
|
of filtReplace:
|
||||||
result = filterReplace(p.config, stdin, filename, n)
|
result = filterReplace(p.config, stdin, filename, n)
|
||||||
if f != filtNone:
|
if f != filtNone:
|
||||||
|
assert p.config != nil
|
||||||
if hintCodeBegin in p.config.notes:
|
if hintCodeBegin in p.config.notes:
|
||||||
rawMessage(p.config, hintCodeBegin, [])
|
rawMessage(p.config, hintCodeBegin, [])
|
||||||
msgWriteln(p.config, result.s)
|
msgWriteln(p.config, result.s)
|
||||||
|
|
@ -124,6 +125,7 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string,
|
||||||
|
|
||||||
proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||||
start: PLLStream): PLLStream =
|
start: PLLStream): PLLStream =
|
||||||
|
assert p.config != nil
|
||||||
result = start
|
result = start
|
||||||
if n.kind == nkEmpty: return
|
if n.kind == nkEmpty: return
|
||||||
if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
|
if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
|
||||||
|
|
@ -139,10 +141,12 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||||
|
|
||||||
proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
|
proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
|
||||||
cache: IdentCache; config: ConfigRef) =
|
cache: IdentCache; config: ConfigRef) =
|
||||||
|
assert config != nil
|
||||||
var s: PLLStream
|
var s: PLLStream
|
||||||
p.skin = skinStandard
|
p.skin = skinStandard
|
||||||
let filename = fileIdx.toFullPathConsiderDirty
|
let filename = fileIdx.toFullPathConsiderDirty
|
||||||
var pipe = parsePipe(filename, inputstream, cache, config)
|
var pipe = parsePipe(filename, inputstream, cache, config)
|
||||||
|
p.config() = config
|
||||||
if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
|
if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
|
||||||
else: s = inputstream
|
else: s = inputstream
|
||||||
case p.skin
|
case p.skin
|
||||||
|
|
|
||||||
|
|
@ -614,7 +614,7 @@ proc firstOrd*(t: PType): BiggestInt =
|
||||||
else:
|
else:
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
result = t.n.sons[0].sym.position
|
result = t.n.sons[0].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
|
||||||
result = firstOrd(lastSon(t))
|
result = firstOrd(lastSon(t))
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if t.len > 0: result = firstOrd(lastSon(t))
|
if t.len > 0: result = firstOrd(lastSon(t))
|
||||||
|
|
@ -653,7 +653,7 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
|
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
|
||||||
result = lastOrd(lastSon(t))
|
result = lastOrd(lastSon(t))
|
||||||
of tyProxy: result = 0
|
of tyProxy: result = 0
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
|
|
|
||||||
|
|
@ -210,8 +210,14 @@ proc putIntoNode(n: var PNode; x: TFullReg) =
|
||||||
of rkInt: n.intVal = x.intVal
|
of rkInt: n.intVal = x.intVal
|
||||||
of rkFloat: n.floatVal = x.floatVal
|
of rkFloat: n.floatVal = x.floatVal
|
||||||
of rkNode:
|
of rkNode:
|
||||||
if nfIsRef in x.node.flags: n = x.node
|
if nfIsRef in x.node.flags:
|
||||||
else: n[] = x.node[]
|
n = x.node
|
||||||
|
else:
|
||||||
|
let destIsRef = nfIsRef in n.flags
|
||||||
|
n[] = x.node[]
|
||||||
|
# Ref-ness must be kept for the destination
|
||||||
|
if destIsRef:
|
||||||
|
n.flags.incl nfIsRef
|
||||||
of rkRegisterAddr: putIntoNode(n, x.regAddr[])
|
of rkRegisterAddr: putIntoNode(n, x.regAddr[])
|
||||||
of rkNodeAddr: n[] = x.nodeAddr[][]
|
of rkNodeAddr: n[] = x.nodeAddr[][]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ path="$lib/pure"
|
||||||
# Configuration for the GNU C/C++ compiler:
|
# Configuration for the GNU C/C++ compiler:
|
||||||
@if windows:
|
@if windows:
|
||||||
#gcc.path = r"$nim\dist\mingw\bin"
|
#gcc.path = r"$nim\dist\mingw\bin"
|
||||||
@if gcc:
|
@if gcc or tcc:
|
||||||
tlsEmulation:on
|
tlsEmulation:on
|
||||||
@end
|
@end
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
|
|
@ -6298,6 +6298,9 @@ modules don't need to import a module's dependencies:
|
||||||
var x: MyObject
|
var x: MyObject
|
||||||
echo $x
|
echo $x
|
||||||
|
|
||||||
|
When the exported symbol is another module, all of its definitions will
|
||||||
|
be forwarded. You can use an ``except`` list to exclude some of the symbols.
|
||||||
|
|
||||||
Note on paths
|
Note on paths
|
||||||
-----------
|
-----------
|
||||||
In module related statements, if any part of the module name /
|
In module related statements, if any part of the module name /
|
||||||
|
|
@ -7798,8 +7801,9 @@ Future directions:
|
||||||
Threadvar pragma
|
Threadvar pragma
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
A global variable can be marked with the ``threadvar`` pragma; it is
|
A variable can be marked with the ``threadvar`` pragma, which makes it a
|
||||||
a `thread-local`:idx: variable then:
|
`thread-local`:idx: variable; Additionally, this implies all the effects
|
||||||
|
of the ``global`` pragma.
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
var checkpoints* {.threadvar.}: seq[string]
|
var checkpoints* {.threadvar.}: seq[string]
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ type
|
||||||
|
|
||||||
{.deprecated: [TBindSymRule: BindSymRule].}
|
{.deprecated: [TBindSymRule: BindSymRule].}
|
||||||
|
|
||||||
proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
|
proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {.
|
||||||
magic: "NBindSym", noSideEffect.}
|
magic: "NBindSym", noSideEffect.}
|
||||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||||
## may be an overloaded symbol.
|
## may be an overloaded symbol.
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ proc tryExec*(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string, `$`]): bool {.
|
args: varargs[string, `$`]): bool {.
|
||||||
tags: [ReadDbEffect, WriteDbEffect].} =
|
tags: [ReadDbEffect, WriteDbEffect].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
|
assert(not db.isNil, "Database not connected.")
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
var stmt: sqlite3.Pstmt
|
var stmt: sqlite3.Pstmt
|
||||||
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
|
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
|
||||||
|
|
@ -144,6 +145,7 @@ proc newRow(L: int): Row =
|
||||||
|
|
||||||
proc setupQuery(db: DbConn, query: SqlQuery,
|
proc setupQuery(db: DbConn, query: SqlQuery,
|
||||||
args: varargs[string]): Pstmt =
|
args: varargs[string]): Pstmt =
|
||||||
|
assert(not db.isNil, "Database not connected.")
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
|
if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
|
||||||
|
|
||||||
|
|
@ -267,6 +269,7 @@ proc tryInsertID*(db: DbConn, query: SqlQuery,
|
||||||
{.tags: [WriteDbEffect], raises: [].} =
|
{.tags: [WriteDbEffect], raises: [].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error.
|
## generated ID for the row or -1 in case of an error.
|
||||||
|
assert(not db.isNil, "Database not connected.")
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
var stmt: sqlite3.Pstmt
|
var stmt: sqlite3.Pstmt
|
||||||
result = -1
|
result = -1
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ type
|
||||||
frames*: seq[TFrame]
|
frames*: seq[TFrame]
|
||||||
screen*: Screen
|
screen*: Screen
|
||||||
performance*: Performance
|
performance*: Performance
|
||||||
|
onpopstate*: proc (event: Event)
|
||||||
|
|
||||||
Frame* = ref FrameObj
|
Frame* = ref FrameObj
|
||||||
FrameObj {.importc.} = object of WindowObj
|
FrameObj {.importc.} = object of WindowObj
|
||||||
|
|
@ -175,6 +176,12 @@ type
|
||||||
text*: cstring
|
text*: cstring
|
||||||
value*: cstring
|
value*: cstring
|
||||||
|
|
||||||
|
TextAreaElement* = ref object of ElementObj
|
||||||
|
value*: cstring
|
||||||
|
selectionStart*, selectionEnd*: int
|
||||||
|
selectionDirection*: cstring
|
||||||
|
rows*, cols*: int
|
||||||
|
|
||||||
FormElement* = ref FormObj
|
FormElement* = ref FormObj
|
||||||
FormObj {.importc.} = object of ElementObj
|
FormObj {.importc.} = object of ElementObj
|
||||||
action*: cstring
|
action*: cstring
|
||||||
|
|
@ -446,6 +453,7 @@ type
|
||||||
proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
|
proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
|
||||||
proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), options: AddEventListenerOptions)
|
proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), options: AddEventListenerOptions)
|
||||||
proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
|
proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
|
||||||
|
proc dispatchEvent*(et: EventTarget, ev: Event)
|
||||||
|
|
||||||
# Window "methods"
|
# Window "methods"
|
||||||
proc alert*(w: Window, msg: cstring)
|
proc alert*(w: Window, msg: cstring)
|
||||||
|
|
@ -500,7 +508,7 @@ proc removeAttributeNode*(n, attr: Node)
|
||||||
proc removeChild*(n, child: Node)
|
proc removeChild*(n, child: Node)
|
||||||
proc replaceChild*(n, newNode, oldNode: Node)
|
proc replaceChild*(n, newNode, oldNode: Node)
|
||||||
proc replaceData*(n: Node, start, len: int, text: cstring)
|
proc replaceData*(n: Node, start, len: int, text: cstring)
|
||||||
proc scrollIntoView*(n: Node)
|
proc scrollIntoView*(n: Node, alignToTop: bool=true)
|
||||||
proc setAttribute*(n: Node, name, value: cstring)
|
proc setAttribute*(n: Node, name, value: cstring)
|
||||||
proc setAttributeNode*(n: Node, attr: Node)
|
proc setAttributeNode*(n: Node, attr: Node)
|
||||||
|
|
||||||
|
|
@ -596,6 +604,7 @@ proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
|
||||||
proc parseInt*(s: cstring): int {.importc, nodecl.}
|
proc parseInt*(s: cstring): int {.importc, nodecl.}
|
||||||
proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
|
proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
|
||||||
|
|
||||||
|
proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TEventHandlers* {.deprecated.} = EventTargetObj
|
TEventHandlers* {.deprecated.} = EventTargetObj
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,13 @@ iterator items*[A](s: HashSet[A]): A =
|
||||||
for h in 0..high(s.data):
|
for h in 0..high(s.data):
|
||||||
if isFilled(s.data[h].hcode): yield s.data[h].key
|
if isFilled(s.data[h].hcode): yield s.data[h].key
|
||||||
|
|
||||||
|
proc hash*[A](s: HashSet[A]): Hash =
|
||||||
|
## hashing of HashSet
|
||||||
|
assert s.isValid, "The set needs to be initialized."
|
||||||
|
for h in 0..high(s.data):
|
||||||
|
result = result xor s.data[h].hcode
|
||||||
|
result = !$result
|
||||||
|
|
||||||
const
|
const
|
||||||
growthFactor = 2
|
growthFactor = 2
|
||||||
|
|
||||||
|
|
@ -690,6 +697,13 @@ iterator items*[A](s: OrderedSet[A]): A =
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield s.data[h].key
|
yield s.data[h].key
|
||||||
|
|
||||||
|
proc hash*[A](s: OrderedSet[A]): Hash =
|
||||||
|
## hashing of OrderedSet
|
||||||
|
assert s.isValid, "The set needs to be initialized."
|
||||||
|
forAllOrderedPairs:
|
||||||
|
result = result !& s.data[h].hcode
|
||||||
|
result = !$result
|
||||||
|
|
||||||
iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
|
iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
|
||||||
assert s.isValid, "The set needs to be initialized"
|
assert s.isValid, "The set needs to be initialized"
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ proc slave(w: ptr Worker) {.thread.} =
|
||||||
await(w.taskArrived)
|
await(w.taskArrived)
|
||||||
# XXX Somebody needs to look into this (why does this assertion fail
|
# XXX Somebody needs to look into this (why does this assertion fail
|
||||||
# in Visual Studio?)
|
# in Visual Studio?)
|
||||||
when not defined(vcc): assert(not w.ready)
|
when not defined(vcc) and not defined(tcc): assert(not w.ready)
|
||||||
|
|
||||||
withLock numSlavesLock:
|
withLock numSlavesLock:
|
||||||
inc numSlavesRunning
|
inc numSlavesRunning
|
||||||
|
|
|
||||||
|
|
@ -960,7 +960,7 @@ when defined(posix) and not defined(nimdoc):
|
||||||
raise newException(ValueError, "socket path too long")
|
raise newException(ValueError, "socket path too long")
|
||||||
copyMem(addr result.sun_path, path.cstring, path.len + 1)
|
copyMem(addr result.sun_path, path.cstring, path.len + 1)
|
||||||
|
|
||||||
when defined(posix):
|
when defined(posix) or defined(nimdoc):
|
||||||
proc connectUnix*(socket: Socket, path: string) =
|
proc connectUnix*(socket: Socket, path: string) =
|
||||||
## Connects to Unix socket on `path`.
|
## Connects to Unix socket on `path`.
|
||||||
## This only works on Unix-style systems: Mac OS X, BSD and Linux
|
## This only works on Unix-style systems: Mac OS X, BSD and Linux
|
||||||
|
|
|
||||||
|
|
@ -1262,21 +1262,20 @@ proc initSkipTable*(a: var SkipTable, sub: string)
|
||||||
{.noSideEffect, rtl, extern: "nsuInitSkipTable".} =
|
{.noSideEffect, rtl, extern: "nsuInitSkipTable".} =
|
||||||
## Preprocess table `a` for `sub`.
|
## Preprocess table `a` for `sub`.
|
||||||
let m = len(sub)
|
let m = len(sub)
|
||||||
let m1 = m + 1
|
|
||||||
var i = 0
|
var i = 0
|
||||||
while i <= 0xff-7:
|
while i <= 0xff-7:
|
||||||
a[chr(i + 0)] = m1
|
a[chr(i + 0)] = m
|
||||||
a[chr(i + 1)] = m1
|
a[chr(i + 1)] = m
|
||||||
a[chr(i + 2)] = m1
|
a[chr(i + 2)] = m
|
||||||
a[chr(i + 3)] = m1
|
a[chr(i + 3)] = m
|
||||||
a[chr(i + 4)] = m1
|
a[chr(i + 4)] = m
|
||||||
a[chr(i + 5)] = m1
|
a[chr(i + 5)] = m
|
||||||
a[chr(i + 6)] = m1
|
a[chr(i + 6)] = m
|
||||||
a[chr(i + 7)] = m1
|
a[chr(i + 7)] = m
|
||||||
i += 8
|
i += 8
|
||||||
|
|
||||||
for i in 0..m-1:
|
for i in 0 ..< m - 1:
|
||||||
a[sub[i]] = m-i
|
a[sub[i]] = m - 1 - i
|
||||||
|
|
||||||
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
|
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
|
||||||
{.noSideEffect, rtl, extern: "nsuFindStrA".} =
|
{.noSideEffect, rtl, extern: "nsuFindStrA".} =
|
||||||
|
|
@ -1284,18 +1283,29 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0):
|
||||||
## If `last` is unspecified, it defaults to `s.high`.
|
## If `last` is unspecified, it defaults to `s.high`.
|
||||||
##
|
##
|
||||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||||
|
|
||||||
let
|
let
|
||||||
last = if last==0: s.high else: last
|
last = if last==0: s.high else: last
|
||||||
m = len(sub)
|
sLen = last - start + 1
|
||||||
n = last + 1
|
subLast = sub.len - 1
|
||||||
# search:
|
|
||||||
var j = start
|
if subLast == -1:
|
||||||
while j <= n - m:
|
# this was an empty needle string,
|
||||||
block match:
|
# we count this as match in the first possible position:
|
||||||
for k in 0..m-1:
|
return start
|
||||||
if sub[k] != s[k+j]: break match
|
|
||||||
return j
|
# This is an implementation of the Boyer-Moore Horspool algorithms
|
||||||
inc(j, a[s[j+m]])
|
# https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
|
||||||
|
var skip = start
|
||||||
|
|
||||||
|
while last - skip >= subLast:
|
||||||
|
var i = subLast
|
||||||
|
while s[skip + i] == sub[i]:
|
||||||
|
if i == 0:
|
||||||
|
return skip
|
||||||
|
dec i
|
||||||
|
inc skip, a[s[skip + subLast]]
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
when not (defined(js) or defined(nimdoc) or defined(nimscript)):
|
when not (defined(js) or defined(nimdoc) or defined(nimscript)):
|
||||||
|
|
@ -1455,8 +1465,30 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
|
||||||
proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
rtl, extern: "nsuReplaceStr".} =
|
rtl, extern: "nsuReplaceStr".} =
|
||||||
## Replaces `sub` in `s` by the string `by`.
|
## Replaces `sub` in `s` by the string `by`.
|
||||||
var a {.noinit.}: SkipTable
|
|
||||||
result = ""
|
result = ""
|
||||||
|
let subLen = sub.len
|
||||||
|
if subLen == 0:
|
||||||
|
for c in s:
|
||||||
|
add result, by
|
||||||
|
add result, c
|
||||||
|
add result, by
|
||||||
|
return
|
||||||
|
elif subLen == 1:
|
||||||
|
# when the pattern is a single char, we use a faster
|
||||||
|
# char-based search that doesn't need a skip table:
|
||||||
|
var c = sub[0]
|
||||||
|
let last = s.high
|
||||||
|
var i = 0
|
||||||
|
while true:
|
||||||
|
let j = find(s, c, i, last)
|
||||||
|
if j < 0: break
|
||||||
|
add result, substr(s, i, j - 1)
|
||||||
|
add result, by
|
||||||
|
i = j + subLen
|
||||||
|
# copy the rest:
|
||||||
|
add result, substr(s, i)
|
||||||
|
else:
|
||||||
|
var a {.noinit.}: SkipTable
|
||||||
initSkipTable(a, sub)
|
initSkipTable(a, sub)
|
||||||
let last = s.high
|
let last = s.high
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -1465,11 +1497,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
if j < 0: break
|
if j < 0: break
|
||||||
add result, substr(s, i, j - 1)
|
add result, substr(s, i, j - 1)
|
||||||
add result, by
|
add result, by
|
||||||
if sub.len == 0:
|
i = j + subLen
|
||||||
if i < s.len: add result, s[i]
|
|
||||||
i = j + 1
|
|
||||||
else:
|
|
||||||
i = j + sub.len
|
|
||||||
# copy the rest:
|
# copy the rest:
|
||||||
add result, substr(s, i)
|
add result, substr(s, i)
|
||||||
|
|
||||||
|
|
@ -1492,6 +1520,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
## Each occurrence of `sub` has to be surrounded by word boundaries
|
## Each occurrence of `sub` has to be surrounded by word boundaries
|
||||||
## (comparable to ``\\w`` in regular expressions), otherwise it is not
|
## (comparable to ``\\w`` in regular expressions), otherwise it is not
|
||||||
## replaced.
|
## replaced.
|
||||||
|
if sub.len == 0: return s
|
||||||
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||||
var a {.noinit.}: SkipTable
|
var a {.noinit.}: SkipTable
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -2326,6 +2355,57 @@ proc removePrefix*(s: var string, prefix: string) {.
|
||||||
s.delete(0, prefix.len - 1)
|
s.delete(0, prefix.len - 1)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
|
proc nonStaticTests =
|
||||||
|
doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
|
||||||
|
doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235."
|
||||||
|
doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
|
||||||
|
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
||||||
|
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
|
||||||
|
["1,0e-11", "1,0e-011"]
|
||||||
|
# bug #6589
|
||||||
|
doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
|
||||||
|
|
||||||
|
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||||
|
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
||||||
|
|
||||||
|
block: # formatSize tests
|
||||||
|
doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
|
||||||
|
doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
|
||||||
|
doAssert formatSize(4096) == "4KiB"
|
||||||
|
doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
|
||||||
|
doAssert formatSize(4096, includeSpace=true) == "4 KiB"
|
||||||
|
doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
|
||||||
|
|
||||||
|
block: # formatEng tests
|
||||||
|
doAssert formatEng(0, 2, trim=false) == "0.00"
|
||||||
|
doAssert formatEng(0, 2) == "0"
|
||||||
|
doAssert formatEng(53, 2, trim=false) == "53.00"
|
||||||
|
doAssert formatEng(0.053, 2, trim=false) == "53.00e-3"
|
||||||
|
doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3"
|
||||||
|
doAssert formatEng(0.053, 4, trim=true) == "53e-3"
|
||||||
|
doAssert formatEng(0.053, 0) == "53e-3"
|
||||||
|
doAssert formatEng(52731234) == "52.731234e6"
|
||||||
|
doAssert formatEng(-52731234) == "-52.731234e6"
|
||||||
|
doAssert formatEng(52731234, 1) == "52.7e6"
|
||||||
|
doAssert formatEng(-52731234, 1) == "-52.7e6"
|
||||||
|
doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6"
|
||||||
|
doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6"
|
||||||
|
|
||||||
|
doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
|
||||||
|
doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V"
|
||||||
|
doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
|
||||||
|
doAssert formatEng(4100, siPrefix=true) == "4.1 k"
|
||||||
|
doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space
|
||||||
|
doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k"
|
||||||
|
doAssert formatEng(4100) == "4.1e3"
|
||||||
|
doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V"
|
||||||
|
doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 "
|
||||||
|
# Don't use SI prefix as number is too big
|
||||||
|
doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a"
|
||||||
|
# Don't use SI prefix as number is too small
|
||||||
|
doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A"
|
||||||
|
|
||||||
|
proc staticTests =
|
||||||
doAssert align("abc", 4) == " abc"
|
doAssert align("abc", 4) == " abc"
|
||||||
doAssert align("a", 0) == "a"
|
doAssert align("a", 0) == "a"
|
||||||
doAssert align("1232", 6) == " 1232"
|
doAssert align("1232", 6) == " 1232"
|
||||||
|
|
@ -2347,33 +2427,13 @@ when isMainModule:
|
||||||
longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
|
longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
|
||||||
doAssert wordWrap(longInp, 8, true) == longOutp
|
doAssert wordWrap(longInp, 8, true) == longOutp
|
||||||
|
|
||||||
doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
|
|
||||||
doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235."
|
|
||||||
doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
|
|
||||||
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
|
||||||
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
|
|
||||||
["1,0e-11", "1,0e-011"]
|
|
||||||
# bug #6589
|
|
||||||
doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
|
|
||||||
|
|
||||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
|
||||||
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
|
||||||
|
|
||||||
block: # formatSize tests
|
|
||||||
doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"
|
|
||||||
doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
|
|
||||||
doAssert formatSize(4096) == "4KiB"
|
|
||||||
doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
|
|
||||||
doAssert formatSize(4096, includeSpace=true) == "4 KiB"
|
|
||||||
doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
|
|
||||||
|
|
||||||
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
||||||
"The cat eats fish."
|
"The cat eats fish."
|
||||||
|
|
||||||
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
||||||
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
||||||
|
|
||||||
doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc"
|
doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
|
||||||
doAssert "oo".replace("", "abc") == "abcoabcoabc"
|
doAssert "oo".replace("", "abc") == "abcoabcoabc"
|
||||||
|
|
||||||
type MyEnum = enum enA, enB, enC, enuD, enE
|
type MyEnum = enum enA, enB, enC, enuD, enE
|
||||||
|
|
@ -2521,35 +2581,6 @@ bar
|
||||||
doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "]
|
doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "]
|
||||||
doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
|
doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
|
||||||
|
|
||||||
block: # formatEng tests
|
|
||||||
doAssert formatEng(0, 2, trim=false) == "0.00"
|
|
||||||
doAssert formatEng(0, 2) == "0"
|
|
||||||
doAssert formatEng(53, 2, trim=false) == "53.00"
|
|
||||||
doAssert formatEng(0.053, 2, trim=false) == "53.00e-3"
|
|
||||||
doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3"
|
|
||||||
doAssert formatEng(0.053, 4, trim=true) == "53e-3"
|
|
||||||
doAssert formatEng(0.053, 0) == "53e-3"
|
|
||||||
doAssert formatEng(52731234) == "52.731234e6"
|
|
||||||
doAssert formatEng(-52731234) == "-52.731234e6"
|
|
||||||
doAssert formatEng(52731234, 1) == "52.7e6"
|
|
||||||
doAssert formatEng(-52731234, 1) == "-52.7e6"
|
|
||||||
doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6"
|
|
||||||
doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6"
|
|
||||||
|
|
||||||
doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
|
|
||||||
doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V"
|
|
||||||
doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
|
|
||||||
doAssert formatEng(4100, siPrefix=true) == "4.1 k"
|
|
||||||
doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space
|
|
||||||
doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k"
|
|
||||||
doAssert formatEng(4100) == "4.1e3"
|
|
||||||
doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V"
|
|
||||||
doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 "
|
|
||||||
# Don't use SI prefix as number is too big
|
|
||||||
doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a"
|
|
||||||
# Don't use SI prefix as number is too small
|
|
||||||
doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A"
|
|
||||||
|
|
||||||
block: # startsWith / endsWith char tests
|
block: # startsWith / endsWith char tests
|
||||||
var s = "abcdef"
|
var s = "abcdef"
|
||||||
doAssert s.startsWith('a')
|
doAssert s.startsWith('a')
|
||||||
|
|
@ -2559,3 +2590,8 @@ bar
|
||||||
doAssert s.endsWith('\0') == false
|
doAssert s.endsWith('\0') == false
|
||||||
|
|
||||||
#echo("strutils tests passed")
|
#echo("strutils tests passed")
|
||||||
|
|
||||||
|
nonStaticTests()
|
||||||
|
staticTests()
|
||||||
|
static: staticTests()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ when not hasThreadSupport:
|
||||||
var
|
var
|
||||||
colorsFGCache = initTable[Color, string]()
|
colorsFGCache = initTable[Color, string]()
|
||||||
colorsBGCache = initTable[Color, string]()
|
colorsBGCache = initTable[Color, string]()
|
||||||
when not defined(windows):
|
|
||||||
var
|
|
||||||
styleCache = initTable[int, string]()
|
styleCache = initTable[int, string]()
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -41,9 +39,7 @@ var
|
||||||
const
|
const
|
||||||
fgPrefix = "\x1b[38;2;"
|
fgPrefix = "\x1b[38;2;"
|
||||||
bgPrefix = "\x1b[48;2;"
|
bgPrefix = "\x1b[48;2;"
|
||||||
|
ansiResetCode* = "\e[0m"
|
||||||
when not defined(windows):
|
|
||||||
const
|
|
||||||
stylePrefix = "\e["
|
stylePrefix = "\e["
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -468,7 +464,7 @@ proc resetAttributes*(f: File) =
|
||||||
else:
|
else:
|
||||||
discard setConsoleTextAttribute(hStdout, oldStdoutAttr)
|
discard setConsoleTextAttribute(hStdout, oldStdoutAttr)
|
||||||
else:
|
else:
|
||||||
f.write("\e[0m")
|
f.write(ansiResetCode)
|
||||||
|
|
||||||
type
|
type
|
||||||
Style* = enum ## different styles for text output
|
Style* = enum ## different styles for text output
|
||||||
|
|
@ -487,7 +483,7 @@ when not defined(windows):
|
||||||
gFG {.threadvar.}: int
|
gFG {.threadvar.}: int
|
||||||
gBG {.threadvar.}: int
|
gBG {.threadvar.}: int
|
||||||
|
|
||||||
proc getStyleStr(style: int): string =
|
proc ansiStyleCode*(style: int): string =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
result = fmt"{stylePrefix}{style}m"
|
result = fmt"{stylePrefix}{style}m"
|
||||||
else:
|
else:
|
||||||
|
|
@ -497,6 +493,13 @@ when not defined(windows):
|
||||||
result = fmt"{stylePrefix}{style}m"
|
result = fmt"{stylePrefix}{style}m"
|
||||||
styleCache[style] = result
|
styleCache[style] = result
|
||||||
|
|
||||||
|
template ansiStyleCode*(style: Style): string =
|
||||||
|
ansiStyleCode(style.int)
|
||||||
|
|
||||||
|
# The styleCache can be skipped when `style` is known at compile-time
|
||||||
|
template ansiStyleCode*(style: static[Style]): string =
|
||||||
|
(static(stylePrefix & $style.int & "m"))
|
||||||
|
|
||||||
proc setStyle*(f: File, style: set[Style]) =
|
proc setStyle*(f: File, style: set[Style]) =
|
||||||
## Sets the terminal style.
|
## Sets the terminal style.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -510,7 +513,7 @@ proc setStyle*(f: File, style: set[Style]) =
|
||||||
discard setConsoleTextAttribute(h, old or a)
|
discard setConsoleTextAttribute(h, old or a)
|
||||||
else:
|
else:
|
||||||
for s in items(style):
|
for s in items(style):
|
||||||
f.write(getStyleStr(ord(s)))
|
f.write(ansiStyleCode(s))
|
||||||
|
|
||||||
proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
|
proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
|
||||||
## Writes the text `txt` in a given `style` to stdout.
|
## Writes the text `txt` in a given `style` to stdout.
|
||||||
|
|
@ -524,9 +527,9 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
|
||||||
stdout.write(txt)
|
stdout.write(txt)
|
||||||
stdout.resetAttributes()
|
stdout.resetAttributes()
|
||||||
if gFG != 0:
|
if gFG != 0:
|
||||||
stdout.write(getStyleStr(gFG))
|
stdout.write(ansiStyleCode(gFG))
|
||||||
if gBG != 0:
|
if gBG != 0:
|
||||||
stdout.write(getStyleStr(gBG))
|
stdout.write(ansiStyleCode(gBG))
|
||||||
|
|
||||||
type
|
type
|
||||||
ForegroundColor* = enum ## terminal's foreground colors
|
ForegroundColor* = enum ## terminal's foreground colors
|
||||||
|
|
@ -572,7 +575,7 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
|
||||||
else:
|
else:
|
||||||
gFG = ord(fg)
|
gFG = ord(fg)
|
||||||
if bright: inc(gFG, 60)
|
if bright: inc(gFG, 60)
|
||||||
f.write(getStyleStr(gFG))
|
f.write(ansiStyleCode(gFG))
|
||||||
|
|
||||||
proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
||||||
## Sets the terminal's background color.
|
## Sets the terminal's background color.
|
||||||
|
|
@ -594,10 +597,18 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
||||||
else:
|
else:
|
||||||
gBG = ord(bg)
|
gBG = ord(bg)
|
||||||
if bright: inc(gBG, 60)
|
if bright: inc(gBG, 60)
|
||||||
f.write(getStyleStr(gBG))
|
f.write(ansiStyleCode(gBG))
|
||||||
|
|
||||||
|
proc ansiForegroundColorCode*(fg: ForegroundColor, bright=false): string =
|
||||||
|
var style = ord(fg)
|
||||||
|
if bright: inc(style, 60)
|
||||||
|
return ansiStyleCode(style)
|
||||||
|
|
||||||
proc getFGColorStr(color: Color): string =
|
template ansiForegroundColorCode*(fg: static[ForegroundColor],
|
||||||
|
bright: static[bool] = false): string =
|
||||||
|
ansiStyleCode(fg.int + bright.int * 60)
|
||||||
|
|
||||||
|
proc ansiForegroundColorCode*(color: Color): string =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
let rgb = extractRGB(color)
|
let rgb = extractRGB(color)
|
||||||
result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
||||||
|
|
@ -609,7 +620,11 @@ proc getFGColorStr(color: Color): string =
|
||||||
result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
||||||
colorsFGCache[color] = result
|
colorsFGCache[color] = result
|
||||||
|
|
||||||
proc getBGColorStr(color: Color): string =
|
template ansiForegroundColorCode*(color: static[Color]): string =
|
||||||
|
const rgb = extractRGB(color)
|
||||||
|
(static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m"))
|
||||||
|
|
||||||
|
proc ansiBackgroundColorCode*(color: Color): string =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
let rgb = extractRGB(color)
|
let rgb = extractRGB(color)
|
||||||
result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
||||||
|
|
@ -621,15 +636,19 @@ proc getBGColorStr(color: Color): string =
|
||||||
result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"
|
||||||
colorsFGCache[color] = result
|
colorsFGCache[color] = result
|
||||||
|
|
||||||
|
template ansiBackgroundColorCode*(color: static[Color]): string =
|
||||||
|
const rgb = extractRGB(color)
|
||||||
|
(static(fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m"))
|
||||||
|
|
||||||
proc setForegroundColor*(f: File, color: Color) =
|
proc setForegroundColor*(f: File, color: Color) =
|
||||||
## Sets the terminal's foreground true color.
|
## Sets the terminal's foreground true color.
|
||||||
if trueColorIsEnabled:
|
if trueColorIsEnabled:
|
||||||
f.write(getFGColorStr(color))
|
f.write(ansiForegroundColorCode(color))
|
||||||
|
|
||||||
proc setBackgroundColor*(f: File, color: Color) =
|
proc setBackgroundColor*(f: File, color: Color) =
|
||||||
## Sets the terminal's background true color.
|
## Sets the terminal's background true color.
|
||||||
if trueColorIsEnabled:
|
if trueColorIsEnabled:
|
||||||
f.write(getBGColorStr(color))
|
f.write(ansiBackgroundColorCode(color))
|
||||||
|
|
||||||
proc setTrueColor(f: File, color: Color) =
|
proc setTrueColor(f: File, color: Color) =
|
||||||
if fgSetColor:
|
if fgSetColor:
|
||||||
|
|
|
||||||
|
|
@ -1069,17 +1069,15 @@ proc splitData*(textNode: PText, offset: int): PText =
|
||||||
var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
|
var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
|
||||||
return newNode
|
return newNode
|
||||||
|
|
||||||
|
|
||||||
# ProcessingInstruction
|
# ProcessingInstruction
|
||||||
proc target*(pi: PProcessingInstruction): string =
|
proc target*(pi: PProcessingInstruction): string =
|
||||||
## Returns the Processing Instructions target
|
## Returns the Processing Instructions target
|
||||||
|
|
||||||
return pi.fTarget
|
return pi.fTarget
|
||||||
|
|
||||||
|
proc escapeXml*(s: string; result: var string) =
|
||||||
# --Other stuff--
|
## Prepares a string for insertion into a XML document
|
||||||
# Writer
|
## by escaping the XML special characters.
|
||||||
proc addEscaped(s: string): string =
|
|
||||||
result = ""
|
result = ""
|
||||||
for c in items(s):
|
for c in items(s):
|
||||||
case c
|
case c
|
||||||
|
|
@ -1089,11 +1087,20 @@ proc addEscaped(s: string): string =
|
||||||
of '"': result.add(""")
|
of '"': result.add(""")
|
||||||
else: result.add(c)
|
else: result.add(c)
|
||||||
|
|
||||||
|
proc escapeXml*(s: string): string =
|
||||||
|
## Prepares a string for insertion into a XML document
|
||||||
|
## by escaping the XML special characters.
|
||||||
|
result = newStringOfCap(s.len + s.len shr 4)
|
||||||
|
escapeXml(s, result)
|
||||||
|
|
||||||
|
# --Other stuff--
|
||||||
|
# Writer
|
||||||
|
|
||||||
proc nodeToXml(n: PNode, indent: int = 0): string =
|
proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
result = spaces(indent) & "<" & n.nodeName
|
result = spaces(indent) & "<" & n.nodeName
|
||||||
if not isNil(n.attributes):
|
if not isNil(n.attributes):
|
||||||
for i in items(n.attributes):
|
for i in items(n.attributes):
|
||||||
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"")
|
||||||
|
|
||||||
if isNil(n.childNodes) or n.childNodes.len() == 0:
|
if isNil(n.childNodes) or n.childNodes.len() == 0:
|
||||||
result.add("/>") # No idea why this doesn't need a \n :O
|
result.add("/>") # No idea why this doesn't need a \n :O
|
||||||
|
|
@ -1106,7 +1113,7 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
result.add(nodeToXml(i, indent + 2))
|
result.add(nodeToXml(i, indent + 2))
|
||||||
of TextNode:
|
of TextNode:
|
||||||
result.add(spaces(indent * 2))
|
result.add(spaces(indent * 2))
|
||||||
result.add(addEscaped(i.nodeValue))
|
result.add(escapeXml(i.nodeValue))
|
||||||
of CDataSectionNode:
|
of CDataSectionNode:
|
||||||
result.add(spaces(indent * 2))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ when defined(vcc):
|
||||||
else:
|
else:
|
||||||
{.error: "invalid CAS instruction".}
|
{.error: "invalid CAS instruction".}
|
||||||
|
|
||||||
elif defined(tcc) and not defined(windows):
|
elif defined(tcc):
|
||||||
when defined(amd64):
|
when defined(amd64):
|
||||||
{.emit:"""
|
{.emit:"""
|
||||||
static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
||||||
|
|
@ -262,7 +262,7 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
||||||
}
|
}
|
||||||
""".}
|
""".}
|
||||||
else:
|
else:
|
||||||
assert sizeof(int) == 4
|
#assert sizeof(int) == 4
|
||||||
{.emit:"""
|
{.emit:"""
|
||||||
static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import sets
|
import sets
|
||||||
|
import hashes
|
||||||
|
import algorithm
|
||||||
|
|
||||||
block setEquality:
|
block setEquality:
|
||||||
var
|
var
|
||||||
|
|
@ -74,6 +76,48 @@ block orderedSetClearWorked:
|
||||||
|
|
||||||
doAssert r == "zeat jos"
|
doAssert r == "zeat jos"
|
||||||
|
|
||||||
|
block hashForHashedSet:
|
||||||
|
let
|
||||||
|
seq1 = "This is the test."
|
||||||
|
seq2 = "the test is This."
|
||||||
|
s1 = seq1.toSet()
|
||||||
|
s2 = seq2.toSet()
|
||||||
|
var hashSeq: seq[Hash] = @[]
|
||||||
|
doAssert s1 == s2
|
||||||
|
doAssert hash(s1) == hash(s2)
|
||||||
|
|
||||||
|
block hashForOrderdSet:
|
||||||
|
let
|
||||||
|
str = "This is the test."
|
||||||
|
rstr = str.reversed
|
||||||
|
|
||||||
|
var
|
||||||
|
s1 = initOrderedSet[char]()
|
||||||
|
s2 = initOrderedSet[char]()
|
||||||
|
r = initOrderedSet[char]()
|
||||||
|
expected: Hash
|
||||||
|
added: seq[char] = @[]
|
||||||
|
reversed: Hash
|
||||||
|
radded: seq[char] = @[]
|
||||||
|
|
||||||
|
expected = 0
|
||||||
|
for c in str:
|
||||||
|
if (not (c in added)):
|
||||||
|
expected = expected !& hash(c)
|
||||||
|
added.add(c)
|
||||||
|
s1.incl(c)
|
||||||
|
s2.incl(c)
|
||||||
|
expected = !$expected
|
||||||
|
doAssert hash(s1) == expected
|
||||||
|
doAssert hash(s1) == hash(s2)
|
||||||
|
doAssert hash(s1) != hash(r)
|
||||||
|
|
||||||
|
reversed = 0
|
||||||
|
for c in rstr:
|
||||||
|
if (not (c in radded)):
|
||||||
|
reversed = reversed !& hash(c)
|
||||||
|
radded.add(c)
|
||||||
|
r.incl(c)
|
||||||
|
reversed = !$reversed
|
||||||
|
doAssert hash(r) == reversed
|
||||||
|
doAssert hash(s1) != reversed
|
||||||
|
|
|
||||||
14
tests/generics/module_with_generics.nim
Normal file
14
tests/generics/module_with_generics.nim
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
type
|
||||||
|
Base[T] = ref object {.inheritable.}
|
||||||
|
value*: T
|
||||||
|
|
||||||
|
Derived[T] = ref object of Base[T]
|
||||||
|
derivedValue*: T
|
||||||
|
|
||||||
|
proc makeDerived*[T](v: T): Derived[T] =
|
||||||
|
new result
|
||||||
|
result.value = v
|
||||||
|
|
||||||
|
proc setBaseValue*[T](a: Base[T], value: T) =
|
||||||
|
a.value = value
|
||||||
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
discard """
|
discard """
|
||||||
output: "seq[float]\n0"
|
output: "seq[float]\n0"
|
||||||
|
targets: "c cpp"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# https://github.com/nim-lang/Nim/issues/5602
|
# https://github.com/nim-lang/Nim/issues/5602
|
||||||
|
|
||||||
import typetraits
|
import typetraits, module_with_generics
|
||||||
|
|
||||||
type
|
type
|
||||||
Foo[T] = object of RootObj
|
Foo[T] = object of RootObj
|
||||||
|
|
@ -16,3 +17,8 @@ proc p[T](f: Foo[T]): T =
|
||||||
var s: Bar[float]
|
var s: Bar[float]
|
||||||
echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
|
echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
|
||||||
|
|
||||||
|
# Test overloading and code generation when
|
||||||
|
# downcasting is required for generic types:
|
||||||
|
var d = makeDerived(10)
|
||||||
|
setBaseValue(d, 20)
|
||||||
|
|
||||||
|
|
|
||||||
154
tests/macros/tstructuredlogging.nim
Normal file
154
tests/macros/tstructuredlogging.nim
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20
|
||||||
|
exiting: a=12, b=overriden-b, c=100, msg=bye bye, x=16
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros, tables
|
||||||
|
|
||||||
|
template scopeHolder =
|
||||||
|
0 # scope revision number
|
||||||
|
|
||||||
|
type
|
||||||
|
BindingsSet = Table[string, NimNode]
|
||||||
|
|
||||||
|
proc actualBody(n: NimNode): NimNode =
|
||||||
|
# skip over the double StmtList node introduced in `mergeScopes`
|
||||||
|
result = n.body
|
||||||
|
if result.kind == nnkStmtList and result[0].kind == nnkStmtList:
|
||||||
|
result = result[0]
|
||||||
|
|
||||||
|
iterator bindings(n: NimNode, skip = 0): (string, NimNode) =
|
||||||
|
for i in skip ..< n.len:
|
||||||
|
let child = n[i]
|
||||||
|
if child.kind in {nnkAsgn, nnkExprEqExpr}:
|
||||||
|
let name = $child[0]
|
||||||
|
let value = child[1]
|
||||||
|
yield (name, value)
|
||||||
|
|
||||||
|
proc scopeRevision(scopeHolder: NimNode): int =
|
||||||
|
# get the revision number from a scopeHolder sym
|
||||||
|
assert scopeHolder.kind == nnkSym
|
||||||
|
var revisionNode = scopeHolder.getImpl.actualBody[0]
|
||||||
|
result = int(revisionNode.intVal)
|
||||||
|
|
||||||
|
proc lastScopeHolder(scopeHolders: NimNode): NimNode =
|
||||||
|
# get the most recent scopeHolder from a symChoice node
|
||||||
|
if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
|
||||||
|
var bestScopeRev = 0
|
||||||
|
assert scopeHolders.len > 0
|
||||||
|
for scope in scopeHolders:
|
||||||
|
let rev = scope.scopeRevision
|
||||||
|
if result == nil or rev > bestScopeRev:
|
||||||
|
result = scope
|
||||||
|
bestScopeRev = rev
|
||||||
|
else:
|
||||||
|
result = scopeHolders
|
||||||
|
|
||||||
|
assert result.kind == nnkSym
|
||||||
|
|
||||||
|
macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped =
|
||||||
|
var
|
||||||
|
bestScope = scopeHolders.lastScopeHolder
|
||||||
|
bestScopeRev = bestScope.scopeRevision
|
||||||
|
|
||||||
|
var finalBindings = initTable[string, NimNode]()
|
||||||
|
for k, v in bindings(bestScope.getImpl.actualBody, skip = 1):
|
||||||
|
finalBindings[k] = v
|
||||||
|
|
||||||
|
for k, v in bindings(newBindings):
|
||||||
|
finalBindings[k] = v
|
||||||
|
|
||||||
|
var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1))
|
||||||
|
|
||||||
|
for k, v in finalBindings:
|
||||||
|
newScopeDefinition.add newAssignment(newIdentNode(k), v)
|
||||||
|
|
||||||
|
result = quote:
|
||||||
|
template scopeHolder = `newScopeDefinition`
|
||||||
|
|
||||||
|
template scope(newBindings: untyped) {.dirty.} =
|
||||||
|
mergeScopes(bindSym"scopeHolder", newBindings)
|
||||||
|
|
||||||
|
type
|
||||||
|
TextLogRecord = object
|
||||||
|
line: string
|
||||||
|
|
||||||
|
StdoutLogRecord = object
|
||||||
|
|
||||||
|
template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) =
|
||||||
|
if not first: r.line.add ", "
|
||||||
|
r.line.add key
|
||||||
|
r.line.add "="
|
||||||
|
r.line.add val
|
||||||
|
|
||||||
|
template setEventName(r: var StdoutLogRecord, name: string) =
|
||||||
|
stdout.write(name & ": ")
|
||||||
|
|
||||||
|
template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) =
|
||||||
|
when not isFirst: stdout.write ", "
|
||||||
|
stdout.write key
|
||||||
|
stdout.write "="
|
||||||
|
stdout.write $val
|
||||||
|
|
||||||
|
template flushRecord(r: var StdoutLogRecord) =
|
||||||
|
stdout.write "\n"
|
||||||
|
stdout.flushFile
|
||||||
|
|
||||||
|
macro logImpl(scopeHolders: typed,
|
||||||
|
logStmtProps: varargs[untyped]): untyped =
|
||||||
|
let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody
|
||||||
|
var finalBindings = initOrderedTable[string, NimNode]()
|
||||||
|
|
||||||
|
for k, v in bindings(lexicalScope, skip = 1):
|
||||||
|
finalBindings[k] = v
|
||||||
|
|
||||||
|
for k, v in bindings(logStmtProps, skip = 1):
|
||||||
|
finalBindings[k] = v
|
||||||
|
|
||||||
|
finalBindings.sort(system.cmp)
|
||||||
|
|
||||||
|
let eventName = logStmtProps[0]
|
||||||
|
assert eventName.kind in {nnkStrLit}
|
||||||
|
let record = genSym(nskVar, "record")
|
||||||
|
|
||||||
|
result = quote:
|
||||||
|
var `record`: StdoutLogRecord
|
||||||
|
setEventName(`record`, `eventName`)
|
||||||
|
|
||||||
|
var isFirst = true
|
||||||
|
for k, v in finalBindings:
|
||||||
|
result.add newCall(newIdentNode"setProperty",
|
||||||
|
record, newLit(k), v, newLit(isFirst))
|
||||||
|
isFirst = false
|
||||||
|
|
||||||
|
result.add newCall(newIdentNode"flushRecord", record)
|
||||||
|
|
||||||
|
template log(props: varargs[untyped]) {.dirty.} =
|
||||||
|
logImpl(bindSym"scopeHolder", props)
|
||||||
|
|
||||||
|
scope:
|
||||||
|
a = 12
|
||||||
|
b = "original-b"
|
||||||
|
|
||||||
|
scope:
|
||||||
|
x = 16
|
||||||
|
b = "overriden-b"
|
||||||
|
|
||||||
|
scope:
|
||||||
|
c = 100
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
scope:
|
||||||
|
c = 10
|
||||||
|
|
||||||
|
scope:
|
||||||
|
z = 20
|
||||||
|
|
||||||
|
log("main started", a = 10, b = "inner-b", d = "some-d")
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
log("exiting", msg = "bye bye")
|
||||||
|
|
||||||
173
tests/macros/ttemplatesymbols.nim
Normal file
173
tests/macros/ttemplatesymbols.nim
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
import
|
||||||
|
macros, algorithm, strutils
|
||||||
|
|
||||||
|
proc normalProc(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template templateWithtouParams =
|
||||||
|
echo 10
|
||||||
|
|
||||||
|
proc overloadedProc(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
proc overloadedProc(x: string) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
proc overloadedProc[T](x: T) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template normalTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template overloadedTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template overloadedTemplate(x: string) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
macro normalMacro(x: int): untyped =
|
||||||
|
discard
|
||||||
|
|
||||||
|
macro macroWithoutParams: untyped =
|
||||||
|
discard
|
||||||
|
|
||||||
|
macro inspectSymbol(sym: typed, expected: static[string]): untyped =
|
||||||
|
if sym.kind == nnkSym:
|
||||||
|
echo "Symbol node:"
|
||||||
|
let res = sym.getImpl.repr & "\n"
|
||||||
|
echo res
|
||||||
|
# echo "|", res, "|"
|
||||||
|
# echo "|", expected, "|"
|
||||||
|
if expected.len > 0: assert res == expected
|
||||||
|
elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
|
||||||
|
echo "Begin sym choice:"
|
||||||
|
var results = newSeq[string](0)
|
||||||
|
for innerSym in sym:
|
||||||
|
results.add innerSym.getImpl.repr
|
||||||
|
sort(results, cmp[string])
|
||||||
|
let res = results.join("\n") & "\n"
|
||||||
|
echo res
|
||||||
|
if expected.len > 0: assert res == expected
|
||||||
|
echo "End symchoice."
|
||||||
|
else:
|
||||||
|
echo "Non-symbol node: ", sym.kind
|
||||||
|
if expected.len > 0: assert $sym.kind == expected
|
||||||
|
|
||||||
|
macro inspectUntyped(sym: untyped, expected: static[string]): untyped =
|
||||||
|
let res = sym.repr
|
||||||
|
echo "Untyped node: ", res
|
||||||
|
assert res == expected
|
||||||
|
|
||||||
|
inspectSymbol templateWithtouParams, "nnkCommand"
|
||||||
|
# this template is expanded, because bindSym was not used
|
||||||
|
# the end result is the template body (nnkCommand)
|
||||||
|
|
||||||
|
inspectSymbol bindSym("templateWithtouParams"), """
|
||||||
|
template templateWithtouParams() =
|
||||||
|
echo 10
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol macroWithoutParams, "nnkEmpty"
|
||||||
|
# Just like the template above, the macro was expanded
|
||||||
|
|
||||||
|
inspectSymbol bindSym("macroWithoutParams"), """
|
||||||
|
macro macroWithoutParams(): untyped =
|
||||||
|
discard
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol normalMacro, """
|
||||||
|
macro normalMacro(x: int): untyped =
|
||||||
|
discard
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Since the normalMacro has params, it's automatically
|
||||||
|
# treated as a symbol here (no need for `bindSym`)
|
||||||
|
|
||||||
|
inspectSymbol bindSym("normalMacro"), """
|
||||||
|
macro normalMacro(x: int): untyped =
|
||||||
|
discard
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol normalTemplate, """
|
||||||
|
template normalTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol bindSym("normalTemplate"), """
|
||||||
|
template normalTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol overloadedTemplate, """
|
||||||
|
template overloadedTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template overloadedTemplate(x: string) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol bindSym("overloadedTemplate"), """
|
||||||
|
template overloadedTemplate(x: int) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
template overloadedTemplate(x: string) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")"""
|
||||||
|
# binSym is active only in the presense of `typed` params.
|
||||||
|
# `untyped` params still get the raw AST
|
||||||
|
|
||||||
|
inspectSymbol normalProc, """
|
||||||
|
proc normalProc(x: int) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol bindSym("normalProc"), """
|
||||||
|
proc normalProc(x: int) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
inspectSymbol overloadedProc, """
|
||||||
|
proc overloadedProc(x: int) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
proc overloadedProc(x: string) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
proc overloadedProc[T](x: T) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
# XXX: There seems to be a repr rendering problem above.
|
||||||
|
# Notice that `echo [x]`
|
||||||
|
|
||||||
|
inspectSymbol overloadedProc[float], """
|
||||||
|
proc overloadedProc(x: T) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
"""
|
||||||
|
# As expected, when we select a specific generic, the
|
||||||
|
# AST is no longer a symChoice
|
||||||
|
|
||||||
|
inspectSymbol bindSym("overloadedProc"), """
|
||||||
|
proc overloadedProc(x: int) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
proc overloadedProc(x: string) =
|
||||||
|
echo [x]
|
||||||
|
|
||||||
|
proc overloadedProc[T](x: T) =
|
||||||
|
echo x
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
4
tests/modules/definitions.nim
Normal file
4
tests/modules/definitions.nim
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
var v*: int
|
||||||
|
proc p* = echo "proc p called"
|
||||||
|
template t* = echo "template t expanded"
|
||||||
|
|
||||||
3
tests/modules/proxy_module.nim
Normal file
3
tests/modules/proxy_module.nim
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import definitions
|
||||||
|
export definitions except p
|
||||||
|
|
||||||
|
|
@ -6,6 +6,10 @@ output: '''baz
|
||||||
a
|
a
|
||||||
b
|
b
|
||||||
c
|
c
|
||||||
|
x: 1, y: test 1
|
||||||
|
x: 2, y: test 2
|
||||||
|
x: 10, y: test 3
|
||||||
|
x: 4, y: test 4
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -35,3 +39,15 @@ templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1
|
||||||
|
|
||||||
procForwarding "a", "b", "c"
|
procForwarding "a", "b", "c"
|
||||||
|
|
||||||
|
proc hasKeywordArgs(x = 10, y = "y") =
|
||||||
|
echo "x: ", x, ", y: ", y
|
||||||
|
|
||||||
|
proc hasRegularArgs(x: int, y: string) =
|
||||||
|
echo "x: ", x, ", y: ", y
|
||||||
|
|
||||||
|
templateForwarding(hasRegularArgs, true, 1, "test 1")
|
||||||
|
templateForwarding hasKeywordArgs, true, 2, "test 2"
|
||||||
|
|
||||||
|
templateForwarding(hasKeywordArgs, true, y = "test 3")
|
||||||
|
templateForwarding hasKeywordArgs, true, y = "test 4", x = 4
|
||||||
|
|
||||||
|
|
|
||||||
78
tests/threads/tthreadvars.nim
Normal file
78
tests/threads/tthreadvars.nim
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
10
|
||||||
|
1111
|
||||||
|
1222
|
||||||
|
3030303
|
||||||
|
3060606
|
||||||
|
6060606
|
||||||
|
6121212
|
||||||
|
3030903
|
||||||
|
3061206
|
||||||
|
3031503
|
||||||
|
3061806
|
||||||
|
5050505
|
||||||
|
5101010
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
var tls1 {.threadvar.}: int
|
||||||
|
var g0: int
|
||||||
|
var g1 {.global.}: int
|
||||||
|
|
||||||
|
proc customInc(x: var int, delta: int) =
|
||||||
|
x += delta
|
||||||
|
|
||||||
|
customInc(tls1, 10)
|
||||||
|
echo tls1
|
||||||
|
|
||||||
|
proc nonGenericProc: int =
|
||||||
|
var local: int
|
||||||
|
var nonGenericTls {.threadvar.}: int
|
||||||
|
var nonGenericGlobal {.global.}: int
|
||||||
|
var nonGenericMixedPragmas {.global, threadvar.}: int
|
||||||
|
|
||||||
|
customInc local, 1000
|
||||||
|
customInc nonGenericTls, 1
|
||||||
|
customInc nonGenericGlobal, 10
|
||||||
|
customInc nonGenericMixedPragmas, 100
|
||||||
|
|
||||||
|
return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas
|
||||||
|
|
||||||
|
proc genericProc(T: typedesc): int =
|
||||||
|
var local: int
|
||||||
|
var genericTls {.threadvar.}: int
|
||||||
|
var genericGlobal {.global.}: int
|
||||||
|
var genericMixedPragmas {.global, threadvar.}: int
|
||||||
|
|
||||||
|
customInc local, T.name.len * 1000000
|
||||||
|
customInc genericTls, T.name.len * 1
|
||||||
|
customInc genericGlobal, T.name.len * 100
|
||||||
|
customInc genericMixedPragmas, T.name.len * 10000
|
||||||
|
|
||||||
|
return local + genericTls + genericGlobal + genericMixedPragmas
|
||||||
|
|
||||||
|
echo nonGenericProc()
|
||||||
|
echo nonGenericProc()
|
||||||
|
|
||||||
|
echo genericProc(int)
|
||||||
|
echo genericProc(int)
|
||||||
|
|
||||||
|
echo genericProc(string)
|
||||||
|
echo genericProc(string)
|
||||||
|
|
||||||
|
proc echoInThread[T]() {.thread.} =
|
||||||
|
echo genericProc(T)
|
||||||
|
echo genericProc(T)
|
||||||
|
|
||||||
|
proc newEchoThread(T: typedesc) =
|
||||||
|
var t: Thread[void]
|
||||||
|
createThread(t, echoInThread[T])
|
||||||
|
joinThreads(t)
|
||||||
|
|
||||||
|
newEchoThread int
|
||||||
|
newEchoThread int
|
||||||
|
newEchoThread float
|
||||||
|
|
||||||
12
tests/vm/tref.nim
Normal file
12
tests/vm/tref.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
static:
|
||||||
|
var
|
||||||
|
a: ref string
|
||||||
|
b: ref string
|
||||||
|
new a
|
||||||
|
|
||||||
|
a[] = "Hello world"
|
||||||
|
b = a
|
||||||
|
|
||||||
|
b[5] = 'c'
|
||||||
|
doAssert a[] == "Hellocworld"
|
||||||
|
doAssert b[] == "Hellocworld"
|
||||||
|
|
@ -187,12 +187,14 @@ when defined(windows):
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
let desiredPath = expandFilename(getCurrentDir() / "bin")
|
let nimDesiredPath = expandFilename(getCurrentDir() / "bin")
|
||||||
|
let nimbleDesiredPath = expandFilename(getEnv("USERPROFILE") / ".nimble" / "bin")
|
||||||
let p = tryGetUnicodeValue(r"Environment", "Path",
|
let p = tryGetUnicodeValue(r"Environment", "Path",
|
||||||
HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue(
|
HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue(
|
||||||
r"System\CurrentControlSet\Control\Session Manager\Environment", "Path",
|
r"System\CurrentControlSet\Control\Session Manager\Environment", "Path",
|
||||||
HKEY_LOCAL_MACHINE)
|
HKEY_LOCAL_MACHINE)
|
||||||
var alreadyInPath = false
|
var nimAlreadyInPath = false
|
||||||
|
var nimbleAlreadyInPath = false
|
||||||
var mingWchoices: seq[string] = @[]
|
var mingWchoices: seq[string] = @[]
|
||||||
var incompat: seq[string] = @[]
|
var incompat: seq[string] = @[]
|
||||||
for x in p.split(';'):
|
for x in p.split(';'):
|
||||||
|
|
@ -200,18 +202,29 @@ proc main() =
|
||||||
let y = try: expandFilename(if x[0] == '"' and x[^1] == '"':
|
let y = try: expandFilename(if x[0] == '"' and x[^1] == '"':
|
||||||
substr(x, 1, x.len-2) else: x)
|
substr(x, 1, x.len-2) else: x)
|
||||||
except: ""
|
except: ""
|
||||||
if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true
|
if y.cmpIgnoreCase(nimDesiredPath) == 0:
|
||||||
if y.toLowerAscii.contains("mingw"):
|
nimAlreadyInPath = true
|
||||||
|
elif y.cmpIgnoreCase(nimbleDesiredPath) == 0:
|
||||||
|
nimbleAlreadyInPath = true
|
||||||
|
elif y.toLowerAscii.contains("mingw"):
|
||||||
if dirExists(y):
|
if dirExists(y):
|
||||||
if checkGccArch(y): mingWchoices.add y
|
if checkGccArch(y): mingWchoices.add y
|
||||||
else: incompat.add y
|
else: incompat.add y
|
||||||
|
|
||||||
if alreadyInPath:
|
if nimAlreadyInPath:
|
||||||
echo "bin/nim.exe is already in your PATH [Skipping]"
|
echo "bin\\nim.exe is already in your PATH [Skipping]"
|
||||||
else:
|
else:
|
||||||
if askBool("nim.exe is not in your PATH environment variable.\n" &
|
if askBool("nim.exe is not in your PATH environment variable.\n" &
|
||||||
"Should it be added permanently? (y/n) "):
|
"Should it be added permanently? (y/n) "):
|
||||||
addToPathEnv(desiredPath)
|
addToPathEnv(nimDesiredPath)
|
||||||
|
|
||||||
|
if nimbleAlreadyInPath:
|
||||||
|
echo nimbleDesiredPath & " is already in your PATH [Skipping]"
|
||||||
|
else:
|
||||||
|
if askBool(nimbleDesiredPath & " is not in your PATH environment variable.\n" &
|
||||||
|
"Should it be added permanently? (y/n) "):
|
||||||
|
addToPathEnv(nimbleDesiredPath)
|
||||||
|
|
||||||
if mingWchoices.len == 0:
|
if mingWchoices.len == 0:
|
||||||
# No mingw in path, so try a few locations:
|
# No mingw in path, so try a few locations:
|
||||||
let alternative = tryDirs(incompat, defaultMingwLocations())
|
let alternative = tryDirs(incompat, defaultMingwLocations())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue