mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-07 21:43:33 +00:00
fixes testament compilation
This commit is contained in:
@@ -72,6 +72,8 @@
|
||||
- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is
|
||||
now joined in ``binarySearch``. ``smartbinarySearch`` is now
|
||||
deprecated.
|
||||
- The `terminal` module now exports additional procs for generating ANSI color
|
||||
codes as strings.
|
||||
|
||||
### Language additions
|
||||
|
||||
@@ -95,11 +97,18 @@
|
||||
|
||||
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||
these is ``"" / @[]``.
|
||||
|
||||
- Accessing the binary zero terminator in Nim's native strings
|
||||
is now invalid. Internally a Nim string still has the trailing zero for
|
||||
zero-copy interoperability with ``cstring``. Compile your code with the
|
||||
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
|
||||
|
||||
|
||||
@@ -1620,6 +1620,19 @@ proc originatingModule*(s: PSym): PSym =
|
||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||
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.} =
|
||||
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
|
||||
|
||||
@@ -1676,7 +1689,7 @@ proc isException*(t: PType): bool =
|
||||
|
||||
var base = t
|
||||
while base != nil:
|
||||
if base.sym.magic == mException:
|
||||
if base.sym != nil and base.sym.magic == mException:
|
||||
return true
|
||||
base = base.lastSon
|
||||
return false
|
||||
|
||||
@@ -69,22 +69,22 @@ proc debug*(n: PNode) {.deprecated.}
|
||||
|
||||
template mdbg*: bool {.dirty.} =
|
||||
when compiles(c.module):
|
||||
c.module.fileIdx == gProjectMainIdx
|
||||
c.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(c.c.module):
|
||||
c.c.module.fileIdx == gProjectMainIdx
|
||||
c.c.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(m.c.module):
|
||||
m.c.module.fileIdx == gProjectMainIdx
|
||||
m.c.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(cl.c.module):
|
||||
cl.c.module.fileIdx == gProjectMainIdx
|
||||
cl.c.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(p):
|
||||
when compiles(p.lex):
|
||||
p.lex.fileIdx == gProjectMainIdx
|
||||
p.lex.fileIdx.int32 == gProjectMainIdx
|
||||
else:
|
||||
p.module.module.fileIdx == gProjectMainIdx
|
||||
p.module.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(m.module.fileIdx):
|
||||
m.module.fileIdx == gProjectMainIdx
|
||||
m.module.fileIdx.int32 == gProjectMainIdx
|
||||
elif compiles(L.fileIdx):
|
||||
L.fileIdx == gProjectMainIdx
|
||||
L.fileIdx.int32 == gProjectMainIdx
|
||||
else:
|
||||
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 ``()``
|
||||
# `n` is then a nkSym or something similar
|
||||
var totalParams = case n.kind
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1
|
||||
of nkCallKinds: n.len-1
|
||||
else: 0
|
||||
|
||||
var
|
||||
|
||||
@@ -70,9 +70,9 @@ proc parseLine(p: var TTmplParser) =
|
||||
|
||||
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)
|
||||
elif p.x[j] == p.nimDirective:
|
||||
elif j < p.x.len and p.x[j] == p.nimDirective:
|
||||
newLine(p)
|
||||
inc(j)
|
||||
while j <= hi and p.x[j] == ' ': inc(j)
|
||||
|
||||
@@ -16,6 +16,13 @@ import
|
||||
proc evalImport*(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) =
|
||||
var check = strTableGet(c.importTable.symbols, s.name)
|
||||
if check == nil:
|
||||
@@ -199,9 +206,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
var exceptSet = initIntSet()
|
||||
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)
|
||||
importAllSymbolsExcept(c, m, readExceptSet(c, n))
|
||||
#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;
|
||||
cache: IdentCache): PSym {.procvar.} =
|
||||
# this is called by the semantic checking phase
|
||||
assert graph.config != nil
|
||||
result = compileModule(graph, fileIdx, cache, {})
|
||||
graph.addDep(s, fileIdx)
|
||||
#if sfSystemModule in result.flags:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
import strutils, lexbase, streams
|
||||
import "../compiler" / [ast, msgs, idents]
|
||||
import ".." / [ast, msgs, idents]
|
||||
from os import splitFile
|
||||
|
||||
type
|
||||
|
||||
@@ -713,10 +713,17 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||
# progress guaranteed
|
||||
exprColonEqExprListAux(p, endTok, result)
|
||||
|
||||
proc commandParam(p: var TParser): PNode =
|
||||
proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
|
||||
result = parseExpr(p)
|
||||
if p.tok.tokType == tkDo:
|
||||
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 =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
@@ -759,10 +766,11 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
let a = result
|
||||
result = newNodeP(nkCommand, p)
|
||||
addSon(result, a)
|
||||
var isFirstParam = true
|
||||
when true:
|
||||
# progress NOT guaranteed
|
||||
p.hasProgress = false
|
||||
addSon result, commandParam(p)
|
||||
addSon result, commandParam(p, isFirstParam)
|
||||
if not p.hasProgress: break
|
||||
else:
|
||||
while p.tok.tokType != tkEof:
|
||||
@@ -1314,17 +1322,18 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||
addSon(result, b)
|
||||
else:
|
||||
# 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:
|
||||
result = a
|
||||
while true:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, commandParam(p))
|
||||
addSon(result, commandParam(p, isFirstParam))
|
||||
if p.tok.tokType != tkComma: break
|
||||
elif p.tok.indent < 0 and isExprStart(p):
|
||||
result = newNode(nkCommand, a.info, @[a])
|
||||
while true:
|
||||
addSon(result, commandParam(p))
|
||||
addSon(result, commandParam(p, isFirstParam))
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
||||
@@ -781,7 +781,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
incl(sym.flags, sfRegister)
|
||||
of wThreadVar:
|
||||
noVal(c, it)
|
||||
incl(sym.flags, sfThread)
|
||||
incl(sym.flags, {sfThread, sfGlobal})
|
||||
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
||||
of wNoForward: pragmaNoForward(c, it)
|
||||
of wReorder: pragmaNoForward(c, it, sfReorder)
|
||||
|
||||
@@ -89,6 +89,7 @@ type
|
||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||
# store this info in the syms themselves!)
|
||||
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
|
||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||
compilesContextIdGenerator*: int
|
||||
|
||||
@@ -972,18 +972,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
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)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0) or
|
||||
sfCustomPragma in sym.flags:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skParam:
|
||||
@@ -1785,6 +1787,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
let oldInGenericContext = c.inGenericContext
|
||||
let oldInUnrolledContext = c.inUnrolledContext
|
||||
let oldInGenericInst = c.inGenericInst
|
||||
let oldInStaticContext = c.inStaticContext
|
||||
let oldProcCon = c.p
|
||||
c.generics = @[]
|
||||
var err: string
|
||||
@@ -1799,6 +1802,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
c.inGenericContext = oldInGenericContext
|
||||
c.inUnrolledContext = oldInUnrolledContext
|
||||
c.inGenericInst = oldInGenericInst
|
||||
c.inStaticContext = oldInStaticContext
|
||||
c.p = oldProcCon
|
||||
msgs.setInfoContextLen(oldContextLen)
|
||||
setLen(c.graph.owners, oldOwnerLen)
|
||||
@@ -2163,9 +2167,25 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||
closeScope(c)
|
||||
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 =
|
||||
var x = newNodeI(n.kind, n.info)
|
||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
||||
for i in 0..<n.len:
|
||||
let a = n.sons[i]
|
||||
var o: TOverloadIter
|
||||
@@ -2451,9 +2471,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkIncludeStmt:
|
||||
#if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include")
|
||||
result = evalInclude(c, n)
|
||||
of nkExportStmt, nkExportExceptStmt:
|
||||
of nkExportStmt:
|
||||
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
||||
result = semExport(c, n)
|
||||
of nkExportExceptStmt:
|
||||
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
||||
result = semExportExcept(c, n)
|
||||
of nkPragmaBlock:
|
||||
result = semPragmaBlock(c, n)
|
||||
of nkStaticStmt:
|
||||
|
||||
@@ -199,6 +199,10 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
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)
|
||||
else:
|
||||
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 =
|
||||
#echo "semStaticStmt"
|
||||
#writeStackTrace()
|
||||
inc c.inStaticContext
|
||||
let a = semStmt(c, n.sons[0])
|
||||
dec c.inStaticContext
|
||||
n.sons[0] = a
|
||||
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner)
|
||||
result = newNodeI(nkDiscardStmt, n.info, 1)
|
||||
|
||||
@@ -1964,7 +1964,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
inc(m.genericMatches)
|
||||
if arg.typ == nil:
|
||||
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)
|
||||
elif arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
@@ -2034,8 +2035,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||
y.calleeSym = m.calleeSym
|
||||
z.calleeSym = m.calleeSym
|
||||
var best = -1
|
||||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
|
||||
for i in 0 ..< arg.len:
|
||||
if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
|
||||
skIterator, skMacro, skTemplate}:
|
||||
copyCandidate(z, m)
|
||||
z.callee = arg.sons[i].typ
|
||||
if tfUnresolved in z.callee.flags: continue
|
||||
@@ -2064,6 +2066,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||
x = z
|
||||
elif cmp == 0:
|
||||
y = z # z is as good as x
|
||||
|
||||
if x.state == csEmpty:
|
||||
result = nil
|
||||
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!
|
||||
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
||||
# anyway:
|
||||
if f.kind == tyExpr: result = arg
|
||||
if f.kind in {tyExpr, tyStmt}: result = arg
|
||||
else: result = nil
|
||||
else:
|
||||
# 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
|
||||
|
||||
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)
|
||||
if container.isNil:
|
||||
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:
|
||||
result = filterReplace(p.config, stdin, filename, n)
|
||||
if f != filtNone:
|
||||
assert p.config != nil
|
||||
if hintCodeBegin in p.config.notes:
|
||||
rawMessage(p.config, hintCodeBegin, [])
|
||||
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,
|
||||
start: PLLStream): PLLStream =
|
||||
assert p.config != nil
|
||||
result = start
|
||||
if n.kind == nkEmpty: return
|
||||
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;
|
||||
cache: IdentCache; config: ConfigRef) =
|
||||
assert config != nil
|
||||
var s: PLLStream
|
||||
p.skin = skinStandard
|
||||
let filename = fileIdx.toFullPathConsiderDirty
|
||||
var pipe = parsePipe(filename, inputstream, cache, config)
|
||||
p.config() = config
|
||||
if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
|
||||
else: s = inputstream
|
||||
case p.skin
|
||||
|
||||
@@ -614,7 +614,7 @@ proc firstOrd*(t: PType): BiggestInt =
|
||||
else:
|
||||
assert(t.n.sons[0].kind == nkSym)
|
||||
result = t.n.sons[0].sym.position
|
||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic:
|
||||
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred:
|
||||
result = firstOrd(lastSon(t))
|
||||
of tyOrdinal:
|
||||
if t.len > 0: result = firstOrd(lastSon(t))
|
||||
@@ -653,7 +653,7 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
|
||||
of tyEnum:
|
||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||
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))
|
||||
of tyProxy: result = 0
|
||||
of tyOrdinal:
|
||||
|
||||
@@ -210,8 +210,14 @@ proc putIntoNode(n: var PNode; x: TFullReg) =
|
||||
of rkInt: n.intVal = x.intVal
|
||||
of rkFloat: n.floatVal = x.floatVal
|
||||
of rkNode:
|
||||
if nfIsRef in x.node.flags: n = x.node
|
||||
else: n[] = x.node[]
|
||||
if nfIsRef in x.node.flags:
|
||||
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 rkNodeAddr: n[] = x.nodeAddr[][]
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ path="$lib/pure"
|
||||
# Configuration for the GNU C/C++ compiler:
|
||||
@if windows:
|
||||
#gcc.path = r"$nim\dist\mingw\bin"
|
||||
@if gcc:
|
||||
@if gcc or tcc:
|
||||
tlsEmulation:on
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -6298,6 +6298,9 @@ modules don't need to import a module's dependencies:
|
||||
var x: MyObject
|
||||
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
|
||||
-----------
|
||||
In module related statements, if any part of the module name /
|
||||
@@ -7798,8 +7801,9 @@ Future directions:
|
||||
Threadvar pragma
|
||||
----------------
|
||||
|
||||
A global variable can be marked with the ``threadvar`` pragma; it is
|
||||
a `thread-local`:idx: variable then:
|
||||
A variable can be marked with the ``threadvar`` pragma, which makes it a
|
||||
`thread-local`:idx: variable; Additionally, this implies all the effects
|
||||
of the ``global`` pragma.
|
||||
|
||||
.. code-block:: nim
|
||||
var checkpoints* {.threadvar.}: seq[string]
|
||||
|
||||
@@ -385,7 +385,7 @@ type
|
||||
|
||||
{.deprecated: [TBindSymRule: BindSymRule].}
|
||||
|
||||
proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
|
||||
proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {.
|
||||
magic: "NBindSym", noSideEffect.}
|
||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## may be an overloaded symbol.
|
||||
|
||||
@@ -126,6 +126,7 @@ proc tryExec*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): bool {.
|
||||
tags: [ReadDbEffect, WriteDbEffect].} =
|
||||
## 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 stmt: sqlite3.Pstmt
|
||||
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,
|
||||
args: varargs[string]): Pstmt =
|
||||
assert(not db.isNil, "Database not connected.")
|
||||
var q = dbFormat(query, args)
|
||||
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: [].} =
|
||||
## executes the query (typically "INSERT") and returns the
|
||||
## 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 stmt: sqlite3.Pstmt
|
||||
result = -1
|
||||
|
||||
@@ -62,6 +62,7 @@ type
|
||||
frames*: seq[TFrame]
|
||||
screen*: Screen
|
||||
performance*: Performance
|
||||
onpopstate*: proc (event: Event)
|
||||
|
||||
Frame* = ref FrameObj
|
||||
FrameObj {.importc.} = object of WindowObj
|
||||
@@ -175,6 +176,12 @@ type
|
||||
text*: cstring
|
||||
value*: cstring
|
||||
|
||||
TextAreaElement* = ref object of ElementObj
|
||||
value*: cstring
|
||||
selectionStart*, selectionEnd*: int
|
||||
selectionDirection*: cstring
|
||||
rows*, cols*: int
|
||||
|
||||
FormElement* = ref FormObj
|
||||
FormObj {.importc.} = object of ElementObj
|
||||
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), options: AddEventListenerOptions)
|
||||
proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
|
||||
proc dispatchEvent*(et: EventTarget, ev: Event)
|
||||
|
||||
# Window "methods"
|
||||
proc alert*(w: Window, msg: cstring)
|
||||
@@ -500,7 +508,7 @@ proc removeAttributeNode*(n, attr: Node)
|
||||
proc removeChild*(n, child: Node)
|
||||
proc replaceChild*(n, newNode, oldNode: Node)
|
||||
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 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, radix: int):int {.importc, nodecl.}
|
||||
|
||||
proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.}
|
||||
|
||||
type
|
||||
TEventHandlers* {.deprecated.} = EventTargetObj
|
||||
|
||||
@@ -120,6 +120,13 @@ iterator items*[A](s: HashSet[A]): A =
|
||||
for h in 0..high(s.data):
|
||||
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
|
||||
growthFactor = 2
|
||||
|
||||
@@ -690,6 +697,13 @@ iterator items*[A](s: OrderedSet[A]): A =
|
||||
forAllOrderedPairs:
|
||||
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] =
|
||||
assert s.isValid, "The set needs to be initialized"
|
||||
forAllOrderedPairs:
|
||||
|
||||
@@ -331,7 +331,7 @@ proc slave(w: ptr Worker) {.thread.} =
|
||||
await(w.taskArrived)
|
||||
# XXX Somebody needs to look into this (why does this assertion fail
|
||||
# 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:
|
||||
inc numSlavesRunning
|
||||
|
||||
@@ -960,7 +960,7 @@ when defined(posix) and not defined(nimdoc):
|
||||
raise newException(ValueError, "socket path too long")
|
||||
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) =
|
||||
## Connects to Unix socket on `path`.
|
||||
## 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".} =
|
||||
## Preprocess table `a` for `sub`.
|
||||
let m = len(sub)
|
||||
let m1 = m + 1
|
||||
var i = 0
|
||||
while i <= 0xff-7:
|
||||
a[chr(i + 0)] = m1
|
||||
a[chr(i + 1)] = m1
|
||||
a[chr(i + 2)] = m1
|
||||
a[chr(i + 3)] = m1
|
||||
a[chr(i + 4)] = m1
|
||||
a[chr(i + 5)] = m1
|
||||
a[chr(i + 6)] = m1
|
||||
a[chr(i + 7)] = m1
|
||||
a[chr(i + 0)] = m
|
||||
a[chr(i + 1)] = m
|
||||
a[chr(i + 2)] = m
|
||||
a[chr(i + 3)] = m
|
||||
a[chr(i + 4)] = m
|
||||
a[chr(i + 5)] = m
|
||||
a[chr(i + 6)] = m
|
||||
a[chr(i + 7)] = m
|
||||
i += 8
|
||||
|
||||
for i in 0..m-1:
|
||||
a[sub[i]] = m-i
|
||||
for i in 0 ..< m - 1:
|
||||
a[sub[i]] = m - 1 - i
|
||||
|
||||
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
|
||||
{.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`.
|
||||
##
|
||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||
|
||||
let
|
||||
last = if last==0: s.high else: last
|
||||
m = len(sub)
|
||||
n = last + 1
|
||||
# search:
|
||||
var j = start
|
||||
while j <= n - m:
|
||||
block match:
|
||||
for k in 0..m-1:
|
||||
if sub[k] != s[k+j]: break match
|
||||
return j
|
||||
inc(j, a[s[j+m]])
|
||||
sLen = last - start + 1
|
||||
subLast = sub.len - 1
|
||||
|
||||
if subLast == -1:
|
||||
# this was an empty needle string,
|
||||
# we count this as match in the first possible position:
|
||||
return start
|
||||
|
||||
# This is an implementation of the Boyer-Moore Horspool algorithms
|
||||
# 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
|
||||
|
||||
when not (defined(js) or defined(nimdoc) or defined(nimscript)):
|
||||
@@ -1455,23 +1465,41 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
|
||||
proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
||||
rtl, extern: "nsuReplaceStr".} =
|
||||
## Replaces `sub` in `s` by the string `by`.
|
||||
var a {.noinit.}: SkipTable
|
||||
result = ""
|
||||
initSkipTable(a, sub)
|
||||
let last = s.high
|
||||
var i = 0
|
||||
while true:
|
||||
let j = find(a, s, sub, i, last)
|
||||
if j < 0: break
|
||||
add result, substr(s, i, j - 1)
|
||||
let subLen = sub.len
|
||||
if subLen == 0:
|
||||
for c in s:
|
||||
add result, by
|
||||
add result, c
|
||||
add result, by
|
||||
if sub.len == 0:
|
||||
if i < s.len: add result, s[i]
|
||||
i = j + 1
|
||||
else:
|
||||
i = j + sub.len
|
||||
# copy the rest:
|
||||
add result, substr(s, i)
|
||||
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)
|
||||
let last = s.high
|
||||
var i = 0
|
||||
while true:
|
||||
let j = find(a, s, sub, 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)
|
||||
|
||||
proc replace*(s: string, sub, by: char): string {.noSideEffect,
|
||||
rtl, extern: "nsuReplaceChar".} =
|
||||
@@ -1492,6 +1520,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
||||
## Each occurrence of `sub` has to be surrounded by word boundaries
|
||||
## (comparable to ``\\w`` in regular expressions), otherwise it is not
|
||||
## replaced.
|
||||
if sub.len == 0: return s
|
||||
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||
var a {.noinit.}: SkipTable
|
||||
result = ""
|
||||
@@ -2326,236 +2355,243 @@ proc removePrefix*(s: var string, prefix: string) {.
|
||||
s.delete(0, prefix.len - 1)
|
||||
|
||||
when isMainModule:
|
||||
doAssert align("abc", 4) == " abc"
|
||||
doAssert align("a", 0) == "a"
|
||||
doAssert align("1232", 6) == " 1232"
|
||||
doAssert align("1232", 6, '#') == "##1232"
|
||||
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 alignLeft("abc", 4) == "abc "
|
||||
doAssert alignLeft("a", 0) == "a"
|
||||
doAssert alignLeft("1232", 6) == "1232 "
|
||||
doAssert alignLeft("1232", 6, '#') == "1232##"
|
||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
||||
|
||||
let
|
||||
inp = """ this is a long text -- muchlongerthan10chars and here
|
||||
it goes"""
|
||||
outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
|
||||
doAssert wordWrap(inp, 10, false) == outp
|
||||
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"
|
||||
|
||||
let
|
||||
longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
|
||||
longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
|
||||
doAssert wordWrap(longInp, 8, true) == longOutp
|
||||
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 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 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"
|
||||
|
||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
||||
proc staticTests =
|
||||
doAssert align("abc", 4) == " abc"
|
||||
doAssert align("a", 0) == "a"
|
||||
doAssert align("1232", 6) == " 1232"
|
||||
doAssert align("1232", 6, '#') == "##1232"
|
||||
|
||||
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 alignLeft("abc", 4) == "abc "
|
||||
doAssert alignLeft("a", 0) == "a"
|
||||
doAssert alignLeft("1232", 6) == "1232 "
|
||||
doAssert alignLeft("1232", 6, '#') == "1232##"
|
||||
|
||||
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
||||
"The cat eats fish."
|
||||
let
|
||||
inp = """ this is a long text -- muchlongerthan10chars and here
|
||||
it goes"""
|
||||
outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
|
||||
doAssert wordWrap(inp, 10, false) == outp
|
||||
|
||||
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
||||
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
||||
let
|
||||
longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
|
||||
longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
|
||||
doAssert wordWrap(longInp, 8, true) == longOutp
|
||||
|
||||
doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc"
|
||||
doAssert "oo".replace("", "abc") == "abcoabcoabc"
|
||||
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
||||
"The cat eats fish."
|
||||
|
||||
type MyEnum = enum enA, enB, enC, enuD, enE
|
||||
doAssert parseEnum[MyEnum]("enu_D") == enuD
|
||||
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
||||
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
||||
|
||||
doAssert parseEnum("invalid enum value", enC) == enC
|
||||
doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
|
||||
doAssert "oo".replace("", "abc") == "abcoabcoabc"
|
||||
|
||||
doAssert center("foo", 13) == " foo "
|
||||
doAssert center("foo", 0) == "foo"
|
||||
doAssert center("foo", 3, fillChar = 'a') == "foo"
|
||||
doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
|
||||
type MyEnum = enum enA, enB, enC, enuD, enE
|
||||
doAssert parseEnum[MyEnum]("enu_D") == enuD
|
||||
|
||||
doAssert count("foofoofoo", "foofoo") == 1
|
||||
doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
|
||||
doAssert count("foofoofoo", 'f') == 3
|
||||
doAssert count("foofoofoobar", {'f','b'}) == 4
|
||||
doAssert parseEnum("invalid enum value", enC) == enC
|
||||
|
||||
doAssert strip(" foofoofoo ") == "foofoofoo"
|
||||
doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
|
||||
doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
|
||||
doAssert strip("stripme but don't strip this stripme",
|
||||
chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
|
||||
" but don't strip this "
|
||||
doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
|
||||
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
||||
doAssert center("foo", 13) == " foo "
|
||||
doAssert center("foo", 0) == "foo"
|
||||
doAssert center("foo", 3, fillChar = 'a') == "foo"
|
||||
doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
|
||||
|
||||
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
||||
doAssert count("foofoofoo", "foofoo") == 1
|
||||
doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
|
||||
doAssert count("foofoofoo", 'f') == 3
|
||||
doAssert count("foofoofoobar", {'f','b'}) == 4
|
||||
|
||||
doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
|
||||
doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!"
|
||||
doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
|
||||
doAssert strip(" foofoofoo ") == "foofoofoo"
|
||||
doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
|
||||
doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
|
||||
doAssert strip("stripme but don't strip this stripme",
|
||||
chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
|
||||
" but don't strip this "
|
||||
doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
|
||||
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
||||
|
||||
doAssert isAlphaAscii('r')
|
||||
doAssert isAlphaAscii('A')
|
||||
doAssert(not isAlphaAscii('$'))
|
||||
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
||||
|
||||
doAssert isAlphaAscii("Rasp")
|
||||
doAssert isAlphaAscii("Args")
|
||||
doAssert(not isAlphaAscii("$Tomato"))
|
||||
doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
|
||||
doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!"
|
||||
doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
|
||||
|
||||
doAssert isAlphaNumeric('3')
|
||||
doAssert isAlphaNumeric('R')
|
||||
doAssert(not isAlphaNumeric('!'))
|
||||
doAssert isAlphaAscii('r')
|
||||
doAssert isAlphaAscii('A')
|
||||
doAssert(not isAlphaAscii('$'))
|
||||
|
||||
doAssert isAlphaNumeric("34ABc")
|
||||
doAssert isAlphaNumeric("Rad")
|
||||
doAssert isAlphaNumeric("1234")
|
||||
doAssert(not isAlphaNumeric("@nose"))
|
||||
doAssert isAlphaAscii("Rasp")
|
||||
doAssert isAlphaAscii("Args")
|
||||
doAssert(not isAlphaAscii("$Tomato"))
|
||||
|
||||
doAssert isDigit('3')
|
||||
doAssert(not isDigit('a'))
|
||||
doAssert(not isDigit('%'))
|
||||
doAssert isAlphaNumeric('3')
|
||||
doAssert isAlphaNumeric('R')
|
||||
doAssert(not isAlphaNumeric('!'))
|
||||
|
||||
doAssert isDigit("12533")
|
||||
doAssert(not isDigit("12.33"))
|
||||
doAssert(not isDigit("A45b"))
|
||||
doAssert isAlphaNumeric("34ABc")
|
||||
doAssert isAlphaNumeric("Rad")
|
||||
doAssert isAlphaNumeric("1234")
|
||||
doAssert(not isAlphaNumeric("@nose"))
|
||||
|
||||
doAssert isSpaceAscii('\t')
|
||||
doAssert isSpaceAscii('\l')
|
||||
doAssert(not isSpaceAscii('A'))
|
||||
doAssert isDigit('3')
|
||||
doAssert(not isDigit('a'))
|
||||
doAssert(not isDigit('%'))
|
||||
|
||||
doAssert isSpaceAscii("\t\l \v\r\f")
|
||||
doAssert isSpaceAscii(" ")
|
||||
doAssert(not isSpaceAscii("ABc \td"))
|
||||
doAssert isDigit("12533")
|
||||
doAssert(not isDigit("12.33"))
|
||||
doAssert(not isDigit("A45b"))
|
||||
|
||||
doAssert(isNilOrWhitespace(""))
|
||||
doAssert(isNilOrWhitespace(" "))
|
||||
doAssert(isNilOrWhitespace("\t\l \v\r\f"))
|
||||
doAssert(not isNilOrWhitespace("ABc \td"))
|
||||
doAssert isSpaceAscii('\t')
|
||||
doAssert isSpaceAscii('\l')
|
||||
doAssert(not isSpaceAscii('A'))
|
||||
|
||||
doAssert isLowerAscii('a')
|
||||
doAssert isLowerAscii('z')
|
||||
doAssert(not isLowerAscii('A'))
|
||||
doAssert(not isLowerAscii('5'))
|
||||
doAssert(not isLowerAscii('&'))
|
||||
doAssert isSpaceAscii("\t\l \v\r\f")
|
||||
doAssert isSpaceAscii(" ")
|
||||
doAssert(not isSpaceAscii("ABc \td"))
|
||||
|
||||
doAssert isLowerAscii("abcd")
|
||||
doAssert(not isLowerAscii("abCD"))
|
||||
doAssert(not isLowerAscii("33aa"))
|
||||
doAssert(isNilOrWhitespace(""))
|
||||
doAssert(isNilOrWhitespace(" "))
|
||||
doAssert(isNilOrWhitespace("\t\l \v\r\f"))
|
||||
doAssert(not isNilOrWhitespace("ABc \td"))
|
||||
|
||||
doAssert isUpperAscii('A')
|
||||
doAssert(not isUpperAscii('b'))
|
||||
doAssert(not isUpperAscii('5'))
|
||||
doAssert(not isUpperAscii('%'))
|
||||
doAssert isLowerAscii('a')
|
||||
doAssert isLowerAscii('z')
|
||||
doAssert(not isLowerAscii('A'))
|
||||
doAssert(not isLowerAscii('5'))
|
||||
doAssert(not isLowerAscii('&'))
|
||||
|
||||
doAssert isUpperAscii("ABC")
|
||||
doAssert(not isUpperAscii("AAcc"))
|
||||
doAssert(not isUpperAscii("A#$"))
|
||||
doAssert isLowerAscii("abcd")
|
||||
doAssert(not isLowerAscii("abCD"))
|
||||
doAssert(not isLowerAscii("33aa"))
|
||||
|
||||
doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
|
||||
doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
|
||||
doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""]
|
||||
doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"]
|
||||
doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"]
|
||||
doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"]
|
||||
doAssert rsplit("foothebar", sep="the") == @["foo", "bar"]
|
||||
doAssert isUpperAscii('A')
|
||||
doAssert(not isUpperAscii('b'))
|
||||
doAssert(not isUpperAscii('5'))
|
||||
doAssert(not isUpperAscii('%'))
|
||||
|
||||
doAssert(unescape(r"\x013", "", "") == "\x013")
|
||||
doAssert isUpperAscii("ABC")
|
||||
doAssert(not isUpperAscii("AAcc"))
|
||||
doAssert(not isUpperAscii("A#$"))
|
||||
|
||||
doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
|
||||
doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
|
||||
doAssert join([1, 2, 3]) == "123"
|
||||
doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
|
||||
doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
|
||||
doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
|
||||
doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""]
|
||||
doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"]
|
||||
doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"]
|
||||
doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"]
|
||||
doAssert rsplit("foothebar", sep="the") == @["foo", "bar"]
|
||||
|
||||
doAssert """~~!!foo
|
||||
doAssert(unescape(r"\x013", "", "") == "\x013")
|
||||
|
||||
doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
|
||||
doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
|
||||
doAssert join([1, 2, 3]) == "123"
|
||||
doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
|
||||
|
||||
doAssert """~~!!foo
|
||||
~~!!bar
|
||||
~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
|
||||
|
||||
doAssert """~~!!foo
|
||||
doAssert """~~!!foo
|
||||
~~!!bar
|
||||
~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
|
||||
doAssert """~~foo
|
||||
doAssert """~~foo
|
||||
~~ bar
|
||||
~~ baz""".unindent(4, "~") == "foo\n bar\n baz"
|
||||
doAssert """foo
|
||||
doAssert """foo
|
||||
bar
|
||||
baz
|
||||
""".unindent(4) == "foo\nbar\nbaz\n"
|
||||
doAssert """foo
|
||||
doAssert """foo
|
||||
bar
|
||||
baz
|
||||
""".unindent(2) == "foo\n bar\n baz\n"
|
||||
doAssert """foo
|
||||
doAssert """foo
|
||||
bar
|
||||
baz
|
||||
""".unindent(100) == "foo\nbar\nbaz\n"
|
||||
|
||||
doAssert """foo
|
||||
doAssert """foo
|
||||
foo
|
||||
bar
|
||||
""".unindent() == "foo\nfoo\nbar\n"
|
||||
|
||||
let s = " this is an example "
|
||||
let s2 = ":this;is;an:example;;"
|
||||
let s = " this is an example "
|
||||
let s2 = ":this;is;an:example;;"
|
||||
|
||||
doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
|
||||
doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""]
|
||||
doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "]
|
||||
doAssert s.split(' ', maxsplit=1) == @["", "this is an example "]
|
||||
doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "]
|
||||
doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
|
||||
doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""]
|
||||
doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "]
|
||||
doAssert s.split(' ', maxsplit=1) == @["", "this is an example "]
|
||||
doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "]
|
||||
|
||||
doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
|
||||
doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "]
|
||||
doAssert s.splitWhitespace(maxsplit=2) == @["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() == @["this", "is", "an", "example"]
|
||||
doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "]
|
||||
doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "]
|
||||
doAssert s.splitWhitespace(maxsplit=3) == @["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"
|
||||
block: # startsWith / endsWith char tests
|
||||
var s = "abcdef"
|
||||
doAssert s.startsWith('a')
|
||||
doAssert s.startsWith('b') == false
|
||||
doAssert s.endsWith('f')
|
||||
doAssert s.endsWith('a') == false
|
||||
doAssert s.endsWith('\0') == false
|
||||
|
||||
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"
|
||||
#echo("strutils tests passed")
|
||||
|
||||
block: # startsWith / endsWith char tests
|
||||
var s = "abcdef"
|
||||
doAssert s.startsWith('a')
|
||||
doAssert s.startsWith('b') == false
|
||||
doAssert s.endsWith('f')
|
||||
doAssert s.endsWith('a') == false
|
||||
doAssert s.endsWith('\0') == false
|
||||
nonStaticTests()
|
||||
staticTests()
|
||||
static: staticTests()
|
||||
|
||||
#echo("strutils tests passed")
|
||||
|
||||
@@ -29,9 +29,7 @@ when not hasThreadSupport:
|
||||
var
|
||||
colorsFGCache = initTable[Color, string]()
|
||||
colorsBGCache = initTable[Color, string]()
|
||||
when not defined(windows):
|
||||
var
|
||||
styleCache = initTable[int, string]()
|
||||
styleCache = initTable[int, string]()
|
||||
|
||||
var
|
||||
trueColorIsSupported: bool
|
||||
@@ -41,10 +39,8 @@ var
|
||||
const
|
||||
fgPrefix = "\x1b[38;2;"
|
||||
bgPrefix = "\x1b[48;2;"
|
||||
|
||||
when not defined(windows):
|
||||
const
|
||||
stylePrefix = "\e["
|
||||
ansiResetCode* = "\e[0m"
|
||||
stylePrefix = "\e["
|
||||
|
||||
when defined(windows):
|
||||
import winlean, os
|
||||
@@ -468,7 +464,7 @@ proc resetAttributes*(f: File) =
|
||||
else:
|
||||
discard setConsoleTextAttribute(hStdout, oldStdoutAttr)
|
||||
else:
|
||||
f.write("\e[0m")
|
||||
f.write(ansiResetCode)
|
||||
|
||||
type
|
||||
Style* = enum ## different styles for text output
|
||||
@@ -487,15 +483,22 @@ when not defined(windows):
|
||||
gFG {.threadvar.}: int
|
||||
gBG {.threadvar.}: int
|
||||
|
||||
proc getStyleStr(style: int): string =
|
||||
when hasThreadSupport:
|
||||
result = fmt"{stylePrefix}{style}m"
|
||||
proc ansiStyleCode*(style: int): string =
|
||||
when hasThreadSupport:
|
||||
result = fmt"{stylePrefix}{style}m"
|
||||
else:
|
||||
if styleCache.hasKey(style):
|
||||
result = styleCache[style]
|
||||
else:
|
||||
if styleCache.hasKey(style):
|
||||
result = styleCache[style]
|
||||
else:
|
||||
result = fmt"{stylePrefix}{style}m"
|
||||
styleCache[style] = result
|
||||
result = fmt"{stylePrefix}{style}m"
|
||||
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]) =
|
||||
## Sets the terminal style.
|
||||
@@ -510,7 +513,7 @@ proc setStyle*(f: File, style: set[Style]) =
|
||||
discard setConsoleTextAttribute(h, old or a)
|
||||
else:
|
||||
for s in items(style):
|
||||
f.write(getStyleStr(ord(s)))
|
||||
f.write(ansiStyleCode(s))
|
||||
|
||||
proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
|
||||
## 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.resetAttributes()
|
||||
if gFG != 0:
|
||||
stdout.write(getStyleStr(gFG))
|
||||
stdout.write(ansiStyleCode(gFG))
|
||||
if gBG != 0:
|
||||
stdout.write(getStyleStr(gBG))
|
||||
stdout.write(ansiStyleCode(gBG))
|
||||
|
||||
type
|
||||
ForegroundColor* = enum ## terminal's foreground colors
|
||||
@@ -572,7 +575,7 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
|
||||
else:
|
||||
gFG = ord(fg)
|
||||
if bright: inc(gFG, 60)
|
||||
f.write(getStyleStr(gFG))
|
||||
f.write(ansiStyleCode(gFG))
|
||||
|
||||
proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
||||
## Sets the terminal's background color.
|
||||
@@ -594,10 +597,18 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
||||
else:
|
||||
gBG = ord(bg)
|
||||
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:
|
||||
let rgb = extractRGB(color)
|
||||
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"
|
||||
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:
|
||||
let rgb = extractRGB(color)
|
||||
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"
|
||||
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) =
|
||||
## Sets the terminal's foreground true color.
|
||||
if trueColorIsEnabled:
|
||||
f.write(getFGColorStr(color))
|
||||
f.write(ansiForegroundColorCode(color))
|
||||
|
||||
proc setBackgroundColor*(f: File, color: Color) =
|
||||
## Sets the terminal's background true color.
|
||||
if trueColorIsEnabled:
|
||||
f.write(getBGColorStr(color))
|
||||
f.write(ansiBackgroundColorCode(color))
|
||||
|
||||
proc setTrueColor(f: File, color: Color) =
|
||||
if fgSetColor:
|
||||
|
||||
@@ -1069,17 +1069,15 @@ proc splitData*(textNode: PText, offset: int): PText =
|
||||
var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
|
||||
return newNode
|
||||
|
||||
|
||||
# ProcessingInstruction
|
||||
proc target*(pi: PProcessingInstruction): string =
|
||||
## Returns the Processing Instructions target
|
||||
|
||||
return pi.fTarget
|
||||
|
||||
|
||||
# --Other stuff--
|
||||
# Writer
|
||||
proc addEscaped(s: string): string =
|
||||
proc escapeXml*(s: string; result: var string) =
|
||||
## Prepares a string for insertion into a XML document
|
||||
## by escaping the XML special characters.
|
||||
result = ""
|
||||
for c in items(s):
|
||||
case c
|
||||
@@ -1089,11 +1087,20 @@ proc addEscaped(s: string): string =
|
||||
of '"': result.add(""")
|
||||
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 =
|
||||
result = spaces(indent) & "<" & n.nodeName
|
||||
if not isNil(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:
|
||||
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))
|
||||
of TextNode:
|
||||
result.add(spaces(indent * 2))
|
||||
result.add(addEscaped(i.nodeValue))
|
||||
result.add(escapeXml(i.nodeValue))
|
||||
of CDataSectionNode:
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||
|
||||
@@ -241,7 +241,7 @@ when defined(vcc):
|
||||
else:
|
||||
{.error: "invalid CAS instruction".}
|
||||
|
||||
elif defined(tcc) and not defined(windows):
|
||||
elif defined(tcc):
|
||||
when defined(amd64):
|
||||
{.emit:"""
|
||||
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:
|
||||
assert sizeof(int) == 4
|
||||
#assert sizeof(int) == 4
|
||||
{.emit:"""
|
||||
static int __tcc_cas(int *ptr, int oldVal, int newVal)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import sets
|
||||
import hashes
|
||||
import algorithm
|
||||
|
||||
block setEquality:
|
||||
var
|
||||
@@ -35,7 +37,7 @@ block setWithSequences:
|
||||
doAssert( not s.contains(@[4, 5, 6]) )
|
||||
|
||||
block setClearWorked:
|
||||
var s = initSet[char]()
|
||||
var s = initSet[char]()
|
||||
|
||||
for c in "this is a test":
|
||||
s.incl(c)
|
||||
@@ -68,12 +70,54 @@ block orderedSetClearWorked:
|
||||
for c in "eat at joes":
|
||||
s.incl(c)
|
||||
|
||||
r = ""
|
||||
r = ""
|
||||
for c in items(s):
|
||||
add(r, c)
|
||||
|
||||
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 """
|
||||
output: "seq[float]\n0"
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/5602
|
||||
|
||||
import typetraits
|
||||
import typetraits, module_with_generics
|
||||
|
||||
type
|
||||
Foo[T] = object of RootObj
|
||||
@@ -16,3 +17,8 @@ proc p[T](f: Foo[T]): T =
|
||||
var s: Bar[float]
|
||||
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
|
||||
b
|
||||
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"
|
||||
|
||||
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() =
|
||||
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",
|
||||
HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue(
|
||||
r"System\CurrentControlSet\Control\Session Manager\Environment", "Path",
|
||||
HKEY_LOCAL_MACHINE)
|
||||
var alreadyInPath = false
|
||||
var nimAlreadyInPath = false
|
||||
var nimbleAlreadyInPath = false
|
||||
var mingWchoices: seq[string] = @[]
|
||||
var incompat: seq[string] = @[]
|
||||
for x in p.split(';'):
|
||||
@@ -200,18 +202,29 @@ proc main() =
|
||||
let y = try: expandFilename(if x[0] == '"' and x[^1] == '"':
|
||||
substr(x, 1, x.len-2) else: x)
|
||||
except: ""
|
||||
if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true
|
||||
if y.toLowerAscii.contains("mingw"):
|
||||
if y.cmpIgnoreCase(nimDesiredPath) == 0:
|
||||
nimAlreadyInPath = true
|
||||
elif y.cmpIgnoreCase(nimbleDesiredPath) == 0:
|
||||
nimbleAlreadyInPath = true
|
||||
elif y.toLowerAscii.contains("mingw"):
|
||||
if dirExists(y):
|
||||
if checkGccArch(y): mingWchoices.add y
|
||||
else: incompat.add y
|
||||
|
||||
if alreadyInPath:
|
||||
echo "bin/nim.exe is already in your PATH [Skipping]"
|
||||
if nimAlreadyInPath:
|
||||
echo "bin\\nim.exe is already in your PATH [Skipping]"
|
||||
else:
|
||||
if askBool("nim.exe is not in your PATH environment variable.\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:
|
||||
# No mingw in path, so try a few locations:
|
||||
let alternative = tryDirs(incompat, defaultMingwLocations())
|
||||
|
||||
Reference in New Issue
Block a user