Merge branch 'devel' into pr_legacy_asm

This commit is contained in:
ringabout
2025-02-28 20:03:10 +08:00
committed by GitHub
94 changed files with 2957 additions and 958 deletions

View File

@@ -10,6 +10,16 @@ body:
Please provide a minimal code example that reproduces the bug if possible.
Reports with a reproducible example or detailed information will likely receive fixes faster.
- type: textarea
id: nim-version
attributes:
label: Nim Version
description: |
Can be obtained from `nim -v` on the command line along with the OS/architecture.
For development versions, including the commit hash may help.
validations:
required: true
- type: textarea
id: description
attributes:
@@ -19,16 +29,6 @@ body:
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
validations:
required: true
- type: textarea
id: nim-version
attributes:
label: Nim Version
description: |
Can be obtained from `nim -v` on the command line along with the OS/architecture.
For development versions, make sure to include the commit hash.
validations:
required: true
- type: textarea
id: current-logs

View File

@@ -41,7 +41,7 @@ jobs:
target: [linux, windows, osx]
include:
- target: linux
os: ubuntu-20.04
os: ubuntu-22.04
- target: windows
os: windows-2019
- target: osx

View File

@@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-13]
os: [ubuntu-22.04, macos-13]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'

View File

@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
os: [ubuntu-22.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
@@ -21,10 +21,10 @@ jobs:
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
- name: 'Install node.js'
uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version: ''
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
@@ -34,17 +34,6 @@ jobs:
sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash

View File

@@ -169,7 +169,7 @@ echo f
- The Nim compiler now supports a new pragma called ``.localPassc`` to
pass specific compiler options to the C(++) backend for the C(++) file
that was produced from the current Nim module.
- The compiler now inferes "sink parameters". To disable this for a specific routine,
- The compiler now infers "sink parameters". To disable this for a specific routine,
annotate it with `.nosinks`. To disable it for a section of code, use
`{.push sinkInference: off.}`...`{.pop.}`.
- The compiler now supports a new switch `--panics:on` that turns runtime
@@ -261,7 +261,7 @@ echo f
([#12812](https://github.com/nim-lang/Nim/issues/12812))
- Fixed "Produce static/const initializations for variables when possible"
([#12216](https://github.com/nim-lang/Nim/issues/12216))
- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors"
- Fixed "Assigning discriminator field leads to internal assert with --gc:destructors"
([#12821](https://github.com/nim-lang/Nim/issues/12821))
- Fixed "nimsuggest `use` command does not return all instances of symbol"
([#12832](https://github.com/nim-lang/Nim/issues/12832))

View File

@@ -2198,6 +2198,13 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: putIntoDest(p, d, e, cIntValue(lengthOrd(p.config, typ)))
else: internalError(p.config, e.info, "genArrayLen()")
proc isTrivialTypesToSnippet(t: PType): Snippet =
if containsGarbageCollectedRef(t) or
hasDestructor(t):
result = NimFalse
else:
result = NimTrue
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
if optSeqDestructors in p.config.globalOptions:
e[1] = makeAddr(e[1], p.module.idgen)
@@ -2220,7 +2227,8 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
pExpr = cIfExpr(ra, cAddr(derefField(ra, "Sup")), NimNil)
else:
pExpr = ra
call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb))
call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb,
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0])))
genAssignment(p, a, call, {})
gcUsage(p.config, e)

View File

@@ -57,11 +57,15 @@ proc mangleField(m: BModule; name: PIdent): string =
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
var params = ""
var staticLists = ""
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])
params.add encodeType(m, s.typ[i], staticLists)
result.add encodeSym(m, s, makeUnique, staticLists)
result.add params
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
@@ -115,7 +119,7 @@ proc fillLocalName(p: BProc; s: PSym) =
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
elif s.kind != skResult:
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
s.loc.snippet = result
@@ -247,10 +251,6 @@ proc hasNoInit(t: PType): bool =
proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDescKind): Rope
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.baseClass == nil) or isPureObject(typ))
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
# Arrays and sets cannot be returned by a C procedure, because C is
# such a poor programming language.

View File

@@ -11,7 +11,7 @@
import
ast, types, msgs, wordrecg,
platform, trees, options, cgendata, mangleutils
platform, trees, options, cgendata, mangleutils, renderer
import std/[hashes, strutils, formatfloat]
@@ -101,7 +101,11 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = true # ordinary objects are always passed by reference,
# otherwise casting doesn't work
of tyTuple:
result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
if s.typ.kind == tySink:
# it's a sink, so we pass it by value
result = false
else:
result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options)
else:
result = false
# first parameter and return type is 'lent T'? --> use pass by pointer
@@ -120,14 +124,14 @@ proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false; extra: string = ""): string =
#Module::Type
var name = s.name.s
var name = s.name.s & extra
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
proc encodeType*(m: BModule; t: PType): string =
proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
@@ -138,10 +142,10 @@ proc encodeType*(m: BModule; t: PType): string =
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add encodeType(m, t[i], staticLists)
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
tyPtr, tyRef, tyVar, tyLent, tySink, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
@@ -150,8 +154,13 @@ proc encodeType*(m: BModule; t: PType): string =
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add encodeType(m, s, staticLists)
result.add "E"
of tyStatic:
if t.n != nil:
staticLists.add "_s" & renderTree(t.n)
else:
raiseAssert "unreachable"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
@@ -164,7 +173,7 @@ proc encodeType*(m: BModule; t: PType): string =
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
result = encodeType(m, t.elementType, staticLists)
else:
assert false, "encodeType " & $t.kind

View File

@@ -172,6 +172,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasDefaultFloatRoundtrip")
defineSymbol("nimHasXorSet")
defineSymbol("nimHasLegacyNoStrictDefs")
defineSymbol("nimHasAsmSemSymbol")

View File

@@ -1197,7 +1197,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not isObjLackingTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
@@ -1207,6 +1207,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
result.ast[pragmasPos].add newTree(nkExprColonExpr,
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
if kind == attachedDestructor:
incl result.options, optQuirky
completePartialOp(g, idgen.module, typ, kind, result)

View File

@@ -48,7 +48,7 @@ define:useStdoutAsStdmsg
@if nimUseStrictDefs:
experimental:strictDefs # deadcode
experimental:strictDefs
warningAsError[Uninit]:on
warningAsError[ProveInit]:on
@end

View File

@@ -248,8 +248,6 @@ type
## Useful for libraries that rely on local passC
jsNoLambdaLifting
## Old transformation for closures in JS backend
noStrictDefs
## disable "strictdefs"
noAsmSemSymbol
## disable type checking for backticked symbols in the `asm/emit` statements

View File

@@ -590,7 +590,7 @@ proc processCompile(c: PContext, n: PNode) =
var customArgs = ""
if n.kind in nkCallKinds:
s = getStrLit(c, n, 1)
if n.len <= 3:
if n.len == 3:
customArgs = getStrLit(c, n, 2)
else:
localError(c.config, n.info, "'.compile' pragma takes up 2 arguments")
@@ -1319,8 +1319,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises, wQuirky:
of wEnforceNoRaises:
sym.flags.incl sfNeverRaises
of wQuirky:
sym.flags.incl sfNeverRaises
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
sym.options.incl optQuirky
of wSystemRaisesDefect:
sym.flags.incl sfSystemRaisesDefect
of wVirtual:

View File

@@ -500,6 +500,21 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
dec(c.config.evalTemplateCounter)
discard c.friendModules.pop()
proc getLineInfo(n: PNode): TLineInfo =
case n.kind
of nkPostfix:
if len(n) > 1:
result = getLineInfo(n[1])
else:
result = n.info
of nkAccQuoted, nkPragmaExpr:
if len(n) > 0:
result = getLineInfo(n[0])
else:
result = n.info
else:
result = n.info
const
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"

View File

@@ -878,7 +878,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
if aa notin {arLValue, arLocalLValue}:
if aa == arDiscriminant and c.inUncheckedAssignSection > 0:
discard "allow access within a cast(unsafeAssign) section"
elif noStrictDefs notin c.config.legacyFeatures and aa == arAddressableConst and
elif strictDefs in c.features and aa == arAddressableConst and
sym != nil and sym.kind == skLet and isOutParam:
discard "allow let varaibles to be passed to out parameters"
else:
@@ -2068,8 +2068,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
let root = getRoot(a)
let useStrictDefLet = root != nil and root.kind == skLet and
assignable == arAddressableConst and
noStrictDefs notin c.config.legacyFeatures and
isLocalSym(root)
strictDefs in c.features and isLocalSym(root)
if le == nil:
localError(c.config, a.info, "expression has no type")
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
@@ -2929,7 +2928,10 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i][1] = fitNode(c, expectedElemType, n[i][1], n[i][1].info)
let conversion = indexTypesMatch(c, expectedElemType, n[i][1].typ, n[i][1])
# ignore matching error, full tuple will be matched later which may call converter, see #24609
if conversion != nil:
n[i][1] = conversion
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@@ -2942,7 +2944,14 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
typ.n.add newSymNode(f)
n[i][0] = newSymNode(f)
result.add n[i]
let oldType = n.typ
result.typ() = typ
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
# convert back to old type
let conversion = indexTypesMatch(c, oldType, typ, result)
# ignore matching error, the goal is just to keep the original type info
if conversion != nil:
result = conversion
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = n # we don't modify n, but compute the type:
@@ -2961,9 +2970,19 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i] = fitNode(c, expectedElemType, n[i], n[i].info)
let conversion = indexTypesMatch(c, expectedElemType, n[i].typ, n[i])
# ignore matching error, full tuple will be matched later which may call converter, see #24609
if conversion != nil:
n[i] = conversion
addSonSkipIntLit(typ, n[i].typ.skipTypes({tySink}), c.idgen)
let oldType = n.typ
result.typ() = typ
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
# convert back to old type
let conversion = indexTypesMatch(c, oldType, typ, result)
# ignore matching error, the goal is just to keep the original type info
if conversion != nil:
result = conversion
include semobjconstr
@@ -3052,9 +3071,12 @@ proc semExport(c: PContext, n: PNode): PNode =
s = nextOverloadIter(o, c, a)
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var tupexp = semTuplePositionsConstr(c, n, flags, expectedType)
result = semTuplePositionsConstr(c, n, flags, expectedType)
var tupexp = result
while tupexp.kind == nkHiddenSubConv: tupexp = tupexp[1]
var isTupleType: bool = false
if tupexp.len > 0: # don't interpret () as type
internalAssert c.config, tupexp.kind == nkTupleConstr
isTupleType = tupexp[0].typ.kind == tyTypeDesc
# check if either everything or nothing is tyTypeDesc
for i in 1..<tupexp.len:
@@ -3064,8 +3086,6 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
result = n
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ() = makeTypeDesc(c, typ)
else:
result = tupexp
proc isExplicitGenericCall(c: PContext, n: PNode): bool =
## checks if a call node `n` is a routine call with explicit generic params

View File

