diff --git a/.gitignore b/.gitignore
index d804fb8f54..462df4efc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,3 @@ xcuserdata/
/testresults.html
/testresults.json
testament.db
-/csources/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..26f35d82cd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "csources"]
+ path = csources
+ url = ../../nim-lang/csources.git
diff --git a/build.sh b/build.sh
old mode 100644
new mode 100755
index 139c283599..91e1692412
--- a/build.sh
+++ b/build.sh
@@ -2,8 +2,8 @@
set -e
set -x
-if [ ! -d "csources" ]; then
- git clone --depth 1 https://github.com/nim-lang/csources.git
+if [ ! -e csources/.git ]; then
+ git submodule update --init --depth 1
fi
cd "csources"
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 10f2a71da2..3798410e87 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
-# (c) Copyright 2013 Andreas Rumpf
+# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -296,6 +296,7 @@ const
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
+ sfGoto* = sfOverriden # var is used for 'goto' code generation
const
# getting ready for the future expr/stmt merge
@@ -472,7 +473,7 @@ type
# T and I here can bind to both typedesc and static types
# before this is determined, we'll consider them to be a
# wildcard type.
- tfGuarded # guarded pointer
+ tfHasAsgn # type has overloaded assignment operator
tfBorrowDot # distinct type borrows '.'
TTypeFlags* = set[TTypeFlag]
@@ -529,19 +530,20 @@ type
TMagic* = enum # symbols that require compiler magic:
mNone,
mDefined, mDefinedInScope, mCompiles,
- mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
+ mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
mEcho, mShallowCopy, mSlurp, mStaticExec,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
- mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
- mGCunref,
+ mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+ mIncl, mExcl, mCard, mChr,
+ mGCref, mGCunref,
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mSucc, mPred,
mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
- mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
+ mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
mDivU, mModU, mEqI, mLeI,
mLtI,
@@ -550,7 +552,7 @@ type
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
- mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+ mUnaryPlusI, mBitnotI,
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
@@ -589,11 +591,12 @@ type
const
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
mPred, mInc, mDec, mOrd, mLengthOpenArray,
- mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
+ mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+ mIncl, mExcl, mCard, mChr,
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
- mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
+ mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
mDivU, mModU, mEqI, mLeI,
mLtI,
@@ -602,7 +605,7 @@ const
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
- mUnaryPlusI, mBitnotI, mUnaryPlusI64,
+ mUnaryPlusI, mBitnotI,
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
@@ -685,8 +688,8 @@ type
s*: TStorageLoc
flags*: TLocFlags # location's flags
t*: PType # type of location
- r*: PRope # rope value of location (code generators)
- heapRoot*: PRope # keeps track of the enclosing heap object that
+ r*: Rope # rope value of location (code generators)
+ heapRoot*: Rope # keeps track of the enclosing heap object that
# owns this location (required by GC algorithms
# employing heap snapshots or sliding views)
@@ -698,7 +701,7 @@ type
kind*: TLibKind
generated*: bool # needed for the backends:
isOverriden*: bool
- name*: PRope
+ name*: Rope
path*: PNode # can be a string literal!
TInstantiation* = object
@@ -728,7 +731,8 @@ type
typScope*: PScope
of routineKinds:
procInstCache*: seq[PInstantiation]
- scope*: PScope # the scope where the proc was defined
+ gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
+ #scope*: PScope # the scope where the proc was defined
of skModule:
# modules keep track of the generic symbols they use from other modules.
# this is because in incremental compilation, when a module is about to
@@ -794,8 +798,8 @@ type
# for enum types a list of symbols
# for tyInt it can be the int literal
# for procs and tyGenericBody, it's the
- # the body of the user-defined type class
# formal param list
+ # for concepts, the concept body
# else: unused
owner*: PSym # the 'owner' of the type
sym*: PSym # types have the sym associated with them
@@ -804,6 +808,7 @@ type
# mean that there is no destructor.
# see instantiateDestructor in semdestruct.nim
deepCopy*: PSym # overriden 'deepCopy' operation
+ assignment*: PSym # overriden '=' operator
size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown
align*: int16 # the type's alignment requirements
@@ -1168,7 +1173,9 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
result.lockLevel = UnspecifiedLockLevel
when debugIds:
registerId(result)
- #if result.id < 2000:
+ #if result.id == 92231:
+ # echo "KNID ", kind
+ # writeStackTrace()
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
proc mergeLoc(a: var TLoc, b: TLoc) =
@@ -1218,6 +1225,7 @@ proc assignType*(dest, src: PType) =
dest.align = src.align
dest.destructor = src.destructor
dest.deepCopy = src.deepCopy
+ dest.assignment = src.assignment
dest.lockLevel = src.lockLevel
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
@@ -1314,6 +1322,13 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
result = t
while result.kind in kinds: result = lastSon(result)
+proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
+ ## same as skipTypes but handles 'nil'
+ result = t
+ while result != nil and result.kind in kinds:
+ if result.len == 0: return nil
+ result = lastSon(result)
+
proc isGCedMem*(t: PType): bool {.inline.} =
result = t.kind in {tyString, tyRef, tySequence} or
t.kind == tyProc and t.callConv == ccClosure
@@ -1334,6 +1349,13 @@ proc propagateToOwner*(owner, elem: PType) =
if elem.isMetaType:
owner.flags.incl tfHasMeta
+ if tfHasAsgn in elem.flags:
+ let o2 = elem.skipTypes({tyGenericInst})
+ if o2.kind in {tyTuple, tyObject, tyArray, tyArrayConstr,
+ tySequence, tySet, tyDistinct}:
+ o2.flags.incl tfHasAsgn
+ owner.flags.incl tfHasAsgn
+
if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
tyGenericInvocation}:
let elemB = elem.skipTypes({tyGenericInst})
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index c53e53b88e..1707718d75 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -11,18 +11,18 @@
# and sets of nodes are supported. Efficiency is important as
# the data structures here are used in various places of the compiler.
-import
+import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
proc hashNode*(p: RootRef): THash
-proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
+proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph.
-proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope
-proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
-proc lineInfoToStr*(info: TLineInfo): PRope
-
+proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc lineInfoToStr*(info: TLineInfo): Rope
+
# ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
# returns true whether n is in t
@@ -34,10 +34,10 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
# ----------------------- (key, val)-Hashtables ----------------------------
proc tablePut*(t: var TTable, key, val: RootRef)
proc tableGet*(t: TTable, key: RootRef): RootRef
-type
+type
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
-proc tableSearch*(t: TTable, key, closure: RootRef,
+proc tableSearch*(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef
# return val as soon as comparator returns true; if this never happens,
# nil is returned
@@ -45,16 +45,16 @@ proc tableSearch*(t: TTable, key, closure: RootRef,
# ----------------------- str table -----------------------------------------
proc strTableContains*(t: TStrTable, n: PSym): bool
proc strTableAdd*(t: var TStrTable, n: PSym)
-proc strTableGet*(t: TStrTable, name: PIdent): PSym
-
-type
+proc strTableGet*(t: TStrTable, name: PIdent): PSym
+
+type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
- # var
+ # var
# i: TTabIter
# s: PSym
# s = InitTabIter(i, table)
@@ -63,7 +63,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# s = NextIter(i, table)
#
-type
+type
TIdentIter*{.final.} = object # iterator over all syms with same identifier
h*: THash # current hash
name*: PIdent
@@ -97,11 +97,11 @@ proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: THash): THash {.inline.}
# ------------- table[int, int] ---------------------------------------------
-const
+const
InvalidKey* = low(int)
-type
- TIIPair*{.final.} = object
+type
+ TIIPair*{.final.} = object
key*, val*: int
TIIPairSeq* = seq[TIIPair]
@@ -127,21 +127,21 @@ proc skipConvAndClosure*(n: PNode): PNode =
result = result.sons[1]
else: break
-proc sameValue*(a, b: PNode): bool =
+proc sameValue*(a, b: PNode): bool =
result = false
case a.kind
- of nkCharLit..nkUInt64Lit:
+ of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
- of nkFloatLit..nkFloat64Lit:
+ of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
- of nkStrLit..nkTripleStrLit:
+ of nkStrLit..nkTripleStrLit:
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
else:
# don't raise an internal error for 'nimrod check':
#InternalError(a.info, "SameValue")
discard
-proc leValue*(a, b: PNode): bool =
+proc leValue*(a, b: PNode): bool =
# a <= b?
result = false
case a.kind
@@ -162,289 +162,289 @@ proc weakLeValue*(a, b: PNode): TImplication =
else:
result = if leValue(a, b): impYes else: impNo
-proc lookupInRecord(n: PNode, field: PIdent): PSym =
+proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = nil
case n.kind
- of nkRecList:
- for i in countup(0, sonsLen(n) - 1):
+ of nkRecList:
+ for i in countup(0, sonsLen(n) - 1):
result = lookupInRecord(n.sons[i], field)
- if result != nil: return
- of nkRecCase:
+ if result != nil: return
+ of nkRecCase:
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
result = lookupInRecord(n.sons[0], field)
- if result != nil: return
- for i in countup(1, sonsLen(n) - 1):
+ if result != nil: return
+ for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
- of nkOfBranch, nkElse:
+ of nkOfBranch, nkElse:
result = lookupInRecord(lastSon(n.sons[i]), field)
- if result != nil: return
+ if result != nil: return
else: internalError(n.info, "lookupInRecord(record case branch)")
- of nkSym:
+ of nkSym:
if n.sym.name.id == field.id: result = n.sym
else: internalError(n.info, "lookupInRecord()")
-
-proc getModule(s: PSym): PSym =
+
+proc getModule(s: PSym): PSym =
result = s
assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner
-
-proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
- for i in countup(start, sonsLen(list) - 1):
+
+proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
+ for i in countup(start, sonsLen(list) - 1):
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
- if result.name.id == ident.id: return
+ if result.name.id == ident.id: return
else: internalError(list.info, "getSymFromList")
result = nil
-proc hashNode(p: RootRef): THash =
+proc hashNode(p: RootRef): THash =
result = hash(cast[pointer](p))
-proc mustRehash(length, counter: int): bool =
+proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
-proc rspaces(x: int): PRope =
+proc rspaces(x: int): Rope =
# returns x spaces
- result = toRope(spaces(x))
+ result = rope(spaces(x))
-proc toYamlChar(c: char): string =
+proc toYamlChar(c: char): string =
case c
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c
else: result = $c
-
-proc makeYamlString*(s: string): PRope =
+
+proc makeYamlString*(s: string): Rope =
# We have to split long strings into many ropes. Otherwise
# this could trigger InternalError(111). See the ropes module for
# further information.
const MaxLineLength = 64
result = nil
var res = "\""
- for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
- if (i + 1) mod MaxLineLength == 0:
+ for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
+ if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, "\n")
- app(result, toRope(res))
+ add(result, rope(res))
res = "\"" # reset
add(res, toYamlChar(s[i]))
add(res, '\"')
- app(result, toRope(res))
+ add(result, rope(res))
-proc flagsToStr[T](flags: set[T]): PRope =
- if flags == {}:
- result = toRope("[]")
- else:
+proc flagsToStr[T](flags: set[T]): Rope =
+ if flags == {}:
+ result = rope("[]")
+ else:
result = nil
- for x in items(flags):
- if result != nil: app(result, ", ")
- app(result, makeYamlString($x))
- result = con("[", con(result, "]"))
+ for x in items(flags):
+ if result != nil: add(result, ", ")
+ add(result, makeYamlString($x))
+ result = "[" & result & "]"
-proc lineInfoToStr(info: TLineInfo): PRope =
- result = ropef("[$1, $2, $3]", [makeYamlString(toFilename(info)),
- toRope(toLinenumber(info)),
- toRope(toColumn(info))])
+proc lineInfoToStr(info: TLineInfo): Rope =
+ result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
+ rope(toLinenumber(info)),
+ rope(toColumn(info))]
-proc treeToYamlAux(n: PNode, marker: var IntSet,
- indent, maxRecDepth: int): PRope
-proc symToYamlAux(n: PSym, marker: var IntSet,
- indent, maxRecDepth: int): PRope
-proc typeToYamlAux(n: PType, marker: var IntSet,
- indent, maxRecDepth: int): PRope
-proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
- maxRecDepth: int): PRope =
+proc treeToYamlAux(n: PNode, marker: var IntSet,
+ indent, maxRecDepth: int): Rope
+proc symToYamlAux(n: PSym, marker: var IntSet,
+ indent, maxRecDepth: int): Rope
+proc typeToYamlAux(n: PType, marker: var IntSet,
+ indent, maxRecDepth: int): Rope
+proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
+ maxRecDepth: int): Rope =
var istr = rspaces(indent + 2)
- result = toRope("[")
+ result = rope("[")
var mycount = 0
- for i in countup(0, high(n.data)):
- if n.data[i] != nil:
- if mycount > 0: app(result, ",")
- appf(result, "$N$1$2",
+ for i in countup(0, high(n.data)):
+ if n.data[i] != nil:
+ if mycount > 0: add(result, ",")
+ addf(result, "$N$1$2",
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
inc(mycount)
- if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
- app(result, "]")
+ if mycount > 0: addf(result, "$N$1", [rspaces(indent)])
+ add(result, "]")
assert(mycount == n.counter)
-proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
+proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
# array of (name, value) pairs
var istr = rspaces(indent + 2)
- result = toRope("{")
+ result = rope("{")
var i = 0
- while i <= high(c):
- if i > 0: app(result, ",")
- appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
+ while i <= high(c):
+ if i > 0: add(result, ",")
+ addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
inc(i, 2)
- appf(result, "$N$1}", [rspaces(indent)])
+ addf(result, "$N$1}", [rspaces(indent)])
-proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
- maxRecDepth: int): PRope =
- if n == nil:
- result = toRope("null")
- elif containsOrIncl(marker, n.id):
- result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
- strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
- else:
+proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
+ maxRecDepth: int): Rope =
+ if n == nil:
+ result = rope("null")
+ elif containsOrIncl(marker, n.id):
+ result = "\"$1 @$2\"" % [rope(n.name.s), rope(
+ strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+ else:
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
- result = ropeConstr(indent, [toRope("kind"),
- makeYamlString($n.kind),
- toRope("name"), makeYamlString(n.name.s),
- toRope("typ"), typeToYamlAux(n.typ, marker,
- indent + 2, maxRecDepth - 1),
- toRope("info"), lineInfoToStr(n.info),
- toRope("flags"), flagsToStr(n.flags),
- toRope("magic"), makeYamlString($n.magic),
- toRope("ast"), ast, toRope("options"),
- flagsToStr(n.options), toRope("position"),
- toRope(n.position)])
+ result = ropeConstr(indent, [rope("kind"),
+ makeYamlString($n.kind),
+ rope("name"), makeYamlString(n.name.s),
+ rope("typ"), typeToYamlAux(n.typ, marker,
+ indent + 2, maxRecDepth - 1),
+ rope("info"), lineInfoToStr(n.info),
+ rope("flags"), flagsToStr(n.flags),
+ rope("magic"), makeYamlString($n.magic),
+ rope("ast"), ast, rope("options"),
+ flagsToStr(n.options), rope("position"),
+ rope(n.position)])
-proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
- maxRecDepth: int): PRope =
- if n == nil:
- result = toRope("null")
- elif containsOrIncl(marker, n.id):
- result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
- strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
- else:
- if sonsLen(n) > 0:
- result = toRope("[")
- for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(result, ",")
- appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
+proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
+ maxRecDepth: int): Rope =
+ if n == nil:
+ result = rope("null")
+ elif containsOrIncl(marker, n.id):
+ result = "\"$1 @$2\"" % [rope($n.kind), rope(
+ strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+ else:
+ if sonsLen(n) > 0:
+ result = rope("[")
+ for i in countup(0, sonsLen(n) - 1):
+ if i > 0: add(result, ",")
+ addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)])
- appf(result, "$N$1]", [rspaces(indent + 2)])
- else:
- result = toRope("null")
- result = ropeConstr(indent, [toRope("kind"),
- makeYamlString($n.kind),
- toRope("sym"), symToYamlAux(n.sym, marker,
- indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker,
- indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags),
- toRope("callconv"),
- makeYamlString(CallingConvToStr[n.callConv]),
- toRope("size"), toRope(n.size),
- toRope("align"), toRope(n.align),
- toRope("sons"), result])
+ addf(result, "$N$1]", [rspaces(indent + 2)])
+ else:
+ result = rope("null")
+ result = ropeConstr(indent, [rope("kind"),
+ makeYamlString($n.kind),
+ rope("sym"), symToYamlAux(n.sym, marker,
+ indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
+ indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
+ rope("callconv"),
+ makeYamlString(CallingConvToStr[n.callConv]),
+ rope("size"), rope(n.size),
+ rope("align"), rope(n.align),
+ rope("sons"), result])
-proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
- maxRecDepth: int): PRope =
- if n == nil:
- result = toRope("null")
- else:
+proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
+ maxRecDepth: int): Rope =
+ if n == nil:
+ result = rope("null")
+ else:
var istr = rspaces(indent + 2)
- result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
- if maxRecDepth != 0:
- appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+ result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
+ if maxRecDepth != 0:
+ addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
case n.kind
- of nkCharLit..nkInt64Lit:
- appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
- of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
- appf(result, ",$N$1\"floatVal\": $2",
- [istr, toRope(n.floatVal.toStrMaxPrecision)])
- of nkStrLit..nkTripleStrLit:
+ of nkCharLit..nkInt64Lit:
+ addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+ of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+ addf(result, ",$N$1\"floatVal\": $2",
+ [istr, rope(n.floatVal.toStrMaxPrecision)])
+ of nkStrLit..nkTripleStrLit:
if n.strVal.isNil:
- appf(result, ",$N$1\"strVal\": null", [istr])
+ addf(result, ",$N$1\"strVal\": null", [istr])
else:
- appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
- of nkSym:
- appf(result, ",$N$1\"sym\": $2",
+ addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+ of nkSym:
+ addf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
- of nkIdent:
- if n.ident != nil:
- appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
- else:
- appf(result, ",$N$1\"ident\": null", [istr])
- else:
- if sonsLen(n) > 0:
- appf(result, ",$N$1\"sons\": [", [istr])
- for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(result, ",")
- appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
+ of nkIdent:
+ if n.ident != nil:
+ addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+ else:
+ addf(result, ",$N$1\"ident\": null", [istr])
+ else:
+ if sonsLen(n) > 0:
+ addf(result, ",$N$1\"sons\": [", [istr])
+ for i in countup(0, sonsLen(n) - 1):
+ if i > 0: add(result, ",")
+ addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)])
- appf(result, "$N$1]", [istr])
- appf(result, ",$N$1\"typ\": $2",
+ addf(result, "$N$1]", [istr])
+ addf(result, ",$N$1\"typ\": $2",
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
- appf(result, "$N$1}", [rspaces(indent)])
+ addf(result, "$N$1}", [rspaces(indent)])
-proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
+proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = treeToYamlAux(n, marker, indent, maxRecDepth)
-proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
+proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = typeToYamlAux(n, marker, indent, maxRecDepth)
-proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
+proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = symToYamlAux(n, marker, indent, maxRecDepth)
-proc debugTree(n: PNode, indent: int, maxRecDepth: int; renderType=false): PRope
-proc debugType(n: PType, maxRecDepth=100): PRope =
- if n == nil:
- result = toRope("null")
+proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
+proc debugType(n: PType, maxRecDepth=100): Rope =
+ if n == nil:
+ result = rope("null")
else:
- result = toRope($n.kind)
- if n.sym != nil:
- app(result, " ")
- app(result, n.sym.name.s)
+ result = rope($n.kind)
+ if n.sym != nil:
+ add(result, " ")
+ add(result, n.sym.name.s)
if n.kind in IntegralTypes and n.n != nil:
- app(result, ", node: ")
- app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
+ add(result, ", node: ")
+ add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
- app(result, "(")
+ add(result, "(")
for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(result, ", ")
+ if i > 0: add(result, ", ")
if n.sons[i] == nil:
- app(result, "null")
+ add(result, "null")
else:
- app(result, debugType(n.sons[i], maxRecDepth-1))
+ add(result, debugType(n.sons[i], maxRecDepth-1))
if n.kind == tyObject and n.n != nil:
- app(result, ", node: ")
- app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
- app(result, ")")
+ add(result, ", node: ")
+ add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
+ add(result, ")")
proc debugTree(n: PNode, indent: int, maxRecDepth: int;
- renderType=false): PRope =
- if n == nil:
- result = toRope("null")
- else:
+ renderType=false): Rope =
+ if n == nil:
+ result = rope("null")
+ else:
var istr = rspaces(indent + 2)
- result = ropef("{$N$1\"kind\": $2",
- [istr, makeYamlString($n.kind)])
- if maxRecDepth != 0:
+ result = "{$N$1\"kind\": $2" %
+ [istr, makeYamlString($n.kind)]
+ if maxRecDepth != 0:
case n.kind
of nkCharLit..nkUInt64Lit:
- appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
- of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
- appf(result, ",$N$1\"floatVal\": $2",
- [istr, toRope(n.floatVal.toStrMaxPrecision)])
- of nkStrLit..nkTripleStrLit:
+ addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+ of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+ addf(result, ",$N$1\"floatVal\": $2",
+ [istr, rope(n.floatVal.toStrMaxPrecision)])
+ of nkStrLit..nkTripleStrLit:
if n.strVal.isNil:
- appf(result, ",$N$1\"strVal\": null", [istr])
+ addf(result, ",$N$1\"strVal\": null", [istr])
else:
- appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
- of nkSym:
- appf(result, ",$N$1\"sym\": $2_$3",
- [istr, toRope(n.sym.name.s), toRope(n.sym.id)])
- # [istr, symToYaml(n.sym, indent, maxRecDepth),
- # toRope(n.sym.id)])
+ addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+ of nkSym:
+ addf(result, ",$N$1\"sym\": $2_$3",
+ [istr, rope(n.sym.name.s), rope(n.sym.id)])
+ # [istr, symToYaml(n.sym, indent, maxRecDepth),
+ # rope(n.sym.id)])
if renderType and n.sym.typ != nil:
- appf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
- of nkIdent:
- if n.ident != nil:
- appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
- else:
- appf(result, ",$N$1\"ident\": null", [istr])
- else:
- if sonsLen(n) > 0:
- appf(result, ",$N$1\"sons\": [", [istr])
- for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(result, ",")
- appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
+ addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
+ of nkIdent:
+ if n.ident != nil:
+ addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+ else:
+ addf(result, ",$N$1\"ident\": null", [istr])
+ else:
+ if sonsLen(n) > 0:
+ addf(result, ",$N$1\"sons\": [", [istr])
+ for i in countup(0, sonsLen(n) - 1):
+ if i > 0: add(result, ",")
+ addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
indent + 4, maxRecDepth - 1, renderType)])
- appf(result, "$N$1]", [istr])
- appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
- appf(result, "$N$1}", [rspaces(indent)])
+ addf(result, "$N$1]", [istr])
+ addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+ addf(result, "$N$1}", [rspaces(indent)])
proc debug(n: PSym) =
if n == nil:
@@ -452,27 +452,26 @@ proc debug(n: PSym) =
elif n.kind == skUnknown:
msgWriteln("skUnknown")
else:
- #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
+ #writeln(stdout, $symToYaml(n, 0, 1))
msgWriteln("$1_$2: $3, $4, $5, $6" % [
- n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
- flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
- $n.kind])
+ n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
+ $lineInfoToStr(n.info), $n.kind])
-proc debug(n: PType) =
- msgWriteln(ropeToStr(debugType(n)))
+proc debug(n: PType) =
+ msgWriteln($debugType(n))
-proc debug(n: PNode) =
- msgWriteln(ropeToStr(debugTree(n, 0, 100)))
+proc debug(n: PNode) =
+ msgWriteln($debugTree(n, 0, 100))
-const
+const
EmptySeq = @[]
-proc nextTry(h, maxHash: THash): THash =
- result = ((5 * h) + 1) and maxHash
+proc nextTry(h, maxHash: THash): THash =
+ result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
-
+
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
@@ -490,94 +489,94 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
assert(data[h] == nil)
data[h] = obj
-proc objectSetEnlarge(t: var TObjectSet) =
+proc objectSetEnlarge(t: var TObjectSet) =
var n: TObjectSeq
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)):
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n)
-proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
+proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj)
inc(t.counter)
-proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
+proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
# returns true if obj is already in the string table:
var h: THash = hashNode(obj) and high(t.data)
- while true:
+ while true:
var it = t.data[h]
- if it == nil: break
- if it == obj:
+ if it == nil: break
+ if it == obj:
return true # found it
h = nextTry(h, high(t.data))
- if mustRehash(len(t.data), t.counter):
+ if mustRehash(len(t.data), t.counter):
objectSetEnlarge(t)
objectSetRawInsert(t.data, obj)
- else:
+ else:
assert(t.data[h] == nil)
t.data[h] = obj
inc(t.counter)
result = false
-proc tableRawGet(t: TTable, key: RootRef): int =
+proc tableRawGet(t: TTable, key: RootRef): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
- while t.data[h].key != nil:
- if t.data[h].key == key:
+ while t.data[h].key != nil:
+ if t.data[h].key == key:
return h
h = nextTry(h, high(t.data))
result = -1
-proc tableSearch(t: TTable, key, closure: RootRef,
- comparator: TCmpProc): RootRef =
+proc tableSearch(t: TTable, key, closure: RootRef,
+ comparator: TCmpProc): RootRef =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
- while t.data[h].key != nil:
- if t.data[h].key == key:
- if comparator(t.data[h].val, closure):
+ while t.data[h].key != nil:
+ if t.data[h].key == key:
+ if comparator(t.data[h].val, closure):
# BUGFIX 1
return t.data[h].val
h = nextTry(h, high(t.data))
result = nil
-proc tableGet(t: TTable, key: RootRef): RootRef =
+proc tableGet(t: TTable, key: RootRef): RootRef =
var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
-
-proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
+
+proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
var h: THash = hashNode(key) and high(data)
- while data[h].key != nil:
+ while data[h].key != nil:
assert(data[h].key != key)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
-proc tableEnlarge(t: var TTable) =
+proc tableEnlarge(t: var TTable) =
var n: TPairSeq
newSeq(n, len(t.data) * GrowthFactor)
- for i in countup(0, high(t.data)):
+ for i in countup(0, high(t.data)):
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
-proc tablePut(t: var TTable, key, val: RootRef) =
+proc tablePut(t: var TTable, key, val: RootRef) =
var index = tableRawGet(t, key)
- if index >= 0:
+ if index >= 0:
t.data[index].val = val
- else:
+ else:
if mustRehash(len(t.data), t.counter): tableEnlarge(t)
tableRawInsert(t.data, key, val)
inc(t.counter)
-proc strTableContains(t: TStrTable, n: PSym): bool =
+proc strTableContains(t: TStrTable, n: PSym): bool =
var h: THash = n.name.h and high(t.data) # start with real hash value
- while t.data[h] != nil:
- if (t.data[h] == n):
+ while t.data[h] != nil:
+ if (t.data[h] == n):
return true
h = nextTry(h, high(t.data))
result = false
-proc strTableRawInsert(data: var TSymSeq, n: PSym) =
+proc strTableRawInsert(data: var TSymSeq, n: PSym) =
var h: THash = n.name.h and high(data)
if sfImmediate notin n.flags:
# fast path:
@@ -614,18 +613,18 @@ proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
return
h = nextTry(h, high(data))
assert false
-
+
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
symTabReplaceRaw(t.data, prevSym, newSym)
-proc strTableEnlarge(t: var TStrTable) =
+proc strTableEnlarge(t: var TStrTable) =
var n: TSymSeq
newSeq(n, len(t.data) * GrowthFactor)
- for i in countup(0, high(t.data)):
+ for i in countup(0, high(t.data)):
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n)
-proc strTableAdd(t: var TStrTable, n: PSym) =
+proc strTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n)
inc(t.counter)
@@ -666,103 +665,103 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
inc(t.counter)
result = false
-proc strTableGet(t: TStrTable, name: PIdent): PSym =
+proc strTableGet(t: TStrTable, name: PIdent): PSym =
var h: THash = name.h and high(t.data)
- while true:
+ while true:
result = t.data[h]
- if result == nil: break
- if result.name.id == name.id: break
+ if result == nil: break
+ if result.name.id == name.id: break
h = nextTry(h, high(t.data))
-proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
+proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h
ti.name = s
if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab)
-
-proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
+
+proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
var h = ti.h and high(tab.data)
var start = h
result = tab.data[h]
- while result != nil:
- if result.name.id == ti.name.id: break
+ while result != nil:
+ if result.name.id == ti.name.id: break
h = nextTry(h, high(tab.data))
- if h == start:
+ if h == start:
result = nil
- break
+ break
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
-
-proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
+
+proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: IntSet): PSym =
var h: THash = ti.h and high(tab.data)
var start = h
result = tab.data[h]
- while result != nil:
- if result.name.id == ti.name.id and not contains(excluding, result.id):
+ while result != nil:
+ if result.name.id == ti.name.id and not contains(excluding, result.id):
break
h = nextTry(h, high(tab.data))
- if h == start:
+ if h == start:
result = nil
- break
+ break
result = tab.data[h]
ti.h = nextTry(h, high(tab.data))
if result != nil and contains(excluding, result.id): result = nil
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
- excluding: IntSet): PSym =
+ excluding: IntSet): PSym =
ti.h = s.h
ti.name = s
if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding)
-proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
+proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0 # we start by zero ...
- if tab.counter == 0:
+ if tab.counter == 0:
result = nil # FIX 1: removed endless loop
- else:
+ else:
result = nextIter(ti, tab)
-
-proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
+
+proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
result = nil
- while (ti.h <= high(tab.data)):
+ while (ti.h <= high(tab.data)):
result = tab.data[ti.h]
inc(ti.h) # ... and increment by one always
- if result != nil: break
+ if result != nil: break
-iterator items*(tab: TStrTable): PSym =
+iterator items*(tab: TStrTable): PSym =
var it: TTabIter
var s = initTabIter(it, tab)
- while s != nil:
+ while s != nil:
yield s
s = nextIter(it, tab)
-proc hasEmptySlot(data: TIdPairSeq): bool =
- for h in countup(0, high(data)):
- if data[h].key == nil:
+proc hasEmptySlot(data: TIdPairSeq): bool =
+ for h in countup(0, high(data)):
+ if data[h].key == nil:
return true
result = false
-proc idTableRawGet(t: TIdTable, key: int): int =
+proc idTableRawGet(t: TIdTable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
- while t.data[h].key != nil:
+ while t.data[h].key != nil:
if t.data[h].key.id == key:
return h
h = nextTry(h, high(t.data))
result = - 1
-proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
+proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key
else: result = false
-
-proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
+
+proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
-
-proc idTableGet(t: TIdTable, key: int): RootRef =
+
+proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
@@ -771,30 +770,30 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
for i in 0..high(t.data):
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
-
-proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
+
+proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: THash
h = key.id and high(data)
- while data[h].key != nil:
+ while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
-proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
- var
+proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
+ var
index: int
n: TIdPairSeq
index = idTableRawGet(t, key.id)
- if index >= 0:
+ if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
- else:
- if mustRehash(len(t.data), t.counter):
+ else:
+ if mustRehash(len(t.data), t.counter):
newSeq(n, len(t.data) * GrowthFactor)
- for i in countup(0, high(t.data)):
- if t.data[i].key != nil:
+ for i in countup(0, high(t.data)):
+ if t.data[i].key != nil:
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
@@ -805,7 +804,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
-proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
+proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
@@ -814,7 +813,7 @@ proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
h = nextTry(h, high(t.data))
result = - 1
-proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
+proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int
index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
@@ -823,28 +822,28 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
if not isNil(t.data):
result = idNodeTableGet(t, key)
-
-proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
+
+proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash
h = key.id and high(data)
- while data[h].key != nil:
+ while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
-proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
+proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key)
- if index >= 0:
+ if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
- else:
- if mustRehash(len(t.data), t.counter):
+ else:
+ if mustRehash(len(t.data), t.counter):
var n: TIdNodePairSeq
newSeq(n, len(t.data) * GrowthFactor)
- for i in countup(0, high(t.data)):
- if t.data[i].key != nil:
+ for i in countup(0, high(t.data)):
+ if t.data[i].key != nil:
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
idNodeTableRawInsert(t.data, key, val)
@@ -858,46 +857,46 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
-proc initIITable(x: var TIITable) =
+proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, StartSize)
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
-
-proc iiTableRawGet(t: TIITable, key: int): int =
+
+proc iiTableRawGet(t: TIITable, key: int): int =
var h: THash
h = key and high(t.data) # start with real hash value
- while t.data[h].key != InvalidKey:
+ while t.data[h].key != InvalidKey:
if t.data[h].key == key: return h
h = nextTry(h, high(t.data))
result = -1
-proc iiTableGet(t: TIITable, key: int): int =
+proc iiTableGet(t: TIITable, key: int): int =
var index = iiTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = InvalidKey
-
-proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
+
+proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
var h: THash
h = key and high(data)
- while data[h].key != InvalidKey:
+ while data[h].key != InvalidKey:
assert(data[h].key != key)
h = nextTry(h, high(data))
assert(data[h].key == InvalidKey)
data[h].key = key
data[h].val = val
-proc iiTablePut(t: var TIITable, key, val: int) =
+proc iiTablePut(t: var TIITable, key, val: int) =
var index = iiTableRawGet(t, key)
- if index >= 0:
+ if index >= 0:
assert(t.data[index].key != InvalidKey)
t.data[index].val = val
- else:
- if mustRehash(len(t.data), t.counter):
+ else:
+ if mustRehash(len(t.data), t.counter):
var n: TIIPairSeq
newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(n)): n[i].key = InvalidKey
- for i in countup(0, high(t.data)):
- if t.data[i].key != InvalidKey:
+ for i in countup(0, high(t.data)):
+ if t.data[i].key != InvalidKey:
iiTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
iiTableRawInsert(t.data, key, val)
diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim
index 50d3fd017e..6fcc57a913 100644
--- a/compiler/canonicalizer.nim
+++ b/compiler/canonicalizer.nim
@@ -243,24 +243,24 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
encodeNode(w, n.info, n.sons[i], result)
add(result, ')')
-proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
+proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
- if loc.s != low(loc.s):
+ if loc.s != low(loc.s):
add(result, '*')
encodeVInt(ord(loc.s), result)
- if loc.flags != {}:
+ if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil:
add(result, '^')
encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t)
- if loc.r != nil:
+ if loc.r != nil:
add(result, '!')
- encodeStr(ropeToStr(loc.r), result)
- if loc.a != 0:
+ encodeStr($loc.r, result)
+ if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldLen + 1 == result.len:
@@ -317,7 +317,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
- encodeStr(ropeToStr(lib.name), result)
+ encodeStr($lib.name, result)
add(result, '|')
encodeNode(w, info, lib.path, result)
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 5c4767aed2..2dacc25e9f 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -19,13 +19,13 @@ proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
- callee, params: PRope) =
- var pl = con(callee, ~"(", params)
+ callee, params: Rope) =
+ var pl = callee & ~"(" & params
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
- if params != nil: pl.app(~", ")
+ if params != nil: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
# Great, we can use 'd':
@@ -33,18 +33,18 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
resetLoc(p, d)
- app(pl, addrLoc(d))
- app(pl, ~");$n")
+ add(pl, addrLoc(d))
+ add(pl, ~");$n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true)
- app(pl, addrLoc(tmp))
- app(pl, ~");$n")
+ add(pl, addrLoc(tmp))
+ add(pl, ~");$n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
- app(pl, ~")")
+ add(pl, ~")")
if p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen
@@ -60,7 +60,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
- app(pl, ~");$n")
+ add(pl, ~");$n")
line(p, cpsStmts, pl)
proc isInCurrentFrame(p: BProc, n: PNode): bool =
@@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = isInCurrentFrame(p, n.sons[0])
else: discard
-proc openArrayLoc(p: BProc, n: PNode): PRope =
+proc openArrayLoc(p: BProc, n: PNode): Rope =
var a: TLoc
let q = skipConv(n)
@@ -104,28 +104,28 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
else:
"$1->data+($2), ($3)-($2)+1"
else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
- result = ropef(fmt, [rdLoc(a), rdLoc(b), rdLoc(c)])
+ result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
else:
initLocExpr(p, n, a)
case skipTypes(a.t, abstractVar).kind
of tyOpenArray, tyVarargs:
- result = ropef("$1, $1Len0", [rdLoc(a)])
+ result = "$1, $1Len0" % [rdLoc(a)]
of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar and
not compileToCpp(p.module):
- result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
+ result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
else:
- result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
+ result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
of tyArray, tyArrayConstr:
- result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
+ result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
else: internalError("openArrayLoc: " & typeToString(a.t))
-proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} =
+proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
var a: TLoc
initLocExpr(p, n.sons[0], a)
- result = ropef("$1->data", [a.rdLoc])
+ result = "$1->data" % [a.rdLoc]
-proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
+proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n)
@@ -151,7 +151,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
initLocExprSingleUse(p, n, a)
result = rdLoc(a)
-proc genArgNoParam(p: BProc, n: PNode): PRope =
+proc genArgNoParam(p: BProc, n: PNode): Rope =
var a: TLoc
if n.kind == nkStringToCString:
result = genArgStringToCString(p, n)
@@ -163,7 +163,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
initLocExpr(p, ri.sons[0], op)
- var params: PRope
+ var params: Rope
# getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -171,27 +171,27 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var length = sonsLen(ri)
for i in countup(1, length - 1):
if ri.sons[i].typ.isCompileTimeOnly: continue
- if params != nil: app(params, ~", ")
+ if params != nil: add(params, ~", ")
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
- app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
+ add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
else:
- app(params, genArgNoParam(p, ri.sons[i]))
+ add(params, genArgNoParam(p, ri.sons[i]))
fixupCall(p, le, ri, d, op.r, params)
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
- proc getRawProcType(p: BProc, t: PType): PRope =
+ proc getRawProcType(p: BProc, t: PType): Rope =
result = getClosureType(p.module, t, clHalf)
- proc addComma(r: PRope): PRope =
- result = if r == nil: r else: con(r, ~", ")
+ proc addComma(r: Rope): Rope =
+ result = if r == nil: r else: r & ~", "
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc
initLocExpr(p, ri.sons[0], op)
- var pl: PRope
+ var pl: Rope
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -201,19 +201,19 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if ri.sons[i].typ.isCompileTimeOnly: continue
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
- app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
+ add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
else:
- app(pl, genArgNoParam(p, ri.sons[i]))
- if i < length - 1: app(pl, ~", ")
+ add(pl, genArgNoParam(p, ri.sons[i]))
+ if i < length - 1: add(pl, ~", ")
template genCallPattern {.dirty.} =
- lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
+ lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
- if sonsLen(ri) > 1: app(pl, ~", ")
+ if sonsLen(ri) > 1: add(pl, ~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
# Great, we can use 'd':
@@ -222,12 +222,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
resetLoc(p, d)
- app(pl, addrLoc(d))
+ add(pl, addrLoc(d))
genCallPattern()
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true)
- app(pl, addrLoc(tmp))
+ add(pl, addrLoc(tmp))
genCallPattern()
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
@@ -235,12 +235,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
- list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
+ list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
genAssignment(p, d, list, {}) # no need for deep copying
else:
genCallPattern()
-proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
if ri.sons[i].typ.isCompileTimeOnly:
result = nil
elif i < sonsLen(typ):
@@ -291,7 +291,25 @@ y.v() --> y.v() is correct
"""
-proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
+proc skipAddrDeref(node: PNode): PNode =
+ var n = node
+ var isAddr = false
+ case n.kind
+ of nkAddr, nkHiddenAddr:
+ n = n.sons[0]
+ isAddr = true
+ of nkDerefExpr, nkHiddenDeref:
+ n = n.sons[0]
+ else: return n
+ if n.kind == nkObjDownConv: n = n.sons[0]
+ if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
+ result = n.sons[0]
+ elif n.kind in {nkAddr, nkHiddenAddr}:
+ result = n.sons[0]
+ else:
+ result = node
+
+proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
# for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience.
@@ -301,83 +319,84 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
# skip the deref:
var ri = ri[i]
while ri.kind == nkObjDownConv: ri = ri[0]
- if typ.sons[i].kind == tyVar:
+ let t = typ.sons[i].skipTypes({tyGenericInst})
+ if t.kind == tyVar:
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.typ.kind == tyPtr:
result = genArgNoParam(p, x)
- result.app("->")
+ result.add("->")
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
result = genArgNoParam(p, x[0])
- result.app("->")
+ result.add("->")
else:
result = genArgNoParam(p, x)
- result.app(".")
- elif typ.sons[i].kind == tyPtr:
+ result.add(".")
+ elif t.kind == tyPtr:
if ri.kind in {nkAddr, nkHiddenAddr}:
result = genArgNoParam(p, ri[0])
- result.app(".")
+ result.add(".")
else:
result = genArgNoParam(p, ri)
- result.app("->")
+ result.add("->")
else:
+ ri = skipAddrDeref(ri)
+ if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
- result.app(".")
+ result.add(".")
-proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
+proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
var i = 0
var j = 1
while i < pat.len:
case pat[i]
of '@':
if j < ri.len:
- result.app genOtherArg(p, ri, j, typ)
+ result.add genOtherArg(p, ri, j, typ)
for k in j+1 .. < ri.len:
- result.app(~", ")
- result.app genOtherArg(p, ri, k, typ)
+ result.add(~", ")
+ result.add genOtherArg(p, ri, k, typ)
inc i
of '#':
if pat[i+1] in {'+', '@'}:
let ri = ri[j]
if ri.kind in nkCallKinds:
let typ = skipTypes(ri.sons[0].typ, abstractInst)
- if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
- result.app(~"(")
+ if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
+ result.add(~"(")
if 1 < ri.len:
- result.app genOtherArg(p, ri, 1, typ)
+ result.add genOtherArg(p, ri, 1, typ)
for k in j+1 .. < ri.len:
- result.app(~", ")
- result.app genOtherArg(p, ri, k, typ)
- result.app(~")")
+ result.add(~", ")
+ result.add genOtherArg(p, ri, k, typ)
+ result.add(~")")
else:
localError(ri.info, "call expression expected for C++ pattern")
inc i
elif pat[i+1] == '.':
- result.app genThisArg(p, ri, j, typ)
+ result.add genThisArg(p, ri, j, typ)
inc i
+ elif pat[i+1] == '[':
+ var arg = ri.sons[j].skipAddrDeref
+ while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
+ result.add genArgNoParam(p, arg)
+ #result.add debugTree(arg, 0, 10)
else:
- result.app genOtherArg(p, ri, j, typ)
+ result.add genOtherArg(p, ri, j, typ)
inc j
inc i
of '\'':
- inc i
- let stars = i
- while pat[i] == '*': inc i
- if pat[i] in Digits:
- let j = pat[i].ord - '0'.ord
- var t = typ.sons[j]
- for k in 1..i-stars:
- if t != nil and t.len > 0:
- t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
- if t == nil: result.app(~"void")
- else: result.app(getTypeDesc(p.module, t))
- inc i
+ var idx, stars: int
+ if scanCppGenericSlot(pat, i, idx, stars):
+ var t = resolveStarsInCppType(typ, idx, stars)
+ if t == nil: result.add(~"void")
+ else: result.add(getTypeDesc(p.module, t))
else:
let start = i
while i < pat.len:
if pat[i] notin {'@', '#', '\''}: inc(i)
else: break
if i - 1 >= start:
- app(result, substr(pat, start, i - 1))
+ add(result, substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc
@@ -387,7 +406,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
- # don't call 'ropeToStr' here for efficiency:
+ # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil
if pat.contains({'#', '(', '@', '\''}):
@@ -410,19 +429,19 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
- app(pl, ~";$n")
+ add(pl, ~";$n")
line(p, cpsStmts, pl)
else:
- var pl: PRope = nil
+ var pl: Rope = nil
#var param = typ.n.sons[1].sym
if 1 < ri.len:
- app(pl, genThisArg(p, ri, 1, typ))
- app(pl, op.r)
- var params: PRope
+ add(pl, genThisArg(p, ri, 1, typ))
+ add(pl, op.r)
+ var params: Rope
for i in countup(2, length - 1):
- if params != nil: params.app(~", ")
+ if params != nil: params.add(~", ")
assert(sonsLen(typ) == sonsLen(typ.n))
- app(params, genOtherArg(p, ri, i, typ))
+ add(params, genOtherArg(p, ri, i, typ))
fixupCall(p, le, ri, d, pl, params)
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
@@ -436,55 +455,55 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
- # don't call 'ropeToStr' here for efficiency:
+ # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil
var start = 3
if ' ' in pat:
start = 1
- app(pl, op.r)
+ add(pl, op.r)
if length > 1:
- app(pl, ~": ")
- app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+ add(pl, ~": ")
+ add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
start = 2
else:
if length > 1:
- app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
- app(pl, ~" ")
- app(pl, op.r)
+ add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+ add(pl, ~" ")
+ add(pl, op.r)
if length > 2:
- app(pl, ~": ")
- app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
+ add(pl, ~": ")
+ add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
for i in countup(start, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
internalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
- app(pl, ~" ")
- app(pl, param.name.s)
- app(pl, ~": ")
- app(pl, genArg(p, ri.sons[i], param, ri))
+ add(pl, ~" ")
+ add(pl, param.name.s)
+ add(pl, ~": ")
+ add(pl, genArg(p, ri.sons[i], param, ri))
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
- if sonsLen(ri) > 1: app(pl, ~" ")
+ if sonsLen(ri) > 1: add(pl, ~" ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
- app(pl, ~"Result: ")
- app(pl, addrLoc(d))
- app(pl, ~"];$n")
+ add(pl, ~"Result: ")
+ add(pl, addrLoc(d))
+ add(pl, ~"];$n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true)
- app(pl, addrLoc(tmp))
- app(pl, ~"];$n")
+ add(pl, addrLoc(tmp))
+ add(pl, ~"];$n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
- app(pl, ~"]")
+ add(pl, ~"]")
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
@@ -492,7 +511,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
- app(pl, ~"];$n")
+ add(pl, ~"];$n")
line(p, cpsStmts, pl)
proc genCall(p: BProc, e: PNode, d: var TLoc) =
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index aa1bf31bed..05a3602d16 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -11,45 +11,45 @@
# -------------------------- constant expressions ------------------------
-proc int64Literal(i: BiggestInt): PRope =
+proc int64Literal(i: BiggestInt): Rope =
if i > low(int64):
- result = rfmt(nil, "IL64($1)", toRope(i))
+ result = rfmt(nil, "IL64($1)", rope(i))
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
-proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
+proc uint64Literal(i: uint64): Rope = rope($i & "ULL")
-proc intLiteral(i: BiggestInt): PRope =
+proc intLiteral(i: BiggestInt): Rope =
if i > low(int32) and i <= high(int32):
- result = toRope(i)
+ result = rope(i)
elif i == low(int32):
# Nim has the same bug for the same reasons :-)
result = ~"(-2147483647 -1)"
elif i > low(int64):
- result = rfmt(nil, "IL64($1)", toRope(i))
+ result = rfmt(nil, "IL64($1)", rope(i))
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
-proc int32Literal(i: int): PRope =
+proc int32Literal(i: int): Rope =
if i == int(low(int32)):
result = ~"(-2147483647 -1)"
else:
- result = toRope(i)
+ result = rope(i)
-proc genHexLiteral(v: PNode): PRope =
+proc genHexLiteral(v: PNode): Rope =
# hex literals are unsigned in C
# so we don't generate hex literals any longer.
if v.kind notin {nkIntLit..nkUInt64Lit}:
internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal)
-proc getStrLit(m: BModule, s: string): PRope =
+proc getStrLit(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq")
- result = con("TMP", toRope(backendId()))
- appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
- [result, makeCString(s), toRope(len(s))])
+ result = "TMP" & rope(backendId())
+ addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
+ [result, makeCString(s), rope(len(s))])
-proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
+proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
case n.kind
of nkCharLit..nkUInt64Lit:
@@ -62,21 +62,21 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
of tyInt64: result = int64Literal(n.intVal)
of tyUInt64: result = uint64Literal(uint64(n.intVal))
else:
- result = ropef("(($1) $2)", [getTypeDesc(p.module,
- skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
+ result = "(($1) $2)" % [getTypeDesc(p.module,
+ skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]
of nkNilLit:
let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
- result = con("TMP", toRope(id))
+ result = "TMP" & rope(id)
if id == gBackendId:
# not found in cache:
inc(gBackendId)
- appf(p.module.s[cfsData],
+ addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result])
else:
- result = toRope("NIM_NIL")
+ result = rope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
@@ -87,16 +87,16 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, n.strVal)])
else:
- result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
+ result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
else:
result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit:
- result = toRope(n.floatVal.toStrMaxPrecision)
+ result = rope(n.floatVal.toStrMaxPrecision)
else:
internalError(n.info, "genLiteral(" & $n.kind & ')')
result = nil
-proc genLiteral(p: BProc, n: PNode): PRope =
+proc genLiteral(p: BProc, n: PNode): Rope =
result = genLiteral(p, n, n.typ)
proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
@@ -113,10 +113,10 @@ proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8)
-proc genRawSetData(cs: TBitSet, size: int): PRope =
- var frmt: TFormatStr
+proc genRawSetData(cs: TBitSet, size: int): Rope =
+ var frmt: FormatStr
if size > 8:
- result = ropef("{$n")
+ result = "{$n" % []
for i in countup(0, size - 1):
if i < size - 1:
# not last iteration?
@@ -124,22 +124,22 @@ proc genRawSetData(cs: TBitSet, size: int): PRope =
else: frmt = "0x$1, "
else:
frmt = "0x$1}$n"
- appf(result, frmt, [toRope(toHex(ze64(cs[i]), 2))])
+ addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))])
else:
result = intLiteral(bitSetToWord(cs, size))
- # result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
+ # result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
-proc genSetNode(p: BProc, n: PNode): PRope =
+proc genSetNode(p: BProc, n: PNode): Rope =
var cs: TBitSet
var size = int(getSize(n.typ))
toBitSet(n, cs)
if size > 8:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
- result = con("TMP", toRope(id))
+ result = "TMP" & rope(id)
if id == gBackendId:
# not found in cache:
inc(gBackendId)
- appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
+ addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else:
result = genRawSetData(cs, size)
@@ -211,12 +211,12 @@ proc asgnComplexity(n: PNode): int =
result += asgnComplexity(t)
else: discard
-proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
+proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
assert field != nil
result.k = locField
result.s = a.s
result.t = t
- result.r = rdLoc(a).con(".").con(field)
+ result.r = rdLoc(a) & "." & field
result.heapRoot = a.heapRoot
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@@ -230,7 +230,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let t = skipTypes(dest.t, abstractInst).getUniqueType()
for i in 0 .. $3) #raiseOverflow();$n",
result, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
@@ -522,11 +522,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# later via 'chckRange'
let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options:
- let res = ropef(opr[m], [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)])
+ let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
putIntoDest(p, d, e.typ, res)
else:
let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
- putIntoDest(p, d, e.typ, ropef("($#)($#)", [getTypeDesc(p.module, t), res]))
+ putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
@@ -544,7 +544,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
rdLoc(a), intLiteral(firstOrd(t)))
- putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)]))
+ putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
@@ -566,8 +566,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"($4)($1 & $2)", # BitandI64
"($4)($1 | $2)", # BitorI64
"($4)($1 ^ $2)", # BitxorI64
- "(($1 <= $2) ? $1 : $2)", # MinI64
- "(($1 >= $2) ? $1 : $2)", # MaxI64
"(($1 <= $2) ? $1 : $2)", # MinF64
"(($1 >= $2) ? $1 : $2)", # MaxF64
"($4)((NU$3)($1) + (NU$3)($2))", # AddU
@@ -613,8 +611,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ,
- ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s),
- getSimpleTypeDesc(p.module, e.typ)]))
+ binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
+ getSimpleTypeDesc(p.module, e.typ)])
proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
@@ -624,10 +622,9 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[2], b)
if a.t.callConv == ccClosure:
putIntoDest(p, d, e.typ,
- ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
- rdLoc(a), rdLoc(b)]))
+ "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
else:
- putIntoDest(p, d, e.typ, ropef("($1 == $2)", [rdLoc(a), rdLoc(b)]))
+ putIntoDest(p, d, e.typ, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
let t = skipTypes(e.sons[1].typ, abstractRange)
@@ -641,7 +638,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
"$1", # UnaryPlusI
"($3)((NU$2) ~($1))", # BitnotI
- "$1", # UnaryPlusI64
"($3)((NU$2) ~($1))", # BitnotI64
"$1", # UnaryPlusF64
"-($1)", # UnaryMinusF64
@@ -667,8 +663,8 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ,
- ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
- getSimpleTypeDesc(p.module, e.typ)]))
+ unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8),
+ getSimpleTypeDesc(p.module, e.typ)])
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
result = p.module.compileToCpp and
@@ -677,7 +673,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
let mt = mapType(e.sons[0].typ)
- if (mt in {ctArray, ctPtrToArray} and not enforceDeref):
+ if mt in {ctArray, ctPtrToArray} and not enforceDeref:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
#if e[0].kind != nkBracketExpr:
@@ -686,19 +682,29 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
else:
var a: TLoc
initLocExprSingleUse(p, e.sons[0], a)
- let typ = skipTypes(a.t, abstractInst)
- case typ.kind
- of tyRef:
- d.s = OnHeap
- of tyVar:
- d.s = OnUnknown
- if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
- e.kind == nkHiddenDeref:
+ if d.k == locNone:
+ let typ = skipTypes(a.t, abstractInst)
+ # dest = *a; <-- We do not know that 'dest' is on the heap!
+ # It is completely wrong to set 'd.s' here, unless it's not yet
+ # been assigned to.
+ case typ.kind
+ of tyRef:
+ d.s = OnHeap
+ of tyVar:
+ d.s = OnUnknown
+ if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
+ e.kind == nkHiddenDeref:
+ putIntoDest(p, d, e.typ, rdLoc(a))
+ return
+ of tyPtr:
+ d.s = OnUnknown # BUGFIX!
+ else: internalError(e.info, "genDeref " & $a.t.kind)
+ elif p.module.compileToCpp:
+ let typ = skipTypes(a.t, abstractInst)
+ if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
+ e.kind == nkHiddenDeref:
putIntoDest(p, d, e.typ, rdLoc(a))
return
- of tyPtr:
- d.s = OnUnknown # BUGFIX!
- else: internalError(e.info, "genDeref " & $a.t.kind)
if enforceDeref and mt == ctPtrToArray:
# we lie about the type for better C interop: 'ptr array[3,T]' is
# translated to 'ptr T', but for deref'ing this produces wrong code.
@@ -707,14 +713,14 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
# so the '&' and '*' cancel out:
putIntoDest(p, d, a.t.sons[0], rdLoc(a))
else:
- putIntoDest(p, d, e.typ, ropef("(*$1)", [rdLoc(a)]))
+ putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)])
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
var a: TLoc
initLocExpr(p, e.sons[0], a)
- putIntoDest(p, d, e.typ, con("&", a.r))
+ putIntoDest(p, d, e.typ, "&" & a.r)
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
expr(p, e.sons[0], d)
@@ -747,7 +753,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
- appf(r, ".Field$1", [toRope(i)])
+ addf(r, ".Field$1", [rope(i)])
putIntoDest(p, d, ty.sons[i], r)
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
@@ -758,7 +764,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information
# so we use Field$i
- appf(r, ".Field$1", [toRope(f.position)])
+ addf(r, ".Field$1", [rope(f.position)])
putIntoDest(p, d, f.typ, r)
else:
var field: PSym = nil
@@ -767,17 +773,17 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
internalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name)
if field != nil: break
- if not p.module.compileToCpp: app(r, ".Sup")
+ if not p.module.compileToCpp: add(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
- appf(r, ".$1", [field.loc.r])
+ addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
#d.s = a.s
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
-proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
+proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
var test, u, v: TLoc
for i in countup(1, sonsLen(e) - 1):
var it = e.sons[i]
@@ -790,12 +796,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
initLoc(test, locNone, it.typ, OnStack)
initLocExpr(p, it.sons[1], u)
initLoc(v, locExpr, disc.typ, OnUnknown)
- v.r = ropef("$1.$2", [obj, disc.sym.loc.r])
+ v.r = "$1.$2" % [obj, disc.sym.loc.r]
genInExprAux(p, it, u, v, test)
let id = nodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
- else: con("TMP", toRope(id))
+ else: "TMP" & rope(id)
if op.magic == mNot:
linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@@ -811,7 +817,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
a: TLoc
f, field: PSym
ty: PType
- r: PRope
+ r: Rope
ty = genRecordFieldAux(p, e.sons[0], d, a)
r = rdLoc(a)
f = e.sons[0].sons[1].sym
@@ -820,13 +826,13 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
assert(ty.kind in {tyTuple, tyObject})
field = lookupInRecord(ty.n, f.name)
if field != nil: break
- if not p.module.compileToCpp: app(r, ".Sup")
+ if not p.module.compileToCpp: add(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genCheckedRecordField")
if field.loc.r == nil:
internalError(e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field)
- app(r, rfmt(nil, ".$1", field.loc.r))
+ add(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r)
else:
genRecordField(p, e.sons[0], d)
@@ -955,11 +961,14 @@ proc genEcho(p: BProc, n: PNode) =
# is threadsafe.
internalAssert n.kind == nkBracket
discard lists.includeStr(p.module.headerFiles, "")
- var args: PRope = nil
+ var args: Rope = nil
var a: TLoc
for i in countup(0, n.len-1):
- initLocExpr(p, n.sons[i], a)
- appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
+ if n.sons[i].skipConv.kind == nkNilLit:
+ add(args, ", \"nil\"")
+ else:
+ initLocExpr(p, n.sons[i], a)
+ addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeat("%s", n.len) & tnl), args)
@@ -986,22 +995,22 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
var a, tmp: TLoc
getTemp(p, e.typ, tmp)
var L = 0
- var appends: PRope = nil
- var lens: PRope = nil
+ var appends: Rope = nil
+ var lens: Rope = nil
for i in countup(0, sonsLen(e) - 2):
# compute the length expression:
initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L)
- app(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
+ add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal))
else:
- appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
- app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
- linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
- app(p.s(cpsStmts), appends)
+ addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+ add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
+ linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
+ add(p.s(cpsStmts), appends)
if d.k == locNone:
d = tmp
keepAlive(p, tmp)
@@ -1023,7 +1032,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# }
var
a, dest: TLoc
- appends, lens: PRope
+ appends, lens: Rope
assert(d.k == locNone)
var L = 0
initLocExpr(p, e.sons[1], dest)
@@ -1032,19 +1041,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L)
- app(appends, rfmt(p.module, "#appendChar($1, $2);$n",
+ add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
rdLoc(dest), rdLoc(a)))
else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal))
else:
- appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
- app(appends, rfmt(p.module, "#appendString($1, $2);$n",
+ addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+ add(appends, rfmt(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
- rdLoc(dest), lens, toRope(L))
+ rdLoc(dest), lens, rope(L))
keepAlive(p, dest)
- app(p.s(cpsStmts), appends)
+ add(p.s(cpsStmts), appends)
gcUsage(e)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
@@ -1074,14 +1083,14 @@ proc genReset(p: BProc, n: PNode) =
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
-proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
+proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
var sizeExpr = sizeExpr
let refType = skipTypes(a.t, abstractVarRange)
var b: TLoc
initLoc(b, locExpr, a.t, OnHeap)
if sizeExpr.isNil:
- sizeExpr = ropef("sizeof($1)",
- getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange)))
+ sizeExpr = "sizeof($1)" %
+ [getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))]
let args = [getTypeDesc(p.module, refType),
genTypeInfo(p.module, refType),
sizeExpr]
@@ -1111,7 +1120,7 @@ proc genNew(p: BProc, e: PNode) =
rawGenNew(p, a, nil)
gcUsage(e)
-proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
+proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), length]
@@ -1144,7 +1153,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
if isRef:
rawGenNew(p, tmp, nil)
t = t.lastSon.skipTypes(abstractInst)
- r = ropef("(*$1)", r)
+ r = "(*$1)" % [r]
gcUsage(e)
else:
constructLoc(p, tmp)
@@ -1158,13 +1167,13 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
while ty != nil:
field = lookupInRecord(ty.n, it.sons[0].sym.name)
if field != nil: break
- if not p.module.compileToCpp: app(tmp2.r, ".Sup")
+ if not p.module.compileToCpp: add(tmp2.r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options:
genFieldCheck(p, it.sons[2], tmp2.r, field)
- app(tmp2.r, ".")
- app(tmp2.r, field.loc.r)
+ add(tmp2.r, ".")
+ add(tmp2.r, field.loc.r)
tmp2.k = locTemp
tmp2.t = field.loc.t
tmp2.s = if isRef: OnHeap else: OnStack
@@ -1214,14 +1223,14 @@ proc genNewFinalize(p: BProc, e: PNode) =
var
a, b, f: TLoc
refType, bt: PType
- ti: PRope
+ ti: Rope
oldModule: BModule
refType = skipTypes(e.sons[1].typ, abstractVarRange)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], f)
initLoc(b, locExpr, a.t, OnHeap)
ti = genTypeInfo(p.module, refType)
- appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
+ addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
@@ -1230,18 +1239,18 @@ proc genNewFinalize(p: BProc, e: PNode) =
genObjectInit(p, cpsStmts, bt, a, false)
gcUsage(e)
-proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope =
+proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first:
let ti = genTypeInfo(p.module, dest)
if tfFinal in dest.flags or (p.module.objHasKidsValid and
tfObjHasKids notin dest.flags):
- result = ropef("$1.m_type == $2", a, ti)
+ result = "$1.m_type == $2" % [a, ti]
else:
discard cgsym(p.module, "TNimType")
inc p.module.labels
- let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope)
- appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache)
+ let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
+ addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
when false:
# former version:
@@ -1253,7 +1262,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
initLocExpr(p, x, a)
var dest = skipTypes(typ, typedescPtrs)
var r = rdLoc(a)
- var nilCheck: PRope = nil
+ var nilCheck: Rope = nil
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
@@ -1262,7 +1271,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
t = skipTypes(t.lastSon, typedescInst)
if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
- app(r, ~".Sup")
+ add(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst)
if isObjLackingTypeField(t):
globalError(x.info, errGenerated,
@@ -1303,13 +1312,13 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
var b: TLoc
case a.t.kind
of tyOpenArray, tyVarargs:
- putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
+ putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)])
of tyString, tySequence:
putIntoDest(p, b, e.typ,
- ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
+ "$1->data, $1->$2" % [rdLoc(a), lenField(p)])
of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ,
- ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
+ "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))])
else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
@@ -1346,19 +1355,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: unaryExpr(p, e, d, "$1Len0")
of tyCString:
useStringh(p.module)
- if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
- else: unaryExpr(p, e, d, "strlen($1)")
+ if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)")
+ else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)")
of tyString, tySequence:
if not p.module.compileToCpp:
- if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
- else: unaryExpr(p, e, d, "$1->Sup.len")
+ if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
+ else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
else:
- if op == mHigh: unaryExpr(p, e, d, "($1->len-1)")
- else: unaryExpr(p, e, d, "$1->len")
+ if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
+ else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
of tyArray, tyArrayConstr:
# YYY: length(sideeffect) is optimized away incorrectly?
- if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(typ)))
- else: putIntoDest(p, d, e.typ, toRope(lengthOrd(typ)))
+ if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
+ else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ)))
else: internalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
@@ -1396,13 +1405,13 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
genAssignment(p, a, b, {})
genAssignment(p, b, tmp, {})
-proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
+proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
# read a location of an set element; it may need a subtraction operation
# before the set operation
result = rdCharLoc(a)
assert(setType.kind == tySet)
if firstOrd(setType) != 0:
- result = ropef("($1- $2)", [result, toRope(firstOrd(setType))])
+ result = "($1- $2)" % [result, rope(firstOrd(setType))]
proc fewCmps(s: PNode): bool =
# this function estimates whether it is better to emit code
@@ -1416,7 +1425,7 @@ proc fewCmps(s: PNode): bool =
result = sonsLen(s) <= 8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
- putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]))
+ putIntoDest(p, d, e.typ, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
@@ -1446,19 +1455,19 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
e.sons[2]
initLocExpr(p, ea, a)
initLoc(b, locExpr, e.typ, OnUnknown)
- b.r = toRope("(")
+ b.r = rope("(")
var length = sonsLen(e.sons[1])
for i in countup(0, length - 1):
if e.sons[1].sons[i].kind == nkRange:
initLocExpr(p, e.sons[1].sons[i].sons[0], x)
initLocExpr(p, e.sons[1].sons[i].sons[1], y)
- appf(b.r, "$1 >= $2 && $1 <= $3",
+ addf(b.r, "$1 >= $2 && $1 <= $3",
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
else:
initLocExpr(p, e.sons[1].sons[i], x)
- appf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
- if i < length - 1: app(b.r, " || ")
- app(b.r, ")")
+ addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
+ if i < length - 1: add(b.r, " || ")
+ add(b.r, ")")
putIntoDest(p, d, e.typ, b.r)
else:
assert(e.sons[1].typ != nil)
@@ -1514,7 +1523,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, getSysType(tyBool), d)
lineF(p, cpsStmts, lookupOpr[op],
- [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
+ [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet:
useStringh(p.module)
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
@@ -1527,8 +1536,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
lineF(p, cpsStmts,
"for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [
- rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
- toRope(lookupOpr[op])])
+ rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
+ rope(lookupOpr[op])])
of mInSet: genInOp(p, e, d)
else: internalError(e.info, "genSetOp")
@@ -1545,14 +1554,14 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a)
let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
- putIntoDest(p, d, e.typ, ropef("(*($1*) ($2))",
- [getTypeDesc(p.module, e.typ), addrLoc(a)]))
+ putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
+ [getTypeDesc(p.module, e.typ), addrLoc(a)])
elif etyp.kind == tyProc and etyp.callConv == ccClosure:
- putIntoDest(p, d, e.typ, ropef("(($1) ($2))",
- [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)]))
+ putIntoDest(p, d, e.typ, "(($1) ($2))" %
+ [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])
else:
- putIntoDest(p, d, e.typ, ropef("(($1) ($2))",
- [getTypeDesc(p.module, e.typ), rdCharLoc(a)]))
+ putIntoDest(p, d, e.typ, "(($1) ($2))" %
+ [getTypeDesc(p.module, e.typ), rdCharLoc(a)])
proc genCast(p: BProc, e: PNode, d: var TLoc) =
const floatTypes = {tyFloat..tyFloat128}
@@ -1562,9 +1571,9 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
if destt.kind in floatTypes or srct.kind in floatTypes:
# 'cast' and some float type involved? --> use a union.
inc(p.labels)
- var lbl = p.labels.toRope
+ var lbl = p.labels.rope
var tmp: TLoc
- tmp.r = ropef("LOC$1.source", lbl)
+ tmp.r = "LOC$1.source" % [lbl]
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
tmp.k = locExpr
@@ -1572,7 +1581,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
tmp.s = OnStack
tmp.flags = {}
expr(p, e.sons[1], tmp)
- putIntoDest(p, d, e.typ, ropef("LOC$#.dest", lbl))
+ putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl])
else:
# I prefer the shorter cast version for pointer types -> generate less
# C code; plus it's the right thing to do for closures:
@@ -1584,16 +1593,14 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
# range checks for unsigned turned out to be buggy and annoying:
if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
initLocExpr(p, n.sons[0], a)
- putIntoDest(p, d, n.typ, ropef("(($1) ($2))",
- [getTypeDesc(p.module, dest), rdCharLoc(a)]))
+ putIntoDest(p, d, n.typ, "(($1) ($2))" %
+ [getTypeDesc(p.module, dest), rdCharLoc(a)])
else:
initLocExpr(p, n.sons[0], a)
- if leValue(n.sons[2], n.sons[1]):
- internalError(n.info, "range check will always fail; empty range")
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
- toRope(magic)]))
+ rope(magic)]))
proc genConv(p: BProc, e: PNode, d: var TLoc) =
let destType = e.typ.skipTypes({tyVar, tyGenericInst})
@@ -1605,8 +1612,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
- putIntoDest(p, d, skipTypes(n.typ, abstractVar), ropef("$1->data",
- [rdLoc(a)]))
+ putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)])
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
@@ -1641,7 +1647,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
- toRope(opr[m]), rdLoc(a), rdLoc(b),
+ rope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ)))
if optNaNCheck in p.options:
linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
@@ -1651,7 +1657,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
binaryArith(p, e, d, m)
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
- var line, filen: PRope
+ var line, filen: Rope
case op
of mOr, mAnd: genAndOr(p, e, d, op)
of mNot..mToBiggestInt: unaryArith(p, e, d, op)
@@ -1672,7 +1678,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"$# = #subInt64($#, $#);$n"]
const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
"$# = #subInt($#, $#);$n"]
- if optOverflowCheck notin p.options:
+ let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
+ if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
binaryStmt(p, e, d, opr[op])
else:
var a, b: TLoc
@@ -1681,12 +1688,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
- let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar})
let res = binaryArithOverflowRaw(p, ranged, a, b,
if underlying.kind == tyInt64: fun64[op] else: fun[op])
- putIntoDest(p, a, ranged, ropef("($#)($#)", [
- getTypeDesc(p.module, ranged), res]))
+ putIntoDest(p, a, ranged, "($#)($#)" % [
+ getTypeDesc(p.module, ranged), res])
of mConStrStr: genStrConcat(p, e, d)
of mAppendStrCh:
@@ -1713,12 +1719,16 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNewSeq: genNewSeq(p, e)
of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
- putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))",
- [getTypeDesc(p.module, t)]))
+ putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
of mChr: genSomeCast(p, e, d)
of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
genArrayLen(p, e, d, op)
+ of mXLenStr, mXLenSeq:
+ if not p.module.compileToCpp:
+ unaryExpr(p, e, d, "($1->Sup.len-1)")
+ else:
+ unaryExpr(p, e, d, "$1->len")
of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
of mSetLengthStr: genSetLengthStr(p, e, d)
@@ -1730,7 +1740,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
mParseBiggestFloat:
var opr = e.sons[0].sym
if lfNoDecl notin opr.loc.flags:
- discard cgsym(p.module, opr.loc.r.ropeToStr)
+ discard cgsym(p.module, $opr.loc.r)
genCall(p, e, d)
of mReset: genReset(p, e)
of mEcho: genEcho(p, e[1].skipConv)
@@ -1752,17 +1762,17 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mDotDot: genCall(p, e, d)
else: internalError(e.info, "genMagicExpr: " & $op)
-proc genConstExpr(p: BProc, n: PNode): PRope
+proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
- fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap)
+ fillLoc(d, locData, t, "TMP" & rope(id), OnHeap)
if id == gBackendId:
# expression not found in the cache:
inc(gBackendId)
- appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+ addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true
else:
@@ -1824,13 +1834,12 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1]
initLoc(rec, locExpr, it.typ, d.s)
- rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
+ rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
expr(p, it, rec)
when false:
initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
- rec.r = ropef("$1.$2",
- [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
+ rec.r = "$1.$2" % [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]
expr(p, it, rec)
proc isConstClosure(n: PNode): bool {.inline.} =
@@ -1842,8 +1851,8 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
if isConstClosure(n):
inc(p.labels)
- var tmp = con("LOC", toRope(p.labels))
- appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+ var tmp = "LOC" & rope(p.labels)
+ addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
putIntoDest(p, d, n.typ, tmp)
else:
@@ -1861,7 +1870,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, n.typ, d)
for i in countup(0, sonsLen(n) - 1):
initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
- arr.r = ropef("$1[$2]", [rdLoc(d), intLiteral(i)])
+ arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
expr(p, n.sons[i], arr)
proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
@@ -1880,16 +1889,16 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
var dest = skipTypes(n.typ, abstractPtrs)
if optObjCheck in p.options and not isObjLackingTypeField(dest):
var r = rdLoc(a)
- var nilCheck: PRope = nil
+ var nilCheck: Rope = nil
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
if t.kind != tyVar or not p.module.compileToCpp:
- r = ropef("(*$1)", [r])
+ r = "(*$1)" % [r]
t = skipTypes(t.lastSon, abstractInst)
if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
- app(r, ".Sup")
+ add(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst)
if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
@@ -1899,10 +1908,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
r, genTypeInfo(p.module, dest))
if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ,
- ropef("(($1) ($2))", [getTypeDesc(p.module, n.typ), rdLoc(a)]))
+ "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)])
else:
- putIntoDest(p, d, n.typ, ropef("(*($1*) ($2))",
- [getTypeDesc(p.module, dest), addrLoc(a)]))
+ putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
+ [getTypeDesc(p.module, dest), addrLoc(a)])
proc downConv(p: BProc, n: PNode, d: var TLoc) =
if p.module.compileToCpp:
@@ -1919,10 +1928,10 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
var r = rdLoc(a)
let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
if isRef:
- app(r, "->Sup")
+ add(r, "->Sup")
else:
- app(r, ".Sup")
- for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
+ add(r, ".Sup")
+ for i in countup(2, abs(inheritanceDiff(dest, src))): add(r, ".Sup")
if isRef:
# it can happen that we end up generating '&&x->Sup' here, so we pack
# the '&x->Sup' into a temporary and then those address is taken
@@ -1933,7 +1942,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
getTemp(p, n.typ, d)
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
else:
- r = con("&", r)
+ r = "&" & r
putIntoDest(p, d, n.typ, r)
else:
putIntoDest(p, d, n.typ, r)
@@ -1942,12 +1951,12 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
- var tmp = con("TMP", toRope(id))
+ var tmp = "TMP" & rope(id)
if id == gBackendId:
# expression not found in the cache:
inc(gBackendId)
- appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+ addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
if d.k == locNone:
@@ -1982,7 +1991,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else:
genComplexConst(p, sym, d)
of skEnumField:
- putIntoDest(p, d, n.typ, toRope(sym.position))
+ putIntoDest(p, d, n.typ, rope(sym.position))
of skVar, skForVar, skResult, skLet:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
@@ -1991,7 +2000,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
if emulatedThreadVars():
- putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
+ putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
else:
putLocIntoDest(p, d, sym.loc)
else:
@@ -2134,42 +2143,42 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkBreakState: genBreakState(p, n)
else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
-proc genNamedConstExpr(p: BProc, n: PNode): PRope =
+proc genNamedConstExpr(p: BProc, n: PNode): Rope =
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
else: result = genConstExpr(p, n)
-proc genConstSimpleList(p: BProc, n: PNode): PRope =
+proc genConstSimpleList(p: BProc, n: PNode): Rope =
var length = sonsLen(n)
- result = toRope("{")
+ result = rope("{")
for i in countup(0, length - 2):
- appf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
- if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1]))
- appf(result, "}$n")
+ addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
+ if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
+ addf(result, "}$n", [])
-proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
- var data = ropef("{{$1, $1}", n.len.toRope)
+proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
+ var data = "{{$1, $1}" % [n.len.rope]
if n.len > 0:
# array part needs extra curlies:
- data.app(", {")
+ data.add(", {")
for i in countup(0, n.len - 1):
- if i > 0: data.appf(",$n")
- data.app genConstExpr(p, n.sons[i])
- data.app("}")
- data.app("}")
+ if i > 0: data.addf(",$n", [])
+ data.add genConstExpr(p, n.sons[i])
+ data.add("}")
+ data.add("}")
inc(gBackendId)
- result = con("CNSTSEQ", gBackendId.toRope)
+ result = "CNSTSEQ" & gBackendId.rope
appcg(p.module, cfsData,
"NIM_CONST struct {$n" &
" #TGenericSeq Sup;$n" &
" $1 data[$2];$n" &
"} $3 = $4;$n", [
- getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data])
+ getTypeDesc(p.module, t.sons[0]), n.len.rope, result, data])
- result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result])
+ result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
-proc genConstExpr(p: BProc, n: PNode): PRope =
+proc genConstExpr(p: BProc, n: PNode): Rope =
case n.kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genConstExpr(p, n.sons[1])
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index 5057b9ff1d..2a37257b6c 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -45,29 +45,29 @@ const
]
NimMergeEndMark = "/*\tNIM_merge_END:*/"
-proc genSectionStart*(fs: TCFileSection): PRope =
+proc genSectionStart*(fs: TCFileSection): Rope =
if compilationCachePresent:
- result = toRope(tnl)
- app(result, "/*\t")
- app(result, CFileSectionNames[fs])
- app(result, ":*/")
- app(result, tnl)
+ result = rope(tnl)
+ add(result, "/*\t")
+ add(result, CFileSectionNames[fs])
+ add(result, ":*/")
+ add(result, tnl)
-proc genSectionEnd*(fs: TCFileSection): PRope =
+proc genSectionEnd*(fs: TCFileSection): Rope =
if compilationCachePresent:
- result = toRope(NimMergeEndMark & tnl)
+ result = rope(NimMergeEndMark & tnl)
-proc genSectionStart*(ps: TCProcSection): PRope =
+proc genSectionStart*(ps: TCProcSection): Rope =
if compilationCachePresent:
- result = toRope(tnl)
- app(result, "/*\t")
- app(result, CProcSectionNames[ps])
- app(result, ":*/")
- app(result, tnl)
+ result = rope(tnl)
+ add(result, "/*\t")
+ add(result, CProcSectionNames[ps])
+ add(result, ":*/")
+ add(result, tnl)
-proc genSectionEnd*(ps: TCProcSection): PRope =
+proc genSectionEnd*(ps: TCProcSection): Rope =
if compilationCachePresent:
- result = toRope(NimMergeEndMark & tnl)
+ result = rope(NimMergeEndMark & tnl)
proc writeTypeCache(a: TIdTable, s: var string) =
var i = 0
@@ -79,7 +79,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
s.add(' ')
encodeVInt(id, s)
s.add(':')
- encodeStr(PRope(value).ropeToStr, s)
+ encodeStr($Rope(value), s)
inc i
s.add('}')
@@ -95,7 +95,7 @@ proc writeIntSet(a: IntSet, s: var string) =
inc i
s.add('}')
-proc genMergeInfo*(m: BModule): PRope =
+proc genMergeInfo*(m: BModule): Rope =
if optSymbolFiles notin gGlobalOptions: return nil
var s = "/*\tNIM_merge_INFO:"
s.add(tnl)
@@ -111,7 +111,7 @@ proc genMergeInfo*(m: BModule): PRope =
encodeVInt(ord(m.frameDeclared), s)
s.add(tnl)
s.add("*/")
- result = s.toRope
+ result = s.rope
template `^`(pos: int): expr = L.buf[pos]
@@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len
-proc readVerbatimSection(L: var TBaseLexer): PRope =
+proc readVerbatimSection(L: var TBaseLexer): Rope =
var pos = L.bufpos
var buf = L.buf
var r = newStringOfCap(30_000)
@@ -169,7 +169,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
r.add(buf[pos])
inc pos
L.bufpos = pos
- result = r.toRope
+ result = r.rope
proc readKey(L: var TBaseLexer, result: var string) =
var pos = L.bufpos
@@ -197,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
# XXX little hack: we create a "fake" type object with the correct Id
# better would be to adapt the data structure to not even store the
# object as key, but only the Id
- idTablePut(result, newFakeType(key), value.toRope)
+ idTablePut(result, newFakeType(key), value.rope)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
@@ -280,11 +280,11 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
if m.s[i] != nil:
- #echo "not empty: ", i, " ", ropeToStr(m.s[i])
+ #echo "not empty: ", i, " ", m.s[i]
return true
for i in low(TCProcSection)..high(TCProcSection):
if m.initProc.s(i) != nil:
- #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
+ #echo "not empty: ", i, " ", m.initProc.s[i]
return true
proc mergeFiles*(cfilename: string, m: BModule) =
@@ -293,6 +293,6 @@ proc mergeFiles*(cfilename: string, m: BModule) =
readMergeSections(cfilename, old)
# do the merge; old section before new section:
for i in low(TCFileSection)..high(TCFileSection):
- m.s[i] = con(old.f[i], m.s[i])
+ m.s[i] = old.f[i] & m.s[i]
for i in low(TCProcSection)..high(TCProcSection):
- m.initProc.s(i) = con(old.p[i], m.initProc.s(i))
+ m.initProc.s(i) = old.p[i] & m.initProc.s(i)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 0cf4529854..6d29b16847 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -61,11 +61,10 @@ proc genVarTuple(p: BProc, n: PNode) =
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
initLoc(field, locExpr, t.sons[i], tup.s)
if t.kind == tyTuple:
- field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
+ field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
- field.r = ropef("$1.$2",
- [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
+ field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
putLocIntoDest(p, v.loc, field)
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
@@ -86,8 +85,8 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
else:
expr(p, ri, a)
-proc startBlock(p: BProc, start: TFormatStr = "{$n",
- args: varargs[PRope]): int {.discardable.} =
+proc startBlock(p: BProc, start: FormatStr = "{$n",
+ args: varargs[Rope]): int {.discardable.} =
lineCg(p, cpsStmts, start, args)
inc(p.labels)
result = len(p.blocks)
@@ -96,21 +95,21 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
-proc assignLabel(b: var TBlock): PRope {.inline.} =
- b.label = con("LA", b.id.toRope)
+proc assignLabel(b: var TBlock): Rope {.inline.} =
+ b.label = "LA" & b.id.rope
result = b.label
-proc blockBody(b: var TBlock): PRope =
+proc blockBody(b: var TBlock): Rope =
result = b.sections[cpsLocals]
if b.frameLen > 0:
- result.appf("F.len+=$1;$n", b.frameLen.toRope)
- result.app(b.sections[cpsInit])
- result.app(b.sections[cpsStmts])
+ result.addf("F.len+=$1;$n", [b.frameLen.rope])
+ result.add(b.sections[cpsInit])
+ result.add(b.sections[cpsStmts])
-proc endBlock(p: BProc, blockEnd: PRope) =
+proc endBlock(p: BProc, blockEnd: Rope) =
let topBlock = p.blocks.len-1
# the block is merged into the parent block
- app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
+ add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
setLen(p.blocks, topBlock)
# this is done after the block is popped so $n is
# properly indented when pretty printing is enabled
@@ -124,7 +123,7 @@ proc endBlock(p: BProc) =
~"}$n"
let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0:
- blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
+ blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@@ -145,7 +144,7 @@ template preserveBreakIdx(body: stmt): stmt {.immediate.} =
proc genState(p: BProc, n: PNode) =
internalAssert n.len == 1 and n.sons[0].kind == nkIntLit
let idx = n.sons[0].intVal
- linefmt(p, cpsStmts, "STATE$1: ;$n", idx.toRope)
+ linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope)
proc genGotoState(p: BProc, n: PNode) =
# we resist the temptation to translate it into duff's device as it later
@@ -159,7 +158,7 @@ proc genGotoState(p: BProc, n: PNode) =
p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
for i in 0 .. lastOrd(n.sons[0].typ):
- lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
+ lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
lineF(p, cpsStmts, "}$n", [])
proc genBreakState(p: BProc, n: PNode) =
@@ -176,9 +175,18 @@ proc genBreakState(p: BProc, n: PNode) =
proc genVarPrototypeAux(m: BModule, sym: PSym)
+proc genGotoVar(p: BProc; value: PNode) =
+ if value.kind notin {nkCharLit..nkUInt64Lit}:
+ localError(value.info, "'goto' target must be a literal value")
+ else:
+ lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
+
proc genSingleVar(p: BProc, a: PNode) =
var v = a.sons[0].sym
- if sfCompileTime in v.flags: return
+ if {sfCompileTime, sfGoto} * v.flags != {}:
+ # translate 'var state {.goto.} = X' into 'goto LX':
+ if sfGoto in v.flags: genGotoVar(p, a.sons[2])
+ return
var targetProc = p
if sfGlobal in v.flags:
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
@@ -214,17 +222,17 @@ proc genSingleVar(p: BProc, a: PNode) =
var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
- var params: PRope
+ var params: Rope
let typ = skipTypes(value.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1.. 0:
@@ -560,7 +576,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
linefmt(p, cpsStmts, "#reraiseException();$n")
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
- rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
+ rangeFormat, eqFormat: FormatStr, labl: TLabel) =
var
x, y: TLoc
var length = sonsLen(b)
@@ -578,7 +594,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel =
var lend = getLabel(p)
for i in 1..until:
- lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
+ lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d)
@@ -588,7 +604,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
result = lend
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
- rangeFormat, eqFormat: TFormatStr,
+ rangeFormat, eqFormat: FormatStr,
until: int, a: TLoc): TLabel =
# generate a C-if statement for a Nim case statement
var labId = p.labels
@@ -596,27 +612,27 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
inc(p.labels)
if t.sons[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
- con("LA", toRope(p.labels)))
+ "LA" & rope(p.labels))
else:
- lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
+ lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
if until < t.len-1:
inc(p.labels)
var gotoTarget = p.labels
- lineF(p, cpsStmts, "goto LA$1;$n", [toRope(gotoTarget)])
+ lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
result = genCaseSecondPass(p, t, d, labId, until)
- lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)])
+ lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
else:
result = genCaseSecondPass(p, t, d, labId, until)
proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
- rangeFormat, eqFormat: TFormatStr) =
+ rangeFormat, eqFormat: FormatStr) =
var a: TLoc
initLocExpr(p, t.sons[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
- branches: var openArray[PRope]) =
+ branches: var openArray[Rope]) =
var x: TLoc
var length = sonsLen(b)
for i in countup(0, length - 2):
@@ -634,7 +650,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
if strings > stringCaseThreshold:
var bitMask = math.nextPowerOfTwo(strings) - 1
- var branches: seq[PRope]
+ var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
@@ -642,21 +658,21 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
for i in countup(1, sonsLen(t) - 1):
inc(p.labels)
if t.sons[i].kind == nkOfBranch:
- genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)),
+ genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
branches)
else:
# else statement: nothing to do yet
# but we reserved a label, which we use later
discard
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
- rdLoc(a), toRope(bitMask))
+ rdLoc(a), rope(bitMask))
for j in countup(0, high(branches)):
if branches[j] != nil:
lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]])
- lineF(p, cpsStmts, "}$n") # else statement:
+ lineF(p, cpsStmts, "}$n", []) # else statement:
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
- lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
+ lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
# third pass: generate statements
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend)
@@ -718,13 +734,13 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
genCaseRange(p, branch)
else:
# else part of case statement:
- lineF(p, cpsStmts, "default:$n")
+ lineF(p, cpsStmts, "default:$n", [])
hasDefault = true
exprBlock(p, branch.lastSon, d)
- lineF(p, cpsStmts, "break;$n")
+ lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[cCompiler].props) and not hasDefault:
- lineF(p, cpsStmts, "default: __assume(0);$n")
- lineF(p, cpsStmts, "}$n")
+ lineF(p, cpsStmts, "default: __assume(0);$n", [])
+ lineF(p, cpsStmts, "}$n", [])
if lend != nil: fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) =
@@ -738,7 +754,10 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
else:
- genOrdinalCase(p, t, d)
+ if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
+ genGotoForCase(p, t)
+ else:
+ genOrdinalCase(p, t, d)
proc hasGeneralExceptSection(t: PNode): bool =
var length = sonsLen(t)
@@ -773,11 +792,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# finallyPart();
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
- var
- exc: PRope
- i, length, blen: int
genLineDir(p, t)
- exc = getTempName()
+ let exc = getTempName()
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
@@ -785,36 +801,42 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
add(p.nestedTryStmts, t)
startBlock(p, "try {$n")
expr(p, t.sons[0], d)
- length = sonsLen(t)
+ let length = sonsLen(t)
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
if optStackTrace in p.options:
- linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
+ linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
inc p.inExceptBlock
- i = 1
+ var i = 1
var catchAllPresent = false
while (i < length) and (t.sons[i].kind == nkExceptBranch):
- blen = sonsLen(t.sons[i])
- if i > 1: appf(p.s(cpsStmts), "else ")
+ let blen = sonsLen(t.sons[i])
+ if i > 1: addf(p.s(cpsStmts), "else ", [])
if blen == 1:
# general except section:
catchAllPresent = true
- exprBlock(p, t.sons[i].sons[0], d)
+ startBlock(p)
+ expr(p, t.sons[i].sons[0], d)
+ linefmt(p, cpsStmts, "#popCurrentException();$n")
+ endBlock(p)
else:
- var orExpr: PRope = nil
+ var orExpr: Rope = nil
for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType)
- if orExpr != nil: app(orExpr, "||")
+ if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr,
"#isObj($1.exp->m_type, $2)",
[exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
lineF(p, cpsStmts, "if ($1) ", [orExpr])
- exprBlock(p, t.sons[i].sons[blen-1], d)
+ startBlock(p)
+ expr(p, t.sons[i].sons[blen-1], d)
+ linefmt(p, cpsStmts, "#popCurrentException();$n")
+ endBlock(p)
inc(i)
# reraise the exception if there was no catch all
# and none of the handlers matched
if not catchAllPresent:
- if i > 1: lineF(p, cpsStmts, "else ")
+ if i > 1: lineF(p, cpsStmts, "else ", [])
startBlock(p)
var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally:
@@ -824,7 +846,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
line(p, cpsStmts, ~"throw;$n")
endBlock(p)
- lineF(p, cpsStmts, "}$n") # end of catch block
+ lineF(p, cpsStmts, "}$n", []) # end of catch block
dec p.inExceptBlock
discard pop(p.nestedTryStmts)
@@ -888,24 +910,24 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
startBlock(p, "else {$n")
linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.options:
- linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
+ linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
inc p.inExceptBlock
var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch):
var blen = sonsLen(t.sons[i])
if blen == 1:
# general except section:
- if i > 1: lineF(p, cpsStmts, "else")
+ if i > 1: lineF(p, cpsStmts, "else", [])
startBlock(p)
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
expr(p, t.sons[i].sons[0], d)
linefmt(p, cpsStmts, "#popCurrentException();$n")
endBlock(p)
else:
- var orExpr: PRope = nil
+ var orExpr: Rope = nil
for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType)
- if orExpr != nil: app(orExpr, "||")
+ if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)",
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
@@ -925,7 +947,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
-proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
+proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
var res = ""
for i in countup(0, sonsLen(t) - 1):
case t.sons[i].kind
@@ -936,7 +958,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
var a: TLoc
initLocExpr(p, t.sons[i], a)
- res.add(rdLoc(a).ropeToStr)
+ res.add($rdLoc(a))
else:
var r = sym.loc.r
if r == nil:
@@ -944,7 +966,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
# it doesn't matter much:
r = mangleName(sym)
sym.loc.r = r # but be consequent!
- res.add(r.ropeToStr)
+ res.add($r)
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
@@ -954,15 +976,15 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or
# some clobber register list:
- app(result, x); app(result, tnl)
+ add(result, x); add(result, tnl)
elif x[j] != '\0':
# ignore empty lines
- app(result, "\"")
- app(result, x)
- app(result, "\\n\"\n")
+ add(result, "\"")
+ add(result, x)
+ add(result, "\\n\"\n")
else:
res.add(tnl)
- result = res.toRope
+ result = res.rope
proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
@@ -973,23 +995,30 @@ proc genAsmStmt(p: BProc, t: PNode) =
# work:
if p.prc == nil:
# top level asm statement?
- appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
+ addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
else:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
+proc determineSection(n: PNode): TCFileSection =
+ result = cfsProcHeaders
+ if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
+ if n.sons[0].strVal.startsWith("/*TYPESECTION*/"): result = cfsTypes
+ elif n.sons[0].strVal.startsWith("/*VARSECTION*/"): result = cfsVars
+
proc genEmit(p: BProc, t: PNode) =
var s = genAsmOrEmitStmt(p, t.sons[1])
if p.prc == nil:
# top level emit pragma?
- genCLineDir(p.module.s[cfsProcHeaders], t.info)
- app(p.module.s[cfsProcHeaders], s)
+ let section = determineSection(t[1])
+ genCLineDir(p.module.s[section], t.info)
+ add(p.module.s[section], s)
else:
genLineDir(p, t)
line(p, cpsStmts, s)
var
breakPointId: int = 0
- gBreakpoints: PRope # later the breakpoints are inserted into the main proc
+ gBreakpoints: Rope # later the breakpoints are inserted into the main proc
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
@@ -1003,7 +1032,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
genLineDir(p, t) # BUGFIX
appcg(p.module, gBreakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
- toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
+ rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) =
@@ -1066,7 +1095,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
- if not fieldDiscriminantCheckNeeded(p, e):
+ if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
+ genGotoVar(p, e.sons[1])
+ elif not fieldDiscriminantCheckNeeded(p, e):
var a: TLoc
initLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy)
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index c24dd5c412..d741c47a9f 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
-## Thread var support for crappy architectures that lack native support for
+## Thread var support for crappy architectures that lack native support for
## thread local storage. (**Thank you Mac OS X!**)
# included from cgen.nim
@@ -19,12 +19,12 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
p.module.usesThreadVars = true
- appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
- app(p.procSec(cpsInit),
+ addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
+ add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
-
+
var
- nimtv: PRope # nimrod thread vars; the struct body
+ nimtv: Rope # nimrod thread vars; the struct body
nimtvDeps: seq[PType] = @[] # type deps: every module needs whole struct
nimtvDeclared = initIntSet() # so that every var/field exists only once
# in the struct
@@ -43,23 +43,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
# allocator for it :-(
if not containsOrIncl(nimtvDeclared, s.id):
nimtvDeps.add(s.loc.t)
- appf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
+ addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else:
- if isExtern: app(m.s[cfsVars], "extern ")
- if optThreads in gGlobalOptions: app(m.s[cfsVars], "NIM_THREADVAR ")
- app(m.s[cfsVars], getTypeDesc(m, s.loc.t))
- appf(m.s[cfsVars], " $1;$n", [s.loc.r])
-
+ if isExtern: add(m.s[cfsVars], "extern ")
+ if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
+ add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
+ addf(m.s[cfsVars], " $1;$n", [s.loc.r])
+
proc generateThreadLocalStorage(m: BModule) =
if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
for t in items(nimtvDeps): discard getTypeDesc(m, t)
- appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
+ addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
let externc = if gCmd != cmdCompileToCpp and
sfCompileToCpp in m.module.flags: "extern \"C\""
else: ""
- appf(m.s[cfsProcs],
+ addf(m.s[cfsProcs],
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
- [externc.toRope])
+ [externc.rope])
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 8bb8202839..5f59702e55 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -17,11 +17,11 @@ type
p: BProc
visitorFrmt: string
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode) =
if n == nil: return
case n.kind
of nkRecList:
@@ -31,31 +31,31 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
- lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
+ lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch)
else:
- lineF(p, cpsStmts, "default:$n")
+ lineF(p, cpsStmts, "default:$n", [])
genTraverseProc(c, accessor, lastSon(branch))
- lineF(p, cpsStmts, "break;$n")
- lineF(p, cpsStmts, "} $n")
+ lineF(p, cpsStmts, "break;$n", [])
+ lineF(p, cpsStmts, "} $n", [])
of nkSym:
let field = n.sym
if field.loc.t == nil:
internalError(n.info, "genTraverseProc()")
- genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
+ genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(n.info, "genTraverseProc()")
-proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
+proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
if not m.compileToCpp:
- result = ropef("$1.Sup", accessor)
+ result = "$1.Sup" % [accessor]
else:
result = accessor
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
if typ == nil: return
var p = c.p
case typ.kind
@@ -66,9 +66,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var i: TLoc
getTemp(p, getSysType(tyInt), i)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
- i.r, arraySize.toRope)
+ i.r, arraySize.rope)
genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
- lineF(p, cpsStmts, "}$n")
+ lineF(p, cpsStmts, "}$n", [])
of tyObject:
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
@@ -76,7 +76,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
of tyTuple:
let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1):
- genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
+ genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
of tyRef, tyString, tySequence:
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
of tyProc:
@@ -85,67 +85,67 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
else:
discard
-proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
+proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
- assert typ.kind == tySequence
+ assert typ.kind == tySequence
var i: TLoc
getTemp(p, getSysType(tyInt), i)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
- i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
- genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
- lineF(p, cpsStmts, "}$n")
-
-proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
+ [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
+ genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
+ lineF(p, cpsStmts, "}$n", [])
+
+proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = getGlobalTempName()
-
+
case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
else: assert false
-
- let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
-
+
+ let header = "N_NIMCALL(void, $1)(void* p, NI op)" % [result]
+
let t = getTypeDesc(m, typ)
- lineF(p, cpsLocals, "$1 a;$n", t)
- lineF(p, cpsInit, "a = ($1)p;$n", t)
-
+ lineF(p, cpsLocals, "$1 a;$n", [t])
+ lineF(p, cpsInit, "a = ($1)p;$n", [t])
+
c.p = p
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
- genTraverseProcSeq(c, "a".toRope, typ)
+ genTraverseProcSeq(c, "a".rope, typ)
else:
if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
# C's arrays are broken beyond repair:
- genTraverseProc(c, "a".toRope, typ.sons[0])
+ genTraverseProc(c, "a".rope, typ.sons[0])
else:
- genTraverseProc(c, "(*a)".toRope, typ.sons[0])
-
- let generatedProc = ropef("$1 {$n$2$3$4}$n",
- [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
-
- m.s[cfsProcHeaders].appf("$1;$n", header)
- m.s[cfsProcs].app(generatedProc)
+ genTraverseProc(c, "(*a)".rope, typ.sons[0])
-proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
+ let generatedProc = "$1 {$n$2$3$4}$n" %
+ [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+ m.s[cfsProcHeaders].addf("$1;$n", [header])
+ m.s[cfsProcs].add(generatedProc)
+
+proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
discard genTypeInfo(m, s.loc.t)
-
+
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = s.loc.r
result = getGlobalTempName()
-
+
if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)
- sLoc = con("NimTV->", sLoc)
-
+ sLoc = "NimTV->" & sLoc
+
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p
- let header = ropef("N_NIMCALL(void, $1)()", result)
+ let header = "N_NIMCALL(void, $1)()" % [result]
genTraverseProc(c, sLoc, s.loc.t)
-
- let generatedProc = ropef("$1 {$n$2$3$4}$n",
- [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
-
- m.s[cfsProcHeaders].appf("$1;$n", header)
- m.s[cfsProcs].app(generatedProc)
+
+ let generatedProc = "$1 {$n$2$3$4}$n" %
+ [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+ m.s[cfsProcHeaders].addf("$1;$n", [header])
+ m.s[cfsProcs].add(generatedProc)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 086aeb966f..3742fd2fd0 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -11,21 +11,22 @@
# ------------------------- Name Mangling --------------------------------
-proc mangleField(name: string): string =
- result = mangle(name)
- result[0] = result[0].toUpper # Mangling makes everything lowercase,
- # but some identifiers are C keywords
-
proc isKeyword(w: PIdent): bool =
- # nimrod and C++ share some keywords
- # it's more efficient to test the whole nimrod keywords range
+ # Nim and C++ share some keywords
+ # it's more efficient to test the whole Nim keywords range
case w.id
of ccgKeywordsLow..ccgKeywordsHigh,
nimKeywordsLow..nimKeywordsHigh,
ord(wInline): return true
else: return false
-proc mangleName(s: PSym): PRope =
+proc mangleField(name: PIdent): string =
+ result = mangle(name.s)
+ if isKeyword(name):
+ result[0] = result[0].toUpper # Mangling makes everything lowercase,
+ # but some identifiers are C keywords
+
+proc mangleName(s: PSym): Rope =
result = s.loc.r
if result == nil:
when oKeepVariableNames:
@@ -77,27 +78,27 @@ proc mangleName(s: PSym): PRope =
# These are not properly scoped now - we need to add blocks
# around for loops in transf
if keepOrigName:
- result = s.name.s.mangle.newRope
+ result = s.name.s.mangle.rope
else:
- app(result, newRope(mangle(s.name.s)))
- app(result, ~"_")
- app(result, toRope(s.id))
+ add(result, rope(mangle(s.name.s)))
+ add(result, ~"_")
+ add(result, rope(s.id))
else:
- app(result, newRope(mangle(s.name.s)))
- app(result, ~"_")
- app(result, toRope(s.id))
+ add(result, rope(mangle(s.name.s)))
+ add(result, ~"_")
+ add(result, rope(s.id))
s.loc.r = result
-proc typeName(typ: PType): PRope =
- result = if typ.sym != nil: typ.sym.name.s.mangle.toRope
+proc typeName(typ: PType): Rope =
+ result = if typ.sym != nil: typ.sym.name.s.mangle.rope
else: ~"TY"
-proc getTypeName(typ: PType): PRope =
+proc getTypeName(typ: PType): Rope =
if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
result = typ.sym.loc.r
else:
if typ.loc.r == nil:
- typ.loc.r = con(typ.typeName, typ.id.toRope)
+ typ.loc.r = typ.typeName & typ.id.rope
result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind)
@@ -110,7 +111,7 @@ proc mapSetType(typ: PType): TCTypeKind =
else: result = ctArray
proc mapType(typ: PType): TCTypeKind =
- ## Maps a nimrod type to a C type
+ ## Maps a Nim type to a C type
case typ.kind
of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool
@@ -156,7 +157,7 @@ proc isImportedType(t: PType): bool =
proc isImportedCppType(t: PType): bool =
result = t.sym != nil and sfInfixCall in t.sym.flags
-proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope
proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ)
@@ -189,17 +190,17 @@ const
# but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
-proc cacheGetType(tab: TIdTable, key: PType): PRope =
+proc cacheGetType(tab: TIdTable, key: PType): Rope =
# returns nil if we need to declare this type
# since types are now unique via the ``getUniqueType`` mechanism, this slow
# linear search is not necessary anymore:
- result = PRope(idTableGet(tab, key))
+ result = Rope(idTableGet(tab, key))
-proc getTempName(): PRope =
- result = rfmt(nil, "TMP$1", toRope(backendId()))
+proc getTempName(): Rope =
+ result = rfmt(nil, "TMP$1", rope(backendId()))
-proc getGlobalTempName(): PRope =
- result = rfmt(nil, "TMP$1", toRope(backendId()))
+proc getGlobalTempName(): Rope =
+ result = rfmt(nil, "TMP$1", rope(backendId()))
proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, typedescInst)
@@ -226,13 +227,13 @@ proc fillResult(param: PSym) =
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
-proc typeNameOrLiteral(t: PType, literal: string): PRope =
+proc typeNameOrLiteral(t: PType, literal: string): Rope =
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
result = getTypeName(t)
else:
- result = toRope(literal)
+ result = rope(literal)
-proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
+proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
const
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
"NI", "NI8", "NI16", "NI32", "NI64",
@@ -268,20 +269,20 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ)
-proc getTypePre(m: BModule, typ: PType): PRope =
- if typ == nil: result = toRope("void")
+proc getTypePre(m: BModule, typ: PType): Rope =
+ if typ == nil: result = rope("void")
else:
result = getSimpleTypeDesc(m, typ)
if result == nil: result = cacheGetType(m.typeCache, typ)
-proc structOrUnion(t: PType): PRope =
- (if tfUnion in t.flags: toRope("union") else: toRope("struct"))
+proc structOrUnion(t: PType): Rope =
+ (if tfUnion in t.flags: rope("union") else: rope("struct"))
proc getForwardStructFormat(m: BModule): string =
if m.compileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n"
-proc getTypeForward(m: BModule, typ: PType): PRope =
+proc getTypeForward(m: BModule, typ: PType): Rope =
result = cacheGetType(m.forwTypeCache, typ)
if result != nil: return
result = getTypePre(m, typ)
@@ -290,12 +291,12 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
of tySequence, tyTuple, tyObject:
result = getTypeName(typ)
if not isImportedType(typ):
- appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+ addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')')
-proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
+proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
## like getTypeDescAux but creates only a *weak* dependency. In other words
## we know we only need a pointer to it so we only generate a struct forward
## declaration:
@@ -310,7 +311,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
pushType(m, x)
of tySequence:
let x = getUniqueType(etB)
- result = getTypeForward(m, x).con("*")
+ result = getTypeForward(m, x) & "*"
pushType(m, x)
else:
result = getTypeDescAux(m, t, check)
@@ -321,7 +322,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
else:
result = OnUnknown
-proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
+proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true) =
params = nil
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
@@ -332,18 +333,18 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
- if params != nil: app(params, ~", ")
+ if params != nil: add(params, ~", ")
fillLoc(param.loc, locParam, param.typ, mangleName(param),
param.paramStorageLoc)
if ccgIntroducedPtr(param):
- app(params, getTypeDescWeak(m, param.typ, check))
- app(params, ~"*")
+ add(params, getTypeDescWeak(m, param.typ, check))
+ add(params, ~"*")
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
else:
- app(params, getTypeDescAux(m, param.typ, check))
- app(params, ~" ")
- app(params, param.loc.r)
+ add(params, getTypeDescAux(m, param.typ, check))
+ add(params, ~" ")
+ add(params, param.loc.r)
# declare the len field for open arrays:
var arr = param.typ
if arr.kind == tyVar: arr = arr.sons[0]
@@ -352,78 +353,78 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
# this fixes the 'sort' bug:
if param.typ.kind == tyVar: param.loc.s = OnUnknown
# need to pass hidden parameter:
- appf(params, ", NI $1Len$2", [param.loc.r, j.toRope])
+ addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
inc(j)
arr = arr.sons[0]
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
var arr = t.sons[0]
- if params != nil: app(params, ", ")
+ if params != nil: add(params, ", ")
if (mapReturnType(t.sons[0]) != ctArray):
- app(params, getTypeDescWeak(m, arr, check))
- app(params, "*")
+ add(params, getTypeDescWeak(m, arr, check))
+ add(params, "*")
else:
- app(params, getTypeDescAux(m, arr, check))
- appf(params, " Result", [])
+ add(params, getTypeDescAux(m, arr, check))
+ addf(params, " Result", [])
if t.callConv == ccClosure and declareEnvironment:
- if params != nil: app(params, ", ")
- app(params, "void* ClEnv")
+ if params != nil: add(params, ", ")
+ add(params, "void* ClEnv")
if tfVarargs in t.flags:
- if params != nil: app(params, ", ")
- app(params, "...")
- if params == nil: app(params, "void)")
- else: app(params, ")")
- params = con("(", params)
+ if params != nil: add(params, ", ")
+ add(params, "...")
+ if params == nil: add(params, "void)")
+ else: add(params, ")")
+ params = "(" & params
-proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
+proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
if (rectype.sym != nil) and
({sfImportc, sfExportc} * rectype.sym.flags != {}):
result = field.loc.r
else:
- result = toRope(mangleField(field.name.s))
+ result = rope(mangleField(field.name))
if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
- accessExpr: PRope, rectype: PType,
- check: var IntSet): PRope =
+ accessExpr: Rope, rectype: PType,
+ check: var IntSet): Rope =
var
- ae, uname, sname, a: PRope
+ ae, uname, sname, a: Rope
k: PNode
field: PSym
result = nil
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
- app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
+ add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
- app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
- uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
- if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
+ add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
+ uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
+ if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname]
else: ae = uname
- var unionBody: PRope = nil
+ var unionBody: Rope = nil
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
k = lastSon(n.sons[i])
if k.kind != nkSym:
- sname = con("S", toRope(i))
- a = genRecordFieldsAux(m, k, ropef("$1.$2", [ae, sname]), rectype,
+ sname = "S" & rope(i)
+ a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
check)
if a != nil:
- app(unionBody, "struct {")
- app(unionBody, a)
- appf(unionBody, "} $1;$n", [sname])
+ add(unionBody, "struct {")
+ add(unionBody, a)
+ addf(unionBody, "} $1;$n", [sname])
else:
- app(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
+ add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
else: internalError("genRecordFieldsAux(record case branch)")
if unionBody != nil:
- appf(result, "union{$n$1} $2;$n", [unionBody, uname])
+ addf(result, "union{$n$1} $2;$n", [unionBody, uname])
of nkSym:
field = n.sym
if field.typ.kind == tyEmpty: return
#assert(field.ast == nil)
sname = mangleRecFieldName(field, rectype)
- if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
+ if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't
@@ -432,27 +433,27 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
- appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
+ addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname])
elif fieldType.kind == tySequence:
# we need to use a weak dependency here for trecursive_table.
- appf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+ addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
- appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
+ addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
-proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
+proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
-proc getRecordDesc(m: BModule, typ: PType, name: PRope,
- check: var IntSet): PRope =
+proc getRecordDesc(m: BModule, typ: PType, name: Rope,
+ check: var IntSet): Rope =
# declare the record:
var hasField = false
- var attribute: PRope =
- if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
+ var attribute: Rope =
+ if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
else: nil
result = ropecg(m, CC[cCompiler].structStmtFmt,
@@ -475,27 +476,54 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
else:
- appf(result, " {$n", [name])
+ addf(result, " {$n", [name])
var desc = getRecordFields(m, typ, check)
if desc == nil and not hasField:
- appf(result, "char dummy;$n", [])
+ addf(result, "char dummy;$n", [])
else:
- app(result, desc)
- app(result, "};" & tnl)
+ add(result, desc)
+ add(result, "};" & tnl)
-proc getTupleDesc(m: BModule, typ: PType, name: PRope,
- check: var IntSet): PRope =
- result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
- var desc: PRope = nil
+proc getTupleDesc(m: BModule, typ: PType, name: Rope,
+ check: var IntSet): Rope =
+ result = "$1 $2 {$n" % [structOrUnion(typ), name]
+ var desc: Rope = nil
for i in countup(0, sonsLen(typ) - 1):
- appf(desc, "$1 Field$2;$n",
- [getTypeDescAux(m, typ.sons[i], check), toRope(i)])
- if desc == nil: app(result, "char dummy;" & tnl)
- else: app(result, desc)
- app(result, "};" & tnl)
+ addf(desc, "$1 Field$2;$n",
+ [getTypeDescAux(m, typ.sons[i], check), rope(i)])
+ if desc == nil: add(result, "char dummy;" & tnl)
+ else: add(result, desc)
+ add(result, "};" & tnl)
-proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
+proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
+ # A helper proc for handling cppimport patterns, involving numeric
+ # placeholders for generic types (e.g. '0, '**2, etc).
+ # pre: the cursor must be placed at the ' symbol
+ # post: the cursor will be placed after the final digit
+ # false will returned if the input is not recognized as a placeholder
+ inc cursor
+ let begin = cursor
+ while pat[cursor] == '*': inc cursor
+ if pat[cursor] in Digits:
+ outIdx = pat[cursor].ord - '0'.ord
+ outStars = cursor - begin
+ inc cursor
+ return true
+ else:
+ return false
+
+proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
+ # XXX: we should catch this earlier and report it as a semantic error
+ if idx >= typ.len: internalError "invalid apostrophe type parameter index"
+
+ result = typ.sons[idx]
+ for i in 1..stars:
+ if result != nil and result.len > 0:
+ result = if result.kind == tyGenericInst: result.sons[1]
+ else: result.elemType
+
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
# returns only the type's name
var t = getUniqueType(typ)
if t == nil: internalError("getTypeDescAux: t == nil")
@@ -523,39 +551,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst:
- result = con(getTypeDescAux(m, et, check), star)
+ result = getTypeDescAux(m, et, check) & star
else:
# no restriction! We have a forward declaration for structs
let x = getUniqueType(etB)
let name = getTypeForward(m, x)
- result = con(name, star)
+ result = name & star
idTablePut(m.typeCache, t, result)
pushType(m, x)
of tySequence:
# no restriction! We have a forward declaration for structs
let x = getUniqueType(etB)
let name = getTypeForward(m, x)
- result = con(name, "*" & star)
+ result = name & "*" & star
idTablePut(m.typeCache, t, result)
pushType(m, x)
else:
# else we have a strong dependency :-(
- result = con(getTypeDescAux(m, et, check), star)
+ result = getTypeDescAux(m, et, check) & star
idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs:
- result = con(getTypeDescAux(m, t.sons[0], check), "*")
+ result = getTypeDescAux(m, t.sons[0], check) & "*"
idTablePut(m.typeCache, t, result)
of tyProc:
result = getTypeName(t)
idTablePut(m.typeCache, t, result)
- var rettype, desc: PRope
+ var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
- appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
- [toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
+ addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+ [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
else:
- appf(m.s[cfsTypes], "typedef struct {$n" &
+ addf(m.s[cfsTypes], "typedef struct {$n" &
"N_NIMCALL_PTR($2, ClPrc) $3;$n" &
"void* ClEnv;$n} $1;$n",
[result, rettype, desc])
@@ -566,11 +594,11 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
- appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+ addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
assert(cacheGetType(m.typeCache, t) == nil)
- idTablePut(m.typeCache, t, con(result, "*"))
+ idTablePut(m.typeCache, t, result & "*")
if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const
@@ -582,8 +610,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
" $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
else:
- result = toRope("TGenericSeq")
- app(result, "*")
+ result = rope("TGenericSeq")
+ add(result, "*")
of tyArrayConstr, tyArray:
var n: BiggestInt = lengthOrd(t)
if n <= 0: n = 1 # make an array of at least one element
@@ -591,17 +619,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
let foo = getTypeDescAux(m, t.sons[1], check)
- appf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
- [foo, result, toRope(n)])
+ addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
+ [foo, result, rope(n)])
of tyObject, tyTuple:
if isImportedCppType(t) and typ.kind == tyGenericInst:
# for instantiated templates we do not go through the type cache as the
# the type cache is not aware of 'tyGenericInst'.
- result = getTypeName(t).con("<")
- for i in 1 .. typ.len-2:
- if i > 1: result.app(", ")
- result.app(getTypeDescAux(m, typ.sons[i], check))
- result.app("> ")
+ let cppName = getTypeName(t)
+ var i = 0
+ var chunkStart = 0
+ while i < cppName.data.len:
+ if cppName.data[i] == '\'':
+ var chunkEnd = 1: result.add(", ")
+ result.add(getTypeDescAux(m, typ.sons[i], check))
+ result.add("> ")
# always call for sideeffects:
assert t.kind != tyTuple
discard getRecordDesc(m, t, result, check)
@@ -610,25 +660,25 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
- appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+ addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
idTablePut(m.typeCache, t, result) # always call for sideeffects:
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check)
- if not isImportedType(t): app(m.s[cfsTypes], recdesc)
+ if not isImportedType(t): add(m.s[cfsTypes], recdesc)
of tySet:
case int(getSize(t))
- of 1: result = toRope("NU8")
- of 2: result = toRope("NU16")
- of 4: result = toRope("NU32")
- of 8: result = toRope("NU64")
+ of 1: result = rope("NU8")
+ of 2: result = rope("NU16")
+ of 4: result = rope("NU32")
+ of 8: result = rope("NU64")
else:
result = getTypeName(t)
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
- appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
- [result, toRope(getSize(t))])
+ addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
+ [result, rope(getSize(t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
tyIter, tyTypeDesc:
result = getTypeDescAux(m, lastSon(t), check)
@@ -638,7 +688,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
# fixes bug #145:
excl(check, t.id)
-proc getTypeDesc(m: BModule, typ: PType): PRope =
+proc getTypeDesc(m: BModule, typ: PType): Rope =
var check = initIntSet()
result = getTypeDescAux(m, typ, check)
@@ -646,23 +696,23 @@ type
TClosureTypeKind = enum
clHalf, clHalfWithEnv, clFull
-proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): PRope =
+proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc
var check = initIntSet()
result = getTempName()
- var rettype, desc: PRope
+ var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t):
if t.callConv != ccClosure or kind != clFull:
- appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
- [toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
+ addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+ [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
else:
- appf(m.s[cfsTypes], "typedef struct {$n" &
+ addf(m.s[cfsTypes], "typedef struct {$n" &
"N_NIMCALL_PTR($2, ClPrc) $3;$n" &
"void* ClEnv;$n} $1;$n",
[result, rettype, desc])
-proc getTypeDesc(m: BModule, magic: string): PRope =
+proc getTypeDesc(m: BModule, magic: string): Rope =
var sym = magicsys.getCompilerProc(magic)
if sym != nil:
result = getTypeDesc(m, sym.typ)
@@ -678,38 +728,38 @@ proc finishTypeDescriptions(m: BModule) =
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
-proc genProcHeader(m: BModule, prc: PSym): PRope =
+proc genProcHeader(m: BModule, prc: PSym): Rope =
var
- rettype, params: PRope
+ rettype, params: Rope
genCLineDir(result, prc.info)
# using static is needed for inline procs
if lfExportLib in prc.loc.flags:
if m.isHeaderFile:
- result.app "N_LIB_IMPORT "
+ result.add "N_LIB_IMPORT "
else:
- result.app "N_LIB_EXPORT "
+ result.add "N_LIB_EXPORT "
elif prc.typ.callConv == ccInline:
- result.app "static "
+ result.add "static "
var check = initIntSet()
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
genProcParams(m, prc.typ, rettype, params, check)
# careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph!
if prc.constraint.isNil:
- appf(result, "$1($2, $3)$4",
- [toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
+ addf(result, "$1($2, $3)$4",
+ [rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
params])
else:
- result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
+ result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
# ------------------ type info generation -------------------------------------
-proc genTypeInfo(m: BModule, t: PType): PRope
-proc getNimNode(m: BModule): PRope =
- result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
+proc genTypeInfo(m: BModule, t: PType): Rope
+proc getNimNode(m: BModule): Rope =
+ result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes)
-proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
+proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
var nimtypeKind: int
#allocMemTI(m, typ, name)
if isObjLackingTypeField(typ):
@@ -717,48 +767,47 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
else:
nimtypeKind = ord(typ.kind)
- var size: PRope
- if tfIncompleteStruct in typ.flags: size = toRope"void*"
+ var size: Rope
+ if tfIncompleteStruct in typ.flags: size = rope"void*"
elif m.compileToCpp: size = getTypeDesc(m, origType)
else: size = getTypeDesc(m, typ)
- appf(m.s[cfsTypeInit3],
+ addf(m.s[cfsTypeInit3],
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
- [name, size, toRope(nimtypeKind), base])
+ [name, size, rope(nimtypeKind), base])
# compute type flags for GC optimization
var flags = 0
if not containsGarbageCollectedRef(typ): flags = flags or 1
if not canFormAcycle(typ): flags = flags or 2
#else MessageOut("can contain a cycle: " & typeToString(typ))
if flags != 0:
- appf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, toRope(flags)])
+ addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
discard cgsym(m, "TNimType")
- appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
- [name, toRope(typeToString(typ))])
+ addf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
+ [name, rope(typeToString(typ))])
-proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
- var base: PRope
+proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
+ var base: Rope
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
base = genTypeInfo(m, typ.sons[0])
else:
- base = toRope("0")
+ base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base)
-proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
+proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
# bugfix: we need to search the type that contains the discriminator:
var objtype = objtype
while lookupInRecord(objtype.n, d.name) == nil:
objtype = objtype.sons[0]
if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator")
- result = ropef("NimDT_$1_$2", [
- toRope(objtype.id), toRope(d.name.s.mangle)])
+ result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)]
-proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
+proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d)
- result = ropef("TNimNode* $1[$2];$n", [tmp, toRope(lengthOrd(d.typ)+1)])
+ result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
-proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
+proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
case n.kind
of nkRecList:
var L = sonsLen(n)
@@ -766,29 +815,29 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
genObjectFields(m, typ, n.sons[0], expr)
elif L > 0:
var tmp = getTempName()
- appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(L)])
+ addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1):
var tmp2 = getNimNode(m)
- appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
+ addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
genObjectFields(m, typ, n.sons[i], tmp2)
- appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
- [expr, toRope(L), tmp])
+ addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+ [expr, rope(L), tmp])
else:
- appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, toRope(L)])
+ addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
of nkRecCase:
assert(n.sons[0].kind == nkSym)
var field = n.sons[0].sym
var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(field.typ)
assert L > 0
- appf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
+ addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ),
makeCString(field.name.s),
- tmp, toRope(L)])
- appf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, toRope(L+1)])
+ tmp, rope(L)])
+ addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
for i in countup(1, sonsLen(n)-1):
var b = n.sons[i] # branch
var tmp2 = getNimNode(m)
@@ -802,60 +851,60 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
var x = int(getOrdValue(b.sons[j].sons[0]))
var y = int(getOrdValue(b.sons[j].sons[1]))
while x <= y:
- appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(x), tmp2])
+ addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
inc(x)
else:
- appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
- [tmp, toRope(getOrdValue(b.sons[j])), tmp2])
+ addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+ [tmp, rope(getOrdValue(b.sons[j])), tmp2])
of nkElse:
- appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
- [tmp, toRope(L), tmp2])
+ addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+ [tmp, rope(L), tmp2])
else: internalError(n.info, "genObjectFields(nkRecCase)")
of nkSym:
var field = n.sym
- appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+ addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, typ),
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields")
-proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
+proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
- else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
+ else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
var tmp = getNimNode(m)
if not isImportedCppType(typ):
genObjectFields(m, typ, typ.n, tmp)
- appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
+ addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0]
while t != nil:
t = t.skipTypes(abstractInst)
t.flags.incl tfObjHasKids
t = t.sons[0]
-proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
- genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
+proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
+ genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
var expr = getNimNode(m)
var length = sonsLen(typ)
if length > 0:
var tmp = getTempName()
- appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(length)])
+ addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
for i in countup(0, length - 1):
var a = typ.sons[i]
var tmp2 = getNimNode(m)
- appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
- appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+ addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+ addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n",
- [tmp2, getTypeDesc(m, typ), toRope(i), genTypeInfo(m, a)])
- appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
- [expr, toRope(length), tmp])
+ [tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)])
+ addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+ [expr, rope(length), tmp])
else:
- appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
- [expr, toRope(length)])
- appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
+ addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
+ [expr, rope(length)])
+ addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
-proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
+proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
# Type information for enumerations is quite heavy, so we do some
# optimizations here: The ``typ`` field is never set, as it is redundant
# anyway. We generate a cstring array and a loop over it. Exceptional
@@ -863,9 +912,9 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName()
var length = sonsLen(typ.n)
- appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
- [nodePtrs, toRope(length)])
- var enumNames, specialCases: PRope
+ addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
+ [nodePtrs, rope(length)])
+ var enumNames, specialCases: Rope
var firstNimNode = m.typeNodes
var hasHoles = false
for i in countup(0, length - 1):
@@ -874,38 +923,38 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
var elemNode = getNimNode(m)
if field.ast == nil:
# no explicit string literal for the enum field, so use field.name:
- app(enumNames, makeCString(field.name.s))
+ add(enumNames, makeCString(field.name.s))
else:
- app(enumNames, makeCString(field.ast.strVal))
- if i < length - 1: app(enumNames, ", " & tnl)
+ add(enumNames, makeCString(field.ast.strVal))
+ if i < length - 1: add(enumNames, ", " & tnl)
if field.position != i or tfEnumHasHoles in typ.flags:
- appf(specialCases, "$1.offset = $2;$n", [elemNode, toRope(field.position)])
+ addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true
var enumArray = getTempName()
var counter = getTempName()
- appf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
- appf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
- [enumArray, toRope(length), enumNames])
- appf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
+ addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
+ addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
+ [enumArray, rope(length), enumNames])
+ addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
"$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
"$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
- toRope(length), m.typeNodesName, toRope(firstNimNode), enumArray, nodePtrs])
- app(m.s[cfsTypeInit3], specialCases)
- appf(m.s[cfsTypeInit3],
+ rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
+ add(m.s[cfsTypeInit3], specialCases)
+ addf(m.s[cfsTypeInit3],
"$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
- [getNimNode(m), toRope(length), nodePtrs, name])
+ [getNimNode(m), rope(length), nodePtrs, name])
if hasHoles:
# 1 << 2 is {ntfEnumHole}
- appf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
+ addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
-proc genSetInfo(m: BModule, typ: PType, name: PRope) =
+proc genSetInfo(m: BModule, typ: PType, name: Rope) =
assert(typ.sons[0] != nil)
genTypeInfoAux(m, typ, typ, name)
var tmp = getNimNode(m)
- appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
- [tmp, toRope(firstOrd(typ)), name])
+ addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
+ [tmp, rope(firstOrd(typ)), name])
-proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
+proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
proc fakeClosureType(owner: PSym): PType =
@@ -925,17 +974,17 @@ type
include ccgtrav
-proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
+proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
genProc(m, s)
- appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
+ addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r])
-proc genTypeInfo(m: BModule, t: PType): PRope =
+proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t
var t = getUniqueType(t)
- result = ropef("NTI$1", [toRope(t.id)])
+ result = "NTI$1" % [rope(t.id)]
if containsOrIncl(m.typeInfoMarker, t.id):
- return con("(&".toRope, result, ")".toRope)
+ return "(&".rope & result & ")".rope
# getUniqueType doesn't skip tyDistinct when that has an overriden operation:
while t.kind == tyDistinct: t = t.lastSon
@@ -946,23 +995,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
# reference the type info as extern here
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
- appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
- [result, toRope(typeToString(t))])
- return con("(&".toRope, result, ")".toRope)
+ addf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
+ [result, rope(typeToString(t))])
+ return "(&".rope & result & ")".rope
case t.kind
- of tyEmpty: result = toRope"0"
+ of tyEmpty: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
- genTypeInfoAuxBase(m, t, t, result, toRope"0")
+ genTypeInfoAuxBase(m, t, t, result, rope"0")
of tyProc:
if t.callConv != ccClosure:
- genTypeInfoAuxBase(m, t, t, result, toRope"0")
+ genTypeInfoAuxBase(m, t, t, result, rope"0")
else:
genTupleInfo(m, fakeClosureType(t.owner), result)
of tySequence, tyRef:
genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, t, tiNew)
- appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
+ addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
of tySet: genSetInfo(m, t, result)
@@ -979,7 +1028,7 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
genDeepCopyProc(m, t.deepCopy, result)
elif origType.deepCopy != nil:
genDeepCopyProc(m, origType.deepCopy, result)
- result = con("(&".toRope, result, ")".toRope)
+ result = "(&".rope & result & ")".rope
proc genTypeSection(m: BModule, n: PNode) =
discard
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 25c1a12e58..4ba6643ecf 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -176,7 +176,7 @@ proc mangle*(name: string): string =
result = newStringOfCap(name.len)
case name[0]
of Letters:
- result.add(name[0].toLower)
+ result.add(name[0])
of Digits:
result.add("N" & name[0])
else:
@@ -193,13 +193,13 @@ proc mangle*(name: string): string =
else:
add(result, "HEX" & toHex(ord(c), 2))
-proc makeLLVMString*(s: string): PRope =
+proc makeLLVMString*(s: string): Rope =
const MaxLineLength = 64
result = nil
var res = "c\""
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
- app(result, toRope(res))
+ add(result, rope(res))
setLen(res, 0)
case s[i]
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
@@ -207,6 +207,6 @@ proc makeLLVMString*(s: string): PRope =
add(res, toHex(ord(s[i]), 2))
else: add(res, s[i])
add(res, "\\00\"")
- app(result, toRope(res))
+ add(result, rope(res))
initTypeTables()
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 01db97e73c..4b0bac28ad 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -10,13 +10,15 @@
## This module implements the C code generator.
import
- ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
+ ast, astalgo, hashes, trees, platform, magicsys, extccomp,
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
semparallel
+import strutils except `%` # collides with ropes.`%`
+
when options.hasTinyCBackend:
import tccgen
@@ -48,7 +50,7 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.r = nil
result.flags = {}
-proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
+proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
# fills the loc if it is not already initialized
if a.k == locNone:
a.k = k
@@ -72,9 +74,9 @@ proc useHeader(m: BModule, sym: PSym) =
assert(sym.annex != nil)
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
-proc cgsym(m: BModule, name: string): PRope
+proc cgsym(m: BModule, name: string): Rope
-proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
+proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
var i = 0
var length = len(frmt)
result = nil
@@ -84,11 +86,11 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
inc(i) # skip '$'
case frmt[i]
of '$':
- app(result, "$")
+ add(result, "$")
inc(i)
of '#':
inc(i)
- app(result, args[num])
+ add(result, args[num])
inc(num)
of '0'..'9':
var j = 0
@@ -99,12 +101,12 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
num = j
if j > high(args) + 1:
internalError("ropes: invalid format string $" & $j)
- app(result, args[j-1])
+ add(result, args[j-1])
of 'n':
- if optLineDir notin gOptions: app(result, rnl)
+ if optLineDir notin gOptions: add(result, rnl)
inc(i)
of 'N':
- app(result, rnl)
+ add(result, rnl)
inc(i)
else: internalError("ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
@@ -113,74 +115,74 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
while frmt[j] in IdentChars: inc(j)
var ident = substr(frmt, i, j-1)
i = j
- app(result, cgsym(m, ident))
+ add(result, cgsym(m, ident))
elif frmt[i] == '#' and frmt[i+1] == '$':
inc(i, 2)
var j = 0
while frmt[i] in Digits:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
- app(result, cgsym(m, args[j-1].ropeToStr))
+ add(result, cgsym(m, $args[j-1]))
var start = i
while i < length:
if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break
if i - 1 >= start:
- app(result, substr(frmt, start, i - 1))
+ add(result, substr(frmt, start, i - 1))
-template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
+template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
ropecg(m, fmt, args)
-proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(c, ropecg(m, frmt, args))
+proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(c, ropecg(m, frmt, args))
-proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(m.s[s], ropecg(m, frmt, args))
+proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(m.s[s], ropecg(m, frmt, args))
-proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(p.s(s), ropecg(p.module, frmt, args))
+proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(p.s(s), ropecg(p.module, frmt, args))
-var indent = "\t".toRope
-proc indentLine(p: BProc, r: PRope): PRope =
+var indent = "\t".rope
+proc indentLine(p: BProc, r: Rope): Rope =
result = r
for i in countup(0, p.blocks.len-1): prepend(result, indent)
-proc line(p: BProc, s: TCProcSection, r: PRope) =
- app(p.s(s), indentLine(p, r))
+proc line(p: BProc, s: TCProcSection, r: Rope) =
+ add(p.s(s), indentLine(p, r))
proc line(p: BProc, s: TCProcSection, r: string) =
- app(p.s(s), indentLine(p, r.toRope))
+ add(p.s(s), indentLine(p, r.rope))
-proc lineF(p: BProc, s: TCProcSection, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(p.s(s), indentLine(p, ropef(frmt, args)))
+proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
+ args: openarray[Rope]) =
+ add(p.s(s), indentLine(p, frmt % args))
-proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
-proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
-proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
- args: varargs[PRope]) =
- app(r, indentLine(p, ropecg(p.module, frmt, args)))
+proc appLineCg(p: BProc, r: var Rope, frmt: FormatStr,
+ args: varargs[Rope]) =
+ add(r, indentLine(p, ropecg(p.module, frmt, args)))
proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line
-proc genCLineDir(r: var PRope, filename: string, line: int) =
+proc genCLineDir(r: var Rope, filename: string, line: int) =
assert line >= 0
if optLineDir in gOptions:
- appf(r, "$N#line $2 $1$N",
- [toRope(makeSingleLineCString(filename)), toRope(line)])
+ addf(r, "$N#line $2 $1$N",
+ [rope(makeSingleLineCString(filename)), rope(line)])
-proc genCLineDir(r: var PRope, info: TLineInfo) =
+proc genCLineDir(r: var Rope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
@@ -193,22 +195,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
proc genLineDir(p: BProc, t: PNode) =
var line = t.info.safeLineNm
if optEmbedOrigSrc in gGlobalOptions:
- app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
+ add(p.s(cpsStmts), ~"//" & t.info.sourceLine & rnl)
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "#endb($1, $2);$n",
- line.toRope, makeCString(toFilename(t.info)))
+ line.rope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln($1, $2);$n",
- line.toRope, t.info.quotedFilename)
+ line.rope, t.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} =
- app(p.s(cpsStmts), p.module.injectStmt)
+ add(p.s(cpsStmts), p.module.injectStmt)
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.}
@@ -221,21 +223,21 @@ include "ccgtypes.nim"
# ------------------------------ Manager of temporaries ------------------
-proc rdLoc(a: TLoc): PRope =
+proc rdLoc(a: TLoc): Rope =
# 'read' location (deref if indirect)
result = a.r
- if lfIndirect in a.flags: result = ropef("(*$1)", [result])
+ if lfIndirect in a.flags: result = "(*$1)" % [result]
-proc addrLoc(a: TLoc): PRope =
+proc addrLoc(a: TLoc): Rope =
result = a.r
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
- result = con("(&", result).con(")")
+ result = "(&" & result & ")"
-proc rdCharLoc(a: TLoc): PRope =
+proc rdCharLoc(a: TLoc): Rope =
# read a location that may need a char-cast:
result = rdLoc(a)
if skipTypes(a.t, abstractRange).kind == tyChar:
- result = ropef("((NU8)($1))", [result])
+ result = "((NU8)($1))" % [result]
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
takeAddr: bool) =
@@ -244,11 +246,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
discard
of frHeader:
var r = rdLoc(a)
- if not takeAddr: r = ropef("(*$1)", [r])
+ if not takeAddr: r = "(*$1)" % [r]
var s = skipTypes(t, abstractInst)
if not p.module.compileToCpp:
while (s.kind == tyObject) and (s.sons[0] != nil):
- app(r, ".Sup")
+ add(r, ".Sup")
s = skipTypes(s.sons[0], abstractInst)
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
of frEmbedded:
@@ -276,7 +278,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, OnStack)
- nilLoc.r = toRope("NIM_NIL")
+ nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
@@ -325,7 +327,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
- result.r = con("LOC", toRope(p.labels))
+ result.r = "LOC" & rope(p.labels)
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp
#result.a = - 1
@@ -340,9 +342,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
# of interior pointers instead
if optRefcGC notin gGlobalOptions: return
var result: TLoc
- var fid = toRope(p.gcFrameId)
- result.r = con("GCFRAME.F", fid)
- appf(p.gcFrameType, " $1 F$2;$n",
+ var fid = rope(p.gcFrameId)
+ result.r = "GCFRAME.F" & fid
+ addf(p.gcFrameType, " $1 F$2;$n",
[getTypeDesc(p.module, toKeepAlive.t), fid])
inc(p.gcFrameId)
result.k = locTemp
@@ -359,10 +361,10 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
-proc initGCFrame(p: BProc): PRope =
- if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType)
+proc initGCFrame(p: BProc): Rope =
+ if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
-proc deinitGCFrame(p: BProc): PRope =
+proc deinitGCFrame(p: BProc): Rope =
if p.gcFrameId > 0:
result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
@@ -371,42 +373,42 @@ proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
- var a = con("&", s.loc.r)
+ var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
lineF(p, cpsInit,
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
- [p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
+ [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen
-proc localVarDecl(p: BProc; s: PSym): PRope =
+proc localVarDecl(p: BProc; s: PSym): Rope =
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
- if sfRegister in s.flags: app(result, " register")
+ if sfRegister in s.flags: add(result, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
- # app(decl, " GC_GUARD")
- if sfVolatile in s.flags: app(result, " volatile")
- app(result, " ")
- app(result, s.loc.r)
+ # add(decl, " GC_GUARD")
+ if sfVolatile in s.flags: add(result, " volatile")
+ add(result, " ")
+ add(result, s.loc.r)
else:
- result = ropef(s.cgDeclFrmt, result, s.loc.r)
+ result = s.cgDeclFrmt % [result, s.loc.r]
proc assignLocalVar(p: BProc, s: PSym) =
#assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
- let decl = localVarDecl(p, s).con(";" & tnl)
+ let decl = localVarDecl(p, s) & ";" & tnl
line(p, cpsLocals, decl)
localDebugInfo(p, s)
include ccgthreadvars
proc varInDynamicLib(m: BModule, sym: PSym)
-proc mangleDynLibProc(sym: PSym): PRope
+proc mangleDynLibProc(sym: PSym): Rope
proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
@@ -424,17 +426,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags)
else:
- var decl: PRope = nil
+ var decl: Rope = nil
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
- if sfImportc in s.flags: app(decl, "extern ")
- app(decl, td)
- if sfRegister in s.flags: app(decl, " register")
- if sfVolatile in s.flags: app(decl, " volatile")
- appf(decl, " $1;$n", [s.loc.r])
+ if sfImportc in s.flags: add(decl, "extern ")
+ add(decl, td)
+ if sfRegister in s.flags: add(decl, " register")
+ if sfVolatile in s.flags: add(decl, " volatile")
+ addf(decl, " $1;$n", [s.loc.r])
else:
- decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
- app(p.module.s[cfsVars], decl)
+ decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
+ add(p.module.s[cfsVars], decl)
if p.withinLoop > 0:
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
@@ -455,7 +457,7 @@ proc fillProcLoc(sym: PSym) =
proc getLabel(p: BProc): TLabel =
inc(p.labels)
- result = con("LA", toRope(p.labels))
+ result = "LA" & rope(p.labels)
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
@@ -467,9 +469,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
-proc intLiteral(i: BiggestInt): PRope
-proc genLiteral(p: BProc, n: PNode): PRope
-proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope
+proc intLiteral(i: BiggestInt): Rope
+proc genLiteral(p: BProc, n: PNode): Rope
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown)
@@ -480,13 +482,13 @@ proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
result.flags.incl lfSingleUse
expr(p, e, result)
-proc lenField(p: BProc): PRope =
- result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
+proc lenField(p: BProc): Rope =
+ result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
# ----------------------------- dynamic library handling -----------------
-# We don't finalize dynamic libs as this does the OS for us.
+# We don't finalize dynamic libs as the OS does this for us.
proc isGetProcAddr(lib: PLib): bool =
let n = lib.path
@@ -500,16 +502,16 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var tmp = getGlobalTempName()
assert(lib.name == nil)
lib.name = tmp # BUGFIX: cgsym has awful side-effects
- appf(m.s[cfsVars], "static void* $1;$n", [tmp])
+ addf(m.s[cfsVars], "static void* $1;$n", [tmp])
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
if gVerbosity >= 2:
msgWriteln("Dependency: " & lib.path.strVal)
- var loadlib: PRope = nil
+ var loadlib: Rope = nil
for i in countup(0, high(s)):
inc(m.labels)
- if i > 0: app(loadlib, "||")
+ if i > 0: add(loadlib, "||")
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
[tmp, getStrLit(m, s[i])])
appcg(m, m.s[cfsDynLibInit],
@@ -520,21 +522,21 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
p.options = p.options - {optStackTrace, optEndb}
var dest: TLoc
initLocExpr(p, lib.path, dest)
- app(m.s[cfsVars], p.s(cpsLocals))
- app(m.s[cfsDynLibInit], p.s(cpsInit))
- app(m.s[cfsDynLibInit], p.s(cpsStmts))
+ add(m.s[cfsVars], p.s(cpsLocals))
+ add(m.s[cfsDynLibInit], p.s(cpsInit))
+ add(m.s[cfsDynLibInit], p.s(cpsStmts))
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: internalError("loadDynamicLib")
-proc mangleDynLibProc(sym: PSym): PRope =
+proc mangleDynLibProc(sym: PSym): Rope =
if sfCompilerProc in sym.flags:
# NOTE: sym.loc.r is the external name!
- result = toRope(sym.name.s)
+ result = rope(sym.name.s)
else:
- result = ropef("Dl_$1", [toRope(sym.id)])
+ result = "Dl_$1" % [rope(sym.id)]
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -549,30 +551,28 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
let n = lib.path
var a: TLoc
initLocExpr(m.initProc, n[0], a)
- var params = con(rdLoc(a), "(")
+ var params = rdLoc(a) & "("
for i in 1 .. n.len-2:
initLocExpr(m.initProc, n[i], a)
- params.app(rdLoc(a))
- params.app(", ")
- let load = ropef("\t$1 = ($2) ($3$4));$n",
- [tmp, getTypeDesc(m, sym.typ),
- params, makeCString(ropeToStr(extname))])
+ params.add(rdLoc(a))
+ params.add(", ")
+ let load = "\t$1 = ($2) ($3$4));$n" %
+ [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1]
internalAssert(last.kind == nkStrLit)
let idx = last.strVal
if idx.len == 0:
- app(m.initProc.s(cpsStmts), load)
+ add(m.initProc.s(cpsStmts), load)
elif idx.len == 1 and idx[0] in {'0'..'9'}:
- app(m.extensionLoaders[idx[0]], load)
+ add(m.extensionLoaders[idx[0]], load)
else:
internalError(sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
- [tmp, getTypeDesc(m, sym.typ),
- lib.name, makeCString(ropeToStr(extname))])
- appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+ [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+ addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -584,16 +584,15 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
- [tmp, getTypeDesc(m, sym.typ),
- lib.name, makeCString(ropeToStr(extname))])
- appf(m.s[cfsVars], "$2* $1;$n",
+ [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+ addf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
-proc cgsym(m: BModule, name: string): PRope =
+proc cgsym(m: BModule, name: string): Rope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
case sym.kind
@@ -609,29 +608,29 @@ proc cgsym(m: BModule, name: string): PRope =
result = sym.loc.r
proc generateHeaders(m: BModule) =
- app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
+ add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
var it = PStrEntry(m.headerFiles.head)
while it != nil:
if it.data[0] notin {'\"', '<'}:
- appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
+ addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
else:
- appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
+ addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
-proc initFrame(p: BProc, procname, filename: PRope): PRope =
+proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "TVarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
- procname, filename, p.maxFrameLen.toRope,
- p.blocks[0].frameLen.toRope)
+ procname, filename, p.maxFrameLen.rope,
+ p.blocks[0].frameLen.rope)
else:
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
-proc deinitFrame(p: BProc): PRope =
+proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n")
proc closureSetup(p: BProc, prc: PSym) =
@@ -650,7 +649,7 @@ proc closureSetup(p: BProc, prc: PSym) =
proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = genProcHeader(m, prc)
- var returnStmt: PRope = nil
+ var returnStmt: Rope = nil
assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
@@ -676,33 +675,36 @@ proc genProcAux(m: BModule, prc: PSym) =
assignParam(p, param)
closureSetup(p, prc)
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
- var generatedProc: PRope
+ var generatedProc: Rope
+ if sfNoReturn in prc.flags:
+ if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+ header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
- if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
- header = con("__declspec(naked) ", header)
+ if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+ header = "__declspec(naked) " & header
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
else:
generatedProc = rfmt(nil, "$N$1 {$N", header)
- app(generatedProc, initGCFrame(p))
+ add(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
- app(generatedProc, p.s(cpsLocals))
+ add(generatedProc, p.s(cpsLocals))
var procname = makeCString(prc.name.s)
- app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
+ add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else:
- app(generatedProc, p.s(cpsLocals))
+ add(generatedProc, p.s(cpsLocals))
if optProfiler in prc.options:
# invoke at proc entry for recursion:
appcg(p, cpsInit, "\t#nimProfile();$n", [])
- if p.beforeRetNeeded: app(generatedProc, "{")
- app(generatedProc, p.s(cpsInit))
- app(generatedProc, p.s(cpsStmts))
- if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n")
- app(generatedProc, deinitGCFrame(p))
- if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
- app(generatedProc, returnStmt)
- app(generatedProc, ~"}$N")
- app(m.s[cfsProcs], generatedProc)
+ if p.beforeRetNeeded: add(generatedProc, "{")
+ add(generatedProc, p.s(cpsInit))
+ add(generatedProc, p.s(cpsStmts))
+ if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
+ add(generatedProc, deinitGCFrame(p))
+ if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
+ add(generatedProc, returnStmt)
+ add(generatedProc, ~"}$N")
+ add(m.s[cfsProcs], generatedProc)
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
result = sfCompileToCpp in m.module.flags and
@@ -715,15 +717,17 @@ proc genProcPrototype(m: BModule, sym: PSym) =
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not containsOrIncl(m.declaredThings, sym.id):
- app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
+ add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym)
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
- header = con("extern \"C\" ", header)
- if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
- header.app(" __attribute__((naked))")
- app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
+ header = "extern \"C\" " & header
+ if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
+ header.add(" __attribute__((naked))")
+ if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
+ header.add(" __attribute__((noreturn))")
+ add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(prc)
@@ -760,16 +764,16 @@ proc requestConstImpl(p: BProc, sym: PSym) =
var q = findPendingModule(m, sym)
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
assert q.initProc.module == q
- appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+ addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
# declare header:
if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
- let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
- [getTypeDesc(m, sym.loc.t), sym.loc.r])
- app(m.s[cfsData], headerDecl)
+ let headerDecl = "extern NIM_CONST $1 $2;$n" %
+ [getTypeDesc(m, sym.loc.t), sym.loc.r]
+ add(m.s[cfsData], headerDecl)
if sfExportc in sym.flags and generatedHeader != nil:
- app(generatedHeader.s[cfsData], headerDecl)
+ add(generatedHeader.s[cfsData], headerDecl)
proc isActivated(prc: PSym): bool = prc.typ != nil
@@ -798,47 +802,47 @@ proc genVarPrototypeAux(m: BModule, sym: PSym) =
if sfThread in sym.flags:
declareThreadVar(m, sym, true)
else:
- app(m.s[cfsVars], "extern ")
- app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
- if lfDynamicLib in sym.loc.flags: app(m.s[cfsVars], "*")
- if sfRegister in sym.flags: app(m.s[cfsVars], " register")
- if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
- appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
+ add(m.s[cfsVars], "extern ")
+ add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
+ if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
+ if sfRegister in sym.flags: add(m.s[cfsVars], " register")
+ if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
+ addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc genVarPrototype(m: BModule, sym: PSym) =
genVarPrototypeAux(m, sym)
-proc addIntTypes(result: var PRope) {.inline.} =
- appf(result, "#define NIM_INTBITS $1", [
- platform.CPU[targetCPU].intSize.toRope])
+proc addIntTypes(result: var Rope) {.inline.} =
+ addf(result, "#define NIM_INTBITS $1", [
+ platform.CPU[targetCPU].intSize.rope])
-proc getCopyright(cfile: string): PRope =
+proc getCopyright(cfile: string): Rope =
if optCompileOnly in gGlobalOptions:
- result = ropef("/* Generated by Nim Compiler v$1 */$N" &
+ result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2015 Andreas Rumpf */$N" &
- "/* The generated code is subject to the original license. */$N",
- [toRope(VersionAsString)])
+ "/* The generated code is subject to the original license. */$N") %
+ [rope(VersionAsString)]
else:
- result = ropef("/* Generated by Nim Compiler v$1 */$N" &
+ result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2015 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" &
- "/* Command for C compiler:$n $5 */$N",
- [toRope(VersionAsString),
- toRope(platform.OS[targetOS].name),
- toRope(platform.CPU[targetCPU].name),
- toRope(extccomp.CC[extccomp.cCompiler].name),
- toRope(getCompileCFileCmd(cfile))])
+ "/* Command for C compiler:$n $5 */$N") %
+ [rope(VersionAsString),
+ rope(platform.OS[targetOS].name),
+ rope(platform.CPU[targetCPU].name),
+ rope(extccomp.CC[extccomp.cCompiler].name),
+ rope(getCompileCFileCmd(cfile))]
-proc getFileHeader(cfile: string): PRope =
+proc getFileHeader(cfile: string): Rope =
result = getCopyright(cfile)
addIntTypes(result)
-proc genFilenames(m: BModule): PRope =
+proc genFilenames(m: BModule): Rope =
discard cgsym(m, "dbgRegisterFilename")
result = nil
for i in 0.. 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
- [m.typeNodesName, toRope(m.typeNodes)])
+ [m.typeNodesName, rope(m.typeNodes)])
if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
- [m.nimTypesName, toRope(m.nimTypes)])
+ [m.nimTypesName, rope(m.nimTypes)])
- app(prc, initGCFrame(m.initProc))
+ add(prc, initGCFrame(m.initProc))
- app(prc, genSectionStart(cpsLocals))
- app(prc, m.preInitProc.s(cpsLocals))
- app(prc, m.initProc.s(cpsLocals))
- app(prc, m.postInitProc.s(cpsLocals))
- app(prc, genSectionEnd(cpsLocals))
+ add(prc, genSectionStart(cpsLocals))
+ add(prc, m.preInitProc.s(cpsLocals))
+ add(prc, m.initProc.s(cpsLocals))
+ add(prc, m.postInitProc.s(cpsLocals))
+ add(prc, genSectionEnd(cpsLocals))
if optStackTrace in m.initProc.options and not m.frameDeclared:
# BUT: the generated init code might depend on a current frame, so
@@ -1009,58 +1013,58 @@ proc genInitCode(m: BModule) =
m.frameDeclared = true
if not m.preventStackTrace:
var procname = makeCString(m.module.name.s)
- app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
+ add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
- app(prc, ~"\tTFrame F; F.len = 0;$N")
+ add(prc, ~"\tTFrame F; F.len = 0;$N")
- app(prc, genSectionStart(cpsInit))
- app(prc, m.preInitProc.s(cpsInit))
- app(prc, m.initProc.s(cpsInit))
- app(prc, m.postInitProc.s(cpsInit))
- app(prc, genSectionEnd(cpsInit))
+ add(prc, genSectionStart(cpsInit))
+ add(prc, m.preInitProc.s(cpsInit))
+ add(prc, m.initProc.s(cpsInit))
+ add(prc, m.postInitProc.s(cpsInit))
+ add(prc, genSectionEnd(cpsInit))
- app(prc, genSectionStart(cpsStmts))
- app(prc, m.preInitProc.s(cpsStmts))
- app(prc, m.initProc.s(cpsStmts))
- app(prc, m.postInitProc.s(cpsStmts))
- app(prc, genSectionEnd(cpsStmts))
+ add(prc, genSectionStart(cpsStmts))
+ add(prc, m.preInitProc.s(cpsStmts))
+ add(prc, m.initProc.s(cpsStmts))
+ add(prc, m.postInitProc.s(cpsStmts))
+ add(prc, genSectionEnd(cpsStmts))
if optStackTrace in m.initProc.options and not m.preventStackTrace:
- app(prc, deinitFrame(m.initProc))
- app(prc, deinitGCFrame(m.initProc))
- appf(prc, "}$N$N")
+ add(prc, deinitFrame(m.initProc))
+ add(prc, deinitGCFrame(m.initProc))
+ addf(prc, "}$N$N", [])
- prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
+ prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
[getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit:
- app(prc, genSectionStart(i))
- app(prc, m.s[i])
- app(prc, genSectionEnd(i))
+ add(prc, genSectionStart(i))
+ add(prc, m.s[i])
+ add(prc, genSectionEnd(i))
- appf(prc, "}$N$N")
+ addf(prc, "}$N$N", [])
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
# that would lead to a *nesting* of merge sections which the merger does
# not support. So we add it to another special section: ``cfsInitProc``
- app(m.s[cfsInitProc], prc)
+ add(m.s[cfsInitProc], prc)
for i, el in pairs(m.extensionLoaders):
if el != nil:
- let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N",
- (i.ord - '0'.ord).toRope, el)
- app(m.s[cfsInitProc], ex)
+ let ex = "N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
+ [(i.ord - '0'.ord).rope, el]
+ add(m.s[cfsInitProc], ex)
-proc genModule(m: BModule, cfile: string): PRope =
+proc genModule(m: BModule, cfile: string): Rope =
result = getFileHeader(cfile)
- result.app(genMergeInfo(m))
+ result.add(genMergeInfo(m))
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
- app(result, genSectionStart(i))
- app(result, m.s[i])
- app(result, genSectionEnd(i))
- app(result, m.s[cfsInitProc])
+ add(result, genSectionStart(i))
+ add(result, m.s[i])
+ add(result, genSectionEnd(i))
+ add(result, m.s[cfsInitProc])
proc newPreInitProc(m: BModule): BProc =
result = newProc(nil, m)
@@ -1172,22 +1176,22 @@ proc myOpen(module: PSym): PPassContext =
proc writeHeader(m: BModule) =
var result = getCopyright(m.filename)
- var guard = ropef("__$1__", m.filename.splitFile.name.toRope)
- result.appf("#ifndef $1$n#define $1$n", guard)
+ var guard = "__$1__" % [m.filename.splitFile.name.rope]
+ result.addf("#ifndef $1$n#define $1$n", [guard])
addIntTypes(result)
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
- app(result, genSectionStart(i))
- app(result, m.s[i])
- app(result, genSectionEnd(i))
- app(result, m.s[cfsInitProc])
+ add(result, genSectionStart(i))
+ add(result, m.s[i])
+ add(result, genSectionEnd(i))
+ add(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions:
- result.app("N_LIB_IMPORT ")
- result.appf("N_CDECL(void, NimMain)(void);$n")
- result.appf("#endif /* $1 */$n", guard)
+ result.add("N_LIB_IMPORT ")
+ result.addf("N_CDECL(void, NimMain)(void);$n", [])
+ result.addf("#endif /* $1 */$n", [guard])
writeRope(result, m.filename)
proc getCFile(m: BModule): string =
@@ -1224,7 +1228,7 @@ proc finishModule(m: BModule) =
dec(gForwardedProcsCounter, i)
setLen(m.forwardedProcs, 0)
-proc shouldRecompile(code: PRope, cfile: string): bool =
+proc shouldRecompile(code: Rope, cfile: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfile)
@@ -1249,13 +1253,13 @@ proc writeModule(m: BModule, pending: bool) =
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
# generate main file:
- app(m.s[cfsProcHeaders], mainModProcs)
+ add(m.s[cfsProcHeaders], mainModProcs)
generateThreadVarsSize(m)
var code = genModule(m, cfile)
when hasTinyCBackend:
if gCmd == cmdRun:
- tccgen.compileCCode(ropeToStr(code))
+ tccgen.compileCCode($code)
return
if shouldRecompile(code, cfile):
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 9e9640f59c..1871863733 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -15,7 +15,7 @@ import
from msgs import TLineInfo
type
- TLabel* = PRope # for the C generator a label is just a rope
+ TLabel* = Rope # for the C generator a label is just a rope
TCFileSection* = enum # the sections a generated C file consists of
cfsMergeInfo, # section containing merge information
cfsHeaders, # section for C include file headers
@@ -45,17 +45,17 @@ type
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
- TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
+ TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
cpsInit, # section for init of variables for C proc
cpsStmts # section of local statements for C proc
- TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc
+ TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
BModule* = ref TCGen
BProc* = ref TCProc
TBlock*{.final.} = object
id*: int # the ID of the label; positive means that it
- label*: PRope # generated text for the label
+ label*: Rope # generated text for the label
# nil if label is not used
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
@@ -73,7 +73,7 @@ type
inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
- finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
+ finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
# using return in finally statements
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
@@ -89,7 +89,7 @@ type
# requires 'T x = T()' to become 'T x; x = T()'
# (yes, C++ is weird like that)
gcFrameId*: Natural # for the GC stack marking
- gcFrameType*: PRope # the struct {} we put the GC markers into
+ gcFrameType*: Rope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType]
TCGen = object of TPassContext # represents a C source file
@@ -118,24 +118,24 @@ type
dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here
typeNodes*, nimTypes*: int # used for type info generation
- typeNodesName*, nimTypesName*: PRope # used for type info generation
+ typeNodesName*, nimTypesName*: Rope # used for type info generation
labels*: Natural # for generating unique module-scope names
- extensionLoaders*: array['0'..'9', PRope] # special procs for the
+ extensionLoaders*: array['0'..'9', Rope] # special procs for the
# OpenGL wrapper
- injectStmt*: PRope
+ injectStmt*: Rope
var
- mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
+ mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
# varuious parts of the main module
- gMapping*: PRope # the generated mapping file (if requested)
+ gMapping*: Rope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
-proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
+proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block
result = p.blocks[p.blocks.len - 1].sections[s]
-proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} =
+proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections
result = p.blocks[0].sections[s]
diff --git a/compiler/commands.nim b/compiler/commands.nim
index a2d02e469b..b6ebb6bcb7 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -24,8 +24,8 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
bootSwitch(usedNoGC, defined(nogc), "--gc:none")
-import
- os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
+import
+ os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
wordrecg, parseutils, nimblecmd, idents, parseopt
# but some have deps to imported modules. Yay.
@@ -39,8 +39,8 @@ bootSwitch(usedFFI, hasFFI, "-d:useFFI")
proc writeCommandLineUsage*()
-type
- TCmdLinePass* = enum
+type
+ TCmdLinePass* = enum
passCmd1, # first pass over the command line
passCmd2, # second pass over the command line
passPP # preprocessor called processCommand()
@@ -54,35 +54,35 @@ const
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2015 by Andreas Rumpf\n"
-const
+const
Usage = slurp"doc/basicopt.txt".replace("//", "")
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
-proc getCommandLineDesc(): string =
- result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
+proc getCommandLineDesc(): string =
+ result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & Usage
-proc helpOnError(pass: TCmdLinePass) =
+proc helpOnError(pass: TCmdLinePass) =
if pass == passCmd1:
msgWriteln(getCommandLineDesc())
msgQuit(0)
-proc writeAdvancedUsage(pass: TCmdLinePass) =
+proc writeAdvancedUsage(pass: TCmdLinePass) =
if pass == passCmd1:
- msgWriteln(`%`(HelpMessage, [VersionAsString,
- platform.OS[platform.hostOS].name,
+ msgWriteln(`%`(HelpMessage, [VersionAsString,
+ platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & AdvancedUsage)
msgQuit(0)
-proc writeVersionInfo(pass: TCmdLinePass) =
+proc writeVersionInfo(pass: TCmdLinePass) =
if pass == passCmd1:
- msgWriteln(`%`(HelpMessage, [VersionAsString,
- platform.OS[platform.hostOS].name,
+ msgWriteln(`%`(HelpMessage, [VersionAsString,
+ platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]))
- discard """const gitHash = gorge("git log -n 1 --format=%H")
- if gitHash.strip.len == 40:
- msgWriteln("git hash: " & gitHash)"""
+ const gitHash = gorge("git log -n 1 --format=%H").strip
+ when gitHash.len == 40:
+ msgWriteln("git hash: " & gitHash)
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
@@ -92,8 +92,8 @@ proc writeVersionInfo(pass: TCmdLinePass) =
var
helpWritten: bool
-proc writeCommandLineUsage() =
- if not helpWritten:
+proc writeCommandLineUsage() =
+ if not helpWritten:
msgWriteln(getCommandLineDesc())
helpWritten = true
@@ -101,51 +101,51 @@ proc addPrefix(switch: string): string =
if len(switch) == 1: result = "-" & switch
else: result = "--" & switch
-proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
+proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
-proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
- info: TLineInfo) =
+proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
+ info: TLineInfo) =
cmd = ""
var i = 0
if i < len(switch) and switch[i] == '-': inc(i)
if i < len(switch) and switch[i] == '-': inc(i)
- while i < len(switch):
+ while i < len(switch):
case switch[i]
of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
- else: break
+ else: break
inc(i)
if i >= len(switch): arg = ""
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
else: invalidCmdLineOption(pass, switch, info)
-
-proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
- info: TLineInfo) =
+
+proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
+ info: TLineInfo) =
case whichKeyword(arg)
of wOn: gOptions = gOptions + op
of wOff: gOptions = gOptions - op
else: localError(info, errOnOrOffExpectedButXFound, arg)
-
-proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
- info: TLineInfo) =
+
+proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
+ info: TLineInfo) =
case whichKeyword(arg)
of wOn: gGlobalOptions = gGlobalOptions + op
of wOff: gGlobalOptions = gGlobalOptions - op
else: localError(info, errOnOrOffExpectedButXFound, arg)
-
-proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+
+proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
-
-proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+
+proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
-
-proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
- info: TLineInfo; orig: string) =
+
+proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
+ info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off"
var i = 0
var n = hintMin
- while i < len(arg) and (arg[i] != ']'):
+ while i < len(arg) and (arg[i] != ']'):
add(id, arg[i])
inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i)
@@ -165,7 +165,7 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
of wOff: excl(gNotes, n)
else: localError(info, errOnOrOffExpectedButXFound, arg)
-proc processCompile(filename: string) =
+proc processCompile(filename: string) =
var found = findFile(filename)
if found == "": found = filename
var trunc = changeFileExt(found, "")
@@ -191,7 +191,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: invalidCmdLineOption(passCmd1, switch, info)
-proc testCompileOption*(switch: string, info: TLineInfo): bool =
+proc testCompileOption*(switch: string, info: TLineInfo): bool =
case switch.normalize
of "debuginfo": result = contains(gGlobalOptions, optCDebug)
of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
@@ -228,11 +228,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "patterns": result = contains(gOptions, optPatterns)
of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info)
-
+
proc processPath(path: string, notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or
- '$' in path or path[0] == '.':
- path
+ '$' in path or path[0] == '.':
+ path
else:
options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
@@ -251,14 +251,14 @@ proc trackDirty(arg: string, info: TLineInfo) =
localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[3], column) <= 0:
localError(info, errInvalidNumber, a[2])
-
+
let dirtyOriginalIdx = a[1].fileInfoIdx
if dirtyOriginalIdx >= 0:
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
-proc track(arg: string, info: TLineInfo) =
+proc track(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
var line, column: int
@@ -273,13 +273,13 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg)
-proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
- var
+proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+ var
theOS: TSystemOS
cpu: TSystemCPU
key, val: string
case switch.normalize
- of "path", "p":
+ of "path", "p":
expectArg(switch, arg, pass, info)
addPath(processPath(arg), info)
of "nimblepath", "babelpath":
@@ -303,7 +303,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "nimcache":
expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg)
- of "out", "o":
+ of "out", "o":
expectArg(switch, arg, pass, info)
options.outFile = arg
of "docseesrcurl":
@@ -311,19 +311,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
options.docSeeSrcUrl = arg
of "mainmodule", "m":
discard "allow for backwards compatibility, but don't do anything"
- of "define", "d":
+ of "define", "d":
expectArg(switch, arg, pass, info)
defineSymbol(arg)
- of "undef", "u":
+ of "undef", "u":
expectArg(switch, arg, pass, info)
undefSymbol(arg)
of "symbol":
expectArg(switch, arg, pass, info)
- declareSymbol(arg)
- of "compile":
+ # deprecated, do nothing
+ of "compile":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: processCompile(arg)
- of "link":
+ of "link":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: addFileToLink(arg)
of "debuginfo":
@@ -332,25 +332,25 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "embedsrc":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optEmbedOrigSrc)
- of "compileonly", "c":
+ of "compileonly", "c":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optCompileOnly)
- of "nolinking":
+ of "nolinking":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoLinking)
- of "nomain":
+ of "nomain":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoMain)
- of "forcebuild", "f":
+ of "forcebuild", "f":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optForceFullMake)
of "project":
expectNoArg(switch, arg, pass, info)
gWholeProject = true
- of "gc":
+ of "gc":
expectArg(switch, arg, pass, info)
case arg.normalize
- of "boehm":
+ of "boehm":
gSelectedGC = gcBoehm
defineSymbol("boehmgc")
of "refc":
@@ -388,7 +388,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
undefSymbol("endb")
else:
localError(info, "expected endb|gdb but found " & arg)
- of "profiler":
+ of "profiler":
processOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: defineSymbol("profiler")
else: undefSymbol("profiler")
@@ -407,7 +407,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads":
processOnOffSwitchG({optThreads}, arg, pass, info)
- if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
+ #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
of "implicitstatic":
@@ -417,17 +417,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "opt":
expectArg(switch, arg, pass, info)
case arg.normalize
- of "speed":
+ of "speed":
incl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
- of "size":
+ of "size":
excl(gOptions, optOptimizeSpeed)
incl(gOptions, optOptimizeSize)
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
- of "app":
+ of "app":
expectArg(switch, arg, pass, info)
case arg.normalize
of "gui":
@@ -449,10 +449,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
defineSymbol("library")
defineSymbol("staticlib")
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
- of "passc", "t":
+ of "passc", "t":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
- of "passl", "l":
+ of "passl", "l":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes":
@@ -475,52 +475,50 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "include":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: implicitIncludes.add arg
- of "listcmd":
+ of "listcmd":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optListCmd)
- of "genmapping":
+ of "genmapping":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenMapping)
- of "os":
+ of "os":
expectArg(switch, arg, pass, info)
- if pass in {passCmd1, passPP}:
+ if pass in {passCmd1, passPP}:
theOS = platform.nameToOS(arg)
if theOS == osNone: localError(info, errUnknownOS, arg)
- elif theOS != platform.hostOS:
+ elif theOS != platform.hostOS:
setTarget(theOS, targetCPU)
- condsyms.initDefines()
- of "cpu":
+ of "cpu":
expectArg(switch, arg, pass, info)
- if pass in {passCmd1, passPP}:
+ if pass in {passCmd1, passPP}:
cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(info, errUnknownCPU, arg)
- elif cpu != platform.hostCPU:
+ elif cpu != platform.hostCPU:
setTarget(targetOS, cpu)
- condsyms.initDefines()
- of "run", "r":
+ of "run", "r":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optRun)
- of "verbosity":
+ of "verbosity":
expectArg(switch, arg, pass, info)
gVerbosity = parseInt(arg)
- of "parallelbuild":
+ of "parallelbuild":
expectArg(switch, arg, pass, info)
gNumberOfProcessors = parseInt(arg)
- of "version", "v":
+ of "version", "v":
expectNoArg(switch, arg, pass, info)
writeVersionInfo(pass)
- of "advanced":
+ of "advanced":
expectNoArg(switch, arg, pass, info)
writeAdvancedUsage(pass)
- of "help", "h":
+ of "help", "h":
expectNoArg(switch, arg, pass, info)
helpOnError(pass)
- of "symbolfiles":
+ of "symbolfiles":
processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
- of "skipcfg":
+ of "skipcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipConfigFile)
- of "skipprojcfg":
+ of "skipprojcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipProjConfigFile)
of "skipusercfg":
@@ -529,17 +527,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "skipparentcfg":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipParentConfigFiles)
- of "genscript":
+ of "genscript":
expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenScript)
of "lib":
expectArg(switch, arg, pass, info)
libpath = processPath(arg, notRelativeToProj=true)
- of "putenv":
+ of "putenv":
expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info)
os.putEnv(key, val)
- of "cc":
+ of "cc":
expectArg(switch, arg, pass, info)
setCC(arg)
of "track":
@@ -548,7 +546,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "trackdirty":
expectArg(switch, arg, pass, info)
trackDirty(arg, info)
- of "suggest":
+ of "suggest":
expectNoArg(switch, arg, pass, info)
gIdeCmd = ideSug
of "def":
@@ -584,7 +582,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info)
-
+
proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
@@ -600,14 +598,14 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here
var bracketLe = strutils.find(p.key, '[')
- if bracketLe >= 0:
+ if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val
processSwitch(key, val, pass, gCmdLineInfo)
- else:
+ else:
processSwitch(p.key, p.val, pass, gCmdLineInfo)
-proc processArgument*(pass: TCmdLinePass; p: OptParser;
+proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool =
if argsCount == 0:
options.command = p.key
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 7ddf44d4ac..ad7d80c850 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -9,71 +9,69 @@
# This module handles the conditional symbols.
-import
+import
strtabs, platform, strutils, idents
-# We need to use a PStringTable here as defined symbols are always guaranteed
+# We need to use a StringTableRef here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: StringTableRef
-proc defineSymbol*(symbol: string) =
+const
+ catNone = "false"
+
+proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"
-proc declareSymbol*(symbol: string) =
- gSymbols[symbol] = "unknown"
+proc undefSymbol*(symbol: string) =
+ gSymbols[symbol] = catNone
-proc undefSymbol*(symbol: string) =
- gSymbols[symbol] = "false"
-
-proc isDefined*(symbol: string): bool =
+proc isDefined*(symbol: string): bool =
if gSymbols.hasKey(symbol):
- result = gSymbols[symbol] == "true"
-
+ result = gSymbols[symbol] != catNone
+ elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
+ result = true
+ elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
+ result = true
+ else:
+ case symbol.normalize
+ of "x86": result = targetCPU == cpuI386
+ of "itanium": result = targetCPU == cpuIa64
+ of "x8664": result = targetCPU == cpuAmd64
+ of "posix", "unix":
+ result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
+ osQnx, osAtari, osAix,
+ osHaiku, osVxWorks, osSolaris, osNetbsd,
+ osFreebsd, osOpenbsd, osMacosx}
+ of "bsd":
+ result = targetOS in {osNetbsd, osFreebsd, osOpenbsd}
+ of "emulatedthreadvars":
+ result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
+ of "msdos": result = targetOS == osDos
+ of "mswindows", "win32": result = targetOS == osWindows
+ of "macintosh": result = targetOS in {osMacos, osMacosx}
+ of "sunos": result = targetOS == osSolaris
+ of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
+ of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
+ of "cpu8": result = CPU[targetCPU].bit == 8
+ of "cpu16": result = CPU[targetCPU].bit == 16
+ of "cpu32": result = CPU[targetCPU].bit == 32
+ of "cpu64": result = CPU[targetCPU].bit == 64
+ of "nimrawsetjmp":
+ result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx}
+ else: discard
+
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
-proc isDeclared*(symbol: PIdent): bool = gSymbols.hasKey(symbol.s)
iterator definedSymbolNames*: string =
for key, val in pairs(gSymbols):
- if val == "true": yield key
+ if val != catNone: yield key
-proc countDefinedSymbols*(): int =
+proc countDefinedSymbols*(): int =
result = 0
for key, val in pairs(gSymbols):
- if val == "true": inc(result)
+ if val != catNone: inc(result)
-# For ease of bootstrapping, we keep them here and not in the global config
-# file for now:
-const
- additionalSymbols = """
- x86 itanium x8664
- msdos mswindows win32 unix posix sunos bsd macintosh RISCOS hpux
- mac
-
- hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
-
- ecmascript js nimrodvm nimffi nimdoc cpp objc
- gcc llvmgcc clang lcc bcc dmc wcc vcc tcc pcc ucc icl
- boehmgc gcmarkandsweep gcgenerational nogc gcUseBitvectors
- endb profiler
- executable guiapp consoleapp library dll staticlib
-
- quick
- release debug
- useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
- nodejs kwin nimfix
-
- usesysassert usegcassert tinyC useFFI
- useStdoutAsStdmsg createNimRtl
- booting fulldebug corruption nimsuperops noSignalHandler useGnuReadline
- noCaas noDocGen noBusyWaiting nativeStackTrace useNodeIds selftest
- reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
- debugExecProcesses pcreDll useLipzipSrc
- preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
-
- nimStdSetjmp nimRawSetjmp nimSigSetjmp
- """.split
-
-proc initDefines*() =
+proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
defineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code:
@@ -90,58 +88,3 @@ proc initDefines*() =
defineSymbol("nimalias")
defineSymbol("nimlocks")
defineSymbol("nimnode")
-
- # add platform specific symbols:
- for c in low(CPU)..high(CPU):
- declareSymbol("cpu" & $CPU[c].bit)
- declareSymbol(normalize(EndianToStr[CPU[c].endian]))
- declareSymbol(CPU[c].name)
- for o in low(platform.OS)..high(platform.OS):
- declareSymbol(platform.OS[o].name)
-
- for a in additionalSymbols:
- declareSymbol(a)
-
- # -----------------------------------------------------------
- case targetCPU
- of cpuI386: defineSymbol("x86")
- of cpuIa64: defineSymbol("itanium")
- of cpuAmd64: defineSymbol("x8664")
- else: discard
- case targetOS
- of osDos:
- defineSymbol("msdos")
- of osWindows:
- defineSymbol("mswindows")
- defineSymbol("win32")
- of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix,
- osHaiku, osVxWorks:
- # these are all 'unix-like'
- defineSymbol("unix")
- defineSymbol("posix")
- of osSolaris:
- defineSymbol("sunos")
- defineSymbol("unix")
- defineSymbol("posix")
- of osNetbsd, osFreebsd, osOpenbsd:
- defineSymbol("unix")
- defineSymbol("bsd")
- defineSymbol("posix")
- of osMacos:
- defineSymbol("macintosh")
- of osMacosx:
- defineSymbol("macintosh")
- defineSymbol("unix")
- defineSymbol("posix")
- else: discard
- defineSymbol("cpu" & $CPU[targetCPU].bit)
- defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
- defineSymbol(CPU[targetCPU].name)
- defineSymbol(platform.OS[targetOS].name)
- declareSymbol("emulatedthreadvars")
- if platform.OS[targetOS].props.contains(ospLacksThreadVars):
- defineSymbol("emulatedthreadvars")
- case targetOS
- of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx:
- defineSymbol("nimRawSetjmp")
- else: discard
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 115a98f84b..1ccb134f26 100644
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -9,41 +9,41 @@
# This module implements a dependency file generator.
-import
+import
os, options, ast, astalgo, msgs, ropes, idents, passes, importer
proc generateDot*(project: string)
-type
+type
TGen = object of TPassContext
module*: PSym
PGen = ref TGen
-var gDotGraph: PRope # the generated DOT file; we need a global variable
+var gDotGraph: Rope # the generated DOT file; we need a global variable
-proc addDependencyAux(importing, imported: string) =
- appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)])
+proc addDependencyAux(importing, imported: string) =
+ addf(gDotGraph, "$1 -> $2;$n", [rope(importing), rope(imported)])
# s1 -> s2_4[label="[0-9]"];
-
-proc addDotDependency(c: PPassContext, n: PNode): PNode =
+
+proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
case n.kind
- of nkImportStmt:
- for i in countup(0, sonsLen(n) - 1):
+ of nkImportStmt:
+ for i in countup(0, sonsLen(n) - 1):
var imported = getModuleName(n.sons[i])
addDependencyAux(g.module.name.s, imported)
- of nkFromStmt, nkImportExceptStmt:
+ of nkFromStmt, nkImportExceptStmt:
var imported = getModuleName(n.sons[0])
addDependencyAux(g.module.name.s, imported)
- of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
+ of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
- else:
+ else:
discard
-proc generateDot(project: string) =
- writeRope(ropef("digraph $1 {$n$2}$n", [
- toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
+proc generateDot(project: string) =
+ writeRope("digraph $1 {$n$2}$n" % [
+ rope(changeFileExt(extractFilename(project), "")), gDotGraph],
changeFileExt(project, "dot"))
proc myOpen(module: PSym): PPassContext =
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 4af69745be..f8489d825f 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -17,9 +17,9 @@ import
importer, sempass2, json, xmltree, cgi, typesrenderer
type
- TSections = array[TSymKind, PRope]
+ TSections = array[TSymKind, Rope]
TDocumentor = object of rstgen.TRstGenerator
- modDesc: PRope # module description
+ modDesc: Rope # module description
id: int # for generating IDs
toc, section: TSections
indexValFilename: string
@@ -82,9 +82,9 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
-proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
- if gCmd != cmdRst2tex: appf(dest, xml, args)
- else: appf(dest, tex, args)
+proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
+ if gCmd != cmdRst2tex: addf(dest, xml, args)
+ else: addf(dest, tex, args)
proc getVarIdx(varnames: openArray[string], id: string): int =
for i in countup(0, high(varnames)):
@@ -92,8 +92,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
return i
result = -1
-proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
- varvalues: openArray[PRope]): PRope =
+proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
+ varvalues: openArray[Rope]): Rope =
var i = 0
var L = len(frmt)
result = nil
@@ -103,11 +103,11 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i) # skip '$'
case frmt[i]
of '#':
- app(result, varvalues[num])
+ add(result, varvalues[num])
inc(num)
inc(i)
of '$':
- app(result, "$")
+ add(result, "$")
inc(i)
of '0'..'9':
var j = 0
@@ -117,7 +117,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
num = j
- app(result, varvalues[j - 1])
+ add(result, varvalues[j - 1])
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
var id = ""
while true:
@@ -125,7 +125,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i)
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
var idx = getVarIdx(varnames, id)
- if idx >= 0: app(result, varvalues[idx])
+ if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id)
of '{':
var id = ""
@@ -137,14 +137,14 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i) # skip }
# search for the variable:
var idx = getVarIdx(varnames, id)
- if idx >= 0: app(result, varvalues[idx])
+ if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id)
else: internalError("ropeFormatNamedVars")
var start = i
while i < L:
if frmt[i] != '$': inc(i)
else: break
- if i - 1 >= start: app(result, substr(frmt, start, i - 1))
+ if i - 1 >= start: add(result, substr(frmt, start, i - 1))
proc genComment(d: PDoc, n: PNode): string =
result = ""
@@ -154,9 +154,9 @@ proc genComment(d: PDoc, n: PNode): string =
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}), result)
-proc genRecComment(d: PDoc, n: PNode): PRope =
+proc genRecComment(d: PDoc, n: PNode): Rope =
if n == nil: return nil
- result = genComment(d, n).toRope
+ result = genComment(d, n).rope
if result == nil:
if n.kind notin {nkEmpty..nkNilLit}:
for i in countup(0, len(n)-1):
@@ -331,9 +331,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return
let
name = getName(d, nameNode)
- nameRope = name.toRope
+ nameRope = name.rope
plainDocstring = getPlainDocstring(n) # call here before genRecComment!
- var result: PRope = nil
+ var result: Rope = nil
var literal, plainName = ""
var kind = tkEof
var comm = genRecComment(d, n) # call this here for the side-effect!
@@ -356,69 +356,69 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
break
of tkComment:
dispA(result, "", "\\spanComment{$1}",
- [toRope(esc(d.target, literal))])
+ [rope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh:
dispA(result, "$1", "\\spanKeyword{$1}",
- [toRope(literal)])
+ [rope(literal)])
of tkOpr:
dispA(result, "$1", "\\spanOperator{$1}",
- [toRope(esc(d.target, literal))])
+ [rope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit:
dispA(result, "$1",
- "\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
+ "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
of tkCharLit:
dispA(result, "$1", "\\spanCharLit{$1}",
- [toRope(esc(d.target, literal))])
+ [rope(esc(d.target, literal))])
of tkIntLit..tkUInt64Lit:
dispA(result, "$1",
- "\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
+ "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
of tkFloatLit..tkFloat128Lit:
dispA(result, "$1",
- "\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
+ "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
of tkSymbol:
dispA(result, "$1",
- "\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
+ "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid:
- app(result, literal)
+ add(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "$1", "\\spanOther{$1}",
- [toRope(esc(d.target, literal))])
+ [rope(esc(d.target, literal))])
inc(d.id)
let
- plainNameRope = toRope(xmltree.escape(plainName.strip))
+ plainNameRope = rope(xmltree.escape(plainName.strip))
cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol)
- plainSymbolRope = toRope(cleanPlainSymbol)
- plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
- itemIDRope = toRope(d.id)
+ plainSymbolRope = rope(cleanPlainSymbol)
+ plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol))
+ itemIDRope = rope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
- symbolOrIdRope = symbolOrId.toRope
- symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
+ symbolOrIdRope = symbolOrId.rope
+ symbolOrIdEncRope = encodeUrl(symbolOrId).rope
- var seeSrcRope: PRope = nil
+ var seeSrcRope: Rope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
# XXX toFilename doesn't really work. We need to ensure that this keeps
# returning a relative path.
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
- ["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
+ ["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
- ["path", "line", "url"], [n.info.toFilename.toRope,
- toRope($n.info.line), urlRope])])
+ ["path", "line", "url"], [n.info.toFilename.rope,
+ rope($n.info.line), urlRope])])
- app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
+ add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
- app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
+ add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
- [toRope(getName(d, nameNode, d.splitAfter)), result, comm,
+ [rope(getName(d, nameNode, d.splitAfter)), result, comm,
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope]))
@@ -436,7 +436,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
if not isVisible(nameNode): return
var
name = getName(d, nameNode)
- comm = genRecComment(d, n).ropeToStr()
+ comm = $genRecComment(d, n)
r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
@@ -453,14 +453,14 @@ proc checkForFalse(n: PNode): bool =
proc traceDeps(d: PDoc, n: PNode) =
const k = skModule
- if d.section[k] != nil: app(d.section[k], ", ")
+ if d.section[k] != nil: add(d.section[k], ", ")
dispA(d.section[k],
"$1",
- "$1", [toRope(getModuleName(n))])
+ "$1", [rope(getModuleName(n))])
proc generateDoc*(d: PDoc, n: PNode) =
case n.kind
- of nkCommentStmt: app(d.modDesc, genComment(d, n))
+ of nkCommentStmt: add(d.modDesc, genComment(d, n))
of nkProcDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skProc)
@@ -540,28 +540,28 @@ proc genSection(d: PDoc, kind: TSymKind) =
"Iterators", "Iterators", "Converters", "Macros", "Templates"
]
if d.section[kind] == nil: return
- var title = sectionNames[kind].toRope
+ var title = sectionNames[kind].rope
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
- ord(kind).toRope, title, toRope(ord(kind) + 50), d.section[kind]])
+ ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
- ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
+ ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
-proc genOutFile(d: PDoc): PRope =
+proc genOutFile(d: PDoc): Rope =
var
- code, content: PRope
+ code, content: Rope
title = ""
var j = 0
var tmp = ""
renderTocEntries(d[], j, 1, tmp)
- var toc = tmp.toRope
+ var toc = tmp.rope
for i in countup(low(TSymKind), high(TSymKind)):
genSection(d, i)
- app(toc, d.toc[i])
+ add(toc, d.toc[i])
if toc != nil:
toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
- for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
+ for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
# Extract the title. Non API modules generate an entry in the index table.
if d.meta[metaTitle].len != 0:
@@ -574,16 +574,16 @@ proc genOutFile(d: PDoc): PRope =
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
"tableofcontents", "moduledesc", "date", "time", "content"],
- [title.toRope, toc, d.modDesc, toRope(getDateStr()),
- toRope(getClockStr()), code])
+ [title.rope, toc, d.modDesc, rope(getDateStr()),
+ rope(getClockStr()), code])
if optCompileOnly notin gGlobalOptions:
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
- [title.toRope, toc, d.modDesc, toRope(getDateStr()),
- toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
- d.meta[metaVersion].toRope, d.analytics.toRope])
+ [title.rope, toc, d.modDesc, rope(getDateStr()),
+ rope(getClockStr()), content, d.meta[metaAuthor].rope,
+ d.meta[metaVersion].rope, d.analytics.rope])
else:
code = content
result = code
@@ -618,7 +618,7 @@ proc commandRstAux(filename, outExt: string) =
#d.modDesc = newMutableRope(30_000)
renderRstToOut(d[], rst, modDesc)
#freezeMutableRope(d.modDesc)
- d.modDesc = toRope(modDesc)
+ d.modDesc = rope(modDesc)
writeOutput(d, filename, outExt)
generateIndex(d)
@@ -635,7 +635,7 @@ proc commandJSON*() =
var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true
var json = generateJson(d, ast)
- var content = newRope(pretty(json))
+ var content = rope(pretty(json))
if optStdout in gGlobalOptions:
writeRope(stdout, content)
@@ -644,12 +644,12 @@ proc commandJSON*() =
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc commandBuildIndex*() =
- var content = mergeIndexes(gProjectFull).toRope
+ var content = mergeIndexes(gProjectFull).rope
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
- ["Index".toRope, nil, nil, toRope(getDateStr()),
- toRope(getClockStr()), content, nil, nil, nil])
+ ["Index".rope, nil, nil, rope(getDateStr()),
+ rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available
writeRope(code, getOutFile("theindex", HtmlExt))
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index a68e7f7348..186a3884df 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -15,9 +15,9 @@
import
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
-type
- TSystemCC* = enum
- ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
+type
+ TSystemCC* = enum
+ ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
ccTcc, ccPcc, ccUcc, ccIcl
TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
@@ -26,8 +26,8 @@ type
hasAssume, # CC has __assume (Visual C extension)
hasGcGuard, # CC supports GC_GUARD to keep stack roots
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
- hasNakedDeclspec, # CC has __declspec(naked)
- hasNakedAttribute # CC has __attribute__((naked))
+ hasDeclspec, # CC has __declspec(X)
+ hasAttribute, # CC has __attribute__((X))
TInfoCCProps* = set[TInfoCCProp]
TInfoCC* = tuple[
name: string, # the short name of the compiler
@@ -54,7 +54,7 @@ type
props: TInfoCCProps] # properties of the C compiler
-# Configuration settings for various compilers.
+# Configuration settings for various compilers.
# When adding new compilers, the cmake sources could be a good reference:
# http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
@@ -85,7 +85,7 @@ compiler gcc:
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
packedPragma: "__attribute__((__packed__))",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
- hasNakedAttribute})
+ hasAttribute})
# LLVM Frontend for GCC/G++
compiler llvmGcc:
@@ -127,7 +127,7 @@ compiler vcc:
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$3$n$1 $2",
packedPragma: "#pragma pack(1)",
- props: {hasCpp, hasAssume, hasNakedDeclspec})
+ props: {hasCpp, hasAssume, hasDeclspec})
# Intel C/C++ Compiler
compiler icl:
@@ -136,7 +136,7 @@ compiler icl:
result = vcc()
else:
result = gcc()
-
+
result.name = "icl"
result.compilerExe = "icl"
result.linkerExe = "icl"
@@ -317,7 +317,7 @@ compiler ucc:
packedPragma: "", # XXX: not supported yet
props: {})
-const
+const
CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
gcc(),
llvmGcc(),
@@ -346,7 +346,7 @@ var
proc libNameTmpl(): string {.inline.} =
result = if targetOS == osWindows: "$1.lib" else: "lib$1.a"
-var
+var
toLink, toCompile, externalToCompile: TLinkedList
linkOptions: string = ""
compileOptions: string = ""
@@ -355,8 +355,8 @@ var
proc nameToCC*(name: string): TSystemCC =
## Returns the kind of compiler referred to by `name`, or ccNone
## if the name doesn't refer to any known compiler.
- for i in countup(succ(ccNone), high(TSystemCC)):
- if cmpIgnoreStyle(name, CC[i].name) == 0:
+ for i in countup(succ(ccNone), high(TSystemCC)):
+ if cmpIgnoreStyle(name, CC[i].name) == 0:
return i
result = ccNone
@@ -375,8 +375,8 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
optCompileOnly notin gGlobalOptions:
- let fullCCname = platform.CPU[targetCPU].name & '.' &
- platform.OS[targetOS].name & '.' &
+ let fullCCname = platform.CPU[targetCPU].name & '.' &
+ platform.OS[targetOS].name & '.' &
CC[c].name & fullSuffix
result = getConfigVar(fullCCname)
if result.len == 0:
@@ -385,7 +385,7 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
else:
result = getConfigVar(CC[c].name & fullSuffix)
-proc setCC*(ccname: string) =
+proc setCC*(ccname: string) =
cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always")
@@ -394,18 +394,18 @@ proc setCC*(ccname: string) =
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
-proc addOpt(dest: var string, src: string) =
+proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
add(dest, src)
proc addLinkOption*(option: string) =
addOpt(linkOptions, option)
-proc addCompileOption*(option: string) =
- if strutils.find(compileOptions, option, 0) < 0:
+proc addCompileOption*(option: string) =
+ if strutils.find(compileOptions, option, 0) < 0:
addOpt(compileOptions, option)
-proc initVars*() =
+proc initVars*() =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
@@ -414,10 +414,10 @@ proc initVars*() =
if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path")
-proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
+proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(cfile, createSubDir)
-proc toObjFile*(filename: string): string =
+proc toObjFile*(filename: string): string =
# Object file for compilation
result = changeFileExt(filename, CC[cCompiler].objExt)
@@ -449,22 +449,22 @@ proc execExternalProgram*(cmd: string, prettyCmd = "") =
if execWithEcho(cmd, prettyCmd) != 0:
rawMessage(errExecutionOfProgramFailed, "")
-proc generateScript(projectFile: string, script: PRope) =
+proc generateScript(projectFile: string, script: Rope) =
let (dir, name, ext) = splitFile(projectFile)
- writeRope(script, dir / addFileExt("compile_" & name,
+ writeRope(script, dir / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt))
-proc getOptSpeed(c: TSystemCC): string =
+proc getOptSpeed(c: TSystemCC): string =
result = getConfigVar(c, ".options.speed")
if result == "":
result = CC[c].optSpeed # use default settings from this file
-proc getDebug(c: TSystemCC): string =
+proc getDebug(c: TSystemCC): string =
result = getConfigVar(c, ".options.debug")
if result == "":
result = CC[c].debug # use default settings from this file
-proc getOptSize(c: TSystemCC): string =
+proc getOptSize(c: TSystemCC): string =
result = getConfigVar(c, ".options.size")
if result == "":
result = CC[c].optSize # use default settings from this file
@@ -476,7 +476,7 @@ proc noAbsolutePaths: bool {.inline.} =
# `optGenMapping` is included here for niminst.
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
-const
+const
specialFileA = 42
specialFileB = 42
@@ -488,7 +488,7 @@ proc add(s: var string, many: openArray[string]) =
proc cFileSpecificOptions(cfilename: string): string =
result = compileOptions
var trunk = splitFile(cfilename).name
- if optCDebug in gGlobalOptions:
+ if optCDebug in gGlobalOptions:
var key = trunk & ".debug"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getDebug(cCompiler))
@@ -528,17 +528,17 @@ proc getLinkerExe(compiler: TSystemCC): string =
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: compiler.getCompilerExe
-proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
+proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
var c = cCompiler
var options = cFileSpecificOptions(cfilename)
var exe = getConfigVar(c, ".exe")
if exe.len == 0: exe = c.getCompilerExe
-
+
if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and
ospNeedsPIC in platform.OS[targetOS].props:
add(options, ' ' & CC[c].pic)
-
+
var includeCmd, compilePattern: string
if not noAbsolutePaths():
# compute include paths:
@@ -551,7 +551,7 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
else:
includeCmd = ""
compilePattern = c.getCompilerExe
-
+
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
else: cfilename
var objfile = if not isExternal or noAbsolutePaths():
@@ -580,14 +580,14 @@ proc footprint(filename: string): TCrc32 =
extccomp.CC[extccomp.cCompiler].name ><
getCompileCFileCmd(filename, true)
-proc externalFileChanged(filename: string): bool =
+proc externalFileChanged(filename: string): bool =
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
return false
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
var currentCrc = int(footprint(filename))
var f: File
- if open(f, crcFile, fmRead):
+ if open(f, crcFile, fmRead):
var line = newStringOfCap(40)
if not f.readLine(line): line = "0"
close(f)
@@ -595,7 +595,7 @@ proc externalFileChanged(filename: string): bool =
result = oldCrc != currentCrc
else:
result = true
- if result:
+ if result:
if open(f, crcFile, fmWrite):
f.writeln($currentCrc)
close(f)
@@ -604,41 +604,41 @@ proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename)
-proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
+proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
prettyCmds: var TStringSeq, isExternal: bool) =
var it = PStrEntry(list.head)
- while it != nil:
+ while it != nil:
inc(fileCounter) # call the C compiler for the .c file:
var compileCmd = getCompileCFileCmd(it.data, isExternal)
- if optCompileOnly notin gGlobalOptions:
+ if optCompileOnly notin gGlobalOptions:
add(cmds, compileCmd)
let (dir, name, ext) = splitFile(it.data)
add(prettyCmds, "CC: " & name)
- if optGenScript in gGlobalOptions:
- app(script, compileCmd)
- app(script, tnl)
+ if optGenScript in gGlobalOptions:
+ add(script, compileCmd)
+ add(script, tnl)
it = PStrEntry(it.next)
proc callCCompiler*(projectfile: string) =
- var
+ var
linkCmd, buildgui, builddll: string
- if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
+ if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
fileCounter = 0
var c = cCompiler
- var script: PRope = nil
+ var script: Rope = nil
var cmds: TStringSeq = @[]
var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
compileCFile(toCompile, script, cmds, prettyCmds, false)
compileCFile(externalToCompile, script, cmds, prettyCmds, true)
- if optCompileOnly notin gGlobalOptions:
+ if optCompileOnly notin gGlobalOptions:
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
- if gNumberOfProcessors <= 1:
- for i in countup(0, high(cmds)):
+ if gNumberOfProcessors <= 1:
+ for i in countup(0, high(cmds)):
res = execWithEcho(cmds[i])
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
elif optListCmd in gGlobalOptions or gVerbosity > 1:
@@ -668,7 +668,8 @@ proc callCCompiler*(projectfile: string) =
it = PStrEntry(it.next)
if optGenStaticLib in gGlobalOptions:
- linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
+ let name = splitFile(gProjectName).name
+ linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name),
"objfiles", objfiles]
else:
var linkerExe = getConfigVar(c, ".linkerexe")
@@ -685,13 +686,13 @@ proc callCCompiler*(projectfile: string) =
else:
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
builddll = ""
- if options.outFile.len > 0:
+ if options.outFile.len > 0:
exefile = options.outFile.expandTilde
if not noAbsolutePaths():
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
exefile = quoteShell(exefile)
- let linkOptions = getLinkOptions() & " " &
+ let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
@@ -710,30 +711,30 @@ proc callCCompiler*(projectfile: string) =
else:
linkCmd = ""
if optGenScript in gGlobalOptions:
- app(script, linkCmd)
- app(script, tnl)
+ add(script, linkCmd)
+ add(script, tnl)
generateScript(projectfile, script)
-proc genMappingFiles(list: TLinkedList): PRope =
+proc genMappingFiles(list: TLinkedList): Rope =
var it = PStrEntry(list.head)
- while it != nil:
- appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
+ while it != nil:
+ addf(result, "--file:r\"$1\"$N", [rope(it.data)])
it = PStrEntry(it.next)
-proc writeMapping*(gSymbolMapping: PRope) =
- if optGenMapping notin gGlobalOptions: return
- var code = toRope("[C_Files]\n")
- app(code, genMappingFiles(toCompile))
- app(code, genMappingFiles(externalToCompile))
- app(code, "\n[C_Compiler]\nFlags=")
- app(code, strutils.escape(getCompileOptions()))
-
- app(code, "\n[Linker]\nFlags=")
- app(code, strutils.escape(getLinkOptions() & " " &
+proc writeMapping*(gSymbolMapping: Rope) =
+ if optGenMapping notin gGlobalOptions: return
+ var code = rope("[C_Files]\n")
+ add(code, genMappingFiles(toCompile))
+ add(code, genMappingFiles(externalToCompile))
+ add(code, "\n[C_Compiler]\nFlags=")
+ add(code, strutils.escape(getCompileOptions()))
+
+ add(code, "\n[Linker]\nFlags=")
+ add(code, strutils.escape(getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")))
- app(code, "\n[Environment]\nlibpath=")
- app(code, strutils.escape(libpath))
-
- appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
+ add(code, "\n[Environment]\nlibpath=")
+ add(code, strutils.escape(libpath))
+
+ addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
diff --git a/compiler/guards.nim b/compiler/guards.nim
index cedd2be2bd..df2c1dd75f 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -22,7 +22,8 @@ const
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
mLtCh, mLtB, mLtPtr, mLtStr}
- someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
+ someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
+ mXLenStr, mXLenSeq}
someIn = {mInRange, mInSet}
@@ -34,8 +35,8 @@ const
someMul = {mMulI, mMulI64, mMulF64}
someDiv = {mDivI, mDivI64, mDivF64}
someMod = {mModI, mModI64}
- someMax = {mMaxI, mMaxI64, mMaxF64}
- someMin = {mMinI, mMinI64, mMinF64}
+ someMax = {mMaxI, mMaxF64}
+ someMin = {mMinI, mMinF64}
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
proc isLocation(n: PNode): bool = not n.isValue
@@ -122,7 +123,7 @@ proc neg(n: PNode): PNode =
let eAsNode = newIntNode(nkIntLit, e.sym.position)
if not inSet(n.sons[1], eAsNode): s.add eAsNode
result.sons[1] = s
- elif lengthOrd(t) < 1000:
+ elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
result.sons[1] = complement(n.sons[1])
else:
# not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4
@@ -907,5 +908,5 @@ proc buildProperFieldCheck(access, check: PNode): PNode =
proc checkFieldAccess*(m: TModel, n: PNode) =
for i in 1..n.len-1:
let check = buildProperFieldCheck(n.sons[0], n.sons[i])
- if m.doesImply(check) != impYes:
+ if check != nil and m.doesImply(check) != impYes:
message(n.info, warnProveField, renderTree(n.sons[0])); break
diff --git a/compiler/installer.ini b/compiler/installer.ini
index b4160cab3e..fff82cb5b1 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -47,7 +47,7 @@ Start: "doc/overview.html"
[Other]
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
-Files: "configure;makefile"
+Files: "makefile"
Files: "*.ini"
Files: "koch.nim"
@@ -62,7 +62,7 @@ Files: "icons/koch_icon.o"
Files: "compiler/readme.txt"
Files: "compiler/installer.ini"
-Files: "compiler/nim.nimrod.cfg"
+Files: "compiler/nim.nim.cfg"
Files: "compiler/*.nim"
Files: "doc/*.txt"
Files: "doc/manual/*.txt"
@@ -70,6 +70,10 @@ Files: "doc/*.nim"
Files: "doc/*.cfg"
Files: "compiler/nimfix/*.nim"
Files: "compiler/nimfix/*.cfg"
+Files: "compiler/nimsuggest/*.nim"
+Files: "compiler/nimsuggest/*.cfg"
+Files: "compiler/plugins/locals/*.nim"
+Files: "compiler/plugins/active.nim"
Files: "tools/*.nim"
Files: "tools/*.cfg"
Files: "tools/*.tmpl"
@@ -97,13 +101,8 @@ Files: "lib/pure/concurrency/*.cfg"
Files: "lib/impure/*.nim"
Files: "lib/wrappers/*.nim"
-Files: "lib/wrappers/cairo/*.nim"
-Files: "lib/wrappers/gtk/*.nim"
-Files: "lib/wrappers/lua/*.nim"
-Files: "lib/wrappers/opengl/*.nim"
Files: "lib/wrappers/readline/*.nim"
Files: "lib/wrappers/sdl/*.nim"
-Files: "lib/wrappers/x11/*.nim"
Files: "lib/wrappers/zip/*.nim"
Files: "lib/wrappers/zip/libzip_all.c"
@@ -115,8 +114,6 @@ Files: "lib/packages/docutils/*.nim"
[Other]
Files: "examples/*.nim"
-Files: "examples/gtk/*.nim"
-Files: "examples/0mq/*.nim"
Files: "examples/c++iface/*.nim"
Files: "examples/objciface/*.nim"
Files: "examples/cross_calculator/"
@@ -126,12 +123,109 @@ Files: "examples/*.txt"
Files: "examples/*.cfg"
Files: "examples/*.tmpl"
+Files: "tests/actiontable/*.nim"
+Files: "tests/alias/*.nim"
+Files: "tests/ambsym/*.nim"
+Files: "tests/array/*.nim"
+Files: "tests/assign/*.nim"
+Files: "tests/astoverload/*.nim"
+Files: "tests/async/*.nim"
+Files: "tests/benchmarks/*.nim"
+Files: "tests/bind/*.nim"
+Files: "tests/borrow/*.nim"
+Files: "tests/casestmt/*.nim"
+Files: "tests/ccgbugs/*.nim"
+Files: "tests/clearmsg/*.nim"
+Files: "tests/closure/*.nim"
+Files: "tests/cnstseq/*.nim"
+Files: "tests/collections/*.nim"
+Files: "tests/compiles/*.nim"
+Files: "tests/concat/*.nim"
+Files: "tests/concepts/*.nim"
+Files: "tests/constr/*.nim"
+Files: "tests/constraints/*.nim"
+Files: "tests/controlflow/*.nim"
+Files: "tests/converter/*.nim"
+Files: "tests/cpp/*.nim"
+Files: "tests/defaultprocparam/*.nim"
+Files: "tests/deprecated/*.nim"
+Files: "tests/destructor/*.nim"
+Files: "tests/dir with space/*.nim"
+Files: "tests/discard/*.nim"
+Files: "tests/distinct/*.nim"
+Files: "tests/dll/*.nim"
+Files: "tests/effects/*.nim"
+Files: "tests/enum/*.nim"
+Files: "tests/exception/*.nim"
+Files: "tests/exprs/*.nim"
+Files: "tests/fields/*.nim"
+Files: "tests/float/*.nim"
+Files: "tests/friends/*.nim"
+Files: "tests/gc/*.nim"
+Files: "tests/generics/*.nim"
+Files: "tests/gensym/*.nim"
+Files: "tests/global/*.nim"
+Files: "tests/implicit/*.nim"
+Files: "tests/init/*.nim"
+Files: "tests/iter/*.nim"
+Files: "tests/js/*.nim"
+Files: "tests/js/*.cfg"
+Files: "tests/let/*.nim"
+Files: "tests/lexer/*.nim"
+Files: "tests/lookups/*.nim"
+Files: "tests/macros/*.nim"
+Files: "tests/magics/*.nim"
+Files: "tests/metatype/*.nim"
+Files: "tests/method/*.nim"
+Files: "tests/misc/*.nim"
+Files: "tests/modules/*.nim"
+Files: "tests/namedparams/*.nim"
+Files: "tests/notnil/*.nim"
+Files: "tests/objects/*.nim"
+Files: "tests/objvariant/*.nim"
+Files: "tests/openarray/*.nim"
+Files: "tests/osproc/*.nim"
+Files: "tests/overflw/*.nim"
+Files: "tests/overload/*.nim"
+Files: "tests/parallel/*.nim"
+Files: "tests/parallel/*.cfg"
+Files: "tests/parser/*.nim"
+Files: "tests/pragmas/*.nim"
+Files: "tests/proc/*.nim"
+Files: "tests/procvar/*.nim"
+Files: "tests/range/*.nim"
+Files: "tests/rodfiles/*.nim"
+Files: "tests/seq/*.nim"
+Files: "tests/sets/*.nim"
+Files: "tests/showoff/*.nim"
+Files: "tests/specialops/*.nim"
+Files: "tests/stdlib/*.nim"
+Files: "tests/system/*.nim"
+Files: "tests/template/*.nim"
+Files: "tests/testament/*.nim"
+Files: "tests/testdata/*.nim"
+Files: "tests/threads/*.nim"
+Files: "tests/threads/*.cfg"
+Files: "tests/trmacros/*.nim"
+Files: "tests/tuples/*.nim"
+Files: "tests/typerel/*.nim"
+Files: "tests/types/*.nim"
+Files: "tests/usingstmt/*.nim"
+Files: "tests/varres/*.nim"
+Files: "tests/varstmt/*.nim"
+Files: "tests/vm/*.nim"
+Files: "tests/readme.txt"
+Files: "tests/testament/css/*.css"
+Files: "tests/testament/*.cfg"
+Files: "lib/pure/unidecode/unidecode.dat"
[Windows]
Files: "bin/nim.exe"
-Files: "bin/nim_debug.exe"
Files: "bin/c2nim.exe"
Files: "bin/nimgrep.exe"
+Files: "bin/nimsuggest.exe"
+Files: "bin/nimble.exe"
+Files: "bin/*.dll"
Files: "dist/*.dll"
Files: "koch.exe"
@@ -142,7 +236,7 @@ BinPath: r"bin;dist\mingw\bin;dist"
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
-Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe"
+Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe"
; for now only NSIS supports optional downloads
[UnixBin]
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 563f0c866e..704713243f 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -59,9 +59,9 @@ type
TCompRes = object
kind: TResKind
typ: TJSTypeKind
- res: PRope # result part; index if this is an
+ res: Rope # result part; index if this is an
# (address, index)-tuple
- address: PRope # address of an (address, index)-tuple
+ address: Rope # address of an (address, index)-tuple
TBlock = object
id: int # the ID of the label; positive means that it
@@ -69,7 +69,7 @@ type
isLoop: bool # whether it's a 'block' or 'while'
TGlobals = object
- typeInfo, code: PRope
+ typeInfo, code: Rope
forwarded: seq[PSym]
generatedSyms: IntSet
typeInfoGenerated: IntSet
@@ -79,7 +79,7 @@ type
TProc = object
procDef: PNode
prc: PSym
- locals, body: PRope
+ locals, body: Rope
options: TOptions
module: BModule
g: PGlobals
@@ -104,13 +104,13 @@ proc initCompRes(r: var TCompRes) =
r.typ = etyNone
r.kind = resNone
-proc rdLoc(a: TCompRes): PRope {.inline.} =
+proc rdLoc(a: TCompRes): Rope {.inline.} =
result = a.res
when false:
if a.typ != etyBaseIndex:
result = a.res
else:
- result = ropef("$1[$2]", a.address, a.res)
+ result = "$1[$2]" % [a.address, a.res]
proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc =
@@ -124,7 +124,7 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
const
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
- tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
+ tySet, tyBigNum, tyVarargs}
proc mapType(typ: PType): TJSTypeKind =
let t = skipTypes(typ, abstractInst)
@@ -155,21 +155,22 @@ proc mapType(typ: PType): TJSTypeKind =
of tyProc: result = etyProc
of tyCString: result = etyString
-proc mangleName(s: PSym): PRope =
+proc mangleName(s: PSym): Rope =
result = s.loc.r
if result == nil:
- result = toRope(mangle(s.name.s))
- app(result, "_")
- app(result, toRope(s.id))
+ result = rope(mangle(s.name.s))
+ add(result, "_")
+ add(result, rope(s.id))
s.loc.r = result
-proc makeJSString(s: string): PRope = strutils.escape(s).toRope
+proc makeJSString(s: string): Rope =
+ (if s.isNil: "null".rope else: strutils.escape(s).rope)
include jstypes
proc gen(p: PProc, n: PNode, r: var TCompRes)
proc genStmt(p: PProc, n: PNode)
-proc genProc(oldProc: PProc, prc: PSym): PRope
+proc genProc(oldProc: PProc, prc: PSym): Rope
proc genConstant(p: PProc, c: PSym)
proc useMagic(p: PProc, name: string) =
@@ -178,7 +179,7 @@ proc useMagic(p: PProc, name: string) =
if s != nil:
internalAssert s.kind in {skProc, skMethod, skConverter}
if not p.g.generatedSyms.containsOrIncl(s.id):
- app(p.g.code, genProc(p, s))
+ add(p.g.code, genProc(p, s))
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
@@ -196,10 +197,10 @@ proc isSimpleExpr(n: PNode): bool =
elif n.isAtom:
result = true
-proc getTemp(p: PProc): PRope =
+proc getTemp(p: PProc): Rope =
inc(p.unique)
- result = ropef("Tmp$1", [toRope(p.unique)])
- appf(p.locals, "var $1;$n" | "local $1;$n", [result])
+ result = "Tmp$1" % [rope(p.unique)]
+ addf(p.locals, "var $1;$n" | "local $1;$n", [result])
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
@@ -208,7 +209,7 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
gen(p, a, x)
gen(p, b, y)
r.kind = resExpr
- r.res = ropef("($1 && $2)" | "($1 and $2)", [x.rdLoc, y.rdLoc])
+ r.res = ("($1 && $2)" | "($1 and $2)") % [x.rdLoc, y.rdLoc]
else:
r.res = p.getTemp
r.kind = resVal
@@ -222,11 +223,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
# tmp = b
# tmp
gen(p, a, x)
- p.body.appf("if (!$1) $2 = false; else {" |
- "if not $1 then $2 = false; else", x.rdLoc, r.rdLoc)
+ p.body.addf("if (!$1) $2 = false; else {" |
+ "if not $1 then $2 = false; else", [x.rdLoc, r.rdLoc])
gen(p, b, y)
- p.body.appf("$2 = $1; }" |
- "$2 = $1 end", y.rdLoc, r.rdLoc)
+ p.body.addf("$2 = $1; }" |
+ "$2 = $1 end", [y.rdLoc, r.rdLoc])
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
@@ -235,16 +236,16 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
gen(p, a, x)
gen(p, b, y)
r.kind = resExpr
- r.res = ropef("($1 || $2)" | "($1 or $2)", [x.rdLoc, y.rdLoc])
+ r.res = ("($1 || $2)" | "($1 or $2)") % [x.rdLoc, y.rdLoc]
else:
r.res = p.getTemp
r.kind = resVal
gen(p, a, x)
- p.body.appf("if ($1) $2 = true; else {" |
- "if $1 then $2 = true; else", x.rdLoc, r.rdLoc)
+ p.body.addf("if ($1) $2 = true; else {" |
+ "if $1 then $2 = true; else", [x.rdLoc, r.rdLoc])
gen(p, b, y)
- p.body.appf("$2 = $1; }" |
- "$2 = $1 end", y.rdLoc, r.rdLoc)
+ p.body.addf("$2 = $1; }" |
+ "$2 = $1 end", [y.rdLoc, r.rdLoc])
type
TMagicFrmt = array[0..3, string]
@@ -280,8 +281,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
- ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
- ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -325,7 +324,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "!($1)", "!($1)"], # Not
["", "", "+($1)", "+($1)"], # UnaryPlusI
["", "", "~($1)", "~($1)"], # BitnotI
- ["", "", "+($1)", "+($1)"], # UnaryPlusI64
["", "", "~($1)", "~($1)"], # BitnotI64
["", "", "+($1)", "+($1)"], # UnaryPlusF64
["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -382,8 +380,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
- ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
- ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
@@ -427,7 +423,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "not ($1)", "not ($1)"], # Not
["", "", "+($1)", "+($1)"], # UnaryPlusI
["", "", "~($1)", "~($1)"], # BitnotI
- ["", "", "+($1)", "+($1)"], # UnaryPlusI64
["", "", "~($1)", "~($1)"], # BitnotI64
["", "", "+($1)", "+($1)"], # UnaryPlusF64
["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -460,7 +455,7 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
useMagic(p, magic)
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
- r.res = ropef(frmt, [x.rdLoc, y.rdLoc])
+ r.res = frmt % [x.rdLoc, y.rdLoc]
r.kind = resExpr
proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@@ -469,13 +464,13 @@ proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
gen(p, n.sons[3], z)
- r.res = ropef(frmt, [x.rdLoc, y.rdLoc, z.rdLoc])
+ r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
r.kind = resExpr
proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
useMagic(p, magic)
gen(p, n.sons[1], r)
- r.res = ropef(frmt, [r.rdLoc])
+ r.res = frmt % [r.rdLoc]
r.kind = resExpr
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
@@ -486,10 +481,10 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
if sonsLen(n) > 2:
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
- r.res = ropef(ops[op][i + 2], [x.rdLoc, y.rdLoc])
+ r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
else:
gen(p, n.sons[1], r)
- r.res = ropef(ops[op][i + 2], [r.rdLoc])
+ r.res = ops[op][i + 2] % [r.rdLoc]
r.kind = resExpr
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
@@ -498,16 +493,16 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
proc genLineDir(p: PProc, n: PNode) =
let line = toLinenumber(n.info)
if optLineDir in p.options:
- appf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
- [toRope(toFilename(n.info)), toRope(line)])
+ addf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
+ [rope(toFilename(n.info)), rope(line)])
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
((p.prc == nil) or sfPure notin p.prc.flags):
useMagic(p, "endb")
- appf(p.body, "endb($1);$n", [toRope(line)])
+ addf(p.body, "endb($1);$n", [rope(line)])
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
((p.prc == nil) or not (sfPure in p.prc.flags)):
- appf(p.body, "F.line = $1;$n", [toRope(line)])
+ addf(p.body, "F.line = $1;$n", [rope(line)])
proc genWhileStmt(p: PProc, n: PNode) =
var
@@ -519,21 +514,21 @@ proc genWhileStmt(p: PProc, n: PNode) =
setLen(p.blocks, length + 1)
p.blocks[length].id = -p.unique
p.blocks[length].isLoop = true
- let labl = p.unique.toRope
- appf(p.body, "L$1: while (true) {$n" | "while true do$n", labl)
+ let labl = p.unique.rope
+ addf(p.body, "L$1: while (true) {$n" | "while true do$n", [labl])
gen(p, n.sons[0], cond)
- appf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
+ addf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
[cond.res, labl])
genStmt(p, n.sons[1])
- appf(p.body, "}$n" | "end ::L$#::$n", [labl])
+ addf(p.body, "}$n" | "end ::L$#::$n", [labl])
setLen(p.blocks, length)
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
if src.kind != resNone:
if dest.kind != resNone:
- p.body.appf("$1 = $2;$n", dest.rdLoc, src.rdLoc)
+ p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
else:
- p.body.appf("$1;$n", src.rdLoc)
+ p.body.addf("$1;$n", [src.rdLoc])
src.kind = resNone
src.res = nil
@@ -562,52 +557,52 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resVal
r.res = getTemp(p)
inc(p.unique)
- var safePoint = ropef("Tmp$1", [toRope(p.unique)])
- appf(p.body,
+ var safePoint = "Tmp$1" % [rope(p.unique)]
+ addf(p.body,
"var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
"local $1 = pcall(",
[safePoint])
- if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl)
- appf(p.body, "try {$n" | "function()$n")
+ if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
+ addf(p.body, "try {$n" | "function()$n", [])
var length = sonsLen(n)
var a: TCompRes
gen(p, n.sons[0], a)
moveInto(p, a, r)
var i = 1
if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
- appf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n")
+ addf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n", [])
elif p.target == targetLua:
- appf(p.body, "end)$n")
+ addf(p.body, "end)$n", [])
while i < length and n.sons[i].kind == nkExceptBranch:
let blen = sonsLen(n.sons[i])
if blen == 1:
# general except section:
- if i > 1: appf(p.body, "else {$n" | "else$n")
+ if i > 1: addf(p.body, "else {$n" | "else$n", [])
gen(p, n.sons[i].sons[0], a)
moveInto(p, a, r)
- if i > 1: appf(p.body, "}$n" | "end$n")
+ if i > 1: addf(p.body, "}$n" | "end$n", [])
else:
- var orExpr: PRope = nil
+ var orExpr: Rope = nil
useMagic(p, "isObj")
for j in countup(0, blen - 2):
if n.sons[i].sons[j].kind != nkType:
internalError(n.info, "genTryStmt")
- if orExpr != nil: app(orExpr, "||" | " or ")
- appf(orExpr, "isObj($1.exc.m_type, $2)",
+ if orExpr != nil: add(orExpr, "||" | " or ")
+ addf(orExpr, "isObj($1.exc.m_type, $2)",
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
- if i > 1: app(p.body, "else ")
- appf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
+ if i > 1: add(p.body, "else ")
+ addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
[safePoint, orExpr])
gen(p, n.sons[i].sons[blen - 1], a)
moveInto(p, a, r)
- appf(p.body, "}$n" | "end$n")
+ addf(p.body, "}$n" | "end$n", [])
inc(i)
if p.target == targetJS:
- app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
+ add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
if i < length and n.sons[i].kind == nkFinally:
genStmt(p, n.sons[i].sons[0])
if p.target == targetJS:
- app(p.body, "}" & tnl)
+ add(p.body, "}" & tnl)
if p.target == targetLua:
# we need to repeat the finally block for Lua ...
if i < length and n.sons[i].kind == nkFinally:
@@ -620,11 +615,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
gen(p, n.sons[0], a)
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
useMagic(p, "raiseException")
- appf(p.body, "raiseException($1, $2);$n",
+ addf(p.body, "raiseException($1, $2);$n",
[a.rdLoc, makeJSString(typ.sym.name.s)])
else:
useMagic(p, "reraiseException")
- app(p.body, "reraiseException();" & tnl)
+ add(p.body, "reraiseException();" & tnl)
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var
@@ -634,9 +629,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
if stringSwitch:
useMagic(p, "toJSStr")
- appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
+ addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
else:
- appf(p.body, "switch ($1) {$n", [cond.rdLoc])
+ addf(p.body, "switch ($1) {$n", [cond.rdLoc])
if not isEmptyType(n.typ):
r.kind = resVal
r.res = getTemp(p)
@@ -650,27 +645,27 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var v = copyNode(e.sons[0])
while v.intVal <= e.sons[1].intVal:
gen(p, v, cond)
- appf(p.body, "case $1: ", [cond.rdLoc])
+ addf(p.body, "case $1: ", [cond.rdLoc])
inc(v.intVal)
else:
if stringSwitch:
case e.kind
- of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ",
+ of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
[makeJSString(e.strVal)])
else: internalError(e.info, "jsgen.genCaseStmt: 2")
else:
gen(p, e, cond)
- appf(p.body, "case $1: ", [cond.rdLoc])
+ addf(p.body, "case $1: ", [cond.rdLoc])
gen(p, lastSon(it), stmt)
moveInto(p, stmt, r)
- appf(p.body, "$nbreak;$n")
+ addf(p.body, "$nbreak;$n", [])
of nkElse:
- appf(p.body, "default: $n")
+ addf(p.body, "default: $n", [])
gen(p, it.sons[0], stmt)
moveInto(p, stmt, r)
- appf(p.body, "break;$n")
+ addf(p.body, "break;$n", [])
else: internalError(it.info, "jsgen.genCaseStmt")
- appf(p.body, "}$n")
+ addf(p.body, "}$n", [])
proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
var
@@ -681,7 +676,7 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
if stringSwitch:
useMagic(p, "eqStr")
let tmp = getTemp(p)
- appf(p.body, "$1 = $2;$n", [tmp, cond.rdLoc])
+ addf(p.body, "$1 = $2;$n", [tmp, cond.rdLoc])
if not isEmptyType(n.typ):
r.kind = resVal
r.res = getTemp(p)
@@ -689,34 +684,34 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
let it = n.sons[i]
case it.kind
of nkOfBranch:
- if i != 1: appf(p.body, "$nelsif ")
- else: appf(p.body, "if ")
+ if i != 1: addf(p.body, "$nelsif ", [])
+ else: addf(p.body, "if ", [])
for j in countup(0, sonsLen(it) - 2):
- if j != 0: app(p.body, " or ")
+ if j != 0: add(p.body, " or ")
let e = it.sons[j]
if e.kind == nkRange:
var ia, ib: TCompRes
gen(p, e.sons[0], ia)
gen(p, e.sons[1], ib)
- appf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
+ addf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
else:
if stringSwitch:
case e.kind
- of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)",
+ of nkStrLit..nkTripleStrLit: addf(p.body, "eqStr($1, $2)",
[tmp, makeJSString(e.strVal)])
else: internalError(e.info, "jsgen.genCaseStmt: 2")
else:
gen(p, e, cond)
- appf(p.body, "$1 == $2", [tmp, cond.rdLoc])
- appf(p.body, " then$n")
+ addf(p.body, "$1 == $2", [tmp, cond.rdLoc])
+ addf(p.body, " then$n", [])
gen(p, lastSon(it), stmt)
moveInto(p, stmt, r)
of nkElse:
- appf(p.body, "else$n")
+ addf(p.body, "else$n", [])
gen(p, it.sons[0], stmt)
moveInto(p, stmt, r)
else: internalError(it.info, "jsgen.genCaseStmt")
- appf(p.body, "$nend$n")
+ addf(p.body, "$nend$n", [])
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
inc(p.unique)
@@ -730,9 +725,9 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
setLen(p.blocks, idx + 1)
p.blocks[idx].id = - p.unique # negative because it isn't used yet
let labl = p.unique
- appf(p.body, "L$1: do {$n" | "", labl.toRope)
+ addf(p.body, "L$1: do {$n" | "", [labl.rope])
gen(p, n.sons[1], r)
- appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope)
+ addf(p.body, "} while(false);$n" | "$n::L$#::$n", [labl.rope])
setLen(p.blocks, idx)
proc genBreakStmt(p: PProc, n: PNode) =
@@ -751,15 +746,15 @@ proc genBreakStmt(p: PProc, n: PNode) =
if idx < 0 or not p.blocks[idx].isLoop:
internalError(n.info, "no loop to break")
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
- appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)])
+ addf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [rope(p.blocks[idx].id)])
proc genAsmStmt(p: PProc, n: PNode) =
genLineDir(p, n)
assert(n.kind == nkAsmStmt)
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind
- of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
- of nkSym: app(p.body, mangleName(n.sons[i].sym))
+ of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
+ of nkSym: add(p.body, mangleName(n.sons[i].sym))
else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
@@ -772,35 +767,35 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
let it = n.sons[i]
if sonsLen(it) != 1:
if i > 0:
- appf(p.body, "else {$n" | "else$n", [])
+ addf(p.body, "else {$n" | "else$n", [])
inc(toClose)
gen(p, it.sons[0], cond)
- appf(p.body, "if ($1) {$n" | "if $# then$n", cond.rdLoc)
+ addf(p.body, "if ($1) {$n" | "if $# then$n", [cond.rdLoc])
gen(p, it.sons[1], stmt)
else:
# else part:
- appf(p.body, "else {$n" | "else$n")
+ addf(p.body, "else {$n" | "else$n", [])
gen(p, it.sons[0], stmt)
moveInto(p, stmt, r)
- appf(p.body, "}$n" | "end$n")
+ addf(p.body, "}$n" | "end$n", [])
if p.target == targetJS:
- app(p.body, repeat('}', toClose) & tnl)
+ add(p.body, repeat('}', toClose) & tnl)
else:
- for i in 1..toClose: appf(p.body, "end$n")
+ for i in 1..toClose: addf(p.body, "end$n", [])
-proc generateHeader(p: PProc, typ: PType): PRope =
+proc generateHeader(p: PProc, typ: PType): Rope =
result = nil
for i in countup(1, sonsLen(typ.n) - 1):
- if result != nil: app(result, ", ")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
+ if result != nil: add(result, ", ")
var name = mangleName(param)
- app(result, name)
+ add(result, name)
if mapType(param.typ) == etyBaseIndex:
- app(result, ", ")
- app(result, name)
- app(result, "_Idx")
+ add(result, ", ")
+ add(result, name)
+ add(result, "_Idx")
const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
@@ -819,17 +814,17 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
case mapType(x.typ)
of etyObject:
if needsNoCopy(y) or noCopyNeeded:
- appf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+ addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
- appf(p.body, "$1 = nimCopy($2, $3);$n",
+ addf(p.body, "$1 = nimCopy($2, $3);$n",
[a.res, b.res, genTypeInfo(p, y.typ)])
of etyBaseIndex:
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(x.info, "genAsgn")
- appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
+ addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
- appf(p.body, "$1 = $2;$n", [a.res, b.res])
+ addf(p.body, "$1 = $2;$n", [a.res, b.res])
proc genAsgn(p: PProc, n: PNode) =
genLineDir(p, n)
@@ -844,17 +839,17 @@ proc genSwap(p: PProc, n: PNode) =
gen(p, n.sons[1], a)
gen(p, n.sons[2], b)
inc(p.unique)
- var tmp = ropef("Tmp$1", [toRope(p.unique)])
+ var tmp = "Tmp$1" % [rope(p.unique)]
if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
inc(p.unique)
- let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
+ let tmp2 = "Tmp$1" % [rope(p.unique)]
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(n.info, "genSwap")
- appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
+ addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
"local $1 = $2; $2 = $3; $3 = $1;$n", [
tmp, a.address, b.address])
tmp = tmp2
- appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
+ addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
"local $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
proc getFieldPosition(f: PNode): int =
@@ -874,7 +869,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
var f = b.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
- r.res = makeJSString(ropeToStr(f.loc.r))
+ r.res = makeJSString($f.loc.r)
internalAssert a.typ != etyBaseIndex
r.address = a.res
r.kind = resExpr
@@ -883,12 +878,12 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone
gen(p, n.sons[0], r)
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
- r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope])
+ r.res = "$1.Field$2" % [r.res, getFieldPosition(n.sons[1]).rope]
else:
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAddr")
var f = n.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
- r.res = ropef("$1.$2", [r.res, f.loc.r])
+ r.res = "$1.$2" % [r.res, f.loc.r]
r.kind = resExpr
proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
@@ -914,10 +909,9 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
else: first = 0
if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
useMagic(p, "chckIndx")
- r.res = ropef("chckIndx($1, $2, $3.length)-$2",
- [b.res, toRope(first), a.res])
+ r.res = "chckIndx($1, $2, $3.length)-$2" % [b.res, rope(first), a.res]
elif first != 0:
- r.res = ropef("($1)-$2", [b.res, toRope(first)])
+ r.res = "($1)-$2" % [b.res, rope(first)]
else:
r.res = b.res
r.kind = resExpr
@@ -934,10 +928,17 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = etyNone
if r.res == nil: internalError(n.info, "genArrayAccess")
- r.res = ropef("$1[$2]", [r.address, r.res])
+ r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.kind = resExpr
+proc isIndirect(v: PSym): bool =
+ result = {sfAddrTaken, sfGlobal} * v.flags != {} and
+ #(mapType(v.typ) != etyObject) and
+ {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
+ v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator,
+ skConst, skTemp, skLet}
+
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case n.sons[0].kind
of nkSym:
@@ -946,17 +947,21 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case s.kind
of skVar, skLet, skResult:
r.kind = resExpr
- if mapType(n.sons[0].typ) == etyObject:
+ let jsType = mapType(n.typ)
+ if jsType == etyObject:
# make addr() a no-op:
r.typ = etyNone
- r.res = s.loc.r
+ if isIndirect(s):
+ r.res = s.loc.r & "[0]"
+ else:
+ r.res = s.loc.r
r.address = nil
- elif {sfGlobal, sfAddrTaken} * s.flags != {}:
+ elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
# for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal.
r.typ = etyBaseIndex
r.address = s.loc.r
- r.res = toRope("0")
+ r.res = rope("0")
else:
# 'var openArray' for instance produces an 'addr' but this is harmless:
gen(p, n.sons[0], r)
@@ -988,13 +993,13 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
if k == etyBaseIndex:
r.typ = etyBaseIndex
if {sfAddrTaken, sfGlobal} * s.flags != {}:
- r.address = ropef("$1[0]", [s.loc.r])
- r.res = ropef("$1[1]", [s.loc.r])
+ r.address = "$1[0]" % [s.loc.r]
+ r.res = "$1[1]" % [s.loc.r]
else:
r.address = s.loc.r
- r.res = con(s.loc.r, "_Idx")
- elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
- r.res = ropef("$1[0]", [s.loc.r])
+ r.res = s.loc.r & "_Idx"
+ elif isIndirect(s):
+ r.res = "$1[0]" % [s.loc.r]
else:
r.res = s.loc.r
of skConst:
@@ -1018,8 +1023,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var owner = p
while owner != nil and owner.prc != s.owner:
owner = owner.up
- if owner != nil: app(owner.locals, newp)
- else: app(p.g.code, newp)
+ if owner != nil: add(owner.locals, newp)
+ else: add(p.g.code, newp)
else:
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
@@ -1033,26 +1038,26 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
gen(p, n.sons[0], a)
if a.typ != etyBaseIndex: internalError(n.info, "genDeref")
- r.res = ropef("$1[$2]", [a.address, a.res])
+ r.res = "$1[$2]" % [a.address, a.res]
proc genArg(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
gen(p, n, a)
if a.typ == etyBaseIndex:
- app(r.res, a.address)
- app(r.res, ", ")
- app(r.res, a.res)
+ add(r.res, a.address)
+ add(r.res, ", ")
+ add(r.res, a.res)
else:
- app(r.res, a.res)
+ add(r.res, a.res)
proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
- app(r.res, "(")
+ add(r.res, "(")
for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i]
if it.typ.isCompileTimeOnly: continue
- if i > 1: app(r.res, ", ")
+ if i > 1: add(r.res, ", ")
genArg(p, it, r)
- app(r.res, ")")
+ add(r.res, ")")
r.kind = resExpr
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
@@ -1064,58 +1069,58 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
if r.typ == etyBaseIndex:
if r.address == nil:
globalError(n.info, "cannot invoke with infix syntax")
- r.res = ropef("$1[$2]", [r.address, r.res])
+ r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.typ = etyNone
- app(r.res, ".")
+ add(r.res, ".")
var op: TCompRes
gen(p, n.sons[0], op)
- app(r.res, op.res)
+ add(r.res, op.res)
- app(r.res, "(")
+ add(r.res, "(")
for i in countup(2, sonsLen(n) - 1):
- if i > 2: app(r.res, ", ")
+ if i > 2: add(r.res, ", ")
genArg(p, n.sons[i], r)
- app(r.res, ")")
+ add(r.res, ")")
r.kind = resExpr
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
useMagic(p, "rawEcho")
- app(r.res, "rawEcho(")
+ add(r.res, "rawEcho(")
let n = n[1].skipConv
internalAssert n.kind == nkBracket
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.typ.isCompileTimeOnly: continue
- if i > 0: app(r.res, ", ")
+ if i > 0: add(r.res, ", ")
genArg(p, it, r)
- app(r.res, ")")
+ add(r.res, ")")
r.kind = resExpr
-proc putToSeq(s: string, indirect: bool): PRope =
- result = toRope(s)
- if indirect: result = ropef("[$1]", [result])
+proc putToSeq(s: string, indirect: bool): Rope =
+ result = rope(s)
+ if indirect: result = "[$1]" % [result]
-proc createVar(p: PProc, typ: PType, indirect: bool): PRope
-proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope =
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope
+proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope =
result = nil
case rec.kind
of nkRecList:
for i in countup(0, sonsLen(rec) - 1):
- app(result, createRecordVarAux(p, rec.sons[i], c))
+ add(result, createRecordVarAux(p, rec.sons[i], c))
of nkRecCase:
- app(result, createRecordVarAux(p, rec.sons[0], c))
+ add(result, createRecordVarAux(p, rec.sons[0], c))
for i in countup(1, sonsLen(rec) - 1):
- app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
+ add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
of nkSym:
- if c > 0: app(result, ", ")
- app(result, mangleName(rec.sym))
- app(result, ": ")
- app(result, createVar(p, rec.sym.typ, false))
+ if c > 0: add(result, ", ")
+ add(result, mangleName(rec.sym))
+ add(result, ": ")
+ add(result, createVar(p, rec.sym.typ, false))
inc(c)
else: internalError(rec.info, "createRecordVarAux")
-proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
var t = skipTypes(typ, abstractInst)
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
@@ -1125,7 +1130,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
of tyRange, tyGenericInst:
result = createVar(p, lastSon(typ), indirect)
of tySet:
- result = toRope("{}")
+ result = putToSeq("{}", indirect)
of tyBool:
result = putToSeq("false", indirect)
of tyArray, tyArrayConstr:
@@ -1135,33 +1140,36 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
useMagic(p, "arrayConstr")
# XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
useMagic(p, "nimCopy")
- result = ropef("arrayConstr($1, $2, $3)", [toRope(length),
- createVar(p, e, false), genTypeInfo(p, e)])
+ result = "arrayConstr($1, $2, $3)" % [rope(length),
+ createVar(p, e, false), genTypeInfo(p, e)]
else:
- result = toRope("[")
+ result = rope("[")
var i = 0
while i < length:
- if i > 0: app(result, ", ")
- app(result, createVar(p, e, false))
+ if i > 0: add(result, ", ")
+ add(result, createVar(p, e, false))
inc(i)
- app(result, "]")
+ add(result, "]")
+ if indirect: result = "[$1]" % [result]
of tyTuple:
- result = toRope("{")
+ result = rope("{")
for i in 0.. 0: app(result, ", ")
- appf(result, "Field$1: $2" | "Field$# = $#", i.toRope,
- createVar(p, t.sons[i], false))
- app(result, "}")
+ if i > 0: add(result, ", ")
+ addf(result, "Field$1: $2" | "Field$# = $#", [i.rope,
+ createVar(p, t.sons[i], false)])
+ add(result, "}")
+ if indirect: result = "[$1]" % [result]
of tyObject:
- result = toRope("{")
+ result = rope("{")
var c = 0
if tfFinal notin t.flags or t.sons[0] != nil:
inc(c)
- appf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
+ addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
while t != nil:
- app(result, createRecordVarAux(p, t.n, c))
+ add(result, createRecordVarAux(p, t.n, c))
t = t.sons[0]
- app(result, "}")
+ add(result, "}")
+ if indirect: result = "[$1]" % [result]
of tyVar, tyPtr, tyRef:
if mapType(t) == etyBaseIndex:
result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
@@ -1173,17 +1181,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
internalError("createVar: " & $t.kind)
result = nil
-proc isIndirect(v: PSym): bool =
- result = {sfAddrTaken, sfGlobal} * v.flags != {} and
- (mapType(v.typ) != etyObject) and
- v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
-
proc genVarInit(p: PProc, v: PSym, n: PNode) =
var
a: TCompRes
- s: PRope
+ s: Rope
if n.kind == nkEmpty:
- appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
+ addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
[mangleName(v), createVar(p, v.typ, isIndirect(v))])
else:
discard mangleName(v)
@@ -1194,23 +1197,23 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
s = a.res
else:
useMagic(p, "nimCopy")
- s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
+ s = "nimCopy($1, $2)" % [a.res, genTypeInfo(p, n.typ)]
of etyBaseIndex:
if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
if {sfAddrTaken, sfGlobal} * v.flags != {}:
- appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
+ addf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
[v.loc.r, a.address, a.res])
else:
- appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
+ addf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
"local $1 = $2; local $1_Idx = $3;$n", [
v.loc.r, a.address, a.res])
return
else:
s = a.res
if isIndirect(v):
- appf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
+ addf(p.body, "var $1 = /**/[$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
else:
- appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
+ addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
proc genVarStmt(p: PProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
@@ -1233,21 +1236,21 @@ proc genConstant(p: PProc, c: PSym) =
p.body = nil
#genLineDir(p, c.ast)
genVarInit(p, c, c.ast)
- app(p.g.code, p.body)
+ add(p.g.code, p.body)
p.body = oldBody
proc genNew(p: PProc, n: PNode) =
var a: TCompRes
gen(p, n.sons[1], a)
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
- appf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, true)])
+ addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
proc genNewSeq(p: PProc, n: PNode) =
var x, y: TCompRes
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
- appf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
+ addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
x.rdLoc, y.rdLoc, createVar(p, t, false)])
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
@@ -1262,22 +1265,22 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[1], a)
r.kind = resExpr
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
- r.res.app(ropef("[$1].concat(", [a.res]))
+ r.res.add("[$1].concat(" % [a.res])
else:
- r.res.app(ropef("($1.slice(0,-1)).concat(", [a.res]))
+ r.res.add("($1.slice(0,-1)).concat(" % [a.res])
for i in countup(2, sonsLen(n) - 2):
gen(p, n.sons[i], a)
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
- r.res.app(ropef("[$1],", [a.res]))
+ r.res.add("[$1]," % [a.res])
else:
- r.res.app(ropef("$1.slice(0,-1),", [a.res]))
+ r.res.add("$1.slice(0,-1)," % [a.res])
gen(p, n.sons[sonsLen(n) - 1], a)
if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
- r.res.app(ropef("[$1, 0])", [a.res]))
+ r.res.add("[$1, 0])" % [a.res])
else:
- r.res.app(ropef("$1)", [a.res]))
+ r.res.add("$1)" % [a.res])
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
var t = skipTypes(n.sons[1].typ, abstractVarRange)
@@ -1288,8 +1291,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[1], r)
useMagic(p, "cstrToNimstr")
r.kind = resExpr
- r.res = ropef("cstrToNimstr($1.node.sons[$2].name)",
- [genTypeInfo(p, t), r.res])
+ r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
else:
# XXX:
internalError(n.info, "genRepr: Not implemented")
@@ -1299,23 +1301,23 @@ proc genOf(p: PProc, n: PNode, r: var TCompRes) =
let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc})
gen(p, n.sons[1], x)
if tfFinal in t.flags:
- r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)])
+ r.res = "($1.m_type == $2)" % [x.res, genTypeInfo(p, t)]
else:
useMagic(p, "isObj")
- r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)])
+ r.res = "isObj($1.m_type, $2)" % [x.res, genTypeInfo(p, t)]
r.kind = resExpr
proc genReset(p: PProc, n: PNode) =
var x: TCompRes
useMagic(p, "genericReset")
gen(p, n.sons[1], x)
- appf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
+ addf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
genTypeInfo(p, n.sons[1].typ)])
proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
var
a: TCompRes
- line, filen: PRope
+ line, filen: Rope
var op = n.sons[0].sym.magic
case op
of mOr: genOr(p, n.sons[1], n.sons[2], r)
@@ -1327,14 +1329,17 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
# XXX: range checking?
if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
- of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)")
+ of mAppendStrCh: binaryExpr(p, n, r, "addChar",
+ "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
of mAppendStrStr:
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
- binaryExpr(p, n, r, "", "$1 += $2")
+ binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
else:
- binaryExpr(p, n, r, "", "$1 = ($1.slice(0, -1)).concat($2)")
+ binaryExpr(p, n, r, "",
+ "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
# XXX: make a copy of $2, because of Javascript's sucking semantics
- of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)")
+ of mAppendSeqElem: binaryExpr(p, n, r, "",
+ "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
of mConStrStr: genConStrStr(p, n, r)
of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
@@ -1342,17 +1347,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mIsNil: unaryExpr(p, n, r, "", "$1 == null")
of mEnumToStr: genRepr(p, n, r)
of mNew, mNewFinalize: genNew(p, n)
- of mSizeOf: r.res = toRope(getSize(n.sons[1].typ))
+ of mSizeOf: r.res = rope(getSize(n.sons[1].typ))
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r)
- of mLengthStr: unaryExpr(p, n, r, "", "($1.length-1)")
+ of mLengthStr: unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
+ of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
of mLengthSeq, mLengthOpenArray, mLengthArray:
+ unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+ of mXLenSeq:
unaryExpr(p, n, r, "", "$1.length")
of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
- unaryExpr(p, n, r, "", "($1.length-2)")
+ unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
else:
- unaryExpr(p, n, r, "", "($1.length-1)")
+ unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
of mInc:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
@@ -1389,56 +1397,56 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes
useMagic(p, "SetConstr")
- r.res = toRope("SetConstr(")
+ r.res = rope("SetConstr(")
r.kind = resExpr
for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(r.res, ", ")
+ if i > 0: add(r.res, ", ")
var it = n.sons[i]
if it.kind == nkRange:
gen(p, it.sons[0], a)
gen(p, it.sons[1], b)
- appf(r.res, "[$1, $2]", [a.res, b.res])
+ addf(r.res, "[$1, $2]", [a.res, b.res])
else:
gen(p, it, a)
- app(r.res, a.res)
- app(r.res, ")")
+ add(r.res, a.res)
+ add(r.res, ")")
proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
- r.res = toRope("[")
+ r.res = rope("[")
r.kind = resExpr
for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(r.res, ", ")
+ if i > 0: add(r.res, ", ")
gen(p, n.sons[i], a)
- app(r.res, a.res)
- app(r.res, "]")
+ add(r.res, a.res)
+ add(r.res, "]")
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
- r.res = toRope("{")
+ r.res = rope("{")
r.kind = resExpr
for i in countup(0, sonsLen(n) - 1):
- if i > 0: app(r.res, ", ")
+ if i > 0: add(r.res, ", ")
var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1]
gen(p, it, a)
- appf(r.res, "Field$#: $#" | "Field$# = $#", [i.toRope, a.res])
- r.res.app("}")
+ addf(r.res, "Field$#: $#" | "Field$# = $#", [i.rope, a.res])
+ r.res.add("}")
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
# XXX inheritance?
var a: TCompRes
- r.res = toRope("{")
+ r.res = rope("{")
r.kind = resExpr
for i in countup(1, sonsLen(n) - 1):
- if i > 1: app(r.res, ", ")
+ if i > 1: add(r.res, ", ")
var it = n.sons[i]
internalAssert it.kind == nkExprColonExpr
gen(p, it.sons[1], a)
var f = it.sons[0].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
- appf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
- r.res.app("}")
+ addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
+ r.res.add("}")
proc genConv(p: PProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange)
@@ -1449,10 +1457,10 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
return
case dest.kind:
of tyBool:
- r.res = ropef("(($1)? 1:0)" | "toBool($#)", [r.res])
+ r.res = ("(($1)? 1:0)" | "toBool($#)") % [r.res]
r.kind = resExpr
of tyInt:
- r.res = ropef("($1|0)", [r.res])
+ r.res = "($1|0)" % [r.res]
else:
# TODO: What types must we handle here?
discard
@@ -1467,7 +1475,7 @@ proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
gen(p, n.sons[1], a)
gen(p, n.sons[2], b)
useMagic(p, "chckRange")
- r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res])
+ r.res = "chckRange($1, $2, $3)" % [r.res, a.res, b.res]
r.kind = resExpr
proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1479,7 +1487,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0], r)
if r.res == nil: internalError(n.info, "convStrToCStr")
useMagic(p, "toJSStr")
- r.res = ropef("toJSStr($1)", [r.res])
+ r.res = "toJSStr($1)" % [r.res]
r.kind = resExpr
proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1491,7 +1499,7 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0], r)
if r.res == nil: internalError(n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr")
- r.res = ropef("cstrToNimstr($1)", [r.res])
+ r.res = "cstrToNimstr($1)" % [r.res]
r.kind = resExpr
proc genReturnStmt(p: PProc, n: PNode) =
@@ -1501,32 +1509,32 @@ proc genReturnStmt(p: PProc, n: PNode) =
genStmt(p, n.sons[0])
else:
genLineDir(p, n)
- appf(p.body, "break BeforeRet;$n" | "goto ::BeforeRet::;$n")
+ addf(p.body, "break BeforeRet;$n" | "goto ::BeforeRet::;$n", [])
-proc genProcBody(p: PProc, prc: PSym): PRope =
+proc genProcBody(p: PProc, prc: PSym): Rope =
if optStackTrace in prc.options:
- result = ropef(("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
- "local F={procname=$#,prev=framePtr,filename=$#,line=0};$n") &
- "framePtr = F;$n", [
- makeJSString(prc.owner.name.s & '.' & prc.name.s),
- makeJSString(toFilename(prc.info))])
+ result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
+ "local F={procname=$#,prev=framePtr,filename=$#,line=0};$n") &
+ "framePtr = F;$n") % [
+ makeJSString(prc.owner.name.s & '.' & prc.name.s),
+ makeJSString(toFilename(prc.info))]
else:
result = nil
if p.beforeRetNeeded:
- appf(result, "BeforeRet: do {$n$1} while (false); $n" |
+ addf(result, "BeforeRet: do {$n$1} while (false); $n" |
"$#;::BeforeRet::$n", [p.body])
else:
- app(result, p.body)
+ add(result, p.body)
if prc.typ.callConv == ccSysCall and p.target == targetJS:
- result = ropef("try {$n$1} catch (e) {$n" &
- " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result])
+ result = ("try {$n$1} catch (e) {$n" &
+ " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
if optStackTrace in prc.options:
- app(result, "framePtr = framePtr.prev;" & tnl)
+ add(result, "framePtr = framePtr.prev;" & tnl)
-proc genProc(oldProc: PProc, prc: PSym): PRope =
+proc genProc(oldProc: PProc, prc: PSym): Rope =
var
resultSym: PSym
- name, returnStmt, resultAsgn, header: PRope
+ name, returnStmt, resultAsgn, header: Rope
a: TCompRes
#if gVerbosity >= 3:
# echo "BEGIN generating code for: " & prc.name.s
@@ -1539,23 +1547,23 @@ proc genProc(oldProc: PProc, prc: PSym): PRope =
header = generateHeader(p, prc.typ)
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast.sons[resultPos].sym
- resultAsgn = ropef("var $# = $#;$n" | "local $# = $#;$n", [
+ resultAsgn = ("var $# = $#;$n" | "local $# = $#;$n") % [
mangleName(resultSym),
- createVar(p, resultSym.typ, isIndirect(resultSym))])
+ createVar(p, resultSym.typ, isIndirect(resultSym))]
gen(p, prc.ast.sons[resultPos], a)
- returnStmt = ropef("return $#;$n", [a.res])
+ returnStmt = "return $#;$n" % [a.res]
genStmt(p, prc.getBody)
- result = ropef("function $#($#) {$n$#$#$#$#}$n" |
- "function $#($#) $n$#$#$#$#$nend$n",
- [name, header, p.locals, resultAsgn,
- genProcBody(p, prc), returnStmt])
+ result = ("function $#($#) {$n$#$#$#$#}$n" |
+ "function $#($#) $n$#$#$#$#$nend$n") %
+ [name, header, p.locals, resultAsgn,
+ genProcBody(p, prc), returnStmt]
#if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s
proc genStmt(p: PProc, n: PNode) =
var r: TCompRes
gen(p, n, r)
- if r.res != nil: appf(p.body, "$#;$n", r.res)
+ if r.res != nil: addf(p.body, "$#;$n", [r.res])
proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone
@@ -1566,34 +1574,34 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkSym:
genSym(p, n, r)
of nkCharLit..nkInt64Lit:
- r.res = toRope(n.intVal)
+ r.res = rope(n.intVal)
r.kind = resExpr
of nkNilLit:
if isEmptyType(n.typ):
discard
elif mapType(n.typ) == etyBaseIndex:
r.typ = etyBaseIndex
- r.address = toRope"null" | toRope"nil"
- r.res = toRope"0"
+ r.address = rope"null" | rope"nil"
+ r.res = rope"0"
r.kind = resExpr
else:
- r.res = toRope"null" | toRope"nil"
+ r.res = rope"null" | rope"nil"
r.kind = resExpr
of nkStrLit..nkTripleStrLit:
if skipTypes(n.typ, abstractVarRange).kind == tyString:
useMagic(p, "cstrToNimstr")
- r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)])
+ r.res = "cstrToNimstr($1)" % [makeJSString(n.strVal)]
else:
r.res = makeJSString(n.strVal)
r.kind = resExpr
of nkFloatLit..nkFloat64Lit:
let f = n.floatVal
- if f != f: r.res = toRope"NaN"
- elif f == 0.0: r.res = toRope"0.0"
+ if f != f: r.res = rope"NaN"
+ elif f == 0.0: r.res = rope"0.0"
elif f == 0.5 * f:
- if f > 0.0: r.res = toRope"Infinity"
- else: r.res = toRope"-Infinity"
- else: r.res = toRope(f.toStrMaxPrecision)
+ if f > 0.0: r.res = rope"Infinity"
+ else: r.res = rope"-Infinity"
+ else: r.res = rope(f.toStrMaxPrecision)
r.kind = resExpr
of nkCallKinds:
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
@@ -1628,7 +1636,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
- app(p.locals, genProc(p, s))
+ add(p.locals, genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)
of nkStmtList, nkStmtListExpr:
# this shows the distinction is nice for backends and should be kept
@@ -1679,23 +1687,23 @@ proc newModule(module: PSym): BModule =
result.module = module
if globals == nil: globals = newGlobals()
-proc genHeader(): PRope =
- result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
- "/* (c) 2015 Andreas Rumpf */$n$n" &
- "var framePtr = null;$n" &
- "var excHandler = null;$n" &
- "var lastJSError = null;$n",
- [toRope(VersionAsString)])
+proc genHeader(): Rope =
+ result = ("/* Generated by the Nim Compiler v$1 */$n" &
+ "/* (c) 2015 Andreas Rumpf */$n$n" &
+ "var framePtr = null;$n" &
+ "var excHandler = null;$n" &
+ "var lastJSError = null;$n") %
+ [rope(VersionAsString)]
proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options:
- appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
+ addf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
"framePtr = F;$n", [
makeJSString("module " & p.module.module.name.s),
makeJSString(toFilename(p.module.module.info))])
genStmt(p, n)
if optStackTrace in p.options:
- appf(p.body, "framePtr = framePtr.prev;$n")
+ addf(p.body, "framePtr = framePtr.prev;$n", [])
proc myProcess(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
@@ -1704,23 +1712,23 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
if m.module == nil: internalError(n.info, "myProcess")
var p = newProc(globals, m, nil, m.module.options)
genModule(p, n)
- app(p.g.code, p.locals)
- app(p.g.code, p.body)
+ add(p.g.code, p.locals)
+ add(p.g.code, p.body)
-proc wholeCode*(m: BModule): PRope =
+proc wholeCode*(m: BModule): Rope =
for prc in globals.forwarded:
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
- app(p.g.code, genProc(p, prc))
+ add(p.g.code, genProc(p, prc))
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1:
let prc = disp.sons[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
- app(p.g.code, genProc(p, prc))
+ add(p.g.code, genProc(p, prc))
- result = con(globals.typeInfo, globals.code)
+ result = globals.typeInfo & globals.code
proc myClose(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
@@ -1734,7 +1742,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
else: getCurrentDir() / options.outFile
else:
changeFileExt(completeCFilePath(m.module.filename), "js")
- discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
+ discard writeRopeIfNotEqual(genHeader() & code, outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
internalError("symbol files are not possible with the JS code generator")
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 1288c854df..8519383276 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -9,138 +9,138 @@
## Type info generation for the JS backend.
-proc genTypeInfo(p: PProc, typ: PType): PRope
-proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
- var
- s, u: PRope
+proc genTypeInfo(p: PProc, typ: PType): Rope
+proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
+ var
+ s, u: Rope
length: int
field: PSym
b: PNode
result = nil
case n.kind
- of nkRecList:
+ of nkRecList:
length = sonsLen(n)
- if length == 1:
+ if length == 1:
result = genObjectFields(p, typ, n.sons[0])
- else:
+ else:
s = nil
- for i in countup(0, length - 1):
- if i > 0: app(s, ", " & tnl)
- app(s, genObjectFields(p, typ, n.sons[i]))
- result = ropef("{kind: 2, len: $1, offset: 0, " &
- "typ: null, name: null, sons: [$2]}", [toRope(length), s])
- of nkSym:
+ for i in countup(0, length - 1):
+ if i > 0: add(s, ", " & tnl)
+ add(s, genObjectFields(p, typ, n.sons[i]))
+ result = ("{kind: 2, len: $1, offset: 0, " &
+ "typ: null, name: null, sons: [$2]}") % [rope(length), s]
+ of nkSym:
field = n.sym
s = genTypeInfo(p, field.typ)
- result = ropef("{kind: 1, offset: \"$1\", len: 0, " &
- "typ: $2, name: $3, sons: null}",
- [mangleName(field), s, makeJSString(field.name.s)])
- of nkRecCase:
+ result = ("{kind: 1, offset: \"$1\", len: 0, " &
+ "typ: $2, name: $3, sons: null}") %
+ [mangleName(field), s, makeJSString(field.name.s)]
+ of nkRecCase:
length = sonsLen(n)
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
field = n.sons[0].sym
s = genTypeInfo(p, field.typ)
- for i in countup(1, length - 1):
+ for i in countup(1, length - 1):
b = n.sons[i] # branch
u = nil
case b.kind
- of nkOfBranch:
- if sonsLen(b) < 2:
+ of nkOfBranch:
+ if sonsLen(b) < 2:
internalError(b.info, "genObjectFields; nkOfBranch broken")
- for j in countup(0, sonsLen(b) - 2):
- if u != nil: app(u, ", ")
- if b.sons[j].kind == nkRange:
- appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])),
- toRope(getOrdValue(b.sons[j].sons[1]))])
- else:
- app(u, toRope(getOrdValue(b.sons[j])))
- of nkElse:
- u = toRope(lengthOrd(field.typ))
+ for j in countup(0, sonsLen(b) - 2):
+ if u != nil: add(u, ", ")
+ if b.sons[j].kind == nkRange:
+ addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
+ rope(getOrdValue(b.sons[j].sons[1]))])
+ else:
+ add(u, rope(getOrdValue(b.sons[j])))
+ of nkElse:
+ u = rope(lengthOrd(field.typ))
else: internalError(n.info, "genObjectFields(nkRecCase)")
- if result != nil: app(result, ", " & tnl)
- appf(result, "[SetConstr($1), $2]",
+ if result != nil: add(result, ", " & tnl)
+ addf(result, "[SetConstr($1), $2]",
[u, genObjectFields(p, typ, lastSon(b))])
- result = ropef("{kind: 3, offset: \"$1\", len: $3, " &
- "typ: $2, name: $4, sons: [$5]}", [mangleName(field), s,
- toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result])
+ result = ("{kind: 3, offset: \"$1\", len: $3, " &
+ "typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
+ rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
else: internalError(n.info, "genObjectFields")
-
-proc genObjectInfo(p: PProc, typ: PType, name: PRope) =
- var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
- "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+
+proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
+ var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+ "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s)
- appf(p.g.typeInfo, "var NNI$1 = $2;$n",
- [toRope(typ.id), genObjectFields(p, typ, typ.n)])
- appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
- if (typ.kind == tyObject) and (typ.sons[0] != nil):
- appf(p.g.typeInfo, "$1.base = $2;$n",
+ addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+ [rope(typ.id), genObjectFields(p, typ, typ.n)])
+ addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+ if (typ.kind == tyObject) and (typ.sons[0] != nil):
+ addf(p.g.typeInfo, "$1.base = $2;$n",
[name, genTypeInfo(p, typ.sons[0])])
-proc genTupleFields(p: PProc, typ: PType): PRope =
- var s: PRope = nil
+proc genTupleFields(p: PProc, typ: PType): Rope =
+ var s: Rope = nil
for i in 0 .. 0: app(s, ", " & tnl)
- s.appf("{kind: 1, offset: \"Field$1\", len: 0, " &
+ if i > 0: add(s, ", " & tnl)
+ s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
"typ: $2, name: \"Field$1\", sons: null}",
- [i.toRope, genTypeInfo(p, typ.sons[i])])
- result = ropef("{kind: 2, len: $1, offset: 0, " &
- "typ: null, name: null, sons: [$2]}", [toRope(typ.len), s])
+ [i.rope, genTypeInfo(p, typ.sons[i])])
+ result = ("{kind: 2, len: $1, offset: 0, " &
+ "typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
-proc genTupleInfo(p: PProc, typ: PType, name: PRope) =
- var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
- "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
+ var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+ "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s)
- appf(p.g.typeInfo, "var NNI$1 = $2;$n",
- [toRope(typ.id), genTupleFields(p, typ)])
- appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
+ addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+ [rope(typ.id), genTupleFields(p, typ)])
+ addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
-proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
+proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
let length = sonsLen(typ.n)
- var s: PRope = nil
- for i in countup(0, length - 1):
+ var s: Rope = nil
+ for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym
- if i > 0: app(s, ", " & tnl)
+ if i > 0: add(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
- appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
- [toRope(field.position), name, makeJSString(extName)])
- var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
- "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s])
- s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
- "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+ addf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
+ [rope(field.position), name, makeJSString(extName)])
+ var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
+ "name: null, len: $2, sons: [$3]};$n") % [rope(typ.id), rope(length), s]
+ s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+ "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s)
- app(p.g.typeInfo, n)
- appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
+ add(p.g.typeInfo, n)
+ addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
if typ.sons[0] != nil:
- appf(p.g.typeInfo, "$1.base = $2;$n",
+ addf(p.g.typeInfo, "$1.base = $2;$n",
[name, genTypeInfo(p, typ.sons[0])])
-proc genTypeInfo(p: PProc, typ: PType): PRope =
+proc genTypeInfo(p: PProc, typ: PType): Rope =
var t = typ
if t.kind == tyGenericInst: t = lastSon(t)
- result = ropef("NTI$1", [toRope(t.id)])
- if containsOrIncl(p.g.typeInfoGenerated, t.id): return
+ result = "NTI$1" % [rope(t.id)]
+ if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind
- of tyDistinct:
+ of tyDistinct:
result = genTypeInfo(p, typ.sons[0])
of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
- var s = ropef(
- "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
- [result, toRope(ord(t.kind))])
+ var s =
+ "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+ [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
- of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
- var s = ropef(
- "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
- [result, toRope(ord(t.kind))])
+ of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
+ var s =
+ "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+ [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
- appf(p.g.typeInfo, "$1.base = $2;$n",
+ addf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.lastSon)])
- of tyArrayConstr, tyArray:
- var s = ropef(
- "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
- [result, toRope(ord(t.kind))])
+ of tyArrayConstr, tyArray:
+ var s =
+ "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+ [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
- appf(p.g.typeInfo, "$1.base = $2;$n",
+ addf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.sons[1])])
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 123445e1f4..c68bc352cd 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -9,92 +9,92 @@
# This include file implements lambda lifting for the transformator.
-import
- intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
+import
+ intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, rodread, lowerings
discard """
The basic approach is that captured vars need to be put on the heap and
that the calling chain needs to be explicitly modelled. Things to consider:
-
+
proc a =
var v = 0
proc b =
var w = 2
-
+
for x in 0..3:
proc c = capture v, w, x
c()
b()
-
+
for x in 0..4:
proc d = capture x
d()
-
+
Needs to be translated into:
-
+
proc a =
var cl: *
new cl
cl.v = 0
-
+
proc b(cl) =
var bcl: *
new bcl
bcl.w = 2
bcl.up = cl
-
+
for x in 0..3:
var bcl2: *
new bcl2
bcl2.up = bcl
bcl2.up2 = cl
bcl2.x = x
-
+
proc c(cl) = capture cl.up2.v, cl.up.w, cl.x
c(bcl2)
-
+
c(bcl)
-
+
b(cl)
-
+
for x in 0..4:
var acl2: *
new acl2
acl2.x = x
proc d(cl) = capture cl.x
d(acl2)
-
+
Closures as interfaces:
-
+
proc outer: T =
var captureMe: TObject # value type required for efficiency
proc getter(): int = result = captureMe.x
proc setter(x: int) = captureMe.x = x
-
+
result = (getter, setter)
-
+
Is translated to:
-
+
proc outer: T =
var cl: *
new cl
-
+
proc getter(cl): int = result = cl.captureMe.x
proc setter(cl: *, x: int) = cl.captureMe.x = x
-
+
result = ((cl, getter), (cl, setter))
-
-
+
+
For 'byref' capture, the outer proc needs to access the captured var through
the indirection too. For 'bycopy' capture, the outer proc accesses the var
not through the indirection.
-
- Possible optimizations:
-
+
+ Possible optimizations:
+
1) If the closure contains a single 'ref' and this
reference is not re-assigned (check ``sfAddrTaken`` flag) make this the
- closure. This is an important optimization if closures are used as
+ closure. This is an important optimization if closures are used as
interfaces.
2) If the closure does not escape, put it onto the stack, not on the heap.
3) Dataflow analysis would help to eliminate the 'up' indirections.
@@ -126,7 +126,7 @@ type
fn, closureParam, state, resultSym: PSym # most are only valid if
# fn.kind == skClosureIterator
obj: PType
-
+
PEnv = ref TEnv
TEnv {.final.} = object of RootObj
attachedNode, replacementNode: PNode
@@ -141,7 +141,7 @@ type
# if up.fn != fn then we cross function boundaries.
# This is an important case to consider.
vars: IntSet # variables belonging to this environment
-
+
TOuterContext = object
fn: PSym # may also be a module!
head: PEnv
@@ -284,7 +284,7 @@ proc addClosureParam(fn: PSym; e: PEnv) =
#assert e.obj.kind == tyObject
proc illegalCapture(s: PSym): bool {.inline.} =
- result = skipTypes(s.typ, abstractInst).kind in
+ result = skipTypes(s.typ, abstractInst).kind in
{tyVar, tyOpenArray, tyVarargs} or
s.kind == skResult
@@ -344,7 +344,7 @@ proc createUpField(obj, fieldType: PType): PSym =
#rawAddField(obj, result)
addField(obj, result)
-proc captureVar(o: POuterContext; top: PEnv; local: PSym;
+proc captureVar(o: POuterContext; top: PEnv; local: PSym;
info: TLineInfo): bool =
# first check if we should be concerned at all:
var it = top
@@ -408,7 +408,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
var s = n.sym
if interestingVar(s) and e.fn != s.owner:
if captureVar(o, e, s, n.info): result = 1
- of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
+ of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection:
discard
else:
@@ -418,7 +418,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
proc generateThunk(prc: PNode, dest: PType): PNode =
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
## a closure.
-
+
# we cannot generate a proper thunk here for GC-safety reasons (see internal
# documentation):
if gCmd == cmdCompileToJS: return prc
@@ -515,7 +515,7 @@ proc closureCreationPoint(n: PNode): PNode =
proc addParamsToEnv(fn: PSym; env: PEnv) =
let params = fn.typ.n
- for i in 1.. 0:
if n.sons[0].kind == nkGotoState: return nil
- if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
+ if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
n[1][0].kind == nkGotoState:
return nil
result = newNodeI(nkStmtList, it.fn.info)
@@ -812,7 +812,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
var state0 = newNodeI(nkState, it.fn.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
-
+
let newBody = transformOuterProc(o, n, it)
if newBody != nil:
result.add(newBody)
@@ -899,7 +899,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
let x = closure.createdVar
assert x != nil
return makeClosure(local, x, n.info)
-
+
if not contains(o.capturedVars, local.id): return
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
# if sfByCopy notin local.flags:
@@ -946,7 +946,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
proc liftLambdas*(fn: PSym, body: PNode): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
- if body.kind == nkEmpty or gCmd == cmdCompileToJS or
+ if body.kind == nkEmpty or gCmd == cmdCompileToJS or
fn.skipGenericOwner.kind != skModule:
# ignore forward declaration:
result = body
@@ -985,17 +985,17 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
proc liftForLoop*(body: PNode): PNode =
# problem ahead: the iterator could be invoked indirectly, but then
- # we don't know what environment to create here:
- #
+ # we don't know what environment to create here:
+ #
# iterator count(): int =
# yield 0
- #
+ #
# iterator count2(): int =
# var x = 3
# yield x
# inc x
# yield x
- #
+ #
# proc invoke(iter: iterator(): int) =
# for x in iter(): echo x
#
@@ -1004,7 +1004,7 @@ proc liftForLoop*(body: PNode): PNode =
for i in foo(): ...
Is transformed to:
-
+
cl = createClosure()
while true:
let i = foo(cl)
@@ -1016,7 +1016,7 @@ proc liftForLoop*(body: PNode): PNode =
var call = body[L-2]
result = newNodeI(nkStmtList, body.info)
-
+
# static binding?
var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
@@ -1030,18 +1030,18 @@ proc liftForLoop*(body: PNode): PNode =
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env.newSymNode))
-
+
var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
whileLoop.sons[1] = loopBody
result.add whileLoop
-
+
# setup loopBody:
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
- for i in 0 .. L-3:
+ for i in 0 .. L-3:
assert body[i].kind == nkSym
body[i].sym.kind = skLet
addSon(vpart, body[i])
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 78266ef4d3..8080e0e8c3 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -61,7 +61,7 @@ type
tkComma, tkSemiColon,
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
tkOpr, tkComment, tkAccent,
- tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
+ tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TTokTypes* = set[TTokType]
@@ -131,24 +131,10 @@ type
var gLinesCompiled*: int # all lines that have been compiled
-proc isKeyword*(kind: TTokType): bool
-proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
-proc rawGetTok*(L: var TLexer, tok: var TToken)
- # reads in the next token into tok and skips it
-
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
newLineInfo(L.fileIdx, tok.line, tok.col)
-proc closeLexer*(lex: var TLexer)
-proc printTok*(tok: TToken)
-proc tokToStr*(tok: TToken): string
-
-proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
- openLexer(lex, filename.fileInfoIdx, inputstream)
-
-proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
-
-proc isKeyword(kind: TTokType): bool =
+proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isNimIdentifier*(s: string): bool =
@@ -206,14 +192,17 @@ proc fillToken(L: var TToken) =
L.base = base10
L.ident = dummyIdent
-proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
+proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream)
lex.fileIdx = fileidx
lex.indentAhead = - 1
lex.currLineIndent = 0
inc(lex.lineNumber, inputstream.lineOffset)
-proc closeLexer(lex: var TLexer) =
+proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
+ openLexer(lex, filename.fileInfoIdx, inputstream)
+
+proc closeLexer*(lex: var TLexer) =
inc(gLinesCompiled, lex.lineNumber)
closeBaseLexer(lex)
@@ -229,9 +218,13 @@ proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
else:
L.errorHandler(info, msg, arg)
-proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
+proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg)
+proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
+ var info = newLineInfo(L.fileIdx, tok.line, tok.col)
+ L.dispMessage(info, msg, arg)
+
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
L.dispMessage(info, msg, arg)
@@ -785,7 +778,7 @@ proc skip(L: var TLexer, tok: var TToken) =
break # EndOfFile also leaves the loop
L.bufpos = pos
-proc rawGetTok(L: var TLexer, tok: var TToken) =
+proc rawGetTok*(L: var TLexer, tok: var TToken) =
fillToken(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
@@ -874,6 +867,15 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
of '`':
tok.tokType = tkAccent
inc(L.bufpos)
+ of '_':
+ inc(L.bufpos)
+ if L.buf[L.bufpos] notin SymChars:
+ tok.tokType = tkSymbol
+ tok.ident = getIdent("_")
+ else:
+ tok.literal = $c
+ tok.tokType = tkInvalid
+ lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
of '\"':
# check for extended raw string literal:
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index a51ca9ed69..b6b01d5585 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -15,6 +15,10 @@ const
import ast, astalgo, types, idents, magicsys, msgs, options
from trees import getMagic
+proc newDeref*(n: PNode): PNode {.inline.} =
+ result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+ addSon(result, n)
+
proc newTupleAccess*(tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i])
@@ -382,11 +386,11 @@ proc getRoot*(n: PNode): PSym =
if getMagic(n) == mSlice: result = getRoot(n.sons[1])
else: discard
-proc newIntLit(value: BiggestInt): PNode =
+proc newIntLit*(value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value)
result.typ = getSysType(tyInt)
-proc genHigh(n: PNode): PNode =
+proc genHigh*(n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}:
result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
else:
diff --git a/compiler/main.nim b/compiler/main.nim
index 363327e40b..0c80c19b70 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -54,6 +54,7 @@ proc commandDoc2 =
finishDoc2Pass(gProjectName)
proc commandCompileToC =
+ extccomp.initVars()
semanticPasses()
registerPass(cgenPass)
rodPass()
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 22ef9dc30b..041a181be7 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -387,7 +387,7 @@ const
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
- warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
+ warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
@@ -449,10 +449,10 @@ type
fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
shortName*: string # short name of the module
- quotedName*: PRope # cached quoted short name for codegen
+ quotedName*: Rope # cached quoted short name for codegen
# purposes
- lines*: seq[PRope] # the source code of the module
+ lines*: seq[Rope] # the source code of the module
# used for better error messages and
# embedding the original source in the
# generated code
@@ -493,24 +493,20 @@ proc toCChar*(c: char): string =
of '\'', '\"', '\\': result = '\\' & c
else: result = $(c)
-proc makeCString*(s: string): PRope =
- # BUGFIX: We have to split long strings into many ropes. Otherwise
- # this could trigger an internalError(). See the ropes module for
- # further information.
+proc makeCString*(s: string): Rope =
const
MaxLineLength = 64
result = nil
- var res = "\""
+ var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
+ add(res, "\"")
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
add(res, '\"')
add(res, tnl)
- app(result, toRope(res)) # reset:
- setLen(res, 1)
- res[0] = '\"'
+ add(res, '\"')
add(res, toCChar(s[i]))
add(res, '\"')
- app(result, toRope(res))
+ add(result, rope(res))
proc newFileInfo(fullPath, projPath: string): TFileInfo =
@@ -568,7 +564,7 @@ var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
-proc sourceLine*(i: TLineInfo): PRope
+proc sourceLine*(i: TLineInfo): Rope
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
@@ -742,7 +738,7 @@ proc writeContext(lastinfo: TLineInfo) =
if msgContext[i] != lastinfo and msgContext[i] != info:
msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
coordToStr(msgContext[i].line),
- coordToStr(msgContext[i].col),
+ coordToStr(msgContext[i].col+1),
getMessageStr(errInstantiationFrom, "")])
info = msgContext[i]
@@ -776,7 +772,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
proc writeSurroundingSrc(info: TLineInfo) =
const indent = " "
- msgWriteln(indent & info.sourceLine.ropeToStr)
+ msgWriteln(indent & $info.sourceLine)
msgWriteln(indent & spaces(info.col) & '^')
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
@@ -785,7 +781,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
of hintMin..hintMax: PosHintFormat
else: PosErrorFormat
result = frmt % [toMsgFilename(info), coordToStr(info.line),
- coordToStr(info.col), getMessageStr(msg, arg)]
+ coordToStr(info.col+1), getMessageStr(msg, arg)]
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
@@ -808,8 +804,11 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
ignoreMsg = optHints notin gOptions or msg notin gNotes
frmt = PosHintFormat
inc(gHintCounter)
+ # NOTE: currently line info line numbers start with 1,
+ # but column numbers start with 0, however most editors expect
+ # first column to be 1, so we need to +1 here
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
- coordToStr(info.col), getMessageStr(msg, arg)]
+ coordToStr(info.col+1), getMessageStr(msg, arg)]
if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
msgWriteln(s)
if optPrintSurroundingSrc and msg in errMin..errMax:
@@ -831,6 +830,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc localError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doNothing)
+proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
+ localError(info, format % params)
+
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
@@ -852,9 +854,9 @@ template internalAssert*(e: bool): stmt =
if not e: internalError($instantiationInfo())
proc addSourceLine*(fileIdx: int32, line: string) =
- fileInfos[fileIdx].lines.add line.toRope
+ fileInfos[fileIdx].lines.add line.rope
-proc sourceLine*(i: TLineInfo): PRope =
+proc sourceLine*(i: TLineInfo): Rope =
if i.fileIndex < 0: return nil
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
@@ -869,16 +871,14 @@ proc sourceLine*(i: TLineInfo): PRope =
result = fileInfos[i.fileIndex].lines[i.line-1]
-proc quotedFilename*(i: TLineInfo): PRope =
+proc quotedFilename*(i: TLineInfo): Rope =
internalAssert i.fileIndex >= 0
result = fileInfos[i.fileIndex].quotedName
-ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
+ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err
of rInvalidFormatStr:
internalError("ropes: invalid format string: " & msg)
- of rTokenTooLong:
- internalError("ropes: token too long: " & msg)
of rCannotOpenFile:
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg
index 533563a985..73219d6f81 100644
--- a/compiler/nimfix/nimfix.nim.cfg
+++ b/compiler/nimfix/nimfix.nim.cfg
@@ -5,7 +5,7 @@ hint[XDeclaredButNotUsed]:off
path:"$projectPath/.."
path:"$lib/packages/docutils"
-path:"$nim/compiler"
+path:"../../compiler"
define:useStdoutAsStdmsg
symbol:nimfix
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
index b45ca475c9..8285d81d9e 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -82,7 +82,8 @@ proc action(cmd: string) =
if cmd[i] == ';':
i = parseQuoted(cmd, dirtyfile, i+1)
i += skipWhile(cmd, seps, i)
- var line, col = -1
+ var line = -1
+ var col = 0
i += parseInt(cmd, line, i)
i += skipWhile(cmd, seps, i)
i += parseInt(cmd, col, i)
@@ -97,7 +98,7 @@ proc action(cmd: string) =
resetModule dirtyIdx
if dirtyIdx != gProjectMainIdx:
resetModule gProjectMainIdx
- gTrackPos = newLineInfo(dirtyIdx, line, col)
+ gTrackPos = newLineInfo(dirtyIdx, line, col-1)
#echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
gErrorCounter = 0
if not isKnownFile:
@@ -150,11 +151,11 @@ proc mainCommand =
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd)
- while true:
+ while true:
parseopt.next(p)
case p.kind
- of cmdEnd: break
- of cmdLongoption, cmdShortOption:
+ of cmdEnd: break
+ of cmdLongoption, cmdShortOption:
case p.key.normalize
of "port": gPort = parseInt(p.val).Port
of "address": gAddress = p.val
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
index 062092f16d..acca173968 100644
--- a/compiler/nimsuggest/nimsuggest.nim.cfg
+++ b/compiler/nimsuggest/nimsuggest.nim.cfg
@@ -6,7 +6,7 @@ hint[XDeclaredButNotUsed]:off
path:"$projectPath/../.."
path:"$lib/packages/docutils"
-path:"$nim/compiler"
+path:"../../compiler"
define:useStdoutAsStdmsg
define:nimsuggest
diff --git a/compiler/options.nim b/compiler/options.nim
index 1b4a624abf..998ab77819 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
-# (c) Copyright 2013 Andreas Rumpf
+# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -9,7 +9,7 @@
import
os, lists, strutils, strtabs, osproc, sets
-
+
const
hasTinyCBackend* = defined(tinyc)
useEffectSystem* = true
@@ -21,10 +21,10 @@ const
type # please make sure we have under 32 options
# (improves code efficiency a lot!)
TOption* = enum # **keep binary compatible**
- optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
+ optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
optOverflowCheck, optNilCheck,
optNaNCheck, optInfCheck,
- optAssert, optLineDir, optWarns, optHints,
+ optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
optLineTrace, # line tracing support (includes stack tracing)
optEndb, # embedded debugger
@@ -37,8 +37,8 @@ type # please make sure we have under 32 options
TOptions* = set[TOption]
TGlobalOption* = enum # **keep binary compatible**
- gloptNone, optForceFullMake, optDeadCodeElim,
- optListCmd, optCompileOnly, optNoLinking,
+ gloptNone, optForceFullMake, optDeadCodeElim,
+ optListCmd, optCompileOnly, optNoLinking,
optSafeCode, # only allow safe code
optCDebug, # turn on debugging information
optGenDynLib, # generate a dynamic library
@@ -67,9 +67,9 @@ type # please make sure we have under 32 options
TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nim's commands
# **keep binary compatible**
- cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
- cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
- cmdGenDepend, cmdDump,
+ cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
+ cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
+ cmdGenDepend, cmdDump,
cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging)
cmdScan, # scan a single file (for debugging)
@@ -90,12 +90,12 @@ var
gIdeCmd*: TIdeCmd
const
- ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
+ ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
-var
- gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
- optBoundsCheck, optOverflowCheck, optAssert, optWarns,
+var
+ gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
+ optBoundsCheck, optOverflowCheck, optAssert, optWarns,
optHints, optStackTrace, optLineTrace,
optPatterns, optNilCheck}
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
@@ -129,7 +129,7 @@ template optPreserveOrigSource*: expr =
template optPrintSurroundingSrc*: expr =
gVerbosity >= 2
-const
+const
genSubDir* = "nimcache"
NimExt* = "nim"
RodExt* = "rod"
@@ -168,20 +168,20 @@ proc mainCommandArg*: string =
else:
result = gProjectName
-proc existsConfigVar*(key: string): bool =
+proc existsConfigVar*(key: string): bool =
result = hasKey(gConfigVars, key)
-proc getConfigVar*(key: string): string =
+proc getConfigVar*(key: string): string =
result = gConfigVars[key]
-proc setConfigVar*(key, val: string) =
+proc setConfigVar*(key, val: string) =
gConfigVars[key] = val
-proc getOutFile*(filename, ext: string): string =
+proc getOutFile*(filename, ext: string): string =
if options.outFile != "": result = options.outFile
else: result = changeFileExt(filename, ext)
-
-proc getPrefixDir*(): string =
+
+proc getPrefixDir*(): string =
## gets the application directory
result = splitPath(getAppDir()).head
@@ -189,22 +189,22 @@ proc canonicalizePath*(path: string): string =
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
else: result = path.expandFilename
-proc shortenDir*(dir: string): string =
+proc shortenDir*(dir: string): string =
## returns the interesting part of a dir
var prefix = getPrefixDir() & DirSep
- if startsWith(dir, prefix):
+ if startsWith(dir, prefix):
return substr(dir, len(prefix))
prefix = gProjectPath & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
result = dir
-proc removeTrailingDirSep*(path: string): string =
- if (len(path) > 0) and (path[len(path) - 1] == DirSep):
+proc removeTrailingDirSep*(path: string): string =
+ if (len(path) > 0) and (path[len(path) - 1] == DirSep):
result = substr(path, 0, len(path) - 2)
- else:
+ else:
result = path
-
+
proc getGeneratedPath: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
@@ -257,7 +257,7 @@ proc withPackageName*(path: string): string =
let (p, file, ext) = path.splitFile
result = (p / (x & '_' & file)) & ext
-proc toGeneratedFile*(path, ext: string): string =
+proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path)
#if len(head) > 0: head = shortenDir(head & dirSep)
@@ -301,7 +301,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result
-iterator iterSearchPath*(searchPaths: TLinkedList): string =
+iterator iterSearchPath*(searchPaths: TLinkedList): string =
var it = PStrEntry(searchPaths.head)
while it != nil:
yield it.data
@@ -324,7 +324,7 @@ proc rawFindFile2(f: string): string =
it = PStrEntry(it.next)
result = ""
-proc findFile*(f: string): string {.procvar.} =
+proc findFile*(f: string): string {.procvar.} =
result = f.rawFindFile
if result.len == 0:
result = f.toLower.rawFindFile
@@ -351,7 +351,7 @@ proc findModule*(modulename, currentModule: string): string =
if not existsFile(result):
result = findFile(m)
-proc libCandidates*(s: string, dest: var seq[string]) =
+proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(')
var ri = strutils.find(s, ')', le+1)
if le >= 0 and ri > le:
@@ -359,7 +359,7 @@ proc libCandidates*(s: string, dest: var seq[string]) =
var suffix = substr(s, ri + 1)
for middle in split(substr(s, le + 1, ri - 1), '|'):
libCandidates(prefix & middle & suffix, dest)
- else:
+ else:
add(dest, s)
proc canonDynlibName(s: string): string =
@@ -376,17 +376,17 @@ proc inclDynlibOverride*(lib: string) =
proc isDynlibOverride*(lib: string): bool =
result = gDllOverrides.hasKey(lib.canonDynlibName)
-proc binaryStrSearch*(x: openArray[string], y: string): int =
+proc binaryStrSearch*(x: openArray[string], y: string): int =
var a = 0
var b = len(x) - 1
- while a <= b:
+ while a <= b:
var mid = (a + b) div 2
var c = cmpIgnoreCase(x[mid], y)
- if c < 0:
+ if c < 0:
a = mid + 1
- elif c > 0:
+ elif c > 0:
b = mid - 1
- else:
+ else:
return mid
result = - 1
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 3f67005b9f..b7fe269dfc 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -190,6 +190,8 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
result = arLocalLValue
else:
result = arLValue
+ elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
+ result = arLValue
elif n.sym.kind == skType:
let t = n.sym.typ.skipTypes({tyTypeDesc})
if t.kind == tyVar: result = arStrange
diff --git a/compiler/parser.nim b/compiler/parser.nim
index dcd5401e8a..0d2ba7cfc0 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -91,7 +91,7 @@ proc closeParser(p: var TParser) =
proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
## Produce and emit the parser message `arg` to output.
- lexMessage(p.lex, msg, arg)
+ lexMessageTok(p.lex, msg, p.tok, arg)
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
## Produce and emit a parser message to output about the token `tok`
@@ -154,7 +154,7 @@ proc eat(p: var TParser, tokType: TTokType) =
if p.tok.tokType == tokType:
getTok(p)
else:
- lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
+ lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
proc parLineInfo(p: TParser): TLineInfo =
## Retrieve the line information associated with the parser's current state.
@@ -212,27 +212,29 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
let relevantChar = tok.ident.s[0]
# arrow like?
- if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
+ if L > 1 and tok.ident.s[L-1] == '>' and
+ tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
template considerAsgn(value: expr) =
- result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
+ result = if tok.ident.s[L-1] == '=': 1 else: value
case relevantChar
of '$', '^': considerAsgn(10)
of '*', '%', '/', '\\': considerAsgn(9)
- of '~': result = considerStrongSpaces(8)
+ of '~': result = 8
of '+', '-', '|': considerAsgn(8)
of '&': considerAsgn(7)
- of '=', '<', '>', '!': result = considerStrongSpaces(5)
+ of '=', '<', '>', '!': result = 5
of '.': considerAsgn(6)
- of '?': result = considerStrongSpaces(2)
+ of '?': result = 2
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
- of tkDotDot: result = considerStrongSpaces(6)
+ of tkDotDot: result = 6
of tkAnd: result = 4
of tkOr, tkXor, tkPtr, tkRef: result = 3
- else: result = -10
+ else: return -10
+ result = considerStrongSpaces(result)
proc isOperator(tok: TToken): bool =
## Determines if the given token is an operator type token.
@@ -387,7 +389,6 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
- eat(p, endTok)
proc dotExpr(p: var TParser, a: PNode): PNode =
#| dotExpr = expr '.' optInd symbol
@@ -943,8 +944,7 @@ proc parseDoBlock(p: var TParser): PNode =
getTok(p)
let params = parseParamList(p, retColon=false)
let pragmas = optPragmas(p)
- eat(p, tkColon)
- skipComment(p, result)
+ colcom(p, result)
result = newProcNode(nkDo, info, parseStmt(p),
params = params,
pragmas = pragmas)
@@ -1138,9 +1138,11 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
result = makeCall(result)
getTok(p)
skipComment(p, result)
+ let stmtList = newNodeP(nkStmtList, p)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
- addSon(result, makeStmtList(body))
+ stmtList.add body
+ #addSon(result, makeStmtList(body))
while sameInd(p):
var b: PNode
case p.tok.tokType
@@ -1152,19 +1154,22 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
- eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
- skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
- eat(p, tkColon)
else: break
+ eat(p, tkColon)
addSon(b, parseStmt(p))
- addSon(result, b)
+ addSon(stmtList, b)
if b.kind == nkElse: break
+ if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
+ # to keep backwards compatibility (see tests/vm/tstringnil)
+ result.add stmtList[0]
+ else:
+ result.add stmtList
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
@@ -1309,8 +1314,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
var branch = newNodeP(nkElifBranch, p)
optInd(p, branch)
addSon(branch, parseExpr(p))
- eat(p, tkColon)
- skipComment(p, branch)
+ colcom(p, branch)
addSon(branch, parseStmt(p))
skipComment(p, branch)
addSon(result, branch)
@@ -1318,8 +1322,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
if p.tok.tokType == tkElse and sameOrNoInd(p):
var branch = newNodeP(nkElse, p)
eat(p, tkElse)
- eat(p, tkColon)
- skipComment(p, branch)
+ colcom(p, branch)
addSon(branch, parseStmt(p))
addSon(result, branch)
@@ -1367,13 +1370,11 @@ proc parseCase(p: var TParser): PNode =
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
- eat(p, tkColon)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
- eat(p, tkColon)
else: break
- skipComment(p, b)
+ colcom(p, b)
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
@@ -1390,8 +1391,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
#| (optInd 'finally' colcom stmt)?
result = newNodeP(nkTryStmt, p)
getTok(p)
- eat(p, tkColon)
- skipComment(p, result)
+ colcom(p, result)
addSon(result, parseStmt(p))
var b: PNode = nil
while sameOrNoInd(p) or isExpr:
@@ -1401,10 +1401,9 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
exprList(p, tkColon, b)
of tkFinally:
b = newNodeP(nkFinally, p)
- getTokNoInd(p)
- eat(p, tkColon)
+ getTok(p)
else: break
- skipComment(p, b)
+ colcom(p, b)
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkFinally: break
@@ -1413,7 +1412,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
#| exceptBlock = 'except' colcom stmt
result = newNodeP(kind, p)
- getTokNoInd(p)
+ getTok(p)
colcom(p, result)
addSon(result, parseStmt(p))
@@ -1446,7 +1445,7 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
#| staticStmt = 'static' colcom stmt
#| deferStmt = 'defer' colcom stmt
result = newNodeP(k, p)
- getTokNoInd(p)
+ getTok(p)
colcom(p, result)
addSon(result, parseStmt(p))
@@ -1627,7 +1626,7 @@ proc parseEnum(p: var TParser): PNode =
p.tok.tokType == tkEof:
break
if result.len <= 1:
- lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+ lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
proc parseObjectPart(p: var TParser): PNode
proc parseObjectWhen(p: var TParser): PNode =
@@ -1685,9 +1684,8 @@ proc parseObjectCase(p: var TParser): PNode =
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
- eat(p, tkColon)
else: break
- skipComment(p, b)
+ colcom(p, b)
var fields = parseObjectPart(p)
if fields.kind == nkEmpty:
parMessage(p, errIdentifierExpected, p.tok)
@@ -1883,7 +1881,7 @@ proc simpleStmt(p: var TParser): PNode =
proc complexOrSimpleStmt(p: var TParser): PNode =
#| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
- #| | tryStmt | finallyStmt | exceptStmt | forStmt
+ #| | tryStmt | forStmt
#| | blockStmt | staticStmt | deferStmt | asmStmt
#| | 'proc' routine
#| | 'method' routine
@@ -2030,8 +2028,8 @@ proc parseString*(s: string; filename: string = ""; line: int = 0;
var parser: TParser
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces...
- openParser(parser, filename, stream, false)
parser.lex.errorHandler = errorHandler
+ openParser(parser, filename, stream, false)
result = parser.parseAll
closeParser(parser)
diff --git a/compiler/plugins.nim b/compiler/plugins.nim
new file mode 100644
index 0000000000..1c9b7b77b8
--- /dev/null
+++ b/compiler/plugins.nim
@@ -0,0 +1,43 @@
+#
+#
+# The Nim Compiler
+# (c) Copyright 2015 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## Plugin support for the Nim compiler. Right now there are no plugins and they
+## need to be build with the compiler, no DLL support.
+
+import ast, semdata, idents
+
+type
+ Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
+ Plugin = ref object
+ fn, module, package: PIdent
+ t: Transformation
+ next: Plugin
+
+proc pluginMatches(p: Plugin; s: PSym): bool =
+ if s.name.id != p.fn.id: return false
+ let module = s.owner
+ if module == nil or module.kind != skModule or
+ module.name.id != p.module.id: return false
+ let package = module.owner
+ if package == nil or package.kind != skPackage or
+ package.name.id != p.package.id: return false
+ return true
+
+var head: Plugin
+
+proc getPlugin*(fn: PSym): Transformation =
+ var it = head
+ while it != nil:
+ if pluginMatches(it, fn): return it.t
+ it = it.next
+
+proc registerPlugin*(package, module, fn: string; t: Transformation) =
+ let oldHead = head
+ head = Plugin(fn: getIdent(fn), module: getIdent(module),
+ package: getIdent(package), t: t, next: oldHead)
diff --git a/compiler/plugins/active.nim b/compiler/plugins/active.nim
new file mode 100644
index 0000000000..e9c11c2ea7
--- /dev/null
+++ b/compiler/plugins/active.nim
@@ -0,0 +1,13 @@
+#
+#
+# The Nim Compiler
+# (c) Copyright 2015 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## Include file that imports all plugins that are active.
+
+import
+ locals.locals
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
new file mode 100644
index 0000000000..d89149f338
--- /dev/null
+++ b/compiler/plugins/locals/locals.nim
@@ -0,0 +1,42 @@
+#
+#
+# The Nim Compiler
+# (c) Copyright 2015 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## The builtin 'system.locals' implemented as a plugin.
+
+import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
+
+proc semLocals(c: PContext, n: PNode): PNode =
+ var counter = 0
+ var tupleType = newTypeS(tyTuple, c)
+ result = newNodeIT(nkPar, n.info, tupleType)
+ tupleType.n = newNodeI(nkRecList, n.info)
+ # for now we skip openarrays ...
+ for scope in walkScopes(c.currentScope):
+ if scope == c.topLevelScope: break
+ for it in items(scope.symbols):
+ # XXX parameters' owners are wrong for generics; this caused some pain
+ # for closures too; we should finally fix it.
+ #if it.owner != c.p.owner: return result
+ if it.kind in skLocalVars and
+ it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
+ {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
+
+ var field = newSym(skField, it.name, getCurrOwner(), n.info)
+ field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
+ field.position = counter
+ inc(counter)
+
+ addSon(tupleType.n, newSymNode(field))
+ addSonSkipIntLit(tupleType, field.typ)
+
+ var a = newSymNode(it, result.info)
+ if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
+ result.add(a)
+
+registerPlugin("stdlib", "system", "locals", semLocals)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 056e4f4c0b..c048d78e9e 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -60,7 +60,7 @@ const
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
- wGensym, wInject, wCodegenDecl, wGuard}
+ wGensym, wInject, wCodegenDecl, wGuard, wGoto}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
letPragmas* = varPragmas
@@ -89,7 +89,7 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
invalidPragma(it)
proc setExternName(s: PSym, extname: string) =
- s.loc.r = toRope(extname % s.name.s)
+ s.loc.r = rope(extname % s.name.s)
if gCmd == cmdPretty and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
@@ -105,7 +105,7 @@ proc validateExternCName(s: PSym, info: TLineInfo) =
## Valid identifiers are those alphanumeric including the underscore not
## starting with a number. If the check fails, a generic error will be
## displayed to the user.
- let target = ropeToStr(s.loc.r)
+ let target = $s.loc.r
if target.len < 1 or target[0] notin IdentStartChars or
not target.allCharsInSet(IdentChars):
localError(info, errGenerated, "invalid exported symbol")
@@ -677,7 +677,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
- if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
+ if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
of wDestructor:
sym.flags.incl sfOverriden
if sym.name.s.normalize != "destroy":
@@ -843,6 +843,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
invalidPragma(it)
else:
sym.guard = pragmaGuard(c, it, sym.kind)
+ of wGoto:
+ if sym == nil or sym.kind notin {skVar, skLet}:
+ invalidPragma(it)
+ else:
+ sym.flags.incl sfGoto
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
@@ -865,9 +870,11 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
while it != nil:
let o = it.otherPragmas
if not o.isNil:
+ pushInfoContext(n.info)
for i in countup(0, sonsLen(o) - 1):
if singlePragma(c, sym, o, i, validPragmas):
internalError(n.info, "implicitPragmas")
+ popInfoContext()
it = it.next.POptionEntry
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
@@ -877,7 +884,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
sfImportc in sym.flags and lib != nil:
incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym)
- if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
+ if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil:
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index ce818e3cd6..ffdb606964 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -503,6 +503,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
proc hasCom(n: PNode): bool =
result = false
+ if n.isNil: return false
if n.comment != nil: return true
case n.kind
of nkEmpty..nkNilLit: discard
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 545a8dda93..e92f7ecfa4 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -277,7 +277,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.t = nil
if r.s[r.pos] == '!':
inc(r.pos)
- loc.r = toRope(decodeStr(r.s, r.pos))
+ loc.r = rope(decodeStr(r.s, r.pos))
else:
loc.r = nil
if r.s[r.pos] == '>': inc(r.pos)
@@ -344,7 +344,7 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 1")
inc(r.pos)
- result.name = toRope(decodeStr(r.s, r.pos))
+ result.name = rope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 2")
inc(r.pos)
result.path = decodeNode(r, info)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 0f211b4baf..e178b7ce6e 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -186,7 +186,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
- encodeStr(ropeToStr(loc.r), result)
+ encodeStr($loc.r, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
@@ -241,7 +241,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|')
encodeVInt(ord(lib.kind), result)
add(result, '|')
- encodeStr(ropeToStr(lib.name), result)
+ encodeStr($lib.name, result)
add(result, '|')
encodeNode(w, info, lib.path, result)
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index ae71234c44..edac8e9d0c 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -56,77 +56,59 @@
# To cache them they are inserted in a `cache` array.
import
- strutils, platform, hashes, crc, options
+ platform, hashes
type
- TFormatStr* = string # later we may change it to CString for better
+ FormatStr* = string # later we may change it to CString for better
# performance of the code generator (assignments
# copy the format strings
# though it is not necessary)
- PRope* = ref TRope
- TRope*{.acyclic.} = object of RootObj # the empty rope is represented
- # by nil to safe space
- left*, right*: PRope
+ Rope* = ref RopeObj
+ RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
+ # by nil to safe space
+ left*, right*: Rope
length*: int
data*: string # != nil if a leaf
- TRopeSeq* = seq[PRope]
+ RopeSeq* = seq[Rope]
- TRopesError* = enum
+ RopesError* = enum
rCannotOpenFile
rInvalidFormatStr
- rTokenTooLong
-proc con*(a, b: PRope): PRope
-proc con*(a: PRope, b: string): PRope
-proc con*(a: string, b: PRope): PRope
-proc con*(a: varargs[PRope]): PRope
-proc app*(a: var PRope, b: PRope)
-proc app*(a: var PRope, b: string)
-proc prepend*(a: var PRope, b: PRope)
-proc toRope*(s: string): PRope
-proc toRope*(i: BiggestInt): PRope
-proc ropeLen*(a: PRope): int
-proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
-proc ropeToStr*(p: PRope): string
-proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
-proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
-proc ropeEqualsFile*(r: PRope, f: string): bool
- # returns true if the rope r is the same as the contents of file f
-proc ropeInvariant*(r: PRope): bool
- # exported for debugging
# implementation
-var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
+var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
# avoid dependency on msgs.nim
-proc ropeLen(a: PRope): int =
+proc len*(a: Rope): int =
+ ## the rope's length
if a == nil: result = 0
else: result = a.length
-proc newRope*(data: string = nil): PRope =
+proc newRope(data: string = nil): Rope =
new(result)
if data != nil:
result.length = len(data)
result.data = data
-proc newMutableRope*(capacity = 30): PRope =
+proc newMutableRope*(capacity = 30): Rope =
## creates a new rope that supports direct modifications of the rope's
## 'data' and 'length' fields.
new(result)
result.data = newStringOfCap(capacity)
-proc freezeMutableRope*(r: PRope) {.inline.} =
+proc freezeMutableRope*(r: Rope) {.inline.} =
r.length = r.data.len
var
- cache: array[0..2048*2 - 1, PRope]
+ cache: array[0..2048*2 - 1, Rope]
proc resetRopeCache* =
for i in low(cache)..high(cache):
cache[i] = nil
-proc ropeInvariant(r: PRope): bool =
+proc ropeInvariant(r: Rope): bool =
if r == nil:
result = true
else:
@@ -143,7 +125,7 @@ var gCacheTries* = 0
var gCacheMisses* = 0
var gCacheIntTries* = 0
-proc insertInCache(s: string): PRope =
+proc insertInCache(s: string): Rope =
inc gCacheTries
var h = hash(s) and high(cache)
result = cache[h]
@@ -152,82 +134,77 @@ proc insertInCache(s: string): PRope =
result = newRope(s)
cache[h] = result
-proc toRope(s: string): PRope =
+proc rope*(s: string): Rope =
+ ## Converts a string to a rope.
if s.len == 0:
result = nil
else:
result = insertInCache(s)
assert(ropeInvariant(result))
-proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
- var length = len(rs)
- if at > length:
- setLen(rs, at + 1)
- else:
- setLen(rs, length + 1) # move old rope elements:
- for i in countdown(length, at + 1):
- rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
- rs[at] = r
+proc rope*(i: BiggestInt): Rope =
+ ## Converts an int to a rope.
+ inc gCacheIntTries
+ result = rope($i)
-proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
- var stack = @[r]
- while len(stack) > 0:
- var it = pop(stack)
- while it.data == nil:
- add(stack, it.right)
- it = it.left
- assert(it.data != nil)
- copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
- inc(resultLen, it.length)
- assert(resultLen <= len(result))
+proc rope*(f: BiggestFloat): Rope =
+ ## Converts a float to a rope.
+ result = rope($f)
-proc ropeToStr(p: PRope): string =
- if p == nil:
- result = ""
- else:
- result = newString(p.length)
- var resultLen = 0
- newRecRopeToStr(result, resultLen, p)
-
-proc con(a, b: PRope): PRope =
- if a == nil: result = b
- elif b == nil: result = a
+proc `&`*(a, b: Rope): Rope =
+ if a == nil:
+ result = b
+ elif b == nil:
+ result = a
else:
result = newRope()
result.length = a.length + b.length
result.left = a
result.right = b
-proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
-proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
+proc `&`*(a: Rope, b: string): Rope =
+ ## the concatenation operator for ropes.
+ result = a & rope(b)
-proc con(a: varargs[PRope]): PRope =
- for i in countup(0, high(a)): result = con(result, a[i])
+proc `&`*(a: string, b: Rope): Rope =
+ ## the concatenation operator for ropes.
+ result = rope(a) & b
-proc ropeConcat*(a: varargs[PRope]): PRope =
- # not overloaded version of concat to speed-up `rfmt` a little bit
- for i in countup(0, high(a)): result = con(result, a[i])
+proc `&`*(a: openArray[Rope]): Rope =
+ ## the concatenation operator for an openarray of ropes.
+ for i in countup(0, high(a)): result = result & a[i]
-proc toRope(i: BiggestInt): PRope =
- inc gCacheIntTries
- result = toRope($i)
+proc add*(a: var Rope, b: Rope) =
+ ## adds `b` to the rope `a`.
+ a = a & b
-proc app(a: var PRope, b: PRope) = a = con(a, b)
-proc app(a: var PRope, b: string) = a = con(a, b)
-proc prepend(a: var PRope, b: PRope) = a = con(b, a)
+proc add*(a: var Rope, b: string) =
+ ## adds `b` to the rope `a`.
+ a = a & b
-proc writeRope*(f: File, c: PRope) =
- var stack = @[c]
- while len(stack) > 0:
- var it = pop(stack)
- while it.data == nil:
- add(stack, it.right)
- it = it.left
- assert(it != nil)
- assert(it.data != nil)
- write(f, it.data)
+iterator leaves*(r: Rope): string =
+ ## iterates over any leaf string in the rope `r`.
+ if r != nil:
+ var stack = @[r]
+ while stack.len > 0:
+ var it = stack.pop
+ while isNil(it.data):
+ stack.add(it.right)
+ it = it.left
+ assert(it != nil)
+ assert(it.data != nil)
+ yield it.data
-proc writeRope*(head: PRope, filename: string, useWarning = false) =
+iterator items*(r: Rope): char =
+ ## iterates over any character in the rope `r`.
+ for s in leaves(r):
+ for c in items(s): yield c
+
+proc writeRope*(f: File, r: Rope) =
+ ## writes a rope to a file.
+ for s in leaves(r): write(f, s)
+
+proc writeRope*(head: Rope, filename: string, useWarning = false) =
var f: File
if open(f, filename, fmWrite):
if head != nil: writeRope(f, head)
@@ -235,42 +212,69 @@ proc writeRope*(head: PRope, filename: string, useWarning = false) =
else:
errorHandler(rCannotOpenFile, filename, useWarning)
+proc `$`*(r: Rope): string =
+ ## converts a rope back to a string.
+ result = newString(r.len)
+ setLen(result, 0)
+ for s in leaves(r): add(result, s)
+
+proc ropeConcat*(a: varargs[Rope]): Rope =
+ # not overloaded version of concat to speed-up `rfmt` a little bit
+ for i in countup(0, high(a)): result = result & a[i]
+
+proc prepend*(a: var Rope, b: Rope) = a = b & a
+proc prepend*(a: var Rope, b: string) = a = b & a
+
var
rnl* = tnl.newRope
softRnl* = tnl.newRope
-proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
+proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
var i = 0
var length = len(frmt)
result = nil
var num = 0
- while i <= length - 1:
+ while i < length:
if frmt[i] == '$':
inc(i) # skip '$'
case frmt[i]
of '$':
- app(result, "$")
+ add(result, "$")
inc(i)
of '#':
inc(i)
- app(result, args[num])
+ add(result, args[num])
inc(num)
of '0'..'9':
var j = 0
while true:
- j = (j * 10) + ord(frmt[i]) - ord('0')
+ j = j * 10 + ord(frmt[i]) - ord('0')
inc(i)
- if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
+ if frmt[i] notin {'0'..'9'}: break
num = j
if j > high(args) + 1:
errorHandler(rInvalidFormatStr, $(j))
else:
- app(result, args[j - 1])
+ add(result, args[j-1])
+ of '{':
+ inc(i)
+ var j = 0
+ while frmt[i] in {'0'..'9'}:
+ j = j * 10 + ord(frmt[i]) - ord('0')
+ inc(i)
+ num = j
+ if frmt[i] == '}': inc(i)
+ else: errorHandler(rInvalidFormatStr, $(frmt[i]))
+
+ if j > high(args) + 1:
+ errorHandler(rInvalidFormatStr, $(j))
+ else:
+ add(result, args[j-1])
of 'n':
- app(result, softRnl)
- inc i
+ add(result, softRnl)
+ inc(i)
of 'N':
- app(result, rnl)
+ add(result, rnl)
inc(i)
else:
errorHandler(rInvalidFormatStr, $(frmt[i]))
@@ -279,83 +283,67 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
- app(result, substr(frmt, start, i - 1))
+ add(result, substr(frmt, start, i - 1))
assert(ropeInvariant(result))
+proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
+ ## shortcut for ``add(c, frmt % args)``.
+ add(c, frmt % args)
+
when true:
- template `~`*(r: string): PRope = r.ropef
+ template `~`*(r: string): Rope = r % []
else:
{.push stack_trace: off, line_trace: off.}
- proc `~`*(r: static[string]): PRope =
+ proc `~`*(r: static[string]): Rope =
# this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :)
- var r {.global.} = r.ropef
+ var r {.global.} = r % []
return r
{.pop.}
-proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
- app(c, ropef(frmt, args))
-
const
bufSize = 1024 # 1 KB is reasonable
-proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
- if r.data != nil:
- if r.length > bufSize:
- errorHandler(rTokenTooLong, r.data)
- return
- var readBytes = readBuffer(bin, buf, r.length)
- result = readBytes == r.length and
- equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
- else:
- result = auxRopeEqualsFile(r.left, bin, buf)
- if result: result = auxRopeEqualsFile(r.right, bin, buf)
+proc equalsFile*(r: Rope, f: File): bool =
+ ## returns true if the contents of the file `f` equal `r`.
+ var
+ buf: array[bufSize, char]
+ bpos = buf.len
+ blen = buf.len
-proc ropeEqualsFile(r: PRope, f: string): bool =
- var bin: File
- result = open(bin, f)
- if not result:
- return # not equal if file does not exist
- var buf = alloc(bufSize)
- result = auxRopeEqualsFile(r, bin, buf)
+ for s in leaves(r):
+ var spos = 0
+ let slen = s.len
+ while spos < slen:
+ if bpos == blen:
+ # Read more data
+ bpos = 0
+ blen = readBuffer(f, addr(buf[0]), buf.len)
+ if blen == 0: # no more data in file
+ result = false
+ return
+ let n = min(blen - bpos, slen - spos)
+ # TODO There's gotta be a better way of comparing here...
+ if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
+ result = false
+ return
+ spos += n
+ bpos += n
+
+ result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
+
+proc equalsFile*(r: Rope, filename: string): bool =
+ ## returns true if the contents of the file `f` equal `r`. If `f` does not
+ ## exist, false is returned.
+ var f: File
+ result = open(f, filename)
if result:
- result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
- dealloc(buf)
- close(bin)
+ result = equalsFile(r, f)
+ close(f)
-proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
- if r.data != nil:
- result = startVal
- for i in countup(0, len(r.data) - 1):
- result = updateCrc32(r.data[i], result)
- else:
- result = crcFromRopeAux(r.left, startVal)
- result = crcFromRopeAux(r.right, result)
-
-proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
- # XXX profiling shows this is actually expensive
- var stack: TRopeSeq = @[r]
- result = startVal
- while len(stack) > 0:
- var it = pop(stack)
- while it.data == nil:
- add(stack, it.right)
- it = it.left
- assert(it.data != nil)
- var i = 0
- var L = len(it.data)
- while i < L:
- result = updateCrc32(it.data[i], result)
- inc(i)
-
-proc crcFromRope(r: PRope): TCrc32 =
- result = newCrcFromRopeAux(r, InitCrc32)
-
-proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
+proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
# returns true if overwritten
- var c: TCrc32
- c = crcFromFile(filename)
- if c != crcFromRope(r):
+ if not equalsFile(r, filename):
writeRope(r, filename)
result = true
else:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 2d2f15fab6..346a17df1a 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,7 +16,7 @@ import
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
- semparallel, lowerings
+ semparallel, lowerings, plugins, plugins.active
when defined(nimfix):
import nimfix.prettybase
@@ -89,6 +89,10 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
let x = result.skipConv
if x.kind == nkPar and formal.kind != tyExpr:
changeType(x, formal, check=true)
+ else:
+ result = skipHiddenSubConv(result)
+ #result.typ = takeType(formal, arg.typ)
+ #echo arg.info, " picked ", result.typ.typeToString
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode
@@ -398,7 +402,7 @@ proc myOpen(module: PSym): PPassContext =
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
- c.instDeepCopy = sigmatch.instDeepCopy
+ c.instTypeBoundOp = sigmatch.instTypeBoundOp
pushProcCon(c, module)
pushOwner(c.module)
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 208c4ce1a6..a1e209263d 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -7,111 +7,84 @@
# distribution, for details about the copyright.
#
-## This module implements lifting for assignments and ``deepCopy``.
+## This module implements lifting for assignments. Later versions of this code
+## will be able to also lift ``=deepCopy`` and ``=destroy``.
# included from sem.nim
type
- TTypeAttachedOp = enum
- attachedDestructor,
- attachedAsgn,
- attachedDeepCopy
-
TLiftCtx = object
c: PContext
info: TLineInfo # for construction
- result: PNode
kind: TTypeAttachedOp
+ fn: PSym
+ asgnForType: PType
+ recurse: bool
-type
- TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
- tupleType: PType # if != nil we're traversing a tuple
- tupleIndex: int
- field: PSym
- replaceByFieldName: bool
+proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
+proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
-proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
+proc at(a, i: PNode, elemType: PType): PNode =
+ result = newNodeI(nkBracketExpr, a.info, 2)
+ result.sons[0] = a
+ result.sons[1] = i
+ result.typ = elemType
+
+proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
+ for i in 0 .. 2:
- localError(forLoop.info, errGenerated,
- "parallel 'fields' iterator does not work for 'case' objects")
- return
- # iterate over the selector:
- asgnForObjectFields(c, typ[0], forLoop, father)
+ # copy the selector:
+ liftBodyObj(c, n[0], body, x, y)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, c.info)
+ # XXX generate 'if' that checks same branches
# generate selector:
- var access = newNodeI(nkDotExpr, forLoop.info, 2)
- access.sons[0] = call.sons[1]
- access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
- caseStmt.add(semExprWithType(c.c, access))
+ var access = dotField(x, n[0].sym)
+ caseStmt.add(access)
# copy the branches over, but replace the fields with the for loop body:
- for i in 1 .. = isSubtype # isNone
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
@@ -447,6 +447,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
of nkPar:
let tup = newType.skipTypes({tyGenericInst})
if tup.kind != tyTuple:
+ if tup.kind == tyObject: return
internalError(n.info, "changeType: no tuple type for constructor")
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
# named tuple?
@@ -535,43 +536,55 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
proc fixAbstractType(c: PContext, n: PNode) =
- # XXX finally rewrite that crap!
- for i in countup(1, sonsLen(n) - 1):
- var it = n.sons[i]
- case it.kind
- of nkHiddenStdConv, nkHiddenSubConv:
- if it.sons[1].kind == nkBracket:
- it.sons[1].typ = arrayConstrType(c, it.sons[1])
- #it.sons[1] = semArrayConstr(c, it.sons[1])
- if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
- #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
- # debug(n)
-
- var s = skipTypes(it.sons[1].typ, abstractVar)
- if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
- s = copyType(s, getCurrOwner(), false)
- skipTypes(s, abstractVar).sons[1] = elemType(
- skipTypes(it.typ, abstractVar))
- it.sons[1].typ = s
- elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
- s = copyType(s, getCurrOwner(), false)
- skipTypes(s, abstractVar).sons[0] = elemType(
- skipTypes(it.typ, abstractVar))
- it.sons[1].typ = s
-
- elif skipTypes(it.sons[1].typ, abstractVar).kind in
- {tyNil, tyArrayConstr, tyTuple, tySet}:
+ for i in 1 .. < n.len:
+ let it = n.sons[i]
+ # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
+ if it.kind == nkHiddenSubConv and
+ skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
+ if skipTypes(it.sons[1].typ, abstractVar).kind in
+ {tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar)
if s.kind != tyExpr:
changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1]
- of nkBracket:
- # an implicitly constructed array (passed to an open array):
- n.sons[i] = semArrayConstr(c, it, {})
- else:
- discard
- #if (it.typ == nil):
- # InternalError(it.info, "fixAbstractType: " & renderTree(it))
+ when false:
+ # XXX finally rewrite that crap!
+ for i in countup(1, sonsLen(n) - 1):
+ var it = n.sons[i]
+ case it.kind
+ of nkHiddenStdConv, nkHiddenSubConv:
+ if it.sons[1].kind == nkBracket:
+ it.sons[1].typ = arrayConstrType(c, it.sons[1])
+ #it.sons[1] = semArrayConstr(c, it.sons[1])
+ if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
+ #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
+ # debug(n)
+
+ var s = skipTypes(it.sons[1].typ, abstractVar)
+ if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
+ s = copyType(s, getCurrOwner(), false)
+ skipTypes(s, abstractVar).sons[1] = elemType(
+ skipTypes(it.typ, abstractVar))
+ it.sons[1].typ = s
+ elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
+ s = copyType(s, getCurrOwner(), false)
+ skipTypes(s, abstractVar).sons[0] = elemType(
+ skipTypes(it.typ, abstractVar))
+ it.sons[1].typ = s
+
+ elif skipTypes(it.sons[1].typ, abstractVar).kind in
+ {tyNil, tyArrayConstr, tyTuple, tySet}:
+ var s = skipTypes(it.typ, abstractVar)
+ if s.kind != tyExpr:
+ changeType(it.sons[1], s, check=true)
+ n.sons[i] = it.sons[1]
+ of nkBracket:
+ # an implicitly constructed array (passed to an open array):
+ n.sons[i] = semArrayConstr(c, it, {})
+ else:
+ discard
+ #if (it.typ == nil):
+ # InternalError(it.info, "fixAbstractType: " & renderTree(it))
proc skipObjConv(n: PNode): PNode =
case n.kind
@@ -1298,6 +1311,9 @@ proc semAsgn(c: PContext, n: PNode): PNode =
typeMismatch(n, lhs.typ, rhs.typ)
n.sons[1] = fitNode(c, le, rhs)
+ if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
+ return overloadedAsgn(c, lhs, n.sons[1])
+
fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n
@@ -2037,7 +2053,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkEmpty, nkNone, nkCommentStmt:
discard
of nkNilLit:
- result.typ = getSysType(tyNil)
+ if result.typ == nil: result.typ = getSysType(tyNil)
of nkIntLit:
if result.typ == nil: setIntLitType(result)
of nkInt8Lit:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 2e71796737..da24005c2d 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -118,6 +118,9 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
let lowerNode = newIntNode(nkIntLit, minA)
if typ.kind == tyInt and minA == maxA:
result = getIntLitType(lowerNode)
+ elif typ.kind in {tyUint, tyUInt64}:
+ # these are not ordinal types, so you get no subrange type for these:
+ result = typ
else:
var n = newNode(nkRange)
addSon(n, lowerNode)
@@ -135,8 +138,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc getIntervalType*(m: TMagic, n: PNode): PType =
- # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
+ # Nim requires interval arithmetic for ``range`` types. Lots of tedious
# work but the feature is very nice for reducing explicit conversions.
+ const ordIntLit = {nkIntLit..nkUInt64Lit}
result = n.typ
template commutativeOp(opr: expr) {.immediate.} =
@@ -170,13 +174,19 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
let a = n.sons[1].typ
if isFloatRange(a):
# abs(-5.. 1) == (1..5)
- result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
- abs(getFloat(a.n.sons[0])))
+ if a.n[0].floatVal <= 0.0:
+ result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
+ else:
+ result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
+ abs(getFloat(a.n.sons[0])))
of mAbsI, mAbsI64:
let a = n.sons[1].typ
if isIntRange(a):
- result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
- `|abs|`(getInt(a.n.sons[0])))
+ if a.n[0].intVal <= 0:
+ result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
+ else:
+ result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
+ `|abs|`(getInt(a.n.sons[0])))
of mSucc:
let a = n.sons[1].typ
let b = n.sons[2].typ
@@ -202,15 +212,15 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
var a = n.sons[1]
var b = n.sons[2]
# symmetrical:
- if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
- if b.kind in {nkIntLit..nkUInt32Lit}:
+ if b.kind notin ordIntLit: swap(a, b)
+ if b.kind in ordIntLit:
let x = b.intVal|+|1
if (x and -x) == x and x >= 0:
result = makeRange(a.typ, 0, b.intVal)
of mModU:
let a = n.sons[1]
let b = n.sons[2]
- if b.kind in {nkIntLit..nkUInt32Lit}:
+ if a.kind in ordIntLit:
if b.intVal >= 0:
result = makeRange(a.typ, 0, b.intVal-1)
else:
@@ -226,9 +236,9 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
of mDivI, mDivI64, mDivU:
binaryOp(`|div|`)
- of mMinI, mMinI64:
+ of mMinI:
commutativeOp(min)
- of mMaxI, mMaxI64:
+ of mMaxI:
commutativeOp(max)
else: discard
@@ -276,10 +286,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mNot: result = newIntNodeT(1 - getInt(a), n)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
- of mLengthStr: result = newIntNodeT(len(getStr(a)), n)
+ of mLengthStr, mXLenStr:
+ if a.kind == nkNilLit: result = newIntNodeT(0, n)
+ else: result = newIntNodeT(len(getStr(a)), n)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
- of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX
- of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
+ of mLengthSeq, mLengthOpenArray, mXLenSeq:
+ if a.kind == nkNilLit: result = newIntNodeT(0, n)
+ else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
+ of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n)
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
@@ -299,10 +313,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
- of mMinI, mMinI64:
+ of mMinI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
else: result = newIntNodeT(getInt(a), n)
- of mMaxI, mMaxI64:
+ of mMaxI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
else: result = newIntNodeT(getInt(b), n)
of mShlI, mShlI64:
@@ -420,7 +434,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
- mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
+ mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
+ mParallel, mPlugin:
discard
else: internalError(a.info, "evalOp(" & $m & ')')
@@ -513,7 +528,7 @@ proc rangeCheck(n: PNode, value: BiggestInt) =
proc foldConv*(n, a: PNode; check = false): PNode =
# XXX range checks?
case skipTypes(n.typ, abstractRange).kind
- of tyInt..tyInt64:
+ of tyInt..tyInt64, tyUInt..tyUInt64:
case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n)
@@ -640,7 +655,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = copyNode(n)
of nkIfExpr:
result = getConstIfExpr(m, n)
- of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
+ of nkCallKinds:
if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym
if s.kind != skProc: return
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index dc36ecf34a..b2aef63a80 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -176,7 +176,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
for i in 1 .. 1: resetIdTable(cl.symMap)
+ if i > 1:
+ resetIdTable(cl.symMap)
+ resetIdTable(cl.localCache)
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
internalAssert originalParams[i].kind == nkSym
@@ -185,7 +187,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
let param = copySym(oldParam)
param.owner = prc
param.typ = result.sons[i]
- param.ast = oldParam.ast.copyTree
+ if oldParam.ast != nil:
+ param.ast = fitNode(c, param.typ, oldParam.ast)
+
# don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
result.n.sons[i] = newSymNode(param)
addDecl(c, param)
@@ -196,6 +200,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
addDecl(c, result.n.sons[i].sym)
resetIdTable(cl.symMap)
+ resetIdTable(cl.localCache)
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
result.n.sons[0] = originalParams[0].copyTree
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index 2ef7a54e7e..bb9814a169 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -16,9 +16,9 @@ proc ithField(n: PNode, field: int): PSym =
result = nil
case n.kind
of nkRecList:
- for i in countup(0, sonsLen(n) - 1):
+ for i in countup(0, sonsLen(n) - 1):
result = ithField(n.sons[i], field-i)
- if result != nil: return
+ if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
result = ithField(n.sons[0], field-1)
@@ -34,7 +34,7 @@ proc ithField(n: PNode, field: int): PSym =
else: discard
proc annotateType*(n: PNode, t: PType) =
- let x = t.skipTypes(abstractInst)
+ let x = t.skipTypes(abstractInst+{tyRange})
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
case n.kind
@@ -80,7 +80,7 @@ proc annotateType*(n: PNode, t: PType) =
if x.kind in {tyString, tyCString}:
n.typ = t
else:
- globalError(n.info, "string literal must be of some string type")
+ globalError(n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes:
n.typ = t
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index de7700be6d..0a7846f1de 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -54,7 +54,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
result.typ = newType(tyString, context)
result.info = trait.info
of "arity":
- result = newIntNode(nkIntLit, typ.n.len-1)
+ result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
result.typ = newType(tyInt, context)
result.info = trait.info
else:
@@ -101,34 +101,6 @@ proc semBindSym(c: PContext, n: PNode): PNode =
else:
localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
-proc semLocals(c: PContext, n: PNode): PNode =
- var counter = 0
- var tupleType = newTypeS(tyTuple, c)
- result = newNodeIT(nkPar, n.info, tupleType)
- tupleType.n = newNodeI(nkRecList, n.info)
- # for now we skip openarrays ...
- for scope in walkScopes(c.currentScope):
- if scope == c.topLevelScope: break
- for it in items(scope.symbols):
- # XXX parameters' owners are wrong for generics; this caused some pain
- # for closures too; we should finally fix it.
- #if it.owner != c.p.owner: return result
- if it.kind in skLocalVars and
- it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
- {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
-
- var field = newSym(skField, it.name, getCurrOwner(), n.info)
- field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
- field.position = counter
- inc(counter)
-
- addSon(tupleType.n, newSymNode(field))
- addSonSkipIntLit(tupleType, field.typ)
-
- var a = newSymNode(it, result.info)
- if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
- result.add(a)
-
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
proc isStrangeArray(t: PType): bool =
@@ -161,7 +133,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n)
- of mLocals: result = semLocals(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
@@ -196,4 +167,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result.add newSymNode(createMagic("-", mSubI), n.info)
result.add lenExprB
result.add n.sons[1]
+ of mPlugin:
+ let plugin = getPlugin(n[0].sym)
+ if plugin.isNil:
+ localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+ result = n
+ else:
+ result = plugin(c, n)
else: result = n
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 48f54fa6c2..adf03be641 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -194,8 +194,38 @@ proc warnAboutGcUnsafe(n: PNode) =
#assert false
message(n.info, warnGcUnsafe, renderTree(n))
-template markGcUnsafe(a: PEffects) =
+proc markGcUnsafe(a: PEffects; reason: PSym) =
a.gcUnsafe = true
+ if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
+
+proc markGcUnsafe(a: PEffects; reason: PNode) =
+ a.gcUnsafe = true
+ if a.owner.kind in routineKinds:
+ if reason.kind == nkSym:
+ a.owner.gcUnsafetyReason = reason.sym
+ else:
+ a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent(""),
+ a.owner, reason.info)
+
+proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+ let u = s.gcUnsafetyReason
+ if u != nil:
+ let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
+ if u.kind in {skLet, skVar}:
+ message(s.info, msgKind,
+ ("'$#' is not GC-safe as it accesses '$#'" &
+ " which is a global using GC'ed memory") % [s.name.s, u.name.s])
+ elif u.kind in routineKinds:
+ # recursive call *always* produces only a warning so the full error
+ # message is printed:
+ listGcUnsafety(u, true)
+ message(s.info, msgKind,
+ "'$#' is not GC-safe as it calls '$#'" %
+ [s.name.s, u.name.s])
+ else:
+ internalAssert u.kind == skUnknown
+ message(u.info, msgKind,
+ "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
@@ -210,8 +240,8 @@ proc useVar(a: PEffects, n: PNode) =
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
if s.guard != nil: guardGlobal(a, n, s.guard)
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
- if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
- markGcUnsafe(a)
+ #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+ markGcUnsafe(a, s)
type
TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -450,7 +480,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
if notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
- markGcUnsafe(tracked)
+ markGcUnsafe(tracked, s)
mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@@ -504,13 +534,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
# assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
- markGcUnsafe(tracked)
+ markGcUnsafe(tracked, a)
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
- markGcUnsafe(tracked)
+ markGcUnsafe(tracked, a)
notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool =
@@ -530,7 +560,10 @@ proc trackCase(tracked: PEffects, n: PNode) =
track(tracked, n.sons[0])
let oldState = tracked.init.len
let oldFacts = tracked.guards.len
- let interesting = interestingCaseExpr(n.sons[0]) and warnProveField in gNotes
+ let stringCase = skipTypes(n.sons[0].typ,
+ abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
+ let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
+ warnProveField in gNotes
var inter: TIntersection = @[]
var toCover = 0
for i in 1.. = toCover: tracked.init.add id
# else we can't merge
@@ -658,7 +686,7 @@ proc track(tracked: PEffects, n: PNode) =
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
warnAboutGcUnsafe(n)
- markGcUnsafe(tracked)
+ markGcUnsafe(tracked, a)
for i in 1 .. 3:
message(a.info, warnEachIdentIsTuple)
for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], symkind)
- if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+ if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+ addInterfaceDecl(c, v)
when oKeepVariableNames:
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
@@ -429,7 +464,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addSon(b, newSymNode(v))
addSon(b, a.sons[length-2]) # keep type desc for doc generator
addSon(b, copyTree(def))
- addSon(result, b)
+ addToVarSection(c, result, n, b)
else:
if def.kind == nkPar: v.ast = def[j]
v.typ = tup.sons[j]
@@ -518,7 +553,8 @@ proc semForVars(c: PContext, n: PNode): PNode =
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
v.typ = iter.sons[i]
n.sons[i] = newSymNode(v)
- if sfGenSym notin v.flags: addForVarDecl(c, v)
+ if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+ addForVarDecl(c, v)
inc(c.p.nestedLoopCounter)
n.sons[length-1] = semStmt(c, n.sons[length-1])
dec(c.p.nestedLoopCounter)
@@ -654,6 +690,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
#debug s.typ
s.ast = a
popOwner()
+ let aa = a.sons[2]
+ if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
+ aa.sons[0].kind == nkObjectTy:
+ # give anonymous object a dummy symbol:
+ var st = s.typ
+ if st.kind == tyGenericBody: st = st.lastSon
+ internalAssert st.kind in {tyPtr, tyRef}
+ internalAssert st.lastSon.sym == nil
+ st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
+ getCurrOwner(), s.info)
proc checkForMetaFields(n: PNode) =
template checkMeta(t) =
@@ -697,16 +743,6 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
checkConstructedType(s.info, s.typ)
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
checkForMetaFields(s.typ.n)
- let aa = a.sons[2]
- if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
- aa.sons[0].kind == nkObjectTy:
- # give anonymous object a dummy symbol:
- var st = s.typ
- if st.kind == tyGenericBody: st = st.lastSon
- internalAssert st.kind in {tyPtr, tyRef}
- internalAssert st.lastSon.sym == nil
- st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
- getCurrOwner(), s.info)
proc semTypeSection(c: PContext, n: PNode): PNode =
## Processes a type section. This must be done in separate passes, in order
@@ -909,11 +945,12 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
proc semOverride(c: PContext, s: PSym, n: PNode) =
case s.name.s.normalize
- of "destroy":
+ of "destroy", "=destroy":
doDestructorStuff(c, s, n)
if not experimentalMode(c):
localError n.info, "use the {.experimental.} pragma to enable destructors"
- of "deepcopy":
+ incl(s.flags, sfUsed)
+ of "deepcopy", "=deepcopy":
if s.typ.len == 2 and
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ.sons[1], s.typ.sons[0]):
@@ -935,10 +972,35 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
else:
localError(n.info, errGenerated,
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
- of "=": discard
- else: localError(n.info, errGenerated,
- "'destroy' or 'deepCopy' expected for 'override'")
- incl(s.flags, sfUsed)
+ incl(s.flags, sfUsed)
+ of "=":
+ incl(s.flags, sfUsed)
+ let t = s.typ
+ if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
+ var obj = t.sons[1].sons[0]
+ while true:
+ incl(obj.flags, tfHasAsgn)
+ if obj.kind == tyGenericBody: obj = obj.lastSon
+ elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
+ else: break
+ var objB = t.sons[2]
+ while true:
+ if objB.kind == tyGenericBody: objB = objB.lastSon
+ elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
+ else: break
+ if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
+ if obj.assignment.isNil:
+ obj.assignment = s
+ else:
+ localError(n.info, errGenerated,
+ "cannot bind another '=' to: " & typeToString(obj))
+ return
+ localError(n.info, errGenerated,
+ "signature for '=' must be proc[T: object](x: var T; y: T)")
+ else:
+ if sfOverriden in s.flags:
+ localError(n.info, errGenerated,
+ "'destroy' or 'deepCopy' expected for 'override'")
type
TProcCompilationSteps = enum
@@ -970,7 +1032,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s = semIdentDef(c, n.sons[0], kind)
n.sons[namePos] = newSymNode(s)
s.ast = n
- s.scope = c.currentScope
+ #s.scope = c.currentScope
if sfNoForward in c.module.flags and
sfSystemModule notin c.module.flags:
@@ -982,14 +1044,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s.owner = getCurrOwner()
typeIsDetermined = s.typ == nil
s.ast = n
- s.scope = c.currentScope
+ #s.scope = c.currentScope
# if typeIsDetermined: assert phase == stepCompileBody
# else: assert phase == stepDetermineType
# before compiling the proc body, set as current the scope
# where the proc was declared
let oldScope = c.currentScope
- c.currentScope = s.scope
+ #c.currentScope = s.scope
pushOwner(s)
openScope(c)
var gp: PNode
@@ -1014,7 +1076,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind in skIterators:
s.typ.flags.incl(tfIterator)
- var proto = searchForProc(c, s.scope, s)
+ var proto = searchForProc(c, oldScope, s)
if proto == nil:
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC
@@ -1022,10 +1084,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfGenSym in s.flags: discard
elif kind in OverloadableSyms:
if not typeIsDetermined:
- addInterfaceOverloadableSymAt(c, s.scope, s)
+ addInterfaceOverloadableSymAt(c, oldScope, s)
else:
if not typeIsDetermined:
- addInterfaceDeclAt(c, s.scope, s)
+ addInterfaceDeclAt(c, oldScope, s)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], validPragmas)
else:
@@ -1055,7 +1117,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner()
pushOwner(s)
s.options = gOptions
- if sfOverriden in s.flags: semOverride(c, s, n)
+ if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags:
@@ -1093,7 +1155,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
elif sfBorrow in s.flags: semBorrow(c, n, s)
sideEffectsCheck(c, s)
closeScope(c) # close scope for parameters
- c.currentScope = oldScope
+ # c.currentScope = oldScope
popOwner()
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index b6efa51195..161d22fc15 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -482,7 +482,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(s)
# check parameter list:
- s.scope = c.currentScope
+ #s.scope = c.currentScope
pushOwner(s)
openScope(c)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 1da4d7352f..8c7bd7243f 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -261,7 +261,8 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
if not isOrdinalType(indx):
localError(n.sons[1].info, errOrdinalTypeExpected)
elif enumHasHoles(indx):
- localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
+ localError(n.sons[1].info, errEnumXHasHoles,
+ typeToString(indx.skipTypes({tyRange})))
base = semTypeNode(c, n.sons[2], nil)
addSonSkipIntLit(result, base)
else:
@@ -593,7 +594,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
f.position = pos
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
(f.loc.r == nil):
- f.loc.r = toRope(f.name.s)
+ f.loc.r = rope(f.name.s)
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
inc(pos)
if containsOrIncl(check, f.name.id):
@@ -628,7 +629,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
result = t
if result.kind == tyGenericInvocation:
result = result.sons[0]
- if result.kind == tyGenericBody:
+ while result.kind in {tyGenericInst, tyGenericBody}:
result = lastSon(result)
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
@@ -646,14 +647,17 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
# n.sons[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3)
if n.sons[1].kind != nkEmpty:
- base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
- var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
- if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
- addInheritedFields(c, check, pos, concreteBase)
+ base = skipTypesOrNil(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
+ if base.isNil:
+ localError(n.info, errIllegalRecursionInTypeX, "object")
else:
- if concreteBase.kind != tyError:
- localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
- base = nil
+ var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
+ if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
+ addInheritedFields(c, check, pos, concreteBase)
+ else:
+ if concreteBase.kind != tyError:
+ localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
+ base = nil
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c)
rawAddSon(result, base)
@@ -786,7 +790,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
@[newTypeS(paramType.kind, c)])
result = addImplicitGeneric(typ)
else:
- for i in 0 .. 1:
- if t.sons[0].sym.magic in {mShared, mGuarded}:
+ if t.sons[0].sym.magic == mShared:
incl(t.flags, tfShared)
- if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
+ #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
if tfHasGCedMem in t.flags or t.isGCedMem:
localError(info, errGenerated,
"shared memory may not refer to GC'ed thread local memory")
@@ -233,7 +233,9 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
# XXX: relying on allowMetaTypes is a kludge
result = copyType(t, t.owner, cl.allowMetaTypes)
result.flags.incl tfFromGeneric
- result.flags.excl tfInstClearedFlags
+ if not (t.kind in tyMetaTypes or
+ (t.kind == tyStatic and t.n == nil)):
+ result.flags.excl tfInstClearedFlags
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
@@ -307,7 +309,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
- newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
+ newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
+ attachedDeepCopy)
+ let asgn = newbody.assignment
+ if asgn != nil and sfFromGeneric notin asgn.flags:
+ # '=' needs to be instantiated for generics when the type is constructed:
+ newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
+ attachedAsgn)
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
@@ -412,15 +420,23 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = t
of tyGenericInst:
+ result = PType(idTableGet(cl.localCache, t))
+ if result != nil: return result
result = instCopyType(cl, t)
+ idTablePut(cl.localCache, t, result)
for i in 1 .. b.info.fileIndex then exit;
case a.kind
- of nkSym:
+ of nkSym:
# don't go nuts here: same symbol as string is enough:
result = a.sym.name.id == b.sym.name.id
of nkIdent: result = a.ident.id == b.ident.id
@@ -75,15 +75,15 @@ proc sameTree*(a, b: PNode): bool =
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkEmpty, nkNilLit, nkType: result = true
else:
- if sonsLen(a) == sonsLen(b):
- for i in countup(0, sonsLen(a) - 1):
- if not sameTree(a.sons[i], b.sons[i]): return
+ if sonsLen(a) == sonsLen(b):
+ for i in countup(0, sonsLen(a) - 1):
+ if not sameTree(a.sons[i], b.sons[i]): return
result = true
-
-proc getProcSym*(call: PNode): PSym =
+
+proc getProcSym*(call: PNode): PSym =
result = call.sons[0].sym
-proc getOpSym*(op: PNode): PSym =
+proc getOpSym*(op: PNode): PSym =
if op.kind notin {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}:
result = nil
else:
@@ -91,25 +91,25 @@ proc getOpSym*(op: PNode): PSym =
elif op.sons[0].kind == nkSym: result = op.sons[0].sym
else: result = nil
-proc getMagic*(op: PNode): TMagic =
+proc getMagic*(op: PNode): TMagic =
case op.kind
of nkCallKinds:
case op.sons[0].kind
of nkSym: result = op.sons[0].sym.magic
else: result = mNone
else: result = mNone
-
-proc treeToSym*(t: PNode): PSym =
+
+proc treeToSym*(t: PNode): PSym =
result = t.sym
-proc isConstExpr*(n: PNode): bool =
+proc isConstExpr*(n: PNode): bool =
result = (n.kind in
- {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+ {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
proc isDeepConstExpr*(n: PNode): bool =
case n.kind
- of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+ of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit:
result = true
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
@@ -122,33 +122,33 @@ proc isDeepConstExpr*(n: PNode): bool =
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
else: discard
-proc flattenTreeAux(d, a: PNode, op: TMagic) =
+proc flattenTreeAux(d, a: PNode, op: TMagic) =
if (getMagic(a) == op): # a is a "leaf", so add it:
for i in countup(1, sonsLen(a) - 1): # BUGFIX
flattenTreeAux(d, a.sons[i], op)
- else:
+ else:
addSon(d, copyTree(a))
-
-proc flattenTree*(root: PNode, op: TMagic): PNode =
+
+proc flattenTree*(root: PNode, op: TMagic): PNode =
result = copyNode(root)
if getMagic(root) == op:
# BUGFIX: forget to copy prc
addSon(result, copyNode(root.sons[0]))
flattenTreeAux(result, root, op)
-proc swapOperands*(op: PNode) =
+proc swapOperands*(op: PNode) =
var tmp = op.sons[1]
op.sons[1] = op.sons[2]
op.sons[2] = tmp
-proc isRange*(n: PNode): bool {.inline.} =
- if n.kind == nkInfix:
+proc isRange*(n: PNode): bool {.inline.} =
+ if n.kind in nkCallKinds:
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
- n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
+ n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
n[0][1].sym.name.id == ord(wDotDot):
result = true
-proc whichPragma*(n: PNode): TSpecialWord =
+proc whichPragma*(n: PNode): TSpecialWord =
let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
if key.kind == nkIdent: result = whichKeyword(key.ident)
diff --git a/compiler/types.nim b/compiler/types.nim
index 153c26a42f..e205f5722d 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -541,6 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyProc:
result = if tfIterator in t.flags: "iterator (" else: "proc ("
for i in countup(1, sonsLen(t) - 1):
+ if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
+ add(result, t.n[i].sym.name.s)
+ add(result, ": ")
add(result, typeToString(t.sons[i]))
if i < sonsLen(t) - 1: add(result, ", ")
add(result, ')')
@@ -1436,3 +1439,45 @@ proc skipConv*(n: PNode): PNode =
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
+
+proc isEmptyContainer*(t: PType): bool =
+ case t.kind
+ of tyExpr, tyNil: result = true
+ of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
+ of tySet, tySequence, tyOpenArray, tyVarargs:
+ result = t.sons[0].kind == tyEmpty
+ of tyGenericInst: result = isEmptyContainer(t.lastSon)
+ else: result = false
+
+proc takeType*(formal, arg: PType): PType =
+ # param: openArray[string] = []
+ # [] is an array constructor of length 0 of type string!
+ if arg.kind == tyNil:
+ # and not (formal.kind == tyProc and formal.callConv == ccClosure):
+ result = formal
+ elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
+ arg.isEmptyContainer:
+ let a = copyType(arg.skipTypes({tyGenericInst}), arg.owner, keepId=false)
+ a.sons[ord(arg.kind in {tyArray, tyArrayConstr})] = formal.sons[0]
+ result = a
+ elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind:
+ result = formal
+ else:
+ result = arg
+
+proc skipHiddenSubConv*(n: PNode): PNode =
+ if n.kind == nkHiddenSubConv:
+ # param: openArray[string] = []
+ # [] is an array constructor of length 0 of type string!
+ let formal = n.typ
+ result = n.sons[1]
+ let arg = result.typ
+ let dest = takeType(formal, arg)
+ if dest == arg and formal.kind != tyExpr:
+ #echo n.info, " came here for ", formal.typeToString
+ result = n
+ else:
+ result = copyTree(result)
+ result.typ = dest
+ else:
+ result = n
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 3b5c8e7f3b..1c6c9a30b0 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -16,7 +16,8 @@ import ast except getstr
import
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
- parser, vmdeps, idents, trees, renderer, options, transf, parseutils
+ parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
+ vmmarshal
from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate
@@ -371,11 +372,6 @@ template handleJmpBack() {.dirty.} =
globalError(c.debug[pc], errTooManyIterations)
dec(c.loopIterations)
-proc skipColon(n: PNode): PNode =
- result = n
- if n.kind == nkExprColonExpr:
- result = n.sons[1]
-
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start
var tos = tos
@@ -1043,7 +1039,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeB(rkNode)
let newLen = regs[rb].intVal.int
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
- else: setLen(regs[ra].node.sons, newLen)
+ else:
+ let oldLen = regs[ra].node.len
+ setLen(regs[ra].node.sons, newLen)
+ if oldLen < newLen:
+ # XXX This is still not entirely correct
+ # set to default value:
+ for i in oldLen .. 0: typ = typ.sons[0]
createStr regs[ra]
regs[ra].node.strVal = typ.typeToString(preferExported)
+ of opcMarshalLoad:
+ let ra = instr.regA
+ let rb = instr.regB
+ inc pc
+ let typ = c.types[c.code[pc].regBx - wordExcess]
+ putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
+ of opcMarshalStore:
+ decodeB(rkNode)
+ inc pc
+ let typ = c.types[c.code[pc].regBx - wordExcess]
+ createStrKeepNode(regs[ra])
+ if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
+ storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
inc pc
proc execute(c: PCtx, start: int): PNode =
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 90b9f2517a..047009f018 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -16,7 +16,7 @@ const
byteExcess* = 128 # we use excess-K for immediates
wordExcess* = 32768
- MaxLoopIterations* = 500_000 # max iterations of all loops
+ MaxLoopIterations* = 1500_000 # max iterations of all loops
type
@@ -29,7 +29,7 @@ type
opcRet, # return
opcYldYoid, # yield with no value
opcYldVal, # yield with a value
-
+
opcAsgnInt,
opcAsgnStr,
opcAsgnFloat,
@@ -48,8 +48,8 @@ type
opcWrDeref,
opcWrStrIdx,
opcLdStrIdx, # a = b[c]
-
- opcAddInt,
+
+ opcAddInt,
opcAddImmInt,
opcSubInt,
opcSubImmInt,
@@ -58,36 +58,37 @@ type
opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
- opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
- opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
- opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
- opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
+ opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
+ opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
+ opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
+ opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
opcSwap, opcIsNil, opcOf, opcIs,
- opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
+ opcSubStr, opcParseFloat, opcConv, opcCast,
+ opcQuit, opcReset,
opcNarrowS, opcNarrowU,
-
+
opcAddStrCh,
opcAddStrStr,
opcAddSeqElem,
opcRangeChck,
-
+
opcNAdd,
opcNAddMultiple,
- opcNKind,
- opcNIntVal,
- opcNFloatVal,
- opcNSymbol,
+ opcNKind,
+ opcNIntVal,
+ opcNFloatVal,
+ opcNSymbol,
opcNIdent,
opcNGetType,
opcNStrVal,
-
+
opcNSetIntVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
-
+
opcSlurp,
opcGorge,
opcParseExprToAst,
@@ -100,7 +101,7 @@ type
opcEqIdent,
opcStrToIdent,
opcIdentToStr,
-
+
opcEcho,
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
@@ -110,7 +111,7 @@ type
opcNSetChild,
opcCallSite,
opcNewStr,
-
+
opcTJmp, # jump Bx if A != 0
opcFJmp, # jump Bx if A == 0
opcJmp, # jump Bx
@@ -132,7 +133,8 @@ type
opcLdImmInt, # dest = immediate value
opcNBindSym,
opcSetType, # dest.typ = types[Bx]
- opcTypeTrait
+ opcTypeTrait,
+ opcMarshalLoad, opcMarshalStore
TBlock* = object
label*: PSym
@@ -178,13 +180,13 @@ type
slots*: pointer
currentException*: PNode
VmCallback* = proc (args: VmArgs) {.closure.}
-
+
PCtx* = ref TCtx
TCtx* = object of passes.TPassContext # code gen context
code*: seq[TInstr]
debug*: seq[TLineInfo] # line info for every instruction; kept separate
# to not slow down interpretation
- globals*: PNode #
+ globals*: PNode #
constants*: PNode # constant data
types*: seq[PType] # some instructions reference types (e.g. 'except')
currentExceptionA*, currentExceptionB*: PNode
@@ -203,7 +205,7 @@ type
TPosition* = distinct int
PEvalContext* = PCtx
-
+
proc newCtx*(module: PSym): PCtx =
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
@@ -221,7 +223,8 @@ proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
const
firstABxInstr* = opcTJmp
largeInstrs* = { # instructions which use 2 int32s instead of 1:
- opcSubStr, opcConv, opcCast, opcNewSeq, opcOf}
+ opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
+ opcMarshalLoad, opcMarshalStore}
slotSomeTemp* = slotTempUnknown
relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 6148ed319a..21ee4967b1 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -144,7 +144,9 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
of tyIter: result = mapTypeToBracket("iter", t, info)
of tyProxy: result = atomicType"error"
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
- of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info)
+ of tyUserTypeClass:
+ result = mapTypeToBracket("concept", t, info)
+ result.add t.n.copyTree
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
of tyAnd: result = mapTypeToBracket("and", t, info)
of tyOr: result = mapTypeToBracket("or", t, info)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 3178bee60c..0743a45020 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -76,6 +76,11 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
elif opc in {opcLdConst, opcAsgnConst}:
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
c.constants[x.regBx-wordExcess].renderTree)
+ elif opc in {opcMarshalLoad, opcMarshalStore}:
+ let y = c.code[i+1]
+ result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB,
+ c.types[y.regBx-wordExcess].typeToString)
+ inc i
else:
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
result.add("\t#")
@@ -368,7 +373,7 @@ proc sameConstant*(a, b: PNode): bool =
case a.kind
of nkSym: result = a.sym == b.sym
of nkIdent: result = a.ident.id == b.ident.id
- of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+ of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkType, nkNilLit: result = a.typ == b.typ
@@ -696,8 +701,7 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcCard, dest, tmp)
c.freeTemp(tmp)
-proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
- let m = n.sons[0].sym.magic
+proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, dest)
of mOr: c.genAndOr(n, opcTJmp, dest)
@@ -742,9 +746,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcNewStr, dest, tmp)
c.freeTemp(tmp)
# XXX buggy
- of mLengthOpenArray, mLengthArray, mLengthSeq:
+ of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
genUnaryABI(c, n, dest, opcLenSeq)
- of mLengthStr:
+ of mLengthStr, mXLenStr:
genUnaryABI(c, n, dest, opcLenStr)
of mIncl, mExcl:
unused(n, dest)
@@ -791,7 +795,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
genUnaryABC(c, n, dest, opcUnaryMinusInt)
genNarrow(c, n, dest)
of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
- of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: gen(c, n.sons[1], dest)
+ of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
of mBitnotI, mBitnotI64:
genUnaryABC(c, n, dest, opcBitnotInt)
genNarrowU(c, n, dest)
@@ -1008,7 +1012,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcCallSite, dest)
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
- of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI,
+ of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
mAbsI64, mDotDot:
c.genCall(n, dest)
of mExpandToAst:
@@ -1028,6 +1032,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
# mGCref, mGCunref,
internalError(n.info, "cannot generate code for: " & $m)
+proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
+ ## Signature: proc to*[T](data: string): T
+ if dest < 0: dest = c.getTemp(n.typ)
+ var tmp = c.genx(n.sons[1])
+ c.gABC(n, opcMarshalLoad, dest, tmp)
+ c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
+ c.freeTemp(tmp)
+
+proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
+ ## Signature: proc `$$`*[T](x: T): string
+ if dest < 0: dest = c.getTemp(n.typ)
+ var tmp = c.genx(n.sons[1])
+ c.gABC(n, opcMarshalStore, dest, tmp)
+ c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ))
+ c.freeTemp(tmp)
+
const
atomicTypes = {tyBool, tyChar,
tyExpr, tyStmt, tyTypeDesc, tyStatic,
@@ -1364,7 +1384,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyCString, tyString:
result = newNodeIT(nkStrLit, info, t)
of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
- tyStmt, tyTypeDesc, tyStatic, tyRef:
+ tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
result = newNodeIT(nkNilLit, info, t)
of tyProc:
if t.callConv != ccClosure:
@@ -1391,7 +1411,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
addSon(result, getNullValue(t.sons[i], info))
of tySet:
result = newNodeIT(nkCurly, info, t)
- else: internalError("getNullValue: " & $t.kind)
+ else: internalError(info, "getNullValue: " & $t.kind)
proc ldNullOpcode(t: PType): TOpcode =
if fitsRegister(t): opcLdNullReg else: opcLdNull
@@ -1533,6 +1553,15 @@ proc matches(s: PSym; x: string): bool =
dec L
result = true
+proc matches(s: PSym; y: varargs[string]): bool =
+ var s = s
+ var L = y.len-1
+ while L >= 0:
+ if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false
+ s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
+ dec L
+ result = true
+
proc procIsCallback(c: PCtx; s: PSym): bool =
if s.offset < -1: return true
var i = -2
@@ -1570,8 +1599,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
else:
internalError(n.info, "cannot generate code for: " & s.name.s)
of nkCallKinds:
- if n.sons[0].kind == nkSym and n.sons[0].sym.magic != mNone:
- genMagic(c, n, dest)
+ if n.sons[0].kind == nkSym:
+ let s = n.sons[0].sym
+ if s.magic != mNone:
+ genMagic(c, n, dest, s.magic)
+ elif matches(s, "stdlib", "marshal", "to"):
+ genMarshalLoad(c, n, dest)
+ elif matches(s, "stdlib", "marshal", "$$"):
+ genMarshalStore(c, n, dest)
+ else:
+ genCall(c, n, dest)
+ clearDest(c, n, dest)
else:
genCall(c, n, dest)
clearDest(c, n, dest)
@@ -1610,7 +1648,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genBreak(c, n)
of nkTryStmt: genTry(c, n, dest)
of nkStmtList:
- unused(n, dest)
+ #unused(n, dest)
+ # XXX Fix this bug properly, lexim triggers it
for x in n: gen(c, x)
of nkStmtListExpr:
let L = n.len-1
diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim
new file mode 100644
index 0000000000..293d0d9494
--- /dev/null
+++ b/compiler/vmmarshal.nim
@@ -0,0 +1,283 @@
+#
+#
+# The Nim Compiler
+# (c) Copyright 2015 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## Implements marshaling for the VM.
+
+import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
+
+proc ptrToInt(x: PNode): int {.inline.} =
+ result = cast[int](x) # don't skip alignment
+
+proc getField(n: PNode; position: int): PSym =
+ case n.kind
+ of nkRecList:
+ for i in countup(0, sonsLen(n) - 1):
+ result = getField(n.sons[i], position)
+ if result != nil: return
+ of nkRecCase:
+ result = getField(n.sons[0], position)
+ if result != nil: return
+ for i in countup(1, sonsLen(n) - 1):
+ case n.sons[i].kind
+ of nkOfBranch, nkElse:
+ result = getField(lastSon(n.sons[i]), position)
+ if result != nil: return
+ else: internalError(n.info, "getField(record case branch)")
+ of nkSym:
+ if n.sym.position == position: result = n.sym
+ else: discard
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
+
+proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
+ internalAssert x.kind in {nkObjConstr, nkPar}
+ let start = ord(x.kind == nkObjConstr)
+ for i in countup(start, sonsLen(x) - 1):
+ if i > start: s.add(", ")
+ var it = x.sons[i]
+ if it.kind == nkExprColonExpr:
+ internalAssert it.sons[0].kind == nkSym
+ let field = it.sons[0].sym
+ s.add(escapeJson(field.name.s))
+ s.add(": ")
+ storeAny(s, field.typ, it.sons[1], stored)
+ elif typ.n != nil:
+ let field = getField(typ.n, i)
+ s.add(escapeJson(field.name.s))
+ s.add(": ")
+ storeAny(s, field.typ, it, stored)
+
+proc skipColon*(n: PNode): PNode =
+ result = n
+ if n.kind == nkExprColonExpr:
+ result = n.sons[1]
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
+ case t.kind
+ of tyNone: assert false
+ of tyBool: s.add($(a.intVal != 0))
+ of tyChar:
+ let ch = char(a.intVal)
+ if ch < '\128':
+ s.add(escapeJson($ch))
+ else:
+ s.add($int(ch))
+ of tyArray, tySequence:
+ if t.kind == tySequence and a.kind == nkNilLit: s.add("null")
+ else:
+ s.add("[")
+ for i in 0 .. a.len-1:
+ if i > 0: s.add(", ")
+ storeAny(s, t.elemType, a[i], stored)
+ s.add("]")
+ of tyTuple:
+ s.add("{")
+ for i in 0.. 0: s.add(", ")
+ s.add("\"Field" & $i)
+ s.add("\": ")
+ storeAny(s, t.sons[i], a[i].skipColon, stored)
+ s.add("}")
+ of tyObject:
+ s.add("{")
+ storeObj(s, t, a, stored)
+ s.add("}")
+ of tySet:
+ s.add("[")
+ for i in 0.. 0: s.add(", ")
+ if a[i].kind == nkRange:
+ var x = copyNode(a[i][0])
+ storeAny(s, t.lastSon, x, stored)
+ while x.intVal+1 <= a[i][1].intVal:
+ s.add(", ")
+ storeAny(s, t.lastSon, x, stored)
+ inc x.intVal
+ else:
+ storeAny(s, t.lastSon, a[i], stored)
+ s.add("]")
+ of tyRange, tyGenericInst: storeAny(s, t.lastSon, a, stored)
+ of tyEnum:
+ # we need a slow linear search because of enums with holes:
+ for e in items(t.n):
+ if e.sym.position == a.intVal:
+ s.add e.sym.name.s.escapeJson
+ break
+ of tyPtr, tyRef:
+ var x = a
+ if isNil(x) or x.kind == nkNilLit: s.add("null")
+ elif stored.containsOrIncl(x.ptrToInt):
+ # already stored, so we simply write out the pointer as an int:
+ s.add($x.ptrToInt)
+ else:
+ # else as a [value, key] pair:
+ # (reversed order for convenient x[0] access!)
+ s.add("[")
+ s.add($x.ptrToInt)
+ s.add(", ")
+ storeAny(s, t.lastSon, a, stored)
+ s.add("]")
+ of tyString, tyCString:
+ if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
+ else: s.add(escapeJson(a.strVal))
+ of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
+ of tyFloat..tyFloat128: s.add($a.floatVal)
+ else:
+ internalError a.info, "cannot marshal at compile-time " & t.typeToString
+
+proc storeAny*(s: var string; t: PType; a: PNode) =
+ var stored = initIntSet()
+ storeAny(s, t, a, stored)
+
+proc loadAny(p: var JsonParser, t: PType,
+ tab: var Table[BiggestInt, PNode]): PNode =
+ case t.kind
+ of tyNone: assert false
+ of tyBool:
+ case p.kind
+ of jsonFalse: result = newIntNode(nkIntLit, 0)
+ of jsonTrue: result = newIntNode(nkIntLit, 1)
+ else: raiseParseErr(p, "'true' or 'false' expected for a bool")
+ next(p)
+ of tyChar:
+ if p.kind == jsonString:
+ var x = p.str
+ if x.len == 1:
+ result = newIntNode(nkIntLit, ord(x[0]))
+ next(p)
+ return
+ elif p.kind == jsonInt:
+ result = newIntNode(nkIntLit, getInt(p))
+ next(p)
+ return
+ raiseParseErr(p, "string of length 1 expected for a char")
+ of tyEnum:
+ if p.kind == jsonString:
+ for e in items(t.n):
+ if e.sym.name.s == p.str:
+ result = newIntNode(nkIntLit, e.sym.position)
+ next(p)
+ return
+ raiseParseErr(p, "string expected for an enum")
+ of tyArray:
+ if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
+ next(p)
+ result = newNode(nkBracket)
+ while p.kind != jsonArrayEnd and p.kind != jsonEof:
+ result.add loadAny(p, t.elemType, tab)
+ if p.kind == jsonArrayEnd: next(p)
+ else: raiseParseErr(p, "']' end of array expected")
+ of tySequence:
+ case p.kind
+ of jsonNull:
+ result = newNode(nkNilLit)
+ next(p)
+ of jsonArrayStart:
+ next(p)
+ result = newNode(nkBracket)
+ while p.kind != jsonArrayEnd and p.kind != jsonEof:
+ result.add loadAny(p, t.elemType, tab)
+ if p.kind == jsonArrayEnd: next(p)
+ else: raiseParseErr(p, "")
+ else:
+ raiseParseErr(p, "'[' expected for a seq")
+ of tyTuple:
+ if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+ next(p)
+ result = newNode(nkPar)
+ var i = 0
+ while p.kind != jsonObjectEnd and p.kind != jsonEof:
+ if p.kind != jsonString:
+ raiseParseErr(p, "string expected for a field name")
+ next(p)
+ if i >= t.len:
+ raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
+ result.add loadAny(p, t.sons[i], tab)
+ inc i
+ if p.kind == jsonObjectEnd: next(p)
+ else: raiseParseErr(p, "'}' end of object expected")
+ of tyObject:
+ if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+ next(p)
+ result = newNode(nkPar)
+ result.sons = @[]
+ while p.kind != jsonObjectEnd and p.kind != jsonEof:
+ if p.kind != jsonString:
+ raiseParseErr(p, "string expected for a field name")
+ let field = lookupInRecord(t.n, getIdent(p.str))
+ if field.isNil:
+ raiseParseErr(p, "unknown field for object of type " & typeToString(t))
+ next(p)
+ if field.position >= result.sons.len:
+ setLen(result.sons, field.position+1)
+ result.sons[field.position] = loadAny(p, field.typ, tab)
+ if p.kind == jsonObjectEnd: next(p)
+ else: raiseParseErr(p, "'}' end of object expected")
+ of tySet:
+ if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
+ next(p)
+ result = newNode(nkCurly)
+ while p.kind != jsonArrayEnd and p.kind != jsonEof:
+ result.add loadAny(p, t.lastSon, tab)
+ next(p)
+ if p.kind == jsonArrayEnd: next(p)
+ else: raiseParseErr(p, "']' end of array expected")
+ of tyPtr, tyRef:
+ case p.kind
+ of jsonNull:
+ result = newNode(nkNilLit)
+ next(p)
+ of jsonInt:
+ result = tab[p.getInt]
+ if result.isNil:
+ raiseParseErr(p, "cannot load object with address " & $p.getInt)
+ next(p)
+ of jsonArrayStart:
+ next(p)
+ if p.kind == jsonInt:
+ let idx = p.getInt
+ next(p)
+ result = loadAny(p, t.lastSon, tab)
+ tab[idx] = result
+ else: raiseParseErr(p, "index for ref type expected")
+ if p.kind == jsonArrayEnd: next(p)
+ else: raiseParseErr(p, "']' end of ref-address pair expected")
+ else: raiseParseErr(p, "int for pointer type expected")
+ of tyString, tyCString:
+ case p.kind
+ of jsonNull:
+ result = newNode(nkNilLit)
+ next(p)
+ of jsonString:
+ result = newStrNode(nkStrLit, p.str)
+ next(p)
+ else: raiseParseErr(p, "string expected")
+ of tyInt..tyInt64, tyUInt..tyUInt64:
+ if p.kind == jsonInt:
+ result = newIntNode(nkIntLit, getInt(p))
+ next(p)
+ return
+ raiseParseErr(p, "int expected")
+ of tyFloat..tyFloat128:
+ if p.kind == jsonFloat:
+ result = newFloatNode(nkFloatLit, getFloat(p))
+ next(p)
+ return
+ raiseParseErr(p, "float expected")
+ of tyRange, tyGenericInst: result = loadAny(p, t.lastSon, tab)
+ else:
+ internalError "cannot marshal at compile-time " & t.typeToString
+
+proc loadAny*(s: string; t: PType): PNode =
+ var tab = initTable[BiggestInt, PNode]()
+ var p: JsonParser
+ open(p, newStringStream(s), "unknown file")
+ next(p)
+ result = loadAny(p, t, tab)
+ close(p)
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 502ad8ecc3..1023d4783f 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -10,7 +10,7 @@
# Unforunately this cannot be a module yet:
#import vmdeps, vm
from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
- arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
+ arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
floor, ceil, fmod
from os import getEnv, existsEnv, dirExists, fileExists
diff --git a/config/nim.cfg b/config/nim.cfg
index ccb9977db4..fef7df79ec 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -96,7 +96,7 @@ path="$lib/pure/unidecode"
# Configuration for the GNU C/C++ compiler:
@if windows:
- #gcc.path = r"$nimrod\dist\mingw\bin"
+ #gcc.path = r"$nim\dist\mingw\bin"
@if gcc:
tlsEmulation:on
@end
diff --git a/csources b/csources
new file mode 160000
index 0000000000..15724e2e1f
--- /dev/null
+++ b/csources
@@ -0,0 +1 @@
+Subproject commit 15724e2e1f3e7749d508dfcd995e84fea2850802
diff --git a/doc/grammar.txt b/doc/grammar.txt
index b535154950..72dc6c9744 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -179,7 +179,7 @@ simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
| continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
| includeStmt | commentStmt) / exprStmt) COMMENT?
complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
- | tryStmt | finallyStmt | exceptStmt | forStmt
+ | tryStmt | forStmt
| blockStmt | staticStmt | deferStmt | asmStmt
| 'proc' routine
| 'method' routine
diff --git a/doc/lib.txt b/doc/lib.txt
index 385e7a91a7..1c02780683 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -37,7 +37,7 @@ Core
* `unsigned `_
This module implements basic arithmetic operators for unsigned integers.
- To discourage users from using unsigned integers, it's not part
+ To discourage users from using unsigned integers, it's not part
of ``system``, but an extra import.
* `threads `_
@@ -45,7 +45,7 @@ Core
import it explicitly.
* `channels `_
- Nim message passing support for threads. **Note**: This is part of the
+ Nim message passing support for threads. **Note**: This is part of the
system module. Do not import it explicitly.
* `locks `_
@@ -55,7 +55,7 @@ Core
Contains the AST API and documentation of Nim for writing macros.
* `typeinfo `_
- Provides (unsafe) access to Nim's run time type information.
+ Provides (unsafe) access to Nim's run time type information.
* `typetraits `_
This module defines compile-time reflection procs for working with types.
@@ -110,9 +110,9 @@ String handling
* `unicode `_
This module provides support to handle the Unicode UTF-8 encoding.
-
+
* `encodings `_
- Converts between different character encodings. On UNIX, this uses
+ Converts between different character encodings. On UNIX, this uses
the ``iconv`` library, on Windows the Windows API.
* `pegs `_
@@ -159,7 +159,7 @@ Generic Operating System Services
may provide other implementations for this standard stream interface.
* `marshal `_
- Contains procs for serialization and deseralization of arbitrary Nim
+ Contains procs for serialization and deseralization of arbitrary Nim
data structures.
* `terminal `_
@@ -168,7 +168,7 @@ Generic Operating System Services
sequences and does not depend on any other module.
* `memfiles `_
- This module provides support for memory mapped files (Posix's ``mmap``)
+ This module provides support for memory mapped files (Posix's ``mmap``)
on the different operating systems.
* `fsmonitor `_
@@ -228,7 +228,7 @@ Internet Protocols and Support
This module implements a simple HTTP client.
* `smtp `_
- This module implement a simple SMTP client.
+ This module implement a simple SMTP client.
* `ftpclient `_
This module implements an FTP client.
@@ -346,7 +346,7 @@ XML Processing
This module parses an HTML document and creates its XML tree representation.
* `htmlgen `_
- This module implements a simple XML and HTML code
+ This module implements a simple XML and HTML code
generator. Each commonly used HTML tag has a corresponding macro
that generates a string with its HTML representation.
@@ -381,7 +381,7 @@ Miscellaneous
* `oids `_
An OID is a global ID that consists of a timestamp,
- a unique counter and a random value. This combination should suffice to
+ a unique counter and a random value. This combination should suffice to
produce a globally distributed unique ID. This implementation was extracted
from the Mongodb interface and it thus binary compatible with a Mongo OID.
@@ -453,12 +453,8 @@ Other
* `zipfiles `_
This module implements a zip archive creator/reader/modifier.
-* `web `_
- This module contains simple high-level procedures for dealing with the
- Web like loading the contents of a Web page from an URL.
-
* `ssl `_
- This module provides an easy to use sockets-style
+ This module provides an easy to use sockets-style
Nim interface to the OpenSSL library.
* `rdstdin `_
@@ -513,25 +509,6 @@ Regular expressions
Wrapper for the TRE library.
-Graphics libraries
-------------------
-
-* `sdl `_
- Part of the wrapper for SDL.
-* `sdl_gfx `_
- Part of the wrapper for SDL.
-* `sdl_image `_
- Part of the wrapper for SDL.
-* `sdl_mixer `_
- Part of the wrapper for SDL.
-* `sdl_net `_
- Part of the wrapper for SDL.
-* `sdl_ttf `_
- Part of the wrapper for SDL.
-* `smpeg `_
- Part of the wrapper for SDL.
-
-
GUI libraries
-------------
@@ -591,7 +568,7 @@ Data Compression and Archiving
Scientific computing
--------------------
-* `libsvm `_
+* `libsvm `_
Low level wrapper for `lib svm `_.
Nimble
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
index cce3a88307..2736f88fb8 100644
--- a/doc/manual/generics.txt
+++ b/doc/manual/generics.txt
@@ -219,7 +219,7 @@ Concepts are written in the following form:
(x < y) is bool
Container[T] = concept c
- c.len is ordinal
+ c.len is Ordinal
items(c) is iterator
for value in c:
type(value) is T
diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt
index e2f006f04f..df6d85636f 100644
--- a/doc/manual/lexing.txt
+++ b/doc/manual/lexing.txt
@@ -289,7 +289,7 @@ Numerical constants are of a single type and have the form::
INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
- UINT8_LIT = INT_LIT ['\''] ('u' | 'U')
+ UINT_LIT = INT_LIT ['\''] ('u' | 'U')
UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
index 34428233f8..39aebd826b 100644
--- a/doc/manual/pragmas.txt
+++ b/doc/manual/pragmas.txt
@@ -14,7 +14,7 @@ deprecated pragma
The deprecated pragma is used to mark a symbol as deprecated:
-.. code-block:: nimrod
+.. code-block:: nim
proc p() {.deprecated.}
var x {.deprecated.}: char
@@ -22,7 +22,7 @@ It can also be used as a statement. Then it takes a list of *renamings*. The
upcoming ``nimfix`` tool can automatically update the code and perform these
renamings:
-.. code-block:: nimrod
+.. code-block:: nim
type
File = object
Stream = ref object
@@ -71,14 +71,13 @@ procedural variable.
compileTime pragma
------------------
-The ``compileTime`` pragma is used to mark a proc to be used at compile
-time only. No code will be generated for it. Compile time procs are useful
-as helpers for macros.
-
+The ``compileTime`` pragma is used to mark a proc or variable to be used at
+compile time only. No code will be generated for it. Compile time procs are
+useful as helpers for macros.
noReturn pragma
---------------
-The ``noreturn`` pragma is used to mark a proc that never returns.
+The ``noreturn`` pragma is used to mark a proc that never returns.
acyclic pragma
@@ -122,25 +121,25 @@ shallow pragma
--------------
The ``shallow`` pragma affects the semantics of a type: The compiler is
allowed to make a shallow copy. This can cause serious semantic issues and
-break memory safety! However, it can speed up assignments considerably,
-because the semantics of Nim require deep copying of sequences and strings.
+break memory safety! However, it can speed up assignments considerably,
+because the semantics of Nim require deep copying of sequences and strings.
This can be expensive, especially if sequences are used to build a tree
-structure:
+structure:
.. code-block:: nim
type
NodeKind = enum nkLeaf, nkInner
Node {.final, shallow.} = object
case kind: NodeKind
- of nkLeaf:
+ of nkLeaf:
strVal: string
- of nkInner:
+ of nkInner:
children: seq[Node]
pure pragma
-----------
-An object type can be marked with the ``pure`` pragma so that its type
+An object type can be marked with the ``pure`` pragma so that its type
field which is used for runtime type identification is omitted. This used to be
necessary for binary compatibility with other compiled languages.
@@ -163,12 +162,12 @@ error pragma
------------
The ``error`` pragma is used to make the compiler output an error message
with the given content. Compilation does not necessarily abort after an error
-though.
+though.
The ``error`` pragma can also be used to
annotate a symbol (like an iterator or proc). The *usage* of the symbol then
triggers a compile-time error. This is especially useful to rule out that some
-operation is valid due to overloading and type conversions:
+operation is valid due to overloading and type conversions:
.. code-block:: nim
## check that underlying int values are compared and not the pointers:
@@ -201,7 +200,7 @@ The ``line`` pragma can be used to affect line information of the annotated
statement as seen in stack backtraces:
.. code-block:: nim
-
+
template myassert*(cond: expr, msg = "") =
if not cond:
# change run-time line information of the 'raise' statement:
@@ -215,26 +214,26 @@ If the ``line`` pragma is used with a parameter, the parameter needs be a
linearScanEnd pragma
--------------------
-The ``linearScanEnd`` pragma can be used to tell the compiler how to
+The ``linearScanEnd`` pragma can be used to tell the compiler how to
compile a Nim `case`:idx: statement. Syntactically it has to be used as a
statement:
.. code-block:: nim
case myInt
- of 0:
+ of 0:
echo "most common case"
- of 1:
+ of 1:
{.linearScanEnd.}
echo "second most common case"
of 2: echo "unlikely: use branch table"
else: echo "unlikely too: use branch table for ", myInt
-In the example, the case branches ``0`` and ``1`` are much more common than
-the other cases. Therefore the generated assembler code should test for these
-values first, so that the CPU's branch predictor has a good chance to succeed
+In the example, the case branches ``0`` and ``1`` are much more common than
+the other cases. Therefore the generated assembler code should test for these
+values first, so that the CPU's branch predictor has a good chance to succeed
(avoiding an expensive CPU pipeline stall). The other cases might be put into a
jump table for O(1) overhead, but at the cost of a (very likely) pipeline
-stall.
+stall.
The ``linearScanEnd`` pragma should be put into the last branch that should be
tested against via linear scanning. If put into the last branch of the
@@ -243,8 +242,8 @@ whole ``case`` statement, the whole ``case`` statement uses linear scanning.
computedGoto pragma
-------------------
-The ``computedGoto`` pragma can be used to tell the compiler how to
-compile a Nim `case`:idx: in a ``while true`` statement.
+The ``computedGoto`` pragma can be used to tell the compiler how to
+compile a Nim `case`:idx: in a ``while true`` statement.
Syntactically it has to be used as a statement inside the loop:
.. code-block:: nim
@@ -278,21 +277,21 @@ Syntactically it has to be used as a statement inside the loop:
of enumE:
break
inc(pc)
-
+
vm()
As the example shows ``computedGoto`` is mostly useful for interpreters. If
-the underlying backend (C compiler) does not support the computed goto
+the underlying backend (C compiler) does not support the computed goto
extension the pragma is simply ignored.
unroll pragma
-------------
The ``unroll`` pragma can be used to tell the compiler that it should unroll
-a `for`:idx: or `while`:idx: loop for runtime efficiency:
+a `for`:idx: or `while`:idx: loop for runtime efficiency:
.. code-block:: nim
- proc searchChar(s: string, c: char): int =
+ proc searchChar(s: string, c: char): int =
for i in 0 .. s.high:
{.unroll: 4.}
if s[i] == c: return i
@@ -440,7 +439,7 @@ Example:
Please note that if a callable symbol is never used in this scenario, its body
will never be compiled. This is the default behavior leading to best compilation
- times, but if exhaustive compilation of all definitions is required, using
+ times, but if exhaustive compilation of all definitions is required, using
``nim check`` provides this option as well.
Example:
@@ -461,9 +460,9 @@ Example:
pragma pragma
-------------
-The ``pragma`` pragma can be used to declare user defined pragmas. This is
-useful because Nim's templates and macros do not affect pragmas. User
-defined pragmas are in a different module-wide scope than all other symbols.
+The ``pragma`` pragma can be used to declare user defined pragmas. This is
+useful because Nim's templates and macros do not affect pragmas. User
+defined pragmas are in a different module-wide scope than all other symbols.
They cannot be imported from a module.
Example:
@@ -473,8 +472,8 @@ Example:
{.pragma: rtl, exportc, dynlib, cdecl.}
else:
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
-
- proc p*(a, b: int): int {.rtl.} =
+
+ proc p*(a, b: int): int {.rtl.} =
result = a+b
In the example a new pragma named ``rtl`` is introduced that either imports
diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt
index 5b12848722..5e47110e9a 100644
--- a/doc/manual/stmts.txt
+++ b/doc/manual/stmts.txt
@@ -2,7 +2,7 @@ Statements and expressions
==========================
Nim uses the common statement/expression paradigm: Statements do not
-produce a value in contrast to expressions. However, some expressions are
+produce a value in contrast to expressions. However, some expressions are
statements.
Statements are separated into `simple statements`:idx: and
@@ -16,9 +16,9 @@ statements always have to be intended. The details can be found in the grammar.
Statement list expression
-------------------------
-Statements can also occur in an expression context that looks
+Statements can also occur in an expression context that looks
like ``(stmt1; stmt2; ...; ex)``. This is called
-an statement list expression or ``(;)``. The type
+an statement list expression or ``(;)``. The type
of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements
must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.)
``(;)`` does not introduce a new scope.
@@ -30,24 +30,24 @@ Discard statement
Example:
.. code-block:: nim
- proc p(x, y: int): int =
+ proc p(x, y: int): int =
result = x + y
discard p(3, 4) # discard the return value of `p`
The ``discard`` statement evaluates its expression for side-effects and
-throws the expression's resulting value away.
+throws the expression's resulting value away.
Ignoring the return value of a procedure without using a discard statement is
a static error.
The return value can be ignored implicitly if the called proc/iterator has
-been declared with the `discardable`:idx: pragma:
+been declared with the `discardable`:idx: pragma:
.. code-block:: nim
- proc p(x, y: int): int {.discardable.} =
+ proc p(x, y: int): int {.discardable.} =
result = x + y
-
+
p(3, 4) # now valid
An empty ``discard`` statement is often used as a null statement:
@@ -98,11 +98,11 @@ T = enum cast[T](0); this may be an invalid value
The implicit initialization can be avoided for optimization reasons with the
-`noinit`:idx: pragma:
+`noinit`:idx: pragma:
.. code-block:: nim
var
- a {.noInit.}: array [0..1023, char]
+ a {.noInit.}: array [0..1023, char]
If a proc is annotated with the ``noinit`` pragma this refers to its implicit
``result`` variable:
@@ -113,13 +113,13 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit
The implicit initialization can be also prevented by the `requiresInit`:idx:
type pragma. The compiler requires an explicit initialization then. However
-it does a `control flow analysis`:idx: to prove the variable has been
+it does a `control flow analysis`:idx: to prove the variable has been
initialized and does not rely on syntactic properties:
.. code-block:: nim
type
MyObject = object {.requiresInit.}
-
+
proc p() =
# the following is valid:
var x: MyObject
@@ -129,11 +129,12 @@ initialized and does not rely on syntactic properties:
x = a()
use x
+
let statement
-------------
A ``let`` statement declares new local and global `single assignment`:idx:
-variables and binds a value to them. The syntax is the same as that of the ``var``
+variables and binds a value to them. The syntax is the same as that of the ``var``
statement, except that the keyword ``var`` is replaced by the keyword ``let``.
Let variables are not l-values and can thus not be passed to ``var`` parameters
nor can their address be taken. They cannot be assigned new values.
@@ -141,6 +142,19 @@ nor can their address be taken. They cannot be assigned new values.
For let variables the same pragmas are available as for ordinary variables.
+Tuple unpacking
+---------------
+
+In a ``var`` or ``let`` statement tuple unpacking can be performed. The special
+identifier ``_`` can be used to ignore some parts of the tuple:
+
+.. code-block:: nim
+ proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+ let (x, _, z) = returnsTuple()
+
+
+
Const section
-------------
@@ -157,33 +171,33 @@ have no side-effect can be used in constant expressions too:
constEval = contains("abc", 'b') # computed at compile time!
-The rules for compile-time computability are:
+The rules for compile-time computability are:
1. Literals are compile-time computable.
2. Type conversions are compile-time computable.
3. Procedure calls of the form ``p(X)`` are compile-time computable if
- ``p`` is a proc without side-effects (see the `noSideEffect pragma`_
- for details) and if ``X`` is a (possibly empty) list of compile-time
+ ``p`` is a proc without side-effects (see the `noSideEffect pragma`_
+ for details) and if ``X`` is a (possibly empty) list of compile-time
computable arguments.
-Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can
+Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can
they contain such a type.
Static statement/expression
---------------------------
-A static statement/expression can be used to enforce compile
+A static statement/expression can be used to enforce compile
time evaluation explicitly. Enforced compile time evaluation can even evaluate
-code that has side effects:
+code that has side effects:
.. code-block::
static:
echo "echo at compile time"
-It's a static error if the compiler cannot perform the evaluation at compile
+It's a static error if the compiler cannot perform the evaluation at compile
time.
The current implementation poses some restrictions for compile time
@@ -217,7 +231,7 @@ the ``:`` are executed. This goes on until the last ``elif``. If all
conditions fail, the ``else`` part is executed. If there is no ``else``
part, execution continues with the statement after the ``if`` statement.
-The scoping for an ``if`` statement is slightly subtle to support an important
+The scoping for an ``if`` statement is slightly subtle to support an important
use case. A new scope starts for the ``if``/``elif`` condition and ends after
the corresponding *then* block:
@@ -229,7 +243,7 @@ the corresponding *then* block:
else:
# 'm' not declared here
-In the example the scopes have been enclosed in ``{| |}``.
+In the example the scopes have been enclosed in ``{| |}``.
Case statement
@@ -244,7 +258,7 @@ Example:
echo("permission denied")
of "go-for-a-walk": echo("please yourself")
else: echo("unknown command")
-
+
# indentation of the branches is also allowed; and so is an optional colon
# after the selecting expression:
case readline(stdin):
@@ -252,15 +266,15 @@ Example:
echo("permission denied")
of "go-for-a-walk": echo("please yourself")
else: echo("unknown command")
-
+
The ``case`` statement is similar to the if statement, but it represents
a multi-branch selection. The expression after the keyword ``case`` is
evaluated and if its value is in a *slicelist* the corresponding statements
(after the ``of`` keyword) are executed. If the value is not in any
given *slicelist* the ``else`` part is executed. If there is no ``else``
-part and not all possible values that ``expr`` can hold occur in a
-``slicelist``, a static error occurs. This holds only for expressions of
+part and not all possible values that ``expr`` can hold occur in a
+``slicelist``, a static error occurs. This holds only for expressions of
ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s
type. To suppress the static error an ``else`` part with an
empty ``discard`` statement should be used.
@@ -281,7 +295,7 @@ expanded into a list of its elements:
of SymChars, '_': echo "an identifier"
of '0'..'9': echo "a number"
else: echo "other"
-
+
# is equivalent to:
proc classify(s: string) =
case s[0]
@@ -580,14 +594,14 @@ A table constructor is syntactic sugar for an array constructor:
.. code-block:: nim
{"key1": "value1", "key2", "key3": "value2"}
-
+
# is the same as:
[("key1", "value1"), ("key2", "value2"), ("key3", "value2")]
-The empty table can be written ``{:}`` (in contrast to the empty set
+The empty table can be written ``{:}`` (in contrast to the empty set
which is ``{}``) which is thus another way to write as the empty array
-constructor ``[]``. This slightly unusal way of supporting tables
+constructor ``[]``. This slightly unusal way of supporting tables
has lots of advantages:
* The order of the (key,value)-pairs is preserved, thus it is easy to
diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt
index cf44eb5881..24644bce2d 100644
--- a/doc/manual/syntax.txt
+++ b/doc/manual/syntax.txt
@@ -15,8 +15,6 @@ Associativity
Binary operators whose first character is ``^`` are right-associative, all
other binary operators are left-associative.
-Operators ending in ``>`` but longer than a single character are
-called `arrow like`:idx:.
Precedence
@@ -33,9 +31,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
For binary operators that are not keywords the precedence is determined by the
following rules:
+Operators ending in either ``->``, ``~>`` or ``=>`` are called
+`arrow like`:idx:, and have the lowest precedence of all operators.
+
If the operator ends with ``=`` and its first character is none of
``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
-has the lowest precedence.
+has the second lowest precedence.
Otherwise precedence is determined by the first character.
@@ -43,14 +44,14 @@ Otherwise precedence is determined by the first character.
Precedence level Operators First character Terminal symbol
================ =============================================== ================== ===============
10 (highest) ``$ ^`` OP10
- 9 ``* / div mod shl shr %`` ``* % \ /`` OP9
- 8 ``+ -`` ``+ ~ |`` OP8
+ 9 ``* / div mod shl shr %`` ``* % \ /`` OP9
+ 8 ``+ -`` ``+ - ~ |`` OP8
7 ``&`` ``&`` OP7
6 ``..`` ``.`` OP6
- 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5
+ 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5
4 ``and`` OP4
3 ``or xor`` OP3
- 2 ``@ : ?`` OP2
+ 2 ``@ : ?`` OP2
1 *assignment operator* (like ``+=``, ``*=``) OP1
0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0
================ =============================================== ================== ===============
@@ -67,7 +68,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
.. code-block:: nim
#! strongSpaces
- if foo+4 * 4 == 8 and b&c | 9 ++
+ if foo+4 * 4 == 8 and b&c | 9 ++
bar:
echo ""
# is parsed as
diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt
index 245545f6fa..fc3040c87f 100644
--- a/doc/manual/threads.txt
+++ b/doc/manual/threads.txt
@@ -1,16 +1,16 @@
Threads
=======
-To enable thread support the ``--threads:on`` command line switch needs to
-be used. The ``system`` module then contains several threading primitives.
-See the `threads `_ and `channels `_ modules
+To enable thread support the ``--threads:on`` command line switch needs to
+be used. The ``system`` module then contains several threading primitives.
+See the `threads `_ and `channels `_ modules
for the low level thread API. There are also high level parallelism constructs
available. See `spawn`_ for further details.
Nim's memory model for threads is quite different than that of other common
-programming languages (C, Pascal, Java): Each thread has its own (garbage
-collected) heap and sharing of memory is restricted to global variables. This
-helps to prevent race conditions. GC efficiency is improved quite a lot,
+programming languages (C, Pascal, Java): Each thread has its own (garbage
+collected) heap and sharing of memory is restricted to global variables. This
+helps to prevent race conditions. GC efficiency is improved quite a lot,
because the GC never has to stop other threads and see what they reference.
Memory allocation requires no lock at all! This design easily scales to massive
multicore processors that are becoming the norm.
@@ -22,10 +22,10 @@ Thread pragma
A proc that is executed as a new thread of execution should be marked by the
``thread`` pragma for reasons of readability. The compiler checks for
violations of the `no heap sharing restriction`:idx:\: This restriction implies
-that it is invalid to construct a data structure that consists of memory
+that it is invalid to construct a data structure that consists of memory
allocated from different (thread local) heaps.
-A thread proc is passed to ``createThread`` or ``spawn`` and invoked
+A thread proc is passed to ``createThread`` or ``spawn`` and invoked
indirectly; so the ``thread`` pragma implies ``procvar``.
@@ -34,7 +34,7 @@ GC safety
We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable
that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either
-directly or indirectly through a call to a GC unsafe proc.
+directly or indirectly through a call to a GC unsafe proc.
The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
otherwise this property is inferred by the compiler. Note that ``noSideEfect``
@@ -45,10 +45,9 @@ contain a ``ref`` or ``closure`` type. This enforces
the *no heap sharing restriction*.
Routines that are imported from C are always assumed to be ``gcsafe``.
-To enable the GC-safety checking the ``--threadAnalysis:on`` command line
-switch must be used. This is a temporary workaround to ease the porting effort
-from old code to the new threading model. In the future the thread analysis
-will always be performed.
+To disable the GC-safety checking the ``--threadAnalysis:off`` command line
+switch can be used. This is a temporary workaround to ease the porting effort
+from old code to the new threading model.
Future directions:
@@ -59,13 +58,13 @@ Future directions:
Threadvar pragma
----------------
-A global variable can be marked with the ``threadvar`` pragma; it is
+A global variable can be marked with the ``threadvar`` pragma; it is
a `thread-local`:idx: variable then:
.. code-block:: nim
var checkpoints* {.threadvar.}: seq[string]
-Due to implementation restrictions thread local variables cannot be
+Due to implementation restrictions thread local variables cannot be
initialized within the ``var`` section. (Every thread local variable needs to
be replicated at thread creation.)
@@ -73,7 +72,7 @@ be replicated at thread creation.)
Threads and exceptions
----------------------
-The interaction between threads and exceptions is simple: A *handled* exception
+The interaction between threads and exceptions is simple: A *handled* exception
in one thread cannot affect any other thread. However, an *unhandled* exception
in one thread terminates the whole *process*!
@@ -82,7 +81,7 @@ in one thread terminates the whole *process*!
Parallel & Spawn
================
-Nim has two flavors of parallelism:
+Nim has two flavors of parallelism:
1) `Structured`:idx: parallelism via the ``parallel`` statement.
2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement.
@@ -115,7 +114,7 @@ Spawn statement
proc processLine(line: string) =
discard "do some heavy lifting here"
-
+
for x in lines("myinput.txt"):
spawn processLine(x)
sync()
@@ -144,7 +143,7 @@ wait on multiple flow variables at the same time:
.. code-block:: nim
import threadpool, ...
-
+
# wait until 2 out of 3 servers received the update:
proc main =
var responses = newSeq[RawFlowVar](3)
@@ -203,8 +202,7 @@ restrictions / changes:
the ``parallel`` section. This is called the *immutability check*. Currently
it is not specified what exactly "complex location" means. We need to make
this an optimization!
-* Every array access has to be provably within bounds. This is called
+* Every array access has to be provably within bounds. This is called
the *bounds check*.
* Slices are optimized so that no copy is performed. This optimization is not
- yet performed for ordinary slices outside of a ``parallel`` section. Slices
- are also special in that they currently do not support negative indexes!
+ yet performed for ordinary slices outside of a ``parallel`` section.
diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt
index 59d55a6cdd..c707979feb 100644
--- a/doc/manual/type_bound_ops.txt
+++ b/doc/manual/type_bound_ops.txt
@@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type.
operator `=`
------------
-This operator is the assignment operator. Note that in the contexts
-like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for
-parameter passing no assignment is performed. The ``override`` pragma is
-optional for overriding ``=``.
+This operator is the assignment operator. Note that in the contexts
+``result = expr``, ``parameter = defaultValue`` or for
+parameter passing no assignment is performed. For a type ``T`` that has an
+overloaded assignment operator ``var v = T()`` is rewritten
+to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count
+as assignments.
+
+The assignment operator needs to be attached to an object or distinct
+type ``T``. Its signature has to be ``(var T, T)``. Example:
+
+.. code-block:: nim
+ type
+ Concrete = object
+ a, b: string
+
+ proc `=`(d: var Concrete; src: Concrete) =
+ shallowCopy(d.a, src.a)
+ shallowCopy(d.b, src.b)
+ echo "Concrete '=' called"
+
+ var x, y: array[0..2, Concrete]
+ var cA, cB: Concrete
+
+ var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+ x = y
+ cA = cB
+ cATup = cBTup
-**Note**: Overriding of operator ``=`` is not yet implemented.
destructors
-----------
A destructor must have a single parameter with a concrete type (the name of a
-generic type is allowed too). The name of the destructor has to be ``destroy``
-and it need to be annotated with the ``override`` pragma.
+generic type is allowed too). The name of the destructor has to be ``=destroy``.
-``destroy(v)`` will be automatically invoked for every local stack
+``=destroy(v)`` will be automatically invoked for every local stack
variable ``v`` that goes out of scope.
-If a structured type features a field with destructable type and
+If a structured type features a field with destructable type and
the user has not provided an explicit implementation, a destructor for the
-structured type will be automatically generated. Calls to any base class
+structured type will be automatically generated. Calls to any base class
destructors in both user-defined and generated destructors will be inserted.
A destructor is attached to the type it destructs; expressions of this type
@@ -52,13 +74,13 @@ can then only be used in *destructible contexts* and as parameters:
MyObj = object
x, y: int
p: pointer
-
- proc destroy(o: var MyObj) {.override.} =
+
+ proc `=destroy`(o: var MyObj) =
if o.p != nil: dealloc o.p
-
+
proc open: MyObj =
result = MyObj(x: 1, y: 2, p: alloc(3))
-
+
proc work(o: MyObj) =
echo o.x
# No destructor invoked here for 'o' as 'o' is a parameter.
@@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters:
var x = open()
# valid: pass 'x' to some other proc:
work(x)
-
+
# Error: usage of a type with a destructor in a non destructible context
echo open()
@@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve
the support of destructors.
Be aware that destructors are not called for objects allocated with ``new``.
-This may change in future versions of language, but for now the ``finalizer``
+This may change in future versions of language, but for now the `finalizer`:idx:
parameter to ``new`` has to be used.
**Note**: Destructors are still experimental and the spec might change
@@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis.
deepCopy
--------
-``deepCopy`` is a builtin that is invoked whenever data is passed to
+``=deepCopy`` is a builtin that is invoked whenever data is passed to
a ``spawn``'ed proc to ensure memory safety. The programmer can override its
behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
language may weaken this restriction.)
@@ -103,10 +125,10 @@ language may weaken this restriction.)
The signature has to be:
.. code-block:: nim
- proc deepCopy(x: T): T {.override.}
+ proc `=deepCopy`(x: T): T
-This mechanism is used by most data structures that support shared memory like
-channels to implement thread safe automatic memory management.
+This mechanism will be used by most data structures that support shared memory
+like channels to implement thread safe automatic memory management.
The builtin ``deepCopy`` can even clone closures and their environments. See
the documentation of `spawn`_ for details.
diff --git a/doc/manual/types.txt b/doc/manual/types.txt
index e9d33045b1..bdf51941da 100644
--- a/doc/manual/types.txt
+++ b/doc/manual/types.txt
@@ -864,7 +864,9 @@ Future directions:
* Builtin regions like ``private``, ``global`` and ``local`` will
prove very useful for the upcoming OpenCL target.
* Builtin "regions" can model ``lent`` and ``unique`` pointers.
-
+* An assignment operator can be attached to a region so that proper write
+ barriers can be generated. This would imply that the GC can be implemented
+ completely in user-space.
Procedural type
diff --git a/doc/nimc.txt b/doc/nimc.txt
index 831fce5670..fb1873539c 100644
--- a/doc/nimc.txt
+++ b/doc/nimc.txt
@@ -386,6 +386,25 @@ Example:
As can be seen from the example, to Nim symbols can be referred via backticks.
Use two backticks to produce a single verbatim backtick.
+For a toplevel emit statement the section where in the generated C/C++ file
+the code should be emitted can be influenced via the
+prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/``:
+
+.. code-block:: Nim
+ {.emit: """/*TYPESECTION*/
+ struct Vector3 {
+ public:
+ Vector3(): x(5) {}
+ Vector3(float x_): x(x_) {}
+ float x;
+ };
+ """.}
+
+ type Vector3 {.importcpp: "Vector3", nodecl} = object
+ x: cfloat
+
+ proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
ImportCpp pragma
----------------
@@ -506,7 +525,7 @@ For example:
.. code-block:: nim
type Input {.importcpp: "System::Input".} = object
- proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".}
+ proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
let x: ptr Input = getSubsystem[Input]()
@@ -596,6 +615,25 @@ Produces:
x[6] = 91.4;
+- If more precise control is needed, the apostrophe ``'`` can be used in the
+ supplied pattern to denote the concrete type parameters of the generic type.
+ See the usage of the apostrophe operator in proc patterns for more details.
+
+.. code-block:: nim
+
+ type
+ VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
+
+ var x: VectorIterator[cint]
+
+
+Produces:
+
+.. code-block:: C
+
+ std::vector::iterator x;
+
+
ImportObjC pragma
-----------------
Similar to the `importc pragma for C `_, the
diff --git a/doc/nimsuggest.txt b/doc/nimsuggest.txt
new file mode 100644
index 0000000000..2b52196b92
--- /dev/null
+++ b/doc/nimsuggest.txt
@@ -0,0 +1,174 @@
+================================
+ Nim IDE Integration Guide
+================================
+
+:Author: Unknown
+:Version: |nimversion|
+
+.. contents::
+
+
+Nim differs from many other compilers in that it is really fast,
+and being so fast makes it suited to provide external queries for
+text editors about the source code being written. Through the
+``nimsuggest`` tool, any IDE
+can query a ``.nim`` source file and obtain useful information like
+definition of symbols or suggestions for completion.
+
+This document will guide you through the available options. If you
+want to look at practical examples of nimsuggest support you can look
+at the
+`various editor integrations `_
+already available.
+
+
+Installation
+============
+
+Nimsuggest is available as a Nimble package but currently does not install
+properly via Nimble. As nimsuggest is part of the compiler it also doesn't make
+too much sense as a Nimble package. Instead we will do the building manually::
+
+ cd compiler/nimsuggest
+ nim c -d:release nimsuggest
+ cp nimsuggest ../../bin
+ # OR: copy the nimsuggest binary to where your 'nim' binary is
+ cd ../..
+
+
+
+Nimsuggest invocation
+=====================
+
+Run it via ``nimsuggest --stdin myproject.nim``. Nimsuggest is a server that
+takes queries that are related to ``myproject``. There is some support so that
+you can throw random ``.nim`` files which are not part of ``myproject`` at
+Nimsuggest too, but usually the query refer to modules/files that are part of
+``myproject``.
+
+``--stdin`` means that Nimsuggest reads the query from ``stdin``. This is great
+for testing things out and playing with it but for an editor communication
+via sockets is more reasonable so that is the default. It listens to port 6000
+by default.
+
+
+Specifying the location of the query
+------------------------------------
+
+Nimsuggest than waits for queries to process. A query consists of a
+cryptic 3 letter "command" ``def`` or ``con`` or ``sug`` or ``use`` followed by
+a location. A query location consists of:
+
+
+``file.nim``
+ This is the name of the module or include file the query refers to.
+
+``dirtyfile.nim``
+ This is optional.
+
+ The ``file`` paramater is enough for static analysis, but IDEs
+ tend to have *unsaved buffers* where the user may still be in
+ the middle of typing a line. In such situations the IDE can
+ save the current contents to a temporary file and then use the
+ ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should
+ be taken from ``temporary/foobar.nim``.
+
+
+``line``
+ An integer with the line you are going to query. For the compiler
+ lines start at **1**.
+
+``col``
+ An integer with the column you are going to query. For the
+ compiler columns start at **1**.
+
+
+Definitions
+-----------
+
+The ``def`` Nimsuggest command performs a query about the definition
+of a specific symbol. If available, Nimsuggest will answer with the
+type, source file, line/column information and other accessory data
+if available like a docstring. With this information an IDE can
+provide the typical *Jump to definition* where a user puts the
+cursor on a symbol or uses the mouse to select it and is redirected
+to the place where the symbol is located.
+
+Since Nim is implemented in Nim, one of the nice things of
+this feature is that any user with an IDE supporting it can quickly
+jump around the standard library implementation and see exactly
+what a proc does, learning about the language and seeing real life
+examples of how to write/implement specific features.
+
+Nimsuggest will always answer with a single definition or none if it
+can't find any valid symbol matching the position of the query.
+
+
+Suggestions
+-----------
+
+The ``sug`` Nimsuggest command performs a query about possible
+completion symbols at some point in the file.
+
+The typical usage scenario for this option is to call it after the
+user has typed the dot character for `the object oriented call
+syntax `_. Nimsuggest will try to return
+the suggestions sorted first by scope (from innermost to outermost)
+and then by item name.
+
+
+Invocation context
+------------------
+
+The ``con`` Nimsuggest command is very similar to the suggestions
+command, but instead of being used after the user has typed a dot
+character, this one is meant to be used after the user has typed
+an opening brace to start typing parameters.
+
+
+Symbol usages
+-------------
+
+The ``use`` Nimsuggest command lists all usages of the symbol at
+a position. IDEs can use this to find all the places in the file
+where the symbol is used and offer the user to rename it in all
+places at the same time.
+
+For this kind of query the IDE will most likely ignore all the
+type/signature info provided by Nimsuggest and concentrate on the
+filename, line and column position of the multiple returned answers.
+
+
+
+Parsing nimsuggest output
+=========================
+
+Nimsuggest output is always returned on single lines separated by
+tab characters (``\t``). The values of each column are:
+
+1. Three characters indicating the type of returned answer (e.g.
+ ``def`` for definition, ``sug`` for suggestion, etc).
+2. Type of the symbol. This can be ``skProc``, ``skLet``, and just
+ about any of the enums defined in the module ``compiler/ast.nim``.
+3. Full qualitifed path of the symbol. If you are querying a symbol
+ defined in the ``proj.nim`` file, this would have the form
+ ``proj.symbolName``.
+4. Type/signature. For variables and enums this will contain the
+ type of the symbol, for procs, methods and templates this will
+ contain the full unique signature (e.g. ``proc (File)``).
+5. Full path to the file containing the symbol.
+6. Line where the symbol is located in the file. Lines start to
+ count at **1**.
+7. Column where the symbol is located in the file. Columns start
+ to count at **1**.
+8. Docstring for the symbol if available or the empty string. To
+ differentiate the docstring from end of answer,
+ the docstring is always provided enclosed in double quotes, and
+ if the docstring spans multiple lines, all following lines of the
+ docstring will start with a blank space to align visually with
+ the starting quote.
+
+ Also, you won't find raw ``\n`` characters breaking the one
+ answer per line format. Instead you will need to parse sequences
+ in the form ``\xHH``, where *HH* is a hexadecimal value (e.g.
+ newlines generate the sequence ``\x0A``).
diff --git a/doc/tools.txt b/doc/tools.txt
index 7f28308791..b0a45c5757 100644
--- a/doc/tools.txt
+++ b/doc/tools.txt
@@ -4,6 +4,11 @@ Tools available with Nim
The standard distribution ships with the following tools:
+- | `Nimsuggest for IDE support `_
+ | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file
+ and obtain useful information like definition of symbols or suggestions for
+ completion.
+
- | `Nim Installation Generator `_
| How to generate a nice installer for your Nim program.
diff --git a/doc/tut1.txt b/doc/tut1.txt
index cb5a0c8dd5..58ace1dbe0 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -16,7 +16,7 @@ Introduction
-This document is a tutorial for the programming language *Nim*.
+This document is a tutorial for the programming language *Nim*.
This tutorial assumes that you are familiar with basic programming concepts
like variables, types or statements but is kept very basic. The `manual
`_ contains many more examples of the advanced language features.
@@ -50,7 +50,7 @@ Commonly used commands and switches have abbreviations, so you can also use::
nim c -r greetings.nim
To compile a release version use::
-
+
nim c -d:release greetings.nim
By default the Nim compiler generates a large amount of runtime checks
@@ -116,7 +116,7 @@ hash character ``#``. Documentation comments start with ``##``:
.. code-block:: nim
# A comment.
-
+
var myVariable: int ## a documentation comment
@@ -200,7 +200,7 @@ constant declaration at compile time:
.. code-block:: nim
const x = "abc" # the constant x contains the string "abc"
-
+
Indentation can be used after the ``const`` keyword to list a whole section of
constants:
@@ -214,7 +214,7 @@ constants:
The let statement
=================
-The ``let`` statement works like the ``var`` statement but the declared
+The ``let`` statement works like the ``var`` statement but the declared
symbols are *single assignment* variables: After the initialization their
value cannot change:
@@ -228,7 +228,7 @@ and put it into a data section":
.. code-block::
const input = readLine(stdin) # Error: constant expression expected
-
+
.. code-block::
let input = readLine(stdin) # works
@@ -310,8 +310,8 @@ the compiler that for every other value nothing should be done:
else: discard
The empty `discard statement`_ is a *do nothing* statement. The compiler knows
-that a case statement with an else part cannot fail and thus the error
-disappears. Note that it is impossible to cover all possible string values:
+that a case statement with an else part cannot fail and thus the error
+disappears. Note that it is impossible to cover all possible string values:
that is why string cases always need an ``else`` branch.
In general the case statement is used for subrange types or enumerations where
@@ -406,7 +406,7 @@ The block's *label* (``myblock`` in the example) is optional.
Break statement
---------------
A block can be left prematurely with a ``break`` statement. The break statement
-can leave a ``while``, ``for``, or a ``block`` statement. It leaves the
+can leave a ``while``, ``for``, or a ``block`` statement. It leaves the
innermost construct, unless a label of a block is given:
.. code-block:: nim
@@ -461,7 +461,7 @@ differences:
* The statements within a branch do not open a new scope.
* The compiler checks the semantics and produces code *only* for the statements
that belong to the first condition that evaluates to ``true``.
-
+
The ``when`` statement is useful for writing platform specific code, similar to
the ``#ifdef`` construct in the C programming language.
@@ -486,14 +486,14 @@ to be indented, but single simple statements do not:
.. code-block:: nim
# no indentation needed for single assignment statement:
if x: x = false
-
+
# indentation needed for nested if statement:
if x:
if y:
y = false
else:
y = true
-
+
# indentation needed, because two statements follow the condition:
if x:
x = false
@@ -514,7 +514,7 @@ contain indentation at certain places for better readability:
As a rule of thumb, indentation within expressions is allowed after operators,
an open parenthesis and after commas.
-With parenthesis and semicolons ``(;)`` you can use statements where only
+With parenthesis and semicolons ``(;)`` you can use statements where only
an expression is allowed:
.. code-block:: nim
@@ -560,45 +560,45 @@ Some terminology: in the example ``question`` is called a (formal) *parameter*,
Result variable
---------------
-A procedure that returns a value has an implicit ``result`` variable declared
+A procedure that returns a value has an implicit ``result`` variable declared
that represents the return value. A ``return`` statement with no expression is a
-shorthand for ``return result``. The ``result`` value is always returned
+shorthand for ``return result``. The ``result`` value is always returned
automatically at the end a procedure if there is no ``return`` statement at
the exit.
.. code-block:: nim
- proc sumTillNegative(x: varargs[int]): int =
+ proc sumTillNegative(x: varargs[int]): int =
for i in x:
if i < 0:
return
- result = result + i
-
+ result = result + i
+
echo sumTillNegative() # echos 0
echo sumTillNegative(3, 4, 5) # echos 12
echo sumTillNegative(3, 4 , -1 , 6) # echos 7
-The ``result`` variable is already implicitly declared at the start of the
+The ``result`` variable is already implicitly declared at the start of the
function, so declaring it again with 'var result', for example, would shadow it
with a normal variable of the same name. The result variable is also already
initialised with the type's default value. Note that referential data types will
be ``nil`` at the start of the procedure, and thus may require manual
initialisation.
-
+
Parameters
----------
Parameters are constant in the procedure body. By default, their value cannot be
-changed because this allows the compiler to implement parameter passing in the
+changed because this allows the compiler to implement parameter passing in the
most efficient way. If a mutable variable is needed inside the procedure, it has
to be declared with ``var`` in the procedure body. Shadowing the parameter name
-is possible, and actually an idiom:
+is possible, and actually an idiom:
.. code-block:: nim
proc printSeq(s: seq, nprinted: int = -1) =
var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
for i in 0 .. Error: type mismatch: got (tuple[street: string, number: int])
# but expected 'Person'
-
+
# The following works because the field names and types are the same.
var teacher: tuple[name: string, age: int] = ("Mark", 42)
person = teacher
@@ -1450,13 +1450,13 @@ operators perform implicit dereferencing operations for reference types:
type
Node = ref NodeObj
- NodeObj = object
- le, ri: PNode
+ NodeObj = object
+ le, ri: Node
data: int
var
n: Node
new(n)
- n.data = 9
+ n.data = 9
# no need to write n[].data; in fact n[].data is highly discouraged!
To allocate a new traced object, the built-in procedure ``new`` has to be used.
@@ -1559,9 +1559,9 @@ This is best illustrated by an example:
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
-the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous
-if it is defined in two (or more) different modules and both modules are
-imported by a third one:
+the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous
+if it is defined in two (or more) different modules and both modules are
+imported by a third one:
.. code-block:: nim
# Module A
diff --git a/koch.nim b/koch.nim
index 508d7e0070..55019b5446 100644
--- a/koch.nim
+++ b/koch.nim
@@ -81,7 +81,7 @@ proc exec(cmd: string, errorcode: int = QuitFailure) =
echo(cmd)
if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
-proc tryExec(cmd: string): bool =
+proc tryExec(cmd: string): bool =
echo(cmd)
result = execShellCmd(cmd) == 0
@@ -96,7 +96,7 @@ proc copyExe(source, dest: string) =
const
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
-proc csource(args: string) =
+proc csource(args: string) =
exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" %
[args, VersionAsString, compileNimInst, findNim()])
@@ -106,6 +106,12 @@ proc zip(args: string) =
exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
["tools/niminst/niminst".exe, VersionAsString])
+proc targz(args: string) =
+ exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
+ [VersionAsString, compileNimInst, findNim()])
+ exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim targz compiler/installer.ini" %
+ ["tools" / "niminst" / "niminst".exe, VersionAsString])
+
proc buildTool(toolname, args: string) =
exec("$# cc $# $#" % [findNim(), args, toolname])
copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
@@ -113,14 +119,14 @@ proc buildTool(toolname, args: string) =
proc nsis(args: string) =
# make sure we have generated the niminst executables:
buildTool("tools/niminst/niminst", args)
- buildTool("tools/nimgrep", args)
- # produce 'nimrod_debug.exe':
- exec "nim c compiler" / "nim.nim"
- copyExe("compiler/nim".exe, "bin/nim_debug".exe)
+ #buildTool("tools/nimgrep", args)
+ # produce 'nim_debug.exe':
+ #exec "nim c compiler" / "nim.nim"
+ #copyExe("compiler/nim".exe, "bin/nim_debug".exe)
exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
- " nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
+ " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)])
-proc install(args: string) =
+proc install(args: string) =
exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
[findNim(), compileNimInst, VersionAsString])
exec("sh ./install.sh $#" % args)
@@ -139,12 +145,10 @@ proc pdf(args="") =
# -------------- boot ---------------------------------------------------------
-proc findStartNim: string =
+proc findStartNim: string =
# we try several things before giving up:
# * bin/nim
# * $PATH/nim
- # * bin/nimrod
- # * $PATH/nimrod
# If these fail, we try to build nim with the "build.(sh|bat)" script.
var nim = "nim".exe
result = "bin" / nim
@@ -152,34 +156,27 @@ proc findStartNim: string =
for dir in split(getEnv("PATH"), PathSep):
if existsFile(dir / nim): return dir / nim
- # try the old "nimrod.exe":
- var nimrod = "nimrod".exe
- result = "bin" / nimrod
- if existsFile(result): return
- for dir in split(getEnv("PATH"), PathSep):
- if existsFile(dir / nim): return dir / nimrod
-
when defined(Posix):
const buildScript = "build.sh"
- if existsFile(buildScript):
+ if existsFile(buildScript):
if tryExec("./" & buildScript): return "bin" / nim
else:
const buildScript = "build.bat"
- if existsFile(buildScript):
+ if existsFile(buildScript):
if tryExec(buildScript): return "bin" / nim
echo("Found no nim compiler and every attempt to build one failed!")
quit("FAILURE")
-proc thVersion(i: int): string =
+proc thVersion(i: int): string =
result = ("compiler" / "nim" & $i).exe
-
+
proc boot(args: string) =
var output = "compiler" / "nim".exe
var finalDest = "bin" / "nim".exe
# default to use the 'c' command:
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
-
+
copyExe(findStartNim(), 0.thVersion)
for i in 0..2:
echo "iteration: ", i+1
@@ -204,7 +201,7 @@ const
".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
]
-proc cleanAux(dir: string) =
+proc cleanAux(dir: string) =
for kind, path in walkDir(dir):
case kind
of pcFile:
@@ -215,25 +212,25 @@ proc cleanAux(dir: string) =
removeFile(path)
of pcDir:
case splitPath(path).tail
- of "nimcache":
+ of "nimcache":
echo "removing dir: ", path
removeDir(path)
of "dist", ".git", "icons": discard
else: cleanAux(path)
else: discard
-proc removePattern(pattern: string) =
- for f in walkFiles(pattern):
+proc removePattern(pattern: string) =
+ for f in walkFiles(pattern):
echo "removing: ", f
removeFile(f)
-proc clean(args: string) =
+proc clean(args: string) =
if existsFile("koch.dat"): removeFile("koch.dat")
removePattern("web/*.html")
removePattern("doc/*.html")
cleanAux(getCurrentDir())
for kind, path in walkDir(getCurrentDir() / "build"):
- if kind == pcDir:
+ if kind == pcDir:
echo "removing dir: ", path
removeDir(path)
@@ -276,7 +273,7 @@ when defined(withUpdate):
"Local branch must be ahead of it. Exiting...")
else:
quit("An error has occurred.")
-
+
else:
echo("No repo or executable found!")
when defined(haveZipLib):
@@ -293,7 +290,7 @@ when defined(withUpdate):
quit("Error reading archive.")
else:
quit("No failback available. Exiting...")
-
+
echo("Starting update...")
boot(args)
echo("Update complete!")
@@ -317,12 +314,14 @@ proc winRelease() =
#buildTool("tools/niminst/niminst", " -d:release")
buildTool("tools/nimgrep", " -d:release")
buildTool("compiler/nimfix/nimfix", " -d:release")
+ buildTool("compiler/nimsuggest/nimsuggest", " -d:release")
+
+ #run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
+ # "bin/nimfix.exe",
+ # "bin/nimble.exe", "bin/*.dll",
+ # "config", "dist/*.dll", "examples", "lib",
+ # "readme.txt", "contributors.txt", "copying.txt")
- run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
- "bin/nimfix.exe",
- "bin/nimble.exe", "bin/*.dll",
- "config", "dist/*.dll", "examples", "lib",
- "readme.txt", "contributors.txt", "copying.txt")
# second step: XXX build 64 bit version
# -------------- tests --------------------------------------------------------
@@ -346,8 +345,8 @@ proc temp(args: string) =
copyExe(output, finalDest)
if args.len > 0: exec(finalDest & " " & args)
-proc showHelp() =
- quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
+proc showHelp() =
+ quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
CompileDate, CompileTime], QuitSuccess)
var op = initOptParser()
@@ -366,6 +365,7 @@ of cmdArgument:
of "pdf": pdf()
of "csource", "csources": csource(op.cmdLineRest)
of "zip": zip(op.cmdLineRest)
+ of "targz": targz(op.cmdLineRest)
of "nsis": nsis(op.cmdLineRest)
of "install": install(op.cmdLineRest)
of "test", "tests": tests(op.cmdLineRest)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 5583748e0a..35f0f61c17 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -88,7 +88,9 @@ type
ntyBigNum,
ntyConst, ntyMutable, ntyVarargs,
ntyIter,
- ntyError
+ ntyError,
+ ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
+ ntyAnd, ntyOr, ntyNot
TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
NimSymKind* = enum
@@ -162,6 +164,7 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
## returns the `kind` of the node `n`.
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
@@ -355,6 +358,12 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} =
## macros that check its number of arguments.
if n.len != len: error("macro expects a node with " & $len & " children")
+proc newTree*(kind: NimNodeKind,
+ children: varargs[NimNode]): NimNode {.compileTime.} =
+ ## produces a new node with children.
+ result = newNimNode(kind)
+ result.add(children)
+
proc newCall*(theProc: NimNode,
args: varargs[NimNode]): NimNode {.compileTime.} =
## produces a new call node. `theProc` is the proc that is called with
@@ -389,6 +398,11 @@ proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
result = newNimNode(nnkIntLit)
result.intVal = i
+proc newLit*(b: bool): NimNode {.compileTime.} =
+ ## produces a new boolean literal node.
+ result = newNimNode(nnkIntLit)
+ result.intVal = ord(b)
+
proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
## produces a new float literal node.
result = newNimNode(nnkFloatLit)
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 4be692f390..8536ab6f22 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -205,7 +205,7 @@ proc setEncoding*(connection: TDbConn, encoding: string): bool {.
exec(connection, sql"PRAGMA encoding = ?", [encoding])
result = connection.getValue(sql"PRAGMA encoding") == encoding
-when isMainModule:
+when not defined(testing) and isMainModule:
var db = open("db.sql", "", "", "")
exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
exec(db, sql"insert into tbl1 values('hello!',10)", [])
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
index dfadb46eeb..814c0ebe14 100644
--- a/lib/impure/graphics.nim
+++ b/lib/impure/graphics.nim
@@ -499,7 +499,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
if sdl_ttf.init() < 0: raiseEGraphics()
-when isMainModule:
+when not defined(testing) and isMainModule:
var surf = newScreenSurface(800, 600)
surf.fillSurface(colWhite)
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index 55f8c5d32e..f4d00979c5 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -135,7 +135,7 @@ else:
var cur, old: Termios
discard fd.tcgetattr(cur.addr)
old = cur
- cur.lflag = cur.lflag and not Tcflag(ECHO)
+ cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
discard fd.tcsetattr(TCSADRAIN, cur.addr)
stdout.write prompt
result = stdin.readLine(password)
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index c24734f89d..279f8aadd6 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -7,8 +7,11 @@
# distribution, for details about the copyright.
#
-## Regular expression support for Nim. Consider using the pegs module
-## instead.
+## Regular expression support for Nim. Consider using the pegs module instead.
+##
+## There is an alternative regular expressions library with a more unified API:
+## `nre `_. It may be added to the standard
+## library in the future, instead of `re`.
##
## **Note:** The 're' proc defaults to the **extended regular expression
## syntax** which lets you use whitespace freely to make your regexes readable.
@@ -36,31 +39,31 @@ const
type
RegexFlag* = enum ## options for regular expressions
reIgnoreCase = 0, ## do caseless matching
- reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
+ reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
reDotAll = 2, ## ``.`` matches anything including NL
reExtended = 3, ## ignore whitespace and ``#`` comments
reStudy = 4 ## study the expression (may be omitted if the
## expression will be used only once)
-
+
RegexDesc = object
- h: PPcre
- e: ptr TExtra
-
+ h: ptr Pcre
+ e: ptr ExtraData
+
Regex* = ref RegexDesc ## a compiled regular expression
-
+
RegexError* = object of ValueError
## is raised if the pattern is no valid regular expression.
{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
EInvalidRegEx: RegexError].}
-proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
+proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
var e: ref RegexError
new(e)
e.msg = msg
raise e
-proc rawCompile(pattern: string, flags: cint): PPcre =
+proc rawCompile(pattern: string, flags: cint): ptr Pcre =
var
msg: cstring
offset: cint
@@ -68,10 +71,10 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
if result == nil:
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
-proc finalizeRegEx(x: Regex) =
+proc finalizeRegEx(x: Regex) =
# XXX This is a hack, but PCRE does not export its "free" function properly.
# Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
- # Fortunately the implementation is unlikely to change.
+ # Fortunately the implementation is unlikely to change.
pcre.free_substring(cast[cstring](x.h))
if not isNil(x.e):
pcre.free_substring(cast[cstring](x.e))
@@ -84,7 +87,7 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
result.h = rawCompile(s, cast[cint](flags - {reStudy}))
if reStudy in flags:
var msg: cstring
- result.e = pcre.study(result.h, 0, msg)
+ result.e = pcre.study(result.h, 0, addr msg)
if not isNil(msg): raiseInvalidRegex($msg)
proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
@@ -101,10 +104,10 @@ proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = nil
return rawMatches[1] - rawMatches[0]
-
+
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
start = 0): tuple[first, last: int] =
- ## returns the starting position and end position of `pattern` in `s`
+ ## returns the starting position and end position of `pattern` in `s`
## and the captured
## substrings in the array `matches`. If it does not match, nothing
## is written into `matches` and ``(-1,0)`` is returned.
@@ -120,12 +123,12 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = nil
return (rawMatches[0].int, rawMatches[1].int - 1)
-
-proc findBounds*(s: string, pattern: Regex,
+
+proc findBounds*(s: string, pattern: Regex,
matches: var openArray[tuple[first, last: int]],
start = 0): tuple[first, last: int] =
- ## returns the starting position and end position of ``pattern`` in ``s``
- ## and the captured substrings in the array `matches`.
+ ## returns the starting position and end position of ``pattern`` in ``s``
+ ## and the captured substrings in the array `matches`.
## If it does not match, nothing is written into `matches` and
## ``(-1,0)`` is returned.
var
@@ -141,10 +144,10 @@ proc findBounds*(s: string, pattern: Regex,
else: matches[i-1] = (-1,0)
return (rawMatches[0].int, rawMatches[1].int - 1)
-proc findBounds*(s: string, pattern: Regex,
+proc findBounds*(s: string, pattern: Regex,
start = 0): tuple[first, last: int] =
- ## returns the starting position of `pattern` in `s`. If it does not
- ## match, ``(-1,0)`` is returned.
+ ## returns the starting position and end position of ``pattern`` in ``s``.
+ ## If it does not match, ``(-1,0)`` is returned.
var
rtarray = initRtArray[cint](3)
rawMatches = rtarray.getRawData
@@ -152,7 +155,7 @@ proc findBounds*(s: string, pattern: Regex,
cast[ptr cint](rawMatches), 3)
if res < 0'i32: return (int(res), 0)
return (int(rawMatches[0]), int(rawMatches[1]-1))
-
+
proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint =
var
rtarray = initRtArray[cint](3)
@@ -172,7 +175,7 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
proc matchLen*(s: string, pattern: Regex, start = 0): int =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
- ## of zero can happen.
+ ## of zero can happen.
return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
proc match*(s: string, pattern: Regex, start = 0): bool =
@@ -216,7 +219,7 @@ proc find*(s: string, pattern: Regex, start = 0): int =
if res < 0'i32: return res
return rawMatches[0]
-iterator findAll*(s: string, pattern: Regex, start = 0): string =
+iterator findAll*(s: string, pattern: Regex, start = 0): string =
## Yields all matching *substrings* of `s` that match `pattern`.
##
## Note that since this is an iterator you should not modify the string you
@@ -231,10 +234,11 @@ iterator findAll*(s: string, pattern: Regex, start = 0): string =
if res < 0'i32: break
let a = rawMatches[0]
let b = rawMatches[1]
+ if a == b and a == i: break
yield substr(s, int(a), int(b)-1)
i = b
-proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
+proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
## returns all matching *substrings* of `s` that match `pattern`.
## If it does not match, @[] is returned.
accumulateResult(findAll(s, pattern, start))
@@ -242,13 +246,13 @@ proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
when not defined(nimhygiene):
{.pragma: inject.}
-template `=~` *(s: string, pattern: Regex): expr =
- ## This calls ``match`` with an implicit declared ``matches`` array that
- ## can be used in the scope of the ``=~`` call:
- ##
+template `=~` *(s: string, pattern: Regex): expr =
+ ## This calls ``match`` with an implicit declared ``matches`` array that
+ ## can be used in the scope of the ``=~`` call:
+ ##
## .. code-block:: nim
##
- ## if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
+ ## if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
## # matches a key=value pair:
## echo("Key: ", matches[0])
## echo("Value: ", matches[1])
@@ -260,9 +264,9 @@ template `=~` *(s: string, pattern: Regex): expr =
## else:
## echo("syntax error")
##
- bind MaxSubPatterns
+ bind MaxSubpatterns
when not declaredInScope(matches):
- var matches {.inject.}: array[0..MaxSubpatterns-1, string]
+ var matches {.inject.}: array[MaxSubpatterns, string]
match(s, pattern, matches)
# ------------------------- more string handling ------------------------------
@@ -286,7 +290,7 @@ proc endsWith*(s: string, suffix: Regex): bool =
if matchLen(s, suffix, i) == s.len - i: return true
proc replace*(s: string, sub: Regex, by = ""): string =
- ## Replaces `sub` in `s` by the string `by`. Captures cannot be
+ ## Replaces `sub` in `s` by the string `by`. Captures cannot be
## accessed in `by`. Examples:
##
## .. code-block:: nim
@@ -306,7 +310,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
add(result, by)
prev = match.last + 1
add(result, substr(s, prev))
-
+
proc replacef*(s: string, sub: Regex, by: string): string =
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
@@ -320,7 +324,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
##
## "var1<-keykey; val2<-key2key2"
result = ""
- var caps: array[0..MaxSubpatterns-1, string]
+ var caps: array[MaxSubpatterns, string]
var prev = 0
while true:
var match = findBounds(s, sub, caps, prev)
@@ -338,7 +342,7 @@ proc parallelReplace*(s: string, subs: openArray[
## applied in parallel.
result = ""
var i = 0
- var caps: array[0..MaxSubpatterns-1, string]
+ var caps: array[MaxSubpatterns, string]
while i < s.len:
block searchSubs:
for j in 0..high(subs):
@@ -359,7 +363,7 @@ proc transformFile*(infile, outfile: string,
## error occurs. This is supposed to be used for quick scripting.
var x = readFile(infile).string
writeFile(outfile, x.parallelReplace(subs))
-
+
iterator split*(s: string, sep: Regex): string =
## Splits the string `s` into substrings.
##
@@ -373,64 +377,73 @@ iterator split*(s: string, sep: Regex): string =
## Results in:
##
## .. code-block:: nim
+ ## ""
## "this"
## "is"
## "an"
## "example"
+ ## ""
##
var
- first = 0
- last = 0
+ first = -1
+ last = -1
while last < len(s):
var x = matchLen(s, sep, last)
if x > 0: inc(last, x)
first = last
+ if x == 0: inc(last)
while last < len(s):
- inc(last)
x = matchLen(s, sep, last)
- if x > 0: break
- if first < last:
+ if x >= 0: break
+ inc(last)
+ if first <= last:
yield substr(s, first, last-1)
proc split*(s: string, sep: Regex): seq[string] =
## Splits the string `s` into substrings.
accumulateResult(split(s, sep))
-
-proc escapeRe*(s: string): string =
- ## escapes `s` so that it is matched verbatim when used as a regular
+
+proc escapeRe*(s: string): string =
+ ## escapes `s` so that it is matched verbatim when used as a regular
## expression.
result = ""
for c in items(s):
case c
of 'a'..'z', 'A'..'Z', '0'..'9', '_':
result.add(c)
- else:
+ else:
result.add("\\x")
result.add(toHex(ord(c), 2))
-
+
const ## common regular expressions
- reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
- reNatural* = r"\b\d+\b" ## describes a natural number
- reInteger* = r"\b[-+]?\d+\b" ## describes an integer
- reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
- reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
- reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
- reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
+ reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
+ ## describes an identifier
+ reNatural* {.deprecated.} = r"\b\d+\b"
+ ## describes a natural number
+ reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
+ ## describes an integer
+ reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
+ ## describes a hexadecimal number
+ reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
+ ## describes a binary number (example: 0b11101)
+ reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
+ ## describes an octal number (example: 0o777)
+ reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
## describes a floating point number
- reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
- r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
- r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
- r"(?:[a-zA-Z]{2}|com|org|" &
- r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
+ reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
+ r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
+ r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
+ r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
+ r"info|mobi|name|aero|jobs|museum)\b"
## describes a common email address
- reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
- r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
+ reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
+ r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
## describes an URL
when isMainModule:
assert match("(a b c)", re"\( .* \)")
assert match("WHiLe", re("while", {reIgnoreCase}))
-
+
assert "0158787".match(re"\d+")
assert "ABC 0232".match(re"\w+\s+\d+")
assert "ABC".match(re"\d+ | \w+")
@@ -439,21 +452,21 @@ when isMainModule:
var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
assert matchLen("key1= cal9", pattern) == 11
-
+
assert find("_____abc_______", re"abc") == 5
-
- var matches: array[0..5, string]
- if match("abcdefg", re"c(d)ef(g)", matches, 2):
+
+ var matches: array[6, string]
+ if match("abcdefg", re"c(d)ef(g)", matches, 2):
assert matches[0] == "d"
assert matches[1] == "g"
else:
assert false
-
+
if "abc" =~ re"(a)bcxyz|(\w+)":
assert matches[1] == "abc"
else:
assert false
-
+
if "abc" =~ re"(cba)?.*":
assert matches[0] == nil
else: assert false
@@ -461,7 +474,7 @@ when isMainModule:
if "abc" =~ re"().*":
assert matches[0] == ""
else: assert false
-
+
assert "var1=key; var2=key2".endsWith(re"\w+=\w+")
assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
"var1<-keykey; var2<-key2key2")
@@ -471,7 +484,12 @@ when isMainModule:
var accum: seq[string] = @[]
for word in split("00232this02939is39an22example111", re"\d+"):
accum.add(word)
- assert(accum == @["this", "is", "an", "example"])
+ assert(accum == @["", "this", "is", "an", "example", ""])
+
+ accum = @[]
+ for word in split("AAA : : BBB", re"\s*:\s*"):
+ accum.add(word)
+ assert(accum == @["AAA", "", "BBB"])
for x in findAll("abcdef", re"^{.}", 3):
assert x == "d"
@@ -484,7 +502,7 @@ when isMainModule:
assert("XYZ".match(re"^\d*") == true)
block:
- var matches: array[0..15, string]
+ var matches: array[16, string]
if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
for i in 0..matches.high:
assert matches[i] == $chr(i + 'a'.ord)
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
index bb7cfc0d38..d318a19798 100644
--- a/lib/impure/ssl.nim
+++ b/lib/impure/ssl.nim
@@ -82,7 +82,7 @@ proc close*(sock: TSecureSocket) =
ERR_print_errors_fp(stderr)
raiseOSError(osLastError())
-when isMainModule:
+when not defined(testing) and isMainModule:
var s: TSecureSocket
echo connect(s, "smtp.gmail.com", 465)
diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim
index c22294061d..b41ca1e4bb 100644
--- a/lib/impure/zipfiles.nim
+++ b/lib/impure/zipfiles.nim
@@ -9,8 +9,8 @@
## This module implements a zip archive creator/reader/modifier.
-import
- streams, libzip, times, os
+import
+ streams, libzip, times, os, strutils
type
TZipArchive* = object of RootObj ## represents a zip archive
@@ -18,14 +18,14 @@ type
w: PZip
-proc zipError(z: var TZipArchive) =
+proc zipError(z: var TZipArchive) =
var e: ref IOError
new(e)
e.msg = $zip_strerror(z.w)
raise e
-
+
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
- ## Opens a zip file for reading, writing or appending. All file modes are
+ ## Opens a zip file for reading, writing or appending. All file modes are
## supported. Returns true iff successful, false otherwise.
var err, flags: int32
case mode
@@ -41,21 +41,21 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
proc close*(z: var TZipArchive) =
## Closes a zip file.
zip_close(z.w)
-
-proc createDir*(z: var TZipArchive, dir: string) =
+
+proc createDir*(z: var TZipArchive, dir: string) =
## Creates a directory within the `z` archive. This does not fail if the
- ## directory already exists. Note that for adding a file like
+ ## directory already exists. Note that for adding a file like
## ``"path1/path2/filename"`` it is not necessary
- ## to create the ``"path/path2"`` subdirectories - it will be done
- ## automatically by ``addFile``.
- assert(z.mode != fmRead)
+ ## to create the ``"path/path2"`` subdirectories - it will be done
+ ## automatically by ``addFile``.
+ assert(z.mode != fmRead)
discard zip_add_dir(z.w, dir)
zip_error_clear(z.w)
-proc addFile*(z: var TZipArchive, dest, src: string) =
+proc addFile*(z: var TZipArchive, dest, src: string) =
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
- ## may contain a path that will be created.
- assert(z.mode != fmRead)
+ ## may contain a path that will be created.
+ assert(z.mode != fmRead)
if not fileExists(src):
raise newException(IOError, "File '" & src & "' does not exist")
var zipsrc = zip_source_file(z.w, src, 0, -1)
@@ -67,21 +67,21 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
zip_source_free(zipsrc)
zipError(z)
-proc addFile*(z: var TZipArchive, file: string) =
+proc addFile*(z: var TZipArchive, file: string) =
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
## the name of the destination.
addFile(z, file, file)
-
-proc mySourceCallback(state, data: pointer, len: int,
- cmd: TZipSourceCmd): int {.cdecl.} =
+
+proc mySourceCallback(state, data: pointer, len: int,
+ cmd: TZipSourceCmd): int {.cdecl.} =
var src = cast[Stream](state)
case cmd
- of ZIP_SOURCE_OPEN:
+ of ZIP_SOURCE_OPEN:
if src.setPositionImpl != nil: setPosition(src, 0) # reset
of ZIP_SOURCE_READ:
result = readData(src, data, len)
of ZIP_SOURCE_CLOSE: close(src)
- of ZIP_SOURCE_STAT:
+ of ZIP_SOURCE_STAT:
var stat = cast[PZipStat](data)
zip_stat_init(stat)
stat.size = high(int32)-1 # we don't know the size
@@ -94,8 +94,8 @@ proc mySourceCallback(state, data: pointer, len: int,
result = 2*sizeof(cint)
of constZIP_SOURCE_FREE: GC_unref(src)
else: assert(false)
-
-proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
+
+proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
## Adds a file named with `dest` to the archive `z`. `dest`
## may contain a path. The file's content is read from the `src` stream.
assert(z.mode != fmRead)
@@ -105,39 +105,45 @@ proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
if zip_add(z.w, dest, zipsrc) < 0'i32:
zip_source_free(zipsrc)
zipError(z)
-
+
# -------------- zip file stream ---------------------------------------------
type
TZipFileStream = object of StreamObj
f: PZipFile
+ atEnd: bool
- PZipFileStream* =
- ref TZipFileStream ## a reader stream of a file within a zip archive
+ PZipFileStream* =
+ ref TZipFileStream ## a reader stream of a file within a zip archive
proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
-proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
+proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
+proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
+ if result == 0:
+ PZipFileStream(s).atEnd = true
-proc newZipFileStream(f: PZipFile): PZipFileStream =
+proc newZipFileStream(f: PZipFile): PZipFileStream =
new(result)
result.f = f
+ result.atEnd = false
result.closeImpl = fsClose
result.readDataImpl = fsReadData
+ result.atEndImpl = fsAtEnd
# other methods are nil!
# ----------------------------------------------------------------------------
-
-proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
+
+proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
## returns a stream that can be used to read the file named `filename`
## from the archive `z`. Returns nil in case of an error.
- ## The returned stream does not support the `setPosition`, `getPosition`,
+ ## The returned stream does not support the `setPosition`, `getPosition`,
## `writeData` or `atEnd` methods.
var x = zip_fopen(z.w, filename, 0'i32)
if x != nil: result = newZipFileStream(x)
-
-iterator walkFiles*(z: var TZipArchive): string =
- ## walks over all files in the archive `z` and returns the filename
+
+iterator walkFiles*(z: var TZipArchive): string =
+ ## walks over all files in the archive `z` and returns the filename
## (including the path).
var i = 0'i32
var num = zip_get_num_files(z.w)
@@ -158,12 +164,20 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
## extracts a file from the zip archive `z` to the destination filename.
- var file = newFileStream(dest, fmReadWrite)
+ var file = newFileStream(dest, fmWrite)
extractFile(z, srcFile, file)
file.close()
proc extractAll*(z: var TZipArchive, dest: string) =
## extracts all files from archive `z` to the destination directory.
for file in walkFiles(z):
- extractFile(z, file, dest / extractFilename(file))
+ if file.endsWith("/"):
+ createDir(dest / file)
+ else:
+ extractFile(z, file, dest / file)
+when not defined(testing) and isMainModule:
+ var zip: TZipArchive
+ if not zip.open("nim-0.11.0.zip"):
+ raise newException(IOError, "opening zip failed")
+ zip.extractAll("test")
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index 870213db3e..b063fa8386 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -36,8 +36,11 @@ type
onsubmit*: proc (event: ref TEvent) {.nimcall.}
onunload*: proc (event: ref TEvent) {.nimcall.}
- TWindow* {.importc.} = object of TEventHandlers
- document*: ref TDocument
+ addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
+
+ Window* = ref WindowObj
+ WindowObj {.importc.} = object of TEventHandlers
+ document*: Document
event*: ref TEvent
history*: ref THistory
location*: ref TLocation
@@ -55,7 +58,6 @@ type
status*: cstring
toolbar*: ref TToolBar
- addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
alert*: proc (msg: cstring) {.nimcall.}
back*: proc () {.nimcall.}
blur*: proc () {.nimcall.}
@@ -66,7 +68,7 @@ type
confirm*: proc (msg: cstring): bool {.nimcall.}
disableExternalCapture*: proc () {.nimcall.}
enableExternalCapture*: proc () {.nimcall.}
- find*: proc (text: cstring, caseSensitive = false,
+ find*: proc (text: cstring, caseSensitive = false,
backwards = false) {.nimcall.}
focus*: proc () {.nimcall.}
forward*: proc () {.nimcall.}
@@ -75,7 +77,7 @@ type
moveBy*: proc (x, y: int) {.nimcall.}
moveTo*: proc (x, y: int) {.nimcall.}
open*: proc (uri, windowname: cstring,
- properties: cstring = nil): ref TWindow {.nimcall.}
+ properties: cstring = nil): Window {.nimcall.}
print*: proc () {.nimcall.}
prompt*: proc (text, default: cstring): cstring {.nimcall.}
releaseEvents*: proc (eventMask: int) {.nimcall.}
@@ -89,115 +91,8 @@ type
stop*: proc () {.nimcall.}
frames*: seq[TFrame]
- TFrame* {.importc.} = object of TWindow
-
- TDocument* {.importc.} = object of TEventHandlers
- addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
- alinkColor*: cstring
- bgColor*: cstring
- charset*: cstring
- cookie*: cstring
- defaultCharset*: cstring
- fgColor*: cstring
- lastModified*: cstring
- linkColor*: cstring
- referrer*: cstring
- title*: cstring
- URL*: cstring
- vlinkColor*: cstring
- captureEvents*: proc (eventMask: int) {.nimcall.}
- createAttribute*: proc (identifier: cstring): ref TNode {.nimcall.}
- createElement*: proc (identifier: cstring): ref TNode {.nimcall.}
- createTextNode*: proc (identifier: cstring): ref TNode {.nimcall.}
- getElementById*: proc (id: cstring): ref TNode {.nimcall.}
- getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
- getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
- getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
- getSelection*: proc (): cstring {.nimcall.}
- handleEvent*: proc (event: ref TEvent) {.nimcall.}
- open*: proc () {.nimcall.}
- releaseEvents*: proc (eventMask: int) {.nimcall.}
- routeEvent*: proc (event: ref TEvent) {.nimcall.}
- write*: proc (text: cstring) {.nimcall.}
- writeln*: proc (text: cstring) {.nimcall.}
- anchors*: seq[ref TAnchor]
- forms*: seq[ref TForm]
- images*: seq[ref TImage]
- applets*: seq[ref TApplet]
- embeds*: seq[ref TEmbed]
- links*: seq[ref TLink]
-
- TLink* {.importc.} = object of RootObj
- name*: cstring
- target*: cstring
- text*: cstring
- x*: int
- y*: int
-
- TEmbed* {.importc.} = object of RootObj
- height*: int
- hspace*: int
- name*: cstring
- src*: cstring
- width*: int
- `type`*: cstring
- vspace*: int
- play*: proc () {.nimcall.}
- stop*: proc () {.nimcall.}
-
- TAnchor* {.importc.} = object of RootObj
- name*: cstring
- text*: cstring
- x*, y*: int
-
- TApplet* {.importc.} = object of RootObj
-
- TElement* {.importc.} = object of TEventHandlers
- checked*: bool
- defaultChecked*: bool
- defaultValue*: cstring
- disabled*: bool
- form*: ref TForm
- name*: cstring
- readOnly*: bool
- `type`*: cstring
- value*: cstring
- blur*: proc () {.nimcall.}
- click*: proc () {.nimcall.}
- focus*: proc () {.nimcall.}
- handleEvent*: proc (event: ref TEvent) {.nimcall.}
- select*: proc () {.nimcall.}
- options*: seq[ref TOption]
-
- TOption* {.importc.} = object of RootObj
- defaultSelected*: bool
- selected*: bool
- selectedIndex*: int
- text*: cstring
- value*: cstring
-
- TForm* {.importc.} = object of TEventHandlers
- action*: cstring
- encoding*: cstring
- `method`*: cstring
- name*: cstring
- target*: cstring
- handleEvent*: proc (event: ref TEvent) {.nimcall.}
- reset*: proc () {.nimcall.}
- submit*: proc () {.nimcall.}
- elements*: seq[ref TElement]
-
- TImage* {.importc.} = object of TEventHandlers
- border*: int
- complete*: bool
- height*: int
- hspace*: int
- lowsrc*: cstring
- name*: cstring
- src*: cstring
- vspace*: int
- width*: int
- handleEvent*: proc (event: ref TEvent) {.nimcall.}
+ Frame* = ref FrameObj
+ FrameObj {.importc.} = object of WindowObj
ClassList* {.importc.} = object of RootObj
add*: proc (class: cstring) {.nimcall.}
@@ -218,43 +113,153 @@ type
DocumentTypeNode,
DocumentFragmentNode,
NotationNode
- TNode* {.importc.} = object of RootObj
- attributes*: seq[ref TNode]
- childNodes*: seq[ref TNode]
- children*: seq[ref TNode]
- classList*: ref Classlist
+
+ Node* = ref NodeObj
+ NodeObj {.importc.} = object of TEventHandlers
+ attributes*: seq[Node]
+ childNodes*: seq[Node]
+ children*: seq[Node]
data*: cstring
- firstChild*: ref TNode
- lastChild*: ref TNode
- nextSibling*: ref TNode
+ firstChild*: Node
+ lastChild*: Node
+ nextSibling*: Node
nodeName*: cstring
nodeType*: TNodeType
nodeValue*: cstring
- parentNode*: ref TNode
- previousSibling*: ref TNode
- appendChild*: proc (child: ref TNode) {.nimcall.}
+ parentNode*: Node
+ previousSibling*: Node
+ appendChild*: proc (child: Node) {.nimcall.}
appendData*: proc (data: cstring) {.nimcall.}
- cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.}
+ cloneNode*: proc (copyContent: bool): Node {.nimcall.}
deleteData*: proc (start, len: int) {.nimcall.}
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
- getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
- getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
- getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
+ getAttributeNode*: proc (attr: cstring): Node {.nimcall.}
hasChildNodes*: proc (): bool {.nimcall.}
innerHTML*: cstring
- insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
+ insertBefore*: proc (newNode, before: Node) {.nimcall.}
insertData*: proc (position: int, data: cstring) {.nimcall.}
- addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent)) {.nimcall.}
removeAttribute*: proc (attr: cstring) {.nimcall.}
- removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
- removeChild*: proc (child: ref TNode) {.nimcall.}
- replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
+ removeAttributeNode*: proc (attr: Node) {.nimcall.}
+ removeChild*: proc (child: Node) {.nimcall.}
+ replaceChild*: proc (newNode, oldNode: Node) {.nimcall.}
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
scrollIntoView*: proc () {.nimcall.}
setAttribute*: proc (name, value: cstring) {.nimcall.}
- setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
+ setAttributeNode*: proc (attr: Node) {.nimcall.}
style*: ref TStyle
+ Document* = ref DocumentObj
+ DocumentObj {.importc.} = object of NodeObj
+ alinkColor*: cstring
+ bgColor*: cstring
+ body*: Element
+ charset*: cstring
+ cookie*: cstring
+ defaultCharset*: cstring
+ fgColor*: cstring
+ head*: Element
+ lastModified*: cstring
+ linkColor*: cstring
+ referrer*: cstring
+ title*: cstring
+ URL*: cstring
+ vlinkColor*: cstring
+ captureEvents*: proc (eventMask: int) {.nimcall.}
+ createAttribute*: proc (identifier: cstring): Node {.nimcall.}
+ createElement*: proc (identifier: cstring): Element {.nimcall.}
+ createTextNode*: proc (identifier: cstring): Node {.nimcall.}
+ getElementById*: proc (id: cstring): Element {.nimcall.}
+ getElementsByName*: proc (name: cstring): seq[Element] {.nimcall.}
+ getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+ getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
+ getSelection*: proc (): cstring {.nimcall.}
+ handleEvent*: proc (event: ref TEvent) {.nimcall.}
+ open*: proc () {.nimcall.}
+ releaseEvents*: proc (eventMask: int) {.nimcall.}
+ routeEvent*: proc (event: ref TEvent) {.nimcall.}
+ write*: proc (text: cstring) {.nimcall.}
+ writeln*: proc (text: cstring) {.nimcall.}
+ anchors*: seq[AnchorElement]
+ forms*: seq[FormElement]
+ images*: seq[ImageElement]
+ applets*: seq[ref TApplet]
+ embeds*: seq[EmbedElement]
+ links*: seq[LinkElement]
+
+ Element* = ref ElementObj
+ ElementObj {.importc.} = object of NodeObj
+ classList*: ref Classlist
+ checked*: bool
+ defaultChecked*: bool
+ defaultValue*: cstring
+ disabled*: bool
+ form*: FormElement
+ name*: cstring
+ readOnly*: bool
+ blur*: proc () {.nimcall.}
+ click*: proc () {.nimcall.}
+ focus*: proc () {.nimcall.}
+ handleEvent*: proc (event: ref TEvent) {.nimcall.}
+ select*: proc () {.nimcall.}
+ options*: seq[OptionElement]
+ getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+ getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
+
+ LinkElement* = ref LinkObj
+ LinkObj {.importc.} = object of ElementObj
+ target*: cstring
+ text*: cstring
+ x*: int
+ y*: int
+
+ EmbedElement* = ref EmbedObj
+ EmbedObj {.importc.} = object of ElementObj
+ height*: int
+ hspace*: int
+ src*: cstring
+ width*: int
+ `type`*: cstring
+ vspace*: int
+ play*: proc () {.nimcall.}
+ stop*: proc () {.nimcall.}
+
+ AnchorElement* = ref AnchorObj
+ AnchorObj {.importc.} = object of ElementObj
+ text*: cstring
+ x*, y*: int
+
+ TApplet* {.importc.} = object of RootObj
+
+ OptionElement* = ref OptionObj
+ OptionObj {.importc.} = object of ElementObj
+ defaultSelected*: bool
+ selected*: bool
+ selectedIndex*: int
+ text*: cstring
+ value*: cstring
+
+ FormElement* = ref FormObj
+ FormObj {.importc.} = object of ElementObj
+ action*: cstring
+ encoding*: cstring
+ `method`*: cstring
+ target*: cstring
+ reset*: proc () {.nimcall.}
+ submit*: proc () {.nimcall.}
+ elements*: seq[Element]
+
+ ImageElement* = ref ImageObj
+ ImageObj {.importc.} = object of ElementObj
+ border*: int
+ complete*: bool
+ height*: int
+ hspace*: int
+ lowsrc*: cstring
+ src*: cstring
+ vspace*: int
+ width*: int
+
+
TStyle* {.importc.} = object of RootObj
background*: cstring
backgroundAttachment*: cstring
@@ -350,7 +355,7 @@ type
setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.}
TEvent* {.importc.} = object of RootObj
- target*: ref TNode
+ target*: Node
altKey*, ctrlKey*, shiftKey*: bool
button*: int
clientX*, clientY*: int
@@ -448,8 +453,8 @@ type
TInterval* {.importc.} = object of RootObj
var
- window* {.importc, nodecl.}: ref TWindow
- document* {.importc, nodecl.}: ref TDocument
+ window* {.importc, nodecl.}: Window
+ document* {.importc, nodecl.}: Document
navigator* {.importc, nodecl.}: ref TNavigator
screen* {.importc, nodecl.}: ref TScreen
@@ -466,3 +471,17 @@ proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
proc parseInt*(s: cstring): int {.importc, nodecl.}
proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
+
+
+type
+ TWindow* {.deprecated.} = WindowObj
+ TFrame* {.deprecated.} = FrameObj
+ TNode* {.deprecated.} = NodeObj
+ TDocument* {.deprecated.} = DocumentObj
+ TElement* {.deprecated.} = ElementObj
+ TLink* {.deprecated.} = LinkObj
+ TEmbed* {.deprecated.} = EmbedObj
+ TAnchor* {.deprecated.} = AnchorObj
+ TOption* {.deprecated.} = OptionObj
+ TForm* {.deprecated.} = FormObj
+ TImage* {.deprecated.} = ImageObj
diff --git a/lib/nimbase.h b/lib/nimbase.h
index e9dad0bb7a..eea618bac1 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -343,15 +343,15 @@ struct TFrame {
};
#define nimfr(proc, file) \
- TFrame F; \
- F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
+ TFrame FR; \
+ FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
#define nimfrs(proc, file, slots, length) \
- struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
- F.procname = proc; F.filename = file; F.line = 0; F.len = length; nimFrame((TFrame*)&F);
+ struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} FR; \
+ FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
#define nimln(n, file) \
- F.line = n; F.filename = file;
+ FR.line = n; FR.filename = file;
#define NIM_POSIX_INIT __attribute__((constructor))
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 97784898e0..2ee94ba139 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -11,25 +11,25 @@
## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
## also supported.
-import
+import
os, strutils, rstast
type
- TRstParseOption* = enum ## options for the RST parser
+ TRstParseOption* = enum ## options for the RST parser
roSkipPounds, ## skip ``#`` at line beginning (documentation
## embedded in Nim comments)
roSupportSmilies, ## make the RST parser support smilies like ``:)``
roSupportRawDirective, ## support the ``raw`` directive (don't support
## it for sandboxing)
roSupportMarkdown ## support additional features of markdown
-
+
TRstParseOptions* = set[TRstParseOption]
-
+
TMsgClass* = enum
- mcHint = "Hint",
- mcWarning = "Warning",
+ mcHint = "Hint",
+ mcWarning = "Warning",
mcError = "Error"
-
+
TMsgKind* = enum ## the possible messages
meCannotOpenFile,
meExpected,
@@ -41,20 +41,20 @@ type
mwUnknownSubstitution,
mwUnsupportedLanguage,
mwUnsupportedField
-
+
TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
arg: string) {.nimcall.} ## what to do in case of an error
TFindFileHandler* = proc (filename: string): string {.nimcall.}
const
messages: array [TMsgKind, string] = [
- meCannotOpenFile: "cannot open '$1'",
+ meCannotOpenFile: "cannot open '$1'",
meExpected: "'$1' expected",
meGridTableNotImplemented: "grid table is not implemented",
- meNewSectionExpected: "new section expected",
+ meNewSectionExpected: "new section expected",
meGeneralParseError: "general parse error",
meInvalidDirective: "invalid directive: '$1'",
- mwRedefinitionOfLabel: "redefinition of label '$1'",
+ mwRedefinitionOfLabel: "redefinition of label '$1'",
mwUnknownSubstitution: "unknown substitution '$1'",
mwUnsupportedLanguage: "language '$1' not supported",
mwUnsupportedField: "field '$1' not supported"
@@ -67,7 +67,7 @@ proc getArgument*(n: PRstNode): string
# ----------------------------- scanner part --------------------------------
-const
+const
SymChars: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SmileyStartChars: set[char] = {':', ';', '8'}
Smilies = {
@@ -111,14 +111,14 @@ const
}
type
- TTokType = enum
+ TTokType = enum
tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
TToken = object # a RST token
kind*: TTokType # the type of the token
ival*: int # the indentation or parsed integer value
symbol*: string # the parsed symbol as string
line*, col*: int # line and column of the token
-
+
TTokenSeq = seq[TToken]
TLexer = object of RootObj
buf*: cstring
@@ -127,61 +127,61 @@ type
skipPounds*: bool
-proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
+proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
tok.kind = tkWord
tok.line = L.line
tok.col = L.col
var pos = L.bufpos
- while true:
+ while true:
add(tok.symbol, L.buf[pos])
inc(pos)
- if L.buf[pos] notin s: break
+ if L.buf[pos] notin s: break
inc(L.col, pos - L.bufpos)
L.bufpos = pos
-proc getAdornment(L: var TLexer, tok: var TToken) =
+proc getAdornment(L: var TLexer, tok: var TToken) =
tok.kind = tkAdornment
tok.line = L.line
tok.col = L.col
var pos = L.bufpos
var c = L.buf[pos]
- while true:
+ while true:
add(tok.symbol, L.buf[pos])
inc(pos)
- if L.buf[pos] != c: break
+ if L.buf[pos] != c: break
inc(L.col, pos - L.bufpos)
L.bufpos = pos
-proc getIndentAux(L: var TLexer, start: int): int =
+proc getIndentAux(L: var TLexer, start: int): int =
var pos = start
- var buf = L.buf
+ var buf = L.buf
# skip the newline (but include it in the token!)
- if buf[pos] == '\x0D':
+ if buf[pos] == '\x0D':
if buf[pos + 1] == '\x0A': inc(pos, 2)
else: inc(pos)
- elif buf[pos] == '\x0A':
+ elif buf[pos] == '\x0A':
inc(pos)
- if L.skipPounds:
+ if L.skipPounds:
if buf[pos] == '#': inc(pos)
if buf[pos] == '#': inc(pos)
- while true:
+ while true:
case buf[pos]
- of ' ', '\x0B', '\x0C':
+ of ' ', '\x0B', '\x0C':
inc(pos)
inc(result)
- of '\x09':
+ of '\x09':
inc(pos)
result = result - (result mod 8) + 8
- else:
+ else:
break # EndOfFile also leaves the loop
- if buf[pos] == '\0':
+ if buf[pos] == '\0':
result = 0
- elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'):
+ elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'):
# look at the next line for proper indentation:
result = getIndentAux(L, pos)
L.bufpos = pos # no need to set back buf
-
-proc getIndent(L: var TLexer, tok: var TToken) =
+
+proc getIndent(L: var TLexer, tok: var TToken) =
tok.col = 0
tok.kind = tkIndent # skip the newline (but include it in the token!)
tok.ival = getIndentAux(L, L.bufpos)
@@ -191,85 +191,85 @@ proc getIndent(L: var TLexer, tok: var TToken) =
tok.ival = max(tok.ival - L.baseIndent, 0)
tok.symbol = "\n" & spaces(tok.ival)
-proc rawGetTok(L: var TLexer, tok: var TToken) =
+proc rawGetTok(L: var TLexer, tok: var TToken) =
tok.symbol = ""
tok.ival = 0
var c = L.buf[L.bufpos]
case c
- of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9':
+ of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9':
getThing(L, tok, SymChars)
- of ' ', '\x09', '\x0B', '\x0C':
+ of ' ', '\x09', '\x0B', '\x0C':
getThing(L, tok, {' ', '\x09'})
tok.kind = tkWhite
- if L.buf[L.bufpos] in {'\x0D', '\x0A'}:
+ if L.buf[L.bufpos] in {'\x0D', '\x0A'}:
rawGetTok(L, tok) # ignore spaces before \n
- of '\x0D', '\x0A':
+ of '\x0D', '\x0A':
getIndent(L, tok)
- of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
+ of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
- '|', '}', '~':
+ '|', '}', '~':
getAdornment(L, tok)
if len(tok.symbol) <= 3: tok.kind = tkPunct
- else:
+ else:
tok.line = L.line
tok.col = L.col
- if c == '\0':
+ if c == '\0':
tok.kind = tkEof
- else:
+ else:
tok.kind = tkOther
add(tok.symbol, c)
inc(L.bufpos)
inc(L.col)
tok.col = max(tok.col - L.baseIndent, 0)
-proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
+proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
var L: TLexer
var length = len(tokens)
L.buf = cstring(buffer)
L.line = 0 # skip UTF-8 BOM
- if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
+ if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
inc(L.bufpos, 3)
L.skipPounds = skipPounds
- if skipPounds:
- if L.buf[L.bufpos] == '#':
+ if skipPounds:
+ if L.buf[L.bufpos] == '#':
inc(L.bufpos)
inc(result)
- if L.buf[L.bufpos] == '#':
+ if L.buf[L.bufpos] == '#':
inc(L.bufpos)
inc(result)
L.baseIndent = 0
- while L.buf[L.bufpos] == ' ':
+ while L.buf[L.bufpos] == ' ':
inc(L.bufpos)
inc(L.baseIndent)
inc(result)
- while true:
+ while true:
inc(length)
setLen(tokens, length)
rawGetTok(L, tokens[length - 1])
- if tokens[length - 1].kind == tkEof: break
- if tokens[0].kind == tkWhite:
+ if tokens[length - 1].kind == tkEof: break
+ if tokens[0].kind == tkWhite:
# BUGFIX
tokens[0].ival = len(tokens[0].symbol)
tokens[0].kind = tkIndent
type
TLevelMap = array[char, int]
- TSubstitution = object
+ TSubstitution = object
key*: string
value*: PRstNode
- TSharedState = object
+ TSharedState = object
options: TRstParseOptions # parsing options
uLevel, oLevel: int # counters for the section levels
subs: seq[TSubstitution] # substitutions
refs: seq[TSubstitution] # references
underlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the
- # current document.
+ # current document.
# This is for single underline adornments.
- overlineToLevel: TLevelMap # Saves for each possible title adornment
+ overlineToLevel: TLevelMap # Saves for each possible title adornment
# character its level in the current
- # document.
+ # document.
# This is for over-underline adornments.
msgHandler: TMsgHandler # How to handle errors.
findFile: TFindFileHandler # How to find files.
@@ -293,7 +293,7 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
of 'w', 'W': result = mcWarning
of 'h', 'H': result = mcHint
else: assert false, "msgkind does not fit naming scheme"
-
+
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
arg: string) {.procvar.} =
let mc = msgkind.whichMsgClass
@@ -302,31 +302,31 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
if mc == mcError: raise newException(EParseError, message)
else: writeln(stdout, message)
-proc defaultFindFile*(filename: string): string {.procvar.} =
+proc defaultFindFile*(filename: string): string {.procvar.} =
if existsFile(filename): result = filename
else: result = ""
proc newSharedState(options: TRstParseOptions,
findFile: TFindFileHandler,
- msgHandler: TMsgHandler): PSharedState =
+ msgHandler: TMsgHandler): PSharedState =
new(result)
result.subs = @[]
result.refs = @[]
result.options = options
result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
result.findFile = if not isNil(findFile): findFile else: defaultFindFile
-
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
- p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
+ p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind, arg)
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
p.s.msgHandler(p.filename, p.line + line,
p.col + col, msgKind, arg)
-proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
- p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
- p.col + p.tok[p.idx].col, msgKind,
+proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
+ p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+ p.col + p.tok[p.idx].col, msgKind,
p.tok[p.idx].symbol)
when false:
@@ -334,16 +334,16 @@ when false:
assert p.indentStack[0] == 0
for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
-proc currInd(p: TRstParser): int =
+proc currInd(p: TRstParser): int =
result = p.indentStack[high(p.indentStack)]
-proc pushInd(p: var TRstParser, ind: int) =
+proc pushInd(p: var TRstParser, ind: int) =
add(p.indentStack, ind)
proc popInd(p: var TRstParser) =
if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
-
-proc initParser(p: var TRstParser, sharedState: PSharedState) =
+
+proc initParser(p: var TRstParser, sharedState: PSharedState) =
p.indentStack = @[0]
p.tok = @[]
p.idx = 0
@@ -353,150 +353,150 @@ proc initParser(p: var TRstParser, sharedState: PSharedState) =
p.line = 1
p.s = sharedState
-proc addNodesAux(n: PRstNode, result: var string) =
- if n.kind == rnLeaf:
+proc addNodesAux(n: PRstNode, result: var string) =
+ if n.kind == rnLeaf:
add(result, n.text)
- else:
+ else:
for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result)
-
-proc addNodes(n: PRstNode): string =
+
+proc addNodes(n: PRstNode): string =
result = ""
addNodesAux(n, result)
-proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
- if n.kind == rnLeaf:
- for i in countup(0, len(n.text) - 1):
+proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
+ if n.kind == rnLeaf:
+ for i in countup(0, len(n.text) - 1):
case n.text[i]
- of '0'..'9':
- if b:
+ of '0'..'9':
+ if b:
add(r, '-')
b = false
if len(r) == 0: add(r, 'Z')
add(r, n.text[i])
- of 'a'..'z':
- if b:
+ of 'a'..'z':
+ if b:
add(r, '-')
b = false
add(r, n.text[i])
- of 'A'..'Z':
- if b:
+ of 'A'..'Z':
+ if b:
add(r, '-')
b = false
add(r, chr(ord(n.text[i]) - ord('A') + ord('a')))
- else:
+ else:
if (len(r) > 0): b = true
- else:
+ else:
for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b)
-
-proc rstnodeToRefname(n: PRstNode): string =
+
+proc rstnodeToRefname(n: PRstNode): string =
result = ""
var b = false
rstnodeToRefnameAux(n, result, b)
-proc findSub(p: var TRstParser, n: PRstNode): int =
- var key = addNodes(n)
+proc findSub(p: var TRstParser, n: PRstNode): int =
+ var key = addNodes(n)
# the spec says: if no exact match, try one without case distinction:
- for i in countup(0, high(p.s.subs)):
- if key == p.s.subs[i].key:
+ for i in countup(0, high(p.s.subs)):
+ if key == p.s.subs[i].key:
return i
- for i in countup(0, high(p.s.subs)):
- if cmpIgnoreStyle(key, p.s.subs[i].key) == 0:
+ for i in countup(0, high(p.s.subs)):
+ if cmpIgnoreStyle(key, p.s.subs[i].key) == 0:
return i
result = -1
-proc setSub(p: var TRstParser, key: string, value: PRstNode) =
+proc setSub(p: var TRstParser, key: string, value: PRstNode) =
var length = len(p.s.subs)
- for i in countup(0, length - 1):
- if key == p.s.subs[i].key:
+ for i in countup(0, length - 1):
+ if key == p.s.subs[i].key:
p.s.subs[i].value = value
- return
+ return
setLen(p.s.subs, length + 1)
p.s.subs[length].key = key
p.s.subs[length].value = value
-proc setRef(p: var TRstParser, key: string, value: PRstNode) =
+proc setRef(p: var TRstParser, key: string, value: PRstNode) =
var length = len(p.s.refs)
- for i in countup(0, length - 1):
+ for i in countup(0, length - 1):
if key == p.s.refs[i].key:
if p.s.refs[i].value.addNodes != value.addNodes:
rstMessage(p, mwRedefinitionOfLabel, key)
p.s.refs[i].value = value
- return
+ return
setLen(p.s.refs, length + 1)
p.s.refs[length].key = key
p.s.refs[length].value = value
-proc findRef(p: var TRstParser, key: string): PRstNode =
- for i in countup(0, high(p.s.refs)):
- if key == p.s.refs[i].key:
+proc findRef(p: var TRstParser, key: string): PRstNode =
+ for i in countup(0, high(p.s.refs)):
+ if key == p.s.refs[i].key:
return p.s.refs[i].value
-proc newLeaf(p: var TRstParser): PRstNode =
+proc newLeaf(p: var TRstParser): PRstNode =
result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
-proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
+proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
var res = newRstNode(rnInner)
- while true:
+ while true:
case p.tok[p.idx].kind
- of tkWord, tkOther, tkWhite:
+ of tkWord, tkOther, tkWhite:
add(res, newLeaf(p))
- of tkPunct:
- if p.tok[p.idx].symbol == endStr:
+ of tkPunct:
+ if p.tok[p.idx].symbol == endStr:
inc(p.idx)
- break
- else:
+ break
+ else:
add(res, newLeaf(p))
- else:
+ else:
rstMessage(p, meExpected, endStr)
- break
+ break
inc(p.idx)
result = res
-proc untilEol(p: var TRstParser): PRstNode =
+proc untilEol(p: var TRstParser): PRstNode =
result = newRstNode(rnInner)
- while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+ while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
add(result, newLeaf(p))
inc(p.idx)
-proc expect(p: var TRstParser, tok: string) =
+proc expect(p: var TRstParser, tok: string) =
if p.tok[p.idx].symbol == tok: inc(p.idx)
else: rstMessage(p, meExpected, tok)
-
-proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
+
+proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
result = p.tok[p.idx].symbol == markup
- if not result:
+ if not result:
return # Rule 3:
result = not (p.tok[p.idx - 1].kind in {tkIndent, tkWhite})
- if not result:
+ if not result:
return # Rule 4:
result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or
(p.tok[p.idx + 1].symbol[0] in
- {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!',
+ {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!',
'?', '_'})
- if not result:
+ if not result:
return # Rule 7:
- if p.idx > 0:
- if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
+ if p.idx > 0:
+ if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
result = false
-proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
+proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
var d: char
result = p.tok[p.idx].symbol == markup
- if not result:
+ if not result:
return # Rule 1:
result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or
(p.tok[p.idx - 1].symbol[0] in
{'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'})
- if not result:
+ if not result:
return # Rule 2:
result = not (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof})
- if not result:
+ if not result:
return # Rule 5 & 7:
- if p.idx > 0:
- if p.tok[p.idx - 1].symbol == "\\":
+ if p.idx > 0:
+ if p.tok[p.idx - 1].symbol == "\\":
result = false
- else:
+ else:
var c = p.tok[p.idx - 1].symbol[0]
case c
of '\'', '\"': d = c
@@ -507,7 +507,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
else: d = '\0'
if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
-proc match(p: TRstParser, start: int, expr: string): bool =
+proc match(p: TRstParser, start: int, expr: string): bool =
# regular expressions are:
# special char exact match
# 'w' tkWord
@@ -521,7 +521,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
var i = 0
var j = start
var last = len(expr) - 1
- while i <= last:
+ while i <= last:
case expr[i]
of 'w': result = p.tok[j].kind == tkWord
of ' ': result = p.tok[j].kind == tkWhite
@@ -531,75 +531,75 @@ proc match(p: TRstParser, start: int, expr: string): bool =
of 'o': result = p.tok[j].kind == tkOther
of 'T': result = true
of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
- of 'e':
+ of 'e':
result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
- if result:
+ if result:
case p.tok[j].symbol[0]
of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
else: discard
- else:
+ else:
var c = expr[i]
var length = 0
- while (i <= last) and (expr[i] == c):
+ while (i <= last) and (expr[i] == c):
inc(i)
inc(length)
dec(i)
result = (p.tok[j].kind in {tkPunct, tkAdornment}) and
(len(p.tok[j].symbol) == length) and (p.tok[j].symbol[0] == c)
- if not result: return
+ if not result: return
inc(j)
inc(i)
result = true
-
-proc fixupEmbeddedRef(n, a, b: PRstNode) =
+
+proc fixupEmbeddedRef(n, a, b: PRstNode) =
var sep = - 1
- for i in countdown(len(n) - 2, 0):
- if n.sons[i].text == "<":
+ for i in countdown(len(n) - 2, 0):
+ if n.sons[i].text == "<":
sep = i
- break
+ break
var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
for i in countup(0, sep - incr): add(a, n.sons[i])
for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
-
-proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
+
+proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
result = n
- if isInlineMarkupEnd(p, "_"):
+ if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
inc(p.idx)
if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
var a = newRstNode(rnInner)
var b = newRstNode(rnInner)
fixupEmbeddedRef(n, a, b)
- if len(a) == 0:
+ if len(a) == 0:
result = newRstNode(rnStandaloneHyperlink)
add(result, b)
- else:
+ else:
result = newRstNode(rnHyperlink)
add(result, a)
add(result, b)
setRef(p, rstnodeToRefname(a), b)
- elif n.kind == rnInterpretedText:
+ elif n.kind == rnInterpretedText:
n.kind = rnRef
- else:
+ else:
result = newRstNode(rnRef)
add(result, n)
- elif match(p, p.idx, ":w:"):
+ elif match(p, p.idx, ":w:"):
# a role:
- if p.tok[p.idx + 1].symbol == "idx":
+ if p.tok[p.idx + 1].symbol == "idx":
n.kind = rnIdx
- elif p.tok[p.idx + 1].symbol == "literal":
+ elif p.tok[p.idx + 1].symbol == "literal":
n.kind = rnInlineLiteral
- elif p.tok[p.idx + 1].symbol == "strong":
+ elif p.tok[p.idx + 1].symbol == "strong":
n.kind = rnStrongEmphasis
- elif p.tok[p.idx + 1].symbol == "emphasis":
+ elif p.tok[p.idx + 1].symbol == "emphasis":
n.kind = rnEmphasis
elif (p.tok[p.idx + 1].symbol == "sub") or
- (p.tok[p.idx + 1].symbol == "subscript"):
+ (p.tok[p.idx + 1].symbol == "subscript"):
n.kind = rnSub
elif (p.tok[p.idx + 1].symbol == "sup") or
- (p.tok[p.idx + 1].symbol == "supscript"):
+ (p.tok[p.idx + 1].symbol == "supscript"):
n.kind = rnSup
- else:
+ else:
result = newRstNode(rnGeneralRole)
n.kind = rnInner
add(result, n)
@@ -614,7 +614,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
inc j, p.tok[result].symbol.len
inc result
if j < expr.len: result = 0
-
+
proc parseSmiley(p: var TRstParser): PRstNode =
if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
for key, val in items(Smilies):
@@ -636,17 +636,17 @@ proc isUrl(p: TRstParser, i: int): bool =
(p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
-proc parseUrl(p: var TRstParser, father: PRstNode) =
+proc parseUrl(p: var TRstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<':
if isUrl(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
- while true:
+ while true:
case p.tok[p.idx].kind
of tkWord, tkAdornment, tkOther: discard
- of tkPunct:
+ of tkPunct:
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break
- else: break
+ else: break
add(n, newLeaf(p))
inc(p.idx)
add(father, n)
@@ -655,13 +655,13 @@ proc parseUrl(p: var TRstParser, father: PRstNode) =
inc(p.idx)
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
-
-proc parseBackslash(p: var TRstParser, father: PRstNode) =
+
+proc parseBackslash(p: var TRstParser, father: PRstNode) =
assert(p.tok[p.idx].kind == tkPunct)
- if p.tok[p.idx].symbol == "\\\\":
+ if p.tok[p.idx].symbol == "\\\\":
add(father, newRstNode(rnLeaf, "\\"))
inc(p.idx)
- elif p.tok[p.idx].symbol == "\\":
+ elif p.tok[p.idx].symbol == "\\":
# XXX: Unicode?
inc(p.idx)
if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p))
@@ -674,13 +674,13 @@ when false:
proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
if not verbatim and isURL(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
- while true:
+ while true:
case p.tok[p.idx].kind
of tkWord, tkAdornment, tkOther: nil
- of tkPunct:
+ of tkPunct:
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break
- else: break
+ else: break
add(n, newLeaf(p))
inc(p.idx)
add(father, n)
@@ -694,33 +694,33 @@ when false:
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
-proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
- interpretBackslash: bool) =
+proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
+ interpretBackslash: bool) =
let
line = p.tok[p.idx].line
col = p.tok[p.idx].col
inc p.idx
- while true:
+ while true:
case p.tok[p.idx].kind
- of tkPunct:
- if isInlineMarkupEnd(p, postfix):
+ of tkPunct:
+ if isInlineMarkupEnd(p, postfix):
inc(p.idx)
- break
- elif interpretBackslash:
+ break
+ elif interpretBackslash:
parseBackslash(p, father)
- else:
+ else:
add(father, newLeaf(p))
inc(p.idx)
- of tkAdornment, tkWord, tkOther:
+ of tkAdornment, tkWord, tkOther:
add(father, newLeaf(p))
inc(p.idx)
- of tkIndent:
+ of tkIndent:
add(father, newRstNode(rnLeaf, " "))
inc(p.idx)
- if p.tok[p.idx].kind == tkIndent:
+ if p.tok[p.idx].kind == tkIndent:
rstMessage(p, meExpected, postfix, line, col)
- break
- of tkWhite:
+ break
+ of tkWhite:
add(father, newRstNode(rnLeaf, " "))
inc(p.idx)
else: rstMessage(p, meExpected, postfix, line, col)
@@ -753,20 +753,20 @@ proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
result = newRstNode(rnCodeBlock)
add(result, args)
add(result, nil)
- add(result, lb)
-
-proc parseInline(p: var TRstParser, father: PRstNode) =
+ add(result, lb)
+
+proc parseInline(p: var TRstParser, father: PRstNode) =
case p.tok[p.idx].kind
- of tkPunct:
+ of tkPunct:
if isInlineMarkupStart(p, "***"):
var n = newRstNode(rnTripleEmphasis)
parseUntil(p, n, "***", true)
add(father, n)
- elif isInlineMarkupStart(p, "**"):
+ elif isInlineMarkupStart(p, "**"):
var n = newRstNode(rnStrongEmphasis)
parseUntil(p, n, "**", true)
add(father, n)
- elif isInlineMarkupStart(p, "*"):
+ elif isInlineMarkupStart(p, "*"):
var n = newRstNode(rnEmphasis)
parseUntil(p, n, "*", true)
add(father, n)
@@ -777,12 +777,12 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
var n = newRstNode(rnInlineLiteral)
parseUntil(p, n, "``", false)
add(father, n)
- elif isInlineMarkupStart(p, "`"):
+ elif isInlineMarkupStart(p, "`"):
var n = newRstNode(rnInterpretedText)
parseUntil(p, n, "`", true)
n = parsePostfix(p, n)
add(father, n)
- elif isInlineMarkupStart(p, "|"):
+ elif isInlineMarkupStart(p, "|"):
var n = newRstNode(rnSubstitutionReferences)
parseUntil(p, n, "|", false)
add(father, n)
@@ -800,7 +800,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
add(father, n)
return
parseUrl(p, father)
- of tkAdornment, tkOther, tkWhite:
+ of tkAdornment, tkOther, tkWhite:
if roSupportSmilies in p.s.options:
let n = parseSmiley(p)
if n != nil:
@@ -809,75 +809,75 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
add(father, newLeaf(p))
inc(p.idx)
else: discard
-
-proc getDirective(p: var TRstParser): string =
- if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
+
+proc getDirective(p: var TRstParser): string =
+ if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
var j = p.idx
inc(p.idx)
result = p.tok[p.idx].symbol
inc(p.idx)
- while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}:
- if p.tok[p.idx].symbol == "::": break
+ while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}:
+ if p.tok[p.idx].symbol == "::": break
add(result, p.tok[p.idx].symbol)
inc(p.idx)
if p.tok[p.idx].kind == tkWhite: inc(p.idx)
- if p.tok[p.idx].symbol == "::":
+ if p.tok[p.idx].symbol == "::":
inc(p.idx)
if (p.tok[p.idx].kind == tkWhite): inc(p.idx)
- else:
+ else:
p.idx = j # set back
result = "" # error
- else:
+ else:
result = ""
-
-proc parseComment(p: var TRstParser): PRstNode =
+
+proc parseComment(p: var TRstParser): PRstNode =
case p.tok[p.idx].kind
- of tkIndent, tkEof:
- if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
+ of tkIndent, tkEof:
+ if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
inc(p.idx) # empty comment
- else:
+ else:
var indent = p.tok[p.idx].ival
- while true:
+ while true:
case p.tok[p.idx].kind
- of tkEof:
- break
- of tkIndent:
- if (p.tok[p.idx].ival < indent): break
- else:
+ of tkEof:
+ break
+ of tkIndent:
+ if (p.tok[p.idx].ival < indent): break
+ else:
discard
inc(p.idx)
else:
while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx)
result = nil
-type
+type
TDirKind = enum # must be ordered alphabetically!
dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
-const
+const
DirIds: array[0..12, string] = ["", "author", "authors", "code",
"code-block", "container", "contents", "figure", "image", "include",
"index", "raw", "title"]
-proc getDirKind(s: string): TDirKind =
+proc getDirKind(s: string): TDirKind =
let i = find(DirIds, s)
if i >= 0: result = TDirKind(i)
else: result = dkNone
-
-proc parseLine(p: var TRstParser, father: PRstNode) =
- while true:
+
+proc parseLine(p: var TRstParser, father: PRstNode) =
+ while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
- else: break
+ else: break
-proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
- while true:
+proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
+ while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
-
-proc parseSection(p: var TRstParser, result: PRstNode)
+
+proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
proc parseField(p: var TRstParser): PRstNode =
## Returns a parsed rnField node.
##
@@ -888,9 +888,9 @@ proc parseField(p: var TRstParser): PRstNode =
parseUntil(p, fieldname, ":", false)
var fieldbody = newRstNode(rnFieldBody)
if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
- if p.tok[p.idx].kind == tkIndent:
+ if p.tok[p.idx].kind == tkIndent:
var indent = p.tok[p.idx].ival
- if indent > col:
+ if indent > col:
pushInd(p, indent)
parseSection(p, fieldbody)
popInd(p)
@@ -909,14 +909,14 @@ proc parseFields(p: var TRstParser): PRstNode =
var col = if atStart: p.tok[p.idx].col else: p.tok[p.idx].ival
result = newRstNode(rnFieldList)
if not atStart: inc(p.idx)
- while true:
+ while true:
add(result, parseField(p))
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
- (p.tok[p.idx + 1].symbol == ":"):
+ (p.tok[p.idx + 1].symbol == ":"):
inc(p.idx)
- else:
- break
-
+ else:
+ break
+
proc getFieldValue*(n: PRstNode): string =
## Returns the value of a specific ``rnField`` node.
##
@@ -929,122 +929,122 @@ proc getFieldValue*(n: PRstNode): string =
assert n.sons[1].kind == rnFieldBody
result = addNodes(n.sons[1]).strip
-proc getFieldValue(n: PRstNode, fieldname: string): string =
+proc getFieldValue(n: PRstNode, fieldname: string): string =
result = ""
- if n.sons[1] == nil: return
- if (n.sons[1].kind != rnFieldList):
+ if n.sons[1] == nil: return
+ if (n.sons[1].kind != rnFieldList):
#InternalError("getFieldValue (2): " & $n.sons[1].kind)
# We don't like internal errors here anymore as that would break the forum!
return
- for i in countup(0, len(n.sons[1]) - 1):
+ for i in countup(0, len(n.sons[1]) - 1):
var f = n.sons[1].sons[i]
- if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
+ if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
result = addNodes(f.sons[1])
if result == "": result = "\x01\x01" # indicates that the field exists
- return
+ return
-proc getArgument(n: PRstNode): string =
+proc getArgument(n: PRstNode): string =
if n.sons[0] == nil: result = ""
else: result = addNodes(n.sons[0])
-
-proc parseDotDot(p: var TRstParser): PRstNode
-proc parseLiteralBlock(p: var TRstParser): PRstNode =
+
+proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
+proc parseLiteralBlock(p: var TRstParser): PRstNode =
result = newRstNode(rnLiteralBlock)
var n = newRstNode(rnLeaf, "")
- if p.tok[p.idx].kind == tkIndent:
+ if p.tok[p.idx].kind == tkIndent:
var indent = p.tok[p.idx].ival
inc(p.idx)
- while true:
+ while true:
case p.tok[p.idx].kind
- of tkEof:
- break
- of tkIndent:
- if (p.tok[p.idx].ival < indent):
- break
- else:
+ of tkEof:
+ break
+ of tkIndent:
+ if (p.tok[p.idx].ival < indent):
+ break
+ else:
add(n.text, "\n")
add(n.text, spaces(p.tok[p.idx].ival - indent))
inc(p.idx)
- else:
+ else:
add(n.text, p.tok[p.idx].symbol)
inc(p.idx)
- else:
- while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+ else:
+ while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
add(n.text, p.tok[p.idx].symbol)
inc(p.idx)
add(result, n)
-proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
- if map[c] == 0:
+proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
+ if map[c] == 0:
inc(lvl)
map[c] = lvl
result = map[c]
-proc tokenAfterNewline(p: TRstParser): int =
+proc tokenAfterNewline(p: TRstParser): int =
result = p.idx
- while true:
+ while true:
case p.tok[result].kind
- of tkEof:
- break
- of tkIndent:
+ of tkEof:
+ break
+ of tkIndent:
inc(result)
- break
+ break
else: inc(result)
-
-proc isLineBlock(p: TRstParser): bool =
+
+proc isLineBlock(p: TRstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
(p.tok[j].col > p.tok[p.idx].col)
-proc predNL(p: TRstParser): bool =
+proc predNL(p: TRstParser): bool =
result = true
if p.idx > 0:
result = p.tok[p.idx-1].kind == tkIndent and
p.tok[p.idx-1].ival == currInd(p)
-
-proc isDefList(p: TRstParser): bool =
+
+proc isDefList(p: TRstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col < p.tok[j].col) and
(p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
(p.tok[j - 2].symbol != "::")
-proc isOptionList(p: TRstParser): bool =
+proc isOptionList(p: TRstParser): bool =
result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
match(p, p.idx, "/w") or match(p, p.idx, "//w")
-proc whichSection(p: TRstParser): TRstNodeKind =
+proc whichSection(p: TRstParser): TRstNodeKind =
case p.tok[p.idx].kind
- of tkAdornment:
+ of tkAdornment:
if match(p, p.idx + 1, "ii"): result = rnTransition
elif match(p, p.idx + 1, " a"): result = rnTable
elif match(p, p.idx + 1, "i"): result = rnOverline
else: result = rnLeaf
- of tkPunct:
- if match(p, tokenAfterNewline(p), "ai"):
+ of tkPunct:
+ if match(p, tokenAfterNewline(p), "ai"):
result = rnHeadline
- elif p.tok[p.idx].symbol == "::":
+ elif p.tok[p.idx].symbol == "::":
result = rnLiteralBlock
elif predNL(p) and
((p.tok[p.idx].symbol == "+") or (p.tok[p.idx].symbol == "*") or
- (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite):
+ (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite):
result = rnBulletList
- elif (p.tok[p.idx].symbol == "|") and isLineBlock(p):
+ elif (p.tok[p.idx].symbol == "|") and isLineBlock(p):
result = rnLineBlock
- elif (p.tok[p.idx].symbol == "..") and predNL(p):
+ elif (p.tok[p.idx].symbol == "..") and predNL(p):
result = rnDirective
elif match(p, p.idx, ":w:") and predNL(p):
# (p.tok[p.idx].symbol == ":")
result = rnFieldList
- elif match(p, p.idx, "(e) "):
+ elif match(p, p.idx, "(e) "):
result = rnEnumList
- elif match(p, p.idx, "+a+"):
+ elif match(p, p.idx, "+a+"):
result = rnGridTable
rstMessage(p, meGridTableNotImplemented)
- elif isDefList(p):
+ elif isDefList(p):
result = rnDefList
- elif isOptionList(p):
+ elif isOptionList(p):
result = rnOptionList
- else:
+ else:
result = rnParagraph
of tkWord, tkOther, tkWhite:
if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline
@@ -1052,58 +1052,58 @@ proc whichSection(p: TRstParser): TRstNodeKind =
elif isDefList(p): result = rnDefList
else: result = rnParagraph
else: result = rnLeaf
-
-proc parseLineBlock(p: var TRstParser): PRstNode =
+
+proc parseLineBlock(p: var TRstParser): PRstNode =
result = nil
- if p.tok[p.idx + 1].kind == tkWhite:
+ if p.tok[p.idx + 1].kind == tkWhite:
var col = p.tok[p.idx].col
result = newRstNode(rnLineBlock)
pushInd(p, p.tok[p.idx + 2].col)
inc(p.idx, 2)
- while true:
+ while true:
var item = newRstNode(rnLineBlockItem)
parseSection(p, item)
add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
(p.tok[p.idx + 1].symbol == "|") and
- (p.tok[p.idx + 2].kind == tkWhite):
+ (p.tok[p.idx + 2].kind == tkWhite):
inc(p.idx, 3)
- else:
- break
+ else:
+ break
popInd(p)
-proc parseParagraph(p: var TRstParser, result: PRstNode) =
- while true:
+proc parseParagraph(p: var TRstParser, result: PRstNode) =
+ while true:
case p.tok[p.idx].kind
- of tkIndent:
- if p.tok[p.idx + 1].kind == tkIndent:
+ of tkIndent:
+ if p.tok[p.idx + 1].kind == tkIndent:
inc(p.idx)
- break
- elif (p.tok[p.idx].ival == currInd(p)):
+ break
+ elif (p.tok[p.idx].ival == currInd(p)):
inc(p.idx)
case whichSection(p)
- of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
+ of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
add(result, newRstNode(rnLeaf, " "))
- of rnLineBlock:
+ of rnLineBlock:
addIfNotNil(result, parseLineBlock(p))
- else: break
- else:
- break
- of tkPunct:
+ else: break
+ else:
+ break
+ of tkPunct:
if (p.tok[p.idx].symbol == "::") and
(p.tok[p.idx + 1].kind == tkIndent) and
- (currInd(p) < p.tok[p.idx + 1].ival):
+ (currInd(p) < p.tok[p.idx + 1].ival):
add(result, newRstNode(rnLeaf, ":"))
inc(p.idx) # skip '::'
add(result, parseLiteralBlock(p))
- break
- else:
+ break
+ else:
parseInline(p, result)
- of tkWhite, tkWord, tkAdornment, tkOther:
+ of tkWhite, tkWord, tkAdornment, tkOther:
parseInline(p, result)
else: break
-proc parseHeadline(p: var TRstParser): PRstNode =
+proc parseHeadline(p: var TRstParser): PRstNode =
result = newRstNode(rnHeadline)
parseUntilNewline(p, result)
assert(p.tok[p.idx].kind == tkIndent)
@@ -1112,31 +1112,31 @@ proc parseHeadline(p: var TRstParser): PRstNode =
inc(p.idx, 2)
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
-type
+type
TIntSeq = seq[int]
-proc tokEnd(p: TRstParser): int =
+proc tokEnd(p: TRstParser): int =
result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
-proc getColumns(p: var TRstParser, cols: var TIntSeq) =
+proc getColumns(p: var TRstParser, cols: var TIntSeq) =
var L = 0
- while true:
+ while true:
inc(L)
setLen(cols, L)
cols[L - 1] = tokEnd(p)
assert(p.tok[p.idx].kind == tkAdornment)
inc(p.idx)
- if p.tok[p.idx].kind != tkWhite: break
+ if p.tok[p.idx].kind != tkWhite: break
inc(p.idx)
- if p.tok[p.idx].kind != tkAdornment: break
- if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+ if p.tok[p.idx].kind != tkAdornment: break
+ if p.tok[p.idx].kind == tkIndent: inc(p.idx)
# last column has no limit:
cols[L - 1] = 32000
-proc parseDoc(p: var TRstParser): PRstNode
+proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
-proc parseSimpleTable(p: var TRstParser): PRstNode =
- var
+proc parseSimpleTable(p: var TRstParser): PRstNode =
+ var
cols: TIntSeq
row: seq[string]
i, last, line: int
@@ -1148,36 +1148,36 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
row = @[]
a = nil
c = p.tok[p.idx].symbol[0]
- while true:
- if p.tok[p.idx].kind == tkAdornment:
+ while true:
+ if p.tok[p.idx].kind == tkAdornment:
last = tokenAfterNewline(p)
- if p.tok[last].kind in {tkEof, tkIndent}:
+ if p.tok[last].kind in {tkEof, tkIndent}:
# skip last adornment line:
p.idx = last
- break
+ break
getColumns(p, cols)
setLen(row, len(cols))
- if a != nil:
+ if a != nil:
for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
- if p.tok[p.idx].kind == tkEof: break
+ if p.tok[p.idx].kind == tkEof: break
for j in countup(0, high(row)): row[j] = ""
# the following while loop iterates over the lines a single cell may span:
line = p.tok[p.idx].line
- while true:
+ while true:
i = 0
- while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
- if (tokEnd(p) <= cols[i]):
+ while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+ if (tokEnd(p) <= cols[i]):
add(row[i], p.tok[p.idx].symbol)
inc(p.idx)
- else:
+ else:
if p.tok[p.idx].kind == tkWhite: inc(p.idx)
inc(i)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
- if tokEnd(p) <= cols[0]: break
- if p.tok[p.idx].kind in {tkEof, tkAdornment}: break
+ if tokEnd(p) <= cols[0]: break
+ if p.tok[p.idx].kind in {tkEof, tkAdornment}: break
for j in countup(1, high(row)): add(row[j], '\x0A')
a = newRstNode(rnTableRow)
- for j in countup(0, high(row)):
+ for j in countup(0, high(row)):
initParser(q, p.s)
q.col = cols[j]
q.line = line - 1
@@ -1188,95 +1188,95 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
add(a, b)
add(result, a)
-proc parseTransition(p: var TRstParser): PRstNode =
+proc parseTransition(p: var TRstParser): PRstNode =
result = newRstNode(rnTransition)
inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-
-proc parseOverline(p: var TRstParser): PRstNode =
+
+proc parseOverline(p: var TRstParser): PRstNode =
var c = p.tok[p.idx].symbol[0]
inc(p.idx, 2)
result = newRstNode(rnOverline)
- while true:
+ while true:
parseUntilNewline(p, result)
- if p.tok[p.idx].kind == tkIndent:
+ if p.tok[p.idx].kind == tkIndent:
inc(p.idx)
- if p.tok[p.idx - 1].ival > currInd(p):
+ if p.tok[p.idx - 1].ival > currInd(p):
add(result, newRstNode(rnLeaf, " "))
- else:
- break
- else:
- break
+ else:
+ break
+ else:
+ break
result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c)
- if p.tok[p.idx].kind == tkAdornment:
+ if p.tok[p.idx].kind == tkAdornment:
inc(p.idx) # XXX: check?
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-
-proc parseBulletList(p: var TRstParser): PRstNode =
+
+proc parseBulletList(p: var TRstParser): PRstNode =
result = nil
- if p.tok[p.idx + 1].kind == tkWhite:
+ if p.tok[p.idx + 1].kind == tkWhite:
var bullet = p.tok[p.idx].symbol
var col = p.tok[p.idx].col
result = newRstNode(rnBulletList)
pushInd(p, p.tok[p.idx + 2].col)
inc(p.idx, 2)
- while true:
+ while true:
var item = newRstNode(rnBulletItem)
parseSection(p, item)
add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
(p.tok[p.idx + 1].symbol == bullet) and
- (p.tok[p.idx + 2].kind == tkWhite):
+ (p.tok[p.idx + 2].kind == tkWhite):
inc(p.idx, 3)
- else:
- break
+ else:
+ break
popInd(p)
-proc parseOptionList(p: var TRstParser): PRstNode =
+proc parseOptionList(p: var TRstParser): PRstNode =
result = newRstNode(rnOptionList)
- while true:
+ while true:
if isOptionList(p):
var a = newRstNode(rnOptionGroup)
var b = newRstNode(rnDescription)
var c = newRstNode(rnOptionListItem)
if match(p, p.idx, "//w"): inc(p.idx)
- while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
- if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
+ while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+ if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
inc(p.idx)
- break
+ break
add(a, newLeaf(p))
inc(p.idx)
var j = tokenAfterNewline(p)
if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
- (p.tok[j - 1].ival > currInd(p)):
+ (p.tok[j - 1].ival > currInd(p)):
pushInd(p, p.tok[j - 1].ival)
parseSection(p, b)
popInd(p)
- else:
+ else:
parseLine(p, b)
if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
add(c, a)
add(c, b)
add(result, c)
- else:
- break
-
-proc parseDefinitionList(p: var TRstParser): PRstNode =
+ else:
+ break
+
+proc parseDefinitionList(p: var TRstParser): PRstNode =
result = nil
var j = tokenAfterNewline(p) - 1
if (j >= 1) and (p.tok[j].kind == tkIndent) and
- (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
+ (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
var col = p.tok[p.idx].col
result = newRstNode(rnDefList)
- while true:
+ while true:
j = p.idx
var a = newRstNode(rnDefName)
parseLine(p, a)
if (p.tok[p.idx].kind == tkIndent) and
(p.tok[p.idx].ival > currInd(p)) and
(p.tok[p.idx + 1].symbol != "::") and
- not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
+ not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
pushInd(p, p.tok[p.idx].ival)
var b = newRstNode(rnDefBody)
parseSection(p, b)
@@ -1285,74 +1285,74 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
add(c, b)
add(result, c)
popInd(p)
- else:
+ else:
p.idx = j
- break
- if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
+ break
+ if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
inc(p.idx)
j = tokenAfterNewline(p) - 1
if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > col and
- p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
+ p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
discard
- else:
- break
+ else:
+ break
if len(result) == 0: result = nil
-
-proc parseEnumList(p: var TRstParser): PRstNode =
- const
+
+proc parseEnumList(p: var TRstParser): PRstNode =
+ const
wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
wildpos: array[0..2, int] = [1, 0, 0]
result = nil
var w = 0
- while w <= 2:
- if match(p, p.idx, wildcards[w]): break
+ while w <= 2:
+ if match(p, p.idx, wildcards[w]): break
inc(w)
- if w <= 2:
+ if w <= 2:
var col = p.tok[p.idx].col
result = newRstNode(rnEnumList)
inc(p.idx, wildpos[w] + 3)
var j = tokenAfterNewline(p)
- if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
+ if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
pushInd(p, p.tok[p.idx].col)
- while true:
+ while true:
var item = newRstNode(rnEnumItem)
parseSection(p, item)
add(result, item)
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
- match(p, p.idx + 1, wildcards[w]):
+ match(p, p.idx + 1, wildcards[w]):
inc(p.idx, wildpos[w] + 4)
- else:
- break
+ else:
+ break
popInd(p)
- else:
+ else:
dec(p.idx, wildpos[w] + 3)
result = nil
-proc sonKind(father: PRstNode, i: int): TRstNodeKind =
+proc sonKind(father: PRstNode, i: int): TRstNodeKind =
result = rnLeaf
if i < len(father): result = father.sons[i].kind
-
-proc parseSection(p: var TRstParser, result: PRstNode) =
- while true:
+
+proc parseSection(p: var TRstParser, result: PRstNode) =
+ while true:
var leave = false
assert(p.idx >= 0)
- while p.tok[p.idx].kind == tkIndent:
- if currInd(p) == p.tok[p.idx].ival:
+ while p.tok[p.idx].kind == tkIndent:
+ if currInd(p) == p.tok[p.idx].ival:
inc(p.idx)
- elif p.tok[p.idx].ival > currInd(p):
+ elif p.tok[p.idx].ival > currInd(p):
pushInd(p, p.tok[p.idx].ival)
var a = newRstNode(rnBlockQuote)
parseSection(p, a)
add(result, a)
popInd(p)
- else:
+ else:
leave = true
break
if leave or p.tok[p.idx].kind == tkEof: break
var a: PRstNode = nil
var k = whichSection(p)
case k
- of rnLiteralBlock:
+ of rnLiteralBlock:
inc(p.idx) # skip '::'
a = parseLiteralBlock(p)
of rnBulletList: a = parseBulletList(p)
@@ -1362,7 +1362,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
of rnLeaf: rstMessage(p, meNewSectionExpected)
of rnParagraph: discard
of rnDefList: a = parseDefinitionList(p)
- of rnFieldList:
+ of rnFieldList:
if p.idx > 0: dec(p.idx)
a = parseFields(p)
of rnTransition: a = parseTransition(p)
@@ -1373,35 +1373,35 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
else:
#InternalError("rst.parseSection()")
discard
- if a == nil and k != rnDirective:
+ if a == nil and k != rnDirective:
a = newRstNode(rnParagraph)
parseParagraph(p, a)
addIfNotNil(result, a)
- if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
+ if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
result.sons[0].kind = rnInner
-
-proc parseSectionWrapper(p: var TRstParser): PRstNode =
+
+proc parseSectionWrapper(p: var TRstParser): PRstNode =
result = newRstNode(rnInner)
parseSection(p, result)
- while (result.kind == rnInner) and (len(result) == 1):
+ while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0]
-
+
proc `$`(t: TToken): string =
result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
-proc parseDoc(p: var TRstParser): PRstNode =
+proc parseDoc(p: var TRstParser): PRstNode =
result = parseSectionWrapper(p)
- if p.tok[p.idx].kind != tkEof:
+ if p.tok[p.idx].kind != tkEof:
when false:
assert isAllocatedPtr(cast[pointer](p.tok))
for i in 0 .. high(p.tok):
- assert isNil(p.tok[i].symbol) or
+ assert isNil(p.tok[i].symbol) or
isAllocatedPtr(cast[pointer](p.tok[i].symbol))
echo "index: ", p.idx, " length: ", high(p.tok), "##",
p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1]
#assert isAllocatedPtr(cast[pointer](p.indentStack))
rstMessage(p, meGeneralParseError)
-
+
type
TDirFlag = enum
hasArg, hasOptions, argIsFile, argIsWord
@@ -1421,55 +1421,55 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
result = newRstNode(rnDirective)
var args: PRstNode = nil
var options: PRstNode = nil
- if hasArg in flags:
+ if hasArg in flags:
args = newRstNode(rnDirArg)
- if argIsFile in flags:
- while true:
+ if argIsFile in flags:
+ while true:
case p.tok[p.idx].kind
- of tkWord, tkOther, tkPunct, tkAdornment:
+ of tkWord, tkOther, tkPunct, tkAdornment:
add(args, newLeaf(p))
inc(p.idx)
- else: break
+ else: break
elif argIsWord in flags:
while p.tok[p.idx].kind == tkWhite: inc(p.idx)
- if p.tok[p.idx].kind == tkWord:
+ if p.tok[p.idx].kind == tkWord:
add(args, newLeaf(p))
inc(p.idx)
else:
args = nil
- else:
+ else:
parseLine(p, args)
add(result, args)
- if hasOptions in flags:
+ if hasOptions in flags:
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
- (p.tok[p.idx + 1].symbol == ":"):
+ (p.tok[p.idx + 1].symbol == ":"):
options = parseFields(p)
add(result, options)
-
-proc indFollows(p: TRstParser): bool =
+
+proc indFollows(p: TRstParser): bool =
result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
-
-proc parseDirective(p: var TRstParser, flags: TDirFlags,
- contentParser: TSectionParser): PRstNode =
+
+proc parseDirective(p: var TRstParser, flags: TDirFlags,
+ contentParser: TSectionParser): PRstNode =
## Returns a generic rnDirective tree.
##
## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
result = parseDirective(p, flags)
- if not isNil(contentParser) and indFollows(p):
+ if not isNil(contentParser) and indFollows(p):
pushInd(p, p.tok[p.idx].ival)
var content = contentParser(p)
popInd(p)
add(result, content)
- else:
+ else:
add(result, nil)
-proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
- if indFollows(p):
+proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
+ if indFollows(p):
pushInd(p, p.tok[p.idx].ival)
result = contentParser(p)
popInd(p)
-
-proc dirInclude(p: var TRstParser): PRstNode =
+
+proc dirInclude(p: var TRstParser): PRstNode =
#
#The following options are recognized:
#
@@ -1490,18 +1490,18 @@ proc dirInclude(p: var TRstParser): PRstNode =
var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
var filename = strip(addNodes(n.sons[0]))
var path = p.s.findFile(filename)
- if path == "":
+ if path == "":
rstMessage(p, meCannotOpenFile, filename)
- else:
+ else:
# XXX: error handling; recursive file inclusion!
- if getFieldValue(n, "literal") != "":
+ if getFieldValue(n, "literal") != "":
result = newRstNode(rnLiteralBlock)
add(result, newRstNode(rnLeaf, readFile(path)))
else:
var q: TRstParser
initParser(q, p.s)
q.filename = filename
- q.col += getTokens(readFile(path), false, q.tok)
+ q.col += getTokens(readFile(path), false, q.tok)
# workaround a GCC bug; more like the interior pointer bug?
#if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
# InternalError("Too many binary zeros in include file")
@@ -1526,7 +1526,7 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
## file.
result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
var filename = strip(getFieldValue(result, "file"))
- if filename != "":
+ if filename != "":
var path = p.s.findFile(filename)
if path == "": rstMessage(p, meCannotOpenFile, filename)
var n = newRstNode(rnLiteralBlock)
@@ -1548,49 +1548,49 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
result.kind = rnCodeBlock
-proc dirContainer(p: var TRstParser): PRstNode =
+proc dirContainer(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg}, parseSectionWrapper)
assert(result.kind == rnDirective)
assert(len(result) == 3)
result.kind = rnContainer
-proc dirImage(p: var TRstParser): PRstNode =
+proc dirImage(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
result.kind = rnImage
-proc dirFigure(p: var TRstParser): PRstNode =
- result = parseDirective(p, {hasOptions, hasArg, argIsFile},
+proc dirFigure(p: var TRstParser): PRstNode =
+ result = parseDirective(p, {hasOptions, hasArg, argIsFile},
parseSectionWrapper)
result.kind = rnFigure
-proc dirTitle(p: var TRstParser): PRstNode =
+proc dirTitle(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnTitle
-proc dirContents(p: var TRstParser): PRstNode =
+proc dirContents(p: var TRstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnContents
-proc dirIndex(p: var TRstParser): PRstNode =
+proc dirIndex(p: var TRstParser): PRstNode =
result = parseDirective(p, {}, parseSectionWrapper)
result.kind = rnIndex
proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
- contentParser: TSectionParser) =
+ contentParser: TSectionParser) =
var filename = getFieldValue(result, "file")
- if filename.len > 0:
+ if filename.len > 0:
var path = p.s.findFile(filename)
- if path.len == 0:
+ if path.len == 0:
rstMessage(p, meCannotOpenFile, filename)
- else:
+ else:
var f = readFile(path)
result = newRstNode(kind)
add(result, newRstNode(rnLeaf, f))
- else:
+ else:
result.kind = kind
add(result, parseDirBody(p, contentParser))
-proc dirRaw(p: var TRstParser): PRstNode =
+proc dirRaw(p: var TRstParser): PRstNode =
#
#The following options are recognized:
#
@@ -1603,19 +1603,19 @@ proc dirRaw(p: var TRstParser): PRstNode =
if result.sons[0] != nil:
if cmpIgnoreCase(result.sons[0].sons[0].text, "html") == 0:
dirRawAux(p, result, rnRawHtml, parseLiteralBlock)
- elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
+ elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
else:
rstMessage(p, meInvalidDirective, result.sons[0].sons[0].text)
else:
dirRawAux(p, result, rnRaw, parseSectionWrapper)
-proc parseDotDot(p: var TRstParser): PRstNode =
+proc parseDotDot(p: var TRstParser): PRstNode =
result = nil
var col = p.tok[p.idx].col
inc(p.idx)
var d = getDirective(p)
- if d != "":
+ if d != "":
pushInd(p, col)
case getDirKind(d)
of dkInclude: result = dirInclude(p)
@@ -1634,66 +1634,66 @@ proc parseDotDot(p: var TRstParser): PRstNode =
of dkIndex: result = dirIndex(p)
else: rstMessage(p, meInvalidDirective, d)
popInd(p)
- elif match(p, p.idx, " _"):
+ elif match(p, p.idx, " _"):
# hyperlink target:
inc(p.idx, 2)
var a = getReferenceName(p, ":")
if p.tok[p.idx].kind == tkWhite: inc(p.idx)
var b = untilEol(p)
setRef(p, rstnodeToRefname(a), b)
- elif match(p, p.idx, " |"):
+ elif match(p, p.idx, " |"):
# substitution definitions:
inc(p.idx, 2)
var a = getReferenceName(p, "|")
var b: PRstNode
if p.tok[p.idx].kind == tkWhite: inc(p.idx)
- if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
+ if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
inc(p.idx)
expect(p, "::")
b = untilEol(p)
- elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0:
+ elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0:
inc(p.idx)
b = dirImage(p)
- else:
+ else:
rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
setSub(p, addNodes(a), b)
- elif match(p, p.idx, " ["):
+ elif match(p, p.idx, " ["):
# footnotes, citations
inc(p.idx, 2)
var a = getReferenceName(p, "]")
if p.tok[p.idx].kind == tkWhite: inc(p.idx)
var b = untilEol(p)
setRef(p, rstnodeToRefname(a), b)
- else:
+ else:
result = parseComment(p)
-
-proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
+
+proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
result = n
- if n == nil: return
+ if n == nil: return
case n.kind
- of rnSubstitutionReferences:
+ of rnSubstitutionReferences:
var x = findSub(p, n)
- if x >= 0:
+ if x >= 0:
result = p.s.subs[x].value
- else:
+ else:
var key = addNodes(n)
var e = getEnv(key)
if e != "": result = newRstNode(rnLeaf, e)
else: rstMessage(p, mwUnknownSubstitution, key)
- of rnRef:
+ of rnRef:
var y = findRef(p, rstnodeToRefname(n))
- if y != nil:
+ if y != nil:
result = newRstNode(rnHyperlink)
n.kind = rnInner
add(result, n)
add(result, y)
- of rnLeaf:
+ of rnLeaf:
discard
- of rnContents:
+ of rnContents:
p.hasToc = true
- else:
+ else:
for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
-
+
proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool,
options: TRstParseOptions,
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 614001d76d..c3956ab8b5 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -30,7 +30,7 @@ type
rnField, # a field item
rnFieldName, # consisting of a field name ...
rnFieldBody, # ... and a field body
- rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
+ rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
rnLineBlock, # the | thingie
rnLineBlockItem, # sons of the | thing
@@ -50,7 +50,7 @@ type
# * `file#id '_
rnSubstitutionDef, # a definition of a substitution
rnGeneralRole, # Inline markup:
- rnSub, rnSup, rnIdx,
+ rnSub, rnSup, rnIdx,
rnEmphasis, # "*"
rnStrongEmphasis, # "**"
rnTripleEmphasis, # "***"
@@ -71,25 +71,25 @@ type
level*: int ## valid for some node kinds
sons*: TRstNodeSeq ## the node's sons
-proc len*(n: PRstNode): int =
+proc len*(n: PRstNode): int =
result = len(n.sons)
-proc newRstNode*(kind: TRstNodeKind): PRstNode =
+proc newRstNode*(kind: TRstNodeKind): PRstNode =
new(result)
result.sons = @[]
result.kind = kind
-proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
+proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
result = newRstNode(kind)
result.text = s
-proc lastSon*(n: PRstNode): PRstNode =
+proc lastSon*(n: PRstNode): PRstNode =
result = n.sons[len(n.sons)-1]
proc add*(father, son: PRstNode) =
add(father.sons, son)
-proc addIfNotNil*(father, son: PRstNode) =
+proc addIfNotNil*(father, son: PRstNode) =
if son != nil: add(father, son)
@@ -98,26 +98,27 @@ type
indent: int
verbatim: int
-proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string)
+proc renderRstToRst(d: var TRenderContext, n: PRstNode,
+ result: var string) {.gcsafe.}
-proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
- for i in countup(0, len(n) - 1):
+proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
+ for i in countup(0, len(n) - 1):
renderRstToRst(d, n.sons[i], result)
-
+
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
# this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged...
- const
+ const
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
if n == nil: return
var ind = spaces(d.indent)
case n.kind
- of rnInner:
+ of rnInner:
renderRstSons(d, n, result)
of rnHeadline:
result.add("\n")
result.add(ind)
-
+
let oldLen = result.len
renderRstSons(d, n, result)
let headlineLen = result.len - oldLen
@@ -131,16 +132,16 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
var headline = ""
renderRstSons(d, n, headline)
-
+
let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
result.add(lvl)
result.add("\n")
result.add(headline)
-
+
result.add("\n")
result.add(ind)
result.add(lvl)
- of rnTransition:
+ of rnTransition:
result.add("\n\n")
result.add(ind)
result.add repeat('-', 78-d.indent)
@@ -149,11 +150,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("\n\n")
result.add(ind)
renderRstSons(d, n, result)
- of rnBulletItem:
+ of rnBulletItem:
inc(d.indent, 2)
var tmp = ""
renderRstSons(d, n, tmp)
- if tmp.len > 0:
+ if tmp.len > 0:
result.add("\n")
result.add(ind)
result.add("* ")
@@ -163,22 +164,22 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
inc(d.indent, 4)
var tmp = ""
renderRstSons(d, n, tmp)
- if tmp.len > 0:
+ if tmp.len > 0:
result.add("\n")
result.add(ind)
result.add("(#) ")
result.add(tmp)
dec(d.indent, 4)
- of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
- rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
+ of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
+ rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
renderRstSons(d, n, result)
- of rnDefName:
+ of rnDefName:
result.add("\n\n")
result.add(ind)
renderRstSons(d, n, result)
of rnDefBody:
inc(d.indent, 2)
- if n.sons[0].kind != rnBulletList:
+ if n.sons[0].kind != rnBulletList:
result.add("\n")
result.add(ind)
result.add(" ")
@@ -187,10 +188,10 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
of rnField:
var tmp = ""
renderRstToRst(d, n.sons[0], tmp)
-
+
var L = max(tmp.len + 3, 30)
inc(d.indent, L)
-
+
result.add "\n"
result.add ind
result.add ':'
@@ -198,9 +199,9 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add ':'
result.add spaces(L - tmp.len - 2)
renderRstToRst(d, n.sons[1], result)
-
+
dec(d.indent, L)
- of rnLineBlockItem:
+ of rnLineBlockItem:
result.add("\n")
result.add(ind)
result.add("| ")
@@ -209,11 +210,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
inc(d.indent, 2)
renderRstSons(d, n, result)
dec(d.indent, 2)
- of rnRef:
+ of rnRef:
result.add("`")
renderRstSons(d, n, result)
result.add("`_")
- of rnHyperlink:
+ of rnHyperlink:
result.add('`')
renderRstToRst(d, n.sons[0], result)
result.add(" <")
@@ -225,23 +226,23 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("`:")
renderRstToRst(d, n.sons[1],result)
result.add(':')
- of rnSub:
+ of rnSub:
result.add('`')
renderRstSons(d, n, result)
result.add("`:sub:")
- of rnSup:
+ of rnSup:
result.add('`')
renderRstSons(d, n, result)
result.add("`:sup:")
- of rnIdx:
+ of rnIdx:
result.add('`')
renderRstSons(d, n, result)
result.add("`:idx:")
- of rnEmphasis:
+ of rnEmphasis:
result.add("*")
renderRstSons(d, n, result)
result.add("*")
- of rnStrongEmphasis:
+ of rnStrongEmphasis:
result.add("**")
renderRstSons(d, n, result)
result.add("**")
@@ -249,11 +250,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("***")
renderRstSons(d, n, result)
result.add("***")
- of rnInterpretedText:
+ of rnInterpretedText:
result.add('`')
renderRstSons(d, n, result)
result.add('`')
- of rnInlineLiteral:
+ of rnInlineLiteral:
inc(d.verbatim)
result.add("``")
renderRstSons(d, n, result)
@@ -266,11 +267,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("\\\\") # XXX: escape more special characters!
else:
result.add(n.text)
- of rnIndex:
+ of rnIndex:
result.add("\n\n")
result.add(ind)
result.add(".. index::\n")
-
+
inc(d.indent, 3)
if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
dec(d.indent, 3)
@@ -280,7 +281,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add(".. contents::")
else:
result.add("Error: cannot render: " & $n.kind)
-
+
proc renderRstToRst*(n: PRstNode, result: var string) =
## renders `n` into its string representation and appends to `result`.
var d: TRenderContext
@@ -302,7 +303,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
proc renderRstToJson*(node: PRstNode): string =
## Writes the given RST node as JSON that is in the form
- ## ::
+ ## ::
## {
## "kind":string node.kind,
## "text":optional string node.text,
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index da05be9bfb..9e96d8a632 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -34,14 +34,14 @@ type
TOutputTarget* = enum ## which document type to generate
outHtml, # output is HTML
outLatex # output is Latex
-
- TTocEntry = object
+
+ TTocEntry = object
n*: PRstNode
refname*, header*: string
- TMetaEnum* = enum
+ TMetaEnum* = enum
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
-
+
TRstGenerator* = object of RootObj
target*: TOutputTarget
config*: StringTableRef
@@ -60,7 +60,7 @@ type
seenIndexTerms: Table[string, int] ## \
## Keeps count of same text index terms to generate different identifiers
## for hyperlinks. See renderIndexTerm proc for details.
-
+
PDoc = var TRstGenerator ## Alias to type less.
CodeBlockParams = object ## Stores code block params.
@@ -136,7 +136,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
g.currentSection = "Module " & fileParts.name
g.seenIndexTerms = initTable[string, int]()
g.msgHandler = msgHandler
-
+
let s = config["split.item.toc"]
if s != "": g.splitAfter = parseInt(s)
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
@@ -147,23 +147,23 @@ proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
## You previously need to add entries to the index with the `setIndexTerm()
## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
-
-proc addXmlChar(dest: var string, c: char) =
+
+proc addXmlChar(dest: var string, c: char) =
case c
of '&': add(dest, "&")
of '<': add(dest, "<")
of '>': add(dest, ">")
of '\"': add(dest, """)
else: add(dest, c)
-
-proc addRtfChar(dest: var string, c: char) =
+
+proc addRtfChar(dest: var string, c: char) =
case c
of '{': add(dest, "\\{")
of '}': add(dest, "\\}")
of '\\': add(dest, "\\\\")
else: add(dest, c)
-
-proc addTexChar(dest: var string, c: char) =
+
+proc addTexChar(dest: var string, c: char) =
case c
of '_': add(dest, "\\_")
of '{': add(dest, "\\symbol{123}")
@@ -183,54 +183,54 @@ proc addTexChar(dest: var string, c: char) =
var splitter*: string = ""
-proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
+proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
case target
of outHtml: addXmlChar(dest, c)
of outLatex: addTexChar(dest, c)
-
-proc nextSplitPoint*(s: string, start: int): int =
+
+proc nextSplitPoint*(s: string, start: int): int =
result = start
- while result < len(s) + 0:
+ while result < len(s) + 0:
case s[result]
- of '_': return
- of 'a'..'z':
- if result + 1 < len(s) + 0:
- if s[result + 1] in {'A'..'Z'}: return
+ of '_': return
+ of 'a'..'z':
+ if result + 1 < len(s) + 0:
+ if s[result + 1] in {'A'..'Z'}: return
else: discard
inc(result)
dec(result) # last valid index
-
-proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
+
+proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
result = ""
- if splitAfter >= 0:
+ if splitAfter >= 0:
var partLen = 0
var j = 0
- while j < len(s):
+ while j < len(s):
var k = nextSplitPoint(s, j)
- if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
+ if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
partLen = 0
add(result, splitter)
for i in countup(j, k): escChar(target, result, s[i])
inc(partLen, k - j + 1)
j = k + 1
- else:
+ else:
for i in countup(0, len(s) - 1): escChar(target, result, s[i])
proc disp(target: TOutputTarget, xml, tex: string): string =
- if target != outLatex: result = xml
+ if target != outLatex: result = xml
else: result = tex
-
-proc dispF(target: TOutputTarget, xml, tex: string,
- args: varargs[string]): string =
- if target != outLatex: result = xml % args
+
+proc dispF(target: TOutputTarget, xml, tex: string,
+ args: varargs[string]): string =
+ if target != outLatex: result = xml % args
else: result = tex % args
-
-proc dispA(target: TOutputTarget, dest: var string,
+
+proc dispA(target: TOutputTarget, dest: var string,
xml, tex: string, args: varargs[string]) =
if target != outLatex: addf(dest, xml, args)
else: addf(dest, tex, args)
-
+
proc `or`(x, y: string): string {.inline.} =
result = if x.isNil: y else: x
@@ -248,7 +248,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
## renderRstToOut(gen, rst, generatedHTML)
## echo generatedHTML
-proc renderAux(d: PDoc, n: PRstNode, result: var string) =
+proc renderAux(d: PDoc, n: PRstNode, result: var string) =
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
@@ -347,7 +347,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
var term = ""
renderAux(d, n, term)
setIndexTerm(d, id, term, d.currentSection)
- dispA(d.target, result, "$2", "$2\\label{$1}",
+ dispA(d.target, result, "$2", "$2\\label{$1}",
[id, term])
type
@@ -656,7 +656,7 @@ proc mergeIndexes*(dir: string): string =
result.add("API symbols
\n")
result.add(generateSymbolIndex(symbols))
-
+
# ----------------------------------------------------------------------------
proc stripTOCHTML(s: string): string =
@@ -677,7 +677,7 @@ proc stripTOCHTML(s: string): string =
result.delete(first, last)
first = result.find('<', first)
-proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
+proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
var tmp = ""
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
d.currentSection = tmp
@@ -700,9 +700,9 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
"id=\"$2\" href=\"#$2\">$3", "\\rsth$4{$3}\\label{$2}\n",
[$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
else:
- dispA(d.target, result, "\n$3",
+ dispA(d.target, result, "\n$3",
"\\rsth$4{$3}\\label{$2}\n", [
- $n.level, refname, tmp,
+ $n.level, refname, tmp,
$chr(n.level - 1 + ord('A'))])
# Generate index entry using spaces to indicate TOC level for the output HTML.
@@ -710,7 +710,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
setIndexTerm(d, refname, tmp.stripTOCHTML,
spaces(max(0, n.level)) & tmp)
-proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
+proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
if d.meta[metaTitle].len == 0:
for i in countup(0, len(n)-1):
renderRstToOut(d, n.sons[i], d.meta[metaTitle])
@@ -723,14 +723,14 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
var tmp = ""
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
d.currentSection = tmp
- dispA(d.target, result, "$3",
+ dispA(d.target, result, "$3",
"\\rstov$4{$3}\\label{$2}\n", [$n.level,
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
-
-proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
+
+proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
dispA(d.target, result,
- "$2\n",
+ "$2\n",
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
@@ -759,33 +759,33 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
var options = ""
var s = getFieldValue(n, "scale")
if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
-
+
s = getFieldValue(n, "height")
if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
-
+
s = getFieldValue(n, "width")
if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
-
+
s = getFieldValue(n, "alt")
if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
-
+
s = getFieldValue(n, "align")
if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
-
+
if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
let arg = getArgument(n)
if arg.valid:
- dispA(d.target, result, "
", "\\includegraphics$2{$1}",
+ dispA(d.target, result, "
", "\\includegraphics$2{$1}",
[arg, options])
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
-
+
proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
dispA(d.target, result,
- """
""",
"\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
-
+
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
## Parses useful fields which can appear before a code block.
##
@@ -880,11 +880,11 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
else:
var g: TGeneralTokenizer
initGeneralTokenizer(g, m.text)
- while true:
+ while true:
getNextToken(g, params.lang)
case g.kind
- of gtEof: break
- of gtNone, gtWhitespace:
+ of gtEof: break
+ of gtNone, gtWhitespace:
add(result, substr(m.text, g.start, g.length + g.start - 1))
else:
dispA(d.target, result, "$1", "\\span$2{$1}", [
@@ -893,36 +893,36 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
deinitGeneralTokenizer(g)
dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
-proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
+proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
var tmp = ""
renderRstToOut(d, n.sons[2], tmp)
var arg = strip(getArgument(n))
- if arg == "":
+ if arg == "":
dispA(d.target, result, "$1
", "$1", [tmp])
else:
dispA(d.target, result, "$2
", "$2", [arg, tmp])
-
-proc texColumns(n: PRstNode): string =
+
+proc texColumns(n: PRstNode): string =
result = ""
for i in countup(1, len(n)): add(result, "|X")
-
-proc renderField(d: PDoc, n: PRstNode, result: var string) =
+
+proc renderField(d: PDoc, n: PRstNode, result: var string) =
var b = false
- if d.target == outLatex:
+ if d.target == outLatex:
var fieldname = addNodes(n.sons[0])
var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
- if cmpIgnoreStyle(fieldname, "author") == 0 or
+ if cmpIgnoreStyle(fieldname, "author") == 0 or
cmpIgnoreStyle(fieldname, "authors") == 0:
if d.meta[metaAuthor].len == 0:
d.meta[metaAuthor] = fieldval
b = true
- elif cmpIgnoreStyle(fieldname, "version") == 0:
+ elif cmpIgnoreStyle(fieldname, "version") == 0:
if d.meta[metaVersion].len == 0:
d.meta[metaVersion] = fieldval
b = true
if not b:
renderAux(d, n, "$1
\n", "$1", result)
-
+
proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
if n == nil: return
case n.kind
@@ -947,54 +947,54 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
of rnDefBody: renderAux(d, n, "$1\n", "$1\n", result)
of rnFieldList:
var tmp = ""
- for i in countup(0, len(n) - 1):
+ for i in countup(0, len(n) - 1):
renderRstToOut(d, n.sons[i], tmp)
- if tmp.len != 0:
+ if tmp.len != 0:
dispA(d.target, result,
"" &
"" &
- "" &
+ "" &
"$1" &
- "
",
- "\\begin{description}$1\\end{description}\n",
+ "",
+ "\\begin{description}$1\\end{description}\n",
[tmp])
of rnField: renderField(d, n, result)
- of rnFieldName:
+ of rnFieldName:
renderAux(d, n, "$1: | ",
"\\item[$1:]", result)
- of rnFieldBody:
+ of rnFieldBody:
renderAux(d, n, "$1 | ", " $1\n", result)
- of rnIndex:
+ of rnIndex:
renderRstToOut(d, n.sons[2], result)
- of rnOptionList:
- renderAux(d, n, "",
+ of rnOptionList:
+ renderAux(d, n, "",
"\\begin{description}\n$1\\end{description}\n", result)
- of rnOptionListItem:
+ of rnOptionListItem:
renderAux(d, n, "$1
\n", "$1", result)
- of rnOptionGroup:
+ of rnOptionGroup:
renderAux(d, n, "$1 | ", "\\item[$1]", result)
- of rnDescription:
+ of rnDescription:
renderAux(d, n, "$1 | \n", " $1\n", result)
- of rnOption, rnOptionString, rnOptionArgument:
+ of rnOption, rnOptionString, rnOptionArgument:
doAssert false, "renderRstToOut"
of rnLiteralBlock:
- renderAux(d, n, "$1
\n",
+ renderAux(d, n, "$1
\n",
"\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
- of rnQuotedLiteralBlock:
+ of rnQuotedLiteralBlock:
doAssert false, "renderRstToOut"
- of rnLineBlock:
+ of rnLineBlock:
renderAux(d, n, "$1
", "$1\n\n", result)
- of rnLineBlockItem:
+ of rnLineBlockItem:
renderAux(d, n, "$1
", "$1\\\\\n", result)
- of rnBlockQuote:
- renderAux(d, n, "$1
\n",
+ of rnBlockQuote:
+ renderAux(d, n, "$1
\n",
"\\begin{quote}$1\\end{quote}\n", result)
- of rnTable, rnGridTable:
- renderAux(d, n,
- "",
+ of rnTable, rnGridTable:
+ renderAux(d, n,
+ "",
"\\begin{table}\\begin{rsttab}{" &
texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
- of rnTableRow:
+ of rnTableRow:
if len(n) >= 1:
if d.target == outLatex:
#var tmp = ""
@@ -1007,25 +1007,25 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
result.add("")
renderAux(d, n, result)
result.add("
\n")
- of rnTableDataCell:
+ of rnTableDataCell:
renderAux(d, n, "$1 | ", "$1", result)
- of rnTableHeaderCell:
+ of rnTableHeaderCell:
renderAux(d, n, "$1 | ", "\\textbf{$1}", result)
- of rnLabel:
+ of rnLabel:
doAssert false, "renderRstToOut" # used for footnotes and other
- of rnFootnote:
+ of rnFootnote:
doAssert false, "renderRstToOut" # a footnote
- of rnCitation:
+ of rnCitation:
doAssert false, "renderRstToOut" # similar to footnote
- of rnRef:
+ of rnRef:
var tmp = ""
renderAux(d, n, tmp)
dispA(d.target, result,
"$1",
"$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
- of rnStandaloneHyperlink:
- renderAux(d, n,
- "$1",
+ of rnStandaloneHyperlink:
+ renderAux(d, n,
+ "$1",
"\\href{$1}{$1}", result)
of rnHyperlink:
var tmp0 = ""
@@ -1042,11 +1042,11 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
of rnRawLatex:
if d.target == outLatex:
result.add addNodes(lastSon(n))
-
+
of rnImage, rnFigure: renderImage(d, n, result)
of rnCodeBlock: renderCodeBlock(d, n, result)
of rnContainer: renderContainer(d, n, result)
- of rnSubstitutionReferences, rnSubstitutionDef:
+ of rnSubstitutionReferences, rnSubstitutionDef:
renderAux(d, n, "|$1|", "|$1|", result)
of rnDirective:
renderAux(d, n, "", "", result)
@@ -1063,15 +1063,15 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
of rnStrongEmphasis:
renderAux(d, n, "$1", "\\textbf{$1}", result)
of rnTripleEmphasis:
- renderAux(d, n, "$1",
+ renderAux(d, n, "$1",
"\\textbf{emph{$1}}", result)
of rnInterpretedText:
renderAux(d, n, "$1", "\\emph{$1}", result)
of rnIdx:
renderIndexTerm(d, n, result)
- of rnInlineLiteral:
- renderAux(d, n,
- "$1",
+ of rnInlineLiteral:
+ renderAux(d, n,
+ "$1",
"\\texttt{$1}", result)
of rnSmiley: renderSmiley(d, n, result)
of rnLeaf: result.add(esc(d.target, n.text))
@@ -1082,55 +1082,55 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
# -----------------------------------------------------------------------------
-proc getVarIdx(varnames: openArray[string], id: string): int =
- for i in countup(0, high(varnames)):
- if cmpIgnoreStyle(varnames[i], id) == 0:
+proc getVarIdx(varnames: openArray[string], id: string): int =
+ for i in countup(0, high(varnames)):
+ if cmpIgnoreStyle(varnames[i], id) == 0:
return i
result = -1
-proc formatNamedVars*(frmt: string, varnames: openArray[string],
- varvalues: openArray[string]): string =
+proc formatNamedVars*(frmt: string, varnames: openArray[string],
+ varvalues: openArray[string]): string =
var i = 0
var L = len(frmt)
result = ""
var num = 0
- while i < L:
- if frmt[i] == '$':
+ while i < L:
+ if frmt[i] == '$':
inc(i) # skip '$'
case frmt[i]
- of '#':
+ of '#':
add(result, varvalues[num])
inc(num)
inc(i)
- of '$':
+ of '$':
add(result, "$")
inc(i)
- of '0'..'9':
+ of '0'..'9':
var j = 0
- while true:
+ while true:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
- if i > L-1 or frmt[i] notin {'0'..'9'}: break
+ if i > L-1 or frmt[i] notin {'0'..'9'}: break
if j > high(varvalues) + 1:
raise newException(ValueError, "invalid index: " & $j)
num = j
add(result, varvalues[j - 1])
- of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
+ of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
var id = ""
- while true:
+ while true:
add(id, frmt[i])
inc(i)
- if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
+ if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
var idx = getVarIdx(varnames, id)
- if idx >= 0:
+ if idx >= 0:
add(result, varvalues[idx])
else:
raise newException(ValueError, "unknown substitution var: " & id)
- of '{':
+ of '{':
var id = ""
inc(i)
- while frmt[i] != '}':
- if frmt[i] == '\0':
+ while frmt[i] != '}':
+ if frmt[i] == '\0':
raise newException(ValueError, "'}' expected")
add(id, frmt[i])
inc(i)
@@ -1138,12 +1138,12 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
# search for the variable:
var idx = getVarIdx(varnames, id)
if idx >= 0: add(result, varvalues[idx])
- else:
+ else:
raise newException(ValueError, "unknown substitution var: " & id)
else:
raise newException(ValueError, "unknown substitution: $" & $frmt[i])
var start = i
- while i < L:
+ while i < L:
if frmt[i] != '$': inc(i)
else: break
if i-1 >= start: add(result, substr(frmt, start, i - 1))
@@ -1163,10 +1163,10 @@ proc defaultConfig*(): StringTableRef =
## pages, while this proc returns just the content for procs like
## ``rstToHtml`` to generate the bare minimum HTML.
result = newStringTable(modeStyleInsensitive)
-
+
template setConfigVar(key, val: expr) =
result[key] = val
-
+
# If you need to modify these values, it might be worth updating the template
# file in config/nimdoc.cfg.
setConfigVar("split.item.toc", "20")
@@ -1214,7 +1214,7 @@ $content
# ---------- forum ---------------------------------------------------------
-proc rstToHtml*(s: string, options: TRstParseOptions,
+proc rstToHtml*(s: string, options: TRstParseOptions,
config: StringTableRef): string =
## Converts an input rst string into embeddable HTML.
##
@@ -1236,13 +1236,13 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
## output you have to create your own ``TRstGenerator`` with
## ``initRstGenerator`` and related procs.
- proc myFindFile(filename: string): string =
+ proc myFindFile(filename: string): string =
# we don't find any files in online mode:
result = ""
const filen = "input"
var d: TRstGenerator
- initRstGenerator(d, outHtml, config, filen, options, myFindFile,
+ initRstGenerator(d, outHtml, config, filen, options, myFindFile,
rst.defaultMsgHandler)
var dummyHasToc = false
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
@@ -1251,5 +1251,6 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
when isMainModule:
- echo rstToHtml("*Hello* **world**!", {},
- newStringTable(modeStyleInsensitive))
+ assert rstToHtml("*Hello* **world**!", {},
+ newStringTable(modeStyleInsensitive)) ==
+ "Hello world!"
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 00b655a103..0c7b840904 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -95,10 +95,11 @@ type
header: "", final, pure.} = object ## dirent_t struct
d_ino*: Tino ## File serial number.
when defined(linux) or defined(macosx) or defined(bsd):
- d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
d_reclen*: cshort ## Length of this record. (not POSIX)
d_type*: int8 ## Type of file; not supported by all filesystem types.
## (not POSIX)
+ when defined(linux) or defined(bsd):
+ d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
d_name*: array [0..255, char] ## Name of entry.
Tflock* {.importc: "struct flock", final, pure,
@@ -1579,8 +1580,11 @@ else:
when defined(macosx):
# We can't use the NOSIGNAL flag in the ``send`` function, it has no effect
- var
+ # Instead we should use SO_NOSIGPIPE in setsockopt
+ const
MSG_NOSIGNAL* = 0'i32
+ var
+ SO_NOSIGPIPE* {.importc, header: "".}: cint
else:
var
MSG_NOSIGNAL* {.importc, header: "".}: cint
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
index 830e8a2076..710b2fa6ba 100644
--- a/lib/posix/termios.nim
+++ b/lib/posix/termios.nim
@@ -10,28 +10,25 @@
{.deadCodeElim: on.}
import posix
-type
+type
Speed* = cuint
Tcflag* = cuint
-const
+const
NCCS* = 32
-type
- Termios* = object {.importc: "struct termios", header: "", final, pure.}
- iflag*: Tcflag # input mode flags
- oflag*: Tcflag # output mode flags
- cflag*: Tcflag # control mode flags
- lflag*: Tcflag # local mode flags
- line*: cuchar # line discipline
- cc*: array[NCCS, cuchar] # control characters
- ispeed*: Speed # input speed
- ospeed*: Speed # output speed
-
+type
+ Termios* {.importc: "struct termios", header: "".} = object
+ c_iflag*: Tcflag # input mode flags
+ c_oflag*: Tcflag # output mode flags
+ c_cflag*: Tcflag # control mode flags
+ c_lflag*: Tcflag # local mode flags
+ c_line*: cuchar # line discipline
+ c_cc*: array[NCCS, cuchar] # control characters
-# cc characters
+# cc characters
-const
+const
VINTR* = 0
VQUIT* = 1
VERASE* = 2
@@ -50,9 +47,9 @@ const
VLNEXT* = 15
VEOL2* = 16
-# iflag bits
+# iflag bits
-const
+const
IGNBRK* = 1
BRKINT* = 2
IGNPAR* = 4
@@ -69,9 +66,9 @@ const
IMAXBEL* = 20000
IUTF8* = 40000
-# oflag bits
+# oflag bits
-const
+const
OPOST* = 1
OLCUC* = 2
ONLCR* = 4
@@ -104,9 +101,9 @@ const
VT1* = 40000
XTABS* = 14000
-# cflag bit meaning
+# cflag bit meaning
-const
+const
CBAUD* = 10017
B0* = 0
B50* = 1
@@ -158,9 +155,9 @@ const
CMSPAR* = 0o010000000000
CRTSCTS* = 0o020000000000
-# lflag bits
+# lflag bits
-const
+const
ISIG* = 1
ICANON* = 2
XCASE* = 4
@@ -178,87 +175,87 @@ const
IEXTEN* = 0o000000100000
EXTPROC* = 0o000000200000
-# tcflow() and TCXONC use these
+# tcflow() and TCXONC use these
-const
+const
TCOOFF* = 0
TCOON* = 1
TCIOFF* = 2
TCION* = 3
-# tcflush() and TCFLSH use these
+# tcflush() and TCFLSH use these
-const
+const
TCIFLUSH* = 0
TCOFLUSH* = 1
TCIOFLUSH* = 2
-# tcsetattr uses these
+# tcsetattr uses these
-const
+const
TCSANOW* = 0
TCSADRAIN* = 1
TCSAFLUSH* = 2
# Compare a character C to a value VAL from the `cc' array in a
-# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it.
+# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it.
-template cceq*(val, c: expr): expr =
+template cceq*(val, c: expr): expr =
c == val and val != POSIX_VDISABLE
-# Return the output baud rate stored in *TERMIOS_P.
+# Return the output baud rate stored in *TERMIOS_P.
-proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
+proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
header: "".}
-# Return the input baud rate stored in *TERMIOS_P.
+# Return the input baud rate stored in *TERMIOS_P.
-proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
+proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
header: "".}
-# Set the output baud rate stored in *TERMIOS_P to SPEED.
+# Set the output baud rate stored in *TERMIOS_P to SPEED.
proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
importc: "cfsetospeed", header: "".}
-# Set the input baud rate stored in *TERMIOS_P to SPEED.
+# Set the input baud rate stored in *TERMIOS_P to SPEED.
proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
importc: "cfsetispeed", header: "".}
-# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
+# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
importc: "cfsetspeed", header: "".}
-# Put the state of FD into *TERMIOS_P.
+# Put the state of FD into *TERMIOS_P.
proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
importc: "tcgetattr", header: "".}
# Set the state of FD to *TERMIOS_P.
-# Values for OPTIONAL_ACTIONS (TCSA*) are in .
+# Values for OPTIONAL_ACTIONS (TCSA*) are in .
proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
importc: "tcsetattr", header: "".}
-# Set *TERMIOS_P to indicate raw mode.
+# Set *TERMIOS_P to indicate raw mode.
-proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
+proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
header: "".}
-# Send zero bits on FD.
+# Send zero bits on FD.
-proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
+proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
header: "".}
# Wait for pending output to be written on FD.
#
# This function is a cancellation point and therefore not marked with
-# .
+# .
proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "".}
# Flush pending data on FD.
-# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in .
+# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in .
-proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
+proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
header: "".}
# Suspend or restart transmission on FD.
-# Values for ACTION (TC[IO]{OFF,ON}) are in .
+# Values for ACTION (TC[IO]{OFF,ON}) are in .
-proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
+proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
header: "".}
-# Get process group ID for session leader for controlling terminal FD.
+# Get process group ID for session leader for controlling terminal FD.
proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "".}
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index 8c61ce7df3..294c24741e 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
setupTask()
schedule()
-when isMainModule:
+when not defined(testing) and isMainModule:
var
a: TActorPool[int, void]
createActorPool(a)
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index a1ab7be136..f7ccb92348 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -24,7 +24,7 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
var y = order.ord - 1
result = (x xor y) - y
-proc reverse*[T](a: var openArray[T], first, last: int) =
+proc reverse*[T](a: var openArray[T], first, last: Natural) =
## reverses the array ``a[first..last]``.
var x = first
var y = last
@@ -37,11 +37,11 @@ proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`.
reverse(a, 0, a.high)
-proc reversed*[T](a: openArray[T], first, last: int): seq[T] =
+proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
## returns the reverse of the array `a[first..last]`.
result = newSeq[T](last - first + 1)
- var x = first
- var y = last
+ var x = first.int
+ var y = last.int
while x <= last:
result[x] = a[y]
dec(y)
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 8e0ac8d213..a4d7a16324 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -634,6 +634,93 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
+ proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+ flags = {SocketFlag.SafeDisconn}): Future[int] =
+ ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
+ ## at least be of that size. Returned future will complete once all the
+ ## data requested is read, a part of the data has been read, or the socket
+ ## has disconnected in which case the future will complete with a value of
+ ## ``0``.
+ ##
+ ## **Warning**: The ``Peek`` socket flag is not supported on Windows.
+
+
+ # Things to note:
+ # * When WSARecv completes immediately then ``bytesReceived`` is very
+ # unreliable.
+ # * Still need to implement message-oriented socket disconnection,
+ # '\0' in the message currently signifies a socket disconnect. Who
+ # knows what will happen when someone sends that to our socket.
+ verifyPresence(socket)
+ assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
+
+ var retFuture = newFuture[int]("recvInto")
+
+ #buf[] = '\0'
+ var dataBuf: TWSABuf
+ dataBuf.buf = buf
+ dataBuf.len = size
+
+ var bytesReceived: Dword
+ var flagsio = flags.toOSFlags().Dword
+ var ol = PCustomOverlapped()
+ GC_ref(ol)
+ ol.data = TCompletionData(fd: socket, cb:
+ proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+ if not retFuture.finished:
+ if errcode == OSErrorCode(-1):
+ if bytesCount == 0 and dataBuf.buf[0] == '\0':
+ retFuture.complete(0)
+ else:
+ retFuture.complete(bytesCount)
+ else:
+ if flags.isDisconnectionError(errcode):
+ retFuture.complete(0)
+ else:
+ retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+ if dataBuf.buf != nil:
+ dataBuf.buf = nil
+ )
+
+ let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
+ addr flagsio, cast[POVERLAPPED](ol), nil)
+ if ret == -1:
+ let err = osLastError()
+ if err.int32 != ERROR_IO_PENDING:
+ if dataBuf.buf != nil:
+ dataBuf.buf = nil
+ GC_unref(ol)
+ if flags.isDisconnectionError(err):
+ retFuture.complete(0)
+ else:
+ retFuture.fail(newException(OSError, osErrorMsg(err)))
+ elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
+ # We have to ensure that the buffer is empty because WSARecv will tell
+ # us immediately when it was disconnected, even when there is still
+ # data in the buffer.
+ # We want to give the user as much data as we can. So we only return
+ # the empty string (which signals a disconnection) when there is
+ # nothing left to read.
+ retFuture.complete(0)
+ # TODO: "For message-oriented sockets, where a zero byte message is often
+ # allowable, a failure with an error code of WSAEDISCON is used to
+ # indicate graceful closure."
+ # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
+ else:
+ # Request to read completed immediately.
+ # From my tests bytesReceived isn't reliable.
+ let realSize =
+ if bytesReceived == 0:
+ size
+ else:
+ bytesReceived
+ assert realSize <= size
+ retFuture.complete(realSize)
+ # We don't deallocate ``ol`` here because even though this completed
+ # immediately poll will still be notified about its completion and it will
+ # free ``ol``.
+ return retFuture
+
proc send*(socket: TAsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
## Sends ``data`` to ``socket``. The returned future will complete once all
@@ -841,6 +928,8 @@ else:
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false)
+ when defined(macosx):
+ result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result)
proc newAsyncRawSocket*(domain: Domain = AF_INET,
@@ -848,6 +937,8 @@ else:
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false)
+ when defined(macosx):
+ result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result)
proc closeSocket*(sock: TAsyncFD) =
@@ -959,7 +1050,6 @@ else:
result = true
let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
flags.toOSFlags())
- #echo("recv cb res: ", res)
if res < 0:
let lastError = osLastError()
if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
@@ -980,6 +1070,30 @@ else:
addRead(socket, cb)
return retFuture
+ proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+ flags = {SocketFlag.SafeDisconn}): Future[int] =
+ var retFuture = newFuture[int]("recvInto")
+
+ proc cb(sock: TAsyncFD): bool =
+ result = true
+ let res = recv(sock.SocketHandle, buf, size.cint,
+ flags.toOSFlags())
+ if res < 0:
+ let lastError = osLastError()
+ if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+ if flags.isDisconnectionError(lastError):
+ retFuture.complete(0)
+ else:
+ retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+ else:
+ result = false # We still want this callback to be called.
+ else:
+ retFuture.complete(res)
+ # TODO: The following causes a massive slowdown.
+ #if not cb(socket):
+ addRead(socket, cb)
+ return retFuture
+
proc send*(socket: TAsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send")
@@ -1273,7 +1387,7 @@ proc processBody(node, retFutureSym: NimNode,
else: discard
for i in 0 .. = socket.bufLen:
- let res = await socket.readIntoBuf(flags)
+ let res = socket.readIntoBuf(flags)
if res == 0:
- result = ""
- break
+ resString[].setLen(0)
+ return
case socket.buffer[socket.currPos]
of '\r':
@@ -353,24 +362,53 @@ proc recvLine*(socket: AsyncSocket,
socket.currPos.inc()
return
else:
- result.add socket.buffer[socket.currPos]
+ resString[].add socket.buffer[socket.currPos]
socket.currPos.inc()
else:
- result = ""
var c = ""
while true:
- c = await recv(socket, 1, flags)
+ let recvFut = recv(socket, 1, flags)
+ c = recvFut.read()
if c.len == 0:
- return ""
+ resString[].setLen(0)
+ return
if c == "\r":
- c = await recv(socket, 1, flags) # Skip \L
+ let recvFut = recv(socket, 1, flags) # Skip \L
+ c = recvFut.read()
assert c == "\L"
addNLIfEmpty()
return
elif c == "\L":
addNLIfEmpty()
return
- add(result.string, c)
+ resString[].add c
+
+proc recvLine*(socket: AsyncSocket,
+ flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
+ ## Reads a line of data from ``socket``. Returned future will complete once
+ ## a full line is read or an error occurs.
+ ##
+ ## If a full line is read ``\r\L`` is not
+ ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+ ## will be set to it.
+ ##
+ ## If the socket is disconnected, ``line`` will be set to ``""``.
+ ##
+ ## If the socket is disconnected in the middle of a line (before ``\r\L``
+ ## is read) then line will be set to ``""``.
+ ## The partial line **will be lost**.
+ ##
+ ## **Warning**: The ``Peek`` flag is not yet implemented.
+ ##
+ ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
+ ## uses ``\r\L`` to delimit a new line.
+ template addNLIfEmpty(): stmt =
+ if result.len == 0:
+ result.add("\c\L")
+ assert SocketFlag.Peek notin flags ## TODO:
+
+ result = ""
+ await socket.recvLineInto(addr result, flags)
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
## Marks ``socket`` as accepting connections.
@@ -458,7 +496,7 @@ proc isClosed*(socket: AsyncSocket): bool =
## Determines whether the socket has been closed.
return socket.closed
-when isMainModule:
+when not defined(testing) and isMainModule:
type
TestCases = enum
HighClient, LowClient, LowServer
@@ -500,11 +538,11 @@ when isMainModule:
proc (future: Future[void]) =
echo("Send")
client.close()
-
+
var f = accept(sock)
f.callback = onAccept
-
+
var f = accept(sock)
f.callback = onAccept
runForever()
-
+
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index 18ebed67b2..5a943dd05d 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -16,33 +16,33 @@ import times
## Vectors are implemented as direction vectors, ie. when transformed with a matrix
## the translation part of matrix is ignored. The coordinate system used is
## right handed, because its compatible with 2d coordinate system (rotation around
-## zaxis equals 2d rotation).
+## zaxis equals 2d rotation).
## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented
## for vectors and scalars.
##
##
## Quick start example:
-##
+##
## # Create a matrix which first rotates, then scales and at last translates
-##
+##
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
-##
+##
## # Create a 3d point at (100,150,200) and a vector (5,2,3)
-##
-## var pt:TPoint3d=point3d(100.0,150.0,200.0)
-##
+##
+## var pt:TPoint3d=point3d(100.0,150.0,200.0)
+##
## var vec:TVector3d=vector3d(5.0,2.0,3.0)
-##
-##
+##
+##
## pt &= m # transforms pt in place
-##
+##
## var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
-##
+##
## var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
-type
+type
TMatrix3d* =object
## Implements a row major 3d matrix, which means
## transformations are applied the order they are concatenated.
@@ -53,12 +53,12 @@ type
## [ tx ty tz tw ]
ax*,ay*,az*,aw*, bx*,by*,bz*,bw*, cx*,cy*,cz*,cw*, tx*,ty*,tz*,tw*:float
TPoint3d* = object
- ## Implements a non-homegeneous 2d point stored as
+ ## Implements a non-homegeneous 2d point stored as
## an `x` , `y` and `z` coordinate.
x*,y*,z*:float
- TVector3d* = object
- ## Implements a 3d **direction vector** stored as
- ## an `x` , `y` and `z` coordinate. Direction vector means,
+ TVector3d* = object
+ ## Implements a 3d **direction vector** stored as
+ ## an `x` , `y` and `z` coordinate. Direction vector means,
## that when transforming a vector with a matrix, the translational
## part of the matrix is ignored.
x*,y*,z*:float
@@ -67,7 +67,7 @@ type
# Some forward declarations
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
- ## Creates a new 4x4 3d transformation matrix.
+ ## Creates a new 4x4 3d transformation matrix.
## `ax` , `ay` , `az` is the local x axis.
## `bx` , `by` , `bz` is the local y axis.
## `cx` , `cy` , `cz` is the local z axis.
@@ -76,7 +76,7 @@ proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
## Returns a new 3d vector (`x`,`y`,`z`)
proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
## Returns a new 4d point (`x`,`y`,`z`)
-proc tryNormalize*(v:var TVector3d):bool
+proc tryNormalize*(v:var TVector3d):bool
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@@ -85,7 +85,7 @@ proc tryNormalize*(v:var TVector3d):bool
let
IDMATRIX*:TMatrix3d=matrix3d(
- 1.0,0.0,0.0,0.0,
+ 1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0)
@@ -114,20 +114,20 @@ proc safeArccos(v:float):float=
## due to rounding issues
return arccos(clamp(v,-1.0,1.0))
-template makeBinOpVector(s:expr)=
+template makeBinOpVector(s:expr)=
## implements binary operators + , - , * and / for vectors
- proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
+ proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
- proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
+ proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
- proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
+ proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
-
-template makeBinOpAssignVector(s:expr)=
+
+template makeBinOpAssignVector(s:expr)=
## implements inplace binary operators += , -= , /= and *= for vectors
- proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
+ proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
- proc s*(a:var TVector3d,b:float) {.inline.} =
+ proc s*(a:var TVector3d,b:float) {.inline.} =
s(a.x,b) ; s(a.y,b) ; s(a.z,b)
@@ -188,20 +188,20 @@ proc scale*(s:float):TMatrix3d {.noInit.} =
proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
## Returns a new scaling matrix using, `org` as scale origin.
- result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
+ result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
## Returns new a stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
-
+
proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
## Returns a new stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
## `org` is used as stretch origin.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
-
+
proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
## Returns a new translation matrix.
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
@@ -235,7 +235,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
uvomc=normax.x*normax.y*omc
uwomc=normax.x*normax.z*omc
vwomc=normax.y*normax.z*omc
-
+
result.setElements(
u2+(1.0-u2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
uvomc-wsi, v2+(1.0-v2)*cs, vwomc+usi, 0.0,
@@ -248,11 +248,11 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
# for how this is computed
-
+
var normax=axis
if not normax.tryNormalize: #simplifies matrix computation below a lot
raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-
+
let
u=normax.x
v=normax.y
@@ -272,7 +272,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
uvomc=normax.x*normax.y*omc
uwomc=normax.x*normax.z*omc
vwomc=normax.y*normax.z*omc
-
+
result.setElements(
u2+(v2+w2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
uvomc-wsi, v2+(u2+w2)*cs, vwomc+usi, 0.0,
@@ -305,7 +305,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
0,1,0,0,
s,0,c,0,
0,0,0,1)
-
+
proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
## Creates a matrix that rotates around the z-axis with `angle` radians,
## which is also called a 'yaw' matrix.
@@ -317,19 +317,19 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
-s,c,0,0,
0,0,1,0,
0,0,0,1)
-
+
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
- ## Checks if the transform is uniform, that is
+ ## Checks if the transform is uniform, that is
## perpendicular axes of equal length, which means (for example)
## it cannot transform a sphere into an ellipsoid.
- ## `tol` is used as tolerance for both equal length comparison
+ ## `tol` is used as tolerance for both equal length comparison
## and perpendicular comparison.
-
+
#dot product=0 means perpendicular coord. system, check xaxis vs yaxis and xaxis vs zaxis
if abs(m.ax*m.bx+m.ay*m.by+m.az*m.bz)<=tol and # x vs y
abs(m.ax*m.cx+m.ay*m.cy+m.az*m.cz)<=tol and #x vs z
abs(m.bx*m.cx+m.by*m.cy+m.bz*m.cz)<=tol: #y vs z
-
+
#subtract squared lengths of axes to check if uniform scaling:
let
sqxlen=(m.ax*m.ax+m.ay*m.ay+m.az*m.az)
@@ -340,16 +340,16 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
return false
-
+
proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
## and passes through origo. `planeperp` does not need to be normalized.
-
+
# https://en.wikipedia.org/wiki/Transformation_matrix
var n=planeperp
if not n.tryNormalize:
raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-
+
let
a=n.x
b=n.y
@@ -357,7 +357,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
ab=a*b
ac=a*c
bc=b*c
-
+
result.setElements(
1-2*a*a , -2*ab,-2*ac,0,
-2*ab , 1-2*b*b, -2*bc, 0,
@@ -376,7 +376,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
var n=planeperp
if not n.tryNormalize:
raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
-
+
let
a=n.x
b=n.y
@@ -390,7 +390,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
tx=org.x
ty=org.y
tz=org.z
-
+
result.setElements(
1-2*aa , -2*ab,-2*ac,0,
-2*ab , 1-2*bb, -2*bc, 0,
@@ -402,8 +402,8 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
proc determinant*(m:TMatrix3d):float=
## Computes the determinant of matrix `m`.
-
- # This computation is gotten from ratsimp(optimize(determinant(m)))
+
+ # This computation is gotten from ratsimp(optimize(determinant(m)))
# in maxima CAS
let
O1=m.cx*m.tw-m.cw*m.tx
@@ -423,10 +423,10 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
## Computes the inverse of matrix `m`. If the matrix
## determinant is zero, thus not invertible, a EDivByZero
## will be raised.
-
+
# this computation comes from optimize(invert(m)) in maxima CAS
-
- let
+
+ let
det=m.determinant
O2=m.cy*m.tw-m.cw*m.ty
O3=m.cz*m.tw-m.cw*m.tz
@@ -464,7 +464,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
## Checks if all elements of `m1`and `m2` is equal within
## a given tolerance `tol`.
- return
+ return
abs(m1.ax-m2.ax)<=tol and
abs(m1.ay-m2.ay)<=tol and
abs(m1.az-m2.az)<=tol and
@@ -486,11 +486,11 @@ proc `=~`*(m1,m2:TMatrix3d):bool=
## Checks if `m1` and `m2` is approximately equal, using a
## tolerance of 1e-6.
equals(m1,m2)
-
+
proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
## Returns the transpose of `m`
result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
-
+
proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
## Gets the local x axis of `m`
result.x=m.ax
@@ -509,26 +509,26 @@ proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
result.y=m.cy
result.z=m.cz
-
+
proc `$`*(m:TMatrix3d):string=
## String representation of `m`
- return rtos(m.ax) & "," & rtos(m.ay) & "," &rtos(m.az) & "," & rtos(m.aw) &
- "\n" & rtos(m.bx) & "," & rtos(m.by) & "," &rtos(m.bz) & "," & rtos(m.bw) &
- "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," &rtos(m.cz) & "," & rtos(m.cw) &
- "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," &rtos(m.tz) & "," & rtos(m.tw)
-
+ return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
+ "\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
+ "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
+ "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
+
proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
## Applies transformation `m` onto `x` , `y` , `z` , optionally
## using the translation part of the matrix.
- let
+ let
oldx=x
oldy=y
oldz=z
-
+
x=m.cx*oldz+m.bx*oldy+m.ax*oldx
y=m.cy*oldz+m.by*oldy+m.ay*oldx
z=m.cz*oldz+m.bz*oldy+m.az*oldx
-
+
if translate:
x+=m.tx
y+=m.ty
@@ -552,13 +552,13 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
## an arbitrary vector of the requested length is returned.
let fac=newlen/v.len
-
+
if newlen==0.0:
v.x=0.0
v.y=0.0
v.z=0.0
return
-
+
if fac==Inf or fac==NegInf:
#to short for float accuracy
#do as good as possible:
@@ -588,7 +588,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
## Concatenate vector `v` with a transformation matrix.
## Transforming a vector ignores the translational part
## of the matrix.
-
+
# | AX AY AZ AW |
# | X Y Z 1 | * | BX BY BZ BW |
# | CX CY CZ CW |
@@ -605,12 +605,12 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
## Applies transformation `m` onto `v` in place.
## Transforming a vector ignores the translational part
## of the matrix.
-
+
# | AX AY AZ AW |
# | X Y Z 1 | * | BX BY BZ BW |
# | CX CY CZ CW |
# | 0 0 0 1 |
-
+
let
newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
newy=m.cy*v.z+m.by*v.y+m.ay*v.x
@@ -620,38 +620,38 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
## Applies a normal direction transformation `m` onto `v` in place.
- ## The resulting vector is *not* normalized. Transforming a vector ignores the
- ## translational part of the matrix. If the matrix is not invertible
+ ## The resulting vector is *not* normalized. Transforming a vector ignores the
+ ## translational part of the matrix. If the matrix is not invertible
## (determinant=0), an EDivByZero will be raised.
# transforming a normal is done by transforming
# by the transpose of the inverse of the original matrix
-
+
# Major reason this simple function is here is that this function can be optimized in the future,
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=transpose(inverse(m))
-
+
proc transformInv*(v:var TVector3d,m:TMatrix3d)=
- ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
- ## the translational part of the matrix. Transforming a vector ignores the
+ ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
+ ## the translational part of the matrix. Transforming a vector ignores the
## translational part of the matrix.
## If the matrix is not invertible (determinant=0), an EDivByZero
## will be raised.
-
+
# Major reason this simple function is here is that this function can be optimized in the future,
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=m.inverse
-
+
proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
## Applies an inverse normal direction transformation `m` onto `v` in place.
- ## This is faster than creating an inverse
- ## matrix and transformNorm(...) it. Transforming a vector ignores the
+ ## This is faster than creating an inverse
+ ## matrix and transformNorm(...) it. Transforming a vector ignores the
## translational part of the matrix.
-
+
# see vector2d:s equivalent for a deeper look how/why this works
vec&=m.transpose
-proc tryNormalize*(v:var TVector3d):bool=
+proc tryNormalize*(v:var TVector3d):bool=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@@ -663,26 +663,26 @@ proc tryNormalize*(v:var TVector3d):bool=
v.x/=mag
v.y/=mag
v.z/=mag
-
+
return true
-proc normalize*(v:var TVector3d) {.inline.}=
+proc normalize*(v:var TVector3d) {.inline.}=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length, an EDivByZero will be raised.
if not tryNormalize(v):
raise newException(DivByZeroError,"Cannot normalize zero length vector")
proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
- ## Rotates `vec` in place, with `angle` radians over `axis`, which passes
+ ## Rotates `vec` in place, with `angle` radians over `axis`, which passes
## through origo.
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
# for how this is computed
-
+
var normax=axis
if not normax.tryNormalize:
raise newException(DivByZeroError,"Cannot rotate around zero length axis")
-
+
let
cs=cos(angle)
si=sin(angle)
@@ -694,11 +694,11 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
y=vec.y
z=vec.z
uxyzomc=(u*x+v*y+w*z)*omc
-
+
vec.x=u*uxyzomc+x*cs+(v*z-w*y)*si
vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
-
+
proc scale*(v:var TVector3d,s:float)=
## Scales the vector in place with factor `s`
v.x*=s
@@ -713,12 +713,12 @@ proc stretch*(v:var TVector3d,sx,sy,sz:float)=
proc mirror*(v:var TVector3d,planeperp:TVector3d)=
## Computes the mirrored vector of `v` over the plane
- ## that has `planeperp` as normal direction.
+ ## that has `planeperp` as normal direction.
## `planeperp` does not need to be normalized.
-
+
var n=planeperp
n.normalize
-
+
let
x=v.x
y=v.y
@@ -729,7 +729,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
ac=a*c
ab=a*b
bc=b*c
-
+
v.x= -2*(ac*z+ab*y+a*a*x)+x
v.y= -2*(bc*z+b*b*y+ab*x)+y
v.z= -2*(c*c*z+bc*y+ac*x)+z
@@ -740,7 +740,7 @@ proc `-` *(v:TVector3d):TVector3d=
result.x= -v.x
result.y= -v.y
result.z= -v.z
-
+
# declare templated binary operators
makeBinOpVector(`+`)
makeBinOpVector(`-`)
@@ -752,7 +752,7 @@ makeBinOpAssignVector(`*=`)
makeBinOpAssignVector(`/=`)
proc dot*(v1,v2:TVector3d):float {.inline.}=
- ## Computes the dot product of two vectors.
+ ## Computes the dot product of two vectors.
## Returns 0.0 if the vectors are perpendicular.
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
@@ -769,12 +769,12 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
## Checks if two vectors approximately equals with a tolerance.
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
-
+
proc `=~` *(v1,v2:TVector3d):bool=
- ## Checks if two vectors approximately equals with a
+ ## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(v1,v2)
-
+
proc angleTo*(v1,v2:TVector3d):float=
## Returns the smallest angle between v1 and v2,
## which is in range 0-PI
@@ -801,7 +801,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
ay=cross(norm,ax)
ay.normalize()
az=cross(ax,ay)
-
+
result.setElements(
ax.x,ax.y,ax.z,0.0,
ay.x,ay.y,ay.z,0.0,
@@ -811,20 +811,20 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version
- ## of the other is returned. If both input vectors has zero length,
+ ## of the other is returned. If both input vectors has zero length,
## an arbitrary normalized vector `v1` is returned.
var
vmag1=v1.len
vmag2=v2.len
-
- # zero length vector equals arbitrary vector, just change
+
+ # zero length vector equals arbitrary vector, just change
# magnitude to one to avoid zero division
- if vmag1==0.0:
+ if vmag1==0.0:
if vmag2==0: #both are zero length return any normalized vector
return XAXIS
vmag1=1.0
- if vmag2==0.0: vmag2=1.0
-
+ if vmag2==0.0: vmag2=1.0
+
let
x1=v1.x/vmag1
y1=v1.y/vmag1
@@ -832,14 +832,14 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
x2=v2.x/vmag2
y2=v2.y/vmag2
z2=v2.z/vmag2
-
+
result.x=(x1 + x2) * 0.5
result.y=(y1 + y2) * 0.5
result.z=(z1 + z2) * 0.5
-
+
if not result.tryNormalize():
# This can happen if vectors are colinear. In this special case
- # there are actually inifinitely many bisectors, we select just
+ # there are actually inifinitely many bisectors, we select just
# one of them.
result=v1.cross(XAXIS)
if result.sqrLen<1.0e-9:
@@ -857,14 +857,14 @@ proc point3d*(x,y,z:float):TPoint3d=
result.x=x
result.y=y
result.z=z
-
+
proc sqrDist*(a,b:TPoint3d):float=
## Computes the squared distance between `a`and `b`
let dx=b.x-a.x
let dy=b.y-a.y
let dz=b.z-a.z
result=dx*dx+dy*dy+dz*dz
-
+
proc dist*(a,b:TPoint3d):float {.inline.}=
## Computes the absolute distance between `a`and `b`
result=sqrt(sqrDist(a,b))
@@ -876,7 +876,7 @@ proc `$` *(p:TPoint3d):string=
result.add(rtos(p.y))
result.add(",")
result.add(rtos(p.z))
-
+
proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
## Concatenates a point `p` with a transform `m`,
## resulting in a new, transformed point.
@@ -893,18 +893,18 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
p.x=m.cx*z+m.bx*y+m.ax*x+m.tx
p.y=m.cy*z+m.by*y+m.ay*x+m.ty
p.z=m.cz*z+m.bz*y+m.az*x+m.tz
-
+
proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
## Applies the inverse of transformation `m` onto `p` in place.
## If the matrix is not invertable (determinant=0) , EDivByZero will
## be raised.
-
+
# can possibly be more optimized in the future so use this function when possible
p&=inverse(m)
proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
- ## Adds a vector `v` to a point `p`, resulting
+ ## Adds a vector `v` to a point `p`, resulting
## in a new point.
result.x=p.x+v.x
result.y=p.y+v.y
@@ -917,7 +917,7 @@ proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
p.z+=v.z
proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
- ## Subtracts a vector `v` from a point `p`, resulting
+ ## Subtracts a vector `v` from a point `p`, resulting
## in a new point.
result.x=p.x-v.x
result.y=p.y-v.y
@@ -933,37 +933,37 @@ proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
## Subtracts a vector `v` from a point `p` in place.
p.x-=v.x
p.y-=v.y
- p.z-=v.z
+ p.z-=v.z
proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
## Checks if two points approximately equals with a tolerance.
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
- ## Checks if two vectors approximately equals with a
+ ## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(p1,p2)
proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
- ## Rotates point `p` in place `rad` radians about an axis
+ ## Rotates point `p` in place `rad` radians about an axis
## passing through origo.
-
+
var v=vector3d(p.x,p.y,p.z)
v.rotate(rad,axis) # reuse this code here since doing the same thing and quite complicated
p.x=v.x
p.y=v.y
p.z=v.z
-
+
proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
- ## Rotates point `p` in place `rad` radians about an axis
+ ## Rotates point `p` in place `rad` radians about an axis
## passing through `org`
-
+
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
# for how this is computed
-
+
var normax=axis
normax.normalize
-
+
let
cs=cos(angle)
omc=1.0-cs
@@ -987,17 +987,17 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
bv=b*v
cw=c*w
uxmvymwz=ux-vy-wz
-
+
p.x=(a*(vv+ww)-u*(bv+cw-uxmvymwz))*omc + x*cs + (b*w+v*z-c*v-w*y)*si
p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
-
+
proc scale*(p:var TPoint3d,fac:float) {.inline.}=
## Scales a point in place `fac` times with world origo as origin.
p.x*=fac
p.y*=fac
p.z*=fac
-
+
proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
## Scales the point in place `fac` times with `org` as origin.
p.x=(p.x - org.x) * fac + org.x
@@ -1005,7 +1005,7 @@ proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
p.z=(p.z - org.z) * fac + org.z
proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
- ## Scales a point in place non uniformly `facx` , `facy` , `facz` times
+ ## Scales a point in place non uniformly `facx` , `facy` , `facz` times
## with world origo as origin.
p.x*=facx
p.y*=facy
@@ -1017,7 +1017,7 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
p.x=(p.x - org.x) * facx + org.x
p.y=(p.y - org.y) * facy + org.y
p.z=(p.z - org.z) * facz + org.z
-
+
proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
## Translates a point `dx` , `dy` , `dz` in place.
@@ -1033,7 +1033,7 @@ proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
proc area*(a,b,c:TPoint3d):float {.inline.}=
## Computes the area of the triangle thru points `a` , `b` and `c`
-
+
# The area of a planar 3d quadliteral is the magnitude of the cross
# product of two edge vectors. Taking this time 0.5 gives the triangle area.
return cross(b-a,c-a).len*0.5
diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
index c3954468ac..0df97c685e 100644
--- a/lib/pure/collections/LockFreeHash.nim
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
#Tests ----------------------------
-when isMainModule:
+when not defined(testing) and isMainModule:
import locks, times, mersenne
const
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 3d10e39aa3..7e3f238512 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -286,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
result.add("}")
when isMainModule:
+ import sequtils
+
var r: CritBitTree[void]
r.incl "abc"
r.incl "xyz"
r.incl "def"
r.incl "definition"
r.incl "prefix"
+
doAssert r.contains"def"
- #r.del "def"
- for w in r.items:
- echo w
-
- for w in r.itemsWithPrefix("de"):
- echo w
+ r.excl "def"
+ assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
+
+ assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index 7520e6e463..25f6616a62 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -14,12 +14,12 @@
## copy; use ``assign`` to get a deep copy.
import
- os, hashes, math
+ hashes, math
type
BitScalar = int
-const
+const
InitIntSetSize = 8 # must be a power of two!
TrunkShift = 9
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
@@ -31,11 +31,11 @@ const
type
PTrunk = ref TTrunk
- TTrunk {.final.} = object
+ TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
-
+
TTrunkSeq = seq[PTrunk]
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int
@@ -44,42 +44,42 @@ type
{.deprecated: [TIntSet: IntSet].}
-proc mustRehash(length, counter: int): bool {.inline.} =
+proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
-proc nextTry(h, maxHash: THash): THash {.inline.} =
- result = ((5 * h) + 1) and maxHash
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+ result = ((5 * h) + 1) and maxHash
-proc intSetGet(t: IntSet, key: int): PTrunk =
+proc intSetGet(t: IntSet, key: int): PTrunk =
var h = key and t.max
- while t.data[h] != nil:
- if t.data[h].key == key:
+ while t.data[h] != nil:
+ if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
result = nil
-proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
+proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
- while data[h] != nil:
+ while data[h] != nil:
assert(data[h] != desc)
h = nextTry(h, t.max)
assert(data[h] == nil)
data[h] = desc
-proc intSetEnlarge(t: var IntSet) =
+proc intSetEnlarge(t: var IntSet) =
var n: TTrunkSeq
var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)
- for i in countup(0, oldMax):
+ for i in countup(0, oldMax):
if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
swap(t.data, n)
-proc intSetPut(t: var IntSet, key: int): PTrunk =
+proc intSetPut(t: var IntSet, key: int): PTrunk =
var h = key and t.max
- while t.data[h] != nil:
- if t.data[h].key == key:
+ while t.data[h] != nil:
+ if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
@@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
t.data[h] = result
proc contains*(s: IntSet, key: int): bool =
- ## returns true iff `key` is in `s`.
+ ## returns true iff `key` is in `s`.
var t = intSetGet(s, `shr`(key, TrunkShift))
- if t != nil:
+ if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
- else:
+ else:
result = false
-
-proc incl*(s: var IntSet, key: int) =
+
+proc incl*(s: var IntSet, key: int) =
## includes an element `key` in `s`.
var t = intSetPut(s, `shr`(key, TrunkShift))
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
-proc excl*(s: var IntSet, key: int) =
+proc excl*(s: var IntSet, key: int) =
## excludes `key` from the set `s`.
var t = intSetGet(s, `shr`(key, TrunkShift))
- if t != nil:
+ if t != nil:
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
not `shl`(1, u and IntMask)
-proc containsOrIncl*(s: var IntSet, key: int): bool =
+proc containsOrIncl*(s: var IntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned.
var t = intSetGet(s, `shr`(key, TrunkShift))
- if t != nil:
+ if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
- if not result:
+ if not result:
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
- else:
+ else:
incl(s, key)
result = false
-
+
proc initIntSet*: IntSet =
## creates a new int set that is empty.
newSeq(result.data, InitIntSetSize)
@@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
proc assign*(dest: var IntSet, src: IntSet) =
## copies `src` to `dest`. `dest` does not need to be initialized by
- ## `initIntSet`.
+ ## `initIntSet`.
dest.counter = src.counter
dest.max = src.max
newSeq(dest.data, src.data.len)
-
+
var it = src.head
while it != nil:
-
+
var h = it.key and dest.max
while dest.data[h] != nil: h = nextTry(h, dest.max)
assert(dest.data[h] == nil)
@@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
while r != nil:
var i = 0
while i <= high(r.bits):
- var w = r.bits[i]
+ var w = r.bits[i]
# taking a copy of r.bits[i] here is correct, because
# modifying operations are not allowed during traversation
var j = 0
@@ -198,14 +198,21 @@ proc empty*(s: IntSet): bool {.inline, deprecated.} =
result = s.counter == 0
when isMainModule:
+ import sequtils, algorithm
+
var x = initIntSet()
x.incl(1)
x.incl(2)
x.incl(7)
x.incl(1056)
- for e in items(x): echo e
- var y: TIntSet
+ var xs = toSeq(items(x))
+ xs.sort(cmp[int])
+ assert xs == @[1, 2, 7, 1056]
+
+ var y: IntSet
assign(y, x)
- for e in items(y): echo e
+ var ys = toSeq(items(y))
+ ys.sort(cmp[int])
+ assert ys == @[1, 2, 7, 1056]
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 3f37d1ef08..e9cd2cb3c5 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -492,9 +492,8 @@ when isMainModule:
block: # filter iterator test
let numbers = @[1, 4, 5, 8, 9, 7, 4]
- for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
- echo($n)
- # echoes 4, 8, 4 in separate lines
+ assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+ @[4, 8, 4]
block: # keepIf test
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
@@ -616,4 +615,5 @@ when isMainModule:
#doAssert a.repeat(-1) == @[] # will not compile!
doAssert b.repeat(3) == @[]
- echo "Finished doc tests"
+ when not defined(testing):
+ echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 4a20d00a46..280e0eebab 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -114,7 +114,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
-proc rightSize*(count: int): int {.inline.} =
+proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items.
##
## If more items are expected to be added, simply add that
@@ -798,177 +798,179 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
g = nxg
result = compared == s.counter
-proc testModule() =
- ## Internal micro test to validate docstrings and such.
- block isValidTest:
- var options: HashSet[string]
- proc savePreferences(options: HashSet[string]) =
- assert options.isValid, "Pass an initialized set!"
- options = initSet[string]()
- options.savePreferences
+when isMainModule and not defined(release):
+ proc testModule() =
+ ## Internal micro test to validate docstrings and such.
+ block isValidTest:
+ var options: HashSet[string]
+ proc savePreferences(options: HashSet[string]) =
+ assert options.isValid, "Pass an initialized set!"
+ options = initSet[string]()
+ options.savePreferences
- block lenTest:
- var values: HashSet[int]
- assert(not values.isValid)
- assert values.len == 0
- assert values.card == 0
+ block lenTest:
+ var values: HashSet[int]
+ assert(not values.isValid)
+ assert values.len == 0
+ assert values.card == 0
- block setIterator:
- type pair = tuple[a, b: int]
- var a, b = initSet[pair]()
- a.incl((2, 3))
- a.incl((3, 2))
- a.incl((2, 3))
- for x, y in a.items:
- b.incl((x - 2, y + 1))
- assert a.len == b.card
- assert a.len == 2
- #echo b
+ block setIterator:
+ type pair = tuple[a, b: int]
+ var a, b = initSet[pair]()
+ a.incl((2, 3))
+ a.incl((3, 2))
+ a.incl((2, 3))
+ for x, y in a.items:
+ b.incl((x - 2, y + 1))
+ assert a.len == b.card
+ assert a.len == 2
+ #echo b
- block setContains:
- var values = initSet[int]()
- assert(not values.contains(2))
- values.incl(2)
- assert values.contains(2)
- values.excl(2)
- assert(not values.contains(2))
+ block setContains:
+ var values = initSet[int]()
+ assert(not values.contains(2))
+ values.incl(2)
+ assert values.contains(2)
+ values.excl(2)
+ assert(not values.contains(2))
- values.incl(4)
- var others = toSet([6, 7])
- values.incl(others)
- assert values.len == 3
+ values.incl(4)
+ var others = toSet([6, 7])
+ values.incl(others)
+ assert values.len == 3
- values.init
- assert values.containsOrIncl(2) == false
- assert values.containsOrIncl(2) == true
- var
- a = toSet([1, 2])
- b = toSet([1])
- b.incl(2)
- assert a == b
+ values.init
+ assert values.containsOrIncl(2) == false
+ assert values.containsOrIncl(2) == true
+ var
+ a = toSet([1, 2])
+ b = toSet([1])
+ b.incl(2)
+ assert a == b
- block exclusions:
- var s = toSet([2, 3, 6, 7])
- s.excl(2)
- s.excl(2)
- assert s.len == 3
+ block exclusions:
+ var s = toSet([2, 3, 6, 7])
+ s.excl(2)
+ s.excl(2)
+ assert s.len == 3
- var
- numbers = toSet([1, 2, 3, 4, 5])
- even = toSet([2, 4, 6, 8])
- numbers.excl(even)
- #echo numbers
- # --> {1, 3, 5}
+ var
+ numbers = toSet([1, 2, 3, 4, 5])
+ even = toSet([2, 4, 6, 8])
+ numbers.excl(even)
+ #echo numbers
+ # --> {1, 3, 5}
- block toSeqAndString:
- var a = toSet([2, 4, 5])
- var b = initSet[int]()
- for x in [2, 4, 5]: b.incl(x)
- assert($a == $b)
- #echo a
- #echo toSet(["no", "esc'aping", "is \" provided"])
+ block toSeqAndString:
+ var a = toSet([2, 4, 5])
+ var b = initSet[int]()
+ for x in [2, 4, 5]: b.incl(x)
+ assert($a == $b)
+ #echo a
+ #echo toSet(["no", "esc'aping", "is \" provided"])
- #block orderedToSeqAndString:
- # echo toOrderedSet([2, 4, 5])
- # echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+ #block orderedToSeqAndString:
+ # echo toOrderedSet([2, 4, 5])
+ # echo toOrderedSet(["no", "esc'aping", "is \" provided"])
- block setOperations:
- var
- a = toSet(["a", "b"])
- b = toSet(["b", "c"])
- c = union(a, b)
- assert c == toSet(["a", "b", "c"])
- var d = intersection(a, b)
- assert d == toSet(["b"])
- var e = difference(a, b)
- assert e == toSet(["a"])
- var f = symmetricDifference(a, b)
- assert f == toSet(["a", "c"])
- assert d < a and d < b
- assert((a < a) == false)
- assert d <= a and d <= b
- assert((a <= a))
- # Alias test.
- assert a + b == toSet(["a", "b", "c"])
- assert a * b == toSet(["b"])
- assert a - b == toSet(["a"])
- assert a -+- b == toSet(["a", "c"])
- assert disjoint(a, b) == false
- assert disjoint(a, b - a) == true
+ block setOperations:
+ var
+ a = toSet(["a", "b"])
+ b = toSet(["b", "c"])
+ c = union(a, b)
+ assert c == toSet(["a", "b", "c"])
+ var d = intersection(a, b)
+ assert d == toSet(["b"])
+ var e = difference(a, b)
+ assert e == toSet(["a"])
+ var f = symmetricDifference(a, b)
+ assert f == toSet(["a", "c"])
+ assert d < a and d < b
+ assert((a < a) == false)
+ assert d <= a and d <= b
+ assert((a <= a))
+ # Alias test.
+ assert a + b == toSet(["a", "b", "c"])
+ assert a * b == toSet(["b"])
+ assert a - b == toSet(["a"])
+ assert a -+- b == toSet(["a", "c"])
+ assert disjoint(a, b) == false
+ assert disjoint(a, b - a) == true
- block mapSet:
- var a = toSet([1, 2, 3])
- var b = a.map(proc (x: int): string = $x)
- assert b == toSet(["1", "2", "3"])
+ block mapSet:
+ var a = toSet([1, 2, 3])
+ var b = a.map(proc (x: int): string = $x)
+ assert b == toSet(["1", "2", "3"])
- block isValidTest:
- var cards: OrderedSet[string]
- proc saveTarotCards(cards: OrderedSet[string]) =
- assert cards.isValid, "Pass an initialized set!"
- cards = initOrderedSet[string]()
- cards.saveTarotCards
+ block isValidTest:
+ var cards: OrderedSet[string]
+ proc saveTarotCards(cards: OrderedSet[string]) =
+ assert cards.isValid, "Pass an initialized set!"
+ cards = initOrderedSet[string]()
+ cards.saveTarotCards
- block lenTest:
- var values: OrderedSet[int]
- assert(not values.isValid)
- assert values.len == 0
- assert values.card == 0
+ block lenTest:
+ var values: OrderedSet[int]
+ assert(not values.isValid)
+ assert values.len == 0
+ assert values.card == 0
- block setIterator:
- type pair = tuple[a, b: int]
- var a, b = initOrderedSet[pair]()
- a.incl((2, 3))
- a.incl((3, 2))
- a.incl((2, 3))
- for x, y in a.items:
- b.incl((x - 2, y + 1))
- assert a.len == b.card
- assert a.len == 2
+ block setIterator:
+ type pair = tuple[a, b: int]
+ var a, b = initOrderedSet[pair]()
+ a.incl((2, 3))
+ a.incl((3, 2))
+ a.incl((2, 3))
+ for x, y in a.items:
+ b.incl((x - 2, y + 1))
+ assert a.len == b.card
+ assert a.len == 2
- #block orderedSetIterator:
- # var a = initOrderedSet[int]()
- # for value in [9, 2, 1, 5, 1, 8, 4, 2]:
- # a.incl(value)
- # for value in a.items:
- # echo "Got ", value
+ #block orderedSetIterator:
+ # var a = initOrderedSet[int]()
+ # for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+ # a.incl(value)
+ # for value in a.items:
+ # echo "Got ", value
- block setContains:
- var values = initOrderedSet[int]()
- assert(not values.contains(2))
- values.incl(2)
- assert values.contains(2)
+ block setContains:
+ var values = initOrderedSet[int]()
+ assert(not values.contains(2))
+ values.incl(2)
+ assert values.contains(2)
- block toSeqAndString:
- var a = toOrderedSet([2, 4, 5])
- var b = initOrderedSet[int]()
- for x in [2, 4, 5]: b.incl(x)
- assert($a == $b)
- assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
+ block toSeqAndString:
+ var a = toOrderedSet([2, 4, 5])
+ var b = initOrderedSet[int]()
+ for x in [2, 4, 5]: b.incl(x)
+ assert($a == $b)
+ assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
- block initBlocks:
- var a: OrderedSet[int]
- a.init(4)
- a.incl(2)
- a.init
- assert a.len == 0 and a.isValid
- a = initOrderedSet[int](4)
- a.incl(2)
- assert a.len == 1
+ block initBlocks:
+ var a: OrderedSet[int]
+ a.init(4)
+ a.incl(2)
+ a.init
+ assert a.len == 0 and a.isValid
+ a = initOrderedSet[int](4)
+ a.incl(2)
+ assert a.len == 1
- var b: HashSet[int]
- b.init(4)
- b.incl(2)
- b.init
- assert b.len == 0 and b.isValid
- b = initSet[int](4)
- b.incl(2)
- assert b.len == 1
+ var b: HashSet[int]
+ b.init(4)
+ b.incl(2)
+ b.init
+ assert b.len == 0 and b.isValid
+ b = initSet[int](4)
+ b.incl(2)
+ assert b.len == 1
- for i in 0 .. 32:
- var s = rightSize(i)
- if s <= i or mustRehash(s, i):
- echo "performance issue: rightSize() will not elide enlarge() at ", i
+ for i in 0 .. 32:
+ var s = rightSize(i)
+ if s <= i or mustRehash(s, i):
+ echo "performance issue: rightSize() will not elide enlarge() at ", i
- echo "Micro tests run successfully."
+ when not defined(testing):
+ echo "Micro tests run successfully."
-when isMainModule and not defined(release): testModule()
+ testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index f85acef226..9496fa2fea 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -128,7 +128,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
-proc rightSize*(count: int): int {.inline.} =
+proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items.
##
## If more items are expected to be added, simply add that
@@ -215,6 +215,10 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool =
var hc: THash
result = rawGet(t, key, hc) >= 0
+proc contains*[A, B](t: Table[A, B], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A, B](t, key)
+
proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
rawInsertImpl()
@@ -411,6 +415,10 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = t[].hasKey(key)
+proc contains*[A, B](t: TableRef[A, B], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A, B](t, key)
+
proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
## puts a (key, value)-pair into `t`.
t[][key] = val
@@ -532,6 +540,10 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
var hc: THash
result = rawGet(t, key, hc) >= 0
+proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A, B](t, key)
+
proc rawInsert[A, B](t: var OrderedTable[A, B],
data: var OrderedKeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
@@ -704,6 +716,10 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = t[].hasKey(key)
+proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A, B](t, key)
+
proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
## puts a (key, value)-pair into `t`.
t[][key] = val
@@ -804,6 +820,10 @@ proc hasKey*[A](t: CountTable[A], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
+proc contains*[A](t: CountTable[A], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A](t, key)
+
proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
key: A, val: int) =
var h: THash = hash(key) and high(data)
@@ -819,15 +839,18 @@ proc enlarge[A](t: var CountTable[A]) =
swap(t.data, n)
proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
- ## puts a (key, value)-pair into `t`. `val` has to be positive.
+ ## puts a (key, value)-pair into `t`.
assert val > 0
var h = rawGet(t, key)
if h >= 0:
t.data[h].val = val
else:
- h = -1 - h
- t.data[h].key = key
- t.data[h].val = val
+ if mustRehash(len(t.data), t.counter): enlarge(t)
+ rawInsert(t, t.data, key, val)
+ inc(t.counter)
+ #h = -1 - h
+ #t.data[h].key = key
+ #t.data[h].val = val
proc initCountTable*[A](initialSize=64): CountTable[A] =
## creates a new count table that is empty.
@@ -942,6 +965,10 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool =
## returns true iff `key` is in the table `t`.
result = t[].hasKey(key)
+proc contains*[A](t: CountTableRef[A], key: A): bool =
+ ## alias of `hasKey` for use with the `in` operator.
+ return hasKey[A](t, key)
+
proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
## puts a (key, value)-pair into `t`. `val` has to be positive.
assert val > 0
@@ -984,6 +1011,22 @@ proc sort*[A](t: CountTableRef[A]) =
## `t` in the sorted order.
t[].sort
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+ ## merges the second table into the first one
+ for key, value in t:
+ s.inc(key, value)
+
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+ ## merges the two tables into a new one
+ result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+ for table in @[s, t]:
+ for key, value in table:
+ result.inc(key, value)
+
+proc merge*[A](s, t: CountTableRef[A]) =
+ ## merges the second table into the first one
+ s[].merge(t[])
+
when isMainModule:
type
Person = object
@@ -1012,3 +1055,48 @@ when isMainModule:
s2[p2] = 45_000
s3[p1] = 30_000
s3[p2] = 45_000
+
+ var
+ t1 = initCountTable[string]()
+ t2 = initCountTable[string]()
+ t1.inc("foo")
+ t1.inc("bar", 2)
+ t1.inc("baz", 3)
+ t2.inc("foo", 4)
+ t2.inc("bar")
+ t2.inc("baz", 11)
+ merge(t1, t2)
+ assert(t1["foo"] == 5)
+ assert(t1["bar"] == 3)
+ assert(t1["baz"] == 14)
+
+ let
+ t1r = newCountTable[string]()
+ t2r = newCountTable[string]()
+ t1r.inc("foo")
+ t1r.inc("bar", 2)
+ t1r.inc("baz", 3)
+ t2r.inc("foo", 4)
+ t2r.inc("bar")
+ t2r.inc("baz", 11)
+ merge(t1r, t2r)
+ assert(t1r["foo"] == 5)
+ assert(t1r["bar"] == 3)
+ assert(t1r["baz"] == 14)
+
+ var
+ t1l = initCountTable[string]()
+ t2l = initCountTable[string]()
+ t1l.inc("foo")
+ t1l.inc("bar", 2)
+ t1l.inc("baz", 3)
+ t2l.inc("foo", 4)
+ t2l.inc("bar")
+ t2l.inc("baz", 11)
+ let
+ t1merging = t1l
+ t2merging = t2l
+ let merged = merge(t1merging, t2merging)
+ assert(merged["foo"] == 5)
+ assert(merged["bar"] == 3)
+ assert(merged["baz"] == 14)
diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim
index c1796089a3..7ce5e01b77 100644
--- a/lib/pure/concurrency/cpuload.nim
+++ b/lib/pure/concurrency/cpuload.nim
@@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
result = doNothing
inc s.calls
-when isMainModule:
+when not defined(testing) and isMainModule:
proc busyLoop() =
while true:
discard random(80)
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 9f1e53fb8a..a431691add 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -300,7 +300,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
minPoolSize = size
proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
- ## sets the minimal thread pool size. The default value of this
+ ## sets the maximal thread pool size. The default value of this
## is ``MaxThreadPoolSize``.
maxPoolSize = size
if currentPoolSize > maxPoolSize:
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 6247efed24..9983c4a041 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
when isMainModule:
var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
- echo(setCookie("test", "value", tim.getGMTime()))
+ let cookie = setCookie("test", "value", tim.getGMTime())
+ when not defined(testing):
+ echo cookie
+ let start = "Set-Cookie: test=value; Expires="
+ assert cookie[0..start.high] == start
- echo parseCookies("uid=1; kp=2")
+ let table = parseCookies("uid=1; kp=2")
+ assert table["uid"] == "1"
+ assert table["kp"] == "2"
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 25c7ad9ef7..2a61346150 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
finally:
close(c)
-when isMainModule:
+when not defined(testing) and isMainModule:
let
orig = "öäüß"
cp1252 = convert(orig, "CP1252", "UTF-8")
diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim
index e6919b661b..83779eb9c7 100644
--- a/lib/pure/fsmonitor.nim
+++ b/lib/pure/fsmonitor.nim
@@ -198,7 +198,7 @@ proc register*(d: Dispatcher, monitor: FSMonitor,
var deleg = toDelegate(monitor)
d.register(deleg)
-when isMainModule:
+when not defined(testing) and isMainModule:
proc main =
var disp = newDispatcher()
var monitor = newMonitor()
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index dc387b79c7..dd141eb017 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -593,7 +593,7 @@ proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
ftp.disp = d
return ftp.disp.register(ftp.csock)
-when isMainModule:
+when not defined(testing) and isMainModule:
proc main =
var d = newDispatcher()
let hev =
@@ -629,7 +629,7 @@ when isMainModule:
if not d.poll(): break
main()
-when isMainModule and false:
+when not defined(testing) and isMainModule:
var ftp = ftpClient("example.com", user = "foo", pass = "bar")
ftp.connect()
echo ftp.pwd()
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
index a6128efc96..84d0a44de0 100644
--- a/lib/pure/gentabs.nim
+++ b/lib/pure/gentabs.nim
@@ -9,7 +9,7 @@
## The ``gentabs`` module implements an efficient hash table that is a
## key-value mapping. The keys are required to be strings, but the values
-## may be any Nim or user defined type. This module supports matching
+## may be any Nim or user defined type. This module supports matching
## of keys in case-sensitive, case-insensitive and style-insensitive modes.
{.deprecated.}
@@ -22,7 +22,7 @@ type
modeCaseSensitive, ## case sensitive matching of keys
modeCaseInsensitive, ## case insensitive matching of keys
modeStyleInsensitive ## style sensitive matching of keys
-
+
TGenKeyValuePair[T] = tuple[key: string, val: T]
TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
TGenTable*[T] = object of RootObj
@@ -83,7 +83,7 @@ proc rawGet[T](tbl: PGenTable[T], key: string): int =
h = nextTry(h, high(tbl.data))
result = - 1
-proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
+proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
key: string, val: T) =
var h: THash
h = myhash(tbl, key) and high(data)
@@ -96,7 +96,7 @@ proc enlarge[T](tbl: PGenTable[T]) =
var n: TGenKeyValuePairSeq[T]
newSeq(n, len(tbl.data) * growthFactor)
for i in countup(0, high(tbl.data)):
- if not isNil(tbl.data[i].key):
+ if not isNil(tbl.data[i].key):
rawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val)
swap(tbl.data, n)
@@ -141,20 +141,20 @@ when isMainModule:
assert(not x.hasKey("NOPE")) # ...but key "NOPE" is not in the table.
for k,v in pairs(x): # make sure the 'pairs' iterator works
assert(x[k]==v)
-
+
#
# Verify a table of user-defined types
#
type
TMyType = tuple[first, second: string] # a pair of strings
-
+
var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
# value is TMyType tuple
-
+
#var junk: TMyType = ("OK", "Here")
-
+
#echo junk.first, " ", junk.second
-
+
y["Hello"] = ("Hello", "World")
y["Goodbye"] = ("Goodbye", "Everyone")
#y["Hello"] = TMyType( ("Hello", "World") )
@@ -163,31 +163,44 @@ when isMainModule:
assert( not isNil(y["Hello"].first) )
assert( y["Hello"].first == "Hello" )
assert( y["Hello"].second == "World" )
-
+
#
# Verify table of tables
#
- var z: PGenTable[ PGenTable[int] ] # hash table where each value is
+ var z: PGenTable[ PGenTable[int] ] # hash table where each value is
# a hash table of ints
-
+
z = newGenTable[PGenTable[int]](modeCaseInsensitive)
z["first"] = newGenTable[int](modeCaseInsensitive)
z["first"]["one"] = 1
z["first"]["two"] = 2
z["first"]["three"] = 3
-
+
z["second"] = newGenTable[int](modeCaseInsensitive)
z["second"]["red"] = 10
z["second"]["blue"] = 20
-
+
assert(len(z) == 2) # length of outer table
assert(len(z["first"]) == 3) # length of "first" table
assert(len(z["second"]) == 2) # length of "second" table
assert( z["first"]["one"] == 1) # retrieve from first inner table
assert( z["second"]["red"] == 10) # retrieve from second inner table
-
- for k,v in pairs(z):
- echo( "$# ($#) ->" % [k,$len(v)] )
- #for k2,v2 in pairs(v):
- # echo( " $# <-> $#" % [k2,$v2] )
- echo()
+
+ when false:
+ # disabled: depends on hash order:
+ var output = ""
+ for k, v in pairs(z):
+ output.add( "$# ($#) ->\L" % [k,$len(v)] )
+ for k2,v2 in pairs(v):
+ output.add( " $# <-> $#\L" % [k2,$v2] )
+
+ let expected = unindent """
+ first (3) ->
+ two <-> 2
+ three <-> 3
+ one <-> 1
+ second (2) ->
+ red <-> 10
+ blue <-> 20
+ """
+ assert output == expected
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index a16342d446..2ce8ac7961 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -37,29 +37,29 @@
## h = h !& hash(x.bar)
## result = !$h
-import
+import
strutils
-type
- THash* = int ## a hash value; hash tables using these values should
+type
+ THash* = int ## a hash value; hash tables using these values should
## always have a size of a power of two and can use the ``and``
## operator instead of ``mod`` for truncation of the hash value.
-proc `!&`*(h: THash, val: int): THash {.inline.} =
+proc `!&`*(h: THash, val: int): THash {.inline.} =
## mixes a hash value `h` with `val` to produce a new hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
-proc `!$`*(h: THash): THash {.inline.} =
+proc `!$`*(h: THash): THash {.inline.} =
## finishes the computation of the hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
-proc hashData*(data: pointer, size: int): THash =
+proc hashData*(data: pointer, size: int): THash =
## hashes an array of bytes of size `size`
var h: THash = 0
when defined(js):
@@ -69,7 +69,7 @@ proc hashData*(data: pointer, size: int): THash =
var p = cast[cstring](data)
var i = 0
var s = size
- while s > 0:
+ while s > 0:
h = h !& ord(p[i])
inc(i)
dec(s)
@@ -78,7 +78,7 @@ proc hashData*(data: pointer, size: int): THash =
when defined(js):
var objectID = 0
-proc hash*(x: pointer): THash {.inline.} =
+proc hash*(x: pointer): THash {.inline.} =
## efficient hashing of pointers
when defined(js):
asm """
@@ -93,7 +93,7 @@ proc hash*(x: pointer): THash {.inline.} =
"""
else:
result = (cast[THash](x)) shr 3 # skip the alignment
-
+
when not defined(booting):
proc hash*[T: proc](x: T): THash {.inline.} =
## efficient hashing of proc vars; closures are supported too.
@@ -101,58 +101,65 @@ when not defined(booting):
result = hash(rawProc(x)) !& hash(rawEnv(x))
else:
result = hash(pointer(x))
-
-proc hash*(x: int): THash {.inline.} =
+
+proc hash*(x: int): THash {.inline.} =
## efficient hashing of integers
result = x
-proc hash*(x: int64): THash {.inline.} =
+proc hash*(x: int64): THash {.inline.} =
## efficient hashing of integers
result = toU32(x)
-proc hash*(x: char): THash {.inline.} =
+proc hash*(x: char): THash {.inline.} =
## efficient hashing of characters
result = ord(x)
-proc hash*(x: string): THash =
+proc hash*(x: string): THash =
## efficient hashing of strings
var h: THash = 0
- for i in 0..x.len-1:
+ for i in 0..x.len-1:
h = h !& ord(x[i])
result = !$h
-
-proc hashIgnoreStyle*(x: string): THash =
+
+proc hashIgnoreStyle*(x: string): THash =
## efficient hashing of strings; style is ignored
var h: THash = 0
- for i in 0..x.len-1:
+ for i in 0..x.len-1:
var c = x[i]
- if c == '_':
+ if c == '_':
continue # skip _
- if c in {'A'..'Z'}:
+ if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
result = !$h
-proc hashIgnoreCase*(x: string): THash =
+proc hashIgnoreCase*(x: string): THash =
## efficient hashing of strings; case is ignored
var h: THash = 0
- for i in 0..x.len-1:
+ for i in 0..x.len-1:
var c = x[i]
- if c in {'A'..'Z'}:
+ if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
result = !$h
-
-proc hash*[T: tuple](x: T): THash =
- ## efficient hashing of tuples.
- for f in fields(x):
- result = result !& hash(f)
- result = !$result
proc hash*(x: float): THash {.inline.} =
var y = x + 1.0
result = cast[ptr THash](addr(y))[]
+
+# Forward declarations before methods that hash containers. This allows
+# containers to contain other containers
+proc hash*[A](x: openArray[A]): THash
+proc hash*[A](x: set[A]): THash
+
+
+proc hash*[T: tuple](x: T): THash =
+ ## efficient hashing of tuples.
+ for f in fields(x):
+ result = result !& hash(f)
+ result = !$result
+
proc hash*[A](x: openArray[A]): THash =
for it in items(x): result = result !& hash(it)
result = !$result
@@ -160,3 +167,4 @@ proc hash*[A](x: openArray[A]): THash =
proc hash*[A](x: set[A]): THash =
for it in items(x): result = result !& hash(it)
result = !$result
+
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index d712e53f36..e6c15371e7 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -483,7 +483,8 @@ macro `var`*(e: expr): expr {.immediate.} =
result = xmlCheckedTag(e, "var", commonAttr)
when isMainModule:
- var nim = "Nim"
- echo h1(a(href="http://nim-lang.org", nim))
- echo form(action="test", `accept-charset` = "Content-Type")
-
+ let nim = "Nim"
+ assert h1(a(href="http://nim-lang.org", nim)) ==
+ """"""
+ assert form(action="test", `accept-charset` = "Content-Type") ==
+ """"""
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index 5e4eba4e53..9719181b8c 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
var errors: seq[string] = @[]
result = loadHtml(path, errors)
-when isMainModule:
+when not defined(testing) and isMainModule:
import os
var errors: seq[string] = @[]
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 4c2580da03..9c27ecdabb 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -819,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
result = await client.request(redirectTo, httpGET)
lastUrl = redirectTo
-when isMainModule:
+when not defined(testing) and isMainModule:
when true:
# Async
proc main() {.async.} =
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 5efdbe297b..dc76c92284 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
## Closes the ``PAsyncHTTPServer``.
h.asyncSocket.close()
-when isMainModule:
+when not defined(testing) and isMainModule:
var counter = 0
var s: TServer
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index c3db5bdf83..5d824d6f8e 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -605,6 +605,49 @@ proc newJArray*(): JsonNode =
result.kind = JArray
result.elems = @[]
+proc getStr*(n: JsonNode, default: string = ""): string =
+ ## Retrieves the string value of a `JString JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JString``.
+ if n.kind != JString: return default
+ else: return n.str
+
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
+ ## Retrieves the int value of a `JInt JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JInt``.
+ if n.kind != JInt: return default
+ else: return n.num
+
+proc getFNum*(n: JsonNode, default: float = 0.0): float =
+ ## Retrieves the float value of a `JFloat JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JFloat``.
+ if n.kind != JFloat: return default
+ else: return n.fnum
+
+proc getBVal*(n: JsonNode, default: bool = false): bool =
+ ## Retrieves the bool value of a `JBool JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JBool``.
+ if n.kind != JBool: return default
+ else: return n.bval
+
+proc getFields*(n: JsonNode,
+ default: seq[tuple[key: string, val: JsonNode]] = @[]):
+ seq[tuple[key: string, val: JsonNode]] =
+ ## Retrieves the key, value pairs of a `JObject JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JObject``.
+ if n.kind != JObject: return default
+ else: return n.fields
+
+proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
+ ## Retrieves the int value of a `JArray JsonNode`.
+ ##
+ ## Returns ``default`` if ``n`` is not a ``JArray``.
+ if n.kind != JArray: return default
+ else: return n.elems
proc `%`*(s: string): JsonNode =
## Generic constructor for JSON data. Creates a new `JString JsonNode`.
@@ -765,22 +808,25 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
return
obj.fields.add((key, val))
-proc `{}`*(node: JsonNode, key: string): JsonNode =
- ## Transverses the node and gets the given value. If any of the
- ## names does not exist, returns nil
+proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
+ ## Traverses the node and gets the given value. If any of the
+ ## keys do not exist, returns nil. Also returns nil if one of the
+ ## intermediate data structures is not an object
result = node
- if isNil(node): return nil
- result = result[key]
+ for key in keys:
+ if isNil(result) or result.kind!=JObject:
+ return nil
+ result=result[key]
-proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
- ## Transverses the node and tries to set the value at the given location
- ## to `value` If any of the names are missing, they are added
+proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
+ ## Traverses the node and tries to set the value at the given location
+ ## to `value` If any of the keys are missing, they are added
var node = node
- for i in 0..(names.len-2):
- if isNil(node[names[i]]):
- node[names[i]] = newJObject()
- node = node[names[i]]
- node[names[names.len-1]] = value
+ for i in 0..(keys.len-2):
+ if isNil(node[keys[i]]):
+ node[keys[i]] = newJObject()
+ node = node[keys[i]]
+ node[keys[keys.len-1]] = value
proc delete*(obj: JsonNode, key: string) =
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
@@ -1107,19 +1153,22 @@ when false:
when isMainModule:
#var node = parse("{ \"test\": null }")
#echo(node.existsKey("test56"))
+
var parsed = parseFile("tests/testdata/jsontest.json")
var parsed2 = parseFile("tests/testdata/jsontest2.json")
- echo(parsed)
- echo()
- echo(pretty(parsed, 2))
- echo()
- echo(parsed["keyÄÖöoßß"])
- echo()
- echo(pretty(parsed2))
- try:
- echo(parsed["key2"][12123])
- raise newException(ValueError, "That line was expected to fail")
- except IndexError: echo()
+
+ when not defined(testing):
+ echo(parsed)
+ echo()
+ echo(pretty(parsed, 2))
+ echo()
+ echo(parsed["keyÄÖöoßß"])
+ echo()
+ echo(pretty(parsed2))
+ try:
+ echo(parsed["key2"][12123])
+ raise newException(ValueError, "That line was expected to fail")
+ except IndexError: echo()
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
# nil passthrough
@@ -1143,9 +1192,17 @@ when isMainModule:
except:
assert(false, "EInvalidIndex thrown for valid index")
+ assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
+ assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
+ assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+ assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+ assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+ assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+ assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+
# Generator:
var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
- assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+ assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
var j2 = %*
[
@@ -1173,12 +1230,13 @@ when isMainModule:
}
]
assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
-
- discard """
- while true:
- var json = stdin.readLine()
- var node = parse(json)
- echo(node)
- echo()
- echo()
- """
+
+ when not defined(testing):
+ discard """
+ while true:
+ var json = stdin.readLine()
+ var node = parse(json)
+ echo(node)
+ echo()
+ echo()
+ """
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index ca674af4b3..a2ea534726 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -278,7 +278,7 @@ proc getLogFilter*(): Level =
# --------------
-when isMainModule:
+when not defined(testing) and isMainModule:
var L = newConsoleLogger()
var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index b63c334ff4..e0092f314b 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -15,8 +15,8 @@
## type than its compiletime type:
##
## .. code-block:: nim
-##
-## type
+##
+## type
## TA = object
## TB = object of TA
## f: int
@@ -28,6 +28,8 @@
## new(b)
## a = b
## echo($$a[]) # produces "{}", not "{f: 0}"
+##
+## **Note**: The ``to`` and ``$$`` operations are available at compile-time!
import streams, typeinfo, json, intsets, tables
@@ -38,7 +40,12 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
case a.kind
of akNone: assert false
of akBool: s.write($getBool(a))
- of akChar: s.write(escapeJson($getChar(a)))
+ of akChar:
+ let ch = getChar(a)
+ if ch < '\128':
+ s.write(escapeJson($ch))
+ else:
+ s.write($int(ch))
of akArray, akSequence:
if a.kind == akSequence and isNil(a): s.write("null")
else:
@@ -92,7 +99,7 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
case a.kind
of akNone: assert false
- of akBool:
+ of akBool:
case p.kind
of jsonFalse: setBiggestInt(a, 0)
of jsonTrue: setBiggestInt(a, 1)
@@ -105,8 +112,12 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
setBiggestInt(a, ord(x[0]))
next(p)
return
+ elif p.kind == jsonInt:
+ setBiggestInt(a, getInt(p))
+ next(p)
+ return
raiseParseErr(p, "string of length 1 expected for a char")
- of akEnum:
+ of akEnum:
if p.kind == jsonString:
setBiggestInt(a, getEnumOrdinal(a, p.str))
next(p)
@@ -122,7 +133,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
of akSequence:
- case p.kind
+ case p.kind
of jsonNull:
setPointer(a, nil)
next(p)
@@ -143,7 +154,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
next(p)
while p.kind != jsonObjectEnd and p.kind != jsonEof:
- if p.kind != jsonString:
+ if p.kind != jsonString:
raiseParseErr(p, "string expected for a field name")
var fieldName = p.str
next(p)
@@ -160,7 +171,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
of akPtr, akRef:
- case p.kind
+ case p.kind
of jsonNull:
setPointer(a, nil)
next(p)
@@ -170,7 +181,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
of jsonArrayStart:
next(p)
if a.kind == akRef: invokeNew(a)
- else: setPointer(a, alloc0(a.baseTypeSize))
+ else: setPointer(a, alloc0(a.baseTypeSize))
if p.kind == jsonInt:
t[p.getInt] = getPointer(a)
next(p)
@@ -179,8 +190,8 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of ref-address pair expected")
else: raiseParseErr(p, "int for pointer type expected")
- of akProc, akPointer, akCString:
- case p.kind
+ of akProc, akPointer, akCString:
+ case p.kind
of jsonNull:
setPointer(a, nil)
next(p)
@@ -189,7 +200,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
next(p)
else: raiseParseErr(p, "int for pointer type expected")
of akString:
- case p.kind
+ case p.kind
of jsonNull:
setPointer(a, nil)
next(p)
@@ -197,7 +208,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
setString(a, p.str)
next(p)
else: raiseParseErr(p, "string expected")
- of akInt..akInt64, akUInt..akUInt64:
+ of akInt..akInt64, akUInt..akUInt64:
if p.kind == jsonInt:
setBiggestInt(a, getInt(p))
next(p)
@@ -243,22 +254,22 @@ proc to*[T](data: string): T =
## reads data and transforms it to a ``T``.
var tab = initTable[BiggestInt, pointer]()
loadAny(newStringStream(data), toAny(result), tab)
-
-when isMainModule:
+
+when not defined(testing) and isMainModule:
template testit(x: expr) = echo($$to[type(x)]($$x))
var x: array[0..4, array[0..4, string]] = [
- ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
- ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
["test", "1", "2", "3", "4"]]
testit(x)
var test2: tuple[name: string, s: uint] = ("tuple test", 56u)
testit(test2)
-
+
type
TE = enum
blah, blah2
-
+
TestObj = object
test, asd: int
case test2: TE
@@ -266,7 +277,7 @@ when isMainModule:
help: string
else:
nil
-
+
PNode = ref TNode
TNode = object
next, prev: PNode
@@ -294,7 +305,7 @@ when isMainModule:
test4.a = "ref string test: A"
test4.b = "ref string test: B"
testit(test4)
-
+
var test5 = @[(0,1),(2,3),(4,5)]
testit(test5)
@@ -305,7 +316,7 @@ when isMainModule:
echo($$test7)
testit(test7)
- type
+ type
TA {.inheritable.} = object
TB = object of TA
f: int
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index c902af381a..cb58ea39b6 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -85,7 +85,7 @@ proc fac*(n: int): int {.noSideEffect.} =
proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
## returns true, if `x` is a power of two, false otherwise.
## Zero and negative numbers are not a power of two.
- return (x != 0) and ((x and (x - 1)) == 0)
+ return (x > 0) and ((x and (x - 1)) == 0)
proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
## returns `x` rounded up to the nearest power of two.
@@ -114,18 +114,23 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
## If `x` is empty, 0 is returned.
for i in items(x): result = result + i
-proc mean*(x: openArray[float]): float {.noSideEffect.} =
- ## computes the mean of the elements in `x`.
- ## If `x` is empty, NaN is returned.
- result = sum(x) / toFloat(len(x))
+template toFloat(f: float): float = f
-proc variance*(x: openArray[float]): float {.noSideEffect.} =
+proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
+ ## computes the mean of the elements in `x`, which are first converted to floats.
+ ## If `x` is empty, NaN is returned.
+ ## ``toFloat(x: T): float`` must be defined.
+ for i in items(x): result = result + toFloat(i)
+ result = result / toFloat(len(x))
+
+proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
## computes the variance of the elements in `x`.
## If `x` is empty, NaN is returned.
+ ## ``toFloat(x: T): float`` must be defined.
result = 0.0
var m = mean(x)
- for i in 0 .. high(x):
- var diff = x[i] - m
+ for i in items(x):
+ var diff = toFloat(i) - m
result = result + diff*diff
result = result / toFloat(len(x))
@@ -152,6 +157,7 @@ proc randomize*(seed: int) {.benign.}
## Note: Does nothing for the JavaScript target,
## as JavaScript does not support this.
+{.push noSideEffect.}
when not defined(JS):
proc sqrt*(x: float): float {.importc: "sqrt", header: "".}
## computes the square root of `x`.
@@ -273,6 +279,8 @@ else:
var y = exp(2.0*x)
return (y-1.0)/(y+1.0)
+{.pop.}
+
proc `mod`*(x, y: float): float =
result = if y == 0.0: x else: x - y * (x/y).floor
@@ -369,4 +377,10 @@ when isMainModule and not defined(JS):
randomize(seed)
for i in 0..SIZE-1:
assert buf[i] == random(high(int)), "non deterministic random seeding"
- echo "random values equal after reseeding"
+
+ when not defined(testing):
+ echo "random values equal after reseeding"
+
+ # Check for no side effect annotation
+ proc mySqrt(num: float): float {.noSideEffect.} =
+ return sqrt(num)
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index a6a781cb8c..74112e3045 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
return int(y)
# Test
-when isMainModule:
+when not defined(testing) and isMainModule:
var mt = newMersenneTwister(2525)
for i in 0..99:
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index a52ba4ebe9..642419e644 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
when isMainModule:
var m = newMimetypes()
- echo m.getMimetype("mp4")
- echo m.getExt("text/html")
+ assert m.getMimetype("mp4") == "video/mp4"
+ assert m.getExt("text/html") == "html"
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 0dc8e3c15f..ac90dd16b2 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -88,6 +88,6 @@ proc generatedTime*(oid: Oid): Time =
bigEndian32(addr(tmp), addr(dummy))
result = Time(tmp)
-when isMainModule:
+when not defined(testing) and isMainModule:
let xo = genOid()
echo xo.generatedTime
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index cd37000199..dce0673baa 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -137,7 +137,7 @@ proc startProcess*(command: string,
## `env` is the environment that will be passed to the process.
## If ``env == nil`` the environment is inherited of
## the parent process. `options` are additional flags that may be passed
- ## to `startProcess`. See the documentation of ``TProcessOption`` for the
+ ## to `startProcess`. See the documentation of ``ProcessOption`` for the
## meaning of these flags. You need to `close` the process when done.
##
## Note that you can't pass any `args` if you use the option
@@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
-
+
proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
## Returns true iff the process `p` is still running. Returns immediately.
@@ -666,7 +666,7 @@ elif not defined(useNimRtl):
data.workingDir = workingDir
- when declared(posix_spawn) and not defined(useFork) and
+ when declared(posix_spawn) and not defined(useFork) and
not defined(useClone) and not defined(linux):
pid = startProcessAuxSpawn(data)
else:
@@ -823,7 +823,7 @@ elif not defined(useNimRtl):
discard execvp(data.sysCommand, data.sysArgs)
else:
when defined(uClibc):
- # uClibc environment (OpenWrt included) doesn't have the full execvpe
+ # uClibc environment (OpenWrt included) doesn't have the full execvpe
discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
else:
discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
@@ -864,9 +864,9 @@ elif not defined(useNimRtl):
raiseOsError(osLastError())
proc kill(p: Process) =
- if kill(p.id, SIGKILL) != 0'i32:
+ if kill(p.id, SIGKILL) != 0'i32:
raiseOsError(osLastError())
-
+
proc waitForExit(p: Process, timeout: int = -1): int =
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
# ``waitPid`` fails if the process is not running anymore. But then
@@ -883,7 +883,7 @@ elif not defined(useNimRtl):
var ret = waitpid(p.id, p.exitCode, WNOHANG)
var b = ret == int(p.id)
if b: result = -1
- if p.exitCode == -3: result = -1
+ if not WIFEXITED(p.exitCode): result = -1
else: result = p.exitCode.int shr 8
proc createStream(stream: var Stream, handle: var FileHandle,
@@ -907,7 +907,7 @@ elif not defined(useNimRtl):
createStream(p.errStream, p.errHandle, fmRead)
return p.errStream
- proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
+ proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
header: "".}
proc execCmd(command: string): int =
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index f4943ed895..117d75cfa7 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -166,7 +166,7 @@ proc close*(my: var CsvParser) {.inline.} =
## closes the parser `my` and its associated input stream.
lexbase.close(my)
-when isMainModule:
+when not defined(testing) and isMainModule:
import os
var s = newFileStream(paramStr(1), fmRead)
if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index bb4ede7791..91917b1c53 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -1330,7 +1330,7 @@ proc renderSQL*(n: SqlNode): string =
result = ""
ra(n, result, 0)
-when isMainModule:
+when not defined(testing) and isMainModule:
echo(renderSQL(parseSQL(newStringStream("""
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
CREATE TABLE holidays (
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index eb649a878c..c07b713de8 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -323,8 +323,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
i = j
when isMainModule:
- for k, v in interpolatedFragments("$test{} $this is ${an{ example}} "):
- echo "(", k, ", \"", v, "\")"
+ import sequtils
+ let input = "$test{} $this is ${an{ example}} "
+ let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
+ (ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
+ assert toSeq(interpolatedFragments(input)) == expected
+
var value = 0
discard parseHex("0x38", value)
assert value == 56
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 2663c5b2f4..eb792f0862 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -628,7 +628,7 @@ proc next*(my: var XmlParser) =
my.kind = xmlError
my.state = stateNormal
-when isMainModule:
+when not defined(testing) and isMainModule:
import os
var s = newFileStream(paramStr(1), fmRead)
if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/pegs.nimfix b/lib/pure/pegs.nimfix
deleted file mode 100644
index 15bc953511..0000000000
--- a/lib/pure/pegs.nimfix
+++ /dev/null
@@ -1,1770 +0,0 @@
-#
-#
-# Nim's Runtime Library
-# (c) Copyright 2012 Andreas Rumpf
-#
-# See the file "copying.txt", included in this
-# distribution, for details about the copyright.
-#
-
-## Simple PEG (Parsing expression grammar) matching. Uses no memorization, but
-## uses superoperators and symbol inlining to improve performance. Note:
-## Matching performance is hopefully competitive with optimized regular
-## expression engines.
-##
-## .. include:: ../doc/pegdocs.txt
-##
-
-include "system/inclrtl"
-
-const
- useUnicode = true ## change this to deactivate proper UTF-8 support
-
-import
- strutils
-
-when useUnicode:
- import unicode
-
-const
- InlineThreshold = 5 ## number of leaves; -1 to disable inlining
- MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that
- ## can be captured. More subpatterns cannot be captured!
-
-type
- PegKind = enum
- pkEmpty,
- pkAny, ## any character (.)
- pkAnyRune, ## any Unicode character (_)
- pkNewLine, ## CR-LF, LF, CR
- pkLetter, ## Unicode letter
- pkLower, ## Unicode lower case letter
- pkUpper, ## Unicode upper case letter
- pkTitle, ## Unicode title character
- pkWhitespace, ## Unicode whitespace character
- pkTerminal,
- pkTerminalIgnoreCase,
- pkTerminalIgnoreStyle,
- pkChar, ## single character to match
- pkCharChoice,
- pkNonTerminal,
- pkSequence, ## a b c ... --> Internal DSL: peg(a, b, c)
- pkOrderedChoice, ## a / b / ... --> Internal DSL: a / b or /[a, b, c]
- pkGreedyRep, ## a* --> Internal DSL: *a
- ## a+ --> (a a*)
- pkGreedyRepChar, ## x* where x is a single character (superop)
- pkGreedyRepSet, ## [set]* (superop)
- pkGreedyAny, ## .* or _* (superop)
- pkOption, ## a? --> Internal DSL: ?a
- pkAndPredicate, ## &a --> Internal DSL: &a
- pkNotPredicate, ## !a --> Internal DSL: !a
- pkCapture, ## {a} --> Internal DSL: capture(a)
- pkBackRef, ## $i --> Internal DSL: backref(i)
- pkBackRefIgnoreCase,
- pkBackRefIgnoreStyle,
- pkSearch, ## @a --> Internal DSL: !*a
- pkCapturedSearch, ## {@} a --> Internal DSL: !*\a
- pkRule, ## a <- b
- pkList, ## a, b
- pkStartAnchor ## ^ --> Internal DSL: startAnchor()
- NonTerminalFlag = enum
- ntDeclared, ntUsed
- NonTerminalObj = object ## represents a non terminal symbol
- name: string ## the name of the symbol
- line: int ## line the symbol has been declared/used in
- col: int ## column the symbol has been declared/used in
- flags: set[NonTerminalFlag] ## the nonterminal's flags
- rule: TNode ## the rule that the symbol refers to
- TNode {.shallow.} = object
- case kind: PegKind
- of pkEmpty..pkWhitespace: nil
- of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
- of pkChar, pkGreedyRepChar: ch: char
- of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
- of pkNonTerminal: nt: PNonTerminal
- of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
- else: sons: seq[TNode]
- PNonTerminal* = ref NonTerminalObj
- TPeg* = TNode
-
-block:
- type
- Peg = TNode
- NonTerminal = PNonTerminal
- {.deprecated: [TPeg: Peg, PNonTerminal: NonTerminal].}
-
-proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} =
- ## constructs a PEG from a terminal string
- if t.len != 1:
- result.kind = pkTerminal
- result.term = t
- else:
- result.kind = pkChar
- result.ch = t[0]
-
-proc termIgnoreCase*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a PEG from a terminal string; ignore case for matching
- result.kind = pkTerminalIgnoreCase
- result.term = t
-
-proc termIgnoreStyle*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a PEG from a terminal string; ignore style for matching
- result.kind = pkTerminalIgnoreStyle
- result.term = t
-
-proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} =
- ## constructs a PEG from a terminal char
- assert t != '\0'
- result.kind = pkChar
- result.ch = t
-
-proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a PEG from a character set `s`
- assert '\0' notin s
- result.kind = pkCharChoice
- new(result.charChoice)
- result.charChoice[] = s
-
-proc len(a: TPeg): int {.inline.} = return a.sons.len
-proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s)
-
-proc addChoice(dest: var TPeg, elem: TPeg) =
- var L = dest.len-1
- if L >= 0 and dest.sons[L].kind == pkCharChoice:
- # caution! Do not introduce false aliasing here!
- case elem.kind
- of pkCharChoice:
- dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
- of pkChar:
- dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
- else: add(dest, elem)
- else: add(dest, elem)
-
-template multipleOp(k: PegKind, localOpt: expr) =
- result.kind = k
- result.sons = @[]
- for x in items(a):
- if x.kind == k:
- for y in items(x.sons):
- localOpt(result, y)
- else:
- localOpt(result, x)
- if result.len == 1:
- result = result.sons[0]
-
-proc `/`*(a: varargs[TPeg]): TPeg {.
- nosideEffect, rtl, extern: "npegsOrderedChoice".} =
- ## constructs an ordered choice with the PEGs in `a`
- multipleOp(pkOrderedChoice, addChoice)
-
-proc addSequence(dest: var TPeg, elem: TPeg) =
- var L = dest.len-1
- if L >= 0 and dest.sons[L].kind == pkTerminal:
- # caution! Do not introduce false aliasing here!
- case elem.kind
- of pkTerminal:
- dest.sons[L] = term(dest.sons[L].term & elem.term)
- of pkChar:
- dest.sons[L] = term(dest.sons[L].term & elem.ch)
- else: add(dest, elem)
- else: add(dest, elem)
-
-proc sequence*(a: varargs[TPeg]): TPeg {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a sequence with all the PEGs from `a`
- multipleOp(pkSequence, addSequence)
-
-proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} =
- ## constructs an optional for the PEG `a`
- if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
- pkGreedyRepSet}:
- # a* ? --> a*
- # a? ? --> a?
- result = a
- else:
- result.kind = pkOption
- result.sons = @[a]
-
-proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
- ## constructs a "greedy repetition" for the PEG `a`
- case a.kind
- of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
- assert false
- # produces endless loop!
- of pkChar:
- result.kind = pkGreedyRepChar
- result.ch = a.ch
- of pkCharChoice:
- result.kind = pkGreedyRepSet
- result.charChoice = a.charChoice # copying a reference suffices!
- of pkAny, pkAnyRune:
- result.kind = pkGreedyAny
- else:
- result.kind = pkGreedyRep
- result.sons = @[a]
-
-proc `!*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} =
- ## constructs a "search" for the PEG `a`
- result.kind = pkSearch
- result.sons = @[a]
-
-proc `!*\`*(a: TPeg): TPeg {.noSideEffect, rtl,
- extern: "npgegsCapturedSearch".} =
- ## constructs a "captured search" for the PEG `a`
- result.kind = pkCapturedSearch
- result.sons = @[a]
-
-proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
- ## constructs a "greedy positive repetition" with the PEG `a`
- return sequence(a, *a)
-
-proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
- ## constructs an "and predicate" with the PEG `a`
- result.kind = pkAndPredicate
- result.sons = @[a]
-
-proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
- ## constructs a "not predicate" with the PEG `a`
- result.kind = pkNotPredicate
- result.sons = @[a]
-
-proc any*: TPeg {.inline.} =
- ## constructs the PEG `any character`:idx: (``.``)
- result.kind = pkAny
-
-proc anyRune*: TPeg {.inline.} =
- ## constructs the PEG `any rune`:idx: (``_``)
- result.kind = pkAnyRune
-
-proc newLine*: TPeg {.inline.} =
- ## constructs the PEG `newline`:idx: (``\n``)
- result.kind = pkNewLine
-
-proc unicodeLetter*: TPeg {.inline.} =
- ## constructs the PEG ``\letter`` which matches any Unicode letter.
- result.kind = pkLetter
-
-proc unicodeLower*: TPeg {.inline.} =
- ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
- result.kind = pkLower
-
-proc unicodeUpper*: TPeg {.inline.} =
- ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
- result.kind = pkUpper
-
-proc unicodeTitle*: TPeg {.inline.} =
- ## constructs the PEG ``\title`` which matches any Unicode title letter.
- result.kind = pkTitle
-
-proc unicodeWhitespace*: TPeg {.inline.} =
- ## constructs the PEG ``\white`` which matches any Unicode
- ## whitespace character.
- result.kind = pkWhitespace
-
-proc startAnchor*: TPeg {.inline.} =
- ## constructs the PEG ``^`` which matches the start of the input.
- result.kind = pkStartAnchor
-
-proc endAnchor*: TPeg {.inline.} =
- ## constructs the PEG ``$`` which matches the end of the input.
- result = !any()
-
-proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} =
- ## constructs a capture with the PEG `a`
- result.kind = pkCapture
- result.sons = @[a]
-
-proc backref*(index: range[1..MaxSubpatterns]): TPeg {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a back reference of the given `index`. `index` starts counting
- ## from 1.
- result.kind = pkBackRef
- result.index = index-1
-
-proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): TPeg {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a back reference of the given `index`. `index` starts counting
- ## from 1. Ignores case for matching.
- result.kind = pkBackRefIgnoreCase
- result.index = index-1
-
-proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): TPeg {.
- nosideEffect, rtl, extern: "npegs$1".}=
- ## constructs a back reference of the given `index`. `index` starts counting
- ## from 1. Ignores style for matching.
- result.kind = pkBackRefIgnoreStyle
- result.index = index-1
-
-proc spaceCost(n: TPeg): int =
- case n.kind
- of pkEmpty: discard
- of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
- pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
- pkAny..pkWhitespace, pkGreedyAny:
- result = 1
- of pkNonTerminal:
- # we cannot inline a rule with a non-terminal
- result = InlineThreshold+1
- else:
- for i in 0..n.len-1:
- inc(result, spaceCost(n.sons[i]))
- if result >= InlineThreshold: break
-
-proc nonterminal*(n: PNonTerminal): TPeg {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a PEG that consists of the nonterminal symbol
- assert n != nil
- if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
- when false: echo "inlining symbol: ", n.name
- result = n.rule # inlining of rule enables better optimizations
- else:
- result.kind = pkNonTerminal
- result.nt = n
-
-proc newNonTerminal*(name: string, line, column: int): PNonTerminal {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## constructs a nonterminal symbol
- new(result)
- result.name = name
- result.line = line
- result.col = column
-
-template letters*: expr =
- ## expands to ``charset({'A'..'Z', 'a'..'z'})``
- charSet({'A'..'Z', 'a'..'z'})
-
-template digits*: expr =
- ## expands to ``charset({'0'..'9'})``
- charSet({'0'..'9'})
-
-template whitespace*: expr =
- ## expands to ``charset({' ', '\9'..'\13'})``
- charSet({' ', '\9'..'\13'})
-
-template identChars*: expr =
- ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
- charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
-
-template identStartChars*: expr =
- ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
- charSet({'a'..'z', 'A'..'Z', '_'})
-
-template ident*: expr =
- ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
- sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
- *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
-
-template natural*: expr =
- ## same as ``\d+``
- +digits
-
-# ------------------------- debugging -----------------------------------------
-
-proc esc(c: char, reserved = {'\0'..'\255'}): string =
- case c
- of '\b': result = "\\b"
- of '\t': result = "\\t"
- of '\c': result = "\\c"
- of '\L': result = "\\l"
- of '\v': result = "\\v"
- of '\f': result = "\\f"
- of '\e': result = "\\e"
- of '\a': result = "\\a"
- of '\\': result = "\\\\"
- of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
- elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
- elif c in reserved: result = '\\' & c
- else: result = $c
-
-proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
-
-proc singleQuoteEsc(str: string): string =
- result = "'"
- for c in items(str): add result, esc(c, {'\''})
- add result, '\''
-
-proc charSetEscAux(cc: set[char]): string =
- const reserved = {'^', '-', ']'}
- result = ""
- var c1 = 0
- while c1 <= 0xff:
- if chr(c1) in cc:
- var c2 = c1
- while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
- if c1 == c2:
- add result, esc(chr(c1), reserved)
- elif c2 == succ(c1):
- add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
- else:
- add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
- c1 = c2
- inc(c1)
-
-proc charSetEsc(cc: set[char]): string =
- if card(cc) >= 128+64:
- result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
- else:
- result = '[' & charSetEscAux(cc) & ']'
-
-proc toStrAux(r: TPeg, res: var string) =
- case r.kind
- of pkEmpty: add(res, "()")
- of pkAny: add(res, '.')
- of pkAnyRune: add(res, '_')
- of pkLetter: add(res, "\\letter")
- of pkLower: add(res, "\\lower")
- of pkUpper: add(res, "\\upper")
- of pkTitle: add(res, "\\title")
- of pkWhitespace: add(res, "\\white")
-
- of pkNewLine: add(res, "\\n")
- of pkTerminal: add(res, singleQuoteEsc(r.term))
- of pkTerminalIgnoreCase:
- add(res, 'i')
- add(res, singleQuoteEsc(r.term))
- of pkTerminalIgnoreStyle:
- add(res, 'y')
- add(res, singleQuoteEsc(r.term))
- of pkChar: add(res, singleQuoteEsc(r.ch))
- of pkCharChoice: add(res, charSetEsc(r.charChoice[]))
- of pkNonTerminal: add(res, r.nt.name)
- of pkSequence:
- add(res, '(')
- toStrAux(r.sons[0], res)
- for i in 1 .. high(r.sons):
- add(res, ' ')
- toStrAux(r.sons[i], res)
- add(res, ')')
- of pkOrderedChoice:
- add(res, '(')
- toStrAux(r.sons[0], res)
- for i in 1 .. high(r.sons):
- add(res, " / ")
- toStrAux(r.sons[i], res)
- add(res, ')')
- of pkGreedyRep:
- toStrAux(r.sons[0], res)
- add(res, '*')
- of pkGreedyRepChar:
- add(res, singleQuoteEsc(r.ch))
- add(res, '*')
- of pkGreedyRepSet:
- add(res, charSetEsc(r.charChoice[]))
- add(res, '*')
- of pkGreedyAny:
- add(res, ".*")
- of pkOption:
- toStrAux(r.sons[0], res)
- add(res, '?')
- of pkAndPredicate:
- add(res, '&')
- toStrAux(r.sons[0], res)
- of pkNotPredicate:
- add(res, '!')
- toStrAux(r.sons[0], res)
- of pkSearch:
- add(res, '@')
- toStrAux(r.sons[0], res)
- of pkCapturedSearch:
- add(res, "{@}")
- toStrAux(r.sons[0], res)
- of pkCapture:
- add(res, '{')
- toStrAux(r.sons[0], res)
- add(res, '}')
- of pkBackRef:
- add(res, '$')
- add(res, $r.index)
- of pkBackRefIgnoreCase:
- add(res, "i$")
- add(res, $r.index)
- of pkBackRefIgnoreStyle:
- add(res, "y$")
- add(res, $r.index)
- of pkRule:
- toStrAux(r.sons[0], res)
- add(res, " <- ")
- toStrAux(r.sons[1], res)
- of pkList:
- for i in 0 .. high(r.sons):
- toStrAux(r.sons[i], res)
- add(res, "\n")
- of pkStartAnchor:
- add(res, '^')
-
-proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} =
- ## converts a PEG to its string representation
- result = ""
- toStrAux(r, result)
-
-# --------------------- core engine -------------------------------------------
-
-type
- Captures* = object ## contains the captured substrings.
- matches: array[0..MaxSubpatterns-1, tuple[first, last: int]]
- ml: int
- origStart: int
-
-{.deprecated: [TCaptures: Captures].}
-
-proc bounds*(c: Captures,
- i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
- ## returns the bounds ``[first..last]`` of the `i`'th capture.
- result = c.matches[i]
-
-when not useUnicode:
- type
- Rune = char
- template fastRuneAt(s, i, ch: expr) =
- ch = s[i]
- inc(i)
- template runeLenAt(s, i: expr): expr = 1
-
- proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'}
- proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'}
- proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'}
- proc isTitle(a: char): bool {.inline.} = return false
- proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
-
-proc rawMatch*(s: string, p: TPeg, start: int, c: var Captures): int {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## low-level matching proc that implements the PEG interpreter. Use this
- ## for maximum efficiency (every other PEG operation ends up calling this
- ## proc).
- ## Returns -1 if it does not match, else the length of the match
- case p.kind
- of pkEmpty: result = 0 # match of length 0
- of pkAny:
- if s[start] != '\0': result = 1
- else: result = -1
- of pkAnyRune:
- if s[start] != '\0':
- result = runeLenAt(s, start)
- else:
- result = -1
- of pkLetter:
- if s[start] != '\0':
- var a: Rune
- result = start
- fastRuneAt(s, result, a)
- if isAlpha(a): dec(result, start)
- else: result = -1
- else:
- result = -1
- of pkLower:
- if s[start] != '\0':
- var a: Rune
- result = start
- fastRuneAt(s, result, a)
- if isLower(a): dec(result, start)
- else: result = -1
- else:
- result = -1
- of pkUpper:
- if s[start] != '\0':
- var a: Rune
- result = start
- fastRuneAt(s, result, a)
- if isUpper(a): dec(result, start)
- else: result = -1
- else:
- result = -1
- of pkTitle:
- if s[start] != '\0':
- var a: Rune
- result = start
- fastRuneAt(s, result, a)
- if isTitle(a): dec(result, start)
- else: result = -1
- else:
- result = -1
- of pkWhitespace:
- if s[start] != '\0':
- var a: Rune
- result = start
- fastRuneAt(s, result, a)
- if isWhiteSpace(a): dec(result, start)
- else: result = -1
- else:
- result = -1
- of pkGreedyAny:
- result = len(s) - start
- of pkNewLine:
- if s[start] == '\L': result = 1
- elif s[start] == '\C':
- if s[start+1] == '\L': result = 2
- else: result = 1
- else: result = -1
- of pkTerminal:
- result = len(p.term)
- for i in 0..result-1:
- if p.term[i] != s[start+i]:
- result = -1
- break
- of pkTerminalIgnoreCase:
- var
- i = 0
- a, b: Rune
- result = start
- while i < len(p.term):
- fastRuneAt(p.term, i, a)
- fastRuneAt(s, result, b)
- if toLower(a) != toLower(b):
- result = -1
- break
- dec(result, start)
- of pkTerminalIgnoreStyle:
- var
- i = 0
- a, b: Rune
- result = start
- while i < len(p.term):
- while true:
- fastRuneAt(p.term, i, a)
- if a != Rune('_'): break
- while true:
- fastRuneAt(s, result, b)
- if b != Rune('_'): break
- if toLower(a) != toLower(b):
- result = -1
- break
- dec(result, start)
- of pkChar:
- if p.ch == s[start]: result = 1
- else: result = -1
- of pkCharChoice:
- if contains(p.charChoice[], s[start]): result = 1
- else: result = -1
- of pkNonTerminal:
- var oldMl = c.ml
- when false: echo "enter: ", p.nt.name
- result = rawMatch(s, p.nt.rule, start, c)
- when false: echo "leave: ", p.nt.name
- if result < 0: c.ml = oldMl
- of pkSequence:
- var oldMl = c.ml
- result = 0
- for i in 0..high(p.sons):
- var x = rawMatch(s, p.sons[i], start+result, c)
- if x < 0:
- c.ml = oldMl
- result = -1
- break
- else: inc(result, x)
- of pkOrderedChoice:
- var oldMl = c.ml
- for i in 0..high(p.sons):
- result = rawMatch(s, p.sons[i], start, c)
- if result >= 0: break
- c.ml = oldMl
- of pkSearch:
- var oldMl = c.ml
- result = 0
- while start+result < s.len:
- var x = rawMatch(s, p.sons[0], start+result, c)
- if x >= 0:
- inc(result, x)
- return
- inc(result)
- result = -1
- c.ml = oldMl
- of pkCapturedSearch:
- var idx = c.ml # reserve a slot for the subpattern
- inc(c.ml)
- result = 0
- while start+result < s.len:
- var x = rawMatch(s, p.sons[0], start+result, c)
- if x >= 0:
- if idx < MaxSubpatterns:
- c.matches[idx] = (start, start+result-1)
- #else: silently ignore the capture
- inc(result, x)
- return
- inc(result)
- result = -1
- c.ml = idx
- of pkGreedyRep:
- result = 0
- while true:
- var x = rawMatch(s, p.sons[0], start+result, c)
- # if x == 0, we have an endless loop; so the correct behaviour would be
- # not to break. But endless loops can be easily introduced:
- # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
- # expected thing in this case.
- if x <= 0: break
- inc(result, x)
- of pkGreedyRepChar:
- result = 0
- var ch = p.ch
- while ch == s[start+result]: inc(result)
- of pkGreedyRepSet:
- result = 0
- while contains(p.charChoice[], s[start+result]): inc(result)
- of pkOption:
- result = max(0, rawMatch(s, p.sons[0], start, c))
- of pkAndPredicate:
- var oldMl = c.ml
- result = rawMatch(s, p.sons[0], start, c)
- if result >= 0: result = 0 # do not consume anything
- else: c.ml = oldMl
- of pkNotPredicate:
- var oldMl = c.ml
- result = rawMatch(s, p.sons[0], start, c)
- if result < 0: result = 0
- else:
- c.ml = oldMl
- result = -1
- of pkCapture:
- var idx = c.ml # reserve a slot for the subpattern
- inc(c.ml)
- result = rawMatch(s, p.sons[0], start, c)
- if result >= 0:
- if idx < MaxSubpatterns:
- c.matches[idx] = (start, start+result-1)
- #else: silently ignore the capture
- else:
- c.ml = idx
- of pkBackRef..pkBackRefIgnoreStyle:
- if p.index >= c.ml: return -1
- var (a, b) = c.matches[p.index]
- var n: TPeg
- n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
- n.term = s.substr(a, b)
- result = rawMatch(s, n, start, c)
- of pkStartAnchor:
- if c.origStart == start: result = 0
- else: result = -1
- of pkRule, pkList: assert false
-
-template fillMatches(s, caps, c: expr) =
- for k in 0..c.ml-1:
- caps[k] = substr(s, c.matches[k][0], c.matches[k][1])
-
-proc match*(s: string, pattern: TPeg, matches: var openArray[string],
- start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
- ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
- ## the captured substrings in the array ``matches``. If it does not
- ## match, nothing is written into ``matches`` and ``false`` is
- ## returned.
- var c: Captures
- c.origStart = start
- result = rawMatch(s, pattern, start, c) == len(s) - start
- if result: fillMatches(s, matches, c)
-
-proc match*(s: string, pattern: TPeg,
- start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
- ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
- var c: Captures
- c.origStart = start
- result = rawMatch(s, pattern, start, c) == len(s)-start
-
-proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string],
- start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
- ## the same as ``match``, but it returns the length of the match,
- ## if there is no match, -1 is returned. Note that a match length
- ## of zero can happen. It's possible that a suffix of `s` remains
- ## that does not belong to the match.
- var c: Captures
- c.origStart = start
- result = rawMatch(s, pattern, start, c)
- if result >= 0: fillMatches(s, matches, c)
-
-proc matchLen*(s: string, pattern: TPeg,
- start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
- ## the same as ``match``, but it returns the length of the match,
- ## if there is no match, -1 is returned. Note that a match length
- ## of zero can happen. It's possible that a suffix of `s` remains
- ## that does not belong to the match.
- var c: Captures
- c.origStart = start
- result = rawMatch(s, pattern, start, c)
-
-proc find*(s: string, pattern: TPeg, matches: var openArray[string],
- start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
- ## returns the starting position of ``pattern`` in ``s`` and the captured
- ## substrings in the array ``matches``. If it does not match, nothing
- ## is written into ``matches`` and -1 is returned.
- var c: Captures
- c.origStart = start
- for i in start .. s.len-1:
- c.ml = 0
- if rawMatch(s, pattern, i, c) >= 0:
- fillMatches(s, matches, c)
- return i
- return -1
- # could also use the pattern here: (!P .)* P
-
-proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string],
- start = 0): tuple[first, last: int] {.
- nosideEffect, rtl, extern: "npegs$1Capture".} =
- ## returns the starting position and end position of ``pattern`` in ``s``
- ## and the captured
- ## substrings in the array ``matches``. If it does not match, nothing
- ## is written into ``matches`` and (-1,0) is returned.
- var c: Captures
- c.origStart = start
- for i in start .. s.len-1:
- c.ml = 0
- var L = rawMatch(s, pattern, i, c)
- if L >= 0:
- fillMatches(s, matches, c)
- return (i, i+L-1)
- return (-1, 0)
-
-proc find*(s: string, pattern: TPeg,
- start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
- ## returns the starting position of ``pattern`` in ``s``. If it does not
- ## match, -1 is returned.
- var c: Captures
- c.origStart = start
- for i in start .. s.len-1:
- if rawMatch(s, pattern, i, c) >= 0: return i
- return -1
-
-iterator findAll*(s: string, pattern: TPeg, start = 0): string =
- ## yields all matching *substrings* of `s` that match `pattern`.
- var c: Captures
- c.origStart = start
- var i = start
- while i < s.len:
- c.ml = 0
- var L = rawMatch(s, pattern, i, c)
- if L < 0:
- inc(i, 1)
- else:
- yield substr(s, i, i+L-1)
- inc(i, L)
-
-proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## returns all matching *substrings* of `s` that match `pattern`.
- ## If it does not match, @[] is returned.
- accumulateResult(findAll(s, pattern, start))
-
-when not defined(nimhygiene):
- {.pragma: inject.}
-
-template `=~`*(s: string, pattern: TPeg): bool =
- ## This calls ``match`` with an implicit declared ``matches`` array that
- ## can be used in the scope of the ``=~`` call:
- ##
- ## .. code-block:: nim
- ##
- ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
- ## # matches a key=value pair:
- ## echo("Key: ", matches[0])
- ## echo("Value: ", matches[1])
- ## elif line =~ peg"\s*{'#'.*}":
- ## # matches a comment
- ## # note that the implicit ``matches`` array is different from the
- ## # ``matches`` array of the first branch
- ## echo("comment: ", matches[0])
- ## else:
- ## echo("syntax error")
- ##
- bind MaxSubpatterns
- when not declaredInScope(matches):
- var matches {.inject.}: array[0..MaxSubpatterns-1, string]
- match(s, pattern, matches)
-
-# ------------------------- more string handling ------------------------------
-
-proc contains*(s: string, pattern: TPeg, start = 0): bool {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## same as ``find(s, pattern, start) >= 0``
- return find(s, pattern, start) >= 0
-
-proc contains*(s: string, pattern: TPeg, matches: var openArray[string],
- start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
- ## same as ``find(s, pattern, matches, start) >= 0``
- return find(s, pattern, matches, start) >= 0
-
-proc startsWith*(s: string, prefix: TPeg, start = 0): bool {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## returns true if `s` starts with the pattern `prefix`
- result = matchLen(s, prefix, start) >= 0
-
-proc endsWith*(s: string, suffix: TPeg, start = 0): bool {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## returns true if `s` ends with the pattern `prefix`
- var c: Captures
- c.origStart = start
- for i in start .. s.len-1:
- if rawMatch(s, suffix, i, c) == s.len - i: return true
-
-proc replacef*(s: string, sub: TPeg, by: string): string {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
- ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
- ##
- ## .. code-block:: nim
- ## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
- ##
- ## Results in:
- ##
- ## .. code-block:: nim
- ##
- ## "var1<-keykey; val2<-key2key2"
- result = ""
- var i = 0
- var caps: array[0..MaxSubpatterns-1, string]
- var c: Captures
- while i < s.len:
- c.ml = 0
- var x = rawMatch(s, sub, i, c)
- if x <= 0:
- add(result, s[i])
- inc(i)
- else:
- fillMatches(s, caps, c)
- addf(result, by, caps)
- inc(i, x)
- add(result, substr(s, i))
-
-proc replace*(s: string, sub: TPeg, by = ""): string {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed
- ## in `by`.
- result = ""
- var i = 0
- var c: Captures
- while i < s.len:
- var x = rawMatch(s, sub, i, c)
- if x <= 0:
- add(result, s[i])
- inc(i)
- else:
- add(result, by)
- inc(i, x)
- add(result, substr(s, i))
-
-proc parallelReplace*(s: string, subs: varargs[
- tuple[pattern: TPeg, repl: string]]): string {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## Returns a modified copy of `s` with the substitutions in `subs`
- ## applied in parallel.
- result = ""
- var i = 0
- var c: Captures
- var caps: array[0..MaxSubpatterns-1, string]
- while i < s.len:
- block searchSubs:
- for j in 0..high(subs):
- c.ml = 0
- var x = rawMatch(s, subs[j][0], i, c)
- if x > 0:
- fillMatches(s, caps, c)
- addf(result, subs[j][1], caps)
- inc(i, x)
- break searchSubs
- add(result, s[i])
- inc(i)
- # copy the rest:
- add(result, substr(s, i))
-
-proc transformFile*(infile, outfile: string,
- subs: varargs[tuple[pattern: TPeg, repl: string]]) {.
- rtl, extern: "npegs$1".} =
- ## reads in the file `infile`, performs a parallel replacement (calls
- ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
- ## error occurs. This is supposed to be used for quick scripting.
- var x = readFile(infile).string
- writeFile(outfile, x.parallelReplace(subs))
-
-iterator split*(s: string, sep: TPeg): string =
- ## Splits the string `s` into substrings.
- ##
- ## Substrings are separated by the PEG `sep`.
- ## Examples:
- ##
- ## .. code-block:: nim
- ## for word in split("00232this02939is39an22example111", peg"\d+"):
- ## writeln(stdout, word)
- ##
- ## Results in:
- ##
- ## .. code-block:: nim
- ## "this"
- ## "is"
- ## "an"
- ## "example"
- ##
- var c: Captures
- var
- first = 0
- last = 0
- while last < len(s):
- c.ml = 0
- var x = rawMatch(s, sep, last, c)
- if x > 0: inc(last, x)
- first = last
- while last < len(s):
- inc(last)
- c.ml = 0
- x = rawMatch(s, sep, last, c)
- if x > 0: break
- if first < last:
- yield substr(s, first, last-1)
-
-proc split*(s: string, sep: TPeg): seq[string] {.
- nosideEffect, rtl, extern: "npegs$1".} =
- ## Splits the string `s` into substrings.
- accumulateResult(split(s, sep))
-
-# ------------------- scanner -------------------------------------------------
-
-type
- TModifier = enum
- modNone,
- modVerbatim,
- modIgnoreCase,
- modIgnoreStyle
- TTokKind = enum ## enumeration of all tokens
- tkInvalid, ## invalid token
- tkEof, ## end of file reached
- tkAny, ## .
- tkAnyRune, ## _
- tkIdentifier, ## abc
- tkStringLit, ## "abc" or 'abc'
- tkCharSet, ## [^A-Z]
- tkParLe, ## '('
- tkParRi, ## ')'
- tkCurlyLe, ## '{'
- tkCurlyRi, ## '}'
- tkCurlyAt, ## '{@}'
- tkArrow, ## '<-'
- tkBar, ## '/'
- tkStar, ## '*'
- tkPlus, ## '+'
- tkAmp, ## '&'
- tkNot, ## '!'
- tkOption, ## '?'
- tkAt, ## '@'
- tkBuiltin, ## \identifier
- tkEscaped, ## \\
- tkBackref, ## '$'
- tkDollar, ## '$'
- tkHat ## '^'
-
- TToken {.final.} = object ## a token
- kind: TTokKind ## the type of the token
- modifier: TModifier
- literal: string ## the parsed (string) literal
- charset: set[char] ## if kind == tkCharSet
- index: int ## if kind == tkBackref
-
- PegLexer {.inheritable.} = object ## the lexer object.
- bufpos: int ## the current position within the buffer
- buf: cstring ## the buffer itself
- lineNumber: int ## the current line number
- lineStart: int ## index of last line start in buffer
- colOffset: int ## column to add
- filename: string
-
-const
- tokKindToStr: array[TTokKind, string] = [
- "invalid", "[EOF]", ".", "_", "identifier", "string literal",
- "character set", "(", ")", "{", "}", "{@}",
- "<-", "/", "*", "+", "&", "!", "?",
- "@", "built-in", "escaped", "$", "$", "^"
- ]
-
-proc handleCR(L: var PegLexer, pos: int): int =
- assert(L.buf[pos] == '\c')
- inc(L.lineNumber)
- result = pos+1
- if L.buf[result] == '\L': inc(result)
- L.lineStart = result
-
-proc handleLF(L: var PegLexer, pos: int): int =
- assert(L.buf[pos] == '\L')
- inc(L.lineNumber)
- result = pos+1
- L.lineStart = result
-
-proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
- L.buf = input
- L.bufpos = 0
- L.lineNumber = line
- L.colOffset = col
- L.lineStart = 0
- L.filename = filename
-
-proc getColumn(L: PegLexer): int {.inline.} =
- result = abs(L.bufpos - L.lineStart) + L.colOffset
-
-proc getLine(L: PegLexer): int {.inline.} =
- result = L.lineNumber
-
-proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
- var line = if line < 0: getLine(L) else: line
- var col = if col < 0: getColumn(L) else: col
- result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
-
-proc handleHexChar(c: var PegLexer, xi: var int) =
- case c.buf[c.bufpos]
- of '0'..'9':
- xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
- inc(c.bufpos)
- of 'a'..'f':
- xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
- inc(c.bufpos)
- of 'A'..'F':
- xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
- inc(c.bufpos)
- else: discard
-
-proc getEscapedChar(c: var PegLexer, tok: var TToken) =
- inc(c.bufpos)
- case c.buf[c.bufpos]
- of 'r', 'R', 'c', 'C':
- add(tok.literal, '\c')
- inc(c.bufpos)
- of 'l', 'L':
- add(tok.literal, '\L')
- inc(c.bufpos)
- of 'f', 'F':
- add(tok.literal, '\f')
- inc(c.bufpos)
- of 'e', 'E':
- add(tok.literal, '\e')
- inc(c.bufpos)
- of 'a', 'A':
- add(tok.literal, '\a')
- inc(c.bufpos)
- of 'b', 'B':
- add(tok.literal, '\b')
- inc(c.bufpos)
- of 'v', 'V':
- add(tok.literal, '\v')
- inc(c.bufpos)
- of 't', 'T':
- add(tok.literal, '\t')
- inc(c.bufpos)
- of 'x', 'X':
- inc(c.bufpos)
- var xi = 0
- handleHexChar(c, xi)
- handleHexChar(c, xi)
- if xi == 0: tok.kind = tkInvalid
- else: add(tok.literal, chr(xi))
- of '0'..'9':
- var val = ord(c.buf[c.bufpos]) - ord('0')
- inc(c.bufpos)
- var i = 1
- while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
- val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
- inc(c.bufpos)
- inc(i)
- if val > 0 and val <= 255: add(tok.literal, chr(val))
- else: tok.kind = tkInvalid
- of '\0'..'\31':
- tok.kind = tkInvalid
- elif c.buf[c.bufpos] in strutils.Letters:
- tok.kind = tkInvalid
- else:
- add(tok.literal, c.buf[c.bufpos])
- inc(c.bufpos)
-
-proc skip(c: var PegLexer) =
- var pos = c.bufpos
- var buf = c.buf
- while true:
- case buf[pos]
- of ' ', '\t':
- inc(pos)
- of '#':
- while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
- of '\c':
- pos = handleCR(c, pos)
- buf = c.buf
- of '\L':
- pos = handleLF(c, pos)
- buf = c.buf
- else:
- break # EndOfFile also leaves the loop
- c.bufpos = pos
-
-proc getString(c: var PegLexer, tok: var TToken) =
- tok.kind = tkStringLit
- var pos = c.bufpos + 1
- var buf = c.buf
- var quote = buf[pos-1]
- while true:
- case buf[pos]
- of '\\':
- c.bufpos = pos
- getEscapedChar(c, tok)
- pos = c.bufpos
- of '\c', '\L', '\0':
- tok.kind = tkInvalid
- break
- elif buf[pos] == quote:
- inc(pos)
- break
- else:
- add(tok.literal, buf[pos])
- inc(pos)
- c.bufpos = pos
-
-proc getDollar(c: var PegLexer, tok: var TToken) =
- var pos = c.bufpos + 1
- var buf = c.buf
- if buf[pos] in {'0'..'9'}:
- tok.kind = tkBackref
- tok.index = 0
- while buf[pos] in {'0'..'9'}:
- tok.index = tok.index * 10 + ord(buf[pos]) - ord('0')
- inc(pos)
- else:
- tok.kind = tkDollar
- c.bufpos = pos
-
-proc getCharSet(c: var PegLexer, tok: var TToken) =
- tok.kind = tkCharSet
- tok.charset = {}
- var pos = c.bufpos + 1
- var buf = c.buf
- var caret = false
- if buf[pos] == '^':
- inc(pos)
- caret = true
- while true:
- var ch: char
- case buf[pos]
- of ']':
- inc(pos)
- break
- of '\\':
- c.bufpos = pos
- getEscapedChar(c, tok)
- pos = c.bufpos
- ch = tok.literal[tok.literal.len-1]
- of '\C', '\L', '\0':
- tok.kind = tkInvalid
- break
- else:
- ch = buf[pos]
- inc(pos)
- incl(tok.charset, ch)
- if buf[pos] == '-':
- if buf[pos+1] == ']':
- incl(tok.charset, '-')
- inc(pos)
- else:
- inc(pos)
- var ch2: char
- case buf[pos]
- of '\\':
- c.bufpos = pos
- getEscapedChar(c, tok)
- pos = c.bufpos
- ch2 = tok.literal[tok.literal.len-1]
- of '\C', '\L', '\0':
- tok.kind = tkInvalid
- break
- else:
- ch2 = buf[pos]
- inc(pos)
- for i in ord(ch)+1 .. ord(ch2):
- incl(tok.charset, chr(i))
- c.bufpos = pos
- if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
-
-proc getSymbol(c: var PegLexer, tok: var TToken) =
- var pos = c.bufpos
- var buf = c.buf
- while true:
- add(tok.literal, buf[pos])
- inc(pos)
- if buf[pos] notin strutils.IdentChars: break
- c.bufpos = pos
- tok.kind = tkIdentifier
-
-proc getBuiltin(c: var PegLexer, tok: var TToken) =
- if c.buf[c.bufpos+1] in strutils.Letters:
- inc(c.bufpos)
- getSymbol(c, tok)
- tok.kind = tkBuiltin
- else:
- tok.kind = tkEscaped
- getEscapedChar(c, tok) # may set tok.kind to tkInvalid
-
-proc getTok(c: var PegLexer, tok: var TToken) =
- tok.kind = tkInvalid
- tok.modifier = modNone
- setLen(tok.literal, 0)
- skip(c)
- case c.buf[c.bufpos]
- of '{':
- inc(c.bufpos)
- if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}':
- tok.kind = tkCurlyAt
- inc(c.bufpos, 2)
- add(tok.literal, "{@}")
- else:
- tok.kind = tkCurlyLe
- add(tok.literal, '{')
- of '}':
- tok.kind = tkCurlyRi
- inc(c.bufpos)
- add(tok.literal, '}')
- of '[':
- getCharSet(c, tok)
- of '(':
- tok.kind = tkParLe
- inc(c.bufpos)
- add(tok.literal, '(')
- of ')':
- tok.kind = tkParRi
- inc(c.bufpos)
- add(tok.literal, ')')
- of '.':
- tok.kind = tkAny
- inc(c.bufpos)
- add(tok.literal, '.')
- of '_':
- tok.kind = tkAnyRune
- inc(c.bufpos)
- add(tok.literal, '_')
- of '\\':
- getBuiltin(c, tok)
- of '\'', '"': getString(c, tok)
- of '$': getDollar(c, tok)
- of '\0':
- tok.kind = tkEof
- tok.literal = "[EOF]"
- of 'a'..'z', 'A'..'Z', '\128'..'\255':
- getSymbol(c, tok)
- if c.buf[c.bufpos] in {'\'', '"'} or
- c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
- case tok.literal
- of "i": tok.modifier = modIgnoreCase
- of "y": tok.modifier = modIgnoreStyle
- of "v": tok.modifier = modVerbatim
- else: discard
- setLen(tok.literal, 0)
- if c.buf[c.bufpos] == '$':
- getDollar(c, tok)
- else:
- getString(c, tok)
- if tok.modifier == modNone: tok.kind = tkInvalid
- of '+':
- tok.kind = tkPlus
- inc(c.bufpos)
- add(tok.literal, '+')
- of '*':
- tok.kind = tkStar
- inc(c.bufpos)
- add(tok.literal, '+')
- of '<':
- if c.buf[c.bufpos+1] == '-':
- inc(c.bufpos, 2)
- tok.kind = tkArrow
- add(tok.literal, "<-")
- else:
- add(tok.literal, '<')
- of '/':
- tok.kind = tkBar
- inc(c.bufpos)
- add(tok.literal, '/')
- of '?':
- tok.kind = tkOption
- inc(c.bufpos)
- add(tok.literal, '?')
- of '!':
- tok.kind = tkNot
- inc(c.bufpos)
- add(tok.literal, '!')
- of '&':
- tok.kind = tkAmp
- inc(c.bufpos)
- add(tok.literal, '!')
- of '@':
- tok.kind = tkAt
- inc(c.bufpos)
- add(tok.literal, '@')
- if c.buf[c.bufpos] == '@':
- tok.kind = tkCurlyAt
- inc(c.bufpos)
- add(tok.literal, '@')
- of '^':
- tok.kind = tkHat
- inc(c.bufpos)
- add(tok.literal, '^')
- else:
- add(tok.literal, c.buf[c.bufpos])
- inc(c.bufpos)
-
-proc arrowIsNextTok(c: PegLexer): bool =
- # the only look ahead we need
- var pos = c.bufpos
- while c.buf[pos] in {'\t', ' '}: inc(pos)
- result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
-
-# ----------------------------- parser ----------------------------------------
-
-type
- EInvalidPeg* = object of ValueError ## raised if an invalid
- ## PEG has been detected
- PegParser = object of PegLexer ## the PEG parser object
- tok: TToken
- nonterms: seq[PNonTerminal]
- modifier: TModifier
- captures: int
- identIsVerbatim: bool
- skip: TPeg
-
-proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
- var e: ref EInvalidPeg
- new(e)
- e.msg = errorStr(p, msg, line, col)
- raise e
-
-proc getTok(p: var PegParser) =
- getTok(p, p.tok)
- if p.tok.kind == tkInvalid: pegError(p, "invalid token")
-
-proc eat(p: var PegParser, kind: TTokKind) =
- if p.tok.kind == kind: getTok(p)
- else: pegError(p, tokKindToStr[kind] & " expected")
-
-proc parseExpr(p: var PegParser): TPeg
-
-proc getNonTerminal(p: var PegParser, name: string): PNonTerminal =
- for i in 0..high(p.nonterms):
- result = p.nonterms[i]
- if cmpIgnoreStyle(result.name, name) == 0: return
- # forward reference:
- result = newNonTerminal(name, getLine(p), getColumn(p))
- add(p.nonterms, result)
-
-proc modifiedTerm(s: string, m: TModifier): TPeg =
- case m
- of modNone, modVerbatim: result = term(s)
- of modIgnoreCase: result = termIgnoreCase(s)
- of modIgnoreStyle: result = termIgnoreStyle(s)
-
-proc modifiedBackref(s: int, m: TModifier): TPeg =
- case m
- of modNone, modVerbatim: result = backref(s)
- of modIgnoreCase: result = backrefIgnoreCase(s)
- of modIgnoreStyle: result = backrefIgnoreStyle(s)
-
-proc builtin(p: var PegParser): TPeg =
- # do not use "y", "skip" or "i" as these would be ambiguous
- case p.tok.literal
- of "n": result = newLine()
- of "d": result = charSet({'0'..'9'})
- of "D": result = charSet({'\1'..'\xff'} - {'0'..'9'})
- of "s": result = charSet({' ', '\9'..'\13'})
- of "S": result = charSet({'\1'..'\xff'} - {' ', '\9'..'\13'})
- of "w": result = charSet({'a'..'z', 'A'..'Z', '_', '0'..'9'})
- of "W": result = charSet({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
- of "a": result = charSet({'a'..'z', 'A'..'Z'})
- of "A": result = charSet({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
- of "ident": result = pegs.ident
- of "letter": result = unicodeLetter()
- of "upper": result = unicodeUpper()
- of "lower": result = unicodeLower()
- of "title": result = unicodeTitle()
- of "white": result = unicodeWhitespace()
- else: pegError(p, "unknown built-in: " & p.tok.literal)
-
-proc token(terminal: TPeg, p: PegParser): TPeg =
- if p.skip.kind == pkEmpty: result = terminal
- else: result = sequence(p.skip, terminal)
-
-proc primary(p: var PegParser): TPeg =
- case p.tok.kind
- of tkAmp:
- getTok(p)
- return &primary(p)
- of tkNot:
- getTok(p)
- return !primary(p)
- of tkAt:
- getTok(p)
- return !*primary(p)
- of tkCurlyAt:
- getTok(p)
- return !*\primary(p).token(p)
- else: discard
- case p.tok.kind
- of tkIdentifier:
- if p.identIsVerbatim:
- var m = p.tok.modifier
- if m == modNone: m = p.modifier
- result = modifiedTerm(p.tok.literal, m).token(p)
- getTok(p)
- elif not arrowIsNextTok(p):
- var nt = getNonTerminal(p, p.tok.literal)
- incl(nt.flags, ntUsed)
- result = nonterminal(nt).token(p)
- getTok(p)
- else:
- pegError(p, "expression expected, but found: " & p.tok.literal)
- of tkStringLit:
- var m = p.tok.modifier
- if m == modNone: m = p.modifier
- result = modifiedTerm(p.tok.literal, m).token(p)
- getTok(p)
- of tkCharSet:
- if '\0' in p.tok.charset:
- pegError(p, "binary zero ('\\0') not allowed in character class")
- result = charSet(p.tok.charset).token(p)
- getTok(p)
- of tkParLe:
- getTok(p)
- result = parseExpr(p)
- eat(p, tkParRi)
- of tkCurlyLe:
- getTok(p)
- result = capture(parseExpr(p)).token(p)
- eat(p, tkCurlyRi)
- inc(p.captures)
- of tkAny:
- result = any().token(p)
- getTok(p)
- of tkAnyRune:
- result = anyRune().token(p)
- getTok(p)
- of tkBuiltin:
- result = builtin(p).token(p)
- getTok(p)
- of tkEscaped:
- result = term(p.tok.literal[0]).token(p)
- getTok(p)
- of tkDollar:
- result = endAnchor()
- getTok(p)
- of tkHat:
- result = startAnchor()
- getTok(p)
- of tkBackref:
- var m = p.tok.modifier
- if m == modNone: m = p.modifier
- result = modifiedBackref(p.tok.index, m).token(p)
- if p.tok.index < 0 or p.tok.index > p.captures:
- pegError(p, "invalid back reference index: " & $p.tok.index)
- getTok(p)
- else:
- pegError(p, "expression expected, but found: " & p.tok.literal)
- getTok(p) # we must consume a token here to prevent endless loops!
- while true:
- case p.tok.kind
- of tkOption:
- result = ?result
- getTok(p)
- of tkStar:
- result = *result
- getTok(p)
- of tkPlus:
- result = +result
- getTok(p)
- else: break
-
-proc seqExpr(p: var PegParser): TPeg =
- result = primary(p)
- while true:
- case p.tok.kind
- of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
- tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
- tkHat, tkCurlyAt:
- result = sequence(result, primary(p))
- of tkIdentifier:
- if not arrowIsNextTok(p):
- result = sequence(result, primary(p))
- else: break
- else: break
-
-proc parseExpr(p: var PegParser): TPeg =
- result = seqExpr(p)
- while p.tok.kind == tkBar:
- getTok(p)
- result = result / seqExpr(p)
-
-proc parseRule(p: var PegParser): PNonTerminal =
- if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
- result = getNonTerminal(p, p.tok.literal)
- if ntDeclared in result.flags:
- pegError(p, "attempt to redefine: " & result.name)
- result.line = getLine(p)
- result.col = getColumn(p)
- getTok(p)
- eat(p, tkArrow)
- result.rule = parseExpr(p)
- incl(result.flags, ntDeclared) # NOW inlining may be attempted
- else:
- pegError(p, "rule expected, but found: " & p.tok.literal)
-
-proc rawParse(p: var PegParser): TPeg =
- ## parses a rule or a PEG expression
- while p.tok.kind == tkBuiltin:
- case p.tok.literal
- of "i":
- p.modifier = modIgnoreCase
- getTok(p)
- of "y":
- p.modifier = modIgnoreStyle
- getTok(p)
- of "skip":
- getTok(p)
- p.skip = ?primary(p)
- else: break
- if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
- result = parseRule(p).rule
- while p.tok.kind != tkEof:
- discard parseRule(p)
- else:
- p.identIsVerbatim = true
- result = parseExpr(p)
- if p.tok.kind != tkEof:
- pegError(p, "EOF expected, but found: " & p.tok.literal)
- for i in 0..high(p.nonterms):
- var nt = p.nonterms[i]
- if ntDeclared notin nt.flags:
- pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col)
- elif ntUsed notin nt.flags and i > 0:
- pegError(p, "unused rule: " & nt.name, nt.line, nt.col)
-
-proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg =
- ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are
- ## used for error messages, but they only provide start offsets. `parsePeg`
- ## keeps track of line and column numbers within `pattern`.
- var p: PegParser
- init(PegLexer(p), pattern, filename, line, col)
- p.tok.kind = tkInvalid
- p.tok.modifier = modNone
- p.tok.literal = ""
- p.tok.charset = {}
- p.nonterms = @[]
- p.identIsVerbatim = false
- getTok(p)
- result = rawParse(p)
-
-proc peg*(pattern: string): TPeg =
- ## constructs a Peg object from the `pattern`. The short name has been
- ## chosen to encourage its use as a raw string modifier::
- ##
- ## peg"{\ident} \s* '=' \s* {.*}"
- result = parsePeg(pattern, "pattern")
-
-proc escapePeg*(s: string): string =
- ## escapes `s` so that it is matched verbatim when used as a peg.
- result = ""
- var inQuote = false
- for c in items(s):
- case c
- of '\0'..'\31', '\'', '"', '\\':
- if inQuote:
- result.add('\'')
- inQuote = false
- result.add("\\x")
- result.add(toHex(ord(c), 2))
- else:
- if not inQuote:
- result.add('\'')
- inQuote = true
- result.add(c)
- if inQuote: result.add('\'')
-
-when isMainModule:
- assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
- assert match("(a b c)", peg"'(' @ ')'")
- assert match("W_HI_Le", peg"\y 'while'")
- assert(not match("W_HI_L", peg"\y 'while'"))
- assert(not match("W_HI_Le", peg"\y v'while'"))
- assert match("W_HI_Le", peg"y'while'")
-
- assert($ +digits == $peg"\d+")
- assert "0158787".match(peg"\d+")
- assert "ABC 0232".match(peg"\w+\s+\d+")
- assert "ABC".match(peg"\d+ / \w+")
-
- for word in split("00232this02939is39an22example111", peg"\d+"):
- writeln(stdout, word)
-
- assert matchLen("key", ident) == 3
-
- var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
- assert matchLen("key1= cal9", pattern) == 11
-
- var ws = newNonTerminal("ws", 1, 1)
- ws.rule = *whitespace
-
- var expr = newNonTerminal("expr", 1, 1)
- expr.rule = sequence(capture(ident), *sequence(
- nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
-
- var c: Captures
- var s = "a+b + c +d+e+f"
- assert rawMatch(s, expr.rule, 0, c) == len(s)
- var a = ""
- for i in 0..c.ml-1:
- a.add(substr(s, c.matches[i][0], c.matches[i][1]))
- assert a == "abcdef"
- #echo expr.rule
-
- #const filename = "lib/devel/peg/grammar.txt"
- #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
- #echo "a <- [abc]*?".match(grammar)
- assert find("_____abc_______", term("abc"), 2) == 5
- assert match("_______ana", peg"A <- 'ana' / . A")
- assert match("abcs%%%", peg"A <- ..A / .A / '%'")
-
- var matches: array[0..MaxSubpatterns-1, string]
- if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
- assert matches[0] == "abc"
- else:
- assert false
-
- var g2 = peg"""S <- A B / C D
- A <- 'a'+
- B <- 'b'+
- C <- 'c'+
- D <- 'd'+
- """
- assert($g2 == "((A B) / (C D))")
- assert match("cccccdddddd", g2)
- assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
- "var1<-keykey; var2<-key2key2")
- assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
- "$1<-$2$2; $1<-$2$2")
- assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
-
- if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
- assert matches[0] == "a"
- else:
- assert false
-
- if match("abcdefg", peg"c {d} ef {g}", matches, 2):
- assert matches[0] == "d"
- assert matches[1] == "g"
- else:
- assert false
-
- for x in findAll("abcdef", peg".", 3):
- echo x
-
- for x in findAll("abcdef", peg"^{.}", 3):
- assert x == "d"
-
- if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
- assert matches[0] == "f"
- assert matches[1] == "a, b"
- else:
- assert false
-
- assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
- # ß is not a lower cased letter?!
- assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
- assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
- assert(not match("456678", peg"(\letter)+"))
-
- assert("var1 = key; var2 = key2".replacef(
- peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
- "var1<-keykey;var2<-key2key2")
-
- assert match("prefix/start", peg"^start$", 7)
-
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 04aa8316a3..3b68a23819 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -12,6 +12,7 @@
## a denominator `den`, both of type int. The denominator can not be 0.
import math
+import hashes
type Rational*[T] = object
## a rational number, consisting of a numerator and denominator
@@ -32,7 +33,7 @@ proc `$`*[T](x: Rational[T]): string =
## Turn a rational number into a string.
result = $x.num & "/" & $x.den
-proc toRational*[T](x: SomeInteger): Rational[T] =
+proc toRational*[T](x: T): Rational[T] =
## Convert some integer `x` to a rational number.
result.num = x
result.den = 1
@@ -188,7 +189,7 @@ proc `/=`*[T](x: var Rational[T], y: T) =
x.den *= y
reduce(x)
-proc cmp*(x, y: Rational): int =
+proc cmp*(x, y: Rational): int {.procvar.} =
## Compares two rationals.
(x - y).num
@@ -205,6 +206,17 @@ proc abs*[T](x: Rational[T]): Rational[T] =
result.num = abs x.num
result.den = abs x.den
+proc hash*[T](x: Rational[T]): THash =
+ ## Computes hash for rational `x`
+ # reduce first so that hash(x) == hash(y) for x == y
+ var copy = x
+ reduce(copy)
+
+ var h: THash = 0
+ h = h !& hash(copy.num)
+ h = h !& hash(copy.den)
+ result = !$h
+
when isMainModule:
var
z = Rational[int](num: 0, den: 1)
@@ -242,11 +254,13 @@ when isMainModule:
assert( not(o > o) )
assert( cmp(o, o) == 0 )
assert( cmp(z, z) == 0 )
+ assert( hash(o) == hash(o) )
assert( a == b )
assert( a >= b )
assert( not(b > a) )
assert( cmp(a, b) == 0 )
+ assert( hash(a) == hash(b) )
var x = 1//3
@@ -270,6 +284,6 @@ when isMainModule:
y /= 9
assert( y == 13//27 )
- assert toRational[int, int](5) == 5//1
+ assert toRational(5) == 5//1
assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
assert toInt(z) == 0
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index ac348eb1b5..a30c23ada0 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -39,6 +39,9 @@ export
SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
MSG_PEEK
+when defined(macosx):
+ export SO_NOSIGPIPE
+
type
Port* = distinct uint16 ## port type
@@ -428,10 +431,6 @@ proc selectWrite*(writefds: var seq[SocketHandle],
pruneSocketSet(writefds, (wr))
-# We ignore signal SIGPIPE on Darwin
-when defined(macosx):
- signal(SIGPIPE, SIG_IGN)
-
when defined(Windows):
var wsa: WSAData
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 9177ddee59..aa2e0f9bdd 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -1080,7 +1080,7 @@ proc assertListsIdentical(listA, listB: seq[string]) =
assert(item == listB[i])
i = i + 1
-when isMainModule:
+when not defined(testing) and isMainModule:
when false:
var r = open()
diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim
index 79fb755261..0c182843a1 100644
--- a/lib/pure/romans.nim
+++ b/lib/pure/romans.nim
@@ -44,16 +44,13 @@ proc decimalToRoman*(number: range[1..3_999]): string =
("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
("V", 5), ("IV", 4), ("I", 1)]
result = ""
- var decVal = number
+ var decVal: int = number
for key, val in items(romanComposites):
while decVal >= val:
dec(decVal, val)
result.add(key)
when isMainModule:
- import math
- randomize()
- for i in 1 .. 100:
- var rnd = 1 + random(3990)
- assert rnd == rnd.decimalToRoman.romanToDecimal
+ for i in 1 .. 3_999:
+ assert i == i.decimalToRoman.romanToDecimal
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 4cc64a1543..5c7fedfe35 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -52,9 +52,9 @@ proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
## the rope's length
if a == nil: result = 0
else: result = a.length
-
+
proc newRope(): Rope = new(result)
-proc newRope(data: string): Rope =
+proc newRope(data: string): Rope =
new(result)
result.length = len(data)
result.data = data
@@ -65,18 +65,18 @@ var
when countCacheMisses:
var misses, hits: int
-
-proc splay(s: string, tree: Rope, cmpres: var int): Rope =
+
+proc splay(s: string, tree: Rope, cmpres: var int): Rope =
var c: int
var t = tree
N.left = nil
N.right = nil # reset to nil
var le = N
var r = N
- while true:
+ while true:
c = cmp(s, t.data)
- if c < 0:
- if (t.left != nil) and (s < t.left.data):
+ if c < 0:
+ if (t.left != nil) and (s < t.left.data):
var y = t.left
t.left = y.right
y.right = t
@@ -85,8 +85,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
r.left = t
r = t
t = t.left
- elif c > 0:
- if (t.right != nil) and (s > t.right.data):
+ elif c > 0:
+ if (t.right != nil) and (s > t.right.data):
var y = t.right
t.right = y.left
y.left = t
@@ -95,8 +95,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
le.right = t
le = t
t = t.right
- else:
- break
+ else:
+ break
cmpres = c
le.right = t.left
r.left = t.right
@@ -104,50 +104,50 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
t.right = N.left
result = t
-proc insertInCache(s: string, tree: Rope): Rope =
+proc insertInCache(s: string, tree: Rope): Rope =
var t = tree
- if t == nil:
+ if t == nil:
result = newRope(s)
when countCacheMisses: inc(misses)
return
var cmp: int
t = splay(s, t, cmp)
- if cmp == 0:
+ if cmp == 0:
# We get here if it's already in the Tree
# Don't add it again
result = t
when countCacheMisses: inc(hits)
- else:
+ else:
when countCacheMisses: inc(misses)
result = newRope(s)
- if cmp < 0:
+ if cmp < 0:
result.left = t.left
result.right = t
t.left = nil
- else:
+ else:
# i > t.item:
result.right = t.right
result.left = t
t.right = nil
proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
- ## Converts a string to a rope.
- if s.len == 0:
+ ## Converts a string to a rope.
+ if s.len == 0:
result = nil
- elif cacheEnabled:
+ elif cacheEnabled:
result = insertInCache(s, cache)
cache = result
- else:
+ else:
result = newRope(s)
-
-proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
- ## Converts an int to a rope.
+
+proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
+ ## Converts an int to a rope.
result = rope($i)
proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
- ## Converts a float to a rope.
+ ## Converts a float to a rope.
result = rope($f)
-
+
proc enableCache*() {.rtl, extern: "nro$1".} =
## Enables the caching of leaves. This reduces the memory footprint at
## the cost of runtime efficiency.
@@ -160,9 +160,9 @@ proc disableCache*() {.rtl, extern: "nro$1".} =
proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
## the concatenation operator for ropes.
- if a == nil:
+ if a == nil:
result = b
- elif b == nil:
+ elif b == nil:
result = a
else:
result = newRope()
@@ -177,16 +177,16 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
else:
result.left = a
result.right = b
-
-proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
+
+proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
## the concatenation operator for ropes.
result = a & rope(b)
-
-proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
+
+proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
## the concatenation operator for ropes.
result = rope(a) & b
-
-proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
+
+proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
## the concatenation operator for an openarray of ropes.
for i in countup(0, high(a)): result = result & a[i]
@@ -219,7 +219,7 @@ iterator leaves*(r: Rope): string =
## iterates over any leaf string in the rope `r`.
if r != nil:
var stack = @[r]
- while stack.len > 0:
+ while stack.len > 0:
var it = stack.pop
while isConc(it):
stack.add(it.right)
@@ -227,7 +227,7 @@ iterator leaves*(r: Rope): string =
assert(it != nil)
assert(it.data != nil)
yield it.data
-
+
iterator items*(r: Rope): char =
## iterates over any character in the rope `r`.
for s in leaves(r):
@@ -237,7 +237,7 @@ proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
## writes a rope to a file.
for s in leaves(r): write(f, s)
-proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
+proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
## converts a rope back to a string.
result = newString(r.len)
setLen(result, 0)
@@ -251,25 +251,25 @@ when false:
new(result)
result.length = -idx
- proc compileFrmt(frmt: string): Rope =
+ proc compileFrmt(frmt: string): Rope =
var i = 0
var length = len(frmt)
result = nil
var num = 0
- while i < length:
- if frmt[i] == '$':
+ while i < length:
+ if frmt[i] == '$':
inc(i)
case frmt[i]
- of '$':
+ of '$':
add(result, "$")
inc(i)
- of '#':
+ of '#':
inc(i)
add(result, compiledArg(num+1))
inc(num)
- of '0'..'9':
+ of '0'..'9':
var j = 0
- while true:
+ while true:
j = j * 10 + ord(frmt[i]) - ord('0')
inc(i)
if frmt[i] notin {'0'..'9'}: break
@@ -285,13 +285,13 @@ when false:
add(s, compiledArg(j))
else: raise newException(EInvalidValue, "invalid format string")
var start = i
- while i < length:
+ while i < length:
if frmt[i] != '$': inc(i)
- else: break
- if i - 1 >= start:
+ else: break
+ if i - 1 >= start:
add(result, substr(frmt, start, i-1))
-
-proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
+
+proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
rtl, extern: "nroFormat".} =
## `%` substitution operator for ropes. Does not support the ``$identifier``
## nor ``${identifier}`` notations.
@@ -299,23 +299,23 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
var length = len(frmt)
result = nil
var num = 0
- while i < length:
- if frmt[i] == '$':
+ while i < length:
+ if frmt[i] == '$':
inc(i)
case frmt[i]
- of '$':
+ of '$':
add(result, "$")
inc(i)
- of '#':
+ of '#':
inc(i)
add(result, args[num])
inc(num)
- of '0'..'9':
+ of '0'..'9':
var j = 0
- while true:
+ while true:
j = j * 10 + ord(frmt[i]) - ord('0')
inc(i)
- if frmt[i] notin {'0'..'9'}: break
+ if frmt[i] notin {'0'..'9'}: break
add(result, args[j-1])
of '{':
inc(i)
@@ -325,13 +325,14 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
inc(i)
if frmt[i] == '}': inc(i)
else: raise newException(ValueError, "invalid format string")
+
add(result, args[j-1])
else: raise newException(ValueError, "invalid format string")
var start = i
- while i < length:
+ while i < length:
if frmt[i] != '$': inc(i)
- else: break
- if i - 1 >= start:
+ else: break
+ if i - 1 >= start:
add(result, substr(frmt, start, i - 1))
proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
@@ -339,29 +340,46 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
## shortcut for ``add(c, frmt % args)``.
add(c, frmt % args)
+const
+ bufSize = 1024 # 1 KB is reasonable
+
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
## returns true if the contents of the file `f` equal `r`.
- var bufSize = 1024 # reasonable start value
- var buf = alloc(bufSize)
- for s in leaves(r):
- if s.len > bufSize:
- bufSize = max(bufSize * 2, s.len)
- buf = realloc(buf, bufSize)
- var readBytes = readBuffer(f, buf, s.len)
- result = readBytes == s.len and equalMem(buf, cstring(s), s.len)
- if not result: break
- if result:
- result = readBuffer(f, buf, 1) == 0 # really at the end of file?
- dealloc(buf)
+ var
+ buf: array[bufSize, char]
+ bpos = buf.len
+ blen = buf.len
-proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} =
+ for s in leaves(r):
+ var spos = 0
+ let slen = s.len
+ while spos < slen:
+ if bpos == blen:
+ # Read more data
+ bpos = 0
+ blen = readBuffer(f, addr(buf[0]), buf.len)
+ if blen == 0: # no more data in file
+ result = false
+ return
+ let n = min(blen - bpos, slen - spos)
+ # TODO There's gotta be a better way of comparing here...
+ if not equalMem(addr(buf[bpos]),
+ cast[pointer](cast[int](cstring(s))+spos), n):
+ result = false
+ return
+ spos += n
+ bpos += n
+
+ result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
+
+proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
## returns true if the contents of the file `f` equal `r`. If `f` does not
## exist, false is returned.
- var bin: File
- result = open(bin, f)
+ var f: File
+ result = open(f, filename)
if result:
- result = equalsFile(r, bin)
- close(bin)
+ result = equalsFile(r, f)
+ close(f)
new(N) # init dummy node for splay algorithm
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index b6bc9dd3a4..6901ecf588 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -296,7 +296,7 @@ proc contains*(s: Selector, key: SelectorKey): bool =
TReadyInfo: ReadyInfo, PSelector: Selector].}
-when isMainModule and not defined(nimdoc):
+when not defined(testing) and isMainModule and not defined(nimdoc):
# Select()
import sockets
type
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 81198f9e1f..c1bc259a54 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -253,7 +253,7 @@ proc close*(smtp: AsyncSmtp) {.async.} =
await smtp.sock.send("QUIT\c\L")
smtp.sock.close()
-when isMainModule:
+when not defined(testing) and isMainModule:
#var msg = createMessage("Test subject!",
# "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
#echo(msg)
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 727d5a386d..7fdd994f21 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -168,6 +168,12 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
result.counter = 0
newSeq(result.data, startSize)
+proc clear*(s: StringTableRef, mode: StringTableMode) =
+ ## resets a string table to be empty again.
+ s.mode = mode
+ s.counter = 0
+ s.data.setLen(startSize)
+
proc newStringTable*(keyValuePairs: varargs[string],
mode: StringTableMode): StringTableRef {.
rtl, extern: "nst$1WithPairs".} =
@@ -227,7 +233,7 @@ proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} =
result = "{:}"
else:
result = "{"
- for key, val in pairs(t):
+ for key, val in pairs(t):
if result.len > 1: result.add(", ")
result.add(key)
result.add(": ")
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 655203cdae..eb4be719a3 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -169,14 +169,12 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
{.pop.}
-proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
- rtl, extern: "nsuStrip".} =
- ## Strips whitespace from `s` and returns the resulting string.
+proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string
+ {.noSideEffect, rtl, extern: "nsuStrip".} =
+ ## Strips `chars` from `s` and returns the resulting string.
##
- ## If `leading` is true, leading whitespace is stripped.
- ## If `trailing` is true, trailing whitespace is stripped.
- const
- chars: set[char] = Whitespace
+ ## If `leading` is true, leading `chars` are stripped.
+ ## If `trailing` is true, trailing `chars` are stripped.
var
first = 0
last = len(s)-1
@@ -386,7 +384,7 @@ proc split*(s: string, sep: string): seq[string] {.noSideEffect,
## `split iterator <#split.i,string,string>`_.
accumulateResult(split(s, sep))
-proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation.
##
@@ -403,7 +401,7 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
# handle negative overflow
if n == 0 and x < 0: n = -1
-proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
+proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
rtl, extern: "nsuIntToStr".} =
## Converts `x` to its decimal representation.
##
@@ -499,7 +497,7 @@ proc parseEnum*[T: enum](s: string, default: T): T =
return e
result = default
-proc repeat*(c: char, count: int): string {.noSideEffect,
+proc repeat*(c: char, count: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatChar".} =
## Returns a string of length `count` consisting only of
## the character `c`. You can use this proc to left align strings. Example:
@@ -514,7 +512,7 @@ proc repeat*(c: char, count: int): string {.noSideEffect,
result = newString(count)
for i in 0..count-1: result[i] = c
-proc repeat*(s: string, n: int): string {.noSideEffect,
+proc repeat*(s: string, n: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatStr".} =
## Returns String `s` concatenated `n` times. Example:
##
@@ -523,7 +521,7 @@ proc repeat*(s: string, n: int): string {.noSideEffect,
result = newStringOfCap(n * s.len)
for i in 1..n: result.add(s)
-template spaces*(n: int): string = repeat(' ',n)
+template spaces*(n: Natural): string = repeat(' ',n)
## Returns a String with `n` space characters. You can use this proc
## to left align strings. Example:
##
@@ -535,15 +533,15 @@ template spaces*(n: int): string = repeat(' ',n)
## echo text1 & spaces(max(0, width - text1.len)) & "|"
## echo text2 & spaces(max(0, width - text2.len)) & "|"
-proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
+proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
## deprecated: use repeat() or spaces()
-proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
+proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
## deprecated: use repeat(string, count) or string.repeat(count)
-proc align*(s: string, count: int, padding = ' '): string {.
+proc align*(s: string, count: Natural, padding = ' '): string {.
noSideEffect, rtl, extern: "nsuAlignString".} =
- ## Aligns a string `s` with `padding`, so that is of length `count`.
+ ## Aligns a string `s` with `padding`, so that it is of length `count`.
##
## `padding` characters (by default spaces) are added before `s` resulting in
## right alignment. If ``s.len >= count``, no spaces are added and `s` is
@@ -682,7 +680,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
inc(i)
if suffix[i] == '\0': return true
-proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
+proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
rtl, extern: "nsuContinuesWith".} =
## Returns true iff ``s`` continues with ``substr`` at position ``start``.
##
@@ -693,8 +691,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
if s[i+start] != substr[i]: return false
inc(i)
-proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
- inline.} =
+proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
+ {.noSideEffect, inline.} =
## Adds a separator to `dest` only if its length is bigger than `startLen`.
##
## A shorthand for:
@@ -784,7 +782,7 @@ proc findAux(s, sub: string, start: int, a: SkipTable): int =
inc(j, a[s[j+m]])
return -1
-proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
+proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` starting at position `start`.
##
@@ -793,7 +791,7 @@ proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
preprocessSub(sub, a)
result = findAux(s, sub, start, a)
-proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
+proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindChar".} =
## Searches for `sub` in `s` starting at position `start`.
##
@@ -802,7 +800,7 @@ proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
if sub == s[i]: return i
return -1
-proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect,
+proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindCharSet".} =
## Searches for `chars` in `s` starting at position `start`.
##
@@ -933,7 +931,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
var j = findAux(s, sub, i, a)
if j < 0: break
# word boundary?
- if (j == 0 or s[j-1] notin wordChars) and
+ if (j == 0 or s[j-1] notin wordChars) and
(j+sub.len >= s.len or s[j+sub.len] notin wordChars):
add result, substr(s, i, j - 1)
add result, by
@@ -976,7 +974,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
of '\0': break
else: raise newException(ValueError, "invalid integer: " & s)
-proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToOct".} =
## Converts `x` into its octal representation.
##
@@ -992,7 +990,7 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
shift = shift + 3
mask = mask shl 3
-proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToBin".} =
## Converts `x` into its binary representation.
##
@@ -1221,7 +1219,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
## of significant digits to be printed.
## `precision`'s default value is the maximum number of meaningful digits
## after the decimal point for Nim's ``biggestFloat`` type.
- ##
+ ##
## If ``precision == 0``, it tries to format it nicely.
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
var
@@ -1286,7 +1284,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int =
return -1
proc invalidFormatString() {.noinline.} =
- raise newException(ValueError, "invalid format string")
+ raise newException(ValueError, "invalid format string")
proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nsuAddf".} =
@@ -1402,21 +1400,28 @@ when isMainModule:
doAssert align("a", 0) == "a"
doAssert align("1232", 6) == " 1232"
doAssert align("1232", 6, '#') == "##1232"
- echo wordWrap(""" this is a long text -- muchlongerthan10chars and here
- it goes""", 10, false)
+
+ let
+ inp = """ this is a long text -- muchlongerthan10chars and here
+ it goes"""
+ outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+ doAssert wordWrap(inp, 10, false) == outp
+
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
- doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11"
+ doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) in
+ ["1.0e-11", "1.0e-011"]
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
- echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
- echo formatSize(1'i64 shl 31)
+ when not defined(testing):
+ echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
+ echo formatSize(1'i64 shl 31)
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
"The cat eats fish."
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
-
+
type MyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[MyEnum]("enu_D") == enuD
@@ -1426,3 +1431,11 @@ when isMainModule:
doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
doAssert count("foofoofoo", 'f') == 3
doAssert count("foofoofoobar", {'f','b'}) == 4
+
+ doAssert strip(" foofoofoo ") == "foofoofoo"
+ doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+ doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+ doAssert strip("stripme but don't strip this stripme",
+ chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
+ doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+ doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index d701b85b1d..d213c99e6d 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -386,8 +386,13 @@ when isMainModule:
longishA,
longish)"""
- echo "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
- "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]
+ assert "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
+ "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+ strutils.unindent """
+ type TMyEnum* = enum
+ fieldA, fieldB,
+ FiledClkad, fieldD,
+ fieldE, longishFieldName"""
doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
@@ -395,7 +400,12 @@ when isMainModule:
doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
- echo subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
- "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
+ assert subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
+ "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+ strutils.unindent """
+ type
+ TEnum = enum
+ fieldNameA, fieldNameB, fieldNameC,
+ fieldNameD"""
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index df637dcb67..29f700db5c 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -51,12 +51,13 @@ else:
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
var mode: Termios
discard fd.tcgetattr(addr mode)
- mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON)
- mode.oflag = mode.oflag and not Tcflag(OPOST)
- mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8
- mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
- mode.cc[VMIN] = 1.cuchar
- mode.cc[VTIME] = 0.cuchar
+ mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
+ ISTRIP or IXON)
+ mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
+ mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
+ mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
+ mode.c_cc[VMIN] = 1.cuchar
+ mode.c_cc[VTIME] = 0.cuchar
discard fd.tcsetattr(time, addr mode)
proc setCursorPos*(x, y: int) =
@@ -375,7 +376,7 @@ when not defined(windows):
result = stdin.readChar()
discard fd.tcsetattr(TCSADRAIN, addr oldMode)
-when isMainModule:
+when not defined(testing) and isMainModule:
system.addQuitProc(resetAttributes)
write(stdout, "never mind")
eraseLine()
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index c16cae04b5..1b9fa4599e 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -119,7 +119,7 @@ type
## in the range 0 to 23.
monthday*: range[1..31] ## The day of the month, in the range 1 to 31.
month*: Month ## The current month.
- year*: range[-10_000..10_000] ## The current year.
+ year*: int ## The current year.
weekday*: WeekDay ## The current day of the week.
yearday*: range[0..365] ## The number of days since January 1,
## in the range 0 to 365.
@@ -379,7 +379,7 @@ when not defined(JS):
result.hour = t.hour
result.monthday = t.monthday
result.month = ord(t.month)
- result.year = t.year - 1900
+ result.year = cint(t.year - 1900)
result.weekday = weekDays[t.weekday]
result.yearday = t.yearday
result.isdst = if t.isDST: 1 else: 0
@@ -541,6 +541,8 @@ elif defined(JS):
proc getTimezone(): int = result = newDate().getTimezoneOffset()
+ proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
+
proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
## gets the current date as a string of the format ``YYYY-MM-DD``.
var ti = getLocalTime(getTime())
@@ -762,7 +764,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
info.monthday = value[j..j+1].parseInt()
j += 2
of "ddd":
- case value[j..j+2].toLower():
+ case value[j..j+2].toLower()
of "sun":
info.weekday = dSun
of "mon":
@@ -1034,8 +1036,6 @@ when isMainModule:
# Tue 19 Jan 03:14:07 GMT 2038
var t = getGMTime(fromSeconds(2147483647))
- echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
- echo t.format("ddd ddMMMhhmmssZZZyyyy")
assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
@@ -1068,46 +1068,48 @@ when isMainModule:
var f = "dddd at hh:mmtt on MMM d, yyyy"
assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
# ANSIC = "Mon Jan _2 15:04:05 2006"
- s = "Mon Jan 2 15:04:05 2006"
- f = "ddd MMM d HH:mm:ss yyyy"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ s = "Thu Jan 12 15:04:05 2006"
+ f = "ddd MMM dd HH:mm:ss yyyy"
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# UnixDate = "Mon Jan _2 15:04:05 MST 2006"
- s = "Mon Jan 2 15:04:05 MST 2006"
- f = "ddd MMM d HH:mm:ss ZZZ yyyy"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ s = "Thu Jan 12 15:04:05 MST 2006"
+ f = "ddd MMM dd HH:mm:ss ZZZ yyyy"
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
- s = "Mon Jan 02 15:04:05 -07:00 2006"
+ s = "Thu Jan 12 15:04:05 -07:00 2006"
f = "ddd MMM dd HH:mm:ss zzz yyyy"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RFC822 = "02 Jan 06 15:04 MST"
- s = "02 Jan 06 15:04 MST"
+ s = "12 Jan 16 15:04 MST"
f = "dd MMM yy HH:mm ZZZ"
- assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
+ assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
# RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
- s = "02 Jan 06 15:04 -07:00"
+ s = "12 Jan 16 15:04 -07:00"
f = "dd MMM yy HH:mm zzz"
- assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
+ assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
# RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
- s = "Monday, 02-Jan-06 15:04:05 MST"
+ s = "Monday, 12-Jan-06 15:04:05 MST"
f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
- s = "Mon, 02 Jan 2006 15:04:05 MST"
+ s = "Thu, 12 Jan 2006 15:04:05 MST"
f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
- s = "Mon, 02 Jan 2006 15:04:05 -07:00"
+ s = "Thu, 12 Jan 2006 15:04:05 -07:00"
f = "ddd, dd MMM yyyy HH:mm:ss zzz"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RFC3339 = "2006-01-02T15:04:05Z07:00"
- s = "2006-01-02T15:04:05Z-07:00"
+ s = "2006-01-12T15:04:05Z-07:00"
f = "yyyy-MM-ddTHH:mm:ssZzzz"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
- s = "2006-01-02T15:04:05.999999999Z-07:00"
+ s = "2006-01-12T15:04:05.999999999Z-07:00"
f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
- assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
+ assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
# Kitchen = "3:04PM"
s = "3:04PM"
f = "h:mmtt"
- echo "Kitchen: " & $s.parse(f)
+ assert "15:04:00" in $s.parse(f)
+ when not defined(testing):
+ echo "Kitchen: " & $s.parse(f)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index a6f8f916b0..5fd3c2418e 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -19,7 +19,7 @@ type
Rune16* = distinct int16 ## 16 bit Unicode character
{.deprecated: [TRune: Rune, TRune16: Rune16].}
-
+
proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
proc `==`*(a, b: Rune): bool = return int(a) == int(b)
@@ -39,7 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
else: inc i
inc(result)
-proc runeLenAt*(s: string, i: int): int =
+proc runeLenAt*(s: string, i: Natural): int =
## returns the number of bytes the rune starting at ``s[i]`` takes.
if ord(s[i]) <=% 127: result = 1
elif ord(s[i]) shr 5 == 0b110: result = 2
@@ -58,7 +58,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
# assert(ord(s[i+1]) shr 6 == 0b10)
- result = Rune((ord(s[i]) and (ones(5))) shl 6 or
+ result = Rune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
@@ -77,7 +77,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6)))
when doInc: inc(i, 4)
- elif ord(s[i]) shr 2 == 0b111110:
+ elif ord(s[i]) shr 2 == 0b111110:
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
@@ -88,7 +88,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
(ord(s[i+3]) and ones(6)) shl 6 or
(ord(s[i+4]) and ones(6)))
when doInc: inc(i, 5)
- elif ord(s[i]) shr 1 == 0b1111110:
+ elif ord(s[i]) shr 1 == 0b1111110:
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
@@ -105,11 +105,36 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
result = Rune(ord(s[i]))
when doInc: inc(i)
-proc runeAt*(s: string, i: int): Rune =
+proc validateUtf8*(s: string): int =
+ ## returns the position of the invalid byte in ``s`` if the string ``s`` does
+ ## not hold valid UTF-8 data. Otherwise -1 is returned.
+ var i = 0
+ let L = s.len
+ while i < L:
+ if ord(s[i]) <=% 127:
+ inc(i)
+ elif ord(s[i]) shr 5 == 0b110:
+ if i+1 < L and ord(s[i+1]) shr 6 == 0b10: inc(i, 2)
+ else: return i
+ elif ord(s[i]) shr 4 == 0b1110:
+ if i+2 < L and ord(s[i+1]) shr 6 == 0b10 and ord(s[i+2]) shr 6 == 0b10:
+ inc i, 3
+ else: return i
+ elif ord(s[i]) shr 3 == 0b11110:
+ if i+3 < L and ord(s[i+1]) shr 6 == 0b10 and
+ ord(s[i+2]) shr 6 == 0b10 and
+ ord(s[i+3]) shr 6 == 0b10:
+ inc i, 4
+ else: return i
+ else:
+ return i
+ return -1
+
+proc runeAt*(s: string, i: Natural): Rune =
## returns the unicode character in `s` at byte index `i`
fastRuneAt(s, i, result, false)
-proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
+proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
## converts a rune into its UTF8 representation
var i = RuneImpl(c)
if i <=% 127:
@@ -159,967 +184,967 @@ proc `$`*(runes: seq[Rune]): string =
const
alphaRanges = [
- 0x00d8, 0x00f6, # -
- 0x00f8, 0x01f5, # -
- 0x0250, 0x02a8, # -
- 0x038e, 0x03a1, # -
- 0x03a3, 0x03ce, # -
- 0x03d0, 0x03d6, # -
- 0x03e2, 0x03f3, # -
- 0x0490, 0x04c4, # -
- 0x0561, 0x0587, # -
- 0x05d0, 0x05ea, # -
- 0x05f0, 0x05f2, # -
- 0x0621, 0x063a, # -
- 0x0640, 0x064a, # -
- 0x0671, 0x06b7, # -
- 0x06ba, 0x06be, # -
- 0x06c0, 0x06ce, # -
- 0x06d0, 0x06d3, # -
- 0x0905, 0x0939, # -
- 0x0958, 0x0961, # -
- 0x0985, 0x098c, # -
- 0x098f, 0x0990, # -
- 0x0993, 0x09a8, # -
- 0x09aa, 0x09b0, # -
- 0x09b6, 0x09b9, # -
- 0x09dc, 0x09dd, # -
- 0x09df, 0x09e1, # -
- 0x09f0, 0x09f1, # -
- 0x0a05, 0x0a0a, # -
- 0x0a0f, 0x0a10, # -
- 0x0a13, 0x0a28, # -
- 0x0a2a, 0x0a30, # -
- 0x0a32, 0x0a33, # -
- 0x0a35, 0x0a36, # -
- 0x0a38, 0x0a39, # -
- 0x0a59, 0x0a5c, # -
- 0x0a85, 0x0a8b, # -
- 0x0a8f, 0x0a91, # -
- 0x0a93, 0x0aa8, # -
- 0x0aaa, 0x0ab0, # -
- 0x0ab2, 0x0ab3, # -
- 0x0ab5, 0x0ab9, # -
- 0x0b05, 0x0b0c, # -
- 0x0b0f, 0x0b10, # -
- 0x0b13, 0x0b28, # -
- 0x0b2a, 0x0b30, # -
- 0x0b32, 0x0b33, # -
- 0x0b36, 0x0b39, # -
- 0x0b5c, 0x0b5d, # -
- 0x0b5f, 0x0b61, # -
- 0x0b85, 0x0b8a, # -
- 0x0b8e, 0x0b90, # -
- 0x0b92, 0x0b95, # -
- 0x0b99, 0x0b9a, # -
- 0x0b9e, 0x0b9f, # -
- 0x0ba3, 0x0ba4, # -
- 0x0ba8, 0x0baa, # -
- 0x0bae, 0x0bb5, # -
- 0x0bb7, 0x0bb9, # -
- 0x0c05, 0x0c0c, # -
- 0x0c0e, 0x0c10, # -
- 0x0c12, 0x0c28, # -
- 0x0c2a, 0x0c33, # -
- 0x0c35, 0x0c39, # -
- 0x0c60, 0x0c61, # -
- 0x0c85, 0x0c8c, # -
- 0x0c8e, 0x0c90, # -
- 0x0c92, 0x0ca8, # -
- 0x0caa, 0x0cb3, # -
- 0x0cb5, 0x0cb9, # -
- 0x0ce0, 0x0ce1, # -
- 0x0d05, 0x0d0c, # -
- 0x0d0e, 0x0d10, # -
- 0x0d12, 0x0d28, # -
- 0x0d2a, 0x0d39, # -
- 0x0d60, 0x0d61, # -
- 0x0e01, 0x0e30, # -
- 0x0e32, 0x0e33, # -
- 0x0e40, 0x0e46, # -
- 0x0e5a, 0x0e5b, # -
- 0x0e81, 0x0e82, # -
- 0x0e87, 0x0e88, # -
- 0x0e94, 0x0e97, # -
- 0x0e99, 0x0e9f, # -
- 0x0ea1, 0x0ea3, # -
- 0x0eaa, 0x0eab, # -
- 0x0ead, 0x0eae, # -
- 0x0eb2, 0x0eb3, # -
- 0x0ec0, 0x0ec4, # -
- 0x0edc, 0x0edd, # -
- 0x0f18, 0x0f19, # -
- 0x0f40, 0x0f47, # -
- 0x0f49, 0x0f69, # -
- 0x10d0, 0x10f6, # -
- 0x1100, 0x1159, # -
- 0x115f, 0x11a2, # -
- 0x11a8, 0x11f9, # -
- 0x1e00, 0x1e9b, # -
- 0x1f50, 0x1f57, # -
- 0x1f80, 0x1fb4, # -
- 0x1fb6, 0x1fbc, # -
- 0x1fc2, 0x1fc4, # -
- 0x1fc6, 0x1fcc, # -
- 0x1fd0, 0x1fd3, # -
- 0x1fd6, 0x1fdb, # -
- 0x1fe0, 0x1fec, # -
- 0x1ff2, 0x1ff4, # -
- 0x1ff6, 0x1ffc, # -
- 0x210a, 0x2113, # -
- 0x2115, 0x211d, # -
- 0x2120, 0x2122, # -
- 0x212a, 0x2131, # -
- 0x2133, 0x2138, # -
- 0x3041, 0x3094, # -
- 0x30a1, 0x30fa, # -
- 0x3105, 0x312c, # -
- 0x3131, 0x318e, # -
- 0x3192, 0x319f, # -
- 0x3260, 0x327b, # -
- 0x328a, 0x32b0, # -
- 0x32d0, 0x32fe, # -
- 0x3300, 0x3357, # -
- 0x3371, 0x3376, # -
- 0x337b, 0x3394, # -
- 0x3399, 0x339e, # -
- 0x33a9, 0x33ad, # -
- 0x33b0, 0x33c1, # -
- 0x33c3, 0x33c5, # -
- 0x33c7, 0x33d7, # -
- 0x33d9, 0x33dd, # -
- 0x4e00, 0x9fff, # -
- 0xac00, 0xd7a3, # -
- 0xf900, 0xfb06, # -
- 0xfb13, 0xfb17, # -
- 0xfb1f, 0xfb28, # -
- 0xfb2a, 0xfb36, # -
- 0xfb38, 0xfb3c, # -
- 0xfb40, 0xfb41, # -
- 0xfb43, 0xfb44, # -
- 0xfb46, 0xfbb1, # -
- 0xfbd3, 0xfd3d, # -
- 0xfd50, 0xfd8f, # -
- 0xfd92, 0xfdc7, # -
- 0xfdf0, 0xfdf9, # -
- 0xfe70, 0xfe72, # -
- 0xfe76, 0xfefc, # -
- 0xff66, 0xff6f, # -
- 0xff71, 0xff9d, # -
- 0xffa0, 0xffbe, # -
- 0xffc2, 0xffc7, # -
- 0xffca, 0xffcf, # -
- 0xffd2, 0xffd7, # -
- 0xffda, 0xffdc] # -
+ 0x00d8, 0x00f6, # -
+ 0x00f8, 0x01f5, # -
+ 0x0250, 0x02a8, # -
+ 0x038e, 0x03a1, # -
+ 0x03a3, 0x03ce, # -
+ 0x03d0, 0x03d6, # -
+ 0x03e2, 0x03f3, # -
+ 0x0490, 0x04c4, # -
+ 0x0561, 0x0587, # -
+ 0x05d0, 0x05ea, # -
+ 0x05f0, 0x05f2, # -
+ 0x0621, 0x063a, # -
+ 0x0640, 0x064a, # -
+ 0x0671, 0x06b7, # -
+ 0x06ba, 0x06be, # -
+ 0x06c0, 0x06ce, # -
+ 0x06d0, 0x06d3, # -
+ 0x0905, 0x0939, # -
+ 0x0958, 0x0961, # -
+ 0x0985, 0x098c, # -
+ 0x098f, 0x0990, # -
+ 0x0993, 0x09a8, # -
+ 0x09aa, 0x09b0, # -
+ 0x09b6, 0x09b9, # -
+ 0x09dc, 0x09dd, # -
+ 0x09df, 0x09e1, # -
+ 0x09f0, 0x09f1, # -
+ 0x0a05, 0x0a0a, # -
+ 0x0a0f, 0x0a10, # -
+ 0x0a13, 0x0a28, # -
+ 0x0a2a, 0x0a30, # -
+ 0x0a32, 0x0a33, # -
+ 0x0a35, 0x0a36, # -
+ 0x0a38, 0x0a39, # -
+ 0x0a59, 0x0a5c, # -
+ 0x0a85, 0x0a8b, # -
+ 0x0a8f, 0x0a91, # -
+ 0x0a93, 0x0aa8, # -
+ 0x0aaa, 0x0ab0, # -
+ 0x0ab2, 0x0ab3, # -
+ 0x0ab5, 0x0ab9, # -
+ 0x0b05, 0x0b0c, # -
+ 0x0b0f, 0x0b10, # -
+ 0x0b13, 0x0b28, # -
+ 0x0b2a, 0x0b30, # -
+ 0x0b32, 0x0b33, # -
+ 0x0b36, 0x0b39, # -
+ 0x0b5c, 0x0b5d, # -
+ 0x0b5f, 0x0b61, # -
+ 0x0b85, 0x0b8a, # -
+ 0x0b8e, 0x0b90, # -
+ 0x0b92, 0x0b95, # -
+ 0x0b99, 0x0b9a, # -
+ 0x0b9e, 0x0b9f, # -
+ 0x0ba3, 0x0ba4, # -
+ 0x0ba8, 0x0baa, # -
+ 0x0bae, 0x0bb5, # -
+ 0x0bb7, 0x0bb9, # -
+ 0x0c05, 0x0c0c, # -
+ 0x0c0e, 0x0c10, # -
+ 0x0c12, 0x0c28, # -
+ 0x0c2a, 0x0c33, # -
+ 0x0c35, 0x0c39, # -
+ 0x0c60, 0x0c61, # -
+ 0x0c85, 0x0c8c, # -
+ 0x0c8e, 0x0c90, # -
+ 0x0c92, 0x0ca8, # -
+ 0x0caa, 0x0cb3, # -
+ 0x0cb5, 0x0cb9, # -
+ 0x0ce0, 0x0ce1, # -
+ 0x0d05, 0x0d0c, # -
+ 0x0d0e, 0x0d10, # -
+ 0x0d12, 0x0d28, # -
+ 0x0d2a, 0x0d39, # -
+ 0x0d60, 0x0d61, # -
+ 0x0e01, 0x0e30, # -
+ 0x0e32, 0x0e33, # -
+ 0x0e40, 0x0e46, # -
+ 0x0e5a, 0x0e5b, # -
+ 0x0e81, 0x0e82, # -
+ 0x0e87, 0x0e88, # -
+ 0x0e94, 0x0e97, # -
+ 0x0e99, 0x0e9f, # -
+ 0x0ea1, 0x0ea3, # -
+ 0x0eaa, 0x0eab, # -
+ 0x0ead, 0x0eae, # -
+ 0x0eb2, 0x0eb3, # -
+ 0x0ec0, 0x0ec4, # -
+ 0x0edc, 0x0edd, # -
+ 0x0f18, 0x0f19, # -
+ 0x0f40, 0x0f47, # -
+ 0x0f49, 0x0f69, # -
+ 0x10d0, 0x10f6, # -
+ 0x1100, 0x1159, # -
+ 0x115f, 0x11a2, # -
+ 0x11a8, 0x11f9, # -
+ 0x1e00, 0x1e9b, # -
+ 0x1f50, 0x1f57, # -
+ 0x1f80, 0x1fb4, # -
+ 0x1fb6, 0x1fbc, # -
+ 0x1fc2, 0x1fc4, # -
+ 0x1fc6, 0x1fcc, # -
+ 0x1fd0, 0x1fd3, # -
+ 0x1fd6, 0x1fdb, # -
+ 0x1fe0, 0x1fec, # -
+ 0x1ff2, 0x1ff4, # -
+ 0x1ff6, 0x1ffc, # -
+ 0x210a, 0x2113, # -
+ 0x2115, 0x211d, # -
+ 0x2120, 0x2122, # -
+ 0x212a, 0x2131, # -
+ 0x2133, 0x2138, # -
+ 0x3041, 0x3094, # -
+ 0x30a1, 0x30fa, # -
+ 0x3105, 0x312c, # -
+ 0x3131, 0x318e, # -
+ 0x3192, 0x319f, # -
+ 0x3260, 0x327b, # -
+ 0x328a, 0x32b0, # -
+ 0x32d0, 0x32fe, # -
+ 0x3300, 0x3357, # -
+ 0x3371, 0x3376, # -
+ 0x337b, 0x3394, # -
+ 0x3399, 0x339e, # -
+ 0x33a9, 0x33ad, # -
+ 0x33b0, 0x33c1, # -
+ 0x33c3, 0x33c5, # -
+ 0x33c7, 0x33d7, # -
+ 0x33d9, 0x33dd, # -
+ 0x4e00, 0x9fff, # -
+ 0xac00, 0xd7a3, # -
+ 0xf900, 0xfb06, # -
+ 0xfb13, 0xfb17, # -
+ 0xfb1f, 0xfb28, # -
+ 0xfb2a, 0xfb36, # -
+ 0xfb38, 0xfb3c, # -
+ 0xfb40, 0xfb41, # -
+ 0xfb43, 0xfb44, # -
+ 0xfb46, 0xfbb1, # -
+ 0xfbd3, 0xfd3d, # -
+ 0xfd50, 0xfd8f, # -
+ 0xfd92, 0xfdc7, # -
+ 0xfdf0, 0xfdf9, # -
+ 0xfe70, 0xfe72, # -
+ 0xfe76, 0xfefc, # -
+ 0xff66, 0xff6f, # -
+ 0xff71, 0xff9d, # -
+ 0xffa0, 0xffbe, # -
+ 0xffc2, 0xffc7, # -
+ 0xffca, 0xffcf, # -
+ 0xffd2, 0xffd7, # -
+ 0xffda, 0xffdc] # -
alphaSinglets = [
- 0x00aa, #
- 0x00b5, #
- 0x00ba, #
- 0x03da, #
- 0x03dc, #
- 0x03de, #
- 0x03e0, #
- 0x06d5, #
- 0x09b2, #
- 0x0a5e, #
- 0x0a8d, #
- 0x0ae0, #
- 0x0b9c, #
- 0x0cde, #
- 0x0e4f, #
- 0x0e84, #
- 0x0e8a, #
- 0x0e8d, #
- 0x0ea5, #
- 0x0ea7, #
- 0x0eb0, #
- 0x0ebd, #
- 0x1fbe, #
- 0x207f, #
- 0x20a8, #
- 0x2102, #
- 0x2107, #
- 0x2124, #
- 0x2126, #
- 0x2128, #
- 0xfb3e, #
- 0xfe74] #
+ 0x00aa, #
+ 0x00b5, #
+ 0x00ba, #
+ 0x03da, #
+ 0x03dc, #
+ 0x03de, #
+ 0x03e0, #
+ 0x06d5, #
+ 0x09b2, #
+ 0x0a5e, #
+ 0x0a8d, #
+ 0x0ae0, #
+ 0x0b9c, #
+ 0x0cde, #
+ 0x0e4f, #
+ 0x0e84, #
+ 0x0e8a, #
+ 0x0e8d, #
+ 0x0ea5, #
+ 0x0ea7, #
+ 0x0eb0, #
+ 0x0ebd, #
+ 0x1fbe, #
+ 0x207f, #
+ 0x20a8, #
+ 0x2102, #
+ 0x2107, #
+ 0x2124, #
+ 0x2126, #
+ 0x2128, #
+ 0xfb3e, #
+ 0xfe74] #
spaceRanges = [
- 0x0009, 0x000a, # tab and newline
- 0x0020, 0x0020, # space
- 0x00a0, 0x00a0, #
- 0x2000, 0x200b, # -
- 0x2028, 0x2029, # - 0x3000, 0x3000, #
- 0xfeff, 0xfeff] #
+ 0x0009, 0x000a, # tab and newline
+ 0x0020, 0x0020, # space
+ 0x00a0, 0x00a0, #
+ 0x2000, 0x200b, # -
+ 0x2028, 0x2029, # - 0x3000, 0x3000, #
+ 0xfeff, 0xfeff] #
toupperRanges = [
- 0x0061, 0x007a, 468, # a-z A-Z
- 0x00e0, 0x00f6, 468, # - -
- 0x00f8, 0x00fe, 468, # - -
- 0x0256, 0x0257, 295, # - -
- 0x0258, 0x0259, 298, # - -
- 0x028a, 0x028b, 283, # - -
- 0x03ad, 0x03af, 463, # - -
- 0x03b1, 0x03c1, 468, # - -
- 0x03c3, 0x03cb, 468, # - -
- 0x03cd, 0x03ce, 437, # - -
- 0x0430, 0x044f, 468, # - -
- 0x0451, 0x045c, 420, # - -
- 0x045e, 0x045f, 420, # - -
- 0x0561, 0x0586, 452, # - -
- 0x1f00, 0x1f07, 508, # - -
- 0x1f10, 0x1f15, 508, # - -
- 0x1f20, 0x1f27, 508, # - -
- 0x1f30, 0x1f37, 508, # - -
- 0x1f40, 0x1f45, 508, # - -
- 0x1f60, 0x1f67, 508, # - -
- 0x1f70, 0x1f71, 574, # - -
- 0x1f72, 0x1f75, 586, # - -
- 0x1f76, 0x1f77, 600, # - -
- 0x1f78, 0x1f79, 628, # - -
- 0x1f7a, 0x1f7b, 612, # - -
- 0x1f7c, 0x1f7d, 626, # - -
- 0x1f80, 0x1f87, 508, # - -
- 0x1f90, 0x1f97, 508, # - -
- 0x1fa0, 0x1fa7, 508, # - -
- 0x1fb0, 0x1fb1, 508, # - -
- 0x1fd0, 0x1fd1, 508, # - -
- 0x1fe0, 0x1fe1, 508, # - -
- 0x2170, 0x217f, 484, # - -
- 0x24d0, 0x24e9, 474, # - -
- 0xff41, 0xff5a, 468] # - -
+ 0x0061, 0x007a, 468, # a-z A-Z
+ 0x00e0, 0x00f6, 468, # - -
+ 0x00f8, 0x00fe, 468, # - -
+ 0x0256, 0x0257, 295, # - -
+ 0x0258, 0x0259, 298, # - -
+ 0x028a, 0x028b, 283, # - -
+ 0x03ad, 0x03af, 463, # - -
+ 0x03b1, 0x03c1, 468, # - -
+ 0x03c3, 0x03cb, 468, # - -
+ 0x03cd, 0x03ce, 437, # - -
+ 0x0430, 0x044f, 468, # - -
+ 0x0451, 0x045c, 420, # - -
+ 0x045e, 0x045f, 420, # - -
+ 0x0561, 0x0586, 452, # - -
+ 0x1f00, 0x1f07, 508, # - -
+ 0x1f10, 0x1f15, 508, # - -
+ 0x1f20, 0x1f27, 508, # - -
+ 0x1f30, 0x1f37, 508, # - -
+ 0x1f40, 0x1f45, 508, # - -
+ 0x1f60, 0x1f67, 508, # - -
+ 0x1f70, 0x1f71, 574, # - -
+ 0x1f72, 0x1f75, 586, # - -
+ 0x1f76, 0x1f77, 600, # - -
+ 0x1f78, 0x1f79, 628, # - -
+ 0x1f7a, 0x1f7b, 612, # - -
+ 0x1f7c, 0x1f7d, 626, # - -
+ 0x1f80, 0x1f87, 508, # - -
+ 0x1f90, 0x1f97, 508, # - -
+ 0x1fa0, 0x1fa7, 508, # - -
+ 0x1fb0, 0x1fb1, 508, # - -
+ 0x1fd0, 0x1fd1, 508, # - -
+ 0x1fe0, 0x1fe1, 508, # - -
+ 0x2170, 0x217f, 484, # - -
+ 0x24d0, 0x24e9, 474, # - -
+ 0xff41, 0xff5a, 468] # - -
toupperSinglets = [
- 0x00ff, 621, #
- 0x0101, 499, #
- 0x0103, 499, #
- 0x0105, 499, #
- 0x0107, 499, #
- 0x0109, 499, #
- 0x010b, 499, #
- 0x010d, 499, #
- 0x010f, 499, #
- 0x0111, 499, #
- 0x0113, 499, #
- 0x0115, 499, #
- 0x0117, 499, #
- 0x0119, 499, #
- 0x011b, 499, #
- 0x011d, 499, #
- 0x011f, 499, #
- 0x0121, 499, #
- 0x0123, 499, #
- 0x0125, 499, #
- 0x0127, 499, #
- 0x0129, 499, #
- 0x012b, 499, #
- 0x012d, 499, #
- 0x012f, 499, #
- 0x0131, 268, # I
- 0x0133, 499, #
- 0x0135, 499, #
- 0x0137, 499, #
- 0x013a, 499, #
- 0x013c, 499, #
- 0x013e, 499, #
- 0x0140, 499, #
- 0x0142, 499, #
- 0x0144, 499, #
- 0x0146, 499, #
- 0x0148, 499, #
- 0x014b, 499, #
- 0x014d, 499, #
- 0x014f, 499, #
- 0x0151, 499, #
- 0x0153, 499, #
- 0x0155, 499, #
- 0x0157, 499, #
- 0x0159, 499, #
- 0x015b, 499, #
- 0x015d, 499, #
- 0x015f, 499, #
- 0x0161, 499, #
- 0x0163, 499, #
- 0x0165, 499, #
- 0x0167, 499, #
- 0x0169, 499, #
- 0x016b, 499, #
- 0x016d, 499, #
- 0x016f, 499, #
- 0x0171, 499, #
- 0x0173, 499, #
- 0x0175, 499, #
- 0x0177, 499, #
- 0x017a, 499, #
- 0x017c, 499, #
- 0x017e, 499, #
- 0x017f, 200, # S
- 0x0183, 499, #
- 0x0185, 499, #
- 0x0188, 499, #
- 0x018c, 499, #
- 0x0192, 499, #
- 0x0199, 499, #
- 0x01a1, 499, #
- 0x01a3, 499, #
- 0x01a5, 499, #
- 0x01a8, 499, #
- 0x01ad, 499, #
- 0x01b0, 499, #
- 0x01b4, 499, #
- 0x01b6, 499, #
- 0x01b9, 499, #
- 0x01bd, 499, #
- 0x01c5, 499, #
- 0x01c6, 498, #
- 0x01c8, 499, #
- 0x01c9, 498, #
- 0x01cb, 499, #
- 0x01cc, 498, #
- 0x01ce, 499, #
- 0x01d0, 499, #
- 0x01d2, 499, #
- 0x01d4, 499, #
- 0x01d6, 499, #
- 0x01d8, 499, #
- 0x01da, 499, #
- 0x01dc, 499, #
- 0x01df, 499, #
- 0x01e1, 499, #
- 0x01e3, 499, #
- 0x01e5, 499, #
- 0x01e7, 499, #
- 0x01e9, 499, #
- 0x01eb, 499, #
- 0x01ed, 499, #
- 0x01ef, 499, #
- 0x01f2, 499, #
- 0x01f3, 498, #
- 0x01f5, 499, #
- 0x01fb, 499, #
- 0x01fd, 499, #
- 0x01ff, 499, #
- 0x0201, 499, #
- 0x0203, 499, #
- 0x0205, 499, #
- 0x0207, 499, #
- 0x0209, 499, #
- 0x020b, 499, #
- 0x020d, 499, #
- 0x020f, 499, #
- 0x0211, 499, #
- 0x0213, 499, #
- 0x0215, 499, #
- 0x0217, 499, #
- 0x0253, 290, #
- 0x0254, 294, #
- 0x025b, 297, #
- 0x0260, 295, #
- 0x0263, 293, #
- 0x0268, 291, #
- 0x0269, 289, #
- 0x026f, 289, #
- 0x0272, 287, #
- 0x0283, 282, #
- 0x0288, 282, #
- 0x0292, 281, #
- 0x03ac, 462, #
- 0x03cc, 436, #
- 0x03d0, 438, #
- 0x03d1, 443, #
- 0x03d5, 453, #
- 0x03d6, 446, #
- 0x03e3, 499, #
- 0x03e5, 499, #
- 0x03e7, 499, #
- 0x03e9, 499, #
- 0x03eb, 499, #
- 0x03ed, 499, #
- 0x03ef, 499, #
- 0x03f0, 414, #
- 0x03f1, 420, #
- 0x0461, 499, #
- 0x0463, 499, #
- 0x0465, 499, #
- 0x0467, 499, #
- 0x0469, 499, #
- 0x046b, 499, #
- 0x046d, 499, #
- 0x046f, 499, #
- 0x0471, 499, #
- 0x0473, 499, #
- 0x0475, 499, #
- 0x0477, 499, #
- 0x0479, 499, #
- 0x047b, 499, #
- 0x047d, 499, #
- 0x047f, 499, #
- 0x0481, 499, #
- 0x0491, 499, #
- 0x0493, 499, #
- 0x0495, 499, #
- 0x0497, 499, #
- 0x0499, 499, #
- 0x049b, 499, #
- 0x049d, 499, #
- 0x049f, 499, #
- 0x04a1, 499, #
- 0x04a3, 499, #
- 0x04a5, 499, #
- 0x04a7, 499, #
- 0x04a9, 499, #
- 0x04ab, 499, #
- 0x04ad, 499, #
- 0x04af, 499, #
- 0x04b1, 499, #
- 0x04b3, 499, #
- 0x04b5, 499, #
- 0x04b7, 499, #
- 0x04b9, 499, #
- 0x04bb, 499, #
- 0x04bd, 499, #
- 0x04bf, 499, #
- 0x04c2, 499, #
- 0x04c4, 499, #
- 0x04c8, 499, #
- 0x04cc, 499, #
- 0x04d1, 499, #
- 0x04d3, 499, #
- 0x04d5, 499, #
- 0x04d7, 499, #
- 0x04d9, 499, #
- 0x04db, 499, #
- 0x04dd, 499, #
- 0x04df, 499, #
- 0x04e1, 499, #
- 0x04e3, 499, #
- 0x04e5, 499, #
- 0x04e7, 499, #
- 0x04e9, 499, #
- 0x04eb, 499, #
- 0x04ef, 499, #
- 0x04f1, 499, #
- 0x04f3, 499, #
- 0x04f5, 499, #
- 0x04f9, 499, #
- 0x1e01, 499, #
- 0x1e03, 499, #
- 0x1e05, 499, #
- 0x1e07, 499, #
- 0x1e09, 499, #
- 0x1e0b, 499, #
- 0x1e0d, 499, #
- 0x1e0f, 499, #
- 0x1e11, 499, #
- 0x1e13, 499, #
- 0x1e15, 499, #
- 0x1e17, 499, #
- 0x1e19, 499, #
- 0x1e1b, 499, #
- 0x1e1d, 499, #
- 0x1e1f, 499, #
- 0x1e21, 499, #
- 0x1e23, 499, #
- 0x1e25, 499, #
- 0x1e27, 499, #
- 0x1e29, 499, #
- 0x1e2b, 499, #
- 0x1e2d, 499, #
- 0x1e2f, 499, #
- 0x1e31, 499, #
- 0x1e33, 499, #
- 0x1e35, 499, #
- 0x1e37, 499, #
- 0x1e39, 499, #
- 0x1e3b, 499, #
- 0x1e3d, 499, #
- 0x1e3f, 499, #
- 0x1e41, 499, #
- 0x1e43, 499, #
- 0x1e45, 499, #
- 0x1e47, 499, #
- 0x1e49, 499, #
- 0x1e4b, 499, #
- 0x1e4d, 499, #
- 0x1e4f, 499, #
- 0x1e51, 499, #
- 0x1e53, 499, #
- 0x1e55, 499, #
- 0x1e57, 499, #
- 0x1e59, 499, #
- 0x1e5b, 499, #
- 0x1e5d, 499, #
- 0x1e5f, 499, #
- 0x1e61, 499, #
- 0x1e63, 499, #
- 0x1e65, 499, #
- 0x1e67, 499, #
- 0x1e69, 499, #
- 0x1e6b, 499, #
- 0x1e6d, 499, #
- 0x1e6f, 499, #
- 0x1e71, 499, #
- 0x1e73, 499, #
- 0x1e75, 499, #
- 0x1e77, 499, #
- 0x1e79, 499, #
- 0x1e7b, 499, #
- 0x1e7d, 499, #
- 0x1e7f, 499, #
- 0x1e81, 499, #
- 0x1e83, 499, #
- 0x1e85, 499, #
- 0x1e87, 499, #
- 0x1e89, 499, #
- 0x1e8b, 499, #
- 0x1e8d, 499, #
- 0x1e8f, 499, #
- 0x1e91, 499, #
- 0x1e93, 499, #
- 0x1e95, 499, #
- 0x1ea1, 499, #
- 0x1ea3, 499, #
- 0x1ea5, 499, #
- 0x1ea7, 499, #
- 0x1ea9, 499, #
- 0x1eab, 499, #
- 0x1ead, 499, #
- 0x1eaf, 499, #
- 0x1eb1, 499, #
- 0x1eb3, 499, #
- 0x1eb5, 499, #
- 0x1eb7, 499, #
- 0x1eb9, 499, #
- 0x1ebb, 499, #
- 0x1ebd, 499, #
- 0x1ebf, 499, #
- 0x1ec1, 499, #
- 0x1ec3, 499, #
- 0x1ec5, 499, #
- 0x1ec7, 499, #
- 0x1ec9, 499, #
- 0x1ecb, 499, #
- 0x1ecd, 499, #
- 0x1ecf, 499, #
- 0x1ed1, 499, #
- 0x1ed3, 499, #
- 0x1ed5, 499, #
- 0x1ed7, 499, #
- 0x1ed9, 499, #
- 0x1edb, 499, #
- 0x1edd, 499, #
- 0x1edf, 499, #
- 0x1ee1, 499, #
- 0x1ee3, 499, #
- 0x1ee5, 499, #
- 0x1ee7, 499, #
- 0x1ee9, 499, #
- 0x1eeb, 499, #
- 0x1eed, 499, #
- 0x1eef, 499, #
- 0x1ef1, 499, #
- 0x1ef3, 499, #
- 0x1ef5, 499, #
- 0x1ef7, 499, #
- 0x1ef9, 499, #
- 0x1f51, 508, #
- 0x1f53, 508, #
- 0x1f55, 508, #
- 0x1f57, 508, #
- 0x1fb3, 509, #
- 0x1fc3, 509, #
- 0x1fe5, 507, #
- 0x1ff3, 509] #
+ 0x00ff, 621, #
+ 0x0101, 499, #
+ 0x0103, 499, #
+ 0x0105, 499, #
+ 0x0107, 499, #
+ 0x0109, 499, #
+ 0x010b, 499, #
+ 0x010d, 499, #
+ 0x010f, 499, #
+ 0x0111, 499, #
+ 0x0113, 499, #
+ 0x0115, 499, #
+ 0x0117, 499, #
+ 0x0119, 499, #
+ 0x011b, 499, #
+ 0x011d, 499, #
+ 0x011f, 499, #
+ 0x0121, 499, #
+ 0x0123, 499, #
+ 0x0125, 499, #
+ 0x0127, 499, #
+ 0x0129, 499, #
+ 0x012b, 499, #
+ 0x012d, 499, #
+ 0x012f, 499, #
+ 0x0131, 268, # I
+ 0x0133, 499, #
+ 0x0135, 499, #
+ 0x0137, 499, #
+ 0x013a, 499, #
+ 0x013c, 499, #
+ 0x013e, 499, #
+ 0x0140, 499, #
+ 0x0142, 499, #
+ 0x0144, 499, #
+ 0x0146, 499, #
+ 0x0148, 499, #
+ 0x014b, 499, #
+ 0x014d, 499, #
+ 0x014f, 499, #
+ 0x0151, 499, #
+ 0x0153, 499, #
+ 0x0155, 499, #
+ 0x0157, 499, #
+ 0x0159, 499, #
+ 0x015b, 499, #
+ 0x015d, 499, #
+ 0x015f, 499, #
+ 0x0161, 499, #
+ 0x0163, 499, #
+ 0x0165, 499, #
+ 0x0167, 499, #
+ 0x0169, 499, #
+ 0x016b, 499, #
+ 0x016d, 499, #
+ 0x016f, 499, #
+ 0x0171, 499, #
+ 0x0173, 499, #
+ 0x0175, 499, #
+ 0x0177, 499, #
+ 0x017a, 499, #
+ 0x017c, 499, #
+ 0x017e, 499, #
+ 0x017f, 200, # S
+ 0x0183, 499, #
+ 0x0185, 499, #
+ 0x0188, 499, #
+ 0x018c, 499, #
+ 0x0192, 499, #
+ 0x0199, 499, #
+ 0x01a1, 499, #
+ 0x01a3, 499, #
+ 0x01a5, 499, #
+ 0x01a8, 499, #
+ 0x01ad, 499, #
+ 0x01b0, 499, #
+ 0x01b4, 499, #
+ 0x01b6, 499, #
+ 0x01b9, 499, #
+ 0x01bd, 499, #
+ 0x01c5, 499, #
+ 0x01c6, 498, #
+ 0x01c8, 499, #
+ 0x01c9, 498, #
+ 0x01cb, 499, #
+ 0x01cc, 498, #
+ 0x01ce, 499, #
+ 0x01d0, 499, #
+ 0x01d2, 499, #
+ 0x01d4, 499, #
+ 0x01d6, 499, #
+ 0x01d8, 499, #
+ 0x01da, 499, #
+ 0x01dc, 499, #
+ 0x01df, 499, #
+ 0x01e1, 499, #
+ 0x01e3, 499, #
+ 0x01e5, 499, #
+ 0x01e7, 499, #
+ 0x01e9, 499, #
+ 0x01eb, 499, #
+ 0x01ed, 499, #
+ 0x01ef, 499, #
+ 0x01f2, 499, #
+ 0x01f3, 498, #
+ 0x01f5, 499, #
+ 0x01fb, 499, #
+ 0x01fd, 499, #
+ 0x01ff, 499, #
+ 0x0201, 499, #
+ 0x0203, 499, #
+ 0x0205, 499, #
+ 0x0207, 499, #
+ 0x0209, 499, #
+ 0x020b, 499, #
+ 0x020d, 499, #
+ 0x020f, 499, #
+ 0x0211, 499, #
+ 0x0213, 499, #
+ 0x0215, 499, #
+ 0x0217, 499, #
+ 0x0253, 290, #
+ 0x0254, 294, #
+ 0x025b, 297, #
+ 0x0260, 295, #
+ 0x0263, 293, #
+ 0x0268, 291, #
+ 0x0269, 289, #
+ 0x026f, 289, #
+ 0x0272, 287, #
+ 0x0283, 282, #
+ 0x0288, 282, #
+ 0x0292, 281, #
+ 0x03ac, 462, #
+ 0x03cc, 436, #
+ 0x03d0, 438, #
+ 0x03d1, 443, #
+ 0x03d5, 453, #
+ 0x03d6, 446, #
+ 0x03e3, 499, #
+ 0x03e5, 499, #
+ 0x03e7, 499, #
+ 0x03e9, 499, #
+ 0x03eb, 499, #
+ 0x03ed, 499, #
+ 0x03ef, 499, #
+ 0x03f0, 414, #
+ 0x03f1, 420, #
+ 0x0461, 499, #
+ 0x0463, 499, #
+ 0x0465, 499, #
+ 0x0467, 499, #
+ 0x0469, 499, #
+ 0x046b, 499, #
+ 0x046d, 499, #
+ 0x046f, 499, #
+ 0x0471, 499, #
+ 0x0473, 499, #
+ 0x0475, 499, #
+ 0x0477, 499, #
+ 0x0479, 499, #
+ 0x047b, 499, #
+ 0x047d, 499, #
+ 0x047f, 499, #
+ 0x0481, 499, #
+ 0x0491, 499, #
+ 0x0493, 499, #
+ 0x0495, 499, #
+ 0x0497, 499, #
+ 0x0499, 499, #
+ 0x049b, 499, #
+ 0x049d, 499, #
+ 0x049f, 499, #
+ 0x04a1, 499, #
+ 0x04a3, 499, #
+ 0x04a5, 499, #
+ 0x04a7, 499, #
+ 0x04a9, 499, #
+ 0x04ab, 499, #
+ 0x04ad, 499, #
+ 0x04af, 499, #
+ 0x04b1, 499, #
+ 0x04b3, 499, #
+ 0x04b5, 499, #
+ 0x04b7, 499, #
+ 0x04b9, 499, #
+ 0x04bb, 499, #
+ 0x04bd, 499, #
+ 0x04bf, 499, #
+ 0x04c2, 499, #
+ 0x04c4, 499, #
+ 0x04c8, 499, #
+ 0x04cc, 499, #
+ 0x04d1, 499, #
+ 0x04d3, 499, #
+ 0x04d5, 499, #
+ 0x04d7, 499, #
+ 0x04d9, 499, #
+ 0x04db, 499, #
+ 0x04dd, 499, #
+ 0x04df, 499, #
+ 0x04e1, 499, #
+ 0x04e3, 499, #
+ 0x04e5, 499, #
+ 0x04e7, 499, #
+ 0x04e9, 499, #
+ 0x04eb, 499, #
+ 0x04ef, 499, #
+ 0x04f1, 499, #
+ 0x04f3, 499, #
+ 0x04f5, 499, #
+ 0x04f9, 499, #
+ 0x1e01, 499, #
+ 0x1e03, 499, #
+ 0x1e05, 499, #
+ 0x1e07, 499, #
+ 0x1e09, 499, #
+ 0x1e0b, 499, #
+ 0x1e0d, 499, #
+ 0x1e0f, 499, #
+ 0x1e11, 499, #
+ 0x1e13, 499, #
+ 0x1e15, 499, #
+ 0x1e17, 499, #
+ 0x1e19, 499, #
+ 0x1e1b, 499, #
+ 0x1e1d, 499, #
+ 0x1e1f, 499, #
+ 0x1e21, 499, #
+ 0x1e23, 499, #
+ 0x1e25, 499, #
+ 0x1e27, 499, #
+ 0x1e29, 499, #
+ 0x1e2b, 499, #
+ 0x1e2d, 499, #
+ 0x1e2f, 499, #
+ 0x1e31, 499, #
+ 0x1e33, 499, #
+ 0x1e35, 499, #
+ 0x1e37, 499, #
+ 0x1e39, 499, #
+ 0x1e3b, 499, #
+ 0x1e3d, 499, #
+ 0x1e3f, 499, #
+ 0x1e41, 499, #
+ 0x1e43, 499, #
+ 0x1e45, 499, #
+ 0x1e47, 499, #
+ 0x1e49, 499, #
+ 0x1e4b, 499, #
+ 0x1e4d, 499, #
+ 0x1e4f, 499, #
+ 0x1e51, 499, #
+ 0x1e53, 499, #
+ 0x1e55, 499, #
+ 0x1e57, 499, #
+ 0x1e59, 499, #
+ 0x1e5b, 499, #
+ 0x1e5d, 499, #
+ 0x1e5f, 499, #
+ 0x1e61, 499, #
+ 0x1e63, 499, #
+ 0x1e65, 499, #
+ 0x1e67, 499, #
+ 0x1e69, 499, #
+ 0x1e6b, 499, #
+ 0x1e6d, 499, #
+ 0x1e6f, 499, #
+ 0x1e71, 499, #
+ 0x1e73, 499, #
+ 0x1e75, 499, #
+ 0x1e77, 499, #
+ 0x1e79, 499, #
+ 0x1e7b, 499, #
+ 0x1e7d, 499, #
+ 0x1e7f, 499, #
+ 0x1e81, 499, #
+ 0x1e83, 499, #
+ 0x1e85, 499, #
+ 0x1e87, 499, #
+ 0x1e89, 499, #
+ 0x1e8b, 499, #
+ 0x1e8d, 499, #
+ 0x1e8f, 499, #
+ 0x1e91, 499, #
+ 0x1e93, 499, #
+ 0x1e95, 499, #
+ 0x1ea1, 499, #
+ 0x1ea3, 499, #
+ 0x1ea5, 499, #
+ 0x1ea7, 499, #
+ 0x1ea9, 499, #
+ 0x1eab, 499, #
+ 0x1ead, 499, #
+ 0x1eaf, 499, #
+ 0x1eb1, 499, #
+ 0x1eb3, 499, #
+ 0x1eb5, 499, #
+ 0x1eb7, 499, #
+ 0x1eb9, 499, #
+ 0x1ebb, 499, #
+ 0x1ebd, 499, #
+ 0x1ebf, 499, #
+ 0x1ec1, 499, #
+ 0x1ec3, 499, #
+ 0x1ec5, 499, #
+ 0x1ec7, 499, #
+ 0x1ec9, 499, #
+ 0x1ecb, 499, #
+ 0x1ecd, 499, #
+ 0x1ecf, 499, #
+ 0x1ed1, 499, #
+ 0x1ed3, 499, #
+ 0x1ed5, 499, #
+ 0x1ed7, 499, #
+ 0x1ed9, 499, #
+ 0x1edb, 499, #
+ 0x1edd, 499, #
+ 0x1edf, 499, #
+ 0x1ee1, 499, #
+ 0x1ee3, 499, #
+ 0x1ee5, 499, #
+ 0x1ee7, 499, #
+ 0x1ee9, 499, #
+ 0x1eeb, 499, #
+ 0x1eed, 499, #
+ 0x1eef, 499, #
+ 0x1ef1, 499, #
+ 0x1ef3, 499, #
+ 0x1ef5, 499, #
+ 0x1ef7, 499, #
+ 0x1ef9, 499, #
+ 0x1f51, 508, #
+ 0x1f53, 508, #
+ 0x1f55, 508, #
+ 0x1f57, 508, #
+ 0x1fb3, 509, #
+ 0x1fc3, 509, #
+ 0x1fe5, 507, #
+ 0x1ff3, 509] #
tolowerRanges = [
0x0041, 0x005a, 532, # A-Z a-z
- 0x00c0, 0x00d6, 532, # - -
- 0x00d8, 0x00de, 532, # - -
- 0x0189, 0x018a, 705, # - -
- 0x018e, 0x018f, 702, # - -
- 0x01b1, 0x01b2, 717, # - -
- 0x0388, 0x038a, 537, # - -
- 0x038e, 0x038f, 563, # - -
- 0x0391, 0x03a1, 532, # - -
- 0x03a3, 0x03ab, 532, # - -
- 0x0401, 0x040c, 580, # - -
- 0x040e, 0x040f, 580, # - -
- 0x0410, 0x042f, 532, # - -
- 0x0531, 0x0556, 548, # - -
- 0x10a0, 0x10c5, 548, # - -
- 0x1f08, 0x1f0f, 492, # - -
- 0x1f18, 0x1f1d, 492, # - -
- 0x1f28, 0x1f2f, 492, # - -
- 0x1f38, 0x1f3f, 492, # - -
- 0x1f48, 0x1f4d, 492, # - -
- 0x1f68, 0x1f6f, 492, # - -
- 0x1f88, 0x1f8f, 492, # - -
- 0x1f98, 0x1f9f, 492, # - -
- 0x1fa8, 0x1faf, 492, # - -
- 0x1fb8, 0x1fb9, 492, # - -
- 0x1fba, 0x1fbb, 426, # - -
- 0x1fc8, 0x1fcb, 414, # - -
- 0x1fd8, 0x1fd9, 492, # - -
- 0x1fda, 0x1fdb, 400, # - -
- 0x1fe8, 0x1fe9, 492, # - -
- 0x1fea, 0x1feb, 388, # - -
- 0x1ff8, 0x1ff9, 372, # - -
- 0x1ffa, 0x1ffb, 374, # - -
- 0x2160, 0x216f, 516, # - -
- 0x24b6, 0x24cf, 526, # - -
- 0xff21, 0xff3a, 532] # - -
+ 0x00c0, 0x00d6, 532, # - -
+ 0x00d8, 0x00de, 532, # - -
+ 0x0189, 0x018a, 705, # - -
+ 0x018e, 0x018f, 702, # - -
+ 0x01b1, 0x01b2, 717, # - -
+ 0x0388, 0x038a, 537, # - -
+ 0x038e, 0x038f, 563, # - -
+ 0x0391, 0x03a1, 532, # - -
+ 0x03a3, 0x03ab, 532, # - -
+ 0x0401, 0x040c, 580, # - -
+ 0x040e, 0x040f, 580, # - -
+ 0x0410, 0x042f, 532, # - -
+ 0x0531, 0x0556, 548, # - -
+ 0x10a0, 0x10c5, 548, # - -
+ 0x1f08, 0x1f0f, 492, # - -
+ 0x1f18, 0x1f1d, 492, # - -
+ 0x1f28, 0x1f2f, 492, # - -
+ 0x1f38, 0x1f3f, 492, # - -
+ 0x1f48, 0x1f4d, 492, # - -
+ 0x1f68, 0x1f6f, 492, # - -
+ 0x1f88, 0x1f8f, 492, # - -
+ 0x1f98, 0x1f9f, 492, # - -
+ 0x1fa8, 0x1faf, 492, # - -
+ 0x1fb8, 0x1fb9, 492, # - -
+ 0x1fba, 0x1fbb, 426, # - -
+ 0x1fc8, 0x1fcb, 414, # - -
+ 0x1fd8, 0x1fd9, 492, # - -
+ 0x1fda, 0x1fdb, 400, # - -
+ 0x1fe8, 0x1fe9, 492, # - -
+ 0x1fea, 0x1feb, 388, # - -
+ 0x1ff8, 0x1ff9, 372, # - -
+ 0x1ffa, 0x1ffb, 374, # - -
+ 0x2160, 0x216f, 516, # - -
+ 0x24b6, 0x24cf, 526, # - -
+ 0xff21, 0xff3a, 532] # - -
tolowerSinglets = [
- 0x0100, 501, #
- 0x0102, 501, #
- 0x0104, 501, #
- 0x0106, 501, #
- 0x0108, 501, #
- 0x010a, 501, #
- 0x010c, 501, #
- 0x010e, 501, #
- 0x0110, 501, #
- 0x0112, 501, #
- 0x0114, 501, #
- 0x0116, 501, #
- 0x0118, 501, #
- 0x011a, 501, #
- 0x011c, 501, #
- 0x011e, 501, #
- 0x0120, 501, #
- 0x0122, 501, #
- 0x0124, 501, #
- 0x0126, 501, #
- 0x0128, 501, #
- 0x012a, 501, #
- 0x012c, 501, #
- 0x012e, 501, #
- 0x0130, 301, # i
- 0x0132, 501, #
- 0x0134, 501, #
- 0x0136, 501, #
- 0x0139, 501, #
- 0x013b, 501, #
- 0x013d, 501, #
- 0x013f, 501, #
- 0x0141, 501, #
- 0x0143, 501, #
- 0x0145, 501, #
- 0x0147, 501, #
- 0x014a, 501, #
- 0x014c, 501, #
- 0x014e, 501, #
- 0x0150, 501, #
- 0x0152, 501, #
- 0x0154, 501, #
- 0x0156, 501, #
- 0x0158, 501, #
- 0x015a, 501, #
- 0x015c, 501, #
- 0x015e, 501, #
- 0x0160, 501, #
- 0x0162, 501, #
- 0x0164, 501, #
- 0x0166, 501, #
- 0x0168, 501, #
- 0x016a, 501, #
- 0x016c, 501, #
- 0x016e, 501, #
- 0x0170, 501, #
- 0x0172, 501, #
- 0x0174, 501, #
- 0x0176, 501, #
- 0x0178, 379, #
- 0x0179, 501, #
- 0x017b, 501, #
- 0x017d, 501, #
- 0x0181, 710, #
- 0x0182, 501, #
- 0x0184, 501, #
- 0x0186, 706, #
- 0x0187, 501, #
- 0x018b, 501, #
- 0x0190, 703, #
- 0x0191, 501, #
- 0x0193, 705, #
- 0x0194, 707, #
- 0x0196, 711, #
- 0x0197, 709, #
- 0x0198, 501, #
- 0x019c, 711, #
- 0x019d, 713, #
- 0x01a0, 501, #
- 0x01a2, 501, #
- 0x01a4, 501, #
- 0x01a7, 501, #
- 0x01a9, 718, #
- 0x01ac, 501, #
- 0x01ae, 718, #
- 0x01af, 501, #
- 0x01b3, 501, #
- 0x01b5, 501, #
- 0x01b7, 719, #
- 0x01b8, 501, #
- 0x01bc, 501, #
- 0x01c4, 502, #
- 0x01c5, 501, #
- 0x01c7, 502, #
- 0x01c8, 501, #
- 0x01ca, 502, #
- 0x01cb, 501, #
- 0x01cd, 501, #
- 0x01cf, 501, #
- 0x01d1, 501, #
- 0x01d3, 501, #
- 0x01d5, 501, #
- 0x01d7, 501, #
- 0x01d9, 501, #
- 0x01db, 501, #
- 0x01de, 501, #
- 0x01e0, 501, #
- 0x01e2, 501, #
- 0x01e4, 501, #
- 0x01e6, 501, #
- 0x01e8, 501, #
- 0x01ea, 501, #
- 0x01ec, 501, #
- 0x01ee, 501, #
- 0x01f1, 502, #
- 0x01f2, 501, #
- 0x01f4, 501, #
- 0x01fa, 501, #
- 0x01fc, 501, #
- 0x01fe, 501, #
- 0x0200, 501, #
- 0x0202, 501, #
- 0x0204, 501, #
- 0x0206, 501, #
- 0x0208, 501, #
- 0x020a, 501, #
- 0x020c, 501, #
- 0x020e, 501, #
- 0x0210, 501, #
- 0x0212, 501, #
- 0x0214, 501, #
- 0x0216, 501, #
- 0x0386, 538, #
- 0x038c, 564, #
- 0x03e2, 501, #
- 0x03e4, 501, #
- 0x03e6, 501, #
- 0x03e8, 501, #
- 0x03ea, 501, #
- 0x03ec, 501, #
- 0x03ee, 501, #
- 0x0460, 501, #
- 0x0462, 501, #
- 0x0464, 501, #
- 0x0466, 501, #
- 0x0468, 501, #
- 0x046a, 501, #
- 0x046c, 501, #
- 0x046e, 501, #
- 0x0470, 501, #
- 0x0472, 501, #
- 0x0474, 501, #
- 0x0476, 501, #
- 0x0478, 501, #
- 0x047a, 501, #
- 0x047c, 501, #
- 0x047e, 501, #
- 0x0480, 501, #
- 0x0490, 501, #
- 0x0492, 501, #
- 0x0494, 501, #
- 0x0496, 501, #
- 0x0498, 501, #
- 0x049a, 501, #
- 0x049c, 501, #
- 0x049e, 501, #
- 0x04a0, 501, #
- 0x04a2, 501, #
- 0x04a4, 501, #
- 0x04a6, 501, #
- 0x04a8, 501, #
- 0x04aa, 501, #
- 0x04ac, 501, #
- 0x04ae, 501, #
- 0x04b0, 501, #
- 0x04b2, 501, #
- 0x04b4, 501, #
- 0x04b6, 501, #
- 0x04b8, 501, #
- 0x04ba, 501, #
- 0x04bc, 501, #
- 0x04be, 501, #
- 0x04c1, 501, #
- 0x04c3, 501, #
- 0x04c7, 501, #
- 0x04cb, 501, #
- 0x04d0, 501, #
- 0x04d2, 501, #
- 0x04d4, 501, #
- 0x04d6, 501, #
- 0x04d8, 501, #
- 0x04da, 501, #
- 0x04dc, 501, #
- 0x04de, 501, #
- 0x04e0, 501, #
- 0x04e2, 501, #
- 0x04e4, 501, #
- 0x04e6, 501, #
- 0x04e8, 501, #
- 0x04ea, 501, #
- 0x04ee, 501, #
- 0x04f0, 501, #
- 0x04f2, 501, #
- 0x04f4, 501, #
- 0x04f8, 501, #
- 0x1e00, 501, #
- 0x1e02, 501, #
- 0x1e04, 501, #
- 0x1e06, 501, #
- 0x1e08, 501, #
- 0x1e0a, 501, #
- 0x1e0c, 501, #
- 0x1e0e, 501, #
- 0x1e10, 501, #
- 0x1e12, 501, #
- 0x1e14, 501, #
- 0x1e16, 501, #
- 0x1e18, 501, #
- 0x1e1a, 501, #
- 0x1e1c, 501, #
- 0x1e1e, 501, #
- 0x1e20, 501, #
- 0x1e22, 501, #
- 0x1e24, 501, #
- 0x1e26, 501, #
- 0x1e28, 501, #
- 0x1e2a, 501, #
- 0x1e2c, 501, #
- 0x1e2e, 501, #
- 0x1e30, 501, #
- 0x1e32, 501, #
- 0x1e34, 501, #
- 0x1e36, 501, #
- 0x1e38, 501, #
- 0x1e3a, 501, #
- 0x1e3c, 501, #
- 0x1e3e, 501, #
- 0x1e40, 501, #
- 0x1e42, 501, #
- 0x1e44, 501, #
- 0x1e46, 501, #
- 0x1e48, 501, #
- 0x1e4a, 501, #
- 0x1e4c, 501, #
- 0x1e4e, 501, #
- 0x1e50, 501, #
- 0x1e52, 501, #
- 0x1e54, 501, #
- 0x1e56, 501, #
- 0x1e58, 501, #
- 0x1e5a, 501, #
- 0x1e5c, 501, #
- 0x1e5e, 501, #
- 0x1e60, 501, #
- 0x1e62, 501, #
- 0x1e64, 501, #
- 0x1e66, 501, #
- 0x1e68, 501, #
- 0x1e6a, 501, #
- 0x1e6c, 501, #
- 0x1e6e, 501, #
- 0x1e70, 501, #
- 0x1e72, 501, #
- 0x1e74, 501, #
- 0x1e76, 501, #
- 0x1e78, 501, #
- 0x1e7a, 501, #
- 0x1e7c, 501, #
- 0x1e7e, 501, #
- 0x1e80, 501, #
- 0x1e82, 501, #
- 0x1e84, 501, #
- 0x1e86, 501, #
- 0x1e88, 501, #
- 0x1e8a, 501, #
- 0x1e8c, 501, #
- 0x1e8e, 501, #
- 0x1e90, 501, #
- 0x1e92, 501, #
- 0x1e94, 501, #
- 0x1ea0, 501, #
- 0x1ea2, 501, #
- 0x1ea4, 501, #
- 0x1ea6, 501, #
- 0x1ea8, 501, #
- 0x1eaa, 501, #
- 0x1eac, 501, #
- 0x1eae, 501, #
- 0x1eb0, 501, #
- 0x1eb2, 501, #
- 0x1eb4, 501, #
- 0x1eb6, 501, #
- 0x1eb8, 501, #
- 0x1eba, 501, #
- 0x1ebc, 501, #
- 0x1ebe, 501, #
- 0x1ec0, 501, #
- 0x1ec2, 501, #
- 0x1ec4, 501, #
- 0x1ec6, 501, #
- 0x1ec8, 501, #
- 0x1eca, 501, #
- 0x1ecc, 501, #
- 0x1ece, 501, #
- 0x1ed0, 501, #
- 0x1ed2, 501, #
- 0x1ed4, 501, #
- 0x1ed6, 501, #
- 0x1ed8, 501, #
- 0x1eda, 501, #
- 0x1edc, 501, #
- 0x1ede, 501, #
- 0x1ee0, 501, #
- 0x1ee2, 501, #
- 0x1ee4, 501, #
- 0x1ee6, 501, #
- 0x1ee8, 501, #
- 0x1eea, 501, #
- 0x1eec, 501, #
- 0x1eee, 501, #
- 0x1ef0, 501, #
- 0x1ef2, 501, #
- 0x1ef4, 501, #
- 0x1ef6, 501, #
- 0x1ef8, 501, #
- 0x1f59, 492, #
- 0x1f5b, 492, #
- 0x1f5d, 492, #
- 0x1f5f, 492, #
- 0x1fbc, 491, #
- 0x1fcc, 491, #
- 0x1fec, 493, #
- 0x1ffc, 491] #
+ 0x0100, 501, #
+ 0x0102, 501, #
+ 0x0104, 501, #
+ 0x0106, 501, #
+ 0x0108, 501, #
+ 0x010a, 501, #
+ 0x010c, 501, #
+ 0x010e, 501, #
+ 0x0110, 501, #
+ 0x0112, 501, #
+ 0x0114, 501, #
+ 0x0116, 501, #
+ 0x0118, 501, #
+ 0x011a, 501, #
+ 0x011c, 501, #
+ 0x011e, 501, #
+ 0x0120, 501, #
+ 0x0122, 501, #
+ 0x0124, 501, #
+ 0x0126, 501, #
+ 0x0128, 501, #
+ 0x012a, 501, #
+ 0x012c, 501, #
+ 0x012e, 501, #
+ 0x0130, 301, # i
+ 0x0132, 501, #
+ 0x0134, 501, #
+ 0x0136, 501, #
+ 0x0139, 501, #
+ 0x013b, 501, #
+ 0x013d, 501, #
+ 0x013f, 501, #
+ 0x0141, 501, #
+ 0x0143, 501, #
+ 0x0145, 501, #
+ 0x0147, 501, #
+ 0x014a, 501, #
+ 0x014c, 501, #
+ 0x014e, 501, #
+ 0x0150, 501, #
+ 0x0152, 501, #
+ 0x0154, 501, #
+ 0x0156, 501, #
+ 0x0158, 501, #
+ 0x015a, 501, #
+ 0x015c, 501, #
+ 0x015e, 501, #
+ 0x0160, 501, #
+ 0x0162, 501, #
+ 0x0164, 501, #
+ 0x0166, 501, #
+ 0x0168, 501, #
+ 0x016a, 501, #
+ 0x016c, 501, #
+ 0x016e, 501, #
+ 0x0170, 501, #
+ 0x0172, 501, #
+ 0x0174, 501, #
+ 0x0176, 501, #
+ 0x0178, 379, #
+ 0x0179, 501, #
+ 0x017b, 501, #
+ 0x017d, 501, #
+ 0x0181, 710, #
+ 0x0182, 501, #
+ 0x0184, 501, #
+ 0x0186, 706, #
+ 0x0187, 501, #
+ 0x018b, 501, #
+ 0x0190, 703, #
+ 0x0191, 501, #
+ 0x0193, 705, #
+ 0x0194, 707, #
+ 0x0196, 711, #
+ 0x0197, 709, #
+ 0x0198, 501, #
+ 0x019c, 711, #
+ 0x019d, 713, #
+ 0x01a0, 501, #
+ 0x01a2, 501, #
+ 0x01a4, 501, #
+ 0x01a7, 501, #
+ 0x01a9, 718, #
+ 0x01ac, 501, #
+ 0x01ae, 718, #
+ 0x01af, 501, #
+ 0x01b3, 501, #
+ 0x01b5, 501, #
+ 0x01b7, 719, #
+ 0x01b8, 501, #
+ 0x01bc, 501, #
+ 0x01c4, 502, #
+ 0x01c5, 501, #
+ 0x01c7, 502, #
+ 0x01c8, 501, #
+ 0x01ca, 502, #
+ 0x01cb, 501, #
+ 0x01cd, 501, #
+ 0x01cf, 501, #
+ 0x01d1, 501, #
+ 0x01d3, 501, #
+ 0x01d5, 501, #
+ 0x01d7, 501, #
+ 0x01d9, 501, #
+ 0x01db, 501, #
+ 0x01de, 501, #
+ 0x01e0, 501, #
+ 0x01e2, 501, #
+ 0x01e4, 501, #
+ 0x01e6, 501, #
+ 0x01e8, 501, #
+ 0x01ea, 501, #
+ 0x01ec, 501, #
+ 0x01ee, 501, #
+ 0x01f1, 502, #
+ 0x01f2, 501, #
+ 0x01f4, 501, #
+ 0x01fa, 501, #
+ 0x01fc, 501, #
+ 0x01fe, 501, #
+ 0x0200, 501, #
+ 0x0202, 501, #
+ 0x0204, 501, #
+ 0x0206, 501, #
+ 0x0208, 501, #
+ 0x020a, 501, #
+ 0x020c, 501, #
+ 0x020e, 501, #
+ 0x0210, 501, #
+ 0x0212, 501, #
+ 0x0214, 501, #
+ 0x0216, 501, #
+ 0x0386, 538, #
+ 0x038c, 564, #
+ 0x03e2, 501, #
+ 0x03e4, 501, #
+ 0x03e6, 501, #
+ 0x03e8, 501, #
+ 0x03ea, 501, #
+ 0x03ec, 501, #
+ 0x03ee, 501, #
+ 0x0460, 501, #
+ 0x0462, 501, #
+ 0x0464, 501, #
+ 0x0466, 501, #
+ 0x0468, 501, #
+ 0x046a, 501, #
+ 0x046c, 501, #
+ 0x046e, 501, #
+ 0x0470, 501, #
+ 0x0472, 501, #
+ 0x0474, 501, #
+ 0x0476, 501, #
+ 0x0478, 501, #
+ 0x047a, 501, #
+ 0x047c, 501, #
+ 0x047e, 501, #
+ 0x0480, 501, #
+ 0x0490, 501, #
+ 0x0492, 501, #
+ 0x0494, 501, #
+ 0x0496, 501, #
+ 0x0498, 501, #
+ 0x049a, 501, #
+ 0x049c, 501, #
+ 0x049e, 501, #
+ 0x04a0, 501, #
+ 0x04a2, 501, #
+ 0x04a4, 501, #
+ 0x04a6, 501, #
+ 0x04a8, 501, #
+ 0x04aa, 501, #
+ 0x04ac, 501, #
+ 0x04ae, 501, #
+ 0x04b0, 501, #
+ 0x04b2, 501, #
+ 0x04b4, 501, #
+ 0x04b6, 501, #
+ 0x04b8, 501, #
+ 0x04ba, 501, #
+ 0x04bc, 501, #
+ 0x04be, 501, #
+ 0x04c1, 501, #
+ 0x04c3, 501, #
+ 0x04c7, 501, #
+ 0x04cb, 501, #
+ 0x04d0, 501, #
+ 0x04d2, 501, #
+ 0x04d4, 501, #
+ 0x04d6, 501, #
+ 0x04d8, 501, #
+ 0x04da, 501, #
+ 0x04dc, 501, #
+ 0x04de, 501, #
+ 0x04e0, 501, #
+ 0x04e2, 501, #
+ 0x04e4, 501, #
+ 0x04e6, 501, #
+ 0x04e8, 501, #
+ 0x04ea, 501, #
+ 0x04ee, 501, #
+ 0x04f0, 501, #
+ 0x04f2, 501, #
+ 0x04f4, 501, #
+ 0x04f8, 501, #
+ 0x1e00, 501, #
+ 0x1e02, 501, #
+ 0x1e04, 501, #
+ 0x1e06, 501, #
+ 0x1e08, 501, #
+ 0x1e0a, 501, #
+ 0x1e0c, 501, #
+ 0x1e0e, 501, #
+ 0x1e10, 501, #
+ 0x1e12, 501, #
+ 0x1e14, 501, #
+ 0x1e16, 501, #
+ 0x1e18, 501, #
+ 0x1e1a, 501, #
+ 0x1e1c, 501, #
+ 0x1e1e, 501, #
+ 0x1e20, 501, #
+ 0x1e22, 501, #
+ 0x1e24, 501, #
+ 0x1e26, 501, #
+ 0x1e28, 501, #
+ 0x1e2a, 501, #
+ 0x1e2c, 501, #
+ 0x1e2e, 501, #
+ 0x1e30, 501, #
+ 0x1e32, 501, #
+ 0x1e34, 501, #
+ 0x1e36, 501, #
+ 0x1e38, 501, #
+ 0x1e3a, 501, #
+ 0x1e3c, 501, #
+ 0x1e3e, 501, #
+ 0x1e40, 501, #
+ 0x1e42, 501, #
+ 0x1e44, 501, #
+ 0x1e46, 501, #
+ 0x1e48, 501, #
+ 0x1e4a, 501, #
+ 0x1e4c, 501, #
+ 0x1e4e, 501, #
+ 0x1e50, 501, #
+ 0x1e52, 501, #
+ 0x1e54, 501, #
+ 0x1e56, 501, #
+ 0x1e58, 501, #
+ 0x1e5a, 501, #
+ 0x1e5c, 501, #
+ 0x1e5e, 501, #
+ 0x1e60, 501, #
+ 0x1e62, 501, #
+ 0x1e64, 501, #
+ 0x1e66, 501, #
+ 0x1e68, 501, #
+ 0x1e6a, 501, #
+ 0x1e6c, 501, #
+ 0x1e6e, 501, #
+ 0x1e70, 501, #
+ 0x1e72, 501, #
+ 0x1e74, 501, #
+ 0x1e76, 501, #
+ 0x1e78, 501, #
+ 0x1e7a, 501, #
+ 0x1e7c, 501, #
+ 0x1e7e, 501, #
+ 0x1e80, 501, #
+ 0x1e82, 501, #
+ 0x1e84, 501, #
+ 0x1e86, 501, #
+ 0x1e88, 501, #
+ 0x1e8a, 501, #
+ 0x1e8c, 501, #
+ 0x1e8e, 501, #
+ 0x1e90, 501, #
+ 0x1e92, 501, #
+ 0x1e94, 501, #
+ 0x1ea0, 501, #
+ 0x1ea2, 501, #
+ 0x1ea4, 501, #
+ 0x1ea6, 501, #
+ 0x1ea8, 501, #
+ 0x1eaa, 501, #
+ 0x1eac, 501, #
+ 0x1eae, 501, #
+ 0x1eb0, 501, #
+ 0x1eb2, 501, #
+ 0x1eb4, 501, #
+ 0x1eb6, 501, #
+ 0x1eb8, 501, #
+ 0x1eba, 501, #
+ 0x1ebc, 501, #
+ 0x1ebe, 501, #
+ 0x1ec0, 501, #
+ 0x1ec2, 501, #
+ 0x1ec4, 501, #
+ 0x1ec6, 501, #
+ 0x1ec8, 501, #
+ 0x1eca, 501, #
+ 0x1ecc, 501, #
+ 0x1ece, 501, #
+ 0x1ed0, 501, #
+ 0x1ed2, 501, #
+ 0x1ed4, 501, #
+ 0x1ed6, 501, #
+ 0x1ed8, 501, #
+ 0x1eda, 501, #
+ 0x1edc, 501, #
+ 0x1ede, 501, #
+ 0x1ee0, 501, #
+ 0x1ee2, 501, #
+ 0x1ee4, 501, #
+ 0x1ee6, 501, #
+ 0x1ee8, 501, #
+ 0x1eea, 501, #
+ 0x1eec, 501, #
+ 0x1eee, 501, #
+ 0x1ef0, 501, #
+ 0x1ef2, 501, #
+ 0x1ef4, 501, #
+ 0x1ef6, 501, #
+ 0x1ef8, 501, #
+ 0x1f59, 492, #
+ 0x1f5b, 492, #
+ 0x1f5d, 492, #
+ 0x1f5f, 492, #
+ 0x1fbc, 491, #
+ 0x1fcc, 491, #
+ 0x1fec, 493, #
+ 0x1ffc, 491] #
toTitleSinglets = [
- 0x01c4, 501, #
- 0x01c6, 499, #
- 0x01c7, 501, #
- 0x01c9, 499, #
- 0x01ca, 501, #
- 0x01cc, 499, #
- 0x01f1, 501, #
- 0x01f3, 499] #
+ 0x01c4, 501, #
+ 0x01c6, 499, #
+ 0x01c7, 501, #
+ 0x01c9, 499, #
+ 0x01ca, 501, #
+ 0x01cc, 499, #
+ 0x01f1, 501, #
+ 0x01f3, 499] #
-proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
+proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
var n = len
var t = 0
- while n > 1:
+ while n > 1:
var m = n div 2
var p = t + m*stride
if c >= tab[p]:
@@ -1131,9 +1156,9 @@ proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int
return t
return -1
-proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into lower case. This works for any Unicode character.
- ## If possible, prefer `toLower` over `toUpper`.
+ ## If possible, prefer `toLower` over `toUpper`.
var c = RuneImpl(c)
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
@@ -1143,9 +1168,9 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
return Rune(c + tolowerSinglets[p+1] - 500)
return Rune(c)
-proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into upper case. This works for any Unicode character.
- ## If possible, prefer `toLower` over `toUpper`.
+ ## If possible, prefer `toLower` over `toUpper`.
var c = RuneImpl(c)
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
@@ -1155,16 +1180,16 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
return Rune(c + toupperSinglets[p+1] - 500)
return Rune(c)
-proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
var c = RuneImpl(c)
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
if p >= 0 and c == toTitleSinglets[p]:
return Rune(c + toTitleSinglets[p+1] - 500)
return Rune(c)
-proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a lower case Unicode character
- ## If possible, prefer `isLower` over `isUpper`.
+ ## If possible, prefer `isLower` over `isUpper`.
var c = RuneImpl(c)
# Note: toUpperRanges is correct here!
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
@@ -1174,9 +1199,9 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
if p >= 0 and c == toupperSinglets[p]:
return true
-proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a upper case Unicode character
- ## If possible, prefer `isLower` over `isUpper`.
+ ## If possible, prefer `isLower` over `isUpper`.
var c = RuneImpl(c)
# Note: toLowerRanges is correct here!
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
@@ -1186,9 +1211,9 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
if p >= 0 and c == tolowerSinglets[p]:
return true
-proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
- if isUpper(c) or isLower(c):
+ if isUpper(c) or isLower(c):
return true
var c = RuneImpl(c)
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
@@ -1197,11 +1222,11 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
p = binarySearch(c, alphaSinglets, len(alphaSinglets), 1)
if p >= 0 and c == alphaSinglets[p]:
return true
-
-proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+
+proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
return isUpper(c) and isLower(c)
-proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a Unicode whitespace character
var c = RuneImpl(c)
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
@@ -1228,7 +1253,7 @@ iterator runes*(s: string): Rune =
fastRuneAt(s, i, result, true)
yield result
-proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
+proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
## compares two UTF8 strings and ignores the case. Returns:
##
## | 0 iff a == b
diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
index 798eef5d0c..a83b9be0f9 100644
--- a/lib/pure/unidecode/unidecode.nim
+++ b/lib/pure/unidecode/unidecode.nim
@@ -70,5 +70,5 @@ proc unidecode*(s: string): string =
when isMainModule:
loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
- echo unidecode("Äußerst")
+ assert unidecode("Äußerst") == "Ausserst"
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index b0afb75f99..1890a9bf4b 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -53,10 +53,10 @@ proc parseAuthority(authority: string, result: var Uri) =
while true:
case authority[i]
of '@':
- result.password = result.port
- result.port = ""
- result.username = result.hostname
- result.hostname = ""
+ swap result.password, result.port
+ result.port.setLen(0)
+ swap result.username, result.hostname
+ result.hostname.setLen(0)
inPort = false
of ':':
inPort = true
@@ -75,7 +75,7 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
# The 'mailto' scheme's PATH actually contains the hostname/username
if result.scheme.toLower == "mailto":
parseAuthority(result.path, result)
- result.path = ""
+ result.path.setLen(0)
if uri[i] == '?':
i.inc # Skip '?'
@@ -85,13 +85,21 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
i.inc # Skip '#'
i.inc parseUntil(uri, result.anchor, {}, i)
-proc initUri(): Uri =
+proc initUri*(): Uri =
+ ## Initializes a URI.
result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
path: "", query: "", anchor: "")
-proc parseUri*(uri: string): Uri =
- ## Parses a URI.
- result = initUri()
+proc resetUri(uri: var Uri) =
+ for f in uri.fields:
+ when f is string:
+ f.setLen(0)
+ else:
+ f = false
+
+proc parseUri*(uri: string, result: var Uri) =
+ ## Parses a URI. The `result` variable will be cleared before.
+ resetUri(result)
var i = 0
@@ -105,7 +113,7 @@ proc parseUri*(uri: string): Uri =
if uri[i] != ':':
# Assume this is a reference URI (relative URI)
i = 0
- result.scheme = ""
+ result.scheme.setLen(0)
parsePath(uri, i, result)
return
i.inc # Skip ':'
@@ -124,6 +132,11 @@ proc parseUri*(uri: string): Uri =
# Path
parsePath(uri, i, result)
+proc parseUri*(uri: string): Uri =
+ ## Parses a URI and returns it.
+ result = initUri()
+ parseUri(uri, result)
+
proc removeDotSegments(path: string): string =
var collection: seq[string] = @[]
let endsWithSlash = path[path.len-1] == '/'
diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
index 7f34d72a82..0503624357 100644
--- a/lib/pure/xmldomparser.nim
+++ b/lib/pure/xmldomparser.nim
@@ -155,7 +155,7 @@ proc loadXMLFile*(path: string): PDocument =
return loadXMLStream(s)
-when isMainModule:
+when not defined(testing) and isMainModule:
var xml = loadXMLFile("nim/xmldom/test.xml")
#echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
#echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 755bfcdbc4..840cae7341 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -143,7 +143,7 @@ proc loadXml*(path: string): XmlNode =
result = loadXml(path, errors)
if errors.len > 0: raiseInvalidXml(errors)
-when isMainModule:
+when not defined(testing) and isMainModule:
import os
var errors: seq[string] = @[]
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 0bf5b52a46..7526a989a1 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -353,5 +353,6 @@ proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
findAll(n, tag, result)
when isMainModule:
- assert """Nim rules.""" ==
+ let link = "http://nim-lang.org"
+ assert """Nim rules.""" ==
$(<>a(href="http://nim-lang.org", newText("Nim rules.")))
diff --git a/lib/system.nim b/lib/system.nim
index ba0690ace5..1e6f76f3df 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -76,6 +76,10 @@ type
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
auto* = expr
any* = distinct auto
+ untyped* {.magic: Expr.} ## meta type to denote an expression that
+ ## is not resolved (for templates)
+ typed* {.magic: Stmt.} ## meta type to denote an expression that
+ ## is resolved (for templates)
SomeSignedInt* = int|int8|int16|int32|int64
## type class matching all signed integer types
@@ -173,12 +177,6 @@ proc new*(T: typedesc): ref T =
## reference to it as result value
new(result)
-proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.}
- ## creates a new object of type ``T`` and returns a safe (traced)
- ## reference to it in ``a``. This is **unsafe** as it allocates an object
- ## of the passed ``size``. This should only be used for optimization
- ## purposes when you know what you're doing!
-
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
## leaked implementation detail. Do not use.
@@ -513,7 +511,13 @@ type
ESynch: Exception
].}
-proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
+proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
+ ## creates a new object of type ``T`` and returns a safe (traced)
+ ## reference to it in ``a``. This is **unsafe** as it allocates an object
+ ## of the passed ``size``. This should only be used for optimization
+ ## purposes when you know what you're doing!
+
+proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
## returns the size of ``x`` in bytes. Since this is a low-level proc,
## its usage is discouraged - using ``new`` for the most cases suffices
## that one never needs to know ``x``'s size. As a special semantic rule,
@@ -547,7 +551,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = pred(x, y)``.
-proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
+proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
## creates a new sequence of type ``seq[T]`` with length ``len``.
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
## efficient since no reallocation is needed.
@@ -565,7 +569,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
## inputStrings[2] = "would crash"
## #inputStrings[3] = "out of bounds"
-proc newSeq*[T](len = 0): seq[T] =
+proc newSeq*[T](len = 0.Natural): seq[T] =
## creates a new sequence of type ``seq[T]`` with length ``len``.
##
## Note that the sequence will be filled with zeroed entries, which can be a
@@ -659,7 +663,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
-proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.}
+proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
## Unary `+` operator for an integer. Has no effect.
proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
@@ -704,6 +708,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
+ ##
## .. code-block:: Nim
## 1 div 2 == 0
## 2 div 2 == 1
@@ -723,6 +728,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
## computes the `shift right` operation of `x` and `y`.
+ ##
## .. code-block:: Nim
## 0b0001_0000'i8 shr 2 == 0b0100_0000'i8
## 0b1000_0000'i8 shr 2 == 0b0000_0000'i8
@@ -937,7 +943,7 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
-proc setLen*[T](s: var seq[T], newlen: int) {.
+proc setLen*[T](s: var seq[T], newlen: Natural) {.
magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type.
@@ -945,14 +951,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
## a size, use ``newSeq`` instead.
-proc setLen*(s: var string, newlen: int) {.
+proc setLen*(s: var string, newlen: Natural) {.
magic: "SetLengthStr", noSideEffect.}
## sets the length of `s` to `newlen`.
## If the current length is greater than the new length,
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
## a size, use ``newString`` instead.
-proc newString*(len: int): string {.
+proc newString*(len: Natural): string {.
magic: "NewString", importc: "mnewString", noSideEffect.}
## returns a new string of length ``len`` but with uninitialized
## content. One needs to fill the string character after character
@@ -960,7 +966,7 @@ proc newString*(len: int): string {.
## optimization purposes; the same effect can be achieved with the
## ``&`` operator or with ``add``.
-proc newStringOfCap*(cap: int): string {.
+proc newStringOfCap*(cap: Natural): string {.
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
## returns a new string of length ``0`` but with capacity `cap`.This
## procedure exists only for optimization purposes; the same effect can
@@ -1104,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int
## prematurely using ``quit``, this value is ignored.
proc quit*(errorcode: int = QuitSuccess) {.
- magic: "Exit", importc: "exit", header: "", noReturn.}
+ magic: "Exit", importc: "exit", header: "", noreturn.}
## Stops the program immediately with an exit code.
##
## Before stopping the program the "quit procedures" are called in the
@@ -1150,21 +1156,21 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
## is a reason why the default assignment does a deep copy of sequences
## and strings.
-proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
+proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
## This is an O(1) operation.
let xl = x.len
shallowCopy(x[i], x[xl-1])
setLen(x, xl-1)
-proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
+proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
## This is an O(n) operation.
let xl = x.len
for j in i..xl-2: shallowCopy(x[j], x[j+1])
setLen(x, xl-1)
-proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
+proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
## inserts `item` into `x` at position `i`.
let xl = x.len
setLen(x, xl+1)
@@ -1310,19 +1316,19 @@ proc substr*(s: string, first, last: int): string {.
## or `limit`:idx: a string's length.
when not defined(nimrodVM):
- proc zeroMem*(p: pointer, size: int) {.importc, noDecl, benign.}
+ proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*.
- proc copyMem*(dest, source: pointer, size: int) {.
+ proc copyMem*(dest, source: pointer, size: Natural) {.
importc: "memcpy", header: "", benign.}
## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*.
- proc moveMem*(dest, source: pointer, size: int) {.
+ proc moveMem*(dest, source: pointer, size: Natural) {.
importc: "memmove", header: "", benign.}
## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@@ -1330,7 +1336,7 @@ when not defined(nimrodVM):
## and is thus somewhat more safe than ``copyMem``. Like any procedure
## dealing with raw memory this is still *unsafe*, though.
- proc equalMem*(a, b: pointer, size: int): bool {.
+ proc equalMem*(a, b: pointer, size: Natural): bool {.
importc: "equalMem", noDecl, noSideEffect.}
## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
## be compared. If the blocks are equal, true is returned, false
@@ -1338,7 +1344,7 @@ when not defined(nimrodVM):
## *unsafe*.
when hostOS != "standalone":
- proc alloc*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+ proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is not initialized, so reading
@@ -1353,7 +1359,7 @@ when not defined(nimrodVM):
## The allocated memory belongs to its allocating thread!
## Use `createSharedU` to allocate from a shared heap.
cast[ptr T](alloc(T.sizeof * size))
- proc alloc0*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+ proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is initialized with all bytes
@@ -1368,8 +1374,8 @@ when not defined(nimrodVM):
## The allocated memory belongs to its allocating thread!
## Use `createShared` to allocate from a shared heap.
cast[ptr T](alloc0(T.sizeof * size))
- proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
- benign.}
+ proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
+ benign.}
## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least
## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1396,7 +1402,7 @@ when not defined(nimrodVM):
## Use `deallocShared` to deallocate from a shared heap.
proc free*[T](p: ptr T) {.inline, benign.} =
dealloc(p)
- proc allocShared*(size: int): pointer {.noconv, rtl, benign.}
+ proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.}
## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
@@ -1410,7 +1416,7 @@ when not defined(nimrodVM):
## is not initialized, so reading from it before writing to it is
## undefined behaviour!
cast[ptr T](allocShared(T.sizeof * size))
- proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
+ proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign.}
## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
@@ -1423,8 +1429,8 @@ when not defined(nimrodVM):
## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``createSharedU``.
cast[ptr T](allocShared0(T.sizeof * size))
- proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
- benign.}
+ proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl,
+ benign.}
## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at
## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1526,10 +1532,10 @@ const
NimMajor*: int = 0
## is the major number of Nim's version.
- NimMinor*: int = 10
+ NimMinor*: int = 11
## is the minor number of Nim's version.
- NimPatch*: int = 3
+ NimPatch*: int = 2
## is the patch number of Nim's version.
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@@ -1632,7 +1638,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
if x <= y: x else: y
proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
if x <= y: x else: y
-proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} =
+proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
## The minimum value of two integers.
if x <= y: x else: y
@@ -1650,7 +1656,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
if y <= x: x else: y
proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
if y <= x: x else: y
-proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} =
+proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
## The maximum value of two integers.
if y <= x: x else: y
@@ -1738,6 +1744,12 @@ iterator items*(E: typedesc[enum]): E =
for v in low(E)..high(E):
yield v
+iterator items*[T](s: Slice[T]): T =
+ ## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
+ ## (inclusively).
+ for x in s.a..s.b:
+ yield x
+
iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
var i = 0
@@ -2258,20 +2270,21 @@ when hostOS == "standalone":
include panicoverride
when not declared(sysFatal):
- template sysFatal(exceptn: typedesc, message: string) =
- when hostOS == "standalone":
+ when hostOS == "standalone":
+ proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
panic(message)
- else:
+
+ proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
+ rawoutput(message)
+ panic(arg)
+ else:
+ proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
var e: ref exceptn
new(e)
e.msg = message
raise e
- template sysFatal(exceptn: typedesc, message, arg: string) =
- when hostOS == "standalone":
- rawoutput(message)
- panic(arg)
- else:
+ proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
var e: ref exceptn
new(e)
e.msg = message & arg
@@ -2487,37 +2500,37 @@ when not defined(JS): #and not defined(NimrodVM):
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`.
- proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {.
+ proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
- proc readChars*(f: File, a: var openArray[char], start, len: int): int {.
+ proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
- proc readBuffer*(f: File, buffer: pointer, len: int): int {.
+ proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
- proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {.
+ proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
- proc writeChars*(f: File, a: openArray[char], start, len: int): int {.
+ proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
- proc writeBuffer*(f: File, buffer: pointer, len: int): int {.
+ proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [WriteIOEffect], benign.}
## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less
@@ -2539,7 +2552,7 @@ when not defined(JS): #and not defined(NimrodVM):
when not defined(nimfix):
{.deprecated: [fileHandle: getFileHandle].}
- proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
+ proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
## of length ``len``.
newSeq(result, len)
@@ -2809,14 +2822,14 @@ elif defined(JS):
proc getTotalMem(): int = return -1
proc dealloc(p: pointer) = discard
- proc alloc(size: int): pointer = discard
- proc alloc0(size: int): pointer = discard
- proc realloc(p: pointer, newsize: int): pointer = discard
+ proc alloc(size: Natural): pointer = discard
+ proc alloc0(size: Natural): pointer = discard
+ proc realloc(p: pointer, newsize: Natural): pointer = discard
- proc allocShared(size: int): pointer = discard
- proc allocShared0(size: int): pointer = discard
+ proc allocShared(size: Natural): pointer = discard
+ proc allocShared0(size: Natural): pointer = discard
proc deallocShared(p: pointer) = discard
- proc reallocShared(p: pointer, newsize: int): pointer = discard
+ proc reallocShared(p: pointer, newsize: Natural): pointer = discard
when defined(JS):
include "system/jssys"
@@ -3028,8 +3041,8 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
## result = a[pos]
##
## when isMainModule:
- ## testException(EInvalidIndex, tester(30))
- ## testException(EInvalidIndex, tester(1))
+ ## testException(IndexError, tester(30))
+ ## testException(IndexError, tester(1))
## # --> Test failure at example.nim:20 with 'tester(1)'
template currentSourcePath*: string = instantiationInfo(-1, true).filename
@@ -3038,13 +3051,12 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename
proc raiseAssert*(msg: string) {.noinline.} =
sysFatal(AssertionError, msg)
-when true:
- proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
- # trick the compiler to not list ``EAssertionFailed`` when called
- # by ``assert``.
- type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
- tags: [].}
- THide(raiseAssert)(msg)
+proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
+ # trick the compiler to not list ``AssertionError`` when called
+ # by ``assert``.
+ type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
+ tags: [].}
+ THide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note
@@ -3109,24 +3121,18 @@ when not defined(nimhygiene):
template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
## Sets an assertion failure handler that will intercept any assert
- ## statements following `onFailedAssert` in the current lexical scope.
- ## Can be defined multiple times in a single function.
+ ## statements following `onFailedAssert` in the current module scope.
##
## .. code-block:: nim
+ ## # module-wide policy to change the failed assert
+ ## # exception type in order to include a lineinfo
+ ## onFailedAssert(msg):
+ ## var e = new(TMyError)
+ ## e.msg = msg
+ ## e.lineinfo = instantiationInfo(-2)
+ ## raise e
##
- ## proc example(x: int): TErrorCode =
- ## onFailedAssert(msg):
- ## log msg
- ## return E_FAIL
- ##
- ## assert(...)
- ##
- ## onFailedAssert(msg):
- ## raise newException(EMyException, msg)
- ##
- ## assert(...)
- ##
- template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
+ template failedAssertImpl(msgIMPL: string): stmt {.dirty.} =
let msg = msgIMPL
code
@@ -3162,7 +3168,7 @@ when false:
payload()
when hostOS != "standalone":
- proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
+ proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} =
## inserts `item` into `x` at position `i`.
var xl = x.len
setLen(x, xl+item.len)
@@ -3202,7 +3208,7 @@ when hostOS != "standalone":
if x == nil: x = y
else: x.add(y)
-proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
+proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
## generates a tuple constructor expression listing all the local variables
## in the current scope. This is quite fast as it does not rely
## on any debug or runtime information. Note that in constrast to what
@@ -3251,4 +3257,20 @@ proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
## overloaded ``[]`` or ``[]=`` accessors.
discard
+template `..^`*(a, b: expr): expr =
+ ## a shortcut for '.. ^' to avoid the common gotcha that a space between
+ ## '..' and '^' is required.
+ a .. ^b
+
+template `..<`*(a, b: expr): expr =
+ ## a shortcut for '.. <' to avoid the common gotcha that a space between
+ ## '..' and '<' is required.
+ a .. ".}: cint
-
+
proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
off: int): pointer {.header: "".}
proc munmap(adr: pointer, len: int) {.header: "".}
-
- proc osAllocPages(size: int): pointer {.inline.} =
- result = mmap(nil, size, PROT_READ or PROT_WRITE,
+
+ proc osAllocPages(size: int): pointer {.inline.} =
+ result = mmap(nil, size, PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
if result == nil or result == cast[pointer](-1):
raiseOutOfMem()
-
+
proc osDeallocPages(p: pointer, size: int) {.inline} =
when reallyOsDealloc: munmap(p, size)
-
-elif defined(windows):
+
+elif defined(windows):
const
- MEM_RESERVE = 0x2000
+ MEM_RESERVE = 0x2000
MEM_COMMIT = 0x1000
MEM_TOP_DOWN = 0x100000
PAGE_READWRITE = 0x04
@@ -62,12 +62,12 @@ elif defined(windows):
proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
flProtect: int32): pointer {.
header: "", stdcall, importc: "VirtualAlloc".}
-
- proc virtualFree(lpAddress: pointer, dwSize: int,
+
+ proc virtualFree(lpAddress: pointer, dwSize: int,
dwFreeType: int32) {.header: "", stdcall,
importc: "VirtualFree".}
-
- proc osAllocPages(size: int): pointer {.inline.} =
+
+ proc osAllocPages(size: int): pointer {.inline.} =
result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE)
if result == nil: raiseOutOfMem()
@@ -82,7 +82,7 @@ elif defined(windows):
when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
#VirtualFree(p, size, MEM_DECOMMIT)
-else:
+else:
{.error: "Port memory manager to your platform".}
# --------------------- end of non-portable code -----------------------------
@@ -97,17 +97,17 @@ const
InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
SmallChunkSize = PageSize
-type
+type
PTrunk = ptr TTrunk
- TTrunk {.final.} = object
+ TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector
-
+
TTrunkBuckets = array[0..255, PTrunk]
- TIntSet {.final.} = object
+ TIntSet {.final.} = object
data: TTrunkBuckets
-
+
type
TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object
@@ -123,14 +123,14 @@ type
prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize...
-
+
TSmallChunk = object of TBaseChunk
next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell
- free: int # how many bytes remain
+ free: int # how many bytes remain
acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory
-
+
TBigChunk = object of TBaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size
align: int
@@ -139,7 +139,7 @@ type
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
-proc roundup(x, v: int): int {.inline.} =
+proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1)
sysAssert(result >= x, "roundup: result < x")
#return ((-x) and (v-1)) +% x
@@ -153,7 +153,7 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# endings of big chunks. This is needed by the merging operation. The only
# remaining operation is best-fit for big chunks. Since there is a size-limit
# for big chunks (because greater than the limit means they are returned back
-# to the OS), a fixed size array can be used.
+# to the OS), a fixed size array can be used.
type
PLLChunk = ptr TLLChunk
@@ -163,21 +163,21 @@ type
next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode
- TAvlNode {.pure, final.} = object
- link: array[0..1, PAvlNode] # Left (0) and right (1) links
+ TAvlNode {.pure, final.} = object
+ link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int
level: int
-
+
TMemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
- lastSize: int # needed for the case that OS gives us pages linearly
+ lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet
root, deleted, last, freeAvlNodes: PAvlNode
-
+
# shared:
var
bottomData: TAvlNode
@@ -191,7 +191,7 @@ proc initAllocator() =
bottom.link[1] = bottom
{.pop.}
-proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
+proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
@@ -199,11 +199,11 @@ proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int =
- # Since we update maxPagesCount only when freeing pages,
+ # Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here:
result = max(a.currMem, a.maxMem)
-
+
proc llAlloc(a: var TMemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time.
@@ -251,15 +251,15 @@ proc llDeallocAll(a: var TMemRegion) =
var next = it.next
osDeallocPages(it, PageSize)
it = next
-
-proc intSetGet(t: TIntSet, key: int): PTrunk =
+
+proc intSetGet(t: TIntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)]
- while it != nil:
+ while it != nil:
if it.key == key: return it
it = it.next
result = nil
-proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
+proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
result = intSetGet(t, key)
if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@@ -267,20 +267,20 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result
result.key = key
-proc contains(s: TIntSet, key: int): bool =
+proc contains(s: TIntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift)
- if t != nil:
+ if t != nil:
var u = key and TrunkMask
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
- else:
+ else:
result = false
-
-proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
+
+proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
-proc excl(s: var TIntSet, key: int) =
+proc excl(s: var TIntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
@@ -304,11 +304,11 @@ iterator elements(t: TIntSet): int {.inline.} =
w = w shr 1
inc(i)
r = r.next
-
-proc isSmallChunk(c: PChunk): bool {.inline.} =
+
+proc isSmallChunk(c: PChunk): bool {.inline.} =
return c.size <= SmallChunkSize-smallChunkOverhead()
-
-proc chunkUnused(c: PChunk): bool {.inline.} =
+
+proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} =
@@ -319,7 +319,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
if not chunkUnused(c):
if isSmallChunk(c):
var c = cast[PSmallChunk](c)
-
+
let size = c.size
var a = cast[ByteAddress](addr(c.data))
let limit = a + c.acc
@@ -334,17 +334,17 @@ proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1
# ------------- chunk management ----------------------------------------------
-proc pageIndex(c: PChunk): int {.inline.} =
+proc pageIndex(c: PChunk): int {.inline.} =
result = cast[ByteAddress](c) shr PageShift
-proc pageIndex(p: pointer): int {.inline.} =
+proc pageIndex(p: pointer): int {.inline.} =
result = cast[ByteAddress](p) shr PageShift
-proc pageAddr(p: pointer): PChunk {.inline.} =
+proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
-proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
+proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
incCurrMem(a, size)
inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size))
@@ -373,7 +373,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown
a.lastSize = size # for next request
-proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
+proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
# update next.prevSize:
var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size
@@ -387,36 +387,36 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
-proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
+proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p))
-proc contains[T](list, x: T): bool =
+proc contains[T](list, x: T): bool =
var it = list
while it != nil:
if it == x: return true
it = it.next
-
+
proc writeFreeList(a: TMemRegion) =
var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it)
- while it != nil:
- c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
+ while it != nil:
+ c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
it, it.next, it.prev)
it = it.next
-proc listAdd[T](head: var T, c: T) {.inline.} =
+proc listAdd[T](head: var T, c: T) {.inline.} =
sysAssert(c notin head, "listAdd 1")
sysAssert c.prev == nil, "listAdd 2"
sysAssert c.next == nil, "listAdd 3"
c.next = head
- if head != nil:
+ if head != nil:
sysAssert head.prev == nil, "listAdd 4"
head.prev = c
head = c
proc listRemove[T](head: var T, c: T) {.inline.} =
sysAssert(c in head, "listRemove")
- if c == head:
+ if c == head:
head = c.next
sysAssert c.prev == nil, "listRemove 2"
if head != nil: head.prev = nil
@@ -426,15 +426,15 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
if c.next != nil: c.next.prev = c.prev
c.next = nil
c.prev = nil
-
-proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
- prevSize: int) {.inline.} =
+
+proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
+ prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri):
ri.prevSize = prevSize
-
-proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
+
+proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
var c = c
sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size)
@@ -448,7 +448,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
inc(c.size, ri.size)
excl(a.chunkStarts, pageIndex(ri))
when coalescLeft:
- if c.prevSize != 0:
+ if c.prevSize != 0:
var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize)
sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4")
if isAccessible(a, le) and chunkUnused(le):
@@ -467,7 +467,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else:
freeOsChunks(a, c, c.size)
-proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
+proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size
@@ -480,7 +480,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest)
-proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
+proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
# use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2")
@@ -488,7 +488,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
block search:
while result != nil:
sysAssert chunkUnused(result), "getBigChunk 3"
- if result.size == size:
+ if result.size == size:
listRemove(a.freeChunksList, result)
break search
elif result.size > size:
@@ -497,7 +497,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
break search
result = result.next
sysAssert result != a.freeChunksList, "getBigChunk 4"
- if size < InitialMemoryRequest:
+ if size < InitialMemoryRequest:
result = requestOsChunks(a, InitialMemoryRequest)
splitChunk(a, result, size)
else:
@@ -507,7 +507,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size)
-proc getSmallChunk(a: var TMemRegion): PSmallChunk =
+proc getSmallChunk(a: var TMemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2"
@@ -521,15 +521,15 @@ proc allocInv(a: TMemRegion): bool =
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s]
while c != nil:
- if c.next == c:
+ if c.next == c:
echo "[SYSASSERT] c.next == c"
return false
- if c.size != s * MemAlign:
+ if c.size != s * MemAlign:
echo "[SYSASSERT] c.size != s * MemAlign"
return false
var it = c.freeList
while it != nil:
- if it.zeroField != 0:
+ if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0"
c_printf("%ld %p\n", it.zeroField, it)
return false
@@ -539,16 +539,16 @@ proc allocInv(a: TMemRegion): bool =
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin")
- sysAssert(roundup(65, 8) == 72, "rawAlloc 1")
- sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2"
+ sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
+ sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
- if size <= SmallChunkSize-smallChunkOverhead():
+ if size <= SmallChunkSize-smallChunkOverhead():
# allocate a small block: for small chunks, we use only its next pointer
var s = size div MemAlign
var c = a.freeSmallChunks[s]
- if c == nil:
+ if c == nil:
c = getSmallChunk(a)
c.freeList = nil
sysAssert c.size == PageSize, "rawAlloc 3"
@@ -567,7 +567,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
# c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
sysAssert c.size == size, "rawAlloc 6"
if c.freeList == nil:
- sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
+ sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
"rawAlloc 7")
result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
inc(c.acc, size)
@@ -621,9 +621,9 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
f.zeroField = 0
f.next = c.freeList
c.freeList = f
- when overwriteFree:
+ when overwriteFree:
# set to 0xff to check for usage after free bugs:
- c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
+ c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
s -% sizeof(TFreeCell))
# check if it is not in the freeSmallChunks[s] list:
if c.free < s:
@@ -649,13 +649,13 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p)
-proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
+proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p):
var c = pageAddr(p)
if not chunkUnused(c):
if isSmallChunk(c):
var c = cast[PSmallChunk](c)
- var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
+ var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1)
@@ -673,12 +673,12 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if not chunkUnused(c):
if isSmallChunk(c):
var c = cast[PSmallChunk](c)
- var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
+ var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead()
if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
cast[ByteAddress](p), "offset is not what you think it is")
- var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
+ var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size))
if d.zeroField >% 1:
result = d
@@ -711,13 +711,13 @@ proc ptrSize(p: pointer): int =
if not isSmallChunk(c):
dec result, bigChunkOverhead()
-proc alloc(allocator: var TMemRegion, size: int): pointer =
+proc alloc(allocator: var TMemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
-proc alloc0(allocator: var TMemRegion, size: int): pointer =
+proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
result = alloc(allocator, size)
zeroMem(result, size)
@@ -730,7 +730,7 @@ proc dealloc(allocator: var TMemRegion, p: pointer) =
rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
-proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer =
+proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
if newsize > 0:
result = alloc0(allocator, newsize)
if p != nil:
@@ -758,7 +758,7 @@ proc deallocOsPages(a: var TMemRegion) =
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
-proc getOccupiedMem(a: TMemRegion): int {.inline.} =
+proc getOccupiedMem(a: TMemRegion): int {.inline.} =
result = a.currMem - a.freeMem
# ---------------------- thread memory region -------------------------------
@@ -774,16 +774,16 @@ template instantiateForRegion(allocator: expr) =
proc deallocOsPages = deallocOsPages(allocator)
- proc alloc(size: int): pointer =
+ proc alloc(size: Natural): pointer =
result = alloc(allocator, size)
- proc alloc0(size: int): pointer =
+ proc alloc0(size: Natural): pointer =
result = alloc0(allocator, size)
proc dealloc(p: pointer) =
dealloc(allocator, p)
- proc realloc(p: pointer, newsize: int): pointer =
+ proc realloc(p: pointer, newsize: Natural): pointer =
result = realloc(allocator, p, newSize)
when false:
@@ -794,7 +794,7 @@ template instantiateForRegion(allocator: expr) =
inc(result, it.size)
it = it.next
- proc getFreeMem(): int =
+ proc getFreeMem(): int =
result = allocator.freeMem
#sysAssert(result == countFreeMem())
@@ -807,7 +807,7 @@ template instantiateForRegion(allocator: expr) =
var heapLock: TSysLock
initSysLock(heapLock)
- proc allocShared(size: int): pointer =
+ proc allocShared(size: Natural): pointer =
when hasThreadSupport:
acquireSys(heapLock)
result = alloc(sharedHeap, size)
@@ -815,20 +815,20 @@ template instantiateForRegion(allocator: expr) =
else:
result = alloc(size)
- proc allocShared0(size: int): pointer =
+ proc allocShared0(size: Natural): pointer =
result = allocShared(size)
zeroMem(result, size)
proc deallocShared(p: pointer) =
- when hasThreadSupport:
+ when hasThreadSupport:
acquireSys(heapLock)
dealloc(sharedHeap, p)
releaseSys(heapLock)
else:
dealloc(p)
- proc reallocShared(p: pointer, newsize: int): pointer =
- when hasThreadSupport:
+ proc reallocShared(p: pointer, newsize: Natural): pointer =
+ when hasThreadSupport:
acquireSys(heapLock)
result = realloc(sharedHeap, p, newsize)
releaseSys(heapLock)
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index f68e2dcd9f..ef153417c0 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -10,11 +10,11 @@
# simple integer arithmetic with overflow checking
-proc raiseOverflow {.compilerproc, noinline, noreturn.} =
+proc raiseOverflow {.compilerproc, noinline.} =
# a single proc to reduce code size to a minimum
sysFatal(OverflowError, "over- or underflow")
-proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
+proc raiseDivByZero {.compilerproc, noinline.} =
sysFatal(DivByZeroError, "division by zero")
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
@@ -327,13 +327,13 @@ when not declared(mulInt):
# We avoid setting the FPU control word here for compatibility with libraries
# written in other languages.
-proc raiseFloatInvalidOp {.noinline, noreturn.} =
+proc raiseFloatInvalidOp {.noinline.} =
sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result")
proc nanCheck(x: float64) {.compilerProc, inline.} =
if x != x: raiseFloatInvalidOp()
-proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} =
+proc raiseFloatOverflow(x: float64) {.noinline.} =
if x > 0.0:
sysFatal(FloatOverflowError, "FPU operation caused an overflow")
else:
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
index 300fa85f3f..c97d2fc7ff 100644
--- a/lib/system/atomics.nim
+++ b/lib/system/atomics.nim
@@ -87,7 +87,7 @@ when someGcc and hasThreadSupport:
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
- importc: "__atomic_compare_exchange_n ", nodecl.}
+ importc: "__atomic_compare_exchange", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
## value is also a pointer.
diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
index 2f6d25a129..6caf99d27b 100644
--- a/lib/system/chcks.nim
+++ b/lib/system/chcks.nim
@@ -9,16 +9,16 @@
# Implementation of some runtime checks.
-proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} =
+proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
when hostOS == "standalone":
sysFatal(RangeError, "value out of range")
else:
sysFatal(RangeError, "value out of range: ", $val)
-proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+proc raiseIndexError() {.compilerproc, noinline.} =
sysFatal(IndexError, "index out of bounds")
-proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+proc raiseFieldError(f: string) {.compilerproc, noinline.} =
sysFatal(FieldError, f, " is not accessible")
proc chckIndx(i, a, b: int): int =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 1b3471978a..189d52f570 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -58,7 +58,7 @@ proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
proc popSafePoint {.compilerRtl, inl.} =
excHandler = excHandler.prev
-proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
+proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
e.parent = currException
currException = e
@@ -69,12 +69,12 @@ proc popCurrentException {.compilerRtl, inl.} =
const
nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and
not NimStackTrace
- hasSomeStackTrace = NimStackTrace or
+ hasSomeStackTrace = NimStackTrace or
defined(nativeStackTrace) and nativeStackTraceSupported
when defined(nativeStacktrace) and nativeStackTraceSupported:
type
- TDl_info {.importc: "Dl_info", header: "",
+ TDl_info {.importc: "Dl_info", header: "",
final, pure.} = object
dli_fname: cstring
dli_fbase: pointer
@@ -98,7 +98,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
tempDlInfo: TDl_info
# This is allowed to be expensive since it only happens during crashes
# (but this way you don't need manual stack tracing)
- var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
+ var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
len(tempAddresses))
var enabled = false
for i in 0..size-1:
@@ -123,7 +123,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
when not hasThreadSupport:
var
tempFrames: array [0..127, PFrame] # should not be alloc'd on stack
-
+
proc auxWriteStackTrace(f: PFrame, s: var string) =
when hasThreadSupport:
var
@@ -160,7 +160,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
inc(i)
b = b.prev
for j in countdown(i-1, 0):
- if tempFrames[j] == nil:
+ if tempFrames[j] == nil:
add(s, "(")
add(s, $skipped)
add(s, " calls omitted) ...")
@@ -214,41 +214,49 @@ proc raiseExceptionAux(e: ref Exception) =
if not localRaiseHook(e): return
if globalRaiseHook != nil:
if not globalRaiseHook(e): return
- if excHandler != nil:
- if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
- pushCurrentException(e)
- c_longjmp(excHandler.context, 1)
- elif e[] of OutOfMemError:
- showErrorMessage(e.name)
- quitOrDebug()
- else:
- when hasSomeStackTrace:
- var buf = newStringOfCap(2000)
- if isNil(e.trace): rawWriteStackTrace(buf)
- else: add(buf, e.trace)
- add(buf, "Error: unhandled exception: ")
- if not isNil(e.msg): add(buf, e.msg)
- add(buf, " [")
- add(buf, $e.name)
- add(buf, "]\n")
- showErrorMessage(buf)
+ when defined(cpp):
+ if e[] of OutOfMemError:
+ showErrorMessage(e.name)
+ quitOrDebug()
else:
- # ugly, but avoids heap allocations :-)
- template xadd(buf, s, slen: expr) =
- if L + slen < high(buf):
- copyMem(addr(buf[L]), cstring(s), slen)
- inc L, slen
- template add(buf, s: expr) =
- xadd(buf, s, s.len)
- var buf: array [0..2000, char]
- var L = 0
- add(buf, "Error: unhandled exception: ")
- if not isNil(e.msg): add(buf, e.msg)
- add(buf, " [")
- xadd(buf, e.name, c_strlen(e.name))
- add(buf, "]\n")
- showErrorMessage(buf)
- quitOrDebug()
+ pushCurrentException(e)
+ {.emit: "throw NimException(`e`, `e`->name);".}
+ else:
+ if excHandler != nil:
+ if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
+ pushCurrentException(e)
+ c_longjmp(excHandler.context, 1)
+ elif e[] of OutOfMemError:
+ showErrorMessage(e.name)
+ quitOrDebug()
+ else:
+ when hasSomeStackTrace:
+ var buf = newStringOfCap(2000)
+ if isNil(e.trace): rawWriteStackTrace(buf)
+ else: add(buf, e.trace)
+ add(buf, "Error: unhandled exception: ")
+ if not isNil(e.msg): add(buf, e.msg)
+ add(buf, " [")
+ add(buf, $e.name)
+ add(buf, "]\n")
+ showErrorMessage(buf)
+ else:
+ # ugly, but avoids heap allocations :-)
+ template xadd(buf, s, slen: expr) =
+ if L + slen < high(buf):
+ copyMem(addr(buf[L]), cstring(s), slen)
+ inc L, slen
+ template add(buf, s: expr) =
+ xadd(buf, s, s.len)
+ var buf: array [0..2000, char]
+ var L = 0
+ add(buf, "Error: unhandled exception: ")
+ if not isNil(e.msg): add(buf, e.msg)
+ add(buf, " [")
+ xadd(buf, e.name, c_strlen(e.name))
+ add(buf, "]\n")
+ showErrorMessage(buf)
+ quitOrDebug()
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
e.name = ename
@@ -309,7 +317,7 @@ when not defined(noSignalHandler):
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
template processSignal(s, action: expr) {.immediate, dirty.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
- elif s == SIGSEGV:
+ elif s == SIGSEGV:
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
elif s == SIGABRT:
when defined(endb):
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 84e5320493..a378f86e7e 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -109,24 +109,24 @@ when defined(boehmgc):
when not defined(useNimRtl):
- proc alloc(size: int): pointer =
+ proc alloc(size: Natural): pointer =
result = boehmAlloc(size)
if result == nil: raiseOutOfMem()
- proc alloc0(size: int): pointer =
+ proc alloc0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
- proc realloc(p: pointer, newsize: int): pointer =
+ proc realloc(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = boehmDealloc(p)
- proc allocShared(size: int): pointer =
+ proc allocShared(size: Natural): pointer =
result = boehmAlloc(size)
if result == nil: raiseOutOfMem()
- proc allocShared0(size: int): pointer =
+ proc allocShared0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
- proc reallocShared(p: pointer, newsize: int): pointer =
+ proc reallocShared(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = boehmDealloc(p)
@@ -196,24 +196,24 @@ when defined(boehmgc):
elif defined(nogc) and defined(useMalloc):
when not defined(useNimRtl):
- proc alloc(size: int): pointer =
+ proc alloc(size: Natural): pointer =
result = cmalloc(size)
if result == nil: raiseOutOfMem()
- proc alloc0(size: int): pointer =
+ proc alloc0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
- proc realloc(p: pointer, newsize: int): pointer =
+ proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p)
- proc allocShared(size: int): pointer =
+ proc allocShared(size: Natural): pointer =
result = cmalloc(size)
if result == nil: raiseOutOfMem()
- proc allocShared0(size: int): pointer =
+ proc allocShared0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
- proc reallocShared(p: pointer, newsize: int): pointer =
+ proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p)
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 468af17139..3f860655ee 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -16,7 +16,7 @@
# of the standard library!
-proc fputs(c: cstring, f: File) {.importc: "fputs", header: "",
+proc fputs(c: cstring, f: File) {.importc: "fputs", header: "",
tags: [WriteIOEffect].}
proc fgets(c: cstring, n: int, f: File): cstring {.
importc: "fgets", header: "", tags: [ReadIOEffect].}
@@ -26,11 +26,30 @@ proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "",
tags: [].}
proc putc(c: char, stream: File) {.importc: "putc", header: "",
tags: [WriteIOEffect].}
-proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
+proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
header: "", varargs, tags: [WriteIOEffect].}
proc strlen(c: cstring): int {.
importc: "strlen", header: "", tags: [].}
+when defined(posix):
+ proc getc_unlocked(stream: File): cint {.importc: "getc_unlocked",
+ header: "", tags: [ReadIOEffect].}
+
+ proc flockfile(stream: File) {.importc: "flockfile", header: "",
+ tags: [ReadIOEffect].}
+
+ proc funlockfile(stream: File) {.importc: "funlockfile", header: "",
+ tags: [ReadIOEffect].}
+elif false:
+ # doesn't work on Windows yet:
+ proc getc_unlocked(stream: File): cint {.importc: "_fgetc_nolock",
+ header: "", tags: [ReadIOEffect].}
+
+ proc flockfile(stream: File) {.importc: "_lock_file", header: "",
+ tags: [ReadIOEffect].}
+
+ proc funlockfile(stream: File) {.importc: "_unlock_file", header: "",
+ tags: [ReadIOEffect].}
# C routine that is used here:
proc fread(buf: pointer, size, n: int, f: File): int {.
@@ -67,39 +86,57 @@ const
proc raiseEIO(msg: string) {.noinline, noreturn.} =
sysFatal(IOError, msg)
-proc readLine(f: File, line: var TaintedString): bool =
- # of course this could be optimized a bit; but IO is slow anyway...
- # and it was difficult to get this CORRECT with Ansi C's methods
- setLen(line.string, 0) # reuse the buffer!
- while true:
- var c = fgetc(f)
- if c < 0'i32:
- if line.len > 0: break
- else: return false
- if c == 10'i32: break # LF
- if c == 13'i32: # CR
- c = fgetc(f) # is the next char LF?
- if c != 10'i32: ungetc(c, f) # no, put the character back
- break
- add line.string, chr(int(c))
- result = true
+when declared(getc_unlocked):
+ proc readLine(f: File, line: var TaintedString): bool =
+ setLen(line.string, 0) # reuse the buffer!
+ flockfile(f)
+ while true:
+ var c = getc_unlocked(f)
+ if c < 0'i32:
+ if line.len > 0: break
+ else: return false
+ if c == 10'i32: break # LF
+ if c == 13'i32: # CR
+ c = getc_unlocked(f) # is the next char LF?
+ if c != 10'i32: ungetc(c, f) # no, put the character back
+ break
+ add line.string, chr(int(c))
+ result = true
+ funlockfile(f)
+else:
+ proc readLine(f: File, line: var TaintedString): bool =
+ # of course this could be optimized a bit; but IO is slow anyway...
+ # and it was difficult to get this CORRECT with Ansi C's methods
+ setLen(line.string, 0) # reuse the buffer!
+ while true:
+ var c = fgetc(f)
+ if c < 0'i32:
+ if line.len > 0: break
+ else: return false
+ if c == 10'i32: break # LF
+ if c == 13'i32: # CR
+ c = fgetc(f) # is the next char LF?
+ if c != 10'i32: ungetc(c, f) # no, put the character back
+ break
+ add line.string, chr(int(c))
+ result = true
proc readLine(f: File): TaintedString =
result = TaintedString(newStringOfCap(80))
if not readLine(f, result): raiseEIO("EOF reached")
-proc write(f: File, i: int) =
+proc write(f: File, i: int) =
when sizeof(int) == 8:
fprintf(f, "%lld", i)
else:
fprintf(f, "%ld", i)
-proc write(f: File, i: BiggestInt) =
+proc write(f: File, i: BiggestInt) =
when sizeof(BiggestInt) == 8:
fprintf(f, "%lld", i)
else:
fprintf(f, "%ld", i)
-
+
proc write(f: File, b: bool) =
if b: write(f, "true")
else: write(f, "false")
@@ -110,7 +147,7 @@ proc write(f: File, c: char) = putc(c, f)
proc write(f: File, a: varargs[string, `$`]) =
for x in items(a): write(f, x)
-proc readAllBuffer(file: File): string =
+proc readAllBuffer(file: File): string =
# This proc is for File we want to read but don't know how many
# bytes we need to read before the buffer is empty.
result = ""
@@ -123,8 +160,8 @@ proc readAllBuffer(file: File): string =
buffer.setLen(bytesRead)
result.add(buffer)
break
-
-proc rawFileSize(file: File): int =
+
+proc rawFileSize(file: File): int =
# this does not raise an error opposed to `getFileSize`
var oldPos = ftell(file)
discard fseek(file, 0, 2) # seek the end of the file
@@ -141,8 +178,8 @@ proc readAllFile(file: File, len: int): string =
proc readAllFile(file: File): string =
var len = rawFileSize(file)
result = readAllFile(file, len)
-
-proc readAll(file: File): TaintedString =
+
+proc readAll(file: File): TaintedString =
# Separate handling needed because we need to buffer when we
# don't know the overall length of the File.
let len = if file != stdin: rawFileSize(file) else: -1
@@ -150,7 +187,7 @@ proc readAll(file: File): TaintedString =
result = readAllFile(file, len).TaintedString
else:
result = readAllBuffer(file).TaintedString
-
+
proc readFile(filename: string): TaintedString =
var f = open(filename)
try:
@@ -229,7 +266,7 @@ proc open(f: var File, filename: string,
elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0)
-proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
+proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
var p: pointer = freopen(filename, FormatOpen[mode], f)
result = p != nil
@@ -243,23 +280,23 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
proc fwrite(buf: pointer, size, n: int, f: File): int {.
importc: "fwrite", noDecl.}
-proc readBuffer(f: File, buffer: pointer, len: int): int =
+proc readBuffer(f: File, buffer: pointer, len: Natural): int =
result = fread(buffer, 1, len, f)
-proc readBytes(f: File, a: var openArray[int8|uint8], start, len: int): int =
+proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len)
-proc readChars(f: File, a: var openArray[char], start, len: int): int =
+proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len)
{.push stackTrace:off, profiler:off.}
-proc writeBytes(f: File, a: openArray[int8|uint8], start, len: int): int =
+proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len)
-proc writeChars(f: File, a: openArray[char], start, len: int): int =
+proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len)
-proc writeBuffer(f: File, buffer: pointer, len: int): int =
+proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
result = fwrite(buffer, 1, len, f)
proc write(f: File, s: string) =
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index 43c595a644..02c87132af 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -11,7 +11,7 @@
## Unicode version.
{.deadCodeElim: on.}
-
+{.push gcsafe.}
type
WideChar* = uint16
PWideChar* = ptr uint16
@@ -18513,11 +18513,15 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,
proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,
dynlib: "kernel32", importc: "GetProcAddress".}
proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".}
-proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,
+proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall,
dynlib: "kernel32", importc: "GlobalAlloc".}
-proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.
+proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,
+ dynlib: "kernel32", importc: "GlobalAlloc", deprecated.}
+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{.
stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}
-proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32",
+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.
+ stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.}
+proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32",
importc: "GlobalSize".}
proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32",
importc: "GlobalFlags".}
@@ -18541,10 +18545,14 @@ proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",
importc: "GlobalUnWire".}
proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32",
importc: "GlobalMemoryStatus".}
-proc LocalAlloc*(uFlags: WINUINT, uBytes: WINUINT): HLOCAL{.stdcall,
+proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall,
dynlib: "kernel32", importc: "LocalAlloc".}
-proc LocalReAlloc*(hMem: HLOCAL, uBytes: WINUINT, uFlags: WINUINT): HLOCAL{.stdcall,
+proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall,
+ dynlib: "kernel32", importc: "LocalAlloc", deprecated.}
+proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall,
dynlib: "kernel32", importc: "LocalReAlloc".}
+proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall,
+ dynlib: "kernel32", importc: "LocalReAlloc", deprecated.}
proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32",
importc: "LocalLock".}
proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32",
@@ -18564,38 +18572,71 @@ proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",
proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID,
dwSize: DWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "FlushInstructionCache".}
-proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,
+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD,
flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",
importc: "VirtualAlloc".}
-proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.
+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,
+ flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",
+ importc: "VirtualAlloc", deprecated.}
+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,
+ flAllocationType: DWORD, flProtect: DWORD): LPVOID
+ {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".}
+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,
+ flAllocationType: DWORD, flProtect: DWORD): LPVOID
+ {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx",
+ deprecated.}
+proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "VirtualFree".}
-proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,
+proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.
+ stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.}
+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,
+ dwFreeType: DWORD): WINBOOL
+ {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}
+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,
+ dwFreeType: DWORD): WINBOOL
+ {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}
+proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD,
lpflOldProtect: PDWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "VirtualProtect".}
+proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,
+ lpflOldProtect: PDWORD): WINBOOL{.stdcall,
+ dynlib: "kernel32", importc: "VirtualProtect", deprecated.}
proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION,
dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32",
importc: "VirtualQuery".}
-proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,
+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,
flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".}
+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,
+ flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.
+ stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.}
+proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,
+ lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{.
+ stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}
proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,
lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.
- stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}
-proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.
+ stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.}
+proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{.
stdcall, dynlib: "kernel32", importc: "HeapCreate".}
+proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.
+ stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.}
proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",
importc: "HeapDestroy".}
-proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,
+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall,
dynlib: "kernel32", importc: "HeapAlloc".}
-proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.
+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,
+ dynlib: "kernel32", importc: "HeapAlloc", deprecated.}
+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{.
stdcall, dynlib: "kernel32", importc: "HeapReAlloc".}
+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.
+ stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.}
proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "HeapFree".}
-proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): DWORD{.stdcall,
+proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall,
dynlib: "kernel32", importc: "HeapSize".}
proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "HeapValidate".}
-proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): WINUINT{.stdcall,
+proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall,
dynlib: "kernel32", importc: "HeapCompact".}
proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32",
importc: "GetProcessHeap".}
@@ -19221,10 +19262,14 @@ proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "FindNextChangeNotification".}
proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "FindCloseChangeNotification".}
-proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,
+proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "VirtualLock".}
-proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,
+proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,
+ dynlib: "kernel32", importc: "VirtualLock", deprecated.}
+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "VirtualUnlock".}
+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,
+ dynlib: "kernel32", importc: "VirtualUnlock", deprecated.}
proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD,
dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{.
@@ -23481,7 +23526,7 @@ proc ListView_EnsureVisible(hwndLV: HWND, i, fPartialOK: int32): LRESULT =
MAKELPARAM(fPartialOK, 0))
proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 =
- result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),
+ result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),
cast[LPARAM](addr(lvfi))).int32
proc ListView_GetBkColor(wnd: HWND): LRESULT =
@@ -23615,9 +23660,9 @@ proc ListView_SetTextBkColor(wnd: HWND, clrTextBk: COLORREF): LRESULT =
proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT =
result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText))
-proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,
+proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,
lPrm: LPARAM): LRESULT =
- result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),
+ result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),
cast[LPARAM](pfnCompare))
proc ListView_Update(hwndLV: HWND, i: int32): LRESULT =
@@ -23924,3 +23969,5 @@ proc LOCALE_NEUTRAL(): DWORD =
proc LOCALE_INVARIANT(): DWORD =
result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT)
+
+{.pop.}
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 584f7cf482..57b79c7ded 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -10,6 +10,8 @@
## This module implements a small wrapper for some needed Win API procedures,
## so that the Nim compiler does not depend on the huge Windows module.
+{.deadCodeElim:on.}
+
const
useWinUnicode* = not defined(useWinAnsi)
@@ -29,7 +31,7 @@ type
nLength*: int32
lpSecurityDescriptor*: pointer
bInheritHandle*: WINBOOL
-
+
TSTARTUPINFO* {.final, pure.} = object
cb*: int32
lpReserved*: cstring
@@ -59,7 +61,7 @@ type
TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
dwLowDateTime*: DWORD
dwHighDateTime*: DWORD
-
+
TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
dwFileAttributes*: DWORD
ftCreationTime*: TFILETIME
@@ -94,26 +96,26 @@ const
STD_ERROR_HANDLE* = -12'i32
DETACHED_PROCESS* = 8'i32
-
+
SW_SHOWNORMAL* = 1'i32
INVALID_HANDLE_VALUE* = THandle(-1)
-
+
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
-
+
proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
-
+
proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
- lpNumberOfBytesWritten: ptr int32,
+ lpNumberOfBytesWritten: ptr int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc createPipe*(hReadPipe, hWritePipe: var THandle,
- lpPipeAttributes: var TSECURITY_ATTRIBUTES,
+ lpPipeAttributes: var TSECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
@@ -159,7 +161,7 @@ proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
-proc getLastError*(): int32 {.importc: "GetLastError",
+proc getLastError*(): int32 {.importc: "GetLastError",
stdcall, dynlib: "kernel32".}
when useWinUnicode:
@@ -179,7 +181,7 @@ proc localFree*(p: pointer) {.
importc: "LocalFree", stdcall, dynlib: "kernel32".}
when useWinUnicode:
- proc getCurrentDirectoryW*(nBufferLength: int32,
+ proc getCurrentDirectoryW*(nBufferLength: int32,
lpBuffer: WideCString): int32 {.
importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {.
@@ -191,8 +193,8 @@ when useWinUnicode:
proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
- proc getModuleFileNameW*(handle: THandle, buf: WideCString,
- size: int32): int32 {.importc: "GetModuleFileNameW",
+ proc getModuleFileNameW*(handle: THandle, buf: WideCString,
+ size: int32): int32 {.importc: "GetModuleFileNameW",
dynlib: "kernel32", stdcall.}
else:
proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
@@ -269,14 +271,14 @@ proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
when useWinUnicode:
proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32,
- lpBuffer: WideCString,
+ lpBuffer: WideCString,
lpFilePart: var WideCString): int32 {.
- stdcall, dynlib: "kernel32",
+ stdcall, dynlib: "kernel32",
importc: "GetFullPathNameW".}
proc getFileAttributesW*(lpFileName: WideCString): int32 {.
- stdcall, dynlib: "kernel32",
+ stdcall, dynlib: "kernel32",
importc: "GetFileAttributesW".}
- proc setFileAttributesW*(lpFileName: WideCString,
+ proc setFileAttributesW*(lpFileName: WideCString,
dwFileAttributes: int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}
@@ -299,12 +301,12 @@ when useWinUnicode:
else:
proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
lpBuffer: cstring, lpFilePart: var cstring): int32 {.
- stdcall, dynlib: "kernel32",
+ stdcall, dynlib: "kernel32",
importc: "GetFullPathNameA".}
proc getFileAttributesA*(lpFileName: cstring): int32 {.
- stdcall, dynlib: "kernel32",
+ stdcall, dynlib: "kernel32",
importc: "GetFileAttributesA".}
- proc setFileAttributesA*(lpFileName: cstring,
+ proc setFileAttributesA*(lpFileName: cstring,
dwFileAttributes: int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
@@ -324,10 +326,10 @@ else:
proc getCommandLineA*(): cstring {.
importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
-proc rdFileTime*(f: TFILETIME): int64 =
+proc rdFileTime*(f: TFILETIME): int64 =
result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
-proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
+proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
@@ -347,7 +349,7 @@ else:
lpParameters, lpDirectory: cstring,
nShowCmd: int32): THandle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
-
+
proc getFileInformationByHandle*(hFile: THandle,
lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
@@ -357,12 +359,12 @@ const
WSASYS_STATUS_LEN* = 128
FD_SETSIZE* = 64
MSG_PEEK* = 2
-
+
INADDR_ANY* = 0
INADDR_LOOPBACK* = 0x7F000001
INADDR_BROADCAST* = -1
INADDR_NONE* = -1
-
+
ws2dll = "Ws2_32.dll"
WSAEWOULDBLOCK* = 10035
@@ -376,31 +378,31 @@ type
{.deprecated: [TSocketHandle: SocketHandle].}
type
- WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
+ WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
wVersion, wHighVersion: int16
szDescription: array[0..WSADESCRIPTION_LEN, char]
szSystemStatus: array[0..WSASYS_STATUS_LEN, char]
iMaxSockets, iMaxUdpDg: int16
lpVendorInfo: cstring
-
- SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
+
+ SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
sa_family*: int16 # unsigned
sa_data: array[0..13, char]
InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
s_addr*: int32 # IP address
-
- Sockaddr_in* {.importc: "SOCKADDR_IN",
+
+ Sockaddr_in* {.importc: "SOCKADDR_IN",
header: "winsock2.h".} = object
sin_family*: int16
sin_port*: int16 # unsigned
sin_addr*: InAddr
sin_zero*: array[0..7, char]
- In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
+ In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
bytes*: array[0..15, char]
- Sockaddr_in6* {.importc: "SOCKADDR_IN6",
+ Sockaddr_in6* {.importc: "SOCKADDR_IN6",
header: "winsock2.h".} = object
sin6_family*: int16
sin6_port*: int16 # unsigned
@@ -430,23 +432,23 @@ type
h_addrtype*: int16
h_length*: int16
h_addr_list*: cstringArray
-
+
TFdSet* = object
fd_count*: cint # unsigned
fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
-
+
Timeval* = object
tv_sec*, tv_usec*: int32
-
+
AddrInfo* = object
- ai_flags*: cint ## Input flags.
- ai_family*: cint ## Address family of socket.
- ai_socktype*: cint ## Socket type.
- ai_protocol*: cint ## Protocol of socket.
- ai_addrlen*: int ## Length of socket address.
+ ai_flags*: cint ## Input flags.
+ ai_family*: cint ## Address family of socket.
+ ai_socktype*: cint ## Socket type.
+ ai_protocol*: cint ## Protocol of socket.
+ ai_addrlen*: int ## Length of socket address.
ai_canonname*: cstring ## Canonical name of service location.
- ai_addr*: ptr SockAddr ## Socket address of socket.
- ai_next*: ptr AddrInfo ## Pointer to next in list.
+ ai_addr*: ptr SockAddr ## Socket address of socket.
+ ai_next*: ptr AddrInfo ## Pointer to next in list.
SockLen* = cuint
@@ -501,7 +503,7 @@ proc bindSocket*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
stdcall, importc: "bind", dynlib: ws2dll.}
proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
stdcall, importc: "connect", dynlib: ws2dll.}
-proc getsockname*(s: SocketHandle, name: ptr SockAddr,
+proc getsockname*(s: SocketHandle, name: ptr SockAddr,
namelen: ptr SockLen): cint {.
stdcall, importc: "getsockname", dynlib: ws2dll.}
proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
@@ -515,7 +517,7 @@ proc listen*(s: SocketHandle, backlog: cint): cint {.
stdcall, importc: "listen", dynlib: ws2dll.}
proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "recv", dynlib: ws2dll.}
-proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
+proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
fromm: ptr SockAddr, fromlen: ptr SockLen): cint {.
stdcall, importc: "recvfrom", dynlib: ws2dll.}
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
@@ -529,22 +531,22 @@ proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint,
proc shutdown*(s: SocketHandle, how: cint): cint {.
stdcall, importc: "shutdown", dynlib: ws2dll.}
-
+
proc getnameinfo*(a1: ptr SockAddr, a2: SockLen,
a3: cstring, a4: SockLen, a5: cstring,
a6: SockLen, a7: cint): cint {.
stdcall, importc: "getnameinfo", dynlib: ws2dll.}
-
+
proc inet_addr*(cp: cstring): int32 {.
- stdcall, importc: "inet_addr", dynlib: ws2dll.}
+ stdcall, importc: "inet_addr", dynlib: ws2dll.}
proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {.
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
-proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
+proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
result = if WSAFDIsSet(socket, set): 1'i32 else: 0'i32
-proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
+proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
if s.fd_count < FD_SETSIZE:
s.fd_array[int(s.fd_count)] = socket
inc(s.fd_count)
@@ -575,8 +577,8 @@ type
proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
-
-
+
+
# for memfiles.nim:
const
@@ -586,7 +588,7 @@ const
FILE_SHARE_READ* = 1'i32
FILE_SHARE_DELETE* = 4'i32
FILE_SHARE_WRITE* = 2'i32
-
+
CREATE_ALWAYS* = 2'i32
CREATE_NEW* = 1'i32
OPEN_EXISTING* = 3'i32
@@ -628,7 +630,7 @@ proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "SetEndOfFile".}
proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
- lpDistanceToMoveHigh: ptr LONG,
+ lpDistanceToMoveHigh: ptr LONG,
dwMoveMethod: DWORD): DWORD {.
stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
@@ -637,14 +639,14 @@ proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
dwFileOffsetHigh, dwFileOffsetLow: DWORD,
- dwNumberOfBytesToMap: DWORD,
+ dwNumberOfBytesToMap: DWORD,
lpBaseAddress: pointer): pointer{.
stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
proc createFileMappingW*(hFile: THandle,
lpFileMappingAttributes: pointer,
flProtect, dwMaximumSizeHigh: DWORD,
- dwMaximumSizeLow: DWORD,
+ dwMaximumSizeLow: DWORD,
lpName: pointer): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
@@ -702,7 +704,7 @@ proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
-const
+const
IOC_OUT* = 0x40000000
IOC_IN* = 0x80000000
IOC_WS2* = 0x08000000
@@ -725,7 +727,7 @@ var
proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
- lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
+ lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
{.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".}
type
@@ -746,7 +748,7 @@ proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
proc get_osfhandle*(fd:FileHandle): THandle {.
importc: "_get_osfhandle", header:"".}
-proc getSystemTimes*(lpIdleTime, lpKernelTime,
+proc getSystemTimes*(lpIdleTime, lpKernelTime,
lpUserTime: var TFILETIME): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "GetSystemTimes".}
diff --git a/lib/wrappers/claro.nim b/lib/wrappers/claro.nim
index d36b9f1783..0fb0882bf5 100644
--- a/lib/wrappers/claro.nim
+++ b/lib/wrappers/claro.nim
@@ -2710,7 +2710,7 @@ proc workspace_window_set_icon*(w: ptr TWorkspaceWindow, icon: ptr TImage){.
claro_base_init()
claro_graphics_init()
-when isMainModule:
+when not defined(testing) and isMainModule:
var w = newWindow(nil, newBounds(100, 100, 230, 230), 0)
window_set_title(w, "Hello, World!")
diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim
index 27ab7d870a..93e14cccdd 100644
--- a/lib/wrappers/iup.nim
+++ b/lib/wrappers/iup.nim
@@ -1,13 +1,13 @@
#
# Binding for the IUP GUI toolkit
-# (c) 2012 Andreas Rumpf
+# (c) 2012 Andreas Rumpf
# C header files translated by hand
# Licence of IUP follows:
# ****************************************************************************
# Copyright (C) 1994-2009 Tecgraf, PUC-Rio.
-#
+#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -30,12 +30,12 @@
{.deadCodeElim: on.}
-when defined(windows):
- const dllname = "iup(30|27|26|25|24).dll"
+when defined(windows):
+ const dllname = "iup(|30|27|26|25|24).dll"
elif defined(macosx):
- const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).dylib"
-else:
- const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).so.1"
+ const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib"
+else:
+ const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)"
const
IUP_NAME* = "IUP - Portable User Interface"
@@ -67,8 +67,8 @@ proc alarm*(title, msg, b1, b2, b3: cstring): cint {.
importc: "IupAlarm", dynlib: dllname, cdecl.}
proc scanf*(format: cstring): cint {.
importc: "IupScanf", dynlib: dllname, cdecl, varargs.}
-proc listDialog*(theType: cint, title: cstring, size: cint,
- list: cstringArray, op, maxCol, maxLin: cint,
+proc listDialog*(theType: cint, title: cstring, size: cint,
+ list: cstringArray, op, maxCol, maxLin: cint,
marks: ptr cint): cint {.
importc: "IupListDialog", dynlib: dllname, cdecl.}
proc getText*(title, text: cstring): cint {.
@@ -77,14 +77,14 @@ proc getColor*(x, y: cint, r, g, b: var byte): cint {.
importc: "IupGetColor", dynlib: dllname, cdecl.}
type
- Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
+ Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
userData: pointer): cint {.cdecl.}
-proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
+proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
format: cstring): cint {.
importc: "IupGetParam", cdecl, varargs, dynlib: dllname.}
-proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
- format: cstring, paramCount, paramExtra: cint,
+proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
+ format: cstring, paramCount, paramExtra: cint,
paramData: pointer): cint {.
importc: "IupGetParamv", cdecl, dynlib: dllname.}
@@ -96,11 +96,11 @@ proc open*(argc: ptr cint, argv: ptr cstringArray): cint {.
proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.}
proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.}
-proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
+proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
discardable.}
proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname,
discardable.}
-proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
+proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
dynlib: dllname, discardable.}
proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.}
proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.}
@@ -204,7 +204,7 @@ proc getCallback*(ih: PIhandle, name: cstring): Icallback {.
importc: "IupGetCallback", cdecl, dynlib: dllname.}
proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {.
importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.}
-
+
proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {.
importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.}
@@ -235,7 +235,7 @@ proc getClassName*(ih: PIhandle): cstring {.
importc: "IupGetClassName", cdecl, dynlib: dllname.}
proc getClassType*(ih: PIhandle): cstring {.
importc: "IupGetClassType", cdecl, dynlib: dllname.}
-proc getClassAttributes*(classname: cstring, names: cstringArray,
+proc getClassAttributes*(classname: cstring, names: cstringArray,
n: cint): cint {.
importc: "IupGetClassAttributes", cdecl, dynlib: dllname.}
proc saveClassAttributes*(ih: PIhandle) {.
@@ -378,12 +378,12 @@ const
IUP_CONTINUE* = cint(-4)
# IupPopup and IupShowXY Parameter Values
- IUP_CENTER* = cint(0xFFFF)
- IUP_LEFT* = cint(0xFFFE)
- IUP_RIGHT* = cint(0xFFFD)
- IUP_MOUSEPOS* = cint(0xFFFC)
- IUP_CURRENT* = cint(0xFFFB)
- IUP_CENTERPARENT* = cint(0xFFFA)
+ IUP_CENTER* = cint(0xFFFF)
+ IUP_LEFT* = cint(0xFFFE)
+ IUP_RIGHT* = cint(0xFFFD)
+ IUP_MOUSEPOS* = cint(0xFFFC)
+ IUP_CURRENT* = cint(0xFFFB)
+ IUP_CENTERPARENT* = cint(0xFFFA)
IUP_TOP* = IUP_LEFT
IUP_BOTTOM* = IUP_RIGHT
@@ -397,10 +397,10 @@ const
# SCROLL_CB Callback Values
IUP_SBUP* = cint(0)
IUP_SBDN* = cint(1)
- IUP_SBPGUP* = cint(2)
+ IUP_SBPGUP* = cint(2)
IUP_SBPGDN* = cint(3)
IUP_SBPOSV* = cint(4)
- IUP_SBDRAGV* = cint(5)
+ IUP_SBDRAGV* = cint(5)
IUP_SBLEFT* = cint(6)
IUP_SBRIGHT* = cint(7)
IUP_SBPGLEFT* = cint(8)
@@ -433,12 +433,12 @@ const
IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?"
IUP_MASK_INT* = "[+/-]?/d+"
IUP_MASK_UINT* = "/d+"
-
+
# from 32 to 126, all character sets are equal,
# the key code i the same as the character code.
const
K_SP* = cint(ord(' '))
- K_exclam* = cint(ord('!'))
+ K_exclam* = cint(ord('!'))
K_quotedbl* = cint(ord('\"'))
K_numbersign* = cint(ord('#'))
K_dollar* = cint(ord('$'))
@@ -467,51 +467,51 @@ const
K_semicolon* = cint(ord(';'))
K_less* = cint(ord('<'))
K_equal* = cint(ord('='))
- K_greater* = cint(ord('>'))
- K_question* = cint(ord('?'))
- K_at* = cint(ord('@'))
- K_upperA* = cint(ord('A'))
- K_upperB* = cint(ord('B'))
- K_upperC* = cint(ord('C'))
- K_upperD* = cint(ord('D'))
- K_upperE* = cint(ord('E'))
- K_upperF* = cint(ord('F'))
- K_upperG* = cint(ord('G'))
- K_upperH* = cint(ord('H'))
- K_upperI* = cint(ord('I'))
- K_upperJ* = cint(ord('J'))
- K_upperK* = cint(ord('K'))
- K_upperL* = cint(ord('L'))
- K_upperM* = cint(ord('M'))
- K_upperN* = cint(ord('N'))
- K_upperO* = cint(ord('O'))
- K_upperP* = cint(ord('P'))
- K_upperQ* = cint(ord('Q'))
- K_upperR* = cint(ord('R'))
- K_upperS* = cint(ord('S'))
- K_upperT* = cint(ord('T'))
- K_upperU* = cint(ord('U'))
- K_upperV* = cint(ord('V'))
- K_upperW* = cint(ord('W'))
- K_upperX* = cint(ord('X'))
- K_upperY* = cint(ord('Y'))
- K_upperZ* = cint(ord('Z'))
- K_bracketleft* = cint(ord('['))
- K_backslash* = cint(ord('\\'))
- K_bracketright* = cint(ord(']'))
- K_circum* = cint(ord('^'))
- K_underscore* = cint(ord('_'))
- K_grave* = cint(ord('`'))
- K_lowera* = cint(ord('a'))
- K_lowerb* = cint(ord('b'))
- K_lowerc* = cint(ord('c'))
- K_lowerd* = cint(ord('d'))
- K_lowere* = cint(ord('e'))
- K_lowerf* = cint(ord('f'))
+ K_greater* = cint(ord('>'))
+ K_question* = cint(ord('?'))
+ K_at* = cint(ord('@'))
+ K_upperA* = cint(ord('A'))
+ K_upperB* = cint(ord('B'))
+ K_upperC* = cint(ord('C'))
+ K_upperD* = cint(ord('D'))
+ K_upperE* = cint(ord('E'))
+ K_upperF* = cint(ord('F'))
+ K_upperG* = cint(ord('G'))
+ K_upperH* = cint(ord('H'))
+ K_upperI* = cint(ord('I'))
+ K_upperJ* = cint(ord('J'))
+ K_upperK* = cint(ord('K'))
+ K_upperL* = cint(ord('L'))
+ K_upperM* = cint(ord('M'))
+ K_upperN* = cint(ord('N'))
+ K_upperO* = cint(ord('O'))
+ K_upperP* = cint(ord('P'))
+ K_upperQ* = cint(ord('Q'))
+ K_upperR* = cint(ord('R'))
+ K_upperS* = cint(ord('S'))
+ K_upperT* = cint(ord('T'))
+ K_upperU* = cint(ord('U'))
+ K_upperV* = cint(ord('V'))
+ K_upperW* = cint(ord('W'))
+ K_upperX* = cint(ord('X'))
+ K_upperY* = cint(ord('Y'))
+ K_upperZ* = cint(ord('Z'))
+ K_bracketleft* = cint(ord('['))
+ K_backslash* = cint(ord('\\'))
+ K_bracketright* = cint(ord(']'))
+ K_circum* = cint(ord('^'))
+ K_underscore* = cint(ord('_'))
+ K_grave* = cint(ord('`'))
+ K_lowera* = cint(ord('a'))
+ K_lowerb* = cint(ord('b'))
+ K_lowerc* = cint(ord('c'))
+ K_lowerd* = cint(ord('d'))
+ K_lowere* = cint(ord('e'))
+ K_lowerf* = cint(ord('f'))
K_lowerg* = cint(ord('g'))
- K_lowerh* = cint(ord('h'))
- K_loweri* = cint(ord('i'))
- K_lowerj* = cint(ord('j'))
+ K_lowerh* = cint(ord('h'))
+ K_loweri* = cint(ord('i'))
+ K_lowerj* = cint(ord('j'))
K_lowerk* = cint(ord('k'))
K_lowerl* = cint(ord('l'))
K_lowerm* = cint(ord('m'))
@@ -553,19 +553,19 @@ proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024
proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280
proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128)
-proc iUPsxCODE*(c: cint): cint =
+proc iUPsxCODE*(c: cint): cint =
return c + cint(256)
- # Shift (must have range to include the standard keys and the normal
+ # Shift (must have range to include the standard keys and the normal
# extended keys, so must be above 256
proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl
proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt
-proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
+proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
const
IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys
- K_HOME* = iUPxCODE(1)
+ K_HOME* = iUPxCODE(1)
K_UP* = iUPxCODE(2)
K_PGUP* = iUPxCODE(3)
K_LEFT* = iUPxCODE(4)
@@ -574,8 +574,8 @@ const
K_END* = iUPxCODE(7)
K_DOWN* = iUPxCODE(8)
K_PGDN* = iUPxCODE(9)
- K_INS* = iUPxCODE(10)
- K_DEL* = iUPxCODE(11)
+ K_INS* = iUPxCODE(10)
+ K_DEL* = iUPxCODE(11)
K_PAUSE* = iUPxCODE(12)
K_ESC* = iUPxCODE(13)
K_ccedilla* = iUPxCODE(14)
@@ -728,13 +728,13 @@ const
K_yPrint* = iUPyxCODE(K_Print)
K_yMenu* = iUPyxCODE(K_Menu)
- K_sPlus* = iUPsxCODE(K_plus)
- K_sComma* = iUPsxCODE(K_comma)
- K_sMinus* = iUPsxCODE(K_minus)
- K_sPeriod* = iUPsxCODE(K_period)
- K_sSlash* = iUPsxCODE(K_slash)
+ K_sPlus* = iUPsxCODE(K_plus)
+ K_sComma* = iUPsxCODE(K_comma)
+ K_sMinus* = iUPsxCODE(K_minus)
+ K_sPeriod* = iUPsxCODE(K_period)
+ K_sSlash* = iUPsxCODE(K_slash)
K_sAsterisk* = iUPsxCODE(K_asterisk)
-
+
K_cupperA* = iUPcxCODE(K_upperA)
K_cupperB* = iUPcxCODE(K_upperB)
K_cupperC* = iUPcxCODE(K_upperC)
@@ -767,16 +767,16 @@ const
K_c4* = iUPcxCODE(K_4)
K_c5* = iUPcxCODE(K_5)
K_c6* = iUPcxCODE(K_6)
- K_c7* = iUPcxCODE(K_7)
- K_c8* = iUPcxCODE(K_8)
+ K_c7* = iUPcxCODE(K_7)
+ K_c8* = iUPcxCODE(K_8)
K_c9* = iUPcxCODE(K_9)
K_c0* = iUPcxCODE(K_0)
- K_cPlus* = iUPcxCODE(K_plus)
- K_cComma* = iUPcxCODE(K_comma)
- K_cMinus* = iUPcxCODE(K_minus)
- K_cPeriod* = iUPcxCODE(K_period)
- K_cSlash* = iUPcxCODE(K_slash)
- K_cSemicolon* = iUPcxCODE(K_semicolon)
+ K_cPlus* = iUPcxCODE(K_plus)
+ K_cComma* = iUPcxCODE(K_comma)
+ K_cMinus* = iUPcxCODE(K_minus)
+ K_cPeriod* = iUPcxCODE(K_period)
+ K_cSlash* = iUPcxCODE(K_slash)
+ K_cSemicolon* = iUPcxCODE(K_semicolon)
K_cEqual* = iUPcxCODE(K_equal)
K_cBracketleft* = iUPcxCODE(K_bracketleft)
K_cBracketright* = iUPcxCODE(K_bracketright)
@@ -815,16 +815,16 @@ const
K_m4* = iUPmxCODE(K_4)
K_m5* = iUPmxCODE(K_5)
K_m6* = iUPmxCODE(K_6)
- K_m7* = iUPmxCODE(K_7)
- K_m8* = iUPmxCODE(K_8)
+ K_m7* = iUPmxCODE(K_7)
+ K_m8* = iUPmxCODE(K_8)
K_m9* = iUPmxCODE(K_9)
K_m0* = iUPmxCODE(K_0)
- K_mPlus* = iUPmxCODE(K_plus)
- K_mComma* = iUPmxCODE(K_comma)
- K_mMinus* = iUPmxCODE(K_minus)
- K_mPeriod* = iUPmxCODE(K_period)
- K_mSlash* = iUPmxCODE(K_slash)
- K_mSemicolon* = iUPmxCODE(K_semicolon)
+ K_mPlus* = iUPmxCODE(K_plus)
+ K_mComma* = iUPmxCODE(K_comma)
+ K_mMinus* = iUPmxCODE(K_minus)
+ K_mPeriod* = iUPmxCODE(K_period)
+ K_mSlash* = iUPmxCODE(K_slash)
+ K_mSemicolon* = iUPmxCODE(K_semicolon)
K_mEqual* = iUPmxCODE(K_equal)
K_mBracketleft* = iUPmxCODE(K_bracketleft)
K_mBracketright* = iUPmxCODE(K_bracketright)
@@ -863,16 +863,16 @@ const
K_y4* = iUPyxCODE(K_4)
K_y5* = iUPyxCODE(K_5)
K_y6* = iUPyxCODE(K_6)
- K_y7* = iUPyxCODE(K_7)
- K_y8* = iUPyxCODE(K_8)
+ K_y7* = iUPyxCODE(K_7)
+ K_y8* = iUPyxCODE(K_8)
K_y9* = iUPyxCODE(K_9)
K_y0* = iUPyxCODE(K_0)
K_yPlus* = iUPyxCODE(K_plus)
K_yComma* = iUPyxCODE(K_comma)
- K_yMinus* = iUPyxCODE(K_minus)
- K_yPeriod* = iUPyxCODE(K_period)
- K_ySlash* = iUPyxCODE(K_slash)
- K_ySemicolon* = iUPyxCODE(K_semicolon)
+ K_yMinus* = iUPyxCODE(K_minus)
+ K_yPeriod* = iUPyxCODE(K_period)
+ K_ySlash* = iUPyxCODE(K_slash)
+ K_ySemicolon* = iUPyxCODE(K_semicolon)
K_yEqual* = iUPyxCODE(K_equal)
K_yBracketleft* = iUPyxCODE(K_bracketleft)
K_yBracketright* = iUPyxCODE(K_bracketright)
@@ -893,11 +893,11 @@ proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dlln
proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.}
# IupMatrix utilities
-proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
value: cstring) {.
cdecl, importc: "IupMatSetAttribute", dynlib: dllname.}
-proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
- value: cstring) {.cdecl,
+proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+ value: cstring) {.cdecl,
importc: "IupMatStoreAttribute", dynlib: dllname.}
proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {.
cdecl, importc: "IupMatGetAttribute", dynlib: dllname.}
@@ -905,9 +905,9 @@ proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {.
cdecl, importc: "IupMatGetInt", dynlib: dllname.}
proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {.
cdecl, importc: "IupMatGetFloat", dynlib: dllname.}
-proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
- format: cstring) {.cdecl,
- importc: "IupMatSetfAttribute",
+proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+ format: cstring) {.cdecl,
+ importc: "IupMatSetfAttribute",
dynlib: dllname, varargs.}
# Used by IupColorbar
@@ -931,10 +931,10 @@ proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {.
proc pPlotEnd*(ih: PIhandle): cint {.
cdecl, importc: "IupPPlotEnd", dynlib: dllname.}
-proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
- y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
+proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
+ y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
dynlib: dllname.}
-proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
+proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
x, y: cfloat) {.
cdecl, importc: "IupPPlotInsert", dynlib: dllname.}
diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim
index afa8f447ab..67436f0265 100644
--- a/lib/wrappers/pcre.nim
+++ b/lib/wrappers/pcre.nim
@@ -1,158 +1,190 @@
#************************************************
-# Perl-Compatible Regular Expressions *
-#***********************************************
+# Perl-Compatible Regular Expressions *
+#************************************************
# This is the public header file for the PCRE library, to be #included by
-#applications that call the PCRE functions.
+# applications that call the PCRE functions.
#
-# Copyright (c) 1997-2010 University of Cambridge
+# Copyright (c) 1997-2014 University of Cambridge
#
#-----------------------------------------------------------------------------
-#Redistribution and use in source and binary forms, with or without
-#modification, are permitted provided that the following conditions are met:
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
#
-# Redistributions of source code must retain the above copyright notice,
+# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
-# Redistributions in binary form must reproduce the above copyright
+# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
-# Neither the name of the University of Cambridge nor the names of its
+# * Neither the name of the University of Cambridge nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-#POSSIBILITY OF SUCH DAMAGE.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
#-----------------------------------------------------------------------------
-#
-{.deadcodeElim: on.}
+{.deadCodeElim: on.}
-when not defined(pcreDll):
- when hostOS == "windows":
- const pcreDll = "pcre.dll"
- elif hostOS == "macosx":
- const pcreDll = "libpcre(.3|.1|).dylib"
- else:
- const pcreDll = "libpcre.so(.3|.1|)"
- {.pragma: pcreImport, dynlib: pcreDll.}
-else:
- {.pragma: pcreImport, header: "".}
+# The current PCRE version information.
-# The current PCRE version information.
-
-const
- MAJOR* = 8
- MINOR* = 31
- PRERELEASE* = true
- DATE* = "2012-07-06"
+const
+ PCRE_MAJOR* = 8
+ PCRE_MINOR* = 36
+ PCRE_PRERELEASE* = true
+ PCRE_DATE* = "2014-09-26"
# When an application links to a PCRE DLL in Windows, the symbols that are
# imported have to be identified as such. When building PCRE, the appropriate
# export setting is defined in pcre_internal.h, which includes this file. So we
-# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
+# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
-# Have to include stdlib.h in order to ensure that size_t is defined;
-# it is needed here for malloc.
+# By default, we use the standard "extern" declarations.
-# Allow for C++ users
+# Allow for C++ users
-# Options. Some are compile-time only, some are run-time only, and some are
-# both, so we keep them all distinct.
-
-const
- CASELESS* = 0x00000001
- MULTILINE* = 0x00000002
- DOTALL* = 0x00000004
- EXTENDED* = 0x00000008
- ANCHORED* = 0x00000010
- DOLLAR_ENDONLY* = 0x00000020
- EXTRA* = 0x00000040
- NOTBOL* = 0x00000080
- NOTEOL* = 0x00000100
- UNGREEDY* = 0x00000200
- NOTEMPTY* = 0x00000400
- UTF8* = 0x00000800
- NO_AUTO_CAPTURE* = 0x00001000
- NO_UTF8_CHECK* = 0x00002000
- AUTO_CALLOUT* = 0x00004000
- PARTIAL_SOFT* = 0x00008000
- PARTIAL* = 0x00008000 # Backwards compatible synonym
- DFA_SHORTEST* = 0x00010000
- DFA_RESTART* = 0x00020000
- FIRSTLINE* = 0x00040000
- DUPNAMES* = 0x00080000
- NEWLINE_CR* = 0x00100000
- NEWLINE_LF* = 0x00200000
- NEWLINE_CRLF* = 0x00300000
- NEWLINE_ANY* = 0x00400000
- NEWLINE_ANYCRLF* = 0x00500000
- BSR_ANYCRLF* = 0x00800000
- BSR_UNICODE* = 0x01000000
- JAVASCRIPT_COMPAT* = 0x02000000
- NO_START_OPTIMIZE* = 0x04000000
- NO_START_OPTIMISE* = 0x04000000
- PARTIAL_HARD* = 0x08000000
- NOTEMPTY_ATSTART* = 0x10000000
- UCP* = 0x20000000
-
-# Exec-time and get/set-time error codes
-
-const
- ERROR_NOMATCH* = (- 1)
- ERROR_NULL* = (- 2)
- ERROR_BADOPTION* = (- 3)
- ERROR_BADMAGIC* = (- 4)
- ERROR_UNKNOWN_OPCODE* = (- 5)
- ERROR_UNKNOWN_NODE* = (- 5) # For backward compatibility
- ERROR_NOMEMORY* = (- 6)
- ERROR_NOSUBSTRING* = (- 7)
- ERROR_MATCHLIMIT* = (- 8)
- ERROR_CALLOUT* = (- 9) # Never used by PCRE itself
- ERROR_BADUTF8* = (- 10)
- ERROR_BADUTF8_OFFSET* = (- 11)
- ERROR_PARTIAL* = (- 12)
- ERROR_BADPARTIAL* = (- 13)
- ERROR_INTERNAL* = (- 14)
- ERROR_BADCOUNT* = (- 15)
- ERROR_DFA_UITEM* = (- 16)
- ERROR_DFA_UCOND* = (- 17)
- ERROR_DFA_UMLIMIT* = (- 18)
- ERROR_DFA_WSSIZE* = (- 19)
- ERROR_DFA_RECURSE* = (- 20)
- ERROR_RECURSIONLIMIT* = (- 21)
- ERROR_NULLWSLIMIT* = (- 22) # No longer actually used
- ERROR_BADNEWLINE* = (- 23)
- ERROR_BADOFFSET* = (- 24)
- ERROR_SHORTUTF8* = (- 25)
- ERROR_RECURSELOOP* = (- 26)
- ERROR_JIT_STACKLIMIT* = (- 27)
- ERROR_BADMODE* = (- 28)
- ERROR_BADENDIANNESS* = (- 29)
- ERROR_DFA_BADRESTART* = (- 30)
-
-# Specific error codes for UTF-8 validity checks
+# Public options. Some are compile-time only, some are run-time only, and some
+# are both. Most of the compile-time options are saved with the compiled regex
+# so that they can be inspected during studying (and therefore JIT compiling).
+# Note that pcre_study() has its own set of options. Originally, all the options
+# defined here used distinct bits. However, almost all the bits in a 32-bit word
+# are now used, so in order to conserve them, option bits that were previously
+# only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
+# also be used for compile-time options that affect only compiling and are not
+# relevant for studying or JIT compiling.
+#
+# Some options for pcre_compile() change its behaviour but do not affect the
+# behaviour of the execution functions. Other options are passed through to the
+# execution functions and affect their behaviour, with or without affecting the
+# behaviour of pcre_compile().
+#
+# Options that can be passed to pcre_compile() are tagged Cx below, with these
+# variants:
+#
+# C1 Affects compile only
+# C2 Does not affect compile; affects exec, dfa_exec
+# C3 Affects compile, exec, dfa_exec
+# C4 Affects compile, exec, dfa_exec, study
+# C5 Affects compile, exec, study
+#
+# Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged
+# with E and D, respectively. They take precedence over C3, C4, and C5 settings
+# passed from pcre_compile(). Those that are compatible with JIT execution are
+# flagged with J.
const
- UTF8_ERR0* = 0
- UTF8_ERR1* = 1
- UTF8_ERR2* = 2
- UTF8_ERR3* = 3
- UTF8_ERR4* = 4
- UTF8_ERR5* = 5
- UTF8_ERR6* = 6
- UTF8_ERR7* = 7
- UTF8_ERR8* = 8
- UTF8_ERR9* = 9
+ CASELESS* = 0x00000001 # C1
+ MULTILINE* = 0x00000002 # C1
+ DOTALL* = 0x00000004 # C1
+ EXTENDED* = 0x00000008 # C1
+ ANCHORED* = 0x00000010 # C4 E D
+ DOLLAR_ENDONLY* = 0x00000020 # C2
+ EXTRA* = 0x00000040 # C1
+ NOTBOL* = 0x00000080 # E D J
+ NOTEOL* = 0x00000100 # E D J
+ UNGREEDY* = 0x00000200 # C1
+ NOTEMPTY* = 0x00000400 # E D J
+ UTF8* = 0x00000800 # C4 )
+ UTF16* = 0x00000800 # C4 ) Synonyms
+ UTF32* = 0x00000800 # C4 )
+ NO_AUTO_CAPTURE* = 0x00001000 # C1
+ NO_UTF8_CHECK* = 0x00002000 # C1 E D J )
+ NO_UTF16_CHECK* = 0x00002000 # C1 E D J ) Synonyms
+ NO_UTF32_CHECK* = 0x00002000 # C1 E D J )
+ AUTO_CALLOUT* = 0x00004000 # C1
+ PARTIAL_SOFT* = 0x00008000 # E D J ) Synonyms
+ PARTIAL* = 0x00008000 # E D J )
+
+# This pair use the same bit.
+const
+ NEVER_UTF* = 0x00010000 # C1 ) Overlaid
+ DFA_SHORTEST* = 0x00010000 # D ) Overlaid
+
+# This pair use the same bit.
+const
+ NO_AUTO_POSSESS* = 0x00020000 # C1 ) Overlaid
+ DFA_RESTART* = 0x00020000 # D ) Overlaid
+
+const
+ FIRSTLINE* = 0x00040000 # C3
+ DUPNAMES* = 0x00080000 # C1
+ NEWLINE_CR* = 0x00100000 # C3 E D
+ NEWLINE_LF* = 0x00200000 # C3 E D
+ NEWLINE_CRLF* = 0x00300000 # C3 E D
+ NEWLINE_ANY* = 0x00400000 # C3 E D
+ NEWLINE_ANYCRLF* = 0x00500000 # C3 E D
+ BSR_ANYCRLF* = 0x00800000 # C3 E D
+ BSR_UNICODE* = 0x01000000 # C3 E D
+ JAVASCRIPT_COMPAT* = 0x02000000 # C5
+ NO_START_OPTIMIZE* = 0x04000000 # C2 E D ) Synonyms
+ NO_START_OPTIMISE* = 0x04000000 # C2 E D )
+ PARTIAL_HARD* = 0x08000000 # E D J
+ NOTEMPTY_ATSTART* = 0x10000000 # E D J
+ UCP* = 0x20000000 # C3
+
+## Exec-time and get/set-time error codes
+const
+ ERROR_NOMATCH* = -1
+ ERROR_NULL* = -2
+ ERROR_BADOPTION* = -3
+ ERROR_BADMAGIC* = -4
+ ERROR_UNKNOWN_OPCODE* = -5
+ ERROR_UNKNOWN_NODE* = -5 ## For backward compatibility
+ ERROR_NOMEMORY* = -6
+ ERROR_NOSUBSTRING* = -7
+ ERROR_MATCHLIMIT* = -8
+ ERROR_CALLOUT* = -9 ## Never used by PCRE itself
+ ERROR_BADUTF8* = -10 ## Same for 8/16/32
+ ERROR_BADUTF16* = -10 ## Same for 8/16/32
+ ERROR_BADUTF32* = -10 ## Same for 8/16/32
+ ERROR_BADUTF8_OFFSET* = -11 ## Same for 8/16
+ ERROR_BADUTF16_OFFSET* = -11 ## Same for 8/16
+ ERROR_PARTIAL* = -12
+ ERROR_BADPARTIAL* = -13
+ ERROR_INTERNAL* = -14
+ ERROR_BADCOUNT* = -15
+ ERROR_DFA_UITEM* = -16
+ ERROR_DFA_UCOND* = -17
+ ERROR_DFA_UMLIMIT* = -18
+ ERROR_DFA_WSSIZE* = -19
+ ERROR_DFA_RECURSE* = -20
+ ERROR_RECURSIONLIMIT* = -21
+ ERROR_NULLWSLIMIT* = -22 ## No longer actually used
+ ERROR_BADNEWLINE* = -23
+ ERROR_BADOFFSET* = -24
+ ERROR_SHORTUTF8* = -25
+ ERROR_SHORTUTF16* = -25 ## Same for 8/16
+ ERROR_RECURSELOOP* = -26
+ ERROR_JIT_STACKLIMIT* = -27
+ ERROR_BADMODE* = -28
+ ERROR_BADENDIANNESS* = -29
+ ERROR_DFA_BADRESTART* = -30
+ ERROR_JIT_BADOPTION* = -31
+ ERROR_BADLENGTH* = -32
+ ERROR_UNSET* = -33
+
+## Specific error codes for UTF-8 validity checks
+const
+ UTF8_ERR0* = 0
+ UTF8_ERR1* = 1
+ UTF8_ERR2* = 2
+ UTF8_ERR3* = 3
+ UTF8_ERR4* = 4
+ UTF8_ERR5* = 5
+ UTF8_ERR6* = 6
+ UTF8_ERR7* = 7
+ UTF8_ERR8* = 8
+ UTF8_ERR9* = 9
UTF8_ERR10* = 10
UTF8_ERR11* = 11
UTF8_ERR12* = 12
@@ -165,193 +197,305 @@ const
UTF8_ERR19* = 19
UTF8_ERR20* = 20
UTF8_ERR21* = 21
+ UTF8_ERR22* = 22 # Unused (was non-character)
-# Request types for pcre_fullinfo()
-
-const
- INFO_OPTIONS* = 0
- INFO_SIZE* = 1
- INFO_CAPTURECOUNT* = 2
- INFO_BACKREFMAX* = 3
- INFO_FIRSTBYTE* = 4
- INFO_FIRSTCHAR* = 4 # For backwards compatibility
- INFO_FIRSTTABLE* = 5
- INFO_LASTLITERAL* = 6
- INFO_NAMEENTRYSIZE* = 7
- INFO_NAMECOUNT* = 8
- INFO_NAMETABLE* = 9
- INFO_STUDYSIZE* = 10
- INFO_DEFAULT_TABLES* = 11
- INFO_OKPARTIAL* = 12
- INFO_JCHANGED* = 13
- INFO_HASCRORLF* = 14
- INFO_MINLENGTH* = 15
- INFO_JIT* = 16
- INFO_JITSIZE* = 17
- INFO_MAXLOOKBEHIND* = 18
-
-# Request types for pcre_config(). Do not re-arrange, in order to remain
-# compatible.
-
-const
- CONFIG_UTF8* = 0
- CONFIG_NEWLINE* = 1
- CONFIG_LINK_SIZE* = 2
- CONFIG_POSIX_MALLOC_THRESHOLD* = 3
- CONFIG_MATCH_LIMIT* = 4
- CONFIG_STACKRECURSE* = 5
- CONFIG_UNICODE_PROPERTIES* = 6
- CONFIG_MATCH_LIMIT_RECURSION* = 7
- CONFIG_BSR* = 8
- CONFIG_JIT* = 9
- CONFIG_JITTARGET* = 11
-
-# Request types for pcre_study(). Do not re-arrange, in order to remain
-# compatible.
-
+## Specific error codes for UTF-16 validity checks
const
- STUDY_JIT_COMPILE* = 0x00000001
- STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x00000002
- STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x00000004
+ UTF16_ERR0* = 0
+ UTF16_ERR1* = 1
+ UTF16_ERR2* = 2
+ UTF16_ERR3* = 3
+ UTF16_ERR4* = 4 # Unused (was non-character)
-# Bit flags for the pcre_extra structure. Do not re-arrange or redefine
-# these bits, just add new ones on the end, in order to remain compatible.
+## Specific error codes for UTF-32 validity checks
+const
+ UTF32_ERR0* = 0
+ UTF32_ERR1* = 1
+ UTF32_ERR2* = 2 # Unused (was non-character)
+ UTF32_ERR3* = 3
-const
- EXTRA_STUDY_DATA* = 0x00000001
- EXTRA_MATCH_LIMIT* = 0x00000002
- EXTRA_CALLOUT_DATA* = 0x00000004
- EXTRA_TABLES* = 0x00000008
- EXTRA_MATCH_LIMIT_RECURSION* = 0x00000010
- EXTRA_MARK* = 0x00000020
- EXTRA_EXECUTABLE_JIT* = 0x00000040
+## Request types for pcre_fullinfo()
+const
+ INFO_OPTIONS* = 0
+ INFO_SIZE* = 1
+ INFO_CAPTURECOUNT* = 2
+ INFO_BACKREFMAX* = 3
+ INFO_FIRSTBYTE* = 4
+ INFO_FIRSTCHAR* = 4 ## For backwards compatibility
+ INFO_FIRSTTABLE* = 5
+ INFO_LASTLITERAL* = 6
+ INFO_NAMEENTRYSIZE* = 7
+ INFO_NAMECOUNT* = 8
+ INFO_NAMETABLE* = 9
+ INFO_STUDYSIZE* = 10
+ INFO_DEFAULT_TABLES* = 11
+ INFO_OKPARTIAL* = 12
+ INFO_JCHANGED* = 13
+ INFO_HASCRORLF* = 14
+ INFO_MINLENGTH* = 15
+ INFO_JIT* = 16
+ INFO_JITSIZE* = 17
+ INFO_MAXLOOKBEHIND* = 18
+ INFO_FIRSTCHARACTER* = 19
+ INFO_FIRSTCHARACTERFLAGS* = 20
+ INFO_REQUIREDCHAR* = 21
+ INFO_REQUIREDCHARFLAGS* = 22
+ INFO_MATCHLIMIT* = 23
+ INFO_RECURSIONLIMIT* = 24
+ INFO_MATCH_EMPTY* = 25
-# Types
+## Request types for pcre_config(). Do not re-arrange, in order to remain
+## compatible.
+const
+ CONFIG_UTF8* = 0
+ CONFIG_NEWLINE* = 1
+ CONFIG_LINK_SIZE* = 2
+ CONFIG_POSIX_MALLOC_THRESHOLD* = 3
+ CONFIG_MATCH_LIMIT* = 4
+ CONFIG_STACKRECURSE* = 5
+ CONFIG_UNICODE_PROPERTIES* = 6
+ CONFIG_MATCH_LIMIT_RECURSION* = 7
+ CONFIG_BSR* = 8
+ CONFIG_JIT* = 9
+ CONFIG_UTF16* = 10
+ CONFIG_JITTARGET* = 11
+ CONFIG_UTF32* = 12
+ CONFIG_PARENS_LIMIT* = 13
-type
- TPcre*{.pure, final.} = object
- PPcre* = ptr TPcre
- Tjit_stack*{.pure, final.} = object
- Pjit_stack* = ptr Tjit_stack
+## Request types for pcre_study(). Do not re-arrange, in order to remain
+## compatible.
+const
+ STUDY_JIT_COMPILE* = 0x0001
+ STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x0002
+ STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x0004
+ STUDY_EXTRA_NEEDED* = 0x0008
-# When PCRE is compiled as a C++ library, the subject pointer type can be
-# replaced with a custom type. For conventional use, the public interface is a
-# const char *.
-
-# The structure for passing additional data to pcre_exec(). This is defined in
-# such as way as to be extensible. Always add new fields at the end, in order to
-# remain compatible.
-
-type
- TExtra*{.pure, final.} = object
- flags*: int ## Bits for which fields are set
- study_data*: pointer ## Opaque data from pcre_study()
- match_limit*: int ## Maximum number of calls to match()
- callout_data*: pointer ## Data passed back in callouts
- tables*: cstring ## Pointer to character tables
- match_limit_recursion*: int ## Max recursive calls to match()
- mark*: ptr cstring ## For passing back a mark pointer
- executable_jit*: pointer ## Contains a pointer to a compiled jit code
-
-
-# The structure for passing out data via the pcre_callout_function. We use a
-# structure so that new fields can be added on the end in future versions,
-# without changing the API of the function, thereby allowing old clients to work
-# without modification.
-
-type
- TCalloutBlock*{.pure, final.} = object
- version*: cint ## Identifies version of block
- callout_number*: cint ## Number compiled into pattern
- offset_vector*: ptr cint ## The offset vector
- subject*: cstring ## The subject being matched
- subject_length*: cint ## The length of the subject
- start_match*: cint ## Offset to start of this match attempt
- current_position*: cint ## Where we currently are in the subject
- capture_top*: cint ## Max current capture
- capture_last*: cint ## Most recently closed capture
- callout_data*: pointer ## Data passed in with the call
- pattern_position*: cint ## Offset to next item in the pattern
- next_item_length*: cint ## Length of next item in the pattern
- mark*: cstring ## Pointer to current mark or NULL
-
-# Indirection for store get and free functions. These can be set to
-#alternative malloc/free functions if required. Special ones are used in the
-#non-recursive case for "frames". There is also an optional callout function
-#that is triggered by the (?) regex item. For Virtual Pascal, these definitions
-#have to take another form.
-
-# User defined callback which provides a stack just before the match starts.
+## Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
+## these bits, just add new ones on the end, in order to remain compatible.
+const
+ EXTRA_STUDY_DATA* = 0x0001
+ EXTRA_MATCH_LIMIT* = 0x0002
+ EXTRA_CALLOUT_DATA* = 0x0004
+ EXTRA_TABLES* = 0x0008
+ EXTRA_MATCH_LIMIT_RECURSION* = 0x0010
+ EXTRA_MARK* = 0x0020
+ EXTRA_EXECUTABLE_JIT* = 0x0040
+## Types
type
- TJitCallback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
+ Pcre* = object
+ Pcre16* = object
+ Pcre32* = object
+ JitStack* = object
+ JitStack16* = object
+ JitStack32* = object
-# Exported PCRE functions
-proc compile*(a2: cstring, a3: cint, a4: ptr cstring, a5: ptr cint,
- a6: ptr char): ptr TPcre{.cdecl, importc: "pcre_compile",
- pcreImport.}
-proc compile2*(a2: cstring, a3: cint, a4: ptr cint, a5: ptr cstring,
- a6: ptr cint, a7: ptr char): ptr TPcre{.cdecl,
- importc: "pcre_compile2", pcreImport.}
-proc config*(a2: cint, a3: pointer): cint{.cdecl, importc: "pcre_config",
- pcreImport.}
-proc copy_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint,
- a6: cstring, a7: cstring, a8: cint): cint{.cdecl,
- importc: "pcre_copy_named_substring", pcreImport.}
-proc copy_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint,
- a6: cstring,
- a7: cint): cint{.cdecl, importc: "pcre_copy_substring",
- pcreImport.}
-proc dfa_exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint,
- a6: cint, a7: cint, a8: ptr cint, a9: cint, a10: ptr cint,
- a11: cint): cint{.cdecl, importc: "pcre_dfa_exec",
- pcreImport.}
-proc exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, a6: cint,
- a7: cint, a8: ptr cint, a9: cint): cint {.
- cdecl, importc: "pcre_exec", pcreImport.}
-proc free_substring*(a2: cstring){.cdecl, importc: "pcre_free_substring",
- pcreImport.}
-proc free_substring_list*(a2: cstringArray){.cdecl,
- importc: "pcre_free_substring_list", pcreImport.}
-proc fullinfo*(a2: ptr TPcre, a3: ptr TExtra, a4: cint, a5: pointer): cint{.
- cdecl, importc: "pcre_fullinfo", pcreImport.}
-proc get_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint,
- a6: cstring, a7: cstringArray): cint{.cdecl,
- importc: "pcre_get_named_substring", pcreImport.}
-proc get_stringnumber*(a2: ptr TPcre, a3: cstring): cint{.cdecl,
- importc: "pcre_get_stringnumber", pcreImport.}
-proc get_stringtable_entries*(a2: ptr TPcre, a3: cstring, a4: cstringArray,
- a5: cstringArray): cint{.cdecl,
- importc: "pcre_get_stringtable_entries", pcreImport.}
-proc get_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint,
- a6: cstringArray): cint{.cdecl,
- importc: "pcre_get_substring", pcreImport.}
-proc get_substring_list*(a2: cstring, a3: ptr cint, a4: cint,
- a5: ptr cstringArray): cint{.cdecl,
- importc: "pcre_get_substring_list", pcreImport.}
-proc maketables*(): ptr char{.cdecl, importc: "pcre_maketables",
- pcreImport.}
-proc refcount*(a2: ptr TPcre, a3: cint): cint{.cdecl, importc: "pcre_refcount",
- pcreImport.}
-proc study*(a2: ptr TPcre, a3: cint, a4: var cstring): ptr TExtra{.cdecl,
- importc: "pcre_study", pcreImport.}
-proc version*(): cstring{.cdecl, importc: "pcre_version", pcreImport.}
+## The structure for passing additional data to pcre_exec(). This is defined in
+## such as way as to be extensible. Always add new fields at the end, in order
+## to remain compatible.
+type
+ ExtraData* = object
+ flags*: clong ## Bits for which fields are set
+ study_data*: pointer ## Opaque data from pcre_study()
+ match_limit*: clong ## Maximum number of calls to match()
+ callout_data*: pointer ## Data passed back in callouts
+ tables*: pointer ## Pointer to character tables
+ match_limit_recursion*: clong ## Max recursive calls to match()
+ mark*: pointer ## For passing back a mark pointer
+ executable_jit*: pointer ## Contains a pointer to a compiled jit code
+
+## The structure for passing out data via the pcre_callout_function. We use a
+## structure so that new fields can be added on the end in future versions,
+## without changing the API of the function, thereby allowing old clients to
+## work without modification.
+type
+ CalloutBlock* = object
+ version* : cint ## Identifies version of block
+ # ------------------------ Version 0 -------------------------------
+ callout_number* : cint ## Number compiled into pattern
+ offset_vector* : ptr cint ## The offset vector
+ subject* : cstring ## The subject being matched
+ subject_length* : cint ## The length of the subject
+ start_match* : cint ## Offset to start of this match attempt
+ current_position*: cint ## Where we currently are in the subject
+ capture_top* : cint ## Max current capture
+ capture_last* : cint ## Most recently closed capture
+ callout_data* : pointer ## Data passed in with the call
+ # ------------------- Added for Version 1 --------------------------
+ pattern_position*: cint ## Offset to next item in the pattern
+ next_item_length*: cint ## Length of next item in the pattern
+ # ------------------- Added for Version 2 --------------------------
+ mark* : pointer ## Pointer to current mark or NULL
+ # ------------------------------------------------------------------
+
+
+## User defined callback which provides a stack just before the match starts.
+type
+ JitCallback* = proc (a: pointer): ptr JitStack {.cdecl.}
+
+
+when not defined(usePcreHeader):
+ when hostOS == "windows":
+ const pcreDll = "pcre.dll"
+ elif hostOS == "macosx":
+ const pcreDll = "libpcre(.3|.1|).dylib"
+ else:
+ const pcreDll = "libpcre.so(.3|.1|)"
+ {.push dynlib: pcreDll.}
+else:
+ {.push header: "".}
+
+{.push cdecl, importc: "pcre_$1".}
+
+# Exported PCRE functions
+
+proc compile*(pattern: cstring,
+ options: cint,
+ errptr: ptr cstring,
+ erroffset: ptr cint,
+ tableptr: pointer): ptr Pcre
+
+proc compile2*(pattern: cstring,
+ options: cint,
+ errorcodeptr: ptr cint,
+ errptr: ptr cstring,
+ erroffset: ptr cint,
+ tableptr: pointer): ptr Pcre
+
+proc config*(what: cint,
+ where: pointer): cint
+
+proc copy_named_substring*(code: ptr Pcre,
+ subject: cstring,
+ ovector: ptr cint,
+ stringcount: cint,
+ stringname: cstring,
+ buffer: cstring,
+ buffersize: cint): cint
+
+proc copy_substring*(subject: cstring,
+ ovector: ptr cint,
+ stringcount: cint,
+ stringnumber: cint,
+ buffer: cstring,
+ buffersize: cint): cint
+
+proc dfa_exec*(code: ptr Pcre,
+ extra: ptr ExtraData,
+ subject: cstring,
+ length: cint,
+ startoffset: cint,
+ options: cint,
+ ovector: ptr cint,
+ ovecsize: cint,
+ workspace: ptr cint,
+ wscount: cint): cint
+
+proc exec*(code: ptr Pcre,
+ extra: ptr ExtraData,
+ subject: cstring,
+ length: cint,
+ startoffset: cint,
+ options: cint,
+ ovector: ptr cint,
+ ovecsize: cint): cint
+
+proc jit_exec*(code: ptr Pcre,
+ extra: ptr ExtraData,
+ subject: cstring,
+ length: cint,
+ startoffset: cint,
+ options: cint,
+ ovector: ptr cint,
+ ovecsize: cint,
+ jstack: ptr JitStack): cint
+
+proc free_substring*(stringptr: cstring)
+
+proc free_substring_list*(stringptr: cstringArray)
+
+proc fullinfo*(code: ptr Pcre,
+ extra: ptr ExtraData,
+ what: cint,
+ where: pointer): cint
+
+proc get_named_substring*(code: ptr Pcre,
+ subject: cstring,
+ ovector: ptr cint,
+ stringcount: cint,
+ stringname: cstring,
+ stringptr: cstringArray): cint
+
+proc get_stringnumber*(code: ptr Pcre,
+ name: cstring): cint
+
+proc get_stringtable_entries*(code: ptr Pcre,
+ name: cstring,
+ first: cstringArray,
+ last: cstringArray): cint
+
+proc get_substring*(subject: cstring,
+ ovector: ptr cint,
+ stringcount: cint,
+ stringnumber: cint,
+ stringptr: cstringArray): cint
+
+proc get_substring_list*(subject: cstring,
+ ovector: ptr cint,
+ stringcount: cint,
+ listptr: ptr cstringArray): cint
+
+proc maketables*(): pointer
+
+proc refcount*(code: ptr Pcre,
+ adjust: cint): cint
+
+proc study*(code: ptr Pcre,
+ options: cint,
+ errptr: ptr cstring): ptr ExtraData
+
+proc free_study*(extra: ptr ExtraData)
+
+proc version*(): cstring
# Utility functions for byte order swaps.
-proc pattern_to_host_byte_order*(a2: ptr TPcre, a3: ptr TExtra,
- a4: ptr char): cint{.cdecl, importc: "pcre_pattern_to_host_byte_order",
- pcreImport.}
+proc pattern_to_host_byte_order*(code: ptr Pcre,
+ extra: ptr ExtraData,
+ tables: pointer): cint
# JIT compiler related functions.
-proc jit_stack_alloc*(a2: cint, a3: cint): ptr Tjit_stack{.cdecl,
- importc: "pcre_jit_stack_alloc", pcreImport.}
-proc jit_stack_free*(a2: ptr Tjit_stack){.cdecl, importc: "pcre_jit_stack_free",
- pcreImport.}
-proc assign_jit_stack*(a2: ptr TExtra, a3: TJitCallback, a4: pointer){.cdecl,
- importc: "pcre_assign_jit_stack", pcreImport.}
+proc jit_stack_alloc*(startsize: cint,
+ maxsize: cint): ptr JitStack
-var
- pcre_free*: proc (p: ptr TPcre) {.cdecl.}
+proc jit_stack_free*(stack: ptr JitStack)
+
+proc assign_jit_stack*(extra: ptr ExtraData,
+ callback: JitCallback,
+ data: pointer)
+
+proc jit_free_unused_memory*()
+
+
+# There was an odd function with `var cstring` instead of `ptr`
+proc study*(code: ptr Pcre,
+ options: cint,
+ errptr: var cstring): ptr ExtraData {.deprecated.}
+
+{.pop.}
+{.pop.}
+
+
+{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
+ PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
+
+{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
+type
+ PPcre* {.deprecated.} = ptr Pcre
+ PJitStack* {.deprecated.} = ptr JitStack
+
+{.deprecated: [TExtra: ExtraData].}
+{.deprecated: [TCalloutBlock: CalloutBlock].}
+{.deprecated: [TJitCallback: JitCallback].}
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
index 729cdcac7f..1e67644712 100644
--- a/tests/assert/tfailedassert.nim
+++ b/tests/assert/tfailedassert.nim
@@ -30,7 +30,7 @@ proc bar: int =
# local overrides that are active only
# in this proc
onFailedAssert(msg): echo "WARNING: " & msg
-
+
assert(false, "first assertion from bar")
onFailedAssert(msg):
diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim
new file mode 100644
index 0000000000..6620adbeb9
--- /dev/null
+++ b/tests/assign/moverload_asgn2.nim
@@ -0,0 +1,10 @@
+type
+ Concrete* = object
+ a*, b*: string
+ rc*: int # refcount
+
+proc `=`(d: var Concrete; src: Concrete) =
+ shallowCopy(d.a, src.a)
+ shallowCopy(d.b, src.b)
+ dec d.rc
+ d.rc = src.rc + 1
diff --git a/tests/assign/toverload_asgn1.nim b/tests/assign/toverload_asgn1.nim
new file mode 100644
index 0000000000..dbc3a71c4e
--- /dev/null
+++ b/tests/assign/toverload_asgn1.nim
@@ -0,0 +1,75 @@
+discard """
+ output: '''Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+GenericT[T] '=' int
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' string
+GenericT[T] '=' int8
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool'''
+"""
+
+import typetraits
+
+type
+ Concrete = object
+ a, b: string
+
+proc `=`(d: var Concrete; src: Concrete) =
+ shallowCopy(d.a, src.a)
+ shallowCopy(d.b, src.b)
+ echo "Concrete '='"
+
+var x, y: array[0..2, Concrete]
+var cA, cB: Concrete
+
+var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+x = y
+cA = cB
+cATup = cBTup
+
+type
+ GenericT[T] = object
+ a, b: T
+
+proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
+ shallowCopy(d.a, src.a)
+ shallowCopy(d.b, src.b)
+ echo "GenericT[T] '=' ", type(T).name
+
+var ag: GenericT[int]
+var bg: GenericT[int]
+
+ag = bg
+
+var xg, yg: array[0..2, GenericT[float]]
+var cAg, cBg: GenericT[string]
+
+var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
+
+xg = yg
+cAg = cBg
+cATupg = cBTupg
+
+var caSeqg, cbSeqg: seq[GenericT[bool]]
+newSeq(cbSeqg, 4)
+caSeqg = cbSeqg
+
+when false:
+ type
+ Foo = object
+ case b: bool
+ of false: xx: GenericT[int]
+ of true: yy: bool
+
+ var
+ a, b: Foo
+ a = b
diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim
new file mode 100644
index 0000000000..243c904947
--- /dev/null
+++ b/tests/assign/toverload_asgn2.nim
@@ -0,0 +1,22 @@
+discard """
+ output: '''i value 88
+2aa'''
+"""
+
+import moverload_asgn2
+
+proc passAround(i: int): Concrete =
+ echo "i value ", i
+ result = Concrete(a: "aa", b: "bb", rc: 0)
+
+proc main =
+ let
+ i = 88
+ v = passAround(i)
+ z = v.a
+ var
+ x: Concrete
+ x = v
+ echo x.rc, z # 2aa
+
+main()
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 99433b9d89..f77198e2e7 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -82,6 +82,15 @@ proc test3(): Future[int] {.async.} =
result = 2
return
+proc test4(): Future[int] {.async.} =
+ try:
+ discard await foo()
+ raise newException(ValueError, "Test4")
+ except OSError:
+ result = 1
+ except:
+ result = 2
+
var x = test()
assert x.read
@@ -90,3 +99,6 @@ assert x.read
var y = test3()
assert y.read == 2
+
+y = test4()
+assert y.read == 2
diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim
new file mode 100644
index 0000000000..444a058beb
--- /dev/null
+++ b/tests/async/tasynctry2.nim
@@ -0,0 +1,16 @@
+discard """
+ file: "tasynctry2.nim"
+ errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
+ line: 15
+"""
+import asyncdispatch
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test5(): Future[int] {.async.} =
+ try:
+ discard await foo()
+ raise newException(ValueError, "Test5")
+ except:
+ discard await foo()
+ result = 0
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index bf6d92927f..5145fdcff6 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,17 +1,17 @@
discard """
line: 18
- errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)"
+ errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
"""
#bug #442
import scgi, sockets, asyncio, strtabs
proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
discard
-proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
+proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
input: string) =
discard
-proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
+proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
input: string), b: int) =
discard
diff --git a/tests/ccgbugs/tarray_equality.nim b/tests/ccgbugs/tarray_equality.nim
new file mode 100644
index 0000000000..66a9534396
--- /dev/null
+++ b/tests/ccgbugs/tarray_equality.nim
@@ -0,0 +1,15 @@
+discard """
+ output: '''true
+true'''
+"""
+
+# bug #2489
+
+let a = [1]
+let b = [1]
+echo a == b
+
+# bug #2498
+var x: array[0, int]
+var y: array[0, int]
+echo x == y
diff --git a/tests/ccgbugs/tpartialcs.nim b/tests/ccgbugs/tpartialcs.nim
new file mode 100644
index 0000000000..12ff65c376
--- /dev/null
+++ b/tests/ccgbugs/tpartialcs.nim
@@ -0,0 +1,20 @@
+
+# bug #2551
+
+type Tup = tuple
+ A, a: int
+
+type Obj = object
+ A, a: int
+
+var x: Tup # This works.
+var y: Obj # This doesn't.
+
+# bug #2212
+
+proc f() =
+ let
+ p = 1.0
+ P = 0.25 + 0.5
+
+f()
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
index 18968a6c6b..c9136a7368 100644
--- a/tests/closure/tinvalidclosure.nim
+++ b/tests/closure/tinvalidclosure.nim
@@ -1,6 +1,6 @@
discard """
line: 12
- errormsg: "type mismatch: got (proc (int){.closure, gcsafe, locks: 0.})"
+ errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})"
"""
proc ugh[T](x: T) {.closure.} =
diff --git a/tests/collections/tcounttable.nim b/tests/collections/tcounttable.nim
new file mode 100644
index 0000000000..ebbb1c8e51
--- /dev/null
+++ b/tests/collections/tcounttable.nim
@@ -0,0 +1,19 @@
+discard """
+ output: "And we get here"
+"""
+
+# bug #2625
+
+const s_len = 32
+
+import tables
+var substr_counts: CountTable[string] = initCountTable[string]()
+var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings."
+for i in 0..(my_string.len - s_len):
+ let s = my_string[i..i+s_len-1]
+ substr_counts[s] = 1
+ # substr_counts[s] = substr_counts[s] + 1 # Also breaks, + 2 as well, etc.
+ # substr_counts.inc(s) # This works
+ #echo "Iteration ", i
+
+echo "And we get here"
diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim
index 656c5b3f2d..a5bbe8dbd6 100644
--- a/tests/collections/tsets.nim
+++ b/tests/collections/tsets.nim
@@ -1,17 +1,37 @@
-discard """
- output: '''true
-true'''
-"""
-
import sets
-var
- a = initSet[int]()
- b = initSet[int]()
- c = initSet[string]()
-for i in 0..5: a.incl(i)
-for i in 1..6: b.incl(i)
-for i in 0..5: c.incl($i)
+block setEquality:
+ var
+ a = initSet[int]()
+ b = initSet[int]()
+ c = initSet[string]()
+
+ for i in 0..5: a.incl(i)
+ for i in 1..6: b.incl(i)
+ for i in 0..5: c.incl($i)
+
+ doAssert map(a, proc(x: int): int = x + 1) == b
+ doAssert map(a, proc(x: int): string = $x) == c
+
+
+block setsContainingTuples:
+ var set = initSet[tuple[i: int, i64: int64, f: float]]()
+ set.incl( (i: 123, i64: 123'i64, f: 3.14) )
+ doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
+ doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
+
+
+block setWithTuplesWithSeqs:
+ var s = initSet[tuple[s: seq[int]]]()
+ s.incl( (s: @[1, 2, 3]) )
+ doAssert s.contains( (s: @[1, 2, 3]) )
+ doAssert( not s.contains((s: @[4, 5, 6])) )
+
+
+block setWithSequences:
+ var s = initSet[seq[int]]()
+ s.incl( @[1, 2, 3] )
+ doAssert s.contains(@[1, 2, 3])
+ doAssert( not s.contains(@[4, 5, 6]) )
+
-echo map(a, proc(x: int): int = x + 1) == b
-echo map(a, proc(x: int): string = $x) == c
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 3a923610ec..a106068436 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -22,15 +22,15 @@ const
"---00": 346677844,
"0": 34404,
"1": 344004,
- "10": 34484,
+ "10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
- "2": 344774, "20": 34454,
+ "2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
- "5": 341232144, "50": 344490,
+ "5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
- assert($t ==
+ assert($t ==
"{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
@@ -55,14 +55,16 @@ block tableTest2:
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
-
+
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
-
+
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
assert(not hasKey(t, "111"))
-
+ assert "123" in t
+ assert("111" notin t)
+
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat
diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim
index 16b0d831e9..0b641ebc74 100644
--- a/tests/collections/ttablesref.nim
+++ b/tests/collections/ttablesref.nim
@@ -22,15 +22,15 @@ const
"---00": 346677844,
"0": 34404,
"1": 344004,
- "10": 34484,
+ "10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
- "2": 344774, "20": 34454,
+ "2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
- "5": 341232144, "50": 344490,
+ "5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
- assert($t ==
+ assert($t ==
"{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
@@ -55,17 +55,19 @@ block tableTest2:
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
-
+
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
-
+
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
+ assert "123" in t
assert(not hasKey(t, "111"))
-
+ assert "111" notin t
+
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat
-
+
block orderedTableTest1:
var t = newOrderedTable[string, int](2)
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
new file mode 100644
index 0000000000..a9ea8e6ce3
--- /dev/null
+++ b/tests/cpp/tcppraise.nim
@@ -0,0 +1,17 @@
+discard """
+ cmd: "nim cpp $file"
+ output: '''foo
+bar
+Need odd and >= 3 digits##
+baz'''
+"""
+
+# bug #1888
+echo "foo"
+try:
+ echo "bar"
+ raise newException(ValueError, "Need odd and >= 3 digits")
+# echo "baz"
+except ValueError:
+ echo getCurrentExceptionMsg(), "##"
+echo "baz"
diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim
new file mode 100644
index 0000000000..4619147390
--- /dev/null
+++ b/tests/cpp/tget_subsystem.nim
@@ -0,0 +1,23 @@
+discard """
+ cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+namespace System {
+ struct Input {};
+}
+
+struct SystemManager {
+ template
+ static T* getSubsystem() { return new T; }
+};
+
+""".}
+
+type Input {.importcpp: "System::Input".} = object
+proc getSubsystem*[T](): ptr T {.
+ importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+let input: ptr Input = getSubsystem[Input]()
+
diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim
new file mode 100644
index 0000000000..cb5ab33aff
--- /dev/null
+++ b/tests/cpp/tvector_iterator.nim
@@ -0,0 +1,19 @@
+discard """
+ cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+template
+struct Vector {
+ struct Iterator {};
+};
+
+""".}
+
+type
+ Vector {.importcpp: "Vector".} [T] = object
+ VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object
+
+var x: VectorIterator[void]
+
diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim
new file mode 100644
index 0000000000..6eb5dc9e42
--- /dev/null
+++ b/tests/cpp/tvectorseq.nim
@@ -0,0 +1,38 @@
+discard """
+ output: '''(x: 1.0)
+(x: 0.0)'''
+ cmd: "nim cpp $file"
+ disabled: "true"
+"""
+
+# This cannot work yet because we omit type information for importcpp'ed types.
+# Fixing this is not hard, but also requires fixing Urhonimo.
+
+# bug #2536
+
+{.emit: """/*TYPESECTION*/
+struct Vector3 {
+public:
+ Vector3(): x(5) {}
+ Vector3(float x_): x(x_) {}
+ float x;
+};
+""".}
+
+type Vector3 {.importcpp: "Vector3", nodecl} = object
+ x: cfloat
+
+proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+# hack around another codegen issue: Generics are attached to where they came
+# from:
+proc `$!`(v: seq[Vector3]): string = "(x: " & $v[0].x & ")"
+
+proc vec3List*(): seq[Vector3] =
+ let s = @[constructVector3(cfloat(1))]
+ echo($!s)
+ result = s
+ echo($!result)
+
+let f = vec3List()
+#echo($!f)
diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim
index cbaba31548..639dba9411 100644
--- a/tests/destructor/tdestructor.nim
+++ b/tests/destructor/tdestructor.nim
@@ -40,7 +40,7 @@ type
x: A
y: B
z: C
-
+
TObjKind = enum A, B, C, D
TCaseObj = object
@@ -57,14 +57,14 @@ type
q: TMyGeneric3[TMyObj, int, int]
r: string
-proc destroy(o: var TMyObj) {.override.} =
+proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
echo "myobj destroyed"
-proc destroy(o: var TMyGeneric1) {.override.} =
+proc `=destroy`(o: var TMyGeneric1) =
echo "mygeneric1 destroyed"
-proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} =
+proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
echo "mygeneric2 destroyed"
proc open: TMyObj =
@@ -83,12 +83,12 @@ proc mygeneric1() =
proc mygeneric2[T](val: T) =
var a = open()
-
+
var b = TMyGeneric2[int, T](x: 10, y: val)
echo "mygeneric2 constructed"
var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
-
+
proc mygeneric3 =
var x = TMyGeneric3[int, string, TMyGeneric1[int]](
x: 10, y: "test", z: TMyGeneric1[int](x: 10))
@@ -111,11 +111,11 @@ proc caseobj =
block:
echo "----"
var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
-
+
block:
echo "----"
var o2 = TCaseObj(kind: B, y: open())
-
+
block:
echo "----"
var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim
index 6f966d861b..34fa466af1 100644
--- a/tests/destructor/tdestructor2.nim
+++ b/tests/destructor/tdestructor2.nim
@@ -5,14 +5,14 @@ discard """
{.experimental.}
-type
+type
TMyObj = object
x, y: int
p: pointer
-
-proc destroy(o: var TMyObj) {.override.} =
+
+proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
-
+
proc open: TMyObj =
result = TMyObj(x: 1, y: 2, p: alloc(3))
diff --git a/tests/distinct/tdistinct_consts.nim b/tests/distinct/tdistinct_consts.nim
new file mode 100644
index 0000000000..4f6ced2d2f
--- /dev/null
+++ b/tests/distinct/tdistinct_consts.nim
@@ -0,0 +1,20 @@
+
+# bug #2641
+
+type MyChar = distinct char
+const c:MyChar = MyChar('a')
+
+type MyBool = distinct bool
+const b:MyBool = MyBool(true)
+
+type MyBoolSet = distinct set[bool]
+const bs:MyBoolSet = MyBoolSet({true})
+
+type MyCharSet= distinct set[char]
+const cs:MyCharSet = MyCharSet({'a'})
+
+type MyBoolSeq = distinct seq[bool]
+const bseq:MyBoolSeq = MyBoolSeq(@[true, false])
+
+type MyBoolArr = distinct array[3, bool]
+const barr:MyBoolArr = MyBoolArr([true, false, true])
diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
index 0d5109439e..d146794b60 100644
--- a/tests/effects/tgcsafe.nim
+++ b/tests/effects/tgcsafe.nim
@@ -1,5 +1,5 @@
discard """
- line: 16
+ line: 17
errormsg: "'mainUnsafe' is not GC-safe"
cmd: "nim $target --hints:on --threads:on $options $file"
"""
diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim
index 76e986787f..00dd8ed9fc 100644
--- a/tests/exception/texceptionbreak.nim
+++ b/tests/exception/texceptionbreak.nim
@@ -5,20 +5,20 @@ discard """
# First variety
try:
- raise newException(EOS, "Problem")
-except EOS:
+ raise newException(OSError, "Problem")
+except OSError:
for y in [1, 2, 3]:
discard
try:
discard
- except EOS:
+ except OSError:
discard
echo "1"
# Second Variety
try:
- raise newException(EOS, "Problem")
-except EOS:
+ raise newException(OSError, "Problem")
+except OSError:
for y in [1, 2, 3]:
discard
for y in [1, 2, 3]:
@@ -28,8 +28,8 @@ echo "2"
# Third Variety
try:
- raise newException(EOS, "Problem")
-except EOS:
+ raise newException(OSError, "Problem")
+except OSError:
block:
break
@@ -38,8 +38,8 @@ echo "3"
# Fourth Variety
block:
try:
- raise newException(EOS, "Problem")
- except EOS:
+ raise newException(OSError, "Problem")
+ except OSError:
break
-echo "4"
\ No newline at end of file
+echo "4"
diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim
index 69b2d0f6a4..bdf3385997 100644
--- a/tests/exception/texceptions.nim
+++ b/tests/exception/texceptions.nim
@@ -35,9 +35,9 @@ echo ""
proc reraise_in_except =
try:
echo "BEFORE"
- raise newException(EIO, "")
+ raise newException(IOError, "")
- except EIO:
+ except IOError:
echo "EXCEPT"
raise
@@ -52,7 +52,7 @@ echo ""
proc return_in_except =
try:
echo "BEFORE"
- raise newException(EIO, "")
+ raise newException(IOError, "")
except:
echo "EXCEPT"
diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim
index 3dba357f9d..02125d2c03 100644
--- a/tests/exception/texcsub.nim
+++ b/tests/exception/texcsub.nim
@@ -5,12 +5,12 @@ discard """
# Test inheritance for exception matching:
try:
- raise newException(EOS, "dummy message")
-except E_Base:
+ raise newException(OSError, "dummy message")
+except Exception:
echo "caught!"
-except:
+except:
echo "wtf!?"
-
+
#OUT caught!
diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim
index 05c57c4f5c..3aa707ff6e 100644
--- a/tests/exception/tfinally4.nim
+++ b/tests/exception/tfinally4.nim
@@ -8,19 +8,19 @@ discard """
var raiseEx = true
var returnA = true
var returnB = false
-
-proc main: int =
+
+proc main: int =
try: #A
try: #B
if raiseEx:
- raise newException(EOS, "")
+ raise newException(OSError, "")
return 3
finally: #B
echo "B1"
if returnB:
return 2
echo "B2"
- except EOS: #A
+ except OSError: #A
echo "catch"
finally: #A
echo "A1"
diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim
index 591638f0ef..1480764f1b 100644
--- a/tests/exception/tnestedreturn.nim
+++ b/tests/exception/tnestedreturn.nim
@@ -7,7 +7,7 @@ discard """
proc test1() =
- finally: echo "A"
+ defer: echo "A"
try:
raise newException(OSError, "Problem")
@@ -19,7 +19,7 @@ test1()
proc test2() =
- finally: echo "B"
+ defer: echo "B"
try:
return
diff --git a/tests/exception/tonraise.nim b/tests/exception/tonraise.nim
index 1a555dd94e..a155f0b8e3 100644
--- a/tests/exception/tonraise.nim
+++ b/tests/exception/tonraise.nim
@@ -4,8 +4,8 @@ success'''
"""
type
- ESomething = object of E_Base
- ESomeOtherErr = object of E_Base
+ ESomething = object of Exception
+ ESomeOtherErr = object of Exception
proc genErrors(s: string) =
if s == "error!":
@@ -17,14 +17,14 @@ proc foo() =
var i = 0
try:
inc i
- onRaise(proc (e: ref E_Base): bool =
+ onRaise(proc (e: ref Exception): bool =
echo "i: ", i)
genErrors("errssor!")
except ESomething:
echo("ESomething happened")
except:
echo("Some other error happened")
-
+
# test that raise handler is gone:
try:
genErrors("error!")
diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim
index cbd0b5f8a1..b2a11d34f2 100644
--- a/tests/exception/treraise.nim
+++ b/tests/exception/treraise.nim
@@ -4,8 +4,8 @@ discard """
exitcode: "1"
"""
type
- ESomething = object of E_Base
- ESomeOtherErr = object of E_Base
+ ESomething = object of Exception
+ ESomeOtherErr = object of Exception
proc genErrors(s: string) =
if s == "error!":
diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim
new file mode 100644
index 0000000000..00d90c55e1
--- /dev/null
+++ b/tests/generics/twrong_generic_object.nim
@@ -0,0 +1,21 @@
+discard """
+ errormsg: "cannot instantiate: 'GenericNodeObj'"
+ line: 21
+"""
+# bug #2509
+type
+ GenericNodeObj[T] = ref object
+ obj: T
+
+ Node* = ref object
+ children*: seq[Node]
+ parent*: Node
+
+ nodeObj*: GenericNodeObj # [int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+ result = Node(nodeObj: nodeObj)
+ newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+var myNode = newNode(genericObj)
diff --git a/tests/js/test2.nim b/tests/js/test2.nim
index 5a734358cb..1a42fbfdad 100644
--- a/tests/js/test2.nim
+++ b/tests/js/test2.nim
@@ -1,6 +1,7 @@
discard """
output: '''foo
-js 3.14'''
+js 3.14
+7'''
"""
# This file tests the JavaScript generator
@@ -20,3 +21,11 @@ else:
proc foo(val: float): string = "js " & $val
echo foo(3.14)
+
+# #2495
+type C = concept x
+
+proc test(x: C, T: typedesc): T =
+ cast[T](x)
+
+echo 7.test(int8)
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
new file mode 100644
index 0000000000..f4ea02fec9
--- /dev/null
+++ b/tests/js/tstringitems.nim
@@ -0,0 +1,24 @@
+discard """
+ output: '''Hello
+Hello'''
+"""
+
+# bug #2581
+
+const someVars = [ "Hello" ]
+var someVars2 = [ "Hello" ]
+
+proc getSomeVar: string =
+ for i in someVars:
+ if i == "Hello":
+ result = i
+ break
+
+proc getSomeVar2: string =
+ for i in someVars2:
+ if i == "Hello":
+ result = i
+ break
+
+echo getSomeVar()
+echo getSomeVar2()
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
index af38cd9b90..8a264a5e02 100644
--- a/tests/js/tunittests.nim
+++ b/tests/js/tunittests.nim
@@ -1,3 +1,10 @@
+discard """
+ disabled: "true"
+"""
+
+# Unittest uses lambdalifting at compile-time which we disable for the JS
+# codegen! So this cannot and will not work for quite some time.
+
import unittest
suite "Bacon":
diff --git a/tests/macros/tlexerex.nim b/tests/macros/tlexerex.nim
new file mode 100644
index 0000000000..d348a4bcc5
--- /dev/null
+++ b/tests/macros/tlexerex.nim
@@ -0,0 +1,16 @@
+
+import macros
+
+macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
+ for sec in sections.children:
+ expectKind sec, nnkOfBranch
+ expectLen sec, 2
+ result = newStmtList()
+
+when isMainModule:
+ var input = "the input"
+ var pos = 0
+ match input, pos:
+ of r"[a-zA-Z_]\w+": echo "an identifier"
+ of r"\d+": echo "an integer"
+ of r".": echo "something else"
diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim
new file mode 100644
index 0000000000..7af26a7472
--- /dev/null
+++ b/tests/macros/treturnsempty.nim
@@ -0,0 +1,12 @@
+discard """
+ errormsg: "type mismatch"
+ line: 11
+"""
+# bug #2372
+macro foo(dummy: int): stmt =
+ discard
+
+proc takeStr(s: string) = echo s
+
+takeStr foo(12)
+
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
index af932eb7dd..c7bbc8e5bd 100644
--- a/tests/macros/ttryparseexpr.nim
+++ b/tests/macros/ttryparseexpr.nim
@@ -15,5 +15,6 @@ const
valid = 45
a = test("foo&&")
b = test("valid")
+ c = test("\"") # bug #2504
echo a, " ", b
diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim
index 016295ba4f..2e59d2154e 100644
--- a/tests/macros/typesapi2.nim
+++ b/tests/macros/typesapi2.nim
@@ -1,4 +1,4 @@
-# tests to see if a symbol returned from macros.getType() can
+# tests to see if a symbol returned from macros.getType() can
# be used as a type
import macros
@@ -20,7 +20,7 @@ static: assert iii is TestFN
proc foo11 : testTypesym(void) =
echo "HI!"
-static: assert foo11 is proc():void
+static: assert foo11 is (proc():void {.nimcall.})
var sss: testTypesym(seq[int])
static: assert sss is seq[int]
diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim
index efd2b21f95..d9b3f43886 100644
--- a/tests/manyloc/standalone/panicoverride.nim
+++ b/tests/manyloc/standalone/panicoverride.nim
@@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "", cdecl.}
proc rawoutput(s: string) =
printf("%s\n", s)
-proc panic(s: string) =
+proc panic(s: string) {.noreturn.} =
rawoutput(s)
exit(1)
# Alternatively we also could implement these 2 here:
#
-# template sysFatal(exceptn: typeDesc, message: string)
-# template sysFatal(exceptn: typeDesc, message, arg: string)
+# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.}
+# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.}
{.pop.}
diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim
index 562f508fc5..ef5377096c 100644
--- a/tests/metatype/tautoproc.nim
+++ b/tests/metatype/tautoproc.nim
@@ -1,11 +1,13 @@
discard """
- errormsg: "expression 'generate(builder)' has no type (or is ambiguous)"
+ output: "empty"
"""
# bug #898
+import typetraits
+
proc measureTime(e: auto) =
- discard
+ echo e.type.name
proc generate(a: int): void =
discard
diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim
new file mode 100644
index 0000000000..1b5d19c18f
--- /dev/null
+++ b/tests/misc/tcharinc.nim
@@ -0,0 +1,10 @@
+discard """
+ output: "1"
+"""
+
+var c = '\0'
+while true:
+ if c == '\xFF': break
+ inc c
+
+echo "1"
diff --git a/tests/misc/tgtk.nim b/tests/misc/tgtk.nim
deleted file mode 100644
index 82227689d4..0000000000
--- a/tests/misc/tgtk.nim
+++ /dev/null
@@ -1,53 +0,0 @@
-discard """
- disabled: true
-"""
-import
- gtk2, glib2, atk, gdk2, gdk2pixbuf, libglade2, pango,
- pangoutils
-
-proc hello(widget: PWidget, data: pointer) {.cdecl.} =
- write(stdout, "Hello World\n")
-
-proc delete_event(widget: PWidget, event: PEvent,
- data: pointer): bool {.cdecl.} =
- # If you return FALSE in the "delete_event" signal handler,
- # GTK will emit the "destroy" signal. Returning TRUE means
- # you don't want the window to be destroyed.
- # This is useful for popping up 'are you sure you want to quit?'
- # type dialogs.
- write(stdout, "delete event occurred\n")
- # Change TRUE to FALSE and the main window will be destroyed with
- # a "delete_event".
- return false
-
-# Another callback
-proc mydestroy(widget: PWidget, data: pointer) {.cdecl.} =
- gtk2.main_quit()
-
-proc mymain() =
- # GtkWidget is the storage type for widgets
- gtk2.nimrod_init()
- var window = window_new(gtk2.WINDOW_TOPLEVEL)
- discard g_signal_connect(window, "delete_event",
- Gcallback(delete_event), nil)
- discard g_signal_connect(window, "destroy", Gcallback(mydestroy), nil)
- # Sets the border width of the window.
- set_border_width(window, 10)
-
- # Creates a new button with the label "Hello World".
- var button = button_new("Hello World")
-
- discard g_signal_connect(button, "clicked", Gcallback(hello), nil)
-
- # This packs the button into the window (a gtk container).
- add(window, button)
-
- # The final step is to display this newly created widget.
- show(button)
-
- # and the window
- show(window)
-
- gtk2.main()
-
-mymain()
diff --git a/tests/misc/tlibs.nim b/tests/misc/tlibs.nim
deleted file mode 100644
index e7a02c7fde..0000000000
--- a/tests/misc/tlibs.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-discard """
- disabled: true
-"""
-
-# Test wether the bindings at least compile...
-
-import
- unicode, cgi, terminal, libcurl,
- parsexml, parseopt, parsecfg,
- osproc, complex,
- sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
- sdl_image, sdl_mixer_nosmpeg,
- cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
- xkblib, xrender, xutil, x, xf86dga, xinerama, xlib, xresource, xv,
- gtk2, glib2, pango, gdk2,
- cairowin32, cairoxlib,
- odbcsql,
- gl, glut, glu, glx, glext, wingl,
- lua, lualib, lauxlib, mysql, sqlite3, python, tcl,
- db_postgres, db_mysql, db_sqlite, ropes, sockets, browsers, httpserver,
- httpclient, parseutils, unidecode, xmldom, xmldomparser, xmltree, xmlparser,
- htmlparser, re, graphics, colors, pegs, subexes, dialogs
-
-when defined(linux):
- import
- zlib, zipfiles
-
-writeln(stdout, "test compilation of binding modules")
diff --git a/tests/misc/tnewlibs.nim b/tests/misc/tnewlibs.nim
deleted file mode 100644
index 3b74a9b63f..0000000000
--- a/tests/misc/tnewlibs.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-discard """
- disabled: true
-"""
-
-# Test wether the bindings at least compile...
-
-import
- tcl,
- sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
- sdl_image, sdl_mixer_nosmpeg,
- gtk2, glib2, pango, gdk2,
- unicode, cgi, terminal, libcurl,
- parsexml, parseopt, parsecfg,
- osproc,
- cairowin32, cairoxlib,
- gl, glut, glu, glx, glext, wingl,
- lua, lualib, lauxlib, mysql, sqlite3, db_mongo, md5, asyncio, mimetypes,
- cookies, events, ftpclient, scgi, irc
-
-
-writeln(stdout, "test compilation of binding modules")
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
index 9ae0d535a9..3007405a2e 100644
--- a/tests/misc/tunsigned64mod.nim
+++ b/tests/misc/tunsigned64mod.nim
@@ -10,3 +10,17 @@ let t1 = v1 mod 2 # works
let t2 = 7'u64 mod 2'u64 # works
let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
let t4 = (v2 mod 2'u64).uint64 # works
+
+# bug #2550
+
+var x: uint # doesn't work
+echo x mod 2 == 0
+
+var y: uint64 # doesn't work
+echo y mod 2 == 0
+
+var z: uint32 # works
+echo z mod 2 == 0
+
+var a: int # works
+echo a mod 2 == 0
diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim
new file mode 100644
index 0000000000..95622156f4
--- /dev/null
+++ b/tests/misc/tunsignedinc.nim
@@ -0,0 +1,14 @@
+discard """
+ output: '''253'''
+"""
+
+# bug #2427
+
+import unsigned
+
+var x = 0'u8
+dec x # OverflowError
+x -= 1 # OverflowError
+x = x - 1 # No error
+
+echo x
diff --git a/tests/objects/tillegal_recursion.nim b/tests/objects/tillegal_recursion.nim
new file mode 100644
index 0000000000..171a04f87e
--- /dev/null
+++ b/tests/objects/tillegal_recursion.nim
@@ -0,0 +1,7 @@
+discard """
+ errormsg: "illegal recursion in type 'object'"
+ line: 7
+"""
+# bug #1691
+type
+ Foo = ref object of Foo
diff --git a/tests/objects/tobjloop.nim b/tests/objects/tobjloop.nim
new file mode 100644
index 0000000000..9fea1e2fb9
--- /dev/null
+++ b/tests/objects/tobjloop.nim
@@ -0,0 +1,15 @@
+discard """
+ output: "is Nil false"
+"""
+# bug #1658
+
+type
+ Loop* = ref object
+ onBeforeSelect*: proc (L: Loop)
+
+var L: Loop
+new L
+L.onBeforeSelect = proc (bar: Loop) =
+ echo "is Nil ", bar.isNil
+
+L.onBeforeSelect(L)
diff --git a/tests/objects/trefobjsyntax2.nim b/tests/objects/trefobjsyntax2.nim
new file mode 100644
index 0000000000..8ee209cc75
--- /dev/null
+++ b/tests/objects/trefobjsyntax2.nim
@@ -0,0 +1,19 @@
+# bug #2508
+
+type
+ GenericNodeObj[T] = ref object
+ obj: T
+
+ Node* = ref object
+ children*: seq[Node]
+ parent*: Node
+
+ nodeObj*: GenericNodeObj[int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+ result = Node(nodeObj: nodeObj)
+ newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+
+var myNode = newNode(genericObj)
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
index 685df503a1..f2002a390e 100644
--- a/tests/overload/tspec.nim
+++ b/tests/overload/tspec.nim
@@ -11,7 +11,10 @@ ref T
123
2
1
-@[123, 2, 1]'''
+@[123, 2, 1]
+Called!
+merge with var
+merge no var'''
"""
# Things that's even in the spec now!
@@ -79,3 +82,37 @@ proc takeV[T](a: varargs[T]) =
takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
echo(@[123, 2, 1])
+
+# bug #2600
+
+type
+ FutureBase* = ref object of RootObj ## Untyped future.
+
+ Future*[T] = ref object of FutureBase ## Typed future.
+ value: T ## Stored value
+
+ FutureVar*[T] = distinct Future[T]
+
+proc newFuture*[T](): Future[T] =
+ new(result)
+
+proc newFutureVar*[T](): FutureVar[T] =
+ result = FutureVar[T](newFuture[T]())
+
+proc mget*[T](future: FutureVar[T]): var T =
+ Future[T](future).value
+
+proc reset*[T](future: FutureVar[T]) =
+ echo "Called!"
+
+proc merge[T](x: Future[T]) = echo "merge no var"
+proc merge[T](x: var Future[T]) = echo "merge with var"
+
+when true:
+ var foo = newFutureVar[string]()
+ foo.mget() = ""
+ foo.mget.add("Foobar")
+ foo.reset()
+ var bar = newFuture[int]()
+ bar.merge # merge with var
+ merge(newFuture[int]()) # merge no var
diff --git a/tests/overload/tstmtoverload.nim b/tests/overload/tstmtoverload.nim
new file mode 100644
index 0000000000..f1944b6379
--- /dev/null
+++ b/tests/overload/tstmtoverload.nim
@@ -0,0 +1,38 @@
+
+# bug #2481
+import math
+
+template test(loopCount: int, extraI: int, testBody: stmt): stmt =
+ block:
+ for i in 0..loopCount-1:
+ testBody
+ echo "done extraI=", extraI
+
+template test(loopCount: int, extraF: float, testBody: stmt): stmt =
+ block:
+ test(loopCount, round(extraF), testBody)
+
+template test(loopCount: int, testBody: stmt): stmt =
+ block:
+ test(loopCount, 0, testBody)
+ echo "done extraI passed 0"
+
+when isMainModule:
+ var
+ loops = 0
+
+ test 0, 0:
+ loops += 1
+ echo "test 0 complete, loops=", loops
+
+ test 1, 1.0:
+ loops += 1
+ echo "test 1.0 complete, loops=", loops
+
+ when true:
+ # when true we get the following compile time error:
+ # b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
+ loops = 0
+ test 2:
+ loops += 1
+ echo "test no extra complete, loops=", loops
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 0000000000..ec4605fe94
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,39 @@
+discard """
+ line: 28
+ nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
+tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
+tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+ errormsg: "'consumer' is not GC-safe as it calls 'track'"
+"""
+
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+ MyObject[T] = object
+ x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+ echo global.x
+ echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+ track(ix)
+
+proc main =
+ for ix in 1..3: channels[ix].open()
+ for ix in 1..3: spawn consumer(ix)
+ for ix in 1..3: channels[ix].send("test")
+ sync()
+ for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+ main()
diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
new file mode 100644
index 0000000000..db32a96d80
--- /dev/null
+++ b/tests/parallel/twrong_refcounts.nim
@@ -0,0 +1,53 @@
+discard """
+ output: "Success"
+"""
+
+import math, threadPool
+
+# ---
+
+type
+ Person = object
+ age: int
+ friend: ref Person
+
+var
+ people: seq[ref Person] = @[]
+
+proc newPerson(age:int): ref Person =
+ result.new()
+ result.age = age
+
+proc greet(p:Person) =
+ #echo p.age, ", ", p.friend.age
+ p.friend.age += 1
+
+# ---
+
+proc setup =
+ for i in 0 .. <20:
+ people.add newPerson(i + 1)
+ for i in 0 .. <20:
+ people[i].friend = people[random(20)]
+
+proc update =
+ var countA: array[20, int]
+ var countB: array[20, int]
+
+ for i, p in people:
+ countA[i] = getRefCount(p)
+ parallel:
+ for i in 0 .. people.high:
+ spawn greet(people[i][])
+ for i, p in people:
+ countB[i] = getRefCount(p)
+
+ for i in 0 .. <20:
+ doAssert countA[i] == countB[i]
+ echo "Success"
+
+# ---
+
+when isMainModule:
+ setup()
+ update()
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
new file mode 100644
index 0000000000..cacde48bd7
--- /dev/null
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -0,0 +1,12 @@
+discard """
+ file: "tinvcolonlocation1.nim"
+ line: 8
+ column: 3
+ errormsg: "':' expected"
+"""
+try #<- missing ':'
+ echo "try"
+except:
+ echo "except"
+finally:
+ echo "finally"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
new file mode 100644
index 0000000000..2b6a92b9d8
--- /dev/null
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -0,0 +1,15 @@
+discard """
+ file: "tinvcolonlocation2.nim"
+ line: 11
+ column: 1
+ errormsg: "':' expected"
+"""
+try:
+ echo "try"
+except #<- missing ':'
+ echo "except"
+finally:
+#<-- error will be here above, at the beginning of finally,
+# since compiler tries to consome echo and part of except
+# expression
+ echo "finally"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
new file mode 100644
index 0000000000..2b30b1dbe9
--- /dev/null
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -0,0 +1,12 @@
+discard """
+ file: "tinvcolonlocation3.nim"
+ line: 12
+ column: 3
+ errormsg: "':' expected"
+"""
+try:
+ echo "try"
+except:
+ echo "except"
+finally #<- missing ':'
+ echo "finally"
diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim
index 91506daf07..e70b91988c 100644
--- a/tests/parser/tstrongspaces.nim
+++ b/tests/parser/tstrongspaces.nim
@@ -2,6 +2,12 @@
discard """
output: '''35
+true
+true
+4
+true
+1
+false
77
(Field0: 1, Field1: 2, Field2: 2)
ha
@@ -9,11 +15,26 @@ true
tester args
all
all args
+19
+-3
+false
+-2
'''
"""
echo 2+5 * 5
+# Keyword operators
+echo 1 + 16 shl 1 == 1 + (16 shl 1)
+echo 2 and 1 in {0, 30}
+echo 2+2 * 2 shr 1
+echo false or 2 and 1 in {0, 30}
+
+proc `^`(a, b: int): int = a + b div 2
+echo 19 mod 16 ^ 4 + 2 and 1
+echo 18 mod 16 ^ 4 > 0
+
+# echo $foo gotcha
let foo = 77
echo $foo
@@ -27,7 +48,7 @@ when true:
let b = 66
let c = 90
let bar = 8000
- if foo+4 * 4 == 8 and b&c | 9 ++
+ if foo+4 * 4 == 8 and b&c | 9 ++
bar:
echo "ho"
else:
@@ -50,3 +71,13 @@ const
echo tester & " " & args|"all"
echo "all" | tester & " " & args
echo "all"|tester & " " & args
+
+# Test arrow like operators. See also tests/macros/tclosuremacro.nim
+proc `+->`(a, b: int): int = a + b*4
+template `===>`(a, b: int): expr = a - b shr 1
+
+echo 3 +-> 2 + 2 and 4
+var arrowed = 3+->2 + 2 and 4 # arrowed = 4
+echo arrowed ===> 15
+echo (2 * 3+->2) == (2*3 +-> 2)
+echo arrowed ===> 2 + 3+->2
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
new file mode 100644
index 0000000000..aaa06f9f41
--- /dev/null
+++ b/tests/parser/ttupleunpack.nim
@@ -0,0 +1,35 @@
+discard """
+ file: "ttupleunpack.nim"
+ output: ""
+ exitcode: 0
+"""
+
+proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+proc main2 =
+ let (x, _, z) = returnsTuple()
+
+proc main() =
+
+ proc foo(): tuple[x, y, z: int] =
+ return (4, 2, 3)
+
+ var (x, _, y) = foo()
+ doAssert x == 4
+ doAssert y == 3
+
+ var (a, _, _) = foo()
+ doAssert a == 4
+
+ var (aa, _, _) = foo()
+ doAssert aa == 4
+
+ iterator bar(): tuple[x, y, z: int] =
+ yield (1,2,3)
+
+ for x, y, _ in bar():
+ doAssert x == 1
+ doAssert y == 2
+
+main()
+main2()
diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim
index e370209ed0..6461753296 100644
--- a/tests/sets/tsets.nim
+++ b/tests/sets/tsets.nim
@@ -1,6 +1,7 @@
discard """
file: "tsets.nim"
- output: "Ha ein F ist in s!"
+ output: '''Ha ein F ist in s!
+false'''
"""
# Test the handling of sets
@@ -15,30 +16,30 @@ type
TAZ = range['a'..'z']
TAZset = set[TAZ]
- TTokType* = enum
+ TTokType* = enum
tkInvalid, tkEof,
tkSymbol,
- tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
- tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
- tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
- tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
- tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
- tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
+ tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
+ tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
+ tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
+ tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
+ tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
+ tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,
- tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
- tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
- tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
- tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
- tkCurlyDotLe, tkCurlyDotRi,
+ tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
+ tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
+ tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
+ tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
+ tkCurlyDotLe, tkCurlyDotRi,
tkParDotLe, tkParDotRi,
- tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
+ tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
tkComment, tkAccent, tkInd, tkSad, tkDed,
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TTokTypeRange = range[tkSymbol..tkDed]
TTokTypes* = set[TTokTypeRange]
const
- toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
+ toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
tkStrLit..tkTripleStrLit}
var
@@ -62,3 +63,142 @@ for x in low(TTokTypeRange) .. high(TTokTypeRange):
#OUT Ha ein F ist in s!
+type
+ TMsgKind* = enum
+ errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
+ errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
+ errIntLiteralExpected, errInvalidCharacterConstant,
+ errClosingTripleQuoteExpected, errClosingQuoteExpected,
+ errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
+ errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
+ errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
+ errNewlineExpected,
+ errInvalidModuleName,
+ errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
+ errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
+ errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
+ errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
+ errExceptionExpected, errExceptionAlreadyHandled,
+ errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
+ errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
+ errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
+ errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
+ errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
+ errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
+ errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
+ errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
+ errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
+ errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
+ errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
+ errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
+ errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
+ errConstantDivisionByZero, errOrdinalTypeExpected,
+ errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
+ errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
+ errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
+ errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
+ errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
+ errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
+ errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
+ errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
+ errMagicOnlyInSystem, errPowerOfTwoExpected,
+ errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
+ errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
+ errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
+ errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
+ errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
+ errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
+ errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
+ errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
+ errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
+ errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
+ errVarForOutParamNeeded,
+ errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
+ errAmbiguousCallXYZ, errWrongNumberOfArguments,
+ errXCannotBePassedToProcVar,
+ errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
+ errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
+ errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
+ errInvalidOrderInArrayConstructor,
+ errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
+ errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
+ errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
+ errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
+ errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
+ errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
+ errXNotAllowedHere, errInvalidControlFlowX,
+ errXisNoType, errCircumNeedsPointer, errInvalidExpression,
+ errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
+ errNamedExprNotAllowed, errXExpectsOneTypeParam,
+ errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
+ errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
+ errNoReturnTypeDeclared,
+ errInvalidCommandX, errXOnlyAtModuleScope,
+ errXNeedsParamObjectType,
+ errTemplateInstantiationTooNested, errInstantiationFrom,
+ errInvalidIndexValueForTuple, errCommandExpectsFilename,
+ errMainModuleMustBeSpecified,
+ errXExpected,
+ errTIsNotAConcreteType,
+ errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
+ errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
+ errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
+ errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
+ errMacroBodyDependsOnGenericTypes,
+ errDestructorNotGenericEnough,
+ errInlineIteratorsAsProcParams,
+ errXExpectsTwoArguments,
+ errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
+ errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
+ errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
+ errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
+ errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
+ errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
+ errXCannotBeClosure, errXMustBeCompileTime,
+ errCannotInferTypeOfTheLiteral,
+ errCannotInferReturnType,
+ errGenericLambdaNotAllowed,
+ errCompilerDoesntSupportTarget,
+ errUser,
+ warnCannotOpenFile,
+ warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
+ warnDeprecated, warnConfigDeprecated,
+ warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
+ warnUnknownSubstitutionX, warnLanguageXNotSupported,
+ warnFieldXNotSupported, warnCommentXIgnored,
+ warnNilStatement, warnTypelessParam,
+ warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
+ warnEachIdentIsTuple, warnShadowIdent,
+ warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
+ warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
+ warnUser,
+ hintSuccess, hintSuccessX,
+ hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
+ hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
+ hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
+ hintConditionAlwaysTrue, hintName, hintPattern,
+ hintUser
+
+const
+ fatalMin* = errUnknown
+ fatalMax* = errInternal
+ errMin* = errUnknown
+ errMax* = errUser
+ warnMin* = warnCannotOpenFile
+ warnMax* = pred(hintSuccess)
+ hintMin* = hintSuccess
+ hintMax* = high(TMsgKind)
+
+type
+ TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
+ TNoteKinds* = set[TNoteKind]
+
+var
+ gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
+ {warnShadowIdent, warnUninit,
+ warnProveField, warnProveIndex, warnGcUnsafe}
+
+
+#import compiler.msgs
+
+echo warnUninit in gNotes
diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim
deleted file mode 100644
index f0203d3197..0000000000
--- a/tests/stdlib/tdialogs.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-# Test the dialogs module
-
-import dialogs, gtk2
-
-gtk2.nimrod_init()
-
-var x = chooseFilesToOpen(nil)
-for a in items(x):
- writeln(stdout, a)
-
-info(nil, "start with an info box")
-warning(nil, "now a warning ...")
-error(nil, "... and an error!")
-
-writeln(stdout, chooseFileToOpen(nil))
-writeln(stdout, chooseFileToSave(nil))
-writeln(stdout, chooseDir(nil))
diff --git a/tests/stdlib/treloop.nim b/tests/stdlib/treloop.nim
new file mode 100644
index 0000000000..35236708cb
--- /dev/null
+++ b/tests/stdlib/treloop.nim
@@ -0,0 +1,9 @@
+discard """
+ output: "@[(, +, 1, 2, )]"
+"""
+
+import re
+
+let str = "(+ 1 2)"
+var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+echo str.findAll(tokenRE)
diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim
new file mode 100644
index 0000000000..891166306d
--- /dev/null
+++ b/tests/template/tdefault_nil.nim
@@ -0,0 +1,14 @@
+
+# bug #2629
+import sequtils, os
+
+template glob_rst(basedir: string = nil): expr =
+ if baseDir.isNil:
+ to_seq(walk_files("*.rst"))
+ else:
+ to_seq(walk_files(basedir/"*.rst"))
+
+let
+ rst_files = concat(glob_rst(), glob_rst("docs"))
+
+when isMainModule: echo rst_files
diff --git a/tests/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim
new file mode 100644
index 0000000000..05c16c3c97
--- /dev/null
+++ b/tests/template/tstmt_semchecked_twice.nim
@@ -0,0 +1,30 @@
+
+# bug #2585
+
+type
+ RenderPass = object
+ state: ref int
+
+ RenderData* = object
+ fb: int
+ walls: seq[RenderPass]
+
+ Mat2 = int
+ Vector2[T] = T
+ Pixels=int
+
+template use*(fb: int, st: stmt) : stmt =
+ echo "a ", $fb
+ st
+ echo "a ", $fb
+
+proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+ indexType = 1) =
+ for i in 0 .. (0, 10, 2):
+ write(W, 'c')
+ else:
+ block:
+ var x: W
+ write(x, char)
+
+ FmtAlign = enum ## Format alignment
+ faDefault ## default for given format type
+ faLeft ## left aligned
+ faRight ## right aligned
+ faCenter ## centered
+ faPadding ## right aligned, fill characters after sign (numbers only)
+
+ FmtSign = enum ## Format sign
+ fsMinus ## only unary minus, no reservered sign space for positive numbers
+ fsPlus ## unary minus and unary plus
+ fsSpace ## unary minus and reserved space for positive numbers
+
+ FmtType = enum ## Format type
+ ftDefault ## default format for given parameter type
+ ftStr ## string
+ ftChar ## character
+ ftDec ## decimal integer
+ ftBin ## binary integer
+ ftOct ## octal integer
+ ftHex ## hexadecimal integer
+ ftFix ## real number in fixed point notation
+ ftSci ## real number in scientific notation
+ ftGen ## real number in generic form (either fixed point or scientific)
+ ftPercent ## real number multiplied by 100 and % added
+
+ Format = tuple ## Formatting information.
+ typ: FmtType ## format type
+ precision: int ## floating point precision
+ width: int ## minimal width
+ fill: string ## the fill character, UTF8
+ align: FmtAlign ## aligment
+ sign: FmtSign ## sign notation
+ baseprefix: bool ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o
+ upcase: bool ## upper case letters in hex or exponential formats
+ comma: bool ##
+ arysep: string ## separator for array elements
+
+ PartKind = enum pkStr, pkFmt
+
+ Part = object
+ ## Information of a part of the target string.
+ case kind: PartKind ## type of the part
+ of pkStr:
+ str: string ## literal string
+ of pkFmt:
+ arg: int ## position argument
+ fmt: string ## format string
+ field: string ## field of argument to be accessed
+ index: int ## array index of argument to be accessed
+ nested: bool ## true if the argument contains nested formats
+
+const
+ DefaultPrec = 6 ## Default precision for floating point numbers.
+ DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil)
+ ## Default format corresponding to the empty format string, i.e.
+ ## `x.format("") == x.format(DefaultFmt)`.
+ round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
+ ## Rounding offset for floating point numbers up to precision 8.
+
+proc write(s: var string; c: char) =
+ s.add(c)
+
+proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} =
+ ## Tests whether `c` contains a non-empty capture `i`.
+ let b = c.bounds(i)
+ result = b.first <= b.last
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} =
+ ## If capture `i` is non-empty return that portion of `str` casted
+ ## to `char`, otherwise return `def`.
+ result = if c.has(i): str[c.bounds(i).first] else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} =
+ ## If capture `i` is non-empty return that portion of `str` as
+ ## string, otherwise return `def`.
+ let b = c.bounds(i)
+ result = if c.has(i): str.substr(b.first + begoff, b.last) else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} =
+ ## If capture `i` is non-empty return that portion of `str`
+ ## converted to int, otherwise return `def`.
+ if c.has(i):
+ discard str.parseInt(result, c.bounds(i).first + begoff)
+ else:
+ result = def
+
+proc parse(fmt: string): Format {.nosideeffect.} =
+ # Converts the format string `fmt` into a `Format` structure.
+ let p =
+ sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))),
+ capture(?charSet({'<', '>', '=', '^'})),
+ capture(?charSet({'-', '+', ' '})),
+ capture(?charSet({'#'})),
+ capture(?(+digits())),
+ capture(?charSet({','})),
+ capture(?sequence(charSet({'.'}), +digits())),
+ capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})),
+ capture(?sequence(charSet({'a'}), *pegs.any())))
+ # let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}"
+
+ var caps: Captures
+ if fmt.rawmatch(p, 0, caps) < 0:
+ raise newException(FormatError, "Invalid format string")
+
+ result.fill = fmt.get(caps, 0, nil)
+
+ case fmt.get(caps, 1, 0.char)
+ of '<': result.align = faLeft
+ of '>': result.align = faRight
+ of '^': result.align = faCenter
+ of '=': result.align = faPadding
+ else: result.align = faDefault
+
+ case fmt.get(caps, 2, '-')
+ of '-': result.sign = fsMinus
+ of '+': result.sign = fsPlus
+ of ' ': result.sign = fsSpace
+ else: result.sign = fsMinus
+
+ result.baseprefix = caps.has(3)
+
+ result.width = fmt.get(caps, 4, -1)
+
+ if caps.has(4) and fmt[caps.bounds(4).first] == '0':
+ if result.fill != nil:
+ raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
+ if result.align != faDefault:
+ raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
+ result.fill = "0"
+ result.align = faPadding
+
+ result.comma = caps.has(5)
+
+ result.precision = fmt.get(caps, 6, -1, 1)
+
+ case fmt.get(caps, 7, 0.char)
+ of 's': result.typ = ftStr
+ of 'c': result.typ = ftChar
+ of 'd', 'n': result.typ = ftDec
+ of 'b': result.typ = ftBin
+ of 'o': result.typ = ftOct
+ of 'x': result.typ = ftHex
+ of 'X': result.typ = ftHex; result.upcase = true
+ of 'f', 'F': result.typ = ftFix
+ of 'e': result.typ = ftSci
+ of 'E': result.typ = ftSci; result.upcase = true
+ of 'g': result.typ = ftGen
+ of 'G': result.typ = ftGen; result.upcase = true
+ of '%': result.typ = ftPercent
+ else: result.typ = ftDefault
+
+ result.arysep = fmt.get(caps, 8, nil, 1)
+
+proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
+ ## Returns the number of left and right padding characters for a
+ ## given format alignment and width of the object to be printed.
+ ##
+ ## `fmt`
+ ## the format data
+ ## `default`
+ ## if `fmt.align == faDefault`, then this alignment is used
+ ## `slen`
+ ## the width of the object to be printed.
+ ##
+ ## The returned values `(left, right)` will be as minimal as possible
+ ## so that `left + slen + right >= fmt.width`.
+ result.left = 0
+ result.right = 0
+ if (fmt.width >= 0) and (slen < fmt.width):
+ let alg = if fmt.align == faDefault: defalign else: fmt.align
+ case alg:
+ of faLeft: result.right = fmt.width - slen
+ of faRight, faPadding: result.left = fmt.width - slen
+ of faCenter:
+ result.left = (fmt.width - slen) div 2
+ result.right = fmt.width - slen - result.left
+ else: discard
+
+proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
+ ## Write characters for filling. This function also writes the sign
+ ## of a numeric format and handles the padding alignment
+ ## accordingly.
+ ##
+ ## `o`
+ ## output object
+ ## `add`
+ ## output function
+ ## `fmt`
+ ## format to be used (important for padding aligment)
+ ## `n`
+ ## the number of filling characters to be written
+ ## `signum`
+ ## the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero
+ if fmt.align == faPadding and signum != 0:
+ if signum < 0: write(o, '-')
+ elif fmt.sign == fsPlus: write(o, '+')
+ elif fmt.sign == fsSpace: write(o, ' ')
+
+ if fmt.fill == nil:
+ for i in 1..n: write(o, ' ')
+ else:
+ for i in 1..n:
+ for c in fmt.fill:
+ write(o, c)
+
+ if fmt.align != faPadding and signum != 0:
+ if signum < 0: write(o, '-')
+ elif fmt.sign == fsPlus: write(o, '+')
+ elif fmt.sign == fsSpace: write(o, ' ')
+
+proc writeformat(o: var Writer; s: string; fmt: Format) =
+ ## Write string `s` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ if fmt.typ notin {ftDefault, ftStr}:
+ raise newException(FormatError, "String variable must have 's' format type")
+
+ # compute alignment
+ let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision)
+ var alg = getalign(fmt, faLeft, len)
+ writefill(o, fmt, alg.left)
+ var pos = 0
+ for i in 0..len-1:
+ let rlen = runeLenAt(s, pos)
+ for j in pos..pos+rlen-1: write(o, s[j])
+ pos += rlen
+ writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: char; fmt: Format) =
+ ## Write character `c` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ if not (fmt.typ in {ftChar, ftDefault}):
+ raise newException(FormatError, "Character variable must have 'c' format type")
+
+ # compute alignment
+ var alg = getalign(fmt, faLeft, 1)
+ writefill(o, fmt, alg.left)
+ write(o, c)
+ writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: Rune; fmt: Format) =
+ ## Write rune `c` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ if not (fmt.typ in {ftChar, ftDefault}):
+ raise newException(FormatError, "Character variable must have 'c' format type")
+
+ # compute alignment
+ var alg = getalign(fmt, faLeft, 1)
+ writefill(o, fmt, alg.left)
+ let s = c.toUTF8
+ for c in s: write(o, c)
+ writefill(o, fmt, alg.right)
+
+proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x
+ ## Return the absolute value of the unsigned int `x`.
+
+proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) =
+ ## Write integer `i` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ var fmt = fmt
+ if fmt.typ == ftDefault:
+ fmt.typ = ftDec
+ if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}):
+ raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n")
+
+ var base: type(i)
+ var len = 0
+ case fmt.typ:
+ of ftDec:
+ base = 10
+ of ftBin:
+ base = 2
+ if fmt.baseprefix: len += 2
+ of ftOct:
+ base = 8
+ if fmt.baseprefix: len += 2
+ of ftHex:
+ base = 16
+ if fmt.baseprefix: len += 2
+ else: assert(false)
+
+ if fmt.sign != fsMinus or i < 0: len.inc
+
+ var x: type(i) = abs(i)
+ var irev: type(i) = 0
+ var ilen = 0
+ while x > 0.SomeInteger:
+ len.inc
+ ilen.inc
+ irev = irev * base + x mod base
+ x = x div base
+ if ilen == 0:
+ ilen.inc
+ len.inc
+
+ var alg = getalign(fmt, faRight, len)
+ writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1)
+ if fmt.baseprefix:
+ case fmt.typ
+ of ftBin:
+ write(o, '0')
+ write(o, 'b')
+ of ftOct:
+ write(o, '0')
+ write(o, 'o')
+ of ftHex:
+ write(o, '0')
+ write(o, 'x')
+ else:
+ raise newException(FormatError, "# only allowed with b, o, x or X")
+ while ilen > 0:
+ ilen.dec
+ let c = irev mod base
+ irev = irev div base
+ if c < 10:
+ write(o, ('0'.int + c.int).char)
+ elif fmt.upcase:
+ write(o, ('A'.int + c.int - 10).char)
+ else:
+ write(o, ('a'.int + c.int - 10).char)
+ writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; p: pointer; fmt: Format) =
+ ## Write pointer `i` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ ##
+ ## Pointers are casted to unsigned int and formated as hexadecimal
+ ## with prefix unless specified otherwise.
+ var f = fmt
+ if f.typ == 0.char:
+ f.typ = 'x'
+ f.baseprefix = true
+ writeformat(o, add, cast[uint](p), f)
+
+proc writeformat(o: var Writer; x: SomeReal; fmt: Format) =
+ ## Write real number `x` according to format `fmt` using output
+ ## object `o` and output function `add`.
+ var fmt = fmt
+ # handle default format
+ if fmt.typ == ftDefault:
+ fmt.typ = ftGen
+ if fmt.precision < 0: fmt.precision = DefaultPrec
+ if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}):
+ raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%")
+
+ let positive = x >= 0 and classify(x) != fcNegZero
+ var len = 0
+
+ if fmt.sign != fsMinus or not positive: len.inc
+
+ var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision
+ var y = abs(x)
+ var exp = 0
+ var numstr, frstr: array[0..31, char]
+ var numlen, frbeg, frlen = 0
+
+ if fmt.typ == ftPercent: y *= 100
+
+ case classify(x):
+ of fcNan:
+ numstr[0..2] = ['n', 'a', 'n']
+ numlen = 3
+ of fcInf, fcNegInf:
+ numstr[0..2] = ['f', 'n', 'i']
+ numlen = 3
+ of fcZero, fcNegZero:
+ numstr[0] = '0'
+ numlen = 1
+ else: # a usual fractional number
+ if not (fmt.typ in {ftFix, ftPercent}): # not fixed point
+ exp = int(floor(log10(y)))
+ if fmt.typ == ftGen:
+ if prec == 0: prec = 1
+ if -4 <= exp and exp < prec:
+ prec = prec-1-exp
+ exp = 0
+ else:
+ prec = prec - 1
+ len += 4 # exponent
+ else:
+ len += 4 # exponent
+ # shift y so that 1 <= abs(y) < 2
+ if exp > 0: y /= pow(10.SomeReal, abs(exp).SomeReal)
+ elif exp < 0: y *= pow(10.SomeReal, abs(exp).SomeReal)
+ elif fmt.typ == ftPercent:
+ len += 1 # percent sign
+
+ # handle rounding by adding +0.5 * LSB
+ if prec < len(round_nums): y += round_nums[prec]
+
+ # split into integer and fractional part
+ var mult = 1'i64
+ for i in 1..prec: mult *= 10
+ var num = y.int64
+ var fr = ((y - num.SomeReal) * mult.SomeReal).int64
+ # build integer part string
+ while num != 0:
+ numstr[numlen] = ('0'.int + (num mod 10)).char
+ numlen.inc
+ num = num div 10
+ if numlen == 0:
+ numstr[0] = '0'
+ numlen.inc
+ # build fractional part string
+ while fr != 0:
+ frstr[frlen] = ('0'.int + (fr mod 10)).char
+ frlen.inc
+ fr = fr div 10
+ while frlen < prec:
+ frstr[frlen] = '0'
+ frlen.inc
+ # possible remove trailing 0
+ if fmt.typ == ftGen:
+ while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc
+ # update length of string
+ len += numlen;
+ if frbeg < frlen:
+ len += 1 + frlen - frbeg # decimal point and fractional string
+
+ let alg = getalign(fmt, faRight, len)
+ writefill(o, fmt, alg.left, if positive: 1 else: -1)
+ for i in (numlen-1).countdown(0): write(o, numstr[i])
+ if frbeg < frlen:
+ write(o, '.')
+ for i in (frlen-1).countdown(frbeg): write(o, frstr[i])
+ if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0):
+ write(o, if fmt.upcase: 'E' else: 'e')
+ if exp >= 0:
+ write(o, '+')
+ else:
+ write(o, '-')
+ exp = -exp
+ if exp < 10:
+ write(o, '0')
+ write(o, ('0'.int + exp).char)
+ else:
+ var i=0
+ while exp > 0:
+ numstr[i] = ('0'.int + exp mod 10).char
+ i+=1
+ exp = exp div 10
+ while i>0:
+ i-=1
+ write(o, numstr[i])
+ if fmt.typ == ftPercent: write(o, '%')
+ writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; b: bool; fmt: Format) =
+ ## Write boolean value `b` according to format `fmt` using output
+ ## object `o`. A boolean may be formatted numerically or as string.
+ ## In the former case true is written as 1 and false as 0, in the
+ ## latter the strings "true" and "false" are shown, respectively.
+ ## The default is string format.
+ if fmt.typ in {ftStr, ftDefault}:
+ writeformat(o,
+ if b: "true"
+ else: "false",
+ fmt)
+ elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}:
+ writeformat(o,
+ if b: 1
+ else: 0,
+ fmt)
+ else:
+ raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n")
+
+proc writeformat(o: var Writer; ary: openarray[any]; fmt: Format) =
+ ## Write array `ary` according to format `fmt` using output object
+ ## `o` and output function `add`.
+ if ary.len == 0: return
+
+ var sep: string
+ var nxtfmt = fmt
+ if fmt.arysep == nil:
+ sep = "\t"
+ elif fmt.arysep.len == 0:
+ sep = ""
+ else:
+ let sepch = fmt.arysep[0]
+ let nxt = 1 + skipUntil(fmt.arysep, sepch, 1)
+ if nxt >= 1:
+ nxtfmt.arysep = fmt.arysep.substr(nxt)
+ sep = fmt.arysep.substr(1, nxt-1)
+ else:
+ nxtfmt.arysep = ""
+ sep = fmt.arysep.substr(1)
+ writeformat(o, ary[0], nxtfmt)
+ for i in 1..ary.len-1:
+ for c in sep: write(o, c)
+ writeformat(o, ary[i], nxtfmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} =
+ ## Write `x` formatted with `fmt` to `o`.
+ writeformat(o, x, fmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} =
+ ## The same as `addformat(o, x, parse(fmt))`.
+ addformat(o, x, fmt.parse)
+
+proc addformat(s: var string; x: string) {.inline.} =
+ ## Write `x` to `s`. This is a fast specialized version for
+ ## appending unformatted strings.
+ add(s, x)
+
+proc addformat(f: File; x: string) {.inline.} =
+ ## Write `x` to `f`. This is a fast specialized version for
+ ## writing unformatted strings to a file.
+ write(f, x)
+
+proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} =
+ ## Write `x` to file `f` using format `fmt`.
+ var g = f
+ writeformat(g, x, fmt)
+
+proc addformat[T](f: File; x: T; fmt: string) {.inline.} =
+ ## Write `x` to file `f` using format string `fmt`. This is the same
+ ## as `addformat(f, x, parse(fmt))`
+ addformat(f, x, parse(fmt))
+
+proc addformat(s: Stream; x: string) {.inline.} =
+ ## Write `x` to `s`. This is a fast specialized version for
+ ## writing unformatted strings to a stream.
+ write(s, x)
+
+proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} =
+ ## Write `x` to stream `s` using format `fmt`.
+ var g = s
+ writeformat(g, x, fmt)
+
+proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} =
+ ## Write `x` to stream `s` using format string `fmt`. This is the same
+ ## as `addformat(s, x, parse(fmt))`
+ addformat(s, x, parse(fmt))
+
+proc format[T](x: T; fmt: Format): string =
+ ## Return `x` formatted as a string according to format `fmt`.
+ result = ""
+ addformat(result, x, fmt)
+
+proc format[T](x: T; fmt: string): string =
+ ## Return `x` formatted as a string according to format string `fmt`.
+ result = format(x, fmt.parse)
+
+proc format[T](x: T): string {.inline.} =
+ ## Return `x` formatted as a string according to the default format.
+ ## The default format corresponds to an empty format string.
+ var fmt {.global.} : Format = DefaultFmt
+ result = format(x, fmt)
+
+proc unquoted(s: string): string {.compileTime.} =
+ ## Return `s` {{ and }} by single { and }, respectively.
+ result = ""
+ var pos = 0
+ while pos < s.len:
+ let nxt = pos + skipUntil(s, {'{', '}'})
+ result.add(s.substr(pos, nxt))
+ pos = nxt + 2
+
+proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
+ ## Split format string `s` into a sequence of "parts".
+ ##
+
+ ## Each part is either a literal string or a format specification. A
+ ## format specification is a substring of the form
+ ## "{[arg][:format]}" where `arg` is either empty or a number
+ ## refering to the arg-th argument and an additional field or array
+ ## index. The format string is a string accepted by `parse`.
+ let subpeg = sequence(capture(digits()),
+ capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),
+ capture(?sequence(charSet({'['}), +digits(), charSet({']'}))),
+ capture(?sequence(charSet({':'}), *pegs.any())))
+ result = @[]
+ var pos = 0
+ while true:
+ let oppos = pos + skipUntil(s, {'{', '}'}, pos)
+ # reached the end
+ if oppos >= s.len:
+ if pos < s.len:
+ result.add(Part(kind: pkStr, str: s.substr(pos).unquoted))
+ return
+ # skip double
+ if oppos + 1 < s.len and s[oppos] == s[oppos+1]:
+ result.add(Part(kind: pkStr, str: s.substr(pos, oppos)))
+ pos = oppos + 2
+ continue
+ if s[oppos] == '}':
+ error("Single '}' encountered in format string")
+ if oppos > pos:
+ result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted))
+ # find matching closing }
+ var lvl = 1
+ var nested = false
+ pos = oppos
+ while lvl > 0:
+ pos.inc
+ pos = pos + skipUntil(s, {'{', '}'}, pos)
+ if pos >= s.len:
+ error("Single '{' encountered in format string")
+ if s[pos] == '{':
+ lvl.inc
+ if lvl == 2:
+ nested = true
+ if lvl > 2:
+ error("Too many nested format levels")
+ else:
+ lvl.dec
+ let clpos = pos
+ var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested)
+ if fmtpart.fmt.len > 0:
+ var m: array[0..3, string]
+ if not fmtpart.fmt.match(subpeg, m):
+ error("invalid format string")
+
+ if m[1] != nil and m[1].len > 0:
+ fmtpart.field = m[1].substr(1)
+ if m[2] != nil and m[2].len > 0:
+ discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
+
+ if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
+ if m[3] == nil or m[3].len == 0:
+ fmtpart.fmt = ""
+ elif m[3][0] == ':':
+ fmtpart.fmt = m[3].substr(1)
+ else:
+ fmtpart.fmt = m[3]
+ result.add(fmtpart)
+ pos = clpos + 1
+
+proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
+ ## Return the nim literal of string `s`. This handles the case if
+ ## `s` is nil.
+ result = if s == nil: newNilLit() else: newLit(s)
+
+proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
+ ## Return the nim literal of boolean `b`. This is either `true`
+ ## or `false` symbol.
+ result = if b: "true".ident else: "false".ident
+
+proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} =
+ ## Return the nim literal of value `x`.
+ when type(x) is enum:
+ result = ($x).ident
+ else:
+ result = newLit(x)
+
+proc generatefmt(fmtstr: string;
+ args: var openarray[tuple[arg:NimNode, cnt:int]];
+ arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} =
+ ## fmtstr
+ ## the format string
+ ## args
+ ## array of expressions for the arguments
+ ## arg
+ ## the number of the next argument for automatic parsing
+ ##
+ ## If arg is < 0 then the functions assumes that explicit numbering
+ ## must be used, otherwise automatic numbering is used starting at
+ ## `arg`. The value of arg is updated according to the number of
+ ## arguments being used. If arg == 0 then automatic and manual
+ ## numbering is not decided (because no explicit manual numbering is
+ ## fixed und no automatically numbered argument has been used so
+ ## far).
+ ##
+ ## The function returns a list of pairs `(val, fmt)` where `val` is
+ ## an expression to be formatted and `fmt` is the format string (or
+ ## Format). Therefore, the resulting string can be generated by
+ ## concatenating expressions `val.format(fmt)`. If `fmt` is `nil`
+ ## then `val` is a (literal) string expression.
+ try:
+ result = @[]
+ for part in splitfmt(fmtstr):
+ case part.kind
+ of pkStr: result.add((newLit(part.str), nil))
+ of pkFmt:
+ # first compute the argument expression
+ # start with the correct index
+ var argexpr : NimNode
+ if part.arg >= 0:
+ if arg > 0:
+ error("Cannot switch from automatic field numbering to manual field specification")
+ if part.arg >= args.len:
+ error("Invalid explicit argument index: " & $part.arg)
+ argexpr = args[part.arg].arg
+ args[part.arg].cnt = args[part.arg].cnt + 1
+ arg = -1
+ else:
+ if arg < 0:
+ error("Cannot switch from manual field specification to automatic field numbering")
+ if arg >= args.len:
+ error("Too few arguments for format string")
+ argexpr = args[arg].arg
+ args[arg].cnt = args[arg].cnt + 1
+ arg.inc
+ # possible field access
+ if part.field != nil and part.field.len > 0:
+ argexpr = newDotExpr(argexpr, part.field.ident)
+ # possible array access
+ if part.index < int.high:
+ argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index))
+ # now the expression for the format data
+ var fmtexpr: NimNode
+ if part.nested:
+ # nested format string. Compute the format string by
+ # concatenating the parts of the substring.
+ for e in generatefmt(part.fmt, args, arg):
+ var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt)
+ if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
+ fmtexpr = infix(fmtexpr, "&", newexpr)
+ else:
+ fmtexpr = newexpr
+ else:
+ # literal format string, precompute the format data
+ fmtexpr = newNimNode(nnkPar)
+ for field, val in part.fmt.parse.fieldPairs:
+ fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val)))
+ # add argument
+ result.add((argexpr, fmtexpr))
+ finally:
+ discard
+
+proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} =
+ var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len)
+ result = newNimNode(nnkStmtListExpr)
+ # generate let bindings for arguments
+ for i in 0..args.len-1:
+ let argsym = gensym(nskLet, "arg" & $i)
+ result.add(newLetStmt(argsym, args[i]))
+ argexprs[i].arg = argsym
+ # add result values
+ var arg = 0
+ for e in generatefmt(fmtstr, argexprs, arg):
+ if e.fmt == nil or e.fmt.kind == nnkNilLit:
+ result.add(newCall(bindsym"addformat", retvar, e.val))
+ else:
+ result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt))
+ for i, arg in argexprs:
+ if arg.cnt == 0:
+ warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string")
+
+macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[expr]): expr =
+ ## The same as `s.add(fmtstr.fmt(args...))` but faster.
+ result = addfmtfmt($fmtstr, args, s)
+
+var s: string = ""
+s.addfmt("a:{}", 42)
diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim
new file mode 100644
index 0000000000..39edb500f9
--- /dev/null
+++ b/tests/tuples/tuple_with_seq.nim
@@ -0,0 +1,46 @@
+discard """
+ output: '''it's nil
+@[1, 2, 3]'''
+"""
+
+template foo(s: string = nil) =
+ if isNil(s):
+ echo "it's nil"
+ else:
+ echo s
+
+foo
+
+
+# bug #2632
+
+proc takeTup(x: tuple[s: string;x: seq[int]]) =
+ discard
+
+takeTup(("foo", @[]))
+
+
+#proc foobar(): () =
+
+proc f(xs: seq[int]) =
+ discard
+
+proc g(t: tuple[n:int, xs:seq[int]]) =
+ discard
+
+when isMainModule:
+ f(@[]) # OK
+ g((1,@[1])) # OK
+ g((0,@[])) # NG
+
+
+# bug #2630
+type T = tuple[a: seq[int], b: int]
+
+var t: T = (@[1,2,3], 7)
+
+proc test(s: seq[int]): T =
+ echo s
+ (s, 7)
+
+t = test(t.a)
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
index 2b07ba679a..834f63729f 100644
--- a/tests/types/temptyseqs.nim
+++ b/tests/types/temptyseqs.nim
@@ -1,5 +1,13 @@
discard """
- output: "1"
+ output: '''1
+foo
+bar
+baz
+foo
+bar
+baz
+yes
+no'''
"""
# bug #1708
@@ -24,3 +32,59 @@ when true:
const foo2: seq[string] = @[]
echo foo[0][0][0]
+
+proc takeEmpty(x: openArray[string] = []) = discard
+takeEmpty()
+takeEmpty([])
+
+proc takeEmpty2(x: openArray[string] = @[]) = discard
+takeEmpty2()
+takeEmpty2([])
+takeEmpty2(@[])
+
+#takeEmpty2([nil])
+
+#rawMessage(errExecutionOfProgramFailed, [])
+
+# bug #2470
+const
+ stuff: seq[string] = @[]
+
+for str in stuff:
+ echo "str=", str
+
+# bug #1354
+proc foo4[T](more: seq[T] = @[]) =
+ var more2 = more
+
+foo4[int]()
+
+proc maino: int =
+ var wd: cstring = nil
+ inc result
+
+discard maino()
+
+proc varargso(a: varargs[string]) =
+ for x in a:
+ echo x
+
+varargso(["foo", "bar", "baz"])
+varargso("foo", "bar", "baz")
+
+
+type
+ Flago = enum
+ tfNeedsInit, tfNotNil
+
+var s: set[Flago] = {tfNeedsInit}
+
+if {tfNeedsInit, tfNotNil} * s != {}:
+ echo "yes"
+else:
+ echo "no"
+
+if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}:
+ echo "yes"
+else:
+ echo "no"
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
index 8b7fe4e46c..b9acfa5fbe 100644
--- a/tests/types/tisopr.nim
+++ b/tests/types/tisopr.nim
@@ -1,5 +1,11 @@
discard """
- output: '''true true false yes'''
+ output: '''true true false yes
+false
+false
+false
+true
+true
+no'''
"""
proc IsVoid[T](): string =
@@ -28,7 +34,7 @@ no s.items is iterator: float
yes s.items is iterator: TNumber
no s.items is iterator: object
-type
+type
Iter[T] = iterator: T
yes s.items is Iter[TNumber]
@@ -51,3 +57,34 @@ yes Foo[4, int] is Bar[int]
no Foo[4, int] is Baz[4]
yes Foo[4, float] is Baz[4]
+
+# bug #2505
+
+echo(8'i8 is int32)
+
+# bug #1853
+type SeqOrSet[E] = seq[E] or set[E]
+type SeqOfInt = seq[int]
+type SeqOrSetOfInt = SeqOrSet[int]
+
+# This prints "false", which seems less correct that (1) printing "true" or (2)
+# raising a compiler error.
+echo seq is SeqOrSet
+
+# This prints "false", as expected.
+echo seq is SeqOrSetOfInt
+
+# This prints "true", as expected.
+echo SeqOfInt is SeqOrSet
+
+# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
+echo SeqOfInt is SeqOrSetOfInt
+
+# bug #2522
+proc test[T](x: T) =
+ when T is typedesc:
+ echo "yes"
+ else:
+ echo "no"
+
+test(7)
diff --git a/todo.txt b/todo.txt
index fc62385a8d..4972015a73 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,14 +1,26 @@
-version 0.10.4
+version 0.11.2
==============
-- improve GC-unsafety warnings
-- make 'nil' work for 'add' and 'len'
-- overloading of '='
+- The remaining bugs of the lambda lifting pass that is responsible to enable
+ closures and closure iterators need to be fixed.
+- ``concept`` needs to be refined, a nice name for the feature is not enough.
+- Destructors need to be refined.
+- make '--implicitStatic:on' the default; then we can also clean up the
+ 'static[T]' mess in the compiler!
+
+- Finish the implementation of the 'parallel' statement.
+- Deprecate ``immediate`` for templates and macros
+- special case varargs[untyped] and varargs[typed]
+- make 'nil' work for 'add':
+ - resizeString
+ - incrSeq
+ - addChar
version 1.0
===========
+- macro support for '='; bind '=' to a memory region
- remove echo $foo gotcha
- add "all threads are blocked" detection to 'spawn'
- figure out why C++ bootstrapping is so much slower
@@ -37,8 +49,6 @@ Low priority:
Misc
----
-- make '--implicitStatic:on' the default; then we can also clean up the
- 'static[T]' mess in the compiler!
- make tuple unpacking work in a non-var/let context
- built-in 'getImpl'
- prevent 'alloc(TypeWithGCedMemory)'
@@ -52,6 +62,7 @@ Bugs
- scopes are still broken for generic instantiation!
- blocks can "export" an identifier but the CCG generates {} for them ...
- ConcreteTypes in a 'case' means we don't check for duplicated case branches
+- typedesc matches a generic type T!
version 0.9.x
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index e50b251d37..f0ae45484f 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -35,6 +35,7 @@ type
actionNsis, # action: create NSIS installer
actionScripts # action: create install and deinstall scripts
actionZip, # action: create zip file
+ actionTargz, # action: create targz file
actionDeb # action: prepare deb package
FileCategory = enum
@@ -171,6 +172,7 @@ proc parseCmdLine(c: var ConfigData) =
of "csource": incl(c.actions, actionCSource)
of "scripts": incl(c.actions, actionScripts)
of "zip": incl(c.actions, actionZip)
+ of "targz": incl(c.actions, actionTargz)
of "inno": incl(c.actions, actionInno)
of "nsis": incl(c.actions, actionNsis)
of "deb": incl(c.actions, actionDeb)
@@ -181,10 +183,10 @@ proc parseCmdLine(c: var ConfigData) =
break
of cmdLongoption, cmdShortOption:
case normalize(key.string)
- of "help", "h":
+ of "help", "h":
stdout.write(Usage)
quit(0)
- of "version", "v":
+ of "version", "v":
stdout.write(Version & "\n")
quit(0)
of "o", "output": c.outdir = val
@@ -240,7 +242,7 @@ proc incl(s: var seq[string], x: string): int =
for i in 0.. div.active { visibility:visible; opacity:1; transition-delay:0s; }
#slideshow > div.init { transition-delay:0s; }
- #slideshow-nav { z-index:3; position:absolute; top:110px;; right:-12px; }
- #slideshow-nav > div { margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
+ #slideshow-nav { z-index:3; position:absolute; top:341px; left:18px; }
+ #slideshow-nav > div { display:inline-block; margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
#slideshow-nav > div:hover { background-image:url("images/slideshow-nav_active.png"); opacity:0.5; }
#slideshow-nav > div.active { background-image:url("images/slideshow-nav_active.png"); opacity:1; }
diff --git a/web/documentation.txt b/web/documentation.txt
index dbb737cd9c..67f8b4070b 100644
--- a/web/documentation.txt
+++ b/web/documentation.txt
@@ -8,13 +8,13 @@ Nim's Documentation
.. container:: libraries
- - | `Standard Library `_
+ - | `Standard Library `_
| This document describes Nim's standard library.
- - | `Language Manual `_
+ - | `Language Manual `_
| The Nim manual is a draft that will evolve into a proper specification.
- - | `Compiler User Guide `_
+ - | `Compiler User Guide `_
| The user guide lists command line arguments, special features of the
compiler, etc.
@@ -26,11 +26,11 @@ Nim's Documentation
.. container:: tools
- - | `Source Code Filters `_
+ - | `Source Code Filters `_
| The Nim compiler supports source code filters as a simple yet powerful
builtin templating system.
- - | `Tools Documentation `_
+ - | `Tools Documentation `_
| Description of some tools that come with the standard distribution.
@@ -41,16 +41,17 @@ Nim's Documentation
.. container:: internals
- - | `Garbage Collector `_
+ - | `Garbage Collector `_
| Additional documentation about Nim's GC and how to operate it in a
realtime setting.
- - | `Internal Documentation `_
- | The internal documentation describes how the compiler is implemented. Read
- this if you want to hack the compiler.
+ - | `Internal Documentation `_
+ | The internal documentation describes how the compiler is implemented.
+ Read this if you want to hack the compiler.
Search Options
--------------
-`Documentation Index `_ - The generated index. **Index + (Ctrl+F) == Joy**
+`Documentation Index `_ - The generated
+index. **Index + (Ctrl+F) == Joy**
diff --git a/web/download.txt b/web/download.txt
index 3d47467f23..6acc80b53f 100644
--- a/web/download.txt
+++ b/web/download.txt
@@ -13,8 +13,8 @@ Binaries
--------
Unfortunately for now we only provide builds for Windows.
-* 32 bit: `nim-0.10.2_x32.exe `_
-* 64 bit: `nim-0.10.2_x64.exe `_
+* 32 bit: `nim-0.11.2_x32.exe `_
+* 64 bit: `nim-0.11.2_x64.exe `_
Installation based on generated C code
@@ -24,8 +24,12 @@ This installation method is the preferred way for Linux, Mac OS X, and other Uni
like systems. Binary packages may be provided later.
-Download `nim-0.10.2.zip `_, extract it and follow
-these instructions:
+Download one of these:
+
+* `nim-0.11.2.zip (28 MB) `_
+* `nim-0.11.2.tar.xz (2.6MB) `_
+
+Extract the file and follow these instructions:
* sh build.sh
* Add ``$your_install_dir/bin`` to your PATH.
diff --git a/web/learn.txt b/web/learn.txt
index 7a9600e570..bf0cc43efc 100644
--- a/web/learn.txt
+++ b/web/learn.txt
@@ -8,10 +8,10 @@ Learning Nim
.. container:: tutorials
- - | `Tutorial (part I) `_
+ - | `Tutorial (part I) `_
| Learn the basics of Nim's types, variables, procedures, control flow, etc...
- - | `Tutorial (part II) `_
+ - | `Tutorial (part II) `_
| Learn Nim's more advanced features such as OOP, generics, macros, etc...
@@ -52,5 +52,5 @@ Learning Nim
Documentation
-------------
-More examples of Nim code can be found in the `Nim Language Documentation `_.
+More examples of Nim code can be found in the `Nim Language Documentation `_.
diff --git a/web/news.txt b/web/news.txt
index 0b28c29bf6..9719fb8d7b 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -3,323 +3,423 @@ News
====
..
- 2015-03-01 Version 0.10.4 released
+ 2015-05-05 Version 0.11.2 released
==================================
-
Changes affecting backwards compatibility
-----------------------------------------
- - Parameter names are finally properly ``gensym``'ed. This can break
- templates though that used to rely on the fact that they are not.
- (Bug #1915.) This means this doesn't compile anymore:
-
- .. code-block:: nim
-
- template doIt(body: stmt) {.immediate.} =
- # this used to inject the 'str' parameter:
- proc res(str: string) =
- body
-
- doIt:
- echo str # Error: undeclared identifier: 'str'
-
- Declare the ``doIt`` template as ``immediate, dirty`` to get the old
- behaviour.
- - Tuple field names are not ignored anymore, this caused too many problems
- in practice so now the behaviour as it was for version 0.9.6: If field
- names exist for the tuple type, they are checked.
- - ``logging.level`` and ``logging.handlers`` are no longer exported.
- ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
- should be used instead.
- - ``nim idetools`` has been replaced by a separate tool `nimsuggest`_.
- - *arrow like* operators are not right associative anymore.
- - Typeless parameters are now only allowed in templates and macros. The old
- way turned out to be too error-prone.
- - The 'addr' and 'type' operators are now parsed as unary function
- application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
- and not as ``type((x).name)``. Note that this also affects the AST
- structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
- produced instead of ``nkAddr('x')``.
- - ``concept`` is now a keyword and is used instead of ``generic``.
- - The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
- exceptions. This means code like the following:
-
- .. code-block:: nim
- var x = low(T)
- while x <= high(T):
- echo x
- inc x
-
- Needs to be replaced by something like this:
-
- .. code-block:: nim
- var x = low(T).int
- while x <= high(T).int:
- echo x.T
- inc x
-
- - **Negative indexing for slicing does not work anymore!** Instead
- of ``a[0.. -1]`` you can
- use ``a[0.. ^1]``. This also works with accessing a single
- element ``a[^1]``. Note that we cannot detect this reliably as it is
- determined at **runtime** whether negative indexing is used!
- ``a[0.. -1]`` now produces the empty string/sequence.
- - The compiler now warns about code like ``foo +=1`` which uses inconsistent
- spacing around binary operators. Later versions of the language will parse
- these as unary operators instead so that ``echo $foo`` finally can do what
- people expect it to do.
-
Language Additions
------------------
- - For empty ``case object`` branches ``discard`` can finally be used instead
- of ``nil``.
- - Automatic dereferencing is now done for the first argument of a routine
- call if overloading resolution produces no match otherwise. This feature
- has to be enabled with the `experimental`_ pragma.
- - Objects that do not use inheritance nor ``case`` can be put into ``const``
- sections. This means that finally this is possible and produces rather
- nice code:
-
- .. code-block:: nim
- import tables
-
- const
- foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
-
-
- - Ordinary parameters can follow after a varargs parameter. This means the
- following is finally accepted by the compiler:
-
- .. code-block:: nim
- template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
- blck
- echo a, b
-
- takesBlock 1, 2, "some", 0.90, "random stuff":
- echo "yay"
-
- - Overloading by 'var T' is now finally possible:
-
- .. code-block:: nim
- proc varOrConst(x: var int) = echo "var"
- proc varOrConst(x: int) = echo "const"
-
- var x: int
- varOrConst(x) # "var"
- varOrConst(45) # "const"
-
- - Array and seq indexing can now use the builtin ``^`` operator to access
- things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
-
-
- Library additions
- -----------------
-
- - ``reversed`` proc added to the ``unicode`` module.
- - Added multipart param to httpclient's ``post`` and ``postContent`` together
- with a ``newMultipartData`` proc.
- - Added `%*` operator for JSON.
- - The compiler is now available as Nimble package for c2nim.
-
Bugfixes
--------
- - Fixed internal compiler error when using ``char()`` in an echo call
- (`#1788 `_).
- - Fixed Windows cross-compilation on Linux.
- - Overload resolution now works for types distinguished only by a
- ``static[int]`` param
- (`#1056 `_).
- - Other fixes relating to generic types and static params.
- - Fixed some compiler crashes with unnamed tuples
- (`#1774 `_).
- - Fixed ``channels.tryRecv`` blocking
- (`#1816 `_).
- - Fixed generic instantiation errors with ``typedesc``
- (`#419 `_).
- - Fixed generic regression where the compiler no longer detected constant
- expressions properly (`#544 `_).
- - Fixed internal error with generic proc using ``static[T]`` in a specific
- way (`#1049 `_).
- - More fixes relating to generics
- (`#1820 `_,
- `#1050 `_,
- `#1859 `_,
- `#1858 `_).
- - Fixed httpclient to properly encode queries.
- - Many fixes to the ``uri`` module.
- - Async sockets are now closed on error.
- - Fixes to httpclient's handling of multipart data.
- - Fixed GC segfaults with asynchronous sockets
- (`#1796 `_).
- - Added more versions to openssl's DLL version list
- (`076f993 `_).
- - Fixed shallow copy in iterators being broken
- (`#1803 `_).
- - ``nil`` can now be inserted into tables with the ``db_sqlite`` module
- (`#1866 `_).
- - Fixed "Incorrect assembler generated"
- (`#1907 `_)
- - Fixed "Expression templates that define macros are unusable in some contexts"
- (`#1903 `_)
- - Fixed "a second level generic subclass causes the compiler to crash"
- (`#1919 `_)
- - Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
- (`#1901 `_)
- - Fixed "1 shl n produces wrong C code"
- (`#1928 `_)
- - Fixed "Internal error on tuple yield"
- (`#1838 `_)
- - Fixed "ICE with template"
- (`#1915 `_)
- - Fixed "include the tool directory in the installer as it is required by koch"
- (`#1947 `_)
- - Fixed "Can't compile if file location contains spaces on Windows"
- (`#1955 `_)
- - Fixed "List comprehension macro only supports infix checks as guards"
- (`#1920 `_)
- - Fixed "wrong field names of compatible tuples in generic types"
- (`#1910 `_)
- - Fixed "Macros within templates no longer work as expected"
- (`#1944 `_)
- - Fixed "Compiling for Standalone AVR broken in 0.10.2"
- (`#1964 `_)
- - Fixed "Compiling for Standalone AVR broken in 0.10.2"
- (`#1964 `_)
- - Fixed "Code generation for mitems with tuple elements"
- (`#1833 `_)
- - Fixed "httpclient.HttpMethod should not be an enum"
- (`#1962 `_)
- - Fixed "terminal / eraseScreen() throws an OverflowError"
- (`#1906 `_)
- - Fixed "setControlCHook(nil) disables registered quit procs"
- (`#1546 `_)
- - Fixed "Unexpected idetools behaviour"
- (`#325 `_)
- - Fixed "Unused lifted lambda does not compile"
- (`#1642 `_)
- - Fixed "'low' and 'high' don't work with cstring asguments"
- (`#2030 `_)
- - Fixed "Converting to int does not round in JS backend"
- (`#1959 `_)
- - Fixed "Internal error genRecordField 2 when adding region to pointer."
- (`#2039 `_)
- - Fixed "Macros fail to compile when compiled with --os:standalone"
- (`#2041 `_)
- - Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
- (`#2022 `_)
- - Fixed "Passing overloaded symbols to templates fails inside generic procedures"
- (`#1988 `_)
- - Fixed "Compiling iterator with object assignment in release mode causes "var not init""
- (`#2023 `_)
- - Fixed "calling a large number of macros doing some computation fails"
- (`#1989 `_)
- - Fixed "Can't get Koch to install nim under Windows"
- (`#2061 `_)
- - Fixed "Template with two stmt parameters segfaults compiler"
- (`#2057 `_)
- - Fixed "`noSideEffect` not affected by `echo`"
- (`#2011 `_)
- - Fixed "Compiling with the cpp backend ignores --passc"
- (`#1601 `_)
- - Fixed "Put untyped procedure parameters behind the experimental pragma"
- (`#1956 `_)
- - Fixed "generic regression"
- (`#2073 `_)
- - Fixed "generic regression"
- (`#2073 `_)
- - Fixed "Regression in template lookup with generics"
- (`#2004 `_)
- - Fixed "GC's growObj is wrong for edge cases"
- (`#2070 `_)
- - Fixed "Compiler internal error when creating an array out of a typeclass"
- (`#1131 `_)
- - Fixed "GC's growObj is wrong for edge cases"
- (`#2070 `_)
- - Fixed "Invalid Objective-C code generated when calling class method"
- (`#2068 `_)
- - Fixed "walkDirRec Error"
- (`#2116 `_)
- - Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
- (`#2113 `_)
- - Fixed "Regression on exportc"
- (`#2118 `_)
- - Fixed "Error message"
- (`#2102 `_)
- - Fixed "hint[path] = off not working in nim.cfg"
- (`#2103 `_)
- - Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
- (`#2121 `_)
- - Fixed "nim check hangs with when"
- (`#2123 `_)
- - Fixed "static[T] param in nested type resolve/caching issue"
- (`#2125 `_)
- - Fixed "repr should display ``\0``"
- (`#2124 `_)
- - Fixed "'nim check' never ends in case of recursive dependency "
- (`#2051 `_)
- - Fixed "From macros: Error: unhandled exception: sons is not accessible"
- (`#2167 `_)
- - Fixed "`fieldPairs` doesn't work inside templates"
- (`#1902 `_)
- - Fixed "fields iterator misbehavior on break statement"
- (`#2134 `_)
- - Fixed "Fix for compiler not building anymore since #c3244ef1ff"
- (`#2193 `_)
- - Fixed "JSON parser fails in cpp output mode"
- (`#2199 `_)
- - Fixed "macros.getType mishandles void return"
- (`#2211 `_)
- - Fixed "Regression involving templates instantiated within generics"
- (`#2215 `_)
- - Fixed ""Error: invalid type" for 'not nil' on generic type."
- (`#2216 `_)
- - Fixed "--threads:on breaks async"
- (`#2074 `_)
- - Fixed "Type mismatch not always caught, can generate bad code for C backend."
- (`#2169 `_)
- - Fixed "Failed C compilation when storing proc to own type in object"
- (`#2233 `_)
- - Fixed "Unknown line/column number in constant declaration type conversion error"
- (`#2252 `_)
- - Fixed "Adding {.compile.} fails if nimcache already exists."
- (`#2247 `_)
- - Fixed "Two different type names generated for a single type (C backend)"
- (`#2250 `_)
- - Fixed "Ambigous call when it should not be"
- (`#2229 `_)
- - Fixed "Make sure we can load root urls"
- (`#2227 `_)
- - Fixed "Failure to slice a string with an int subrange type"
- (`#794 `_)
- - Fixed "documentation error"
- (`#2205 `_)
- - Fixed "Code growth when using `const`"
- (`#1940 `_)
- - Fixed "Instances of generic types confuse overload resolution"
- (`#2220 `_)
- - Fixed "Compiler error when initializing sdl2's EventType"
- (`#2316 `_)
- - Fixed "Parallel disjoint checking can't handle `<`, `items`, or arrays"
- (`#2287 `_)
- - Fixed "Strings aren't copied in parallel loop"
- (`#2286 `_)
- - Fixed "JavaScript compiler crash with tables"
- (`#2298 `_)
- - Fixed "Range checker too restrictive"
- (`#1845 `_)
- - Fixed "Failure to slice a string with an int subrange type"
- (`#794 `_)
- - Fixed "Remind user when compiling in debug mode"
- (`#1868 `_)
- - Fixed "Compiler user guide has jumbled options/commands."
- (`#1819 `_)
- - Fixed "using `method`: 1 in a objects constructor fails when compiling"
- (`#1791 `_)
+
+2015-05-04 Version 0.11.2 released
+==================================
+
+This is just a bugfix release that fixes the most pressing regressions we
+introduced with version 0.11.0. The way types are computed was
+changed significantly causing all sort of problems. Sorry for the
+inconvenience; we grew overconfident our large test suite would prevent these
+things.
+
+
+2015-04-30 Version 0.11.0 released
+==================================
+
+With this release we are one step closer to reaching version 1.0 and by
+extension the persistence of the Nim specification. As mentioned in the
+previous release notes, starting with version 1.0, we will not be introducing
+any more breaking changes to Nim.
+
+The *language* itself is very close to 1.0, the primary area that requires
+more work is the standard library.
+
+Take a look at the `download `_ page for binaries (Windows-only)
+and 0.11.0 snapshots of the source code. The Windows installer now also
+includes `Aporia `_,
+`Nimble `_ and other useful tools to get
+you started with Nim.
+
+What's left to be done
+~~~~~~~~~~~~~~~~~~~~~~
+
+The 1.0 release is expected by the end of this year. Rumors say it will be in
+summer 2015. What's left:
+
+* Bug fixes, bug fixes, bug fixes, in particular:
+ - The remaining bugs of the lambda lifting pass that is responsible to enable
+ closures and closure iterators need to be fixed.
+ - ``concept`` needs to be refined, a nice name for the feature is not enough.
+ - Destructors need to be refined.
+ - ``static[T]`` needs to be fixed.
+ - Finish the implementation of the 'parallel' statement.
+* ``immediate`` templates and macros will be deprecated as these will soon be
+ completely unnecessary, instead the ``typed`` or ``untyped`` metatypes can
+ be used.
+* More of the standard library should be moved to Nimble packages and what's
+ left should use the features we have for concurrency and parallelism.
+
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Parameter names are finally properly ``gensym``'ed. This can break
+ templates though that used to rely on the fact that they are not.
+ (Bug #1915.) This means this doesn't compile anymore:
+
+.. code-block:: nim
+
+ template doIt(body: stmt) {.immediate.} =
+ # this used to inject the 'str' parameter:
+ proc res(str: string) =
+ body
+
+ doIt:
+ echo str # Error: undeclared identifier: 'str'
+..
+
+ This used to inject the ``str`` parameter into the scope of the body.
+ Declare the ``doIt`` template as ``immediate, dirty`` to get the old
+ behaviour.
+- Tuple field names are not ignored anymore, this caused too many problems
+ in practice so now the behaviour is as it was for version 0.9.6: If field
+ names exist for the tuple type, they are checked.
+- ``logging.level`` and ``logging.handlers`` are no longer exported.
+ ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
+ should be used instead.
+- ``nim idetools`` has been replaced by a separate
+ tool `nimsuggest <0.11.0/nimsuggest.html>`_.
+- *arrow like* operators are not right associative anymore and are required
+ to end with either ``->``, ``~>`` or
+ ``=>``, not just ``>``. Examples of operators still considered arrow like:
+ ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now
+ considered regular operators again: ``|>``, ``-+>``, etc.
+- Typeless parameters are now only allowed in templates and macros. The old
+ way turned out to be too error-prone.
+- The 'addr' and 'type' operators are now parsed as unary function
+ application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
+ and not as ``type((x).name)``. Note that this also affects the AST
+ structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
+ produced instead of ``nkAddr('x')``.
+- ``concept`` is now a keyword and is used instead of ``generic``.
+- The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
+ exceptions. This means code like the following:
+
+.. code-block:: nim
+ var x = low(T)
+ while x <= high(T):
+ echo x
+ inc x
+
+Needs to be replaced by something like this:
+
+.. code-block:: nim
+ var x = low(T).int
+ while x <= high(T).int:
+ echo x.T
+ inc x
+
+- **Negative indexing for slicing does not work anymore!** Instead
+ of ``a[0.. -1]`` you can
+ use ``a[0.. ^1]``. This also works with accessing a single
+ element ``a[^1]``. Note that we cannot detect this reliably as it is
+ determined at **runtime** whether negative indexing is used!
+ ``a[0.. -1]`` now produces the empty string/sequence.
+- The compiler now warns about code like ``foo +=1`` which uses inconsistent
+ spacing around binary operators. Later versions of the language will parse
+ these as unary operators instead so that ``echo $foo`` finally can do what
+ people expect it to do.
+- ``system.untyped`` and ``system.typed`` have been introduced as aliases
+ for ``expr`` and ``stmt``. The new names capture the semantics much better
+ and most likely ``expr`` and ``stmt`` will be deprecated in favor of the
+ new names.
+- The ``split`` method in module ``re`` has changed. It now handles the case
+ of matches having a length of 0, and empty strings being yielded from the
+ iterator. A notable change might be that a pattern being matched at the
+ beginning and end of a string, will result in an empty string being produced
+ at the start and the end of the iterator.
+- The compiler and nimsuggest now count columns starting with 1, not 0 for
+ consistency with the rest of the world.
+
+
+Language Additions
+------------------
+
+- For empty ``case object`` branches ``discard`` can finally be used instead
+ of ``nil``.
+- Automatic dereferencing is now done for the first argument of a routine
+ call if overloading resolution produces no match otherwise. This feature
+ has to be enabled with
+ the `experimental <0.11.0/manual.html#pragmas-experimental-pragma>`_ pragma.
+- Objects that do not use inheritance nor ``case`` can be put into ``const``
+ sections. This means that finally this is possible and produces rather
+ nice code:
+
+.. code-block:: nim
+ import tables
+
+ const
+ foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+
+- Ordinary parameters can follow after a varargs parameter. This means the
+ following is finally accepted by the compiler:
+
+.. code-block:: nim
+ template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+ blck
+ echo a, b
+
+ takesBlock 1, 2, "some", 0.90, "random stuff":
+ echo "yay"
+
+- Overloading by 'var T' is now finally possible:
+
+.. code-block:: nim
+ proc varOrConst(x: var int) = echo "var"
+ proc varOrConst(x: int) = echo "const"
+
+ var x: int
+ varOrConst(x) # "var"
+ varOrConst(45) # "const"
+
+- Array and seq indexing can now use the builtin ``^`` operator to access
+ things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
+- A first version of the specification and implementation of the overloading
+ of the assignment operator has arrived!
+- ``system.len`` for strings and sequences now returns 0 for nil.
+
+- A single underscore can now be used to discard values when unpacking tuples:
+
+.. code-block:: nim
+ let (path, _, _) = os.splitFile("path/file.ext")
+
+
+- ``marshal.$$`` and ``marshal.to`` can be executed at compile-time.
+- Interoperability with C++ improved tremendously; C++'s templates and
+ operators can be wrapped directly. See
+ `this <0.11.0/nimc.html#additional-features-importcpp-pragma>`_
+ for more information.
+- ``macros.getType`` can be used to query an AST's type at compile-time. This
+ enables more powerful macros, for instance *currying* can now be done with
+ a macro.
+
+
+Library additions
+-----------------
+
+- ``reversed`` proc added to the ``unicode`` module.
+- Added multipart param to httpclient's ``post`` and ``postContent`` together
+ with a ``newMultipartData`` proc.
+- Added `%*` operator for JSON.
+- The compiler is now available as Nimble package for c2nim.
+- Added ``..^`` and ``..<`` templates to system so that the rather annoying
+ space between ``.. <`` and ``.. ^`` is not necessary anymore.
+- Added ``system.xlen`` for strings and sequences to get back the old ``len``
+ operation that doesn't check for ``nil`` for efficiency.
+
+
+Bugfixes
+--------
+
+- Fixed internal compiler error when using ``char()`` in an echo call
+ (`#1788 `_).
+- Fixed Windows cross-compilation on Linux.
+- Overload resolution now works for types distinguished only by a
+ ``static[int]`` param
+ (`#1056 `_).
+- Other fixes relating to generic types and static params.
+- Fixed some compiler crashes with unnamed tuples
+ (`#1774 `_).
+- Fixed ``channels.tryRecv`` blocking
+ (`#1816 `_).
+- Fixed generic instantiation errors with ``typedesc``
+ (`#419 `_).
+- Fixed generic regression where the compiler no longer detected constant
+ expressions properly (`#544 `_).
+- Fixed internal error with generic proc using ``static[T]`` in a specific
+ way (`#1049 `_).
+- More fixes relating to generics (`#1820 `_,
+ `#1050 `_,
+ `#1859 `_,
+ `#1858 `_).
+- Fixed httpclient to properly encode queries.
+- Many fixes to the ``uri`` module.
+- Async sockets are now closed on error.
+- Fixes to httpclient's handling of multipart data.
+- Fixed GC segfaults with asynchronous sockets
+ (`#1796 `_).
+- Added more versions to openssl's DLL version list
+ (`076f993 `_).
+- Fixed shallow copy in iterators being broken
+ (`#1803 `_).
+- ``nil`` can now be inserted into tables with the ``db_sqlite`` module
+ (`#1866 `_).
+- Fixed "Incorrect assembler generated"
+ (`#1907 `_)
+- Fixed "Expression templates that define macros are unusable in some contexts"
+ (`#1903 `_)
+- Fixed "a second level generic subclass causes the compiler to crash"
+ (`#1919 `_)
+- Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
+ (`#1901 `_)
+- Fixed "1 shl n produces wrong C code"
+ (`#1928 `_)
+- Fixed "Internal error on tuple yield"
+ (`#1838 `_)
+- Fixed "ICE with template"
+ (`#1915 `_)
+- Fixed "include the tool directory in the installer as it is required by koch"
+ (`#1947 `_)
+- Fixed "Can't compile if file location contains spaces on Windows"
+ (`#1955 `_)
+- Fixed "List comprehension macro only supports infix checks as guards"
+ (`#1920 `_)
+- Fixed "wrong field names of compatible tuples in generic types"
+ (`#1910 `_)
+- Fixed "Macros within templates no longer work as expected"
+ (`#1944 `_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+ (`#1964 `_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+ (`#1964 `_)
+- Fixed "Code generation for mitems with tuple elements"
+ (`#1833 `_)
+- Fixed "httpclient.HttpMethod should not be an enum"
+ (`#1962 `_)
+- Fixed "terminal / eraseScreen() throws an OverflowError"
+ (`#1906 `_)
+- Fixed "setControlCHook(nil) disables registered quit procs"
+ (`#1546 `_)
+- Fixed "Unexpected idetools behaviour"
+ (`#325 `_)
+- Fixed "Unused lifted lambda does not compile"
+ (`#1642 `_)
+- Fixed "'low' and 'high' don't work with cstring asguments"
+ (`#2030 `_)
+- Fixed "Converting to int does not round in JS backend"
+ (`#1959 `_)
+- Fixed "Internal error genRecordField 2 when adding region to pointer."
+ (`#2039 `_)
+- Fixed "Macros fail to compile when compiled with --os:standalone"
+ (`#2041 `_)
+- Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
+ (`#2022 `_)
+- Fixed "Passing overloaded symbols to templates fails inside generic procedures"
+ (`#1988 `_)
+- Fixed "Compiling iterator with object assignment in release mode causes "var not init""
+ (`#2023 `_)
+- Fixed "calling a large number of macros doing some computation fails"
+ (`#1989 `_)
+- Fixed "Can't get Koch to install nim under Windows"
+ (`#2061 `_)
+- Fixed "Template with two stmt parameters segfaults compiler"
+ (`#2057 `_)
+- Fixed "`noSideEffect` not affected by `echo`"
+ (`#2011 `_)
+- Fixed "Compiling with the cpp backend ignores --passc"
+ (`#1601 `_)
+- Fixed "Put untyped procedure parameters behind the experimental pragma"
+ (`#1956 `_)
+- Fixed "generic regression"
+ (`#2073 `_)
+- Fixed "generic regression"
+ (`#2073 `_)
+- Fixed "Regression in template lookup with generics"
+ (`#2004 `_)
+- Fixed "GC's growObj is wrong for edge cases"
+ (`#2070 `_)
+- Fixed "Compiler internal error when creating an array out of a typeclass"
+ (`#1131 `_)
+- Fixed "GC's growObj is wrong for edge cases"
+ (`#2070 `_)
+- Fixed "Invalid Objective-C code generated when calling class method"
+ (`#2068 `_)
+- Fixed "walkDirRec Error"
+ (`#2116 `_)
+- Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
+ (`#2113 `_)
+- Fixed "Regression on exportc"
+ (`#2118 `_)
+- Fixed "Error message"
+ (`#2102 `_)
+- Fixed "hint[path] = off not working in nim.cfg"
+ (`#2103 `_)
+- Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
+ (`#2121 `_)
+- Fixed "nim check hangs with when"
+ (`#2123 `_)
+- Fixed "static[T] param in nested type resolve/caching issue"
+ (`#2125 `_)
+- Fixed "repr should display ``\0``"
+ (`#2124 `_)
+- Fixed "'nim check' never ends in case of recursive dependency "
+ (`#2051