@@ -36,7 +36,8 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
of nkIdent, nkSym:
result = n
let ident = considerQuotedIdent(c.c, n)
if c.replaceByFieldName:
if c.replaceByFieldName and
ident.id != ord(wUnderscore):
if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
@@ -45,7 +46,8 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return
# other fields:
for i in ord(c.replaceByFieldName)..<forLoop.len-2:
if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
if ident.id == considerQuotedIdent(c.c, forLoop[i]).id and
ident.id != ord(wUnderscore):
var call = forLoop[^2]
var tupl = call[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:

View File

@@ -55,7 +55,7 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
result.add typExpr
if typExpr.typ.kind == tyFromExpr:
typExpr.typ.flags.incl tfNonConstExpr
result.typ() = makeTypeDesc(c, typExpr.typ)
result.typ() = makeTypeDesc(c, typExpr.typ.skipTypes({tyStatic}))
type
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn

View File

@@ -124,10 +124,11 @@ proc collectObjectTree(graph: ModuleGraph, n: PNode) =
else:
graph.objectTree[root].add (depthLevel, typ)
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil or sfGeneratedOp in tracked.owner.flags:
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit = false) =
if typ == nil or (sfGeneratedOp in tracked.owner.flags and not explicit):
# don't create type bound ops for anything in a function with a `nodestroy` pragma
# bug #21987
# unless this is an explicit call, bug #24626
return
when false:
let realType = typ.skipTypes(abstractInst)
@@ -136,8 +137,9 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen)
if (tfHasAsgn in typ.flags) or
optSeqDestructors in tracked.config.globalOptions:
if tracked.config.selectedGC == gcRefc or
optSeqDestructors in tracked.config.globalOptions or
tfHasAsgn in typ.flags:
tracked.owner.flags.incl sfInjectDestructors
proc isLocalSym(a: PEffects, s: PSym): bool =
@@ -221,7 +223,7 @@ proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
if volatileCheck: makeVolatile(a, s)
for x in a.init:
if x == s.id:
if noStrictDefs notin a.c.config.legacyFeatures and s.kind == skLet:
if strictDefs in a.c.features and s.kind == skLet:
localError(a.config, n.info, errXCannotBeAssignedTo %
renderTree(n, {renderNoComments}
))
@@ -379,7 +381,7 @@ proc useVar(a: PEffects, n: PNode) =
if s.typ.requiresInit:
message(a.config, n.info, warnProveInit, s.name.s)
elif a.leftPartOfAsgn <= 0:
if noStrictDefs notin a.c.config.legacyFeatures:
if strictDefs in a.c.features:
if s.kind == skLet:
localError(a.config, n.info, errLetNeedsInit)
else:
@@ -1072,7 +1074,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
# rebind type bounds operations after createTypeBoundOps call
let t = n[1].typ.skipTypes({tyAlias, tyVar})
if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
createTypeBoundOps(tracked, t, n.info)
createTypeBoundOps(tracked, t, n.info, explicit = true)
let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
if op != nil:
n[0].sym = op
@@ -1664,7 +1666,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
if not isEmptyType(s.typ.returnType) and
(s.typ.returnType.requiresInit or s.typ.returnType.skipTypes(abstractInst).kind == tyVar or
noStrictDefs notin c.config.legacyFeatures) and
strictDefs in c.features) and
s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone and
sfNoInit notin s.flags:
var res = s.ast[resultPos].sym # get result symbol

View File

@@ -492,19 +492,8 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = tru
incl(result.flags, sfGlobal)
result.options = c.config.options
proc getLineInfo(n: PNode): TLineInfo =
case n.kind
of nkPostfix:
if len(n) > 1:
return getLineInfo(n[1])
of nkAccQuoted, nkPragmaExpr:
if len(n) > 0:
return getLineInfo(n[0])
else:
discard
result = n.info
let info = getLineInfo(n)
if reportToNimsuggest:
let info = getLineInfo(n)
suggestSym(c.graph, info, result, c.graph.usageSym)
proc checkNilable(c: PContext; v: PSym) =
@@ -975,7 +964,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
else:
checkNilable(c, v)
# allow let to not be initialised if imported from C:
if v.kind == skLet and sfImportc notin v.flags and (noStrictDefs in c.config.legacyFeatures or not isLocalSym(v)):
if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)):
localError(c.config, a.info, errLetNeedsInit)
if sfCompileTime in v.flags:
var x = newNodeI(result.kind, v.info)
@@ -1787,6 +1776,17 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# check the style here after the pragmas have been processed:
styleCheckDef(c, s)
# compute the type's size and check for illegal recursions:
if a[0].kind == nkPragmaExpr:
let pragmas = a[0][1]
for i in 0 ..< pragmas.len:
if pragmas[i].kind == nkExprColonExpr and
pragmas[i][0].kind == nkIdent and
whichKeyword(pragmas[i][0].ident) == wSize:
if s.typ.kind != tyEnum and sfImportc notin s.flags:
# EventType* {.size: sizeof(uint32).} = enum
# AtomicFlag* {.importc: "atomic_flag", header: "<stdatomic.h>", size: 1.} = object
localError(c.config, pragmas[i].info, "size pragma only allowed for enum types and imported types")
if a[1].kind == nkEmpty:
var x = a[2]
if x.kind in nkCallKinds and nfSem in x.flags:
@@ -2158,9 +2158,6 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if op == attachedDestructor and t.firstParamType.kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
@@ -2351,7 +2348,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
isInitializer = false
break
var j = 0
while p[j].sym.kind == skParam:
while p[j].kind == nkSym and p[j].sym.kind == skParam:
initializerCall.add val
inc j
if isInitializer:

View File

@@ -67,7 +67,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
if isField:
# possibly not final field sym
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
else:
markUsed(c, info, s)
onUse(info, s)
else:
result = n
@@ -691,6 +696,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s = semIdentVis(c, skTemplate, n[namePos], {})
assert s.kind == skTemplate
let info = getLineInfo(n[namePos])
suggestSym(c.graph, info, s, c.graph.usageSym)
styleCheckDef(c, s)
onDef(n[namePos].info, s)
# check parameter list:

View File

@@ -1501,7 +1501,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
addParamOrResult(c, arg, kind)
styleCheckDef(c, a[j].info, arg)
onDef(a[j].info, arg)
a[j] = newSymNode(arg)
if a[j].kind == nkPragmaExpr:
a[j][0] = newSymNode(arg)
else:
a[j] = newSymNode(arg)
var r: PType = nil
if n[0].kind != nkEmpty:
@@ -1671,6 +1674,11 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
var err = "cannot instantiate "
err.addTypeHeader(c.config, t)
err.add "\ngot: <$1>\nbut expected: <$2>" % [describeArgs(c, n), describeArgs(c, t.n, 0)]
if m.firstMismatch.kind == kTypeMismatch and m.firstMismatch.arg < n.len:
let nArg = n[m.firstMismatch.arg]
if nArg.kind in nkSymChoices:
err.add "\n"
err.add ambiguousIdentifierMsg(nArg)
localError(c.config, n.info, errGenerated, err)
return newOrPrevType(tyError, prev, c)
@@ -1728,10 +1736,10 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
else:
result = nil
proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
proc fixupTypeOf(c: PContext, prev: PType, typ: PType) =
if prev != nil:
let result = newTypeS(tyAlias, c)
result.rawAddSon typExpr.typ
result.rawAddSon typ
result.sym = prev.sym
if prev.kind != tyGenericBody:
assignType(prev, result)
@@ -1923,10 +1931,11 @@ proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n, {efInTypeof})
let ex = semExprWithType(c, n, {efInTypeof})
closeScope(c)
let t = ex.typ.skipTypes({tyStatic})
fixupTypeOf(c, prev, t)
result = t.typ
result = t
if result.kind == tyFromExpr:
result.flags.incl tfNonConstExpr
@@ -1941,10 +1950,11 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
m = mode.intVal
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
let ex = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
closeScope(c)
let t = ex.typ.skipTypes({tyStatic})
fixupTypeOf(c, prev, t)
result = t.typ
result = t
if result.kind == tyFromExpr:
result.flags.incl tfNonConstExpr

View File

@@ -1424,7 +1424,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
return isNone
if fRange.rangeHasUnresolvedStatic:
if aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange:
if (aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange) or
(aRange.kind == tyRange and aRange.rangeHasUnresolvedStatic):
return
return inferStaticsInRange(c, fRange, a)
elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
@@ -1692,7 +1693,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if aAsObject.kind == tyObject and trIsOutParam notin flags:
let baseType = aAsObject.base
if baseType != nil:
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
if tfFinal notin aAsObject.flags:
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
let ret = typeRel(c, f, baseType, flags)
return if ret in {isEqual,isGeneric}: isSubtype else: ret
@@ -1733,6 +1735,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let tr = typeRel(c, f[i], x[i], flags)
if tr <= isSubtype: return
result = isGeneric
let impl = last(f[0])
if impl.kind == tyObject and tfFinal notin impl.flags:
# match non-invocation case
inc c.inheritancePenalty, 0 + int(c.inheritancePenalty < 0)
elif x.kind == tyGenericInst and f[0] == x[0] and
x.len - 1 == f.len:
for i in 1..<f.len:
@@ -1789,7 +1795,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
depth = -1
if depth >= 0:
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
if aobj.kind == tyObject and tfFinal notin aobj.flags:
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
# bug #4863: We still need to bind generic alias crap, so
# we cannot return immediately:
result = if depth == 0: isGeneric else: isSubtype
@@ -2251,7 +2258,7 @@ proc isLValue(c: PContext; n: PNode, isOutParam = false): bool {.inline.} =
result = c.inUncheckedAssignSection > 0
of arAddressableConst:
let sym = getRoot(n)
result = noStrictDefs notin c.config.legacyFeatures and sym != nil and sym.kind == skLet and isOutParam
result = strictDefs in c.features and sym != nil and sym.kind == skLet and isOutParam
else:
result = false

View File

@@ -106,6 +106,13 @@ proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
for i in 0..<n.len:
result[i] = transform(c, n[i], noConstFold)
proc transformSonsAfterType(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
assert n.len != 0
result[0] = copyTree(n[0])
for i in 1..<n.len:
result[i] = transform(c, n[i], noConstFold)
proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
result = newTransNode(kind, ri.info, 2)
result[0] = le
@@ -1102,6 +1109,9 @@ proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = transformConv(c, n)
of nkObjConstr, nkCast:
# don't try to transform type node
result = transformSonsAfterType(c, n)
of nkDiscardStmt:
result = n
if n[0].kind != nkEmpty:

View File

@@ -1485,8 +1485,17 @@ proc commonSuperclass*(a, b: PType): PType =
y = y.baseClass
proc lacksMTypeField*(typ: PType): bool {.inline.} =
## Returns true if the type is an object that lacks a m_type field.
## It doesn't check base classes.
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
proc isObjLackingTypeField*(typ: PType): bool {.inline.} =
## Returns true if the type is an object that lacks a type field.
## Object types that store type headers are not final or pure and
## have inheritable root types, which are not pure, neither.
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.baseClass == nil) or isPureObject(typ))
include sizealignoffsetimpl
proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt =

View File

@@ -12,7 +12,7 @@
import semmacrosanity
import
std/[strutils, tables, parseutils],
std/[strutils, tables, intsets, parseutils],
msgs, vmdef, vmgen, nimsets, types,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
@@ -2425,9 +2425,12 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
setupGlobalCtx(module, g, idgen)
var c = PCtx g.vm
let oldMode = c.mode
let oldLocals = c.locals
c.mode = mode
c.locals = initIntSet()
c.cannotEval = false
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
c.locals = oldLocals
if c.cannotEval:
return errorNode(idgen, prc, n)
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import std/[tables, strutils]
import std/[tables, strutils, intsets]
import ast, idents, options, modulegraphs, lineinfos
@@ -272,6 +272,7 @@ type
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
cannotEval*: bool
locals*: IntSet
PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object

View File

@@ -1583,6 +1583,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
elif s.kind in {skVar, skLet} and s.id in c.locals: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
@@ -1975,7 +1976,7 @@ proc genVarSection(c: PCtx; n: PNode) =
c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
elif a[0].kind == nkSym:
let s = a[0].sym
checkCanEval(c, a[0])
c.locals.incl(s.id)
if s.isGlobal:
let runtimeAccessToCompileTime = c.mode == emRepl and
sfCompileTime in s.flags and s.position > 0
@@ -2040,7 +2041,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
let seqType = n.typ.skipTypes(abstractVar+{tyStatic}-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
c.gABx(n, opcLdImmInt, tmp, n.len)

View File

@@ -263,7 +263,7 @@ proc registerAdditionalOps*(c: PCtx) =
wrap2si(readLines, ioop)
systemop getCurrentExceptionMsg
systemop getCurrentException
registerCallback c, "stdlib.osdirs.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
registerCallback c, "stdlib.staticos.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
registerCallback c, "stdlib.staticos.staticDirExists", proc (a: VmArgs) {.nimcall.} =
setResult(a, dirExists(getString(a, 0)))

View File

@@ -21,4 +21,3 @@ when defined(nimStrictMode):
# future work: XDeclaredButNotUsed
switch("define", "nimVersion:" & NimVersion) # deadcode
switch("experimental", "strictDefs")

View File

@@ -129,7 +129,8 @@ other associated resources. Variables are destroyed via this hook when
they go out of scope or when the routine they were declared in is about
to return.
A `=destroy` hook is allowed to have a parameter of a `var T` or `T` type. Taking a `var T` type is deprecated. The prototype of this hook for a type `T` needs to be:
A `=destroy` hook is allowed to have a parameter of a `var T` or `T` type.
The prototype of this hook for a type `T` needs to be:
```nim
proc `=destroy`(x: T)

View File

@@ -5186,22 +5186,22 @@ caught by reference. Example:
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b: cstring
var b = ""
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = e.what()
doAssert $b == "foo2"
b = $e.what()
doAssert b == "foo2"
try: raise initStdException()
except CStdException: discard
try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = e.what()
b = $e.what()
except CStdException:
doAssert false
doAssert $b == "foo3"
doAssert b == "foo3"
fn()
```

View File

@@ -30,28 +30,30 @@ a working NodeJS on `PATH`.
Commands
========
========================== ==========================
p|pat|pattern <glob> run all the tests matching the given pattern
all run all tests inside of category folders
c|cat|category <category> run all the tests of a certain category
r|run <test> run single test file
html generate testresults.html from the database
========================== ==========================
Options
=======
--print print results to the console
--verbose print commands (compiling and running tests)
--simulate see what tests would be run but don't run them (for debugging)
--failing only show failing/ignored tests
--targets:"c cpp js objc" run tests for specified targets (default: c)
--nim:path use a particular nim executable (default: $PATH/nim)
--directory:dir Change to directory dir before reading the tests or doing anything else.
--colors:on|off Turn messages coloring on|off.
--backendLogging:on|off Disable or enable backend logging. By default turned on.
--megatest:on|off Enable or disable megatest. Default is on.
--valgrind:on|off Enable or disable valgrind support. Default is on.
--skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored
--print print results to the console
--verbose print commands (compiling and running tests)
--simulate see what tests would be run but don't run them (for debugging)
--failing only show failing/ignored tests
--targets:"c cpp js objc" run tests for specified targets (default: c)
--nim:path use a particular nim executable (default: $PATH/nim)
--directory:dir Change to directory dir before reading the tests or doing anything else.
--colors:on|off Turn messages coloring on|off.
--backendLogging:on|off Disable or enable backend logging. By default turned on.
--megatest:on|off Enable or disable megatest. Default is on.
--valgrind:on|off Enable or disable valgrind support. Default is on.
--skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored
Running a single test

View File

@@ -171,7 +171,7 @@ proc bundleAtlasExe(latest: bool, args: string) =
cloneDependency(distDir, "https://github.com/nim-lang/atlas.git",
commit = commit, allowBundled = true)
cloneDependency(distDir / "atlas" / distDir, "https://github.com/nim-lang/sat.git",
commit = SatStableCommit, allowBundled = true)
commit = SatStableCommit, allowBundled = true)
# installer.ini expects it under $nim/bin
nimCompile("dist/atlas/src/atlas.nim",
options = "-d:release --noNimblePath -d:nimAtlasBootstrap " & args)

View File

@@ -1490,7 +1490,9 @@ proc clearInterval*(i: Interval) {.importc, nodecl.}
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 dispatchEvent*(et: EventTarget, ev: Event)
proc removeEventListener*(et: EventTarget; ev: cstring; cb: proc(ev: Event))
proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false)
proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), options: AddEventListenerOptions)
# Window "methods"
proc alert*(w: Window, msg: cstring)

View File

@@ -33,7 +33,7 @@ runnableExamples:
{.push checks: off, line_dir: off, stack_trace: off, debugger: off.}
# the user does not want to trace a part of the standard library!
import std/[math, strformat]
import std/[math, strformat, strutils]
type
Complex*[T: SomeFloat] = object

View File

@@ -105,7 +105,7 @@ when not defined(js) and not defined(nimscript): # C
when compileOption("overflowChecks"):
if y == 0:
raise new(DivByZeroDefect)
elif (x == T.low and y == -1.T):
elif (x == T.low and int64(y) == -1):
raise new(OverflowDefect)
let res = divmod_c(x, y)
result[0] = res.quot
@@ -1145,6 +1145,37 @@ func prod*[T](x: openArray[T]): T =
result = T(1)
for i in items(x): result = result * i
func cumprod*[T](x: var openArray[T]) =
## Transforms ``x`` in-place (must be declared as `var`) into its
## product.
##
## See also:
## * `prod proc <#sum,openArray[T]>`_
## * `cumproded proc <#cumproded,openArray[T]>`_ for a version which
## returns cumproded sequence
runnableExamples:
var a = [1, 2, 3, 4]
cumprod(a)
doAssert a == @[1, 2, 6, 24]
for i in 1 ..< x.len: x[i] = x[i-1] * x[i]
func cumproded*[T](x: openArray[T]): seq[T] =
## Return cumulative (aka prefix) product of ``x``.
##
## See also:
## * `prod proc <#prod,openArray[T]>`_
## * `cumprod proc <#cumprod,openArray[T]>`_ for the in-place version
runnableExamples:
let a = [1, 2, 3, 4]
doAssert cumproded(a) == @[1, 2, 6, 24]
result = @[]
let xLen = x.len
if xLen == 0:
return @[]
result.setLen(xLen)
result[0] = x[0]
for i in 1 ..< xLen: result[i] = result[i-1] * x[i]
func cumsummed*[T](x: openArray[T]): seq[T] =
## Returns the cumulative (aka prefix) summation of `x`.
##
@@ -1353,3 +1384,4 @@ func lcm*[T](x: openArray[T]): T {.since: (1, 1).} =
result = x[0]
for i in 1 ..< x.len:
result = lcm(result, x[i])

File diff suppressed because it is too large Load Diff

View File

@@ -527,7 +527,6 @@ proc parseSaturatedNatural*(s: openArray[char], b: var int): int {.
proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int =
var
res = 0.BiggestUInt
prev = 0.BiggestUInt
i = 0
if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
integerOutOfRangeError()
@@ -535,8 +534,11 @@ proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int =
if i < s.len and s[i] in {'0'..'9'}:
b = 0
while i < s.len and s[i] in {'0'..'9'}:
prev = res
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
if res > BiggestUInt.high div 10: # Highest value that you can multiply 10 without overflow
integerOutOfRangeError()
res = res * 10
let prev = res
res += (ord(s[i]) - ord('0')).BiggestUInt
if prev > res:
integerOutOfRangeError()
inc(i)

View File

@@ -109,7 +109,7 @@ import std/private/since
import std/exitprocs
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[assertions, syncio]
import std/[macros, strutils, streams, times, sets, sequtils]

View File

@@ -19,7 +19,7 @@ include system/inclrtl
when defined(nimPreviewSlimSystem):
import std/widestrs
when defined(nodejs):
from std/private/oscommon import ReadDirEffect
@@ -33,8 +33,6 @@ elif defined(windows):
import std/winlean
elif defined(posix):
import std/posix
else:
{.error: "The cmdline module has not been implemented for the target platform.".}
# Needed by windows in order to obtain the command line for targets

View File

@@ -110,6 +110,10 @@ when defined(js):
}
if (Number.isSafeInteger(`a`))
`result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0";
else if (isNaN(`a`)) // Number.isNaN is since ES6
`result` = "nan"; // or it'll be "NaN"
else if (!isFinite(`a`)) // Number.isFinite newer but unnecessary here
`result` = `a` > 0 ? "inf" : "-inf"; // or it'll be [-]Infinity
else {
`result` = `a`+"";
if(nimOnlyDigitsOrMinus(`result`)){

View File

@@ -5,9 +5,13 @@ import std/[oserrors]
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, widestrs]
from std/staticos import PathComponent
## .. importdoc:: osdirs.nim, os.nim
const weirdTarget* = defined(nimscript) or defined(js)
const
weirdTarget* = defined(nimscript) or defined(js)
supportedSystem* = weirdTarget or defined(windows) or defined(posix)
type
@@ -27,8 +31,6 @@ elif defined(posix):
import std/posix
proc c_rename(oldname, newname: cstring): cint {.
importc: "rename", header: "<stdio.h>".}
else:
{.error: "OS module not ported to your operating system!".}
when weirdTarget:
@@ -65,122 +67,110 @@ when defined(windows) and not weirdTarget:
result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or
f.cFileName[1].int == dot and f.cFileName[2].int == 0)
when supportedSystem:
when defined(posix) and not weirdTarget:
proc getSymlinkFileKind*(path: string):
tuple[pc: PathComponent, isSpecial: bool] =
# Helper function.
var s: Stat
assert(path != "")
result = (pcLinkToFile, false)
if stat(path, s) == 0'i32:
if S_ISDIR(s.st_mode):
result = (pcLinkToDir, false)
elif not S_ISREG(s.st_mode):
result = (pcLinkToFile, true)
type
PathComponent* = enum ## Enumeration specifying a path component.
proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.} =
## Moves a file (or directory if `isDir` is true) from `source` to `dest`.
##
## Returns false in case of `EXDEV` error or `AccessDeniedError` on Windows (if `isDir` is true).
## In case of other errors `OSError` is raised.
## Returns true in case of success.
when defined(windows):
let s = newWideCString(source)
let d = newWideCString(dest)
result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
else:
result = c_rename(source, dest) == 0'i32
if not result:
let err = osLastError()
let isAccessDeniedError =
when defined(windows):
const AccessDeniedError = OSErrorCode(5)
isDir and err == AccessDeniedError
else:
err == EXDEV.OSErrorCode
if not isAccessDeniedError:
raiseOSError(err, $(source, dest))
when not defined(windows):
const maxSymlinkLen* = 1024
proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect], noNimJs, sideEffect.} =
## Returns true if `filename` exists and is a regular file or symlink.
##
## Directories, device files, named pipes and sockets return false.
##
## See also:
## * `walkDirRec iterator`_
## * `FileInfo object`_
pcFile, ## path refers to a file
pcLinkToFile, ## path refers to a symbolic link to a file
pcDir, ## path refers to a directory
pcLinkToDir ## path refers to a symbolic link to a directory
## * `dirExists proc`_
## * `symlinkExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, filename)
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
else:
var res: Stat
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
when defined(posix) and not weirdTarget:
proc getSymlinkFileKind*(path: string):
tuple[pc: PathComponent, isSpecial: bool] =
# Helper function.
var s: Stat
assert(path != "")
result = (pcLinkToFile, false)
if stat(path, s) == 0'i32:
if S_ISDIR(s.st_mode):
result = (pcLinkToDir, false)
elif not S_ISREG(s.st_mode):
result = (pcLinkToFile, true)
proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.} =
## Moves a file (or directory if `isDir` is true) from `source` to `dest`.
##
## Returns false in case of `EXDEV` error or `AccessDeniedError` on Windows (if `isDir` is true).
## In case of other errors `OSError` is raised.
## Returns true in case of success.
when defined(windows):
let s = newWideCString(source)
let d = newWideCString(dest)
result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
else:
result = c_rename(source, dest) == 0'i32
if not result:
let err = osLastError()
let isAccessDeniedError =
when defined(windows):
const AccessDeniedError = OSErrorCode(5)
isDir and err == AccessDeniedError
else:
err == EXDEV.OSErrorCode
if not isAccessDeniedError:
raiseOSError(err, $(source, dest))
when not defined(windows):
const maxSymlinkLen* = 1024
proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect], noNimJs, sideEffect.} =
## Returns true if `filename` exists and is a regular file or symlink.
##
## Directories, device files, named pipes and sockets return false.
##
## See also:
## * `dirExists proc`_
## * `symlinkExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, filename)
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
else:
var res: Stat
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect],
noNimJs, sideEffect.} =
## Returns true if the directory `dir` exists. If `dir` is a file, false
## is returned. Follows symlinks.
##
## See also:
## * `fileExists proc`_
## * `symlinkExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, dir)
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
else:
var res: Stat
result = stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect],
noNimJs, sideEffect.} =
## Returns true if the directory `dir` exists. If `dir` is a file, false
## is returned. Follows symlinks.
##
## See also:
## * `fileExists proc`_
## * `symlinkExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, dir)
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
else:
var res: Stat
result = stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect],
noWeirdTarget, sideEffect.} =
## Returns true if the symlink `link` exists. Will return true
## regardless of whether the link points to a directory or file.
##
## See also:
## * `fileExists proc`_
## * `dirExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, link)
if a != -1'i32:
# xxx see: bug #16784 (bug9); checking `IO_REPARSE_TAG_SYMLINK`
# may also be needed.
result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
else:
var res: Stat
result = lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
when defined(windows) and not weirdTarget:
proc openHandle*(path: string, followSymlink=true, writeAccess=false): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
let access = if writeAccess: GENERIC_WRITE else: 0'i32
proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect],
noWeirdTarget, sideEffect.} =
## Returns true if the symlink `link` exists. Will return true
## regardless of whether the link points to a directory or file.
##
## See also:
## * `fileExists proc`_
## * `dirExists proc`_
when defined(windows):
wrapUnary(a, getFileAttributesW, link)
if a != -1'i32:
# xxx see: bug #16784 (bug9); checking `IO_REPARSE_TAG_SYMLINK`
# may also be needed.
result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
else:
var res: Stat
result = lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
when defined(windows) and not weirdTarget:
proc openHandle*(path: string, followSymlink=true, writeAccess=false): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
let access = if writeAccess: GENERIC_WRITE else: 0'i32
result = createFileW(
newWideCString(path), access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
result = createFileW(
newWideCString(path), access,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)

View File

@@ -6,7 +6,9 @@ import std/oserrors
import ospaths2, osfiles
import oscommon
export dirExists, PathComponent
import std/staticos
when supportedSystem:
export dirExists, PathComponent
when defined(nimPreviewSlimSystem):
@@ -20,9 +22,6 @@ elif defined(windows):
elif defined(posix):
import std/[posix, times]
else:
{.error: "OS module not ported to your operating system!".}
when weirdTarget:
{.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".}
@@ -152,10 +151,6 @@ iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noWeirdTarg
assert "lib/pure/concurrency".unixToNativePath in paths
walkCommon(pattern, isDir)
proc staticWalkDir(dir: string; relative: bool): seq[
tuple[kind: PathComponent, path: string]] =
discard
iterator walkDir*(dir: string; relative = false, checkDir = false,
skipSpecial = false):
tuple[kind: PathComponent, path: string] {.tags: [ReadDirEffect].} =
@@ -325,7 +320,6 @@ iterator walkDirRec*(dir: string,
# continue iteration.
# Future work can provide a way to customize this and do error reporting.
proc rawRemoveDir(dir: string) {.noWeirdTarget.} =
when defined(windows):
wrapUnary(res, removeDirectoryW, dir)

View File

@@ -21,8 +21,6 @@ elif defined(posix):
proc toTime(ts: Timespec): times.Time {.inline.} =
result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
else:
{.error: "OS module not ported to your operating system!".}
when weirdTarget:

View File

@@ -20,8 +20,6 @@ elif defined(windows):
import std/winlean
elif defined(posix):
import std/posix, system/ansi_c
else:
{.error: "OS module not ported to your operating system!".}
when weirdTarget:
{.pragma: noWeirdTarget, error: "this proc is not available on the NimScript/js target".}
@@ -840,7 +838,7 @@ proc unixToNativePath*(path: string, drive=""): string {.
inc(i)
when not defined(nimscript):
when not defined(nimscript) and supportedSystem:
proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
## Returns the `current working directory`:idx: i.e. where the built
## binary is run.
@@ -889,7 +887,7 @@ when not defined(nimscript):
else:
raiseOSError(osLastError())
proc absolutePath*(path: string, root = getCurrentDir()): string =
proc absolutePath*(path: string, root = when supportedSystem: getCurrentDir() else: ""): string =
## Returns the absolute path of `path`, rooted at `root` (which must be absolute;
## default: current directory).
## If `path` is absolute, return it, ignoring `root`.
@@ -907,7 +905,7 @@ proc absolutePath*(path: string, root = getCurrentDir()): string =
joinPath(root, path)
proc absolutePathInternal(path: string): string =
absolutePath(path, getCurrentDir())
absolutePath(path)
proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} =
@@ -984,48 +982,49 @@ proc normalizeExe*(file: var string) {.since: (1, 3, 5).} =
if file.len > 0 and DirSep notin file and file != "." and file != "..":
file = "./" & file
proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect], noWeirdTarget.} =
## Returns true if both pathname arguments refer to the same physical
## file or directory.
##
## Raises `OSError` if any of the files does not
## exist or information about it can not be obtained.
##
## This proc will return true if given two alternative hard-linked or
## sym-linked paths to the same file or directory.
##
## See also:
## * `sameFileContent proc`_
result = false
when defined(windows):
var success = true
var f1 = openHandle(path1)
var f2 = openHandle(path2)
when supportedSystem:
proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
tags: [ReadDirEffect], noWeirdTarget.} =
## Returns true if both pathname arguments refer to the same physical
## file or directory.
##
## Raises `OSError` if any of the files does not
## exist or information about it can not be obtained.
##
## This proc will return true if given two alternative hard-linked or
## sym-linked paths to the same file or directory.
##
## See also:
## * `sameFileContent proc`_
result = false
when defined(windows):
var success = true
var f1 = openHandle(path1)
var f2 = openHandle(path2)
var lastErr: OSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: BY_HANDLE_FILE_INFORMATION
var lastErr: OSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: BY_HANDLE_FILE_INFORMATION
if getFileInformationByHandle(f1, addr(fi1)) != 0 and
getFileInformationByHandle(f2, addr(fi2)) != 0:
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
fi1.nFileIndexLow == fi2.nFileIndexLow
if getFileInformationByHandle(f1, addr(fi1)) != 0 and
getFileInformationByHandle(f2, addr(fi2)) != 0:
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
fi1.nFileIndexLow == fi2.nFileIndexLow
else:
lastErr = osLastError()
success = false
else:
lastErr = osLastError()
success = false
else:
lastErr = osLastError()
success = false
discard closeHandle(f1)
discard closeHandle(f2)
discard closeHandle(f1)
discard closeHandle(f2)
if not success: raiseOSError(lastErr, $(path1, path2))
else:
var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError(), $(path1, path2))
if not success: raiseOSError(lastErr, $(path1, path2))
else:
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError(), $(path1, path2))
else:
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino

View File

@@ -2,7 +2,8 @@ include system/inclrtl
import std/oserrors
import oscommon
export symlinkExists
when supportedSystem:
export symlinkExists
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, widestrs]
@@ -13,8 +14,6 @@ elif defined(windows):
import std/[winlean, times]
elif defined(posix):
import std/posix
else:
{.error: "OS module not ported to your operating system!".}
when weirdTarget:

View File

@@ -14,3 +14,25 @@ proc staticDirExists*(dir: string): bool {.compileTime.} =
## Returns true if the directory `dir` exists. If `dir` is a file, false
## is returned. Follows symlinks.
raiseAssert "implemented in the vmops"
type
PathComponent* = enum ## Enumeration specifying a path component.
##
## See also:
## * `walkDirRec iterator`_
## * `FileInfo object`_
pcFile, ## path refers to a file
pcLinkToFile, ## path refers to a symbolic link to a file
pcDir, ## path refers to a directory
pcLinkToDir ## path refers to a symbolic link to a directory
proc staticWalkDir*(dir: string; relative = false): seq[
tuple[kind: PathComponent, path: string]] {.compileTime.} =
## Walks over the directory `dir` and returns a seq with each directory or
## file in `dir`. The component type and full path for each item are returned.
##
## Walking is not recursive.
## * If `relative` is true (default: false)
## the resulting path is shortened to be relative to ``dir``,
## otherwise the full path is returned.
raiseAssert "implemented in the vmops"

View File

@@ -128,7 +128,7 @@ proc genTempPath*(prefix, suffix: string, dir = ""): string =
##
## The path begins with `prefix` and ends with `suffix`.
##
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <os.html#getTempDir>`_).
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <appdirs.html#getTempDir>`_).
let dir = getTempDirImpl(dir)
result = dir / (prefix & randomPathName(nimTempPathLength) & suffix)
@@ -143,7 +143,7 @@ proc createTempFile*(prefix, suffix: string, dir = ""): tuple[cfile: File, path:
##
## .. note:: It is the caller's responsibility to close `result.cfile` and
## remove `result.file` when no longer needed.
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <os.html#getTempDir>`_).
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <appdirs.html#getTempDir>`_).
runnableExamples:
import std/os
doAssertRaises(OSError): discard createTempFile("", "", "nonexistent")
@@ -176,7 +176,7 @@ proc createTempDir*(prefix, suffix: string, dir = ""): string =
## If failing to create a temporary directory, `OSError` will be raised.
##
## .. note:: It is the caller's responsibility to remove the directory when no longer needed.
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <os.html#getTempDir>`_).
## .. note:: `dir` must exist (empty `dir` will resolve to `getTempDir <appdirs.html#getTempDir>`_).
runnableExamples:
import std/os
doAssertRaises(OSError): discard createTempDir("", "", "nonexistent")

View File

@@ -2965,14 +2965,16 @@ when notJSnotNims and not defined(nimSeqsV2):
assert y == "abcgh"
discard
proc arrayWith*[T](y: T, size: static int): array[size, T] {.raises: [].} =
proc arrayWith*[T](y: T, size: static int): array[size, T] {.noinit, nodestroy, raises: [].} =
## Creates a new array filled with `y`.
result = zeroDefault(array[size, T])
for i in 0..size-1:
result[i] = y
when (NimMajor, NimMinor, NimPatch) >= (2, 3, 1):
result[i] = `=dup`(y)
else:
wasMoved(result[i])
`=copy`(result[i], y)
proc arrayWithDefault*[T](size: static int): array[size, T] {.raises: [].} =
proc arrayWithDefault*[T](size: static int): array[size, T] {.noinit, nodestroy, raises: [].} =
## Creates a new array filled with `default(T)`.
result = zeroDefault(array[size, T])
for i in 0..size-1:
result[i] = default(T)

View File

@@ -87,6 +87,9 @@ else:
template count(x: Cell): untyped =
x.rc shr rcShift
when not defined(nimHasQuirky):
{.pragma: quirky.}
proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
let hdrSize = align(sizeof(RefHeader), alignment)
let s = size + hdrSize
@@ -190,7 +193,7 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
#proc dispose*(x: pointer) = nimRawDispose(x)
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, quirky, raises: [].} =
let rti = cast[ptr PNimTypeV2](p)
if rti.destructor != nil:
cast[DestructorProc](rti.destructor)(p)

View File

@@ -144,8 +144,11 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) {.nodestroy.} =
xu.p = cast[typeof(xu.p)](prepareSeqAddUninit(oldLen, xu.p, newLen - oldLen, sizeof(T), alignof(T)))
xu.len = newLen
for i in oldLen .. newLen-1:
wasMoved(xu.p.data[i])
`=copy`(xu.p.data[i], value)
when (NimMajor, NimMinor, NimPatch) >= (2, 3, 1):
xu.p.data[i] = `=dup`(value)
else:
wasMoved(xu.p.data[i])
`=copy`(xu.p.data[i], value)
proc add*[T](x: var seq[T]; y: sink T) {.magic: "AppendSeqElem", noSideEffect, nodestroy.} =
## Generic proc for adding a data item `y` to a container `x`.

View File

@@ -112,9 +112,10 @@ proc nimToCStringConv(s: NimStringV2): cstring {.compilerproc, nonReloadable, in
proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inline.} =
if src.len > 0:
# also copy the \0 terminator:
copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len+1)
# don't copy the \0 terminator:
copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len)
inc dest.len, src.len
dest.p.data[dest.len] = '\0'
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
dest.p.data[dest.len] = c

View File

@@ -300,7 +300,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericS
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
result.len = newLen
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
compilerRtl.} =
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
if s == nil:
@@ -334,7 +334,8 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
# presence of user defined destructors, the user will expect the cell to be
# "destroyed" thus creating the same problem. We can destroy the cell in the
# finalizer of the sequence, but this makes destruction non-deterministic.
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
if not isTrivial: # optimization for trivial types
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
else:
result = s
zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize)

View File

@@ -16,6 +16,8 @@ import ../compiler / [idents, llstream, ast, msgs, syntaxes, options, pathutils,
import parseopt, strutils, os, sequtils
import std/tempfiles
const
Version = "0.2"
Usage = "nimpretty - Nim Pretty Printer Version " & Version & """
@@ -26,6 +28,7 @@ Usage:
Options:
--out:file set the output file (default: overwrite the input file)
--outDir:dir set the output dir (default: overwrite the input files)
--stdin read input from stdin and write output to stdout
--indent:N[=0] set the number of spaces that is used for indentation
--indent:0 means autodetection (default behaviour)
--maxLineLen:N set the desired maximum line length (default: 80)
@@ -84,7 +87,7 @@ proc finalCheck(content: string; origAst: PNode): bool {.nimcall.} =
closeParser(parser)
result = conf.errorCounter == oldErrors # and goodEnough(newAst, origAst)
proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) =
proc prettyPrint*(infile, outfile: string; opt: PrettyOptions) =
var conf = newConfigRef()
let fileIdx = fileInfoIdx(conf, AbsoluteFile infile)
let f = splitFile(outfile.expandTilde)
@@ -99,12 +102,28 @@ proc prettyPrint*(infile, outfile: string, opt: PrettyOptions) =
when defined(nimpretty):
closeEmitter(parser.em, fullAst, finalCheck)
proc handleStdinInput(opt: PrettyOptions) =
var content = readAll(stdin)
var (cfile, path) = createTempFile("nimpretty_", ".nim")
writeFile(path, content)
prettyPrint(path, path, opt)
echo(readAll(cfile))
close(cfile)
removeFile(path)
proc main =
var outfile, outdir: string
var infiles = newSeq[string]()
var outfiles = newSeq[string]()
var isStdin = false
var backup = false
# when `on`, create a backup file of input in case
# `prettyPrint` could overwrite it (note that the backup may happen even
@@ -112,7 +131,6 @@ proc main =
# --backup was un-documented (rely on git instead).
var opt = PrettyOptions(indWidth: 0, maxLineLen: 80)
for kind, key, val in getopt():
case kind
of cmdArgument:
@@ -132,8 +150,15 @@ proc main =
of "outDir", "outdir": outdir = val
of "indent": opt.indWidth = parseInt(val)
of "maxlinelen": opt.maxLineLen = parseInt(val)
# "" is equal to '-' as input
of "stdin", "": isStdin = true
else: writeHelp()
of cmdEnd: assert(false) # cannot happen
if isStdin:
handleStdinInput(opt)
return
if infiles.len == 0:
quit "[Error] no input file."

View File

@@ -0,0 +1,15 @@
discard """
$nimsuggest --tester $file
>outline $file
outline;;skProc;;t21923.foo;;proc (x: int){.gcsafe, raises: <inferred> [].};;$file;;8;;5;;"";;100
outline;;skTemplate;;t21923.foo2;;;;$file;;11;;9;;"";;100
"""
proc foo(x: int) =
echo "foo"
template foo2(x: int) =
echo "foo2"
foo(12)
foo2(12)

View File

@@ -6,7 +6,7 @@ tmp#[!]#
discard """
$nimsuggest --tester $file
>sug $1
sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix
sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, raises: <inferred> [].};;$file;;2;;6;;"";;100;;Prefix
sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;100;;Prefix
sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix
"""

View File

@@ -33,6 +33,7 @@ copying
123
42
@["", "d", ""]
mutate: 1
ok
destroying variable: 20
destroying variable: 10
@@ -882,3 +883,18 @@ proc test_18070() = # bug #18070
doAssert msg == "", "expected empty string but got: " & $msg
test_18070()
type AnObject = tuple
a: string
b: int
c: int
proc mutate(a: sink AnObject) =
`=wasMoved`(a)
echo "mutate: 1"
# echo "Value is: ", obj.value
proc bar =
mutate(("1.2", 0, 0))
bar()

View File

@@ -0,0 +1,24 @@
discard """
ccodecheck: "'Result[(i_1 - 0)] = eqdup'"
"""
# issue #24626
proc arrayWith2[T](y: T, size: static int): array[size, T] {.noinit, nodestroy, raises: [].} =
## Creates a new array filled with `y`.
for i in 0..size-1:
when defined(nimHasDup):
result[i] = `=dup`(y)
else:
wasMoved(result[i])
`=copy`(result[i], y)
proc useArray(x: seq[int]) =
var a = arrayWith2(x, 2)
proc main =
let x = newSeq[int](100)
for i in 0..5:
useArray(x)
main()

16
tests/arc/tvalgrind.nim Normal file
View File

@@ -0,0 +1,16 @@
discard """
cmd: "nim c --mm:orc -d:useMalloc $file"
valgrind: "true"
"""
import std/streams
proc foo() =
var name = newStringStream("2r2")
raise newException(ValueError, "sh")
try:
foo()
except:
discard

View File

@@ -1,7 +1,7 @@
discard """
matrix: "--mm:refc"
output: "Hello"
ccodecheck: "\\i@'a = ((NimStringDesc*) NIM_NIL)'"
ccodecheck: "\\i@'a_1 = ((NimStringDesc*) NIM_NIL)'"
"""
proc main() =

View File

@@ -161,3 +161,21 @@ typedef struct { int base; } S;
var t = newT()
doAssert t.s.base == 1
type QObject* {.inheritable, pure.} = object
h*: pointer
proc `=destroy`(self: var QObject) =discard
proc `=copy`(dest: var QObject, source: QObject) {.error.}
type QAbstractItemModel* = object of QObject
type VTable = ref object
inst: QAbstractItemModel
proc g() =
var x: VTable = VTable()
x.inst = QAbstractItemModel()
g()

View File

@@ -1,7 +1,7 @@
discard """
output: "1"
cmd: r"nim c --hints:on $options --mm:refc -d:release $file"
ccodecheck: "'NI volatile state;'"
ccodecheck: "'NI volatile state_1;'"
targets: "c"
"""

View File

@@ -45,3 +45,14 @@ block: # bug #22354
main()
proc main = # bug #24677
let NULL = 1
doAssert NULL == 1
var COMMA = 1
doAssert COMMA == 1
for NDEBUG in 0..2:
doAssert NDEBUG == NDEBUG
main()

View File

@@ -29,6 +29,8 @@ discard """
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE10Container2I5int325int32E'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI10Container2I5int325int32EE'"
ccodecheck: "'_ZN14titaniummangle7xxx_s10E'"
ccodecheck: "'_ZN14titaniummangle7xxx_s20E'"
"""
#When debugging this notice that if one check fails, it can be due to any of the above.
@@ -151,6 +153,9 @@ proc testFunc(a: int, xs: varargs[string]) =
for x in xs:
echo x
proc xxx(v: static int) =
echo v
proc testFunc() =
var a = 2
var aPtr = a.addr
@@ -188,6 +193,8 @@ proc testFunc() =
let c2 = Container2[int32, int32](data: 10, data2: 20)
testFunc(c2)
testFunc(Container[Container2[int32, int32]](data: c2))
xxx(10)
xxx(20)
testFunc()

View File

@@ -240,3 +240,11 @@ block: # bug #17197
result = true
doAssert needlemanWunsch("ABC", "DEFG", 1, 2, 3)
block: # bug #12340
func consume(x: sink seq[int]) =
x[0] += 5
let x = @[1, 2, 3, 4]
consume x
doAssert x == @[1, 2, 3, 4]

View File

@@ -128,4 +128,10 @@ block:
var b = makeBoo()
var b2 = makeBoo2()
main()
main()
block: # bug #24658
type
A {.importcpp: "A".} = object
proc a(something: ptr cint = nil): A {.cdecl, constructor, importcpp: "A(@)".}

View File

@@ -1,6 +1,4 @@
discard """
# doesn't work on macos 13 seemingly due to libc++ linking issue https://stackoverflow.com/a/77375947
disabled: osx
targets: cpp
"""
@@ -18,21 +16,21 @@ proc initStdException(): CStdException {.importcpp: "std::exception()", construc
proc fn() =
let a = initRuntimeError("foo")
doAssert $a.what == "foo"
var b: cstring
var b = ""
try: raise initRuntimeError("foo2")
except CStdException as e:
doAssert e is CStdException
b = e.what()
doAssert $b == "foo2"
b = $e.what()
doAssert b == "foo2"
try: raise initStdException()
except CStdException: discard
try: raise initRuntimeError("foo3")
except CRuntimeError as e:
b = e.what()
b = $e.what()
except CStdException:
doAssert false
doAssert $b == "foo3"
doAssert b == "foo3"
fn()

View File

@@ -0,0 +1,11 @@
import "."/[mambtype1, mambtype2]
type H[K] = object
proc b(_: int) = # slightly different, still not useful, error message if `b` generic
proc r(): H[Y] = discard #[tt.Error
^ cannot instantiate H [type declared in tambtypegeneric.nim(2, 6)]
got: <typedesc[Y] | typedesc[Y]>
but expected: <K>
ambiguous identifier: 'Y' -- use one of the following:
mambtype1.Y: Y
mambtype2.Y: Y]#
b(0)

View File

@@ -0,0 +1,9 @@
# issue #24715
type H[c: static[float64]] = object
value: typeof(c)
proc u[T: H](_: typedesc[T]) =
discard default(T)
u(H[1'f64])

View File

@@ -1,5 +1,4 @@
discard """
matrix: "--legacy:nostrictdefs"
joinable: false
"""

View File

@@ -1,6 +1,7 @@
discard """
action: compile
disabled: "windows"
disabled: osx
"""
import sfml, os

View File

@@ -0,0 +1,21 @@
# issue #24708
type Matrix[m, n: static int] = array[m * n, float]
func `[]`(A: Matrix, i, j: int): float =
A[A.n * i + j]
func `[]`(A: var Matrix, i, j: int): var float =
A[A.n * i + j]
func `*`[m, n, p: static int](A: Matrix[m, n], B: Matrix[n, p]): Matrix[m, p] =
for i in 0 ..< m:
for k in 0 ..< p:
for j in 0 ..< n:
result[i, k] += A[i, j] * B[j, k]
func square[n: static int](A: Matrix[n, n]): Matrix[n, n] =
A * A
let A: Matrix[2, 2] = [-1, 1, 0, -1]
doAssert square(A) == [1.0, -2.0, 0.0, 1.0]

View File

@@ -0,0 +1,16 @@
discard """
nimout: '''
proc foo(a {.attr.}: int) =
discard
'''
"""
# fixes #24702
import macros
template attr*() {.pragma.}
proc foo(a {.attr.}: int) = discard
macro showImpl(a: typed) =
echo repr getImpl(a)
showImpl(foo)

View File

@@ -2,7 +2,7 @@ discard """
matrix: "--mm:refc; --mm:orc"
"""
import std/[complex, math]
import std/[complex, math, strformat, formatfloat]
import std/assertions
proc `=~`[T](x, y: Complex[T]): bool =
@@ -113,3 +113,7 @@ doAssert 123.0.im + 456.0 == complex64(456, 123)
let localA = complex(0.1'f32)
doAssert localA.im is float32
block: # bug #24666
let z = complex64(1, 2)
doAssert fmt"{z}" == "(1.0, 2.0)"

View File

@@ -1,7 +1,9 @@
discard """
matrix: "--mm:orc; --mm:refc"
matrix: "--mm:orc"
"""
# TODO: --mm:refc
import std/marshal
import std/[assertions, objectdollar, streams]

View File

@@ -245,6 +245,25 @@ template main() =
empty.cumsum
doAssert empty == @[]
block: # cumprod
block: #cumprod int seq return
let counts = [ 1, 2, 3, 4 ]
doAssert counts.cumproded == [ 1, 2, 6, 24 ]
block: # cumprod float seq return
let counts = [ 1.0, 2.0, 3.0, 4.0 ]
doAssert counts.cumproded == [ 1.0, 2.0, 6.0, 24.0 ]
block: # cumprod int in-place
var counts = [ 1, 2, 3, 4 ]
counts.cumprod
doAssert counts == [ 1, 2, 6, 24 ]
block: # cumprod float in-place
var counts = [ 1.0, 2.0, 3.0, 4.0 ]
counts.cumprod
doAssert counts == [ 1.0, 2.0, 6.0, 24.0 ]
block: # ^ compiles for valid types
doAssert: compiles(5 ^ 2)
doAssert: compiles(5.5 ^ 2)
@@ -525,3 +544,9 @@ when not defined(js) and not defined(danger):
doAssertRaises(OverflowDefect):
discard sum(x)
block: # bug #24673
let x: Natural = 5
let y: Natural = 3
doAssert divmod(x, y) == (Natural 1, Natural 2)

View File

@@ -37,3 +37,30 @@ block: # bug #16771
a.foo b
doAssert a.n == 42
doAssert b.n == 1
block: # bug #24683
block:
var v = newSeq[int](100)
v[99]= 444
v.setLen(5)
v.setLen(100)
doAssert v[99] == 0
when not defined(js):
block:
var
x = @[1, 2, 3, 4, 45, 56, 67, 999, 88, 777]
x.setLen(0) # zero-fills 1mb of released data
type
TGenericSeq = object
len, reserved: int
PGenericSeq = ptr TGenericSeq
when defined(gcRefc):
cast[PGenericSeq](x).len = 10
else:
cast[ptr int](addr x)[] = 10
doAssert x == @[1, 2, 3, 4, 45, 56, 67, 999, 88, 777]

View File

@@ -6,6 +6,54 @@ import unittest, strutils
block: # parseutils
check: parseBiggestUInt("0") == 0'u64
check: parseBiggestUInt("1") == 1'u64
check: parseBiggestUInt("2") == 2'u64
check: parseBiggestUInt("10") == 10'u64
check: parseBiggestUInt("11") == 11'u64
check: parseBiggestUInt("99") == 99'u64
check: parseBiggestUInt("123") == 123'u64
check: parseBiggestUInt("9876") == 9876'u64
check: parseBiggestUInt("1_234") == 1234'u64
check: parseBiggestUInt("123__4") == 1234'u64
for i in 1.BiggestUInt .. 9.BiggestUInt:
var x = i
for j in 1 .. 19:
check parseBiggestUInt((i + '0'.uint).char.repeat j) == x
x *= 10
x += i
check: parseBiggestUInt("18446744073709551609") == 0xFFFF_FFFF_FFFF_FFF9'u64
check: parseBiggestUInt("18446744073709551610") == 0xFFFF_FFFF_FFFF_FFFA'u64
check: parseBiggestUInt("18446744073709551611") == 0xFFFF_FFFF_FFFF_FFFB'u64
check: parseBiggestUInt("18446744073709551612") == 0xFFFF_FFFF_FFFF_FFFC'u64
check: parseBiggestUInt("18446744073709551613") == 0xFFFF_FFFF_FFFF_FFFD'u64
check: parseBiggestUInt("18446744073709551614") == 0xFFFF_FFFF_FFFF_FFFE'u64
check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
expect(ValueError):
discard parseBiggestUInt("18446744073709551616")
expect(ValueError):
discard parseBiggestUInt("18446744073709551617")
expect(ValueError):
discard parseBiggestUInt("18446744073709551618")
expect(ValueError):
discard parseBiggestUInt("18446744073709551619")
expect(ValueError):
discard parseBiggestUInt("18446744073709551620")
expect(ValueError):
discard parseBiggestUInt("18446744073709551621")
expect(ValueError):
discard parseBiggestUInt("18446744073709551622")
expect(ValueError):
discard parseBiggestUInt("18446744073709551623")
expect(ValueError):
for i in 0 .. 999:
discard parseBiggestUInt("18446744073709552" & intToStr(i, 3))
expect(ValueError):
discard parseBiggestUInt("22751622367522324480000000")
expect(ValueError):
discard parseBiggestUInt("41404969074137497600000000")
expect(ValueError):
discard parseBiggestUInt("20701551093035827200000000000000000")
expect(ValueError):
discard parseBiggestUInt("225462255024603136000000000000000000")
expect(ValueError):
discard parseBiggestUInt("204963831854661632000000000000000000")

View File

@@ -13,3 +13,8 @@ block:
type _ = float
doAssert not (compiles do:
let x: _ = 3)
block: # bug #24339
const r = (0, 0)
for _ in r.fields:
let _ = 0

14
tests/system/t24664.nim Normal file
View File

@@ -0,0 +1,14 @@
discard """
output: '''
TestString123TestString123
TestString123TestString123
'''
"""
proc foostring() = # bug #24664
for i in 0..1:
var s = "TestString123"
s.add s
echo s
foostring()

View File

@@ -0,0 +1,9 @@
# issue #24657
proc g() {.error.} = discard
type T = object
g: int
template B(): untyped = typeof(T.g)
type _ = B()

View File

@@ -0,0 +1,15 @@
discard """
matrix: "--skipParentCfg"
"""
# issue #24631
type
V[d: static bool] = object
l: int
template y(): V[false] = V[false](l: 0)
discard y()
template z(): V[false] = cast[V[false]](V[false](l: 0))
discard z()

View File

@@ -0,0 +1,13 @@
# issue #24698
type Point = tuple[x, y: int]
const Origin: Point = (0, 0)
import macros
template next(point: Point): Point =
(point.x + 1, point.y + 1)
discard Origin.x # OK: the field is visible.
discard next(Origin) # Compilation error: the field is not visible.

View File

@@ -0,0 +1,18 @@
# issue #24609
import std/options
type
Config* = object
bits*: tuple[r, g, b, a: Option[int32]]
# works on 2.0.8
#
# results in error on 2.2.0
# type mismatch: got 'int literal(8)' for '8' but expected 'Option[system.int32]'
#
converter toInt32Tuple*(t: tuple[r,g,b,a: int]): tuple[r,g,b,a: Option[int32]] =
(some(t.r.int32), some(t.g.int32), some(t.b.int32), some(t.a.int32))
var cfg: Config
cfg.bits = (r: 8, g: 8, b: 8, a: 16)

View File

@@ -0,0 +1,79 @@
block: # issue #8758
template baz() =
var i = 0
proc foo() =
static:
var i = 0
baz()
block: # issue #10828
proc test(i: byte): bool =
const SET = block: # No issues when defined outside proc
var s: set[byte]
for i in 0u8 .. 255u8: incl(s, i)
s
return i in SET
doAssert test(0)
doAssert test(127)
doAssert test(255)
block: # issue #12172
const TEST = block:
var test: array[5, string]
for i in low(test)..high(test):
test[i] = $i
test
proc test =
const TEST2 = block:
var test: array[5, string] # Error here
for i in low(test)..high(test):
test[i] = $i
test
doAssert TEST == TEST2
doAssert TEST == @["0", "1", "2", "3", "4"]
doAssert TEST2 == @["0", "1", "2", "3", "4"]
test()
block: # issue #21610
func stuff(): int =
const r = block:
var r = 1 # Error: cannot evaluate at compile time: r
for i in 2..10:
r *= i
r
r
doAssert stuff() == 3628800
block: # issue #23803
func foo1(c: int): int {.inline.} =
const arr = block:
var res: array[0..99, int]
res[42] = 43
res
arr[c]
doAssert foo1(41) == 0
doAssert foo1(42) == 43
doAssert foo1(43) == 0
# works
func foo2(c: int): int {.inline.} =
func initArr(): auto =
var res: array[0..99, int]
res[42] = 43
res
const arr = initArr()
arr[c]
doAssert foo2(41) == 0
doAssert foo2(42) == 43
doAssert foo2(43) == 0
# also works
const globalArr = block:
var res: array[0..99, int]
res[42] = 43
res
func foo3(c: int): int {.inline.} = globalArr[c]
doAssert foo3(41) == 0
doAssert foo3(42) == 43
doAssert foo3(43) == 0

View File

@@ -0,0 +1,13 @@
# issue #24634
type J = object
template m(u: J): int =
let v = u
0
proc g() =
const x = J()
const _ = m(x)
g()

View File

@@ -0,0 +1,9 @@
# issue #24633
import std/sequtils
proc f(a: static openArray[int]) =
const s1 = a.mapIt(it)
const s2 = a.toSeq()
f([1,2,3])

View File

@@ -0,0 +1,6 @@
proc test =
const TEST = block:
let i = 1
const j = i + 1 #[tt.Error
^ cannot evaluate at compile time: i]#
j

View File

@@ -87,3 +87,12 @@ block: # bug #22095
z = fn()
doAssert z.limbs[0] == 10
block: # bug #24630
func f(a: static openArray[int]): int =
12
func g(a: static openArray[int]) =
const b = f(a)
g(@[1,2,3])

View File

@@ -4,10 +4,12 @@ import std/private/gitutils
when defined(nimPreviewSlimSystem):
import std/assertions
proc exec(cmd: string) =
proc tryexec(cmd: string): int =
echo "deps.cmd: " & cmd
let status = execShellCmd(cmd)
doAssert status == 0, cmd
execShellCmd(cmd)
proc exec(cmd: string) =
doAssert tryexec(cmd) == 0, cmd
proc execRetry(cmd: string) =
let ok = retryCall(call = block:
@@ -34,8 +36,10 @@ proc cloneDependency*(destDirBase: string, url: string, commit = commitHead,
let oldDir = getCurrentDir()
setCurrentDir(destDir)
try:
execRetry "git fetch -q"
exec fmt"git checkout -q {commit}"
let checkoutCmd = fmt"git checkout -q {commit}"
if tryexec(checkoutCmd) != 0:
execRetry "git fetch -q"
exec checkoutCmd
finally:
setCurrentDir(oldDir)
elif allowBundled:

View File

@@ -1,47 +1,501 @@
# bash completion for nim -*- shell-script -*-
__is_short_or_long()
{
local actual short long
actual="$1"
short="$2"
long="$3"
[[ ! -z $short && $actual == $short ]] && return 0
[[ ! -z $long && $actual == $long ]] && return 0
return 1
}
__ask_for_subcmd_or_subopts()
{
local args cmd subcmd words sub_words word_first word_last word_lastlast
local len ilast ilastlast i ele sub_len n_nopts
args=("$@")
ask_for_what="${args[0]}"
cmd="${args[1]}"
subcmd="${args[2]}"
ilast="${args[3]}"
words=("${args[@]:4}")
len=${#words[@]}
ilastlast=$((ilast - 1))
sub_words=("${words[@]:0:ilast}")
sub_len=${#sub_words[@]}
word_first=${words[0]}
word_last=${words[ilast]}
word_lastlast=${words[ilastlast]}
n_nopts=0
# printf "\n[DBUG] word_first:${word_first}|ilast:${ilast}|words(${len}):${words[*]}|sub_words(${sub_len}):${sub_words[*]}\n"
if [[ $word_first != $cmd ]]
then
return 1
fi
i=0
while [[ $i -lt $len ]]
do
ele=${words[i]}
if [[ ! $ele =~ ^- ]]
then
if [[ $ele == $cmd || $ele == $subcmd ]]
then
((n_nopts+=1))
elif [[ $i -eq $ilast && $ele =~ ^[a-zA-Z] ]]
then
((i=i))
elif [[ -z $ele ]]
then
((i=i))
elif [[ $ele =~ ^: ]]
then
((i+=1))
else
return 1
fi
fi
((i+=1))
done
case $ask_for_what in
1)
if [[ n_nopts -eq 1 ]]
then
if [[ -z $word_last || $word_last =~ ^[a-zA-Z] ]] && [[ $word_lastlast != : ]]
then
return 0
fi
fi
;;
2)
if [[ n_nopts -eq 2 ]]
then
if [[ -z $word_last ]] || [[ $word_last =~ ^[-:] ]]
then
return 0
fi
fi
esac
return 1
}
__ask_for_subcmd()
{
__ask_for_subcmd_or_subopts 1 "$@"
}
__ask_for_subcmd_opts()
{
__ask_for_subcmd_or_subopts 2 "$@"
}
_nim()
{
local cur prev words cword split
_init_completion -s || return
local curr prev prevprev words
local i_curr n_words i_prev i_prevprev
COMPREPLY=()
i_curr=$COMP_CWORD
n_words=$((i_curr+1))
i_prev=$((i_curr-1))
i_prevprev=$((i_curr-2))
curr="${COMP_WORDS[i_curr]}"
prev="${COMP_WORDS[i_prev]}"
prevprev="${COMP_WORDS[i_prevprev]}"
words=("${COMP_WORDS[@]:0:n_words}")
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
local subcmds opts candids
if [ $COMP_CWORD -eq 1 ] ; then
# first item - suggest commands
kw="compile c doc compileToC cc compileToCpp cpp compileToOC objc js e rst2html rst2tex jsondoc buildIndex genDepend dump check"
COMPREPLY=( $( compgen -W "${kw}" -- $cur ) )
return 0
fi
case $prev in
--stackTrace|--lineTrace|--threads|-x|--checks|--objChecks|--fieldChecks|--rangeChecks|--boundChecks|--overflowChecks|-a|--assertions|--floatChecks|--nanChecks|--infChecks)
# Options that require on/off
[[ "$cur" == "=" ]] && cur=""
COMPREPLY=( $(compgen -W 'on off' -- "$cur") )
return 0
;;
--opt)
[[ "$cur" == "=" ]] && cur=""
COMPREPLY=( $(compgen -W 'none speed size' -- "$cur") )
return 0
;;
--app)
[[ "$cur" == "=" ]] && cur=""
COMPREPLY=( $(compgen -W 'console gui lib staticlib' -- "$cur") )
return 0
;;
*)
kw="-r -p= --path= -d= --define= -u= --undef= -f --forceBuild --opt= --app= --stackTrace= --lineTrace= --threads= -x= --checks= --objChecks= --fieldChecks= --rangeChecks= --boundChecks= --overflowChecks= -a= --assertions= --floatChecks= --nanChecks= --infChecks="
COMPREPLY=( $( compgen -W "${kw}" -- $cur ) )
_filedir '@(nim)'
#$split
return 0
;;
esac
return 0
# printf "\n[DBUG] curr:$curr|prev:$prev|words(${#words[*]}):${words[*]}\n"
# Asking for a subcommand
if __ask_for_subcmd nim nim $i_curr "${words[@]}"
then
subcmds=""
# basic
subcmds="${subcmds} compile c"
subcmds="${subcmds} r"
subcmds="${subcmds} doc"
# advanced
subcmds="${subcmds} compileToC cc"
subcmds="${subcmds} compileToCpp cpp"
subcmds="${subcmds} compileToOC objc"
subcmds="${subcmds} js"
subcmds="${subcmds} e"
subcmds="${subcmds} md2html"
subcmds="${subcmds} rst2html"
subcmds="${subcmds} md2tex"
subcmds="${subcmds} rst2tex"
subcmds="${subcmds} doc2tex"
subcmds="${subcmds} jsondoc"
subcmds="${subcmds} ctags"
subcmds="${subcmds} buildIndex"
subcmds="${subcmds} genDepend"
subcmds="${subcmds} dump"
subcmds="${subcmds} check"
COMPREPLY=( $( compgen -W "${subcmds}" -- ${curr}) )
return 0
fi
# Prioritize subcmd over opt
if false
then
return 124
elif false && __ask_for_subcmd_opts nim compileToC $i_curr "${words[@]}"
then # for future use
opts=() \
&& candids=()
opts+=("-u" "--undef" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
else
opts=() \
&& candids=()
opts+=("-p" "--path" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-d" "--define" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
# note, any preceeding left parenthesis will vanish the context
opts+=("-u" "--undef" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-f" "--forceBuild" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stackTrace" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--lineTrace" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--threads" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--checks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--assertions" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--opt" "none speed size") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--debugger" "native") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--app" "console gui lib staticlib") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-r" "--run" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--eval" "CMD") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--fullhelp" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-h" "--help" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-v" "--version" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--objChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--fieldChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--rangeChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--boundChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--overflowChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--floatChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--nanChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--infChecks" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--defusages" "FILE,LINE,COL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-o" "--output" "FILE") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--outdir" "DIR") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--usenimcache" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stdout" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--colors" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--filenames" "abs canonical legacyRelProj") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--processing" "dots filenames off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--unitsep" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--declaredLocs" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--spellSuggest" "NUM") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--hints" "on off list") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--hint" "HINT:on") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--hintAsError" "HINT:on") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-w" "--warnings" "on off list") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--warning" "WARNING:on") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--warningAsError" "X:on X:off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--styleCheck" "off hint error") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--showAllMismatches" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--lib" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--import" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--include" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--nimcache" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--compileOnly" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--noLinking" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--noMain" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--genScript" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--os" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--cpu" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--debuginfo" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--passC" "OPTION") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--passL" "OPTION") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--cc" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--cincludes" "DIR") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--clibdir" "DIR") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--clib" "LIBNAME") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--project" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--docRoot" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--backend" "c cpp js objc") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--docCmd" "CMD") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--docSeeSrcUrl" "URL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--docInternal" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--lineDir" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--embedsrc" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--tlsEmulation" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--implicitStatic" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--trmacros" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--multimethods" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--hotCodeReloading" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--excessiveStackTrace" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stackTraceMsgs" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--skipCfg" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--skipUserCfg" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--skipParentCfg" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--skipProjCfg" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--mm" "orc arc refc markAndSweep boehm go none regions") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--exceptions" "setjmp cpp goto quirky") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--index" "on off only") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--noImportdoc" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--putenv" "KEY=VALUE") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--NimblePath" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--noNimblePath" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--clearNimblePath" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--cppCompileToNamespace" "NAMESPACE") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--nimMainPrefix" "PREFIX") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--expandMacro" "MACRO") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--expandArc" "PROCNAME") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--excludePath" "PATH") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--dynlibOverride" "SYMBOL") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--dynlibOverrideAll" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--listCmd" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--asm" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--parallelBuild" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--incremental" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--verbosity" "0 1 2 3") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--errorMax" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--maxLoopIterationsVM" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--experimental" "dotOperators callOperator parallel destructor notnil dynamicBindSym forLoopMacros caseStmtMacros codeReordering compiletimeFFI vmopsDanger strictFuncs views strictNotNil overloadableEnums strictEffects unicodeOperators flexibleOptionalParams strictDefs strictCaseObjects inferGenericTypes openSym genericsOpenSym vtables") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--legacy" "allowSemcheckedAstModification checkUnsignedConversions laxEffects verboseTypeMismatch emitGenerics jsNoLambdaLifting") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--benchmarkVM" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--profileVM" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--panics" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--deepcopy" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--jsbigint64" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--nimBasePattern" "nimbase.h") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
fi
local c_short c_long c_accvals
local len i idx0 idx1 idx2
case $curr in
# Asking for accepted optvalues, e.g., `out:`
:)
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" --) ) \
&& return 0
((i+=3))
done
return 124
;;
*)
# When in a incomplete opt value, e.g., `--check:of`
if [[ $prev == : ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prevprev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" -- ${curr}) ) \
&& return 0
((i+=3))
done
return 124
fi
# When in a complete optname, might need optvalue, e.g., `--check`
if [[ $curr =~ ^--?[:()a-zA-Z]+$ ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$(((i / 3 * 3)))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
if __is_short_or_long $curr ${c_short} ${c_long}
then
if [[ ! -z $c_accvals ]]
then
COMPREPLY=( $(compgen -W "${curr}:" -- ${curr}) ) \
&& compopt -o nospace \
&& return 0
else
COMPREPLY=( $(compgen -W "${curr}" -- ${curr}) ) \
&& return 0
fi
fi
((i+=3))
done # while
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
# When in an incomplete optname, e.g., `--chec`
elif [[ $curr =~ ^--?[^:]* ]]
then
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
fi
if true
then
compopt -o filenames
COMPREPLY=( $(compgen -f -- "$curr") )
compopt -o nospace
return 0
fi
;;
esac
return 0
} &&
complete -onospace -F _nim nim
complete -F _nim nim
# ex: ts=2 sw=2 et filetypesh
# ex: filetype=sh

View File

@@ -0,0 +1,339 @@
# bash completion for nimgrep -*- shell-script -*-
__is_short_or_long()
{
local actual short long
actual="$1"
short="$2"
long="$3"
[[ ! -z $short && $actual == $short ]] && return 0
[[ ! -z $long && $actual == $long ]] && return 0
return 1
}
__ask_for_subcmd_or_subopts()
{
local args cmd subcmd words sub_words word_first word_last word_lastlast
local len ilast ilastlast i ele sub_len n_nopts
args=("$@")
ask_for_what="${args[0]}"
cmd="${args[1]}"
subcmd="${args[2]}"
ilast="${args[3]}"
words=("${args[@]:4}")
len=${#words[@]}
ilastlast=$((ilast - 1))
sub_words=("${words[@]:0:ilast}")
sub_len=${#sub_words[@]}
word_first=${words[0]}
word_last=${words[ilast]}
word_lastlast=${words[ilastlast]}
n_nopts=0
# printf "\n[DBUG] word_first:${word_first}|ilast:${ilast}|words(${len}):${words[*]}|sub_words(${sub_len}):${sub_words[*]}\n"
if [[ $word_first != $cmd ]]
then
return 1
fi
i=0
while [[ $i -lt $len ]]
do
ele=${words[i]}
if [[ ! $ele =~ ^- ]]
then
if [[ $ele == $cmd || $ele == $subcmd ]]
then
((n_nopts+=1))
elif [[ $i -eq $ilast && $ele =~ ^[a-zA-Z] ]]
then
((i=i))
elif [[ -z $ele ]]
then
((i=i))
elif [[ $ele =~ ^: ]]
then
((i+=1))
else
return 1
fi
fi
((i+=1))
done
case $ask_for_what in
1)
if [[ n_nopts -eq 1 ]]
then
if [[ -z $word_last || $word_last =~ ^[a-zA-Z] ]] && [[ $word_lastlast != : ]]
then
return 0
fi
fi
;;
2)
if [[ n_nopts -eq 2 ]]
then
if [[ -z $word_last ]] || [[ $word_last =~ ^[-:] ]]
then
return 0
fi
fi
esac
return 1
}
__ask_for_subcmd()
{
__ask_for_subcmd_or_subopts 1 "$@"
}
__ask_for_subcmd_opts()
{
__ask_for_subcmd_or_subopts 2 "$@"
}
_nimgrep()
{
local curr prev prevprev words
local i_curr n_words i_prev i_prevprev
COMPREPLY=()
i_curr=$COMP_CWORD
n_words=$((i_curr+1))
i_prev=$((i_curr-1))
i_prevprev=$((i_curr-2))
curr="${COMP_WORDS[i_curr]}"
prev="${COMP_WORDS[i_prev]}"
prevprev="${COMP_WORDS[i_prevprev]}"
words=("${COMP_WORDS[@]:0:n_words}")
local subcmds opts candids
# printf "\n[DBUG] curr:$curr|prev:$prev|words(${#words[*]}):${words[*]}\n"
# Asking for a subcommand
if false && __ask_for_subcmd nimgrep nimgrep $i_curr "${words[@]}"
then
subcmds=""
return 0
fi
# Prioritize subcmd over opt
if false
then
return 124
elif false && __ask_for_subcmd_opts nimgrep compileToC $i_curr "${words[@]}"
then
opts=() \
&& candids=()
else
opts=() \
&& candids=()
opts+=("-f" "--find" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--replace" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--confirm" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--filenames" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--peg" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--re" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-x" "--rex" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-w" "--word" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-i" "--ignoreCase" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-y" "--ignoreStyle" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-r" "--recursive" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--follow" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-s" "--sortTime" "asc desc") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--extensions" "EX") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notextensions" "EX") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--filename" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notfilename" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--dirname" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notdirname" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--dirpath" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notdirpath" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--inFile" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notinFile" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--bin" "on off only") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-t" "--text" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--inContext" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--notinContext" "PAT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--nocolor" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--colorTheme" "THEME") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--color" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--count" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-c" "--context" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-a" "--afterContext" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-b" "--beforeContext" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-g" "--group" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-l" "--newLine" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--cols" "N auto") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--onlyAscii" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-j" "--threads" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stdin" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--verbose" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-h" "--help" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("-v" "--version" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
fi
local c_short c_long c_accvals
local len i idx0 idx1 idx2
case $curr in
# Asking for accepted optvalues, e.g., `out:`
:)
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" --) ) \
&& return 0
((i+=3))
done
return 124
;;
*)
# When in a incomplete opt value, e.g., `--check:of`
if [[ $prev == : ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prevprev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" -- ${curr}) ) \
&& return 0
((i+=3))
done
return 124
fi
# When in a complete optname, might need optvalue, e.g., `--check`
if [[ $curr =~ ^--?[:()a-zA-Z]+$ ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$(((i / 3 * 3)))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
if __is_short_or_long $curr ${c_short} ${c_long}
then
if [[ ! -z $c_accvals ]]
then
COMPREPLY=( $(compgen -W "${curr}:" -- ${curr}) ) \
&& compopt -o nospace \
&& return 0
else
COMPREPLY=( $(compgen -W "${curr}" -- ${curr}) ) \
&& return 0
fi
fi
((i+=3))
done # while
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
# When in an incomplete optname, e.g., `--chec`
elif [[ $curr =~ ^--?[^:]* ]]
then
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
fi
if true
then
compopt -o filenames
COMPREPLY=( $(compgen -f -- "$curr") )
compopt -o nospace
return 0
fi
;;
esac
return 0
} &&
complete -F _nimgrep nimgrep
# ex: filetype=sh

View File

@@ -0,0 +1,267 @@
# bash completion for nimpretty -*- shell-script -*-
__is_short_or_long()
{
local actual short long
actual="$1"
short="$2"
long="$3"
[[ ! -z $short && $actual == $short ]] && return 0
[[ ! -z $long && $actual == $long ]] && return 0
return 1
}
__ask_for_subcmd_or_subopts()
{
local args cmd subcmd words sub_words word_first word_last word_lastlast
local len ilast ilastlast i ele sub_len n_nopts
args=("$@")
ask_for_what="${args[0]}"
cmd="${args[1]}"
subcmd="${args[2]}"
ilast="${args[3]}"
words=("${args[@]:4}")
len=${#words[@]}
ilastlast=$((ilast - 1))
sub_words=("${words[@]:0:ilast}")
sub_len=${#sub_words[@]}
word_first=${words[0]}
word_last=${words[ilast]}
word_lastlast=${words[ilastlast]}
n_nopts=0
# printf "\n[DBUG] word_first:${word_first}|ilast:${ilast}|words(${len}):${words[*]}|sub_words(${sub_len}):${sub_words[*]}\n"
if [[ $word_first != $cmd ]]
then
return 1
fi
i=0
while [[ $i -lt $len ]]
do
ele=${words[i]}
if [[ ! $ele =~ ^- ]]
then
if [[ $ele == $cmd || $ele == $subcmd ]]
then
((n_nopts+=1))
elif [[ $i -eq $ilast && $ele =~ ^[a-zA-Z] ]]
then
((i=i))
elif [[ -z $ele ]]
then
((i=i))
elif [[ $ele =~ ^: ]]
then
((i+=1))
else
return 1
fi
fi
((i+=1))
done
case $ask_for_what in
1)
if [[ n_nopts -eq 1 ]]
then
if [[ -z $word_last || $word_last =~ ^[a-zA-Z] ]] && [[ $word_lastlast != : ]]
then
return 0
fi
fi
;;
2)
if [[ n_nopts -eq 2 ]]
then
if [[ -z $word_last ]] || [[ $word_last =~ ^[-:] ]]
then
return 0
fi
fi
esac
return 1
}
__ask_for_subcmd()
{
__ask_for_subcmd_or_subopts 1 "$@"
}
__ask_for_subcmd_opts()
{
__ask_for_subcmd_or_subopts 2 "$@"
}
_nimpretty()
{
local curr prev prevprev words
local i_curr n_words i_prev i_prevprev
COMPREPLY=()
i_curr=$COMP_CWORD
n_words=$((i_curr+1))
i_prev=$((i_curr-1))
i_prevprev=$((i_curr-2))
curr="${COMP_WORDS[i_curr]}"
prev="${COMP_WORDS[i_prev]}"
prevprev="${COMP_WORDS[i_prevprev]}"
words=("${COMP_WORDS[@]:0:n_words}")
local subcmds opts candids
# printf "\n[DBUG] curr:$curr|prev:$prev|words(${#words[*]}):${words[*]}\n"
# Asking for a subcommand
if false && __ask_for_subcmd nimpretty nimpretty $i_curr "${words[@]}"
then
subcmds=""
return 0
fi
# Prioritize subcmd over opt
if false
then
return 124
elif false && __ask_for_subcmd_opts nimpretty compileToC $i_curr "${words[@]}"
then
opts=() \
&& candids=()
else
opts=() \
&& candids=()
opts+=("" "--out" "file") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--outDir" "DIR") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stdin" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--indent" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--maxLineLen" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--version" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--help" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
fi
local c_short c_long c_accvals
local len i idx0 idx1 idx2
case $curr in
# Asking for accepted optvalues, e.g., `out:`
:)
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" --) ) \
&& return 0
((i+=3))
done
return 124
;;
*)
# When in a incomplete opt value, e.g., `--check:of`
if [[ $prev == : ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prevprev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" -- ${curr}) ) \
&& return 0
((i+=3))
done
return 124
fi
# When in a complete optname, might need optvalue, e.g., `--check`
if [[ $curr =~ ^--?[:()a-zA-Z]+$ ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$(((i / 3 * 3)))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
if __is_short_or_long $curr ${c_short} ${c_long}
then
if [[ ! -z $c_accvals ]]
then
COMPREPLY=( $(compgen -W "${curr}:" -- ${curr}) ) \
&& compopt -o nospace \
&& return 0
else
COMPREPLY=( $(compgen -W "${curr}" -- ${curr}) ) \
&& return 0
fi
fi
((i+=3))
done # while
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
# When in an incomplete optname, e.g., `--chec`
elif [[ $curr =~ ^--?[^:]* ]]
then
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
fi
if true
then
compopt -o filenames
COMPREPLY=( $(compgen -f -- "$curr") )
compopt -o nospace
return 0
fi
;;
esac
return 0
} &&
complete -F _nimpretty nimpretty
# ex: filetype=sh

View File

@@ -0,0 +1,291 @@
# bash completion for nimsuggest -*- shell-script -*-
__is_short_or_long()
{
local actual short long
actual="$1"
short="$2"
long="$3"
[[ ! -z $short && $actual == $short ]] && return 0
[[ ! -z $long && $actual == $long ]] && return 0
return 1
}
__ask_for_subcmd_or_subopts()
{
local args cmd subcmd words sub_words word_first word_last word_lastlast
local len ilast ilastlast i ele sub_len n_nopts
args=("$@")
ask_for_what="${args[0]}"
cmd="${args[1]}"
subcmd="${args[2]}"
ilast="${args[3]}"
words=("${args[@]:4}")
len=${#words[@]}
ilastlast=$((ilast - 1))
sub_words=("${words[@]:0:ilast}")
sub_len=${#sub_words[@]}
word_first=${words[0]}
word_last=${words[ilast]}
word_lastlast=${words[ilastlast]}
n_nopts=0
# printf "\n[DBUG] word_first:${word_first}|ilast:${ilast}|words(${len}):${words[*]}|sub_words(${sub_len}):${sub_words[*]}\n"
if [[ $word_first != $cmd ]]
then
return 1
fi
i=0
while [[ $i -lt $len ]]
do
ele=${words[i]}
if [[ ! $ele =~ ^- ]]
then
if [[ $ele == $cmd || $ele == $subcmd ]]
then
((n_nopts+=1))
elif [[ $i -eq $ilast && $ele =~ ^[a-zA-Z] ]]
then
((i=i))
elif [[ -z $ele ]]
then
((i=i))
elif [[ $ele =~ ^: ]]
then
((i+=1))
else
return 1
fi
fi
((i+=1))
done
case $ask_for_what in
1)
if [[ n_nopts -eq 1 ]]
then
if [[ -z $word_last || $word_last =~ ^[a-zA-Z] ]] && [[ $word_lastlast != : ]]
then
return 0
fi
fi
;;
2)
if [[ n_nopts -eq 2 ]]
then
if [[ -z $word_last ]] || [[ $word_last =~ ^[-:] ]]
then
return 0
fi
fi
esac
return 1
}
__ask_for_subcmd()
{
__ask_for_subcmd_or_subopts 1 "$@"
}
__ask_for_subcmd_opts()
{
__ask_for_subcmd_or_subopts 2 "$@"
}
_nimsuggest()
{
local curr prev prevprev words
local i_curr n_words i_prev i_prevprev
COMPREPLY=()
i_curr=$COMP_CWORD
n_words=$((i_curr+1))
i_prev=$((i_curr-1))
i_prevprev=$((i_curr-2))
curr="${COMP_WORDS[i_curr]}"
prev="${COMP_WORDS[i_prev]}"
prevprev="${COMP_WORDS[i_prevprev]}"
words=("${COMP_WORDS[@]:0:n_words}")
local subcmds opts candids
# printf "\n[DBUG] curr:$curr|prev:$prev|words(${#words[*]}):${words[*]}\n"
# Asking for a subcommand
if false && __ask_for_subcmd nimsuggest nimsuggest $i_curr "${words[@]}"
then
subcmds=""
return 0
fi
# Prioritize subcmd over opt
if false
then
return 124
elif false && __ask_for_subcmd_opts nimsuggest compileToC $i_curr "${words[@]}"
then
opts=() \
&& candids=()
else
opts=() \
&& candids=()
opts+=("" "--autobind" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--port" "PORT") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--address" "HOST") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--stdin" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--clientProcessId" "PID") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--epc" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--debug" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--log" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--v1" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--v2" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--v3" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--v4" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--info" "nimVer protocolVer capabilities") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--refresh" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--maxresults" "N") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--tester" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--find" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--exceptionInlayHints" "on off") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
opts+=("" "--help" "") \
&& candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
fi
local c_short c_long c_accvals
local len i idx0 idx1 idx2
case $curr in
# Asking for accepted optvalues, e.g., `out:`
:)
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" --) ) \
&& return 0
((i+=3))
done
return 124
;;
*)
# When in a incomplete opt value, e.g., `--check:of`
if [[ $prev == : ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$((i / 3 * 3))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
(false \
|| __is_short_or_long $prevprev ${c_short} ${c_long} \
|| false) \
&& COMPREPLY=( $(compgen -W "${c_accvals}" -- ${curr}) ) \
&& return 0
((i+=3))
done
return 124
fi
# When in a complete optname, might need optvalue, e.g., `--check`
if [[ $curr =~ ^--?[:()a-zA-Z]+$ ]]
then
len=${#opts[@]}
i=0
while [[ $i -lt $len ]]
do
idx0=$(((i / 3 * 3)))
idx1=$((idx0 + 1))
idx2=$((idx1 + 1))
c_short=${opts[idx0]}
c_long=${opts[idx1]}
c_accvals=${opts[idx2]}
if __is_short_or_long $curr ${c_short} ${c_long}
then
if [[ ! -z $c_accvals ]]
then
COMPREPLY=( $(compgen -W "${curr}:" -- ${curr}) ) \
&& compopt -o nospace \
&& return 0
else
COMPREPLY=( $(compgen -W "${curr}" -- ${curr}) ) \
&& return 0
fi
fi
((i+=3))
done # while
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
# When in an incomplete optname, e.g., `--chec`
elif [[ $curr =~ ^--?[^:]* ]]
then
if true
then
COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
compopt -o nospace
return 0
fi
fi
if true
then
compopt -o filenames
COMPREPLY=( $(compgen -f -- "$curr") )
compopt -o nospace
return 0
fi
;;
esac
return 0
} &&
complete -F _nimsuggest nimsuggest
# ex: filetype=sh