Merge branch 'devel' into experimentalize-reorder

This commit is contained in:
awr1 2018-09-04 16:33:52 -05:00 • committed by GitHub
commit eb668003bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
241 changed files with 6388 additions and 12619 deletions

6
.gitignore vendored
View file

@ -48,7 +48,10 @@ xcuserdata/
/compiler/nimrod.dot /compiler/nimrod.dot
/reject.json /reject.json
/run.json /run.json
/testresults.html # for `nim doc foo.nim`
/*.html
#/testresults.html #covered by /*.html
/testresults.json /testresults.json
testament.db testament.db
/csources /csources
@ -62,3 +65,4 @@ dist/
testresults/ testresults/
test.txt test.txt
/test.ini /test.ini

View file

@ -50,4 +50,4 @@ script:
- ./koch web - ./koch web
- ./koch csource - ./koch csource
- ./koch nimsuggest - ./koch nimsuggest
# - nim c -r nimsuggest/tester - nim c -r nimsuggest/tester

View file

@ -72,6 +72,7 @@
- ``lineInfoObj`` now returns absolute path instead of project path. - ``lineInfoObj`` now returns absolute path instead of project path.
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc. It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
- ``net.sendTo`` no longer returns an int and now raises an ``OSError``.
- `threadpool`'s `await` and derivatives have been renamed to `blockUntil` - `threadpool`'s `await` and derivatives have been renamed to `blockUntil`
to avoid confusions with `await` from the `async` macro. to avoid confusions with `await` from the `async` macro.
@ -107,6 +108,7 @@
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``. - ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``.
- Added the proc ``flush`` for memory mapped files. - Added the proc ``flush`` for memory mapped files.
- Added the ``MemMapFileStream``. - Added the ``MemMapFileStream``.
- Added a simple interpreting event parser template ``eventParser`` to the ``pegs`` module.
- Added ``macros.copyLineInfo`` to copy lineInfo from other node. - Added ``macros.copyLineInfo`` to copy lineInfo from other node.
- Added ``system.ashr`` an arithmetic right shift for integers. - Added ``system.ashr`` an arithmetic right shift for integers.
@ -139,6 +141,8 @@
- The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal`` - The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal``
object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs`` object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs``
iterators. iterators.
- The ``accept`` socket procedure defined in the ``net`` module can now accept
a nil socket.
### Language additions ### Language additions

View file

@ -628,6 +628,7 @@ type
mIsPartOf, mAstToStr, mParallel, mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mNewStringOfCap, mParseBiggestFloat, mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved,
mReset, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@ -656,7 +657,7 @@ type
mNHint, mNWarning, mNError, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mInstantiationInfo, mGetTypeInfo,
mNimvm, mIntDefine, mStrDefine, mRunnableExamples, mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
mException, mBuiltinType mException, mBuiltinType, mSymOwner
# things that we can evaluate safely at compile time, even if not asked for it: # things that we can evaluate safely at compile time, even if not asked for it:
const const
@ -1020,13 +1021,16 @@ proc isCallExpr*(n: PNode): bool =
proc discardSons*(father: PNode) proc discardSons*(father: PNode)
proc len*(n: PNode): int {.inline.} = proc len*(n: PNode): int {.inline.} =
when defined(nimNoNilSeqs):
result = len(n.sons)
else:
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc safeLen*(n: PNode): int {.inline.} = proc safeLen*(n: PNode): int {.inline.} =
## works even for leaves. ## works even for leaves.
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0 if n.kind in {nkNone..nkNilLit}: result = 0
else: result = len(n.sons) else: result = len(n)
proc safeArrLen*(n: PNode): int {.inline.} = proc safeArrLen*(n: PNode): int {.inline.} =
## works for array-like objects (strings passed as openArray in VM). ## works for array-like objects (strings passed as openArray in VM).
@ -1036,6 +1040,7 @@ proc safeArrLen*(n: PNode): int {.inline.} =
proc add*(father, son: PNode) = proc add*(father, son: PNode) =
assert son != nil assert son != nil
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
@ -1088,9 +1093,9 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
result.id = getID() result.id = getID()
when debugIds: when debugIds:
registerId(result) registerId(result)
#if result.id == 93289: #if result.id == 77131:
# writeStacktrace() # writeStacktrace()
# MessageOut(name.s & " has id: " & toString(result.id)) # echo name.s
proc isMetaType*(t: PType): bool = proc isMetaType*(t: PType): bool =
return t.kind in tyMetaTypes or return t.kind in tyMetaTypes or
@ -1134,19 +1139,16 @@ const # for all kind of hash tables:
proc copyStrTable*(dest: var TStrTable, src: TStrTable) = proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyIdTable*(dest: var TIdTable, src: TIdTable) = proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return
newSeq(dest.data, len(src.data)) newSeq(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
@ -1243,6 +1245,7 @@ proc newStrNode*(strVal: string; info: TLineInfo): PNode =
proc addSon*(father, son: PNode) = proc addSon*(father, son: PNode) =
assert son != nil assert son != nil
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
@ -1268,14 +1271,14 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
new(result) new(result)
result.kind = kind result.kind = kind
result.owner = owner result.owner = owner
result.size = - 1 result.size = -1
result.align = 2 # default alignment result.align = 2 # default alignment
result.id = getID() result.id = getID()
result.lockLevel = UnspecifiedLockLevel result.lockLevel = UnspecifiedLockLevel
when debugIds: when debugIds:
registerId(result) registerId(result)
when false: when false:
if result.id == 205734: if result.id == 76426:
echo "KNID ", kind echo "KNID ", kind
writeStackTrace() writeStackTrace()
@ -1287,12 +1290,18 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
if a.r == nil: a.r = b.r if a.r == nil: a.r = b.r
proc newSons*(father: PNode, length: int) = proc newSons*(father: PNode, length: int) =
when defined(nimNoNilSeqs):
setLen(father.sons, length)
else:
if isNil(father.sons): if isNil(father.sons):
newSeq(father.sons, length) newSeq(father.sons, length)
else: else:
setLen(father.sons, length) setLen(father.sons, length)
proc newSons*(father: PType, length: int) = proc newSons*(father: PType, length: int) =
when defined(nimNoNilSeqs):
setLen(father.sons, length)
else:
if isNil(father.sons): if isNil(father.sons):
newSeq(father.sons, length) newSeq(father.sons, length)
else: else:
@ -1464,19 +1473,25 @@ proc propagateToOwner*(owner, elem: PType) =
owner.flags.incl tfHasGCedMem owner.flags.incl tfHasGCedMem
proc rawAddSon*(father, son: PType) = proc rawAddSon*(father, son: PType) =
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
if not son.isNil: propagateToOwner(father, son) if not son.isNil: propagateToOwner(father, son)
proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) = proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) =
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
proc addSonNilAllowed*(father, son: PNode) = proc addSonNilAllowed*(father, son: PNode) =
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
proc delSon*(father: PNode, idx: int) = proc delSon*(father: PNode, idx: int) =
when defined(nimNoNilSeqs):
if father.len == 0: return
else:
if isNil(father.sons): return if isNil(father.sons): return
var length = sonsLen(father) var length = sonsLen(father)
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1] for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
@ -1579,15 +1594,17 @@ proc getInt*(a: PNode): BiggestInt =
case a.kind case a.kind
of nkCharLit..nkUInt64Lit: result = a.intVal of nkCharLit..nkUInt64Lit: result = a.intVal
else: else:
raiseRecoverableError("cannot extract number from invalid AST node")
#internalError(a.info, "getInt") #internalError(a.info, "getInt")
doAssert false, "getInt" #doAssert false, "getInt"
#result = 0 #result = 0
proc getFloat*(a: PNode): BiggestFloat = proc getFloat*(a: PNode): BiggestFloat =
case a.kind case a.kind
of nkFloatLiterals: result = a.floatVal of nkFloatLiterals: result = a.floatVal
else: else:
doAssert false, "getFloat" raiseRecoverableError("cannot extract number from invalid AST node")
#doAssert false, "getFloat"
#internalError(a.info, "getFloat") #internalError(a.info, "getFloat")
#result = 0.0 #result = 0.0
@ -1601,7 +1618,8 @@ proc getStr*(a: PNode): string =
else: else:
result = nil result = nil
else: else:
doAssert false, "getStr" raiseRecoverableError("cannot extract string from invalid AST node")
#doAssert false, "getStr"
#internalError(a.info, "getStr") #internalError(a.info, "getStr")
#result = "" #result = ""
@ -1610,7 +1628,8 @@ proc getStrOrChar*(a: PNode): string =
of nkStrLit..nkTripleStrLit: result = a.strVal of nkStrLit..nkTripleStrLit: result = a.strVal
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal)) of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
else: else:
doAssert false, "getStrOrChar" raiseRecoverableError("cannot extract string from invalid AST node")
#doAssert false, "getStrOrChar"
#internalError(a.info, "getStrOrChar") #internalError(a.info, "getStrOrChar")
#result = "" #result = ""

View file

@ -206,7 +206,7 @@ proc makeYamlString*(s: string): Rope =
const MaxLineLength = 64 const MaxLineLength = 64
result = nil result = nil
var res = "\"" var res = "\""
for i in countup(0, if s.isNil: -1 else: (len(s)-1)): for i in 0 ..< s.len:
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
add(res, '\"') add(res, '\"')
add(res, "\n") add(res, "\n")
@ -314,9 +314,6 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
addf(result, ",$N$1\"floatVal\": $2", addf(result, ",$N$1\"floatVal\": $2",
[istr, rope(n.floatVal.toStrMaxPrecision)]) [istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil:
addf(result, ",$N$1\"strVal\": null", [istr])
else:
addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
addf(result, ",$N$1\"sym\": $2", addf(result, ",$N$1\"sym\": $2",
@ -395,9 +392,6 @@ proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
addf(result, ",$N$1\"floatVal\": $2", addf(result, ",$N$1\"floatVal\": $2",
[istr, rope(n.floatVal.toStrMaxPrecision)]) [istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil:
addf(result, ",$N$1\"strVal\": null", [istr])
else:
addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
addf(result, ",$N$1\"sym\": $2_$3", addf(result, ",$N$1\"sym\": $2_$3",
@ -759,10 +753,6 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil else: result = nil
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: Hash var h: Hash
h = key.id and high(data) h = key.id and high(data)
@ -789,10 +779,6 @@ proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
idNodeTableRawInsert(t.data, key, val) idNodeTableRawInsert(t.data, key, val)
inc(t.counter) inc(t.counter)
proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
if isNil(t.data): initIdNodeTable(t)
idNodeTablePut(t, key, val)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] = iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data): for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)

View file

@ -124,15 +124,19 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
of tyString, tySequence: of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar and if skipTypes(n.typ, abstractInst).kind == tyVar and
not compileToCpp(p.module): not compileToCpp(p.module):
result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
else: else:
result = "$1$3, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef: of tyPtr, tyRef:
case lastSon(a.t).kind case lastSon(a.t).kind
of tyString, tySequence: of tyString, tySequence:
result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
of tyArray: of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
else: else:

View file

@ -65,13 +65,13 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of tyString: of tyString:
# with the new semantics for 'nil' strings, we can map "" to nil and # with the new semantics for 'nil' strings, we can map "" to nil and
# save tons of allocations: # save tons of allocations:
if n.strVal.len == 0 and optNilSeqs notin p.options: if n.strVal.len == 0 and optNilSeqs notin p.options and
p.config.selectedGc != gcDestructors:
result = genNilStringLiteral(p.module, n.info) result = genNilStringLiteral(p.module, n.info)
else: else:
result = genStringLiteral(p.module, n) result = genStringLiteral(p.module, n)
else: else:
if n.strVal.isNil: result = rope("NIM_NIL") result = makeCString(n.strVal)
else: result = makeCString(n.strVal)
of nkFloatLit, nkFloat64Lit: of nkFloatLit, nkFloat64Lit:
result = rope(n.floatVal.toStrMaxPrecision) result = rope(n.floatVal.toStrMaxPrecision)
of nkFloat32Lit: of nkFloat32Lit:
@ -165,7 +165,7 @@ proc canMove(n: PNode): bool =
# result = false # result = false
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.storage == OnStack or not usesNativeGC(p.config): if dest.storage == OnStack or not usesWriteBarrier(p.config):
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
elif dest.storage == OnHeap: elif dest.storage == OnHeap:
# location is on heap # location is on heap
@ -255,9 +255,13 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# tfShallow flag for the built-in string type too! So we check only # tfShallow flag for the built-in string type too! So we check only
# here for this flag, where it is reasonably safe to do so # here for this flag, where it is reasonably safe to do so
# (for objects, etc.): # (for objects, etc.):
if needToCopy notin flags or if p.config.selectedGC == gcDestructors:
linefmt(p, cpsStmts,
"$1.len = $2.len; $1.p = $2.p;$n",
rdLoc(dest), rdLoc(src))
elif needToCopy notin flags or
tfShallow in skipTypes(dest.t, abstractVarRange).flags: tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if dest.storage == OnStack or not usesNativeGC(p.config): if dest.storage == OnStack or not usesWriteBarrier(p.config):
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)) addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest))
@ -280,17 +284,21 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyRef: of tyRef:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
of tySequence: of tySequence:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): if p.config.selectedGC == gcDestructors:
genGenericAsgn(p, dest, src, flags)
elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
addrLoc(p.config, dest), rdLoc(src), addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)) genTypeInfo(p.module, dest.t, dest.lode.info))
of tyString: of tyString:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): if p.config.selectedGC == gcDestructors:
genGenericAsgn(p, dest, src, flags)
elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
if dest.storage == OnStack or not usesNativeGC(p.config): if dest.storage == OnStack or not usesWriteBarrier(p.config):
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
elif dest.storage == OnHeap: elif dest.storage == OnHeap:
# we use a temporary to care for the dreaded self assignment: # we use a temporary to care for the dreaded self assignment:
@ -453,6 +461,13 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b)) lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr")
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, frmt, addrLoc(p.config, a), rdLoc(b))
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc var a: TLoc
if d.k != locNone: internalError(p.config, e.info, "unaryStmt") if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
@ -889,8 +904,8 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
of tySequence, tyString: of tySequence, tyString:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " & "if ($2-$1 != -1 && " &
"(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n", "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)) #raiseIndexError();$n",
rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p)) rdLoc(a), rdLoc(b), lenExpr(p, arr))
else: discard else: discard
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
@ -914,12 +929,12 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", "if ((NU)($1) > (NU)$2) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField(p)) rdLoc(b), lenExpr(p, a))
else: else:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", "if ((NU)($1) >= (NU)$2) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField(p)) rdLoc(b), lenExpr(p, a))
if d.k == locNone: d.storage = OnHeap if d.k == locNone: d.storage = OnHeap
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
a.r = ropecg(p.module, "(*$1)", a.r) a.r = ropecg(p.module, "(*$1)", a.r)
@ -1010,6 +1025,12 @@ proc genEcho(p: BProc, n: PNode) =
proc gcUsage(conf: ConfigRef; n: PNode) = proc gcUsage(conf: ConfigRef; n: PNode) =
if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
proc strLoc(p: BProc; d: TLoc): Rope =
if p.config.selectedGc == gcDestructors:
result = addrLoc(p.config, d)
else:
result = rdLoc(d)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nim code> # <Nim code>
# s = 'Hello ' & name & ', how do you feel?' & 'z' # s = 'Hello ' & name & ', how do you feel?' & 'z'
@ -1037,13 +1058,14 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 1], a) initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L) inc(L)
add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a))) add(appends, ropecg(p.module, "#appendChar($1, $2);$n", strLoc(p, tmp), rdLoc(a)))
else: else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal)) inc(L, len(e.sons[i + 1].strVal))
else: else:
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(lens, lenExpr(p, a))
add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) add(lens, " + ")
add(appends, ropecg(p.module, "#appendString($1, $2);$n", strLoc(p, tmp), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L)) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
add(p.s(cpsStmts), appends) add(p.s(cpsStmts), appends)
if d.k == locNone: if d.k == locNone:
@ -1076,19 +1098,24 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L) inc(L)
add(appends, ropecg(p.module, "#appendChar($1, $2);$n", add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
rdLoc(dest), rdLoc(a))) strLoc(p, dest), rdLoc(a)))
else: else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal)) inc(L, len(e.sons[i + 2].strVal))
else: else:
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(lens, lenExpr(p, a))
add(lens, " + ")
add(appends, ropecg(p.module, "#appendString($1, $2);$n", add(appends, ropecg(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a))) strLoc(p, dest), rdLoc(a)))
if p.config.selectedGC == gcDestructors:
linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n",
addrLoc(p.config, dest), lens, rope(L))
else:
initLoc(call, locCall, e, OnHeap) initLoc(call, locCall, e, OnHeap)
call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
genAssignment(p, dest, call, {}) genAssignment(p, dest, call, {})
add(p.s(cpsStmts), appends)
gcUsage(p.config, e) gcUsage(p.config, e)
add(p.s(cpsStmts), appends)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x --> # seq &= x -->
@ -1151,7 +1178,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
addf(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)])
let args = [getTypeDesc(p.module, typ), ti, sizeExpr] let args = [getTypeDesc(p.module, typ), ti, sizeExpr]
if a.storage == OnHeap and usesNativeGC(p.config): if a.storage == OnHeap and usesWriteBarrier(p.config):
# use newObjRC1 as an optimization # use newObjRC1 as an optimization
if canFormAcycle(a.t): if canFormAcycle(a.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc) linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
@ -1182,7 +1209,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
genTypeInfo(p.module, seqtype, dest.lode.info), length] genTypeInfo(p.module, seqtype, dest.lode.info), length]
var call: TLoc var call: TLoc
initLoc(call, locExpr, dest.lode, OnHeap) initLoc(call, locExpr, dest.lode, OnHeap)
if dest.storage == OnHeap and usesNativeGC(p.config): if dest.storage == OnHeap and usesWriteBarrier(p.config):
if canFormAcycle(dest.t): if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
else: else:
@ -1201,6 +1228,12 @@ proc genNewSeq(p: BProc, e: PNode) =
var a, b: TLoc var a, b: TLoc
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if p.config.selectedGC == gcDestructors:
let seqtype = skipTypes(e.sons[1].typ, abstractVarRange)
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype))
else:
let lenIsZero = optNilSeqs notin p.options and let lenIsZero = optNilSeqs notin p.options and
e[2].kind == nkIntLit and e[2].intVal == 0 e[2].kind == nkIntLit and e[2].intVal == 0
genNewSeqAux(p, a, b.rdLoc, lenIsZero) genNewSeqAux(p, a, b.rdLoc, lenIsZero)
@ -1448,7 +1481,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage) putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
of tyString, tySequence: of tyString, tySequence:
putIntoDest(p, b, e, putIntoDest(p, b, e,
"$1$3, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p), dataField(p)], a.storage) "$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage)
of tyArray: of tyArray:
putIntoDest(p, b, e, putIntoDest(p, b, e,
"$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage) "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
@ -1492,28 +1525,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
of tyString: of tyString:
if not p.module.compileToCpp: var a: TLoc
if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)") initLocExpr(p, e.sons[1], a)
else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)") var x = lenExpr(p, a)
else: if op == mHigh: x = "($1-1)" % [x]
if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)") putIntoDest(p, d, e, x)
else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
of tySequence: of tySequence:
# we go through a temporary here because people write bullshit code.
var a, tmp: TLoc var a, tmp: TLoc
initLocExpr(p, e[1], a) initLocExpr(p, e[1], a)
getIntTemp(p, tmp) getIntTemp(p, tmp)
var frmt: FormatStr var x = lenExpr(p, a)
if not p.module.compileToCpp: if op == mHigh: x = "($1-1)" % [x]
if op == mHigh: lineCg(p, cpsStmts, "$1 = $2;$n", tmp.r, x)
frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n"
else:
frmt = "$1 = ($2 ? $2->Sup.len : 0);$n"
else:
if op == mHigh:
frmt = "$1 = ($2 ? ($2->len-1) : -1);$n"
else:
frmt = "$1 = ($2 ? $2->len : 0);$n"
lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
putIntoDest(p, d, e, tmp.r) putIntoDest(p, d, e, tmp.r)
of tyArray: of tyArray:
# YYY: length(sideeffect) is optimized away incorrectly? # YYY: length(sideeffect) is optimized away incorrectly?
@ -1522,6 +1546,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: internalError(p.config, e.info, "genArrayLen()") else: internalError(p.config, e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
if p.config.selectedGc == gcDestructors:
genCall(p, e, d)
return
var a, b, call: TLoc var a, b, call: TLoc
assert(d.k == locNone) assert(d.k == locNone)
var x = e.sons[1] var x = e.sons[1]
@ -1542,6 +1569,9 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
gcUsage(p.config, e) gcUsage(p.config, e)
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
if p.config.selectedGc == gcDestructors:
binaryStmtAddr(p, e, d, "#setLengthStrV2($1, $2);$n")
else:
var a, b, call: TLoc var a, b, call: TLoc
if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr")
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
@ -1803,11 +1833,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
initLocExpr(p, e.sons[2], x) initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) ropecg(p.module, "($1 == 0)", lenExpr(p, x)))
elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
initLocExpr(p, e.sons[1], x) initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) ropecg(p.module, "($1 == 0)", lenExpr(p, x)))
else: else:
binaryExpr(p, e, d, "#eqStrings($1, $2)") binaryExpr(p, e, d, "#eqStrings($1, $2)")
@ -1868,6 +1898,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mConStrStr: genStrConcat(p, e, d) of mConStrStr: genStrConcat(p, e, d)
of mAppendStrCh: of mAppendStrCh:
if p.config.selectedGC == gcDestructors:
binaryStmtAddr(p, e, d, "#nimAddCharV1($1, $2);$n")
else:
var dest, b, call: TLoc var dest, b, call: TLoc
initLoc(call, locCall, e, OnHeap) initLoc(call, locCall, e, OnHeap)
initLocExpr(p, e.sons[1], dest) initLocExpr(p, e.sons[1], dest)
@ -1875,7 +1908,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
genAssignment(p, dest, call, {}) genAssignment(p, dest, call, {})
of mAppendStrStr: genStrAppend(p, e, d) of mAppendStrStr: genStrAppend(p, e, d)
of mAppendSeqElem: genSeqElemAppend(p, e, d) of mAppendSeqElem:
if p.config.selectedGc == gcDestructors:
genCall(p, e, d)
else:
genSeqElemAppend(p, e, d)
of mEqStr: genStrEquals(p, e, d) of mEqStr: genStrEquals(p, e, d)
of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)") of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)") of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
@ -1924,8 +1961,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
mInSet: mInSet:
genSetOp(p, e, d, op) genSetOp(p, e, d, op)
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, of mCopyStr, mCopyStrLast:
mParseBiggestFloat: genCall(p, e, d)
of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat:
var opr = e.sons[0].sym var opr = e.sons[0].sym
if lfNoDecl notin opr.loc.flags: if lfNoDecl notin opr.loc.flags:
discard cgsym(p.module, $opr.loc.r) discard cgsym(p.module, $opr.loc.r)
@ -2509,7 +2547,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
var t = skipTypes(n.typ, abstractInst) var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence: if t.kind == tySequence:
result = genConstSeq(p, n, n.typ) result = genConstSeq(p, n, n.typ)
elif t.kind == tyProc and t.callConv == ccClosure and not n.sons.isNil and elif t.kind == tyProc and t.callConv == ccClosure and n.len > 0 and
n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit: n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit:
# this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
# this behaviour is needed since closure_var = nil must be # this behaviour is needed since closure_var = nil must be
@ -2522,6 +2560,13 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
result = genConstSimpleList(p, n) result = genConstSimpleList(p, n)
of nkObjConstr: of nkObjConstr:
result = genConstObjConstr(p, n) result = genConstObjConstr(p, n)
of nkStrLit..nkTripleStrLit:
if p.config.selectedGc == gcDestructors:
result = genStringLiteralV2Const(p.module, n)
else:
var d: TLoc
initLocExpr(p, n, d)
result = rdLoc(d)
else: else:
var d: TLoc var d: TLoc
initLocExpr(p, n, d) initLocExpr(p, n, d)

View file

@ -53,20 +53,36 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope = proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
result = getTempName(m) result = getTempName(m)
addf(m.s[cfsData], " static const NIM_CHAR $1[$2] = $3;$n", addf(m.s[cfsData], "static const struct {$n" &
[result, rope(len(s)+1), makeCString(s)]) " NI cap; void* allocator; NIM_CHAR data[$2];$n" &
"} $1 = { $2, NIM_NIL, $3 };$n",
[result, rope(len(s)), makeCString(s)])
proc genStringLiteralV2(m: BModule; n: PNode): Rope = proc genStringLiteralV2(m: BModule; n: PNode): Rope =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels) let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels: if id == m.labels:
discard cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2")
# string literal not found in the cache: # string literal not found in the cache:
let pureLit = genStringLiteralDataOnlyV2(m, n.strVal) let pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
result = getTempName(m) result = getTempName(m)
addf(m.s[cfsData], "static const #NimStringV2 $1 = {$2, $2, $3};$n", addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
[result, rope(len(n.strVal)+1), pureLit]) [result, rope(len(n.strVal)), pureLit])
else: else:
result = m.tmpBase & rope(id) result = m.tmpBase & rope(id)
proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
discard cgsym(m, "NimStrPayload")
discard cgsym(m, "NimStringV2")
# string literal not found in the cache:
pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
else:
pureLit = m.tmpBase & rope(id)
result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit]
# ------ Version selector --------------------------------------------------- # ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope = proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =

View file

@ -16,7 +16,7 @@ const
# above X strings a hash-switch for strings is generated # above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) = proc registerGcRoot(p: BProc, v: PSym) =
if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and
containsGarbageCollectedRef(v.loc.t): containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage # we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-) # that it works out of the box for thread local storage then :-)

View file

@ -7,8 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## Generates traversal procs for the C backend. Traversal procs are only an ## Generates traversal procs for the C backend.
## optimization; the GC works without them too.
# included from cgen.nim # included from cgen.nim
@ -61,6 +60,7 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
else: else:
result = accessor result = accessor
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
if typ == nil: return if typ == nil: return
@ -93,7 +93,17 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
let typ = getUniqueType(typ) let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i]) genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
of tyRef, tyString, tySequence: of tyRef:
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
of tySequence:
if tfHasAsgn notin typ.flags:
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
elif containsGarbageCollectedRef(typ.lastSon):
# destructor based seqs are themselves not traced but their data is, if
# they contain a GC'ed type:
genTraverseProcSeq(c, accessor, typ)
of tyString:
if tfHasAsgn notin typ.flags:
lineCg(p, cpsStmts, c.visitorFrmt, accessor) lineCg(p, cpsStmts, c.visitorFrmt, accessor)
of tyProc: of tyProc:
if typ.callConv == ccClosure: if typ.callConv == ccClosure:
@ -107,8 +117,11 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var i: TLoc var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts) let oldCode = p.s(cpsStmts)
lineF(p, cpsStmts, "for ($1 = 0; $1 < ($2 ? $2->$3 : 0); $1++) {$n", var a: TLoc
[i.r, accessor, lenField(c.p)]) a.r = accessor
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, lenExpr(c.p, a)])
let oldLen = p.s(cpsStmts).len let oldLen = p.s(cpsStmts).len
genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0]) genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
if p.s(cpsStmts).len == oldLen: if p.s(cpsStmts).len == oldLen:

View file

@ -282,7 +282,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
of tyString: of tyString:
case detectStrVersion(m) case detectStrVersion(m)
of 2: of 2:
discard cgsym(m, "string") discard cgsym(m, "NimStringV2")
result = typeNameOrLiteral(m, typ, "NimStringV2") result = typeNameOrLiteral(m, typ, "NimStringV2")
else: else:
discard cgsym(m, "NimStringDesc") discard cgsym(m, "NimStringDesc")
@ -324,6 +324,10 @@ proc getForwardStructFormat(m: BModule): string =
if m.compileToCpp: result = "$1 $2;$n" if m.compileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n" else: result = "typedef $1 $2 $2;$n"
proc seqStar(m: BModule): string =
if m.config.selectedGC == gcDestructors: result = ""
else: result = "*"
proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
result = cacheGetType(m.forwTypeCache, sig) result = cacheGetType(m.forwTypeCache, sig)
if result != nil: return if result != nil: return
@ -355,7 +359,10 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
result = getTypeForward(m, t, hashType(t)) result = getTypeForward(m, t, hashType(t))
pushType(m, t) pushType(m, t)
of tySequence: of tySequence:
result = getTypeForward(m, t, hashType(t)) & "*" if m.config.selectedGC == gcDestructors:
result = getTypeDescAux(m, t, check)
else:
result = getTypeForward(m, t, hashType(t)) & seqStar(m)
pushType(m, t) pushType(m, t)
else: else:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
@ -442,7 +449,9 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
let uname = rope(mangle(n.sons[0].sym.name.s) & 'U') # prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_'
let uname = rope("_U" & mangle(n.sons[0].sym.name.s))
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname] let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
else: uname else: uname
var unionBody: Rope = nil var unionBody: Rope = nil
@ -487,7 +496,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
addf(result, "$1 $2[SEQ_DECL_SIZE];$n", addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname]) [getTypeDescAux(m, fieldType.elemType, check), sname])
elif fieldType.kind in {tySequence, tyOpt}: elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
# we need to use a weak dependency here for trecursive_table. # we need to use a weak dependency here for trecursive_table.
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
elif field.bitsize != 0: elif field.bitsize != 0:
@ -601,6 +610,15 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
result = if result.kind == tyGenericInst: result.sons[1] result = if result.kind == tyGenericInst: result.sons[1]
else: result.elemType else: result.elemType
proc getSeqPayloadType(m: BModule; t: PType): Rope =
result = getTypeForward(m, t, hashType(t)) & "_Content"
when false:
var check = initIntSet()
# XXX remove this duplication:
appcg(m, m.s[cfsSeqTypes],
"struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE]; };$n",
[getTypeDescAux(m, t.sons[0], check), result])
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
# returns only the type's name # returns only the type's name
var t = origTyp.skipTypes(irrelevantForBackend) var t = origTyp.skipTypes(irrelevantForBackend)
@ -641,7 +659,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
of tySequence: of tySequence:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType et) let name = getTypeForward(m, et, hashType et)
result = name & "*" & star result = name & seqStar(m) & star
m.typeCache[sig] = result m.typeCache[sig] = result
pushType(m, et) pushType(m, et)
else: else:
@ -705,20 +723,29 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
[structOrUnion(t), result]) [structOrUnion(t), result])
m.forwTypeCache[sig] = result m.forwTypeCache[sig] = result
assert(cacheGetType(m.typeCache, sig) == nil) assert(cacheGetType(m.typeCache, sig) == nil)
m.typeCache[sig] = result & "*" m.typeCache[sig] = result & seqStar(m)
if not isImportedType(t): if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty: if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const const
cppSeq = "struct $2 : #TGenericSeq {$n" cppSeq = "struct $2 : #TGenericSeq {$n"
cSeq = "struct $2 {$n" & cSeq = "struct $2 {$n" &
" #TGenericSeq Sup;$n" " #TGenericSeq Sup;$n"
if m.config.selectedGC == gcDestructors:
appcg(m, m.s[cfsTypes],
"typedef struct{ NI cap;void* allocator;$1 data[SEQ_DECL_SIZE];}$2_Content;$n" &
"struct $2 {$n" &
" NI len; $2_Content* p;$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
else:
appcg(m, m.s[cfsSeqTypes], appcg(m, m.s[cfsSeqTypes],
(if m.compileToCpp: cppSeq else: cSeq) & (if m.compileToCpp: cppSeq else: cSeq) &
" $1 data[SEQ_DECL_SIZE];$n" & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result]) "};$n", [getTypeDescAux(m, t.sons[0], check), result])
elif m.config.selectedGC == gcDestructors:
internalError(m.config, "cannot map the empty seq type to a C type")
else: else:
result = rope("TGenericSeq") result = rope("TGenericSeq")
add(result, "*") add(result, seqStar(m))
of tyArray: of tyArray:
var n: BiggestInt = lengthOrd(m.config, t) var n: BiggestInt = lengthOrd(m.config, t)
if n <= 0: n = 1 # make an array of at least one element if n <= 0: n = 1 # make an array of at least one element
@ -1177,7 +1204,13 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
else: else:
let x = fakeClosureType(m, t.owner) let x = fakeClosureType(m, t.owner)
genTupleInfo(m, x, x, result, info) genTupleInfo(m, x, x, result, info)
of tySequence, tyRef, tyOptAsRef: of tySequence:
if tfHasAsgn notin t.flags:
genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig)
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyRef, tyOptAsRef:
genTypeInfoAux(m, t, t, result, info) genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC >= gcMarkAndSweep: if m.config.selectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig) let markerProc = genTraverseProc(m, origType, sig)

View file

@ -230,10 +230,24 @@ proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels) result = m.tmpBase & rope(m.labels)
inc m.labels inc m.labels
proc rdLoc(a: TLoc): Rope =
# 'read' location (deref if indirect)
result = a.r
if lfIndirect in a.flags: result = "(*$1)" % [result]
proc lenField(p: BProc): Rope = proc lenField(p: BProc): Rope =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len") result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
proc lenExpr(p: BProc; a: TLoc): Rope =
if p.config.selectedGc == gcDestructors:
result = rdLoc(a) & ".len"
else:
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
proc dataField(p: BProc): Rope = proc dataField(p: BProc): Rope =
if p.config.selectedGc == gcDestructors:
result = rope".p->data"
else:
result = rope"->data" result = rope"->data"
include ccgliterals include ccgliterals
@ -241,11 +255,6 @@ include ccgtypes
# ------------------------------ Manager of temporaries ------------------ # ------------------------------ Manager of temporaries ------------------
proc rdLoc(a: TLoc): Rope =
# 'read' location (deref if indirect)
result = a.r
if lfIndirect in a.flags: result = "(*$1)" % [result]
proc addrLoc(conf: ConfigRef; a: TLoc): Rope = proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
result = a.r result = a.r
if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray: if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
@ -325,7 +334,9 @@ proc resetLoc(p: BProc, loc: var TLoc) =
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
let typ = loc.t let typ = loc.t
if not isComplexValueType(typ): if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", rdLoc(loc))
elif not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc), linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
getTypeDesc(p.module, typ)) getTypeDesc(p.module, typ))
else: else:
@ -694,9 +705,10 @@ proc containsResult(n: PNode): bool =
for i in 0..<n.safeLen: for i in 0..<n.safeLen:
if containsResult(n[i]): return true if containsResult(n[i]): return true
proc easyResultAsgn(n: PNode): PNode = const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt} +
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt} +
declarativeDefs declarativeDefs
proc easyResultAsgn(n: PNode): PNode =
case n.kind case n.kind
of nkStmtList, nkStmtListExpr: of nkStmtList, nkStmtListExpr:
var i = 0 var i = 0
@ -712,6 +724,105 @@ proc easyResultAsgn(n: PNode): PNode =
if result != nil: incl n.flags, nfPreventCg if result != nil: incl n.flags, nfPreventCg
else: discard else: discard
type
InitResultEnum = enum Unknown, InitSkippable, InitRequired
proc allPathsAsgnResult(n: PNode): InitResultEnum =
# Exceptions coming from calls don't have not be considered here:
#
# proc bar(): string = raise newException(...)
#
# proc foo(): string =
# # optimized out: 'reset(result)'
# result = bar()
#
# try:
# a = foo()
# except:
# echo "a was not written to"
#
template allPathsInBranch(it) =
let a = allPathsAsgnResult(it)
case a
of InitRequired: return InitRequired
of InitSkippable: discard
of Unknown:
# sticky, but can be overwritten by InitRequired:
result = Unknown
result = Unknown
case n.kind
of nkStmtList, nkStmtListExpr:
for it in n:
result = allPathsAsgnResult(it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
if not containsResult(n[1]): result = InitSkippable
else: result = InitRequired
elif containsResult(n):
result = InitRequired
of nkReturnStmt:
if n.len > 0:
result = allPathsAsgnResult(n[0])
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
for it in n:
# Every condition must not use 'result':
if it.len == 2 and containsResult(it[0]):
return InitRequired
if it.len == 1: exhaustive = true
allPathsInBranch(it.lastSon)
# if the 'if' statement is not exhaustive and yet it touched 'result'
# in some way, say Unknown.
if not exhaustive: result = Unknown
of nkCaseStmt:
if containsResult(n[0]): return InitRequired
result = InitSkippable
var exhaustive = skipTypes(n[0].typ,
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
for i in 1..<n.len:
let it = n[i]
allPathsInBranch(it.lastSon)
if it.kind == nkElse: exhaustive = true
if not exhaustive: result = Unknown
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(n[0])
if result == Unknown:
result = allPathsAsgnResult(n[1])
# we cannot assume that the 'while' loop is really executed at least once:
if result == InitSkippable: result = Unknown
of harmless:
result = Unknown
of nkGotoState, nkBreakState:
# give up for now.
result = InitRequired
of nkSym:
# some path reads from 'result' before it was written to!
if n.sym.kind == skResult: result = InitRequired
of nkTryStmt:
# We need to watch out for the following problem:
# try:
# result = stuffThatRaises()
# except:
# discard "result was not set"
#
# So ... even if the assignment to 'result' is the very first
# assignment this is not good enough! The only pattern we allow for
# is 'finally: result = x'
result = InitSkippable
for it in n:
if it.kind == nkFinally:
result = allPathsAsgnResult(it.lastSon)
else:
allPathsInBranch(it.lastSon)
else:
for i in 0..<safeLen(n):
allPathsInBranch(n[i])
proc genProcAux(m: BModule, prc: PSym) = proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m) var p = newProc(prc, m)
var header = genProcHeader(m, prc) var header = genProcHeader(m, prc)
@ -738,7 +849,16 @@ proc genProcAux(m: BModule, prc: PSym) =
else: else:
fillResult(p.config, resNode) fillResult(p.config, resNode)
assignParam(p, res) assignParam(p, res)
if sfNoInit notin prc.flags: resetLoc(p, res.loc) # We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
# to 'unsureAsgn(result, x)'
# Sketch why this is correct: If 'result' points to a stack location
# the 'unsureAsgn' is a nop. If it points to a global variable the
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(prc.getBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray: if skipTypes(res.typ, abstractInst).kind == tyArray:
#incl(res.loc.flags, lfIndirect) #incl(res.loc.flags, lfIndirect)
res.loc.storage = OnUnknown res.loc.storage = OnUnknown

View file

@ -239,7 +239,7 @@ proc toStmtList(n: PNode): PNode =
proc addGotoOut(n: PNode, gotoOut: PNode): PNode = proc addGotoOut(n: PNode, gotoOut: PNode): PNode =
# Make sure `n` is a stmtlist, and ends with `gotoOut` # Make sure `n` is a stmtlist, and ends with `gotoOut`
result = toStmtList(n) result = toStmtList(n)
if result.len != 0 and result.sons[^1].kind != nkGotoState: if result.len == 0 or result.sons[^1].kind != nkGotoState:
result.add(gotoOut) result.add(gotoOut)
proc newTempVar(ctx: var Ctx, typ: PType): PSym = proc newTempVar(ctx: var Ctx, typ: PType): PSym =
@ -678,7 +678,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
n[0] = ex n[0] = ex
result.add(n) result.add(n)
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv:
var ns = false var ns = false
for i in 0 ..< n.len: for i in 0 ..< n.len:
n[i] = ctx.lowerStmtListExprs(n[i], ns) n[i] = ctx.lowerStmtListExprs(n[i], ns)
@ -687,9 +687,9 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
needsSplit = true needsSplit = true
result = newNodeI(nkStmtListExpr, n.info) result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ result.typ = n.typ
let (st, ex) = exprToStmtList(n[1]) let (st, ex) = exprToStmtList(n[^1])
result.add(st) result.add(st)
n[1] = ex n[^1] = ex
result.add(n) result.add(n)
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:

View file

@ -0,0 +1,85 @@
## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix
# TODO: nimfix should use this; currently out of sync
import
compiler/[options, idents, nimconf, scriptconfig, extccomp, commands, msgs, lineinfos, modulegraphs, condsyms],
std/os
type
NimProg* = ref object
suggestMode*: bool
supportsStdinFile*: bool
processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef)
mainCommand*: proc(graph: ModuleGraph)
proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
condsyms.initDefines(conf.symbols)
defineSymbol conf.symbols, name
proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
self.processCmdLine(passCmd1, "", conf)
if self.supportsStdinFile and conf.projectName == "-":
conf.projectName = "stdinfile"
conf.projectFull = "stdinfile"
conf.projectPath = canonicalizePath(conf, getCurrentDir())
conf.projectIsStdin = true
elif conf.projectName != "":
try:
conf.projectFull = canonicalizePath(conf, conf.projectName)
except OSError:
conf.projectFull = conf.projectName
let p = splitFile(conf.projectFull)
let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
conf.projectPath = canonicalizePath(conf, dir)
conf.projectName = p.name
else:
conf.projectPath = canonicalizePath(conf, getCurrentDir())
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
loadConfigs(DefaultConfig, cache, conf) # load all config files
if self.suggestMode:
conf.command = "nimsuggest"
proc runNimScriptIfExists(path: string)=
if fileExists(path):
runNimScript(cache, path, freshDefines = false, conf)
# Caution: make sure this stays in sync with `loadConfigs`
if optSkipSystemConfigFile notin conf.globalOptions:
runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims))
if optSkipUserConfigFile notin conf.globalOptions:
runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(conf.projectPath, fromRoot = true, inclusive = false):
runNimScriptIfExists(dir / DefaultConfigNims)
if optSkipProjConfigFile notin conf.globalOptions:
runNimScriptIfExists(conf.projectPath / DefaultConfigNims)
block:
let scriptFile = conf.projectFull.changeFileExt("nims")
if not self.suggestMode:
runNimScriptIfExists(scriptFile)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile.cmpPaths(conf.projectFull) == 0:
return false
else:
if scriptFile.cmpPaths(conf.projectFull) != 0:
runNimScriptIfExists(scriptFile)
else:
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file
discard
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars(conf)
self.processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
let graph = newModuleGraph(cache, conf)
graph.suggestMode = self.suggestMode
self.mainCommand(graph)
return true

View file

@ -131,7 +131,10 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC
else: break else: break
inc(i) inc(i)
if i >= len(switch): arg = "" if i >= len(switch): arg = ""
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) # cmd:arg => (cmd,arg)
elif switch[i] in {':', '='}: arg = substr(switch, i + 1)
# cmd[sub]:rest => (cmd,[sub]:rest)
elif switch[i] == '[': arg = substr(switch, i)
else: invalidCmdLineOption(conf, pass, switch, info) else: invalidCmdLineOption(conf, pass, switch, info)
proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
@ -167,14 +170,20 @@ proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info:
proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) = info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = "X]:on|off" var id = "" # arg = key:val or [key]:val; with val=on|off
var i = 0 var i = 0
var n = hintMin var n = hintMin
while i < len(arg) and (arg[i] != ']'): var isBracket = false
if i < len(arg) and arg[i] == '[':
isBracket = true
inc(i)
while i < len(arg) and (arg[i] notin {':', '=', ']'}):
add(id, arg[i]) add(id, arg[i])
inc(i) inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i) if isBracket:
if i < len(arg) and arg[i] == ']': inc(i)
else: invalidCmdLineOption(conf, pass, orig, info) else: invalidCmdLineOption(conf, pass, orig, info)
if i < len(arg) and (arg[i] in {':', '='}): inc(i) if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(conf, pass, orig, info) else: invalidCmdLineOption(conf, pass, orig, info)
if state == wHint: if state == wHint:
@ -215,7 +224,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "refc": result = conf.selectedGC == gcRefc of "refc": result = conf.selectedGC == gcRefc
of "v2": result = conf.selectedGC == gcV2 of "v2": result = conf.selectedGC == gcV2
of "markandsweep": result = conf.selectedGC == gcMarkAndSweep of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
of "generational": result = conf.selectedGC == gcGenerational of "generational": result = false
of "destructors": result = conf.selectedGC == gcDestructors
of "go": result = conf.selectedGC == gcGo of "go": result = conf.selectedGC == gcGo
of "none": result = conf.selectedGC == gcNone of "none": result = conf.selectedGC == gcNone
of "stack", "regions": result = conf.selectedGC == gcRegions of "stack", "regions": result = conf.selectedGC == gcRegions
@ -436,9 +446,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "markandsweep": of "markandsweep":
conf.selectedGC = gcMarkAndSweep conf.selectedGC = gcMarkAndSweep
defineSymbol(conf.symbols, "gcmarkandsweep") defineSymbol(conf.symbols, "gcmarkandsweep")
of "generational": of "destructors":
conf.selectedGC = gcGenerational conf.selectedGC = gcDestructors
defineSymbol(conf.symbols, "gcgenerational") defineSymbol(conf.symbols, "gcdestructors")
of "go": of "go":
conf.selectedGC = gcGo conf.selectedGC = gcGo
defineSymbol(conf.symbols, "gogc") defineSymbol(conf.symbols, "gogc")
@ -641,7 +651,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: localError(conf, info, "invalid option for --symbolFiles: " & arg) else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
of "skipcfg": of "skipcfg":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optSkipConfigFile) incl(conf.globalOptions, optSkipSystemConfigFile)
of "skipprojcfg": of "skipprojcfg":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optSkipProjConfigFile) incl(conf.globalOptions, optSkipProjConfigFile)
@ -742,11 +752,11 @@ proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here # we transform it to (key = hint, val = [X]:off)
var bracketLe = strutils.find(p.key, '[') var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0: if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1) var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val var val = substr(p.key, bracketLe) & ':' & p.val
processSwitch(key, val, pass, gCmdLineInfo, config) processSwitch(key, val, pass, gCmdLineInfo, config)
else: else:
processSwitch(p.key, p.val, pass, gCmdLineInfo, config) processSwitch(p.key, p.val, pass, gCmdLineInfo, config)

View file

@ -13,6 +13,7 @@ import
strtabs, platform, strutils, idents strtabs, platform, strutils, idents
from options import Feature from options import Feature
from lineinfos import HintsToStr, WarningsToStr
const const
catNone = "false" catNone = "false"
@ -74,6 +75,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNoZeroTerminator") defineSymbol("nimNoZeroTerminator")
defineSymbol("nimNotNil") defineSymbol("nimNotNil")
defineSymbol("nimVmExportFixed") defineSymbol("nimVmExportFixed")
defineSymbol("nimHasSymOwnerInMacro")
defineSymbol("nimNewRuntime")
defineSymbol("nimIncrSeqV3") defineSymbol("nimIncrSeqV3")
defineSymbol("nimAshr") defineSymbol("nimAshr")
defineSymbol("nimNoNilSeqs") defineSymbol("nimNoNilSeqs")
@ -82,3 +85,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasNilSeqs") defineSymbol("nimHasNilSeqs")
for f in low(Feature)..high(Feature): for f in low(Feature)..high(Feature):
defineSymbol("nimHas" & $f) defineSymbol("nimHas" & $f)
for s in WarningsToStr:
defineSymbol("nimHasWarning" & s)
for s in HintsToStr:
defineSymbol("nimHasHint" & s)

View file

@ -100,12 +100,12 @@ Rule Pattern Transformed into
finally: `=destroy`(x) finally: `=destroy`(x)
1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x) 1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x)
2 x = f() `=sink`(x, f()) 2 x = f() `=sink`(x, f())
3 x = lastReadOf z `=sink`(x, z) 3 x = lastReadOf z `=sink`(x, z); wasMoved(z)
4.1 y = sinkParam `=sink`(y, sinkParam) 4.1 y = sinkParam `=sink`(y, sinkParam)
4.2 x = y `=`(x, y) # a copy 4.2 x = y `=`(x, y) # a copy
5.1 f_sink(g()) f_sink(g()) 5.1 f_sink(g()) f_sink(g())
5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read 5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read
5.3 f_sink(move y) f_sink(y); reset(y) # explicit moves empties 'y' 5.3 f_sink(move y) f_sink(y); wasMoved(y) # explicit moves empties 'y'
5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp) 5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp)
Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
@ -258,8 +258,10 @@ proc registerDropBit(c: var Con; s: PSym) =
c.toDropBit[s.id] = result c.toDropBit[s.id] = result
# generate: # generate:
# if not sinkParam_AliveBit: `=destroy`(sinkParam) # if not sinkParam_AliveBit: `=destroy`(sinkParam)
let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink})
if t.destructor != nil:
c.destroys.add newTree(nkIfStmt, c.destroys.add newTree(nkIfStmt,
newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s))) newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s)))
proc p(n: PNode; c: var Con): PNode proc p(n: PNode; c: var Con): PNode
@ -282,6 +284,11 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode =
newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
result.add n result.add n
proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, magicname, m)))
result.add n
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
if ri.kind in constrExprs: if ri.kind in constrExprs:
result = genSink(c, ri.typ, dest) result = genSink(c, ri.typ, dest)
@ -290,8 +297,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
recurse(ri, ri2) recurse(ri, ri2)
result.add ri2 result.add ri2
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c): elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
result = genSink(c, ri.typ, dest) # Rule 3: `=sink`(x, z); wasMoved(z)
result.add p(ri, c) var snk = genSink(c, ri.typ, dest)
snk.add p(ri, c)
result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
elif ri.kind == nkSym and isSinkParam(ri.sym): elif ri.kind == nkSym and isSinkParam(ri.sym):
result = genSink(c, ri.typ, dest) result = genSink(c, ri.typ, dest)
result.add destructiveMoveSink(ri, c) result.add destructiveMoveSink(ri, c)
@ -313,11 +322,9 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
result.add newTree(nkAsgn, tmp, p(n, c)) result.add newTree(nkAsgn, tmp, p(n, c))
result.add tmp result.add tmp
proc genReset(n: PNode; c: var Con): PNode = proc genWasMoved(n: PNode; c: var Con): PNode =
result = newNodeI(nkCall, n.info) # The mWasMoved builtin does not take the address.
result.add(newSymNode(createMagic(c.graph, "reset", mReset))) result = genMagicCall(n, c, "wasMoved", mWasMoved)
# The mReset builtin does not take the address:
result.add n
proc destructiveMoveVar(n: PNode; c: var Con): PNode = proc destructiveMoveVar(n: PNode; c: var Con): PNode =
# generate: (let tmp = v; reset(v); tmp) # generate: (let tmp = v; reset(v); tmp)
@ -334,7 +341,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
add(v, vpart) add(v, vpart)
result.add v result.add v
result.add genReset(n, c) result.add genWasMoved(n, c)
result.add tempAsNode result.add tempAsNode
proc p(n: PNode; c: var Con): PNode = proc p(n: PNode; c: var Con): PNode =

View file

@ -14,7 +14,7 @@
import import
ast, strutils, strtabs, options, msgs, os, ropes, idents, ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
packages/docutils/rst, packages/docutils/rstgen, times, packages/docutils/rst, packages/docutils/rstgen,
packages/docutils/highlite, sempass2, json, xmltree, cgi, packages/docutils/highlite, sempass2, json, xmltree, cgi,
typesrenderer, astalgo, modulepaths, lineinfos, sequtils typesrenderer, astalgo, modulepaths, lineinfos, sequtils
@ -31,6 +31,7 @@ type
isPureRst: bool isPureRst: bool
conf*: ConfigRef conf*: ConfigRef
cache*: IdentCache cache*: IdentCache
exampleCounter: int
PDoc* = ref TDocumentor ## Alias to type less. PDoc* = ref TDocumentor ## Alias to type less.
@ -284,11 +285,56 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
proc testExample(d: PDoc; ex: PNode) =
if d.conf.errorCounter > 0: return
let outputDir = d.conf.getNimcacheDir / "runnableExamples"
createDir(outputDir)
inc d.exampleCounter
let outp = outputDir / extractFilename(d.filename.changeFileExt"" &
"_examples" & $d.exampleCounter & ".nim")
#let nimcache = outp.changeFileExt"" & "_nimcache"
renderModule(ex, d.filename, outp, conf = d.conf)
let backend = if isDefined(d.conf, "js"): "js"
elif isDefined(d.conf, "cpp"): "cpp"
elif isDefined(d.conf, "objc"): "objc"
else: "c"
if os.execShellCmd(os.getAppFilename() & " " & backend &
" --nimcache:" & outputDir & " -r " & outp) != 0:
quit "[Examples] failed: see " & outp
else:
# keep generated source file `outp` to allow inspection.
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp])
removeFile(outp.changeFileExt(ExeExt))
proc extractImports(n: PNode; result: PNode) =
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
result.add copyTree(n)
n.kind = nkEmpty
return
for i in 0..<n.safeLen: extractImports(n[i], result)
proc prepareExamples(d: PDoc; n: PNode) =
var runnableExamples = newTree(nkStmtList,
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
runnableExamples.info = n.info
let imports = newTree(nkStmtList)
var savedLastSon = copyTree n.lastSon
extractImports(savedLastSon, imports)
for imp in imports: runnableExamples.add imp
runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
testExample(d, runnableExamples)
proc isRunnableExample(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
n.kind == nkIdent and n.ident.s == "runnableExamples"
proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
case n.kind case n.kind
of nkCallKinds: of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and if isRunnableExample(n[0]) and
n.len >= 2 and n.lastSon.kind == nkStmtList: n.len >= 2 and n.lastSon.kind == nkStmtList:
prepareExamples(d, n)
dispA(d.conf, dest, "\n<p><strong class=\"examples_text\">$1</strong></p>\n", dispA(d.conf, dest, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\\textbf{$1}\n", [rope"Examples:"]) "\n\\textbf{$1}\n", [rope"Examples:"])
inc d.listingCounter inc d.listingCounter
@ -627,6 +673,10 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkImportStmt: of nkImportStmt:
for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i]) for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
of nkCallKinds:
var comm: Rope = nil
getAllRunnableExamples(d, n, comm)
if comm > nil: add(d.modDesc, comm)
else: discard else: discard
proc add(d: PDoc; j: JsonNode) = proc add(d: PDoc; j: JsonNode) =
@ -787,14 +837,13 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d) var content = genOutFile(d)
var success = true
if optStdout in d.conf.globalOptions: if optStdout in d.conf.globalOptions:
writeRope(stdout, content) writeRope(stdout, content)
else: else:
let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs") let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs")
success = writeRope(content, outfile) createDir(outfile.parentDir)
if not success: if not writeRope(content, outfile):
rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, filename) rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile)
proc writeOutputJson*(d: PDoc, filename, outExt: string, proc writeOutputJson*(d: PDoc, filename, outExt: string,
useWarning = false) = useWarning = false) =

View file

@ -21,12 +21,15 @@ type
module: PSym module: PSym
PGen = ref TGen PGen = ref TGen
template shouldProcess(g): bool =
(g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or
sfMainModule in g.module.flags
template closeImpl(body: untyped) {.dirty.} = template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p) var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags let useWarning = sfMainModule notin g.module.flags
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
if (g.module.owner.id == g.doc.conf.mainPackageId and optWholeProject in g.doc.conf.globalOptions) or if shouldProcess(g):
sfMainModule in g.module.flags:
body body
try: try:
generateIndex(g.doc) generateIndex(g.doc)
@ -35,27 +38,29 @@ template closeImpl(body: untyped) {.dirty.} =
proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutput(g.doc, toFilename(graph.config, FileIndex g.module.position), HtmlExt, useWarning) writeOutput(g.doc, toFullPath(graph.config, FileIndex g.module.position), HtmlExt, useWarning)
proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
closeImpl: closeImpl:
writeOutputJson(g.doc, toFilename(graph.config, FileIndex g.module.position), ".json", useWarning) writeOutputJson(g.doc, toFullPath(graph.config, FileIndex g.module.position), ".json", useWarning)
proc processNode(c: PPassContext, n: PNode): PNode = proc processNode(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
if shouldProcess(g):
generateDoc(g.doc, n) generateDoc(g.doc, n)
proc processNodeJson(c: PPassContext, n: PNode): PNode = proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n) generateJson(g.doc, n)
proc myOpen(graph: ModuleGraph; module: PSym): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module
var d = newDocumentor(toFilename(graph.config, FileIndex module.position), graph.cache, graph.config) var d = newDocumentor(toFullPath(graph.config, FileIndex module.position), graph.cache, graph.config)
d.hasToc = true d.hasToc = true
g.doc = d g.doc = d
result = g result = g

View file

@ -24,9 +24,15 @@ proc readExceptSet*(c: PContext, n: PNode): IntSet =
result.incl(ident.id) result.incl(ident.id)
proc importPureEnumField*(c: PContext; s: PSym) = proc importPureEnumField*(c: PContext; s: PSym) =
var check = strTableGet(c.importTable.symbols, s.name) let check = strTableGet(c.importTable.symbols, s.name)
if check == nil: if check == nil:
let checkB = strTableGet(c.pureEnumFields, s.name)
if checkB == nil:
strTableAdd(c.pureEnumFields, s) strTableAdd(c.pureEnumFields, s)
else:
# mark as ambigous:
incl(c.ambiguousSymbols, checkB.id)
incl(c.ambiguousSymbols, s.id)
proc rawImportSymbol(c: PContext, s: PSym) = proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be # This does not handle stubs, because otherwise loading on demand would be
@ -164,7 +170,16 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
suggestSym(c.config, n.info, result, c.graph.usageSym, false) suggestSym(c.config, n.info, result, c.graph.usageSym, false)
importStmtResult.add newStrNode(toFullPath(c.config, f), n.info) importStmtResult.add newStrNode(toFullPath(c.config, f), n.info)
proc transformImportAs(c: PContext; n: PNode): PNode =
if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as":
result = newNodeI(nkImportAs, n.info)
result.add n.sons[1]
result.add n.sons[2]
else:
result = n
proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let it = transformImportAs(c, it)
let m = myImportModule(c, it, importStmtResult) let m = myImportModule(c, it, importStmtResult)
if m != nil: if m != nil:
var emptySet: IntSet var emptySet: IntSet
@ -174,26 +189,33 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
#importForwarded(c, m.ast, emptySet) #importForwarded(c, m.ast, emptySet)
proc evalImport(c: PContext, n: PNode): PNode = proc evalImport(c: PContext, n: PNode): PNode =
#result = n
result = newNodeI(nkImportStmt, n.info) result = newNodeI(nkImportStmt, n.info)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket: if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
let sep = it[0] let sep = it[0]
let dir = it[1] let dir = it[1]
let a = newNodeI(nkInfix, it.info) var imp = newNodeI(nkInfix, it.info)
a.add sep imp.add sep
a.add dir imp.add dir
a.add sep # dummy entry, replaced in the loop imp.add sep # dummy entry, replaced in the loop
for x in it[2]: for x in it[2]:
a.sons[2] = x # transform `a/b/[c as d]` to `/a/b/c as d`
impMod(c, a, result) if x.kind == nkInfix and x.sons[0].ident.s == "as":
let impAs = copyTree(x)
imp.sons[2] = x.sons[1]
impAs.sons[1] = imp
impMod(c, imp, result)
else:
imp.sons[2] = x
impMod(c, imp, result)
else: else:
impMod(c, it, result) impMod(c, it, result)
proc evalFrom(c: PContext, n: PNode): PNode = proc evalFrom(c: PContext, n: PNode): PNode =
result = newNodeI(nkImportStmt, n.info) result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
n.sons[0] = transformImportAs(c, n.sons[0])
var m = myImportModule(c, n.sons[0], result) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)
@ -205,6 +227,7 @@ proc evalFrom(c: PContext, n: PNode): PNode =
proc evalImportExcept*(c: PContext, n: PNode): PNode = proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = newNodeI(nkImportStmt, n.info) result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
n.sons[0] = transformImportAs(c, n.sons[0])
var m = myImportModule(c, n.sons[0], result) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)

View file

@ -243,7 +243,8 @@ proc mangleName(m: BModule, s: PSym): Rope =
x.add("HEX" & toHex(ord(c), 2)) x.add("HEX" & toHex(ord(c), 2))
inc i inc i
result = rope(x) result = rope(x)
if s.name.s != "this" and s.kind != skField: # From ES5 on reserved words can be used as object field names
if s.kind != skField:
if optHotCodeReloading in m.config.options: if optHotCodeReloading in m.config.options:
# When hot reloading is enabled, we must ensure that the names # When hot reloading is enabled, we must ensure that the names
# of functions and types will be preserved across rebuilds: # of functions and types will be preserved across rebuilds:
@ -271,9 +272,7 @@ proc escapeJSString(s: string): string =
result.add("\"") result.add("\"")
proc makeJSString(s: string, escapeNonAscii = true): Rope = proc makeJSString(s: string, escapeNonAscii = true): Rope =
if s.isNil: if escapeNonAscii:
result = "null".rope
elif escapeNonAscii:
result = strutils.escape(s).rope result = strutils.escape(s).rope
else: else:
result = escapeJSString(s).rope result = escapeJSString(s).rope
@ -1369,7 +1368,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
let length = int(lengthOrd(p.config, t)) let length = int(lengthOrd(p.config, t))
let e = elemType(t) let e = elemType(t)
let jsTyp = arrayTypeForElemType(e) let jsTyp = arrayTypeForElemType(e)
if not jsTyp.isNil: if jsTyp.len > 0:
result = "new $1($2)" % [rope(jsTyp), rope(length)] result = "new $1($2)" % [rope(jsTyp), rope(length)]
elif length > 32: elif length > 32:
useMagic(p, "arrayConstr") useMagic(p, "arrayConstr")

View file

@ -223,6 +223,9 @@ type
proc `==`*(a, b: FileIndex): bool {.borrow.} proc `==`*(a, b: FileIndex): bool {.borrow.}
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
const const
InvalidFileIDX* = FileIndex(-1) InvalidFileIDX* = FileIndex(-1)

View file

@ -244,7 +244,7 @@ else:
template fixSpelling(n: PNode; ident: PIdent; op: untyped) = discard template fixSpelling(n: PNode; ident: PIdent; op: untyped) = discard
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) = proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
var err = "Error: ambiguous identifier: '" & s.name.s & "'" var err = "ambiguous identifier: '" & s.name.s & "'"
var ti: TIdentIter var ti: TIdentIter
var candidate = initIdentIter(ti, c.importTable.symbols, s.name) var candidate = initIdentIter(ti, c.importTable.symbols, s.name)
var i = 0 var i = 0
@ -259,7 +259,7 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) = proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
var err = "undeclared identifier: '" & name & "'" var err = "undeclared identifier: '" & name & "'"
if c.recursiveDep.len > 0: if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency: " err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep err.add c.recursiveDep
# prevent excessive errors for 'nim check' # prevent excessive errors for 'nim check'
c.recursiveDep = "" c.recursiveDep = ""

View file

@ -120,6 +120,7 @@ proc skipIntLit*(t: PType): PType {.inline.} =
result = t result = t
proc addSonSkipIntLit*(father, son: PType) = proc addSonSkipIntLit*(father, son: PType) =
when not defined(nimNoNilSeqs):
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
let s = son.skipIntLit let s = son.skipIntLit
add(father.sons, s) add(father.sons, s)

View file

@ -126,13 +126,6 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
of nkInfix: of nkInfix:
let n0 = n[0] let n0 = n[0]
let n1 = n[1] let n1 = n[1]
if n0.kind == nkIdent and n0.ident.s == "as":
# XXX hack ahead:
n.kind = nkImportAs
n.sons[0] = n.sons[1]
n.sons[1] = n.sons[2]
n.sons.setLen(2)
return getModuleName(conf, n.sons[0])
when false: when false:
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$": if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
if n0.kind == nkIdent and n0.ident.s == "/": if n0.kind == nkIdent and n0.ident.s == "/":

View file

@ -102,9 +102,6 @@ proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} = proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
result = newLineInfo(fileInfoIdx(conf, filename), line, col) result = newLineInfo(fileInfoIdx(conf, filename), line, col)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
proc concat(strings: openarray[string]): string = proc concat(strings: openarray[string]): string =
var totalLen = 0 var totalLen = 0
@ -176,7 +173,7 @@ proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): string = proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): string =
if fileIdx.int32 < 0: if fileIdx.int32 < 0:
result = "???" result = "???"
elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isNil: elif conf.m.fileInfos[fileIdx.int32].dirtyFile.len > 0:
result = conf.m.fileInfos[fileIdx.int32].dirtyFile result = conf.m.fileInfos[fileIdx.int32].dirtyFile
else: else:
result = conf.m.fileInfos[fileIdx.int32].fullPath result = conf.m.fileInfos[fileIdx.int32].fullPath

View file

@ -21,7 +21,7 @@ when defined(i386) and defined(windows) and defined(vcc):
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, extccomp, strutils, os, osproc, platform, main, parseopt,
nodejs, scriptconfig, idents, modulegraphs, lineinfos nodejs, scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper
when hasTinyCBackend: when hasTinyCBackend:
import tccgen import tccgen
@ -57,47 +57,21 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
rawMessage(config, errGenerated, errArgsNeedRunOption) rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
condsyms.initDefines(conf.symbols) let self = NimProg(
supportsStdinFile: true,
processCmdLine: processCmdLine,
mainCommand: mainCommand
)
self.initDefinesProg(conf, "nim_compiler")
if paramCount() == 0: if paramCount() == 0:
writeCommandLineUsage(conf, conf.helpWritten) writeCommandLineUsage(conf, conf.helpWritten)
else: return
# Process command line arguments:
processCmdLine(passCmd1, "", conf) self.processCmdLineAndProjectPath(conf)
if conf.projectName == "-": if not self.loadConfigsAndRunMainCommand(cache, conf): return
conf.projectName = "stdinfile"
conf.projectFull = "stdinfile"
conf.projectPath = canonicalizePath(conf, getCurrentDir())
conf.projectIsStdin = true
elif conf.projectName != "":
try:
conf.projectFull = canonicalizePath(conf, conf.projectName)
except OSError:
conf.projectFull = conf.projectName
let p = splitFile(conf.projectFull)
let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
conf.projectPath = canonicalizePath(conf, dir)
conf.projectName = p.name
else:
conf.projectPath = canonicalizePath(conf, getCurrentDir())
loadConfigs(DefaultConfig, cache, conf) # load all config files
let scriptFile = conf.projectFull.changeFileExt("nims")
if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false, conf)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == conf.projectFull: return
elif fileExists(conf.projectPath / "config.nims"):
# directory wide NimScript file
runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars(conf)
processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
mainCommand(newModuleGraph(cache, conf))
if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics()) if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
#echo(GC_getStatistics()) #echo(GC_getStatistics())
if conf.errorCounter == 0: if conf.errorCounter != 0: return
when hasTinyCBackend: when hasTinyCBackend:
if conf.cmd == cmdRun: if conf.cmd == cmdRun:
tccgen.run(conf.arguments) tccgen.run(conf.arguments)

View file

@ -140,18 +140,19 @@ when isMainModule:
doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer. doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer.
doAssert v"#a111" < v"#head" doAssert v"#a111" < v"#head"
let conf = newConfigRef()
var rr = newStringTable() var rr = newStringTable()
addPackage rr, "irc-#a111" addPackage conf, rr, "irc-#a111", unknownLineInfo()
addPackage rr, "irc-#head" addPackage conf, rr, "irc-#head", unknownLineInfo()
addPackage rr, "irc-0.1.0" addPackage conf, rr, "irc-0.1.0", unknownLineInfo()
addPackage rr, "irc" #addPackage conf, rr, "irc", unknownLineInfo()
addPackage rr, "another" #addPackage conf, rr, "another", unknownLineInfo()
addPackage rr, "another-0.1" addPackage conf, rr, "another-0.1", unknownLineInfo()
addPackage rr, "ab-0.1.3" addPackage conf, rr, "ab-0.1.3", unknownLineInfo()
addPackage rr, "ab-0.1" addPackage conf, rr, "ab-0.1", unknownLineInfo()
addPackage rr, "justone" addPackage conf, rr, "justone-1.0", unknownLineInfo()
doAssert toSeq(rr.chosen) == doAssert toSeq(rr.chosen) ==
@["irc-#head", "another-0.1", "ab-0.1.3", "justone"] @["irc-#head", "another-0.1", "ab-0.1.3", "justone-1.0"]

View file

@ -175,9 +175,9 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
confTok(L, tok, config, condStack) confTok(L, tok, config, condStack)
if tok.tokType == tkBracketLe: if tok.tokType == tkBracketLe:
# BUGFIX: val, not s! # BUGFIX: val, not s!
# BUGFIX: do not copy '['!
confTok(L, tok, config, condStack) confTok(L, tok, config, condStack)
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, '[')
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, tok, config, condStack) confTok(L, tok, config, condStack)
if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack) if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
@ -219,10 +219,10 @@ proc readConfigFile(
closeLexer(L) closeLexer(L)
return true return true
proc getUserConfigPath(filename: string): string = proc getUserConfigPath*(filename: string): string =
result = joinPath([getConfigDir(), "nim", filename]) result = joinPath([getConfigDir(), "nim", filename])
proc getSystemConfigPath(conf: ConfigRef; filename: string): string = proc getSystemConfigPath*(conf: ConfigRef; filename: string): string =
# try standard configuration file (installation did not distribute files # try standard configuration file (installation did not distribute files
# the UNIX way) # the UNIX way)
let p = getPrefixDir(conf) let p = getPrefixDir(conf)
@ -241,7 +241,7 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
if readConfigFile(configPath, cache, conf): if readConfigFile(configPath, cache, conf):
add(configFiles, configPath) add(configFiles, configPath)
if optSkipConfigFile notin conf.globalOptions: if optSkipSystemConfigFile notin conf.globalOptions:
readConfigFile(getSystemConfigPath(conf, cfg)) readConfigFile(getSystemConfigPath(conf, cfg))
if optSkipUserConfigFile notin conf.globalOptions: if optSkipUserConfigFile notin conf.globalOptions:
@ -263,4 +263,5 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
readConfigFile(projectConfig) readConfigFile(projectConfig)
for filename in configFiles: for filename in configFiles:
# delayed to here so that `hintConf` is honored
rawMessage(conf, hintConf, filename) rawMessage(conf, hintConf, filename)

View file

@ -12,6 +12,7 @@ import
prefixmatches prefixmatches
from terminal import isatty from terminal import isatty
from times import utc, fromUnix, local, getTime, format, DateTime
const const
hasTinyCBackend* = defined(tinyc) hasTinyCBackend* = defined(tinyc)
@ -54,10 +55,10 @@ type # please make sure we have under 32 options
optGenMapping, # generate a mapping file optGenMapping, # generate a mapping file
optRun, # run the compiled project optRun, # run the compiled project
optCheckNep1, # check that the names adhere to NEP-1 optCheckNep1, # check that the names adhere to NEP-1
optSkipConfigFile, # skip the general config file optSkipSystemConfigFile, # skip the system's cfg/nims config file
optSkipProjConfigFile, # skip the project's config file optSkipProjConfigFile, # skip the project's cfg/nims config file
optSkipUserConfigFile, # skip the users's config file optSkipUserConfigFile, # skip the users's cfg/nims config file
optSkipParentConfigFiles, # skip parent dir's config files optSkipParentConfigFiles, # skip parent dir's cfg/nims config files
optNoMain, # do not generate a "main" proc optNoMain, # do not generate a "main" proc
optUseColors, # use colors for hints, warnings, and errors optUseColors, # use colors for hints, warnings, and errors
optThreads, # support for multi-threading optThreads, # support for multi-threading
@ -104,8 +105,8 @@ type
cmdJsonScript # compile a .json build file cmdJsonScript # compile a .json build file
TStringSeq* = seq[string] TStringSeq* = seq[string]
TGCMode* = enum # the selected GC TGCMode* = enum # the selected GC
gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc, gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcDestructors,
gcV2, gcGenerational gcRefc, gcV2
IdeCmd* = enum IdeCmd* = enum
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
@ -260,6 +261,24 @@ const
optPatterns, optNilCheck, optMoveCheck} optPatterns, optNilCheck, optMoveCheck}
DefaultGlobalOptions* = {optThreadAnalysis} DefaultGlobalOptions* = {optThreadAnalysis}
proc getSrcTimestamp(): DateTime =
try:
result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH",
"not a number"))))
except ValueError:
# Environment variable malformed.
# https://reproducible-builds.org/specs/source-date-epoch/: "If the
# value is malformed, the build process SHOULD exit with a non-zero
# error code", which this doesn't do. This uses local time, because
# that maintains compatibility with existing usage.
result = utc getTime()
proc getDateStr*(): string =
result = format(getSrcTimestamp(), "yyyy-MM-dd")
proc getClockStr*(): string =
result = format(getSrcTimestamp(), "HH:mm:ss")
template newPackageCache*(): untyped = template newPackageCache*(): untyped =
newStringTable(when FileSystemCaseSensitive: newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive modeCaseInsensitive
@ -374,7 +393,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
else: discard else: discard
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools} proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
template compilationCachePresent*(conf: ConfigRef): untyped = template compilationCachePresent*(conf: ConfigRef): untyped =
conf.symbolFiles in {v2Sf, writeOnlySf} conf.symbolFiles in {v2Sf, writeOnlySf}
@ -392,6 +411,7 @@ const
TexExt* = "tex" TexExt* = "tex"
IniExt* = "ini" IniExt* = "ini"
DefaultConfig* = "nim.cfg" DefaultConfig* = "nim.cfg"
DefaultConfigNims* = "config.nims"
DocConfig* = "nimdoc.cfg" DocConfig* = "nimdoc.cfg"
DocTexConfig* = "nimdoc.tex.cfg" DocTexConfig* = "nimdoc.tex.cfg"

View file

@ -33,6 +33,7 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
result = file.splitFile.name result = file.splitFile.name
break packageSearch break packageSearch
# we also store if we didn't find anything: # we also store if we didn't find anything:
when not defined(nimNoNilSeqs):
if result.isNil: result = "" if result.isNil: result = ""
for d in myParentDirs(path): for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents #echo "set cache ", d, " |", result, "|", parents

View file

@ -71,6 +71,7 @@ const
letPragmas* = varPragmas letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wLocks, wTags, wGcSafe} wThread, wRaises, wLocks, wTags, wGcSafe}
forVarPragmas* = {wInject, wGensym}
allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode = proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
@ -95,7 +96,9 @@ const
errIntLiteralExpected = "integer literal expected" errIntLiteralExpected = "integer literal expected"
proc invalidPragma*(c: PContext; n: PNode) = proc invalidPragma*(c: PContext; n: PNode) =
localError(c.config, n.info, "invalid pragma: " % renderTree(n, {renderNoComments})) localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments}))
proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
localError(c.config, n.info, "cannot attach a custom pragma to '" & s.name.s & "'")
proc pragmaAsm*(c: PContext, n: PNode): char = proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0' result = '\0'
@ -336,6 +339,20 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
of wPatterns: {optPatterns} of wPatterns: {optPatterns}
else: {} else: {}
proc processExperimental(c: PContext; n: PNode) =
if n.kind notin nkPragmaCallKinds or n.len != 2:
c.features.incl oldExperimentalFeatures
else:
n[1] = c.semConstExpr(c, n[1])
case n[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
try:
c.features.incl parseEnum[Feature](n[1].strVal)
except ValueError:
localError(c.config, n[1].info, "unknown experimental feature")
else:
localError(c.config, n.info, errStringLiteralExpected)
proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool = proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
result = true result = true
if n.kind notin nkPragmaCallKinds or n.len != 2: result = false if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
@ -343,6 +360,9 @@ proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
elif n.sons[0].kind != nkIdent: result = false elif n.sons[0].kind != nkIdent: result = false
else: else:
let sw = whichKeyword(n.sons[0].ident) let sw = whichKeyword(n.sons[0].ident)
if sw == wExperimental:
processExperimental(c, n)
return true
let opts = pragmaToOptions(sw) let opts = pragmaToOptions(sw)
if opts != {}: if opts != {}:
onOff(c, n, opts, resOptions) onOff(c, n, opts, resOptions)
@ -381,6 +401,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
x.defaultCC = y.defaultCC x.defaultCC = y.defaultCC
x.dynlib = y.dynlib x.dynlib = y.dynlib
x.notes = c.config.notes x.notes = c.config.notes
x.features = c.features
c.optionStack.add(x) c.optionStack.add(x)
for i in countup(start, sonsLen(n) - 1): for i in countup(start, sonsLen(n) - 1):
if not tryProcessOption(c, n.sons[i], c.config.options): if not tryProcessOption(c, n.sons[i], c.config.options):
@ -400,6 +421,7 @@ proc processPop(c: PContext, n: PNode) =
else: else:
c.config.options = c.optionStack[^1].options c.config.options = c.optionStack[^1].options
c.config.notes = c.optionStack[^1].notes c.config.notes = c.optionStack[^1].notes
c.features = c.optionStack[^1].features
c.optionStack.setLen(c.optionStack.len - 1) c.optionStack.setLen(c.optionStack.len - 1)
proc processDefine(c: PContext, n: PNode) = proc processDefine(c: PContext, n: PNode) =
@ -710,9 +732,7 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
elif n.kind == nkExprColonExpr: elif n.kind == nkExprColonExpr:
result.kind = n.kind # pragma(arg) -> pragma: arg result.kind = n.kind # pragma(arg) -> pragma: arg
proc processExperimental(c: PContext; n: PNode; s: PSym) = proc processExperimental(c: PContext; n: PNode) =
if not isTopLevel(c):
localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement")
if n.kind notin nkPragmaCallKinds or n.len != 2: if n.kind notin nkPragmaCallKinds or n.len != 2:
c.features.incl oldExperimentalFeatures c.features.incl oldExperimentalFeatures
else: else:
@ -1065,7 +1085,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else: else:
it.sons[1] = c.semExpr(c, it.sons[1]) it.sons[1] = c.semExpr(c, it.sons[1])
of wExperimental: of wExperimental:
processExperimental(c, it, sym) if not isTopLevel(c):
localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement or in a 'push' environment")
processExperimental(c, it)
of wThis: of wThis:
if it.kind in nkPragmaCallKinds and it.len == 2: if it.kind in nkPragmaCallKinds and it.len == 2:
c.selfName = considerQuotedIdent(c, it[1]) c.selfName = considerQuotedIdent(c, it[1])
@ -1090,9 +1112,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else: sym.flags.incl sfUsed else: sym.flags.incl sfUsed
of wLiftLocals: discard of wLiftLocals: discard
else: invalidPragma(c, it) else: invalidPragma(c, it)
else: elif sym.kind in {skField,skProc,skFunc,skConverter,skMethod,skType}:
n.sons[i] = semCustomPragma(c, it) n.sons[i] = semCustomPragma(c, it)
else:
illegalCustomPragma(c, it, sym)
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
validPragmas: TSpecialWords) = validPragmas: TSpecialWords) =

View file

@ -175,7 +175,7 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) =
g.pendingWhitespace = s.len g.pendingWhitespace = s.len
proc putComment(g: var TSrcGen, s: string) = proc putComment(g: var TSrcGen, s: string) =
if s.isNil: return if s.len == 0: return
var i = 0 var i = 0
let hi = len(s) - 1 let hi = len(s) - 1
var isCode = (len(s) >= 2) and (s[1] != ' ') var isCode = (len(s) >= 2) and (s[1] != ' ')
@ -216,7 +216,7 @@ proc putComment(g: var TSrcGen, s: string) =
optNL(g) optNL(g)
proc maxLineLength(s: string): int = proc maxLineLength(s: string): int =
if s.isNil: return 0 if s.len == 0: return 0
var i = 0 var i = 0
let hi = len(s) - 1 let hi = len(s) - 1
var lineLen = 0 var lineLen = 0
@ -752,6 +752,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[genericParamsPos]) gsub(g, n.sons[genericParamsPos])
g.inGenericParams = oldInGenericParams g.inGenericParams = oldInGenericParams
gsub(g, n.sons[paramsPos]) gsub(g, n.sons[paramsPos])
if renderNoPragmas notin g.flags:
gsub(g, n.sons[pragmasPos]) gsub(g, n.sons[pragmasPos])
if renderNoBody notin g.flags: if renderNoBody notin g.flags:
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
@ -1297,7 +1298,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkContinue, "continue") putWithSpace(g, tkContinue, "continue")
gsub(g, n, 0) gsub(g, n, 0)
of nkPragma: of nkPragma:
if renderNoPragmas notin g.flags:
if g.inPragma <= 0: if g.inPragma <= 0:
inc g.inPragma inc g.inPragma
#if not previousNL(g): #if not previousNL(g):

View file

@ -171,7 +171,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
graph.vm = setupVM(m, cache, scriptName, graph) graph.vm = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule() graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes
discard graph.processModule(m, llStreamOpen(scriptName, fmRead)) discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
# ensure we load 'system.nim' again for the real non-config stuff! # ensure we load 'system.nim' again for the real non-config stuff!

View file

@ -607,28 +607,6 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
#if c.config.cmd == cmdIdeTools: findSuggest(c, n) #if c.config.cmd == cmdIdeTools: findSuggest(c, n)
rod.storeNode(c.graph, c.module, result) rod.storeNode(c.graph, c.module, result)
proc testExamples(c: PContext) =
let outputDir = c.config.getNimcacheDir / "runnableExamples"
createDir(outputDir)
let inp = toFullPath(c.config, c.module.info)
let outp = outputDir / extractFilename(inp.changeFileExt"" & "_examples.nim")
let nimcache = outp.changeFileExt"" & "_nimcache"
renderModule(c.runnableExamples, inp, outp, conf = c.config)
let backend = if isDefined(c.config, "js"): "js"
elif isDefined(c.config, "cpp"): "cpp"
elif isDefined(c.config, "objc"): "objc"
else: "c"
if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0:
quit "[Examples] failed: see " & outp
else:
# keep generated source file `outp` to allow inspection.
rawMessage(c.config, hintSuccess, ["runnableExamples: " & outp])
removeFile(outp.changeFileExt(ExeExt))
try:
removeDir(nimcache)
except OSError:
discard
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
var c = PContext(context) var c = PContext(context)
if c.config.cmd == cmdIdeTools and not c.suggestionsMade: if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
@ -644,7 +622,6 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
popOwner(c) popOwner(c)
popProcCon(c) popProcCon(c)
storeRemaining(c.graph, c.module) storeRemaining(c.graph, c.module)
if c.runnableExamples != nil: testExamples(c)
const semPass* = makePass(myOpen, myProcess, myClose, const semPass* = makePass(myOpen, myProcess, myClose,
isFrontend = true) isFrontend = true)

View file

@ -197,12 +197,25 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind case t.kind
of tyNone, tyEmpty, tyVoid: discard of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
tyPtr, tyString, tyRef, tyOpt: tyPtr, tyRef, tyOpt:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyArray, tySequence: of tyArray:
if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}: if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}:
if t.kind == tySequence: let i = declareCounter(c, body, firstOrd(c.c.config, t))
# XXX add 'nil' handling here let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
y.at(i, elemType))
addIncStmt(c, whileLoop.sons[1], i)
body.add whileLoop
else:
defaultOp(c, t, body, x, y)
of tySequence:
# note that tfHasAsgn is propagated so we need the check on
# 'selectedGC' here to determine if we have the new runtime.
if c.c.config.selectedGC == gcDestructors:
discard considerOverloadedOp(c, t, body, x, y)
elif tfHasAsgn in t.flags:
body.add newSeqCall(c.c, x, y) body.add newSeqCall(c.c, x, y)
let i = declareCounter(c, body, firstOrd(c.c.config, t)) let i = declareCounter(c, body, firstOrd(c.c.config, t))
let whileLoop = genWhileLoop(c, i, x) let whileLoop = genWhileLoop(c, i, x)
@ -213,6 +226,11 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add whileLoop body.add whileLoop
else: else:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyString:
if tfHasAsgn in t.flags:
discard considerOverloadedOp(c, t, body, x, y)
else:
defaultOp(c, t, body, x, y)
of tyObject, tyDistinct: of tyObject, tyDistinct:
if not considerOverloadedOp(c, t, body, x, y): if not considerOverloadedOp(c, t, body, x, y):
if t.sons[0] != nil: if t.sons[0] != nil:

View file

@ -138,7 +138,9 @@ proc effectProblem(f, a: PType; result: var string) =
proc renderNotLValue(n: PNode): string = proc renderNotLValue(n: PNode): string =
result = $n result = $n
if n.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and n.len == 2: if n.kind == nkHiddenCallConv and n.len > 1:
result = $n[0] & "(" & result & ")"
elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")" result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")"
proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
@ -164,8 +166,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
prefer = preferModuleInfo prefer = preferModuleInfo
break break
when false:
# we pretend procs are attached to the type of the first
# argument in order to remove plenty of candidates. This is
# comparable to what C# does and C# is doing fine.
var filterOnlyFirst = false
for err in errors:
if err.firstMismatch > 1:
filterOnlyFirst = true
break
var candidates = "" var candidates = ""
for err in errors: for err in errors:
when false:
if filterOnlyFirst and err.firstMismatch == 1: continue
if err.sym.kind in routineKinds and err.sym.ast != nil: if err.sym.kind in routineKinds and err.sym.ast != nil:
add(candidates, renderTree(err.sym.ast, add(candidates, renderTree(err.sym.ast,
{renderNoBody, renderNoComments, renderNoPragmas})) {renderNoBody, renderNoComments, renderNoPragmas}))
@ -175,15 +189,18 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
if err.firstMismatch != 0 and n.len > 1: if err.firstMismatch != 0 and n.len > 1:
let cond = n.len > 2 let cond = n.len > 2
if cond: if cond:
candidates.add(" first type mismatch at position: " & $err.firstMismatch & candidates.add(" first type mismatch at position: " & $abs(err.firstMismatch))
"\n required type: ") if err.firstMismatch >= 0: candidates.add("\n required type: ")
else: candidates.add("\n unknown named parameter: " & $n[-err.firstMismatch][0])
var wanted, got: PType = nil var wanted, got: PType = nil
if err.firstMismatch < err.sym.typ.len: if err.firstMismatch < 0:
discard
elif err.firstMismatch < err.sym.typ.len:
wanted = err.sym.typ.sons[err.firstMismatch] wanted = err.sym.typ.sons[err.firstMismatch]
if cond: candidates.add typeToString(wanted) if cond: candidates.add typeToString(wanted)
else: else:
if cond: candidates.add "none" if cond: candidates.add "none"
if err.firstMismatch < n.len: if err.firstMismatch > 0 and err.firstMismatch < n.len:
if cond: if cond:
candidates.add "\n but expression '" candidates.add "\n but expression '"
candidates.add renderTree(n[err.firstMismatch]) candidates.add renderTree(n[err.firstMismatch])

View file

@ -22,6 +22,7 @@ type
defaultCC*: TCallingConvention defaultCC*: TCallingConvention
dynlib*: PLib dynlib*: PLib
notes*: TNoteKinds notes*: TNoteKinds
features*: set[Feature]
otherPragmas*: PNode # every pragma can be pushed otherPragmas*: PNode # every pragma can be pushed
POptionEntry* = ref TOptionEntry POptionEntry* = ref TOptionEntry
@ -140,7 +141,6 @@ type
# the generic type has been constructed completely. See # the generic type has been constructed completely. See
# tests/destructor/topttree.nim for an example that # tests/destructor/topttree.nim for an example that
# would otherwise fail. # would otherwise fail.
runnableExamples*: PNode
template config*(c: PContext): ConfigRef = c.graph.config template config*(c: PContext): ConfigRef = c.graph.config

View file

@ -800,7 +800,9 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
analyseIfAddressTakenInCall(c, result) analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone: if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags) result = magicsAfterOverloadResolution(c, result, flags)
if result.typ != nil: liftTypeBoundOps(c, result.typ, n.info) if result.typ != nil and
not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty):
liftTypeBoundOps(c, result.typ, n.info)
#result = patchResolvedTypeBoundOp(c, result) #result = patchResolvedTypeBoundOp(c, result)
if c.matchedConcept == nil: if c.matchedConcept == nil:
result = evalAtCompileTime(c, result) result = evalAtCompileTime(c, result)
@ -1389,8 +1391,8 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.sons[1] = semConstExpr(c, n.sons[1]) n.sons[1] = semConstExpr(c, n.sons[1])
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
{tyInt..tyInt64}: {tyInt..tyInt64}:
var idx = getOrdValue(n.sons[1]) let idx = getOrdValue(n.sons[1])
if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] if idx >= 0 and idx < len(arr): n.typ = arr.sons[int(idx)]
else: localError(c.config, n.info, "invalid index value for tuple subscript") else: localError(c.config, n.info, "invalid index value for tuple subscript")
result = n result = n
else: else:
@ -1565,6 +1567,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
n.sons[1] = fitNode(c, le, rhs, n.info) n.sons[1] = fitNode(c, le, rhs, n.info)
liftTypeBoundOps(c, lhs.typ, lhs.info) liftTypeBoundOps(c, lhs.typ, lhs.info)
#liftTypeBoundOps(c, n.sons[0].typ, n.sons[0].info)
fixAbstractType(c, n) fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1]) asgnToResultVar(c, n, n.sons[0], n.sons[1])
@ -1950,13 +1953,6 @@ proc setMs(n: PNode, s: PSym): PNode =
n.sons[0] = newSymNode(s) n.sons[0] = newSymNode(s)
n.sons[0].info = n.info n.sons[0].info = n.info
proc extractImports(n: PNode; result: PNode) =
if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
result.add copyTree(n)
n.kind = nkEmpty
return
for i in 0..<n.safeLen: extractImports(n[i], result)
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# this is a hotspot in the compiler! # this is a hotspot in the compiler!
# DON'T forget to update ast.SpecialSemMagics if you add a magic here! # DON'T forget to update ast.SpecialSemMagics if you add a magic here!
@ -2030,16 +2026,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = magicsAfterOverloadResolution(c, result, flags) result = magicsAfterOverloadResolution(c, result, flags)
of mRunnableExamples: of mRunnableExamples:
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
when false:
if sfMainModule in c.module.flags: if sfMainModule in c.module.flags:
let inp = toFullPath(c.config, c.module.info) let inp = toFullPath(c.config, c.module.info)
if c.runnableExamples == nil: if c.runnableExamples == nil:
c.runnableExamples = newTree(nkStmtList, c.runnableExamples = newTree(nkStmtList,
newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp)))) newTree(nkImportStmt, newStrNode(nkStrLit, expandFilename(inp))))
let imports = newTree(nkStmtList) let imports = newTree(nkStmtList)
var saved_lastSon = copyTree n.lastSon var savedLastSon = copyTree n.lastSon
extractImports(saved_lastSon, imports) extractImports(savedLastSon, imports)
for imp in imports: c.runnableExamples.add imp for imp in imports: c.runnableExamples.add imp
c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree saved_lastSon) c.runnableExamples.add newTree(nkBlockStmt, c.graph.emptyNode, copyTree savedLastSon)
result = setMs(n, s) result = setMs(n, s)
else: else:
result = c.graph.emptyNode result = c.graph.emptyNode
@ -2082,7 +2079,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
typ = commonType(typ, it.sons[1].typ) typ = commonType(typ, it.sons[1].typ)
result = n # when nimvm is not elimited until codegen result = n # when nimvm is not elimited until codegen
else: else:
var e = semConstExpr(c, it.sons[0]) let e = forceBool(c, semConstExpr(c, it.sons[0]))
if e.kind != nkIntLit: if e.kind != nkIntLit:
# can happen for cascading errors, assume false # can happen for cascading errors, assume false
# InternalError(n.info, "semWhen") # InternalError(n.info, "semWhen")

View file

@ -11,7 +11,7 @@
# and evaluation phase # and evaluation phase
import import
strutils, options, ast, astalgo, trees, treetab, nimsets, times, strutils, options, ast, astalgo, trees, treetab, nimsets,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys, modulegraphs, strtabs, lineinfos commands, magicsys, modulegraphs, strtabs, lineinfos
@ -450,21 +450,38 @@ proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
localError(g.config, n.info, "cannot convert " & $value & localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ)) " to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode = proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
let dstTyp = skipTypes(n.typ, abstractRange)
let srcTyp = skipTypes(a.typ, abstractRange)
# XXX range checks? # XXX range checks?
case skipTypes(n.typ, abstractRange).kind case dstTyp.kind
of tyInt..tyInt64, tyUInt..tyUInt64: of tyInt..tyInt64, tyUint..tyUInt64:
case skipTypes(a.typ, abstractRange).kind case srcTyp.kind
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n, g) result = newIntNodeT(int(getFloat(a)), n, g)
of tyChar: result = newIntNodeT(getOrdValue(a), n, g) of tyChar:
result = newIntNodeT(getOrdValue(a), n, g)
of tyUInt8..tyUInt32, tyInt8..tyInt32:
let fromSigned = srcTyp.kind in tyInt..tyInt64
let toSigned = dstTyp.kind in tyInt..tyInt64
let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true)
var val =
if toSigned:
a.getOrdValue mod mask
else:
a.getOrdValue and mask
result = newIntNodeT(val, n, g)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit}: if check and result.kind in {nkCharLit..nkUInt64Lit}:
rangeCheck(n, result.intVal, g) rangeCheck(n, result.intVal, g)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind case srcTyp.kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g) result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
else: else:
@ -549,19 +566,6 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = nil result = nil
proc getSrcTimestamp(): DateTime =
try:
result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH",
"not a number"))))
except ValueError:
# Environment variable malformed.
# https://reproducible-builds.org/specs/source-date-epoch/: "If the
# value is malformed, the build process SHOULD exit with a non-zero
# error code", which this doesn't do. This uses local time, because
# that maintains compatibility with existing usage.
result = local(getTime())
case n.kind case n.kind
of nkSym: of nkSym:
var s = n.sym var s = n.sym
@ -571,10 +575,8 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of skConst: of skConst:
case s.magic case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g) of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g)
of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(), of mCompileDate: result = newStrNodeT(getDateStr(), n, g)
"yyyy-MM-dd"), n, g) of mCompileTime: result = newStrNodeT(getClockStr(), n, g)
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
"HH:mm:ss"), n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[g.config.target.targetCPU].endian), n, g) of mCpuEndian: result = newIntNodeT(ord(CPU[g.config.target.targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g) of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g)
@ -742,7 +744,8 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n.sons[1], g) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv) # XXX: we should enable `check` for other conversion types too
result = foldConv(n, a, g, check=n.kind == nkHiddenSubConv)
of nkCast: of nkCast:
var a = getConstExpr(m, n.sons[1], g) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return

View file

@ -225,7 +225,7 @@ proc semGenericStmt(c: PContext, n: PNode,
var mixinContext = false var mixinContext = false
if s != nil: if s != nil:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mRunnableExamples}
let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen) let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
case s.kind case s.kind
of skMacro: of skMacro:

View file

@ -326,7 +326,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# no need to instantiate generic templates/macros: # no need to instantiate generic templates/macros:
internalAssert c.config, fn.kind notin {skMacro, skTemplate} internalAssert c.config, fn.kind notin {skMacro, skTemplate}
# generates an instantiated proc # generates an instantiated proc
if c.instCounter > 1000: internalError(c.config, fn.ast.info, "nesting too deep") if c.instCounter > 50:
globalError(c.config, info, "generic instantiation too nested")
inc(c.instCounter) inc(c.instCounter)
# careful! we copy the whole AST including the possibly nil body! # careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast) var n = copyTree(fn.ast)

View file

@ -323,13 +323,13 @@ proc catches(tracked: PEffects, e: PType) =
dec L dec L
else: else:
inc i inc i
if not isNil(tracked.exc.sons): if tracked.exc.len > 0:
setLen(tracked.exc.sons, L) setLen(tracked.exc.sons, L)
else: else:
assert L == 0 assert L == 0
proc catchesAll(tracked: PEffects) = proc catchesAll(tracked: PEffects) =
if not isNil(tracked.exc.sons): if tracked.exc.len > 0:
setLen(tracked.exc.sons, tracked.bottom) setLen(tracked.exc.sons, tracked.bottom)
proc track(tracked: PEffects, n: PNode) proc track(tracked: PEffects, n: PNode)

View file

@ -567,6 +567,8 @@ proc symForVar(c: PContext, n: PNode): PSym =
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
result = newSymG(skForVar, m, c) result = newSymG(skForVar, m, c)
styleCheckDef(c.config, result) styleCheckDef(c.config, result)
if n.kind == nkPragmaExpr:
pragma(c, result, n.sons[1], forVarPragmas)
proc semForVars(c: PContext, n: PNode): PNode = proc semForVars(c: PContext, n: PNode): PNode =
result = n result = n
@ -802,7 +804,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
if not isImportedException(typ, c.config): if not isImportedException(typ, c.config):
if typ.kind != tyRef or typ.lastSon.kind != tyObject: if typ.kind != tyRef or typ.lastSon.kind != tyObject:
localError(c.config, n.info, errExprCannotBeRaised) localError(c.config, n.info, errExprCannotBeRaised)
if not isException(typ.lastSon): if typ.len > 0 and not isException(typ.lastSon):
localError(c.config, n.info, "raised object of type $1 does not inherit from Exception", localError(c.config, n.info, "raised object of type $1 does not inherit from Exception",
[typeToString(typ)]) [typeToString(typ)])
@ -1056,8 +1058,8 @@ proc checkForMetaFields(c: PContext; n: PNode) =
case t.kind case t.kind
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyLent, tyPtr, tyRef, of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyLent, tyPtr, tyRef,
tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink: tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink:
let start = int ord(t.kind in {tyGenericInvocation, tyGenericInst}) let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
for i in start ..< t.sons.len: for i in start ..< t.len:
checkMeta(t.sons[i]) checkMeta(t.sons[i])
else: else:
checkMeta(t) checkMeta(t)
@ -1376,7 +1378,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj.sons[0] elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
else: break else: break
if obj.kind in {tyObject, tyDistinct}: if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if obj.destructor.isNil: if obj.destructor.isNil:
obj.destructor = s obj.destructor = s
else: else:
@ -1398,7 +1400,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
if t.kind == tyGenericBody: t = t.lastSon if t.kind == tyGenericBody: t = t.lastSon
elif t.kind == tyGenericInvocation: t = t.sons[0] elif t.kind == tyGenericInvocation: t = t.sons[0]
else: break else: break
if t.kind in {tyObject, tyDistinct, tyEnum}: if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
if t.deepCopy.isNil: t.deepCopy = s if t.deepCopy.isNil: t.deepCopy = s
else: else:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
@ -1427,7 +1429,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
elif objB.kind in {tyGenericInvocation, tyGenericInst}: elif objB.kind in {tyGenericInvocation, tyGenericInst}:
objB = objB.sons[0] objB = objB.sons[0]
else: break else: break
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB): if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink) let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink)
if opr[].isNil: if opr[].isNil:
opr[] = s opr[] = s
@ -1592,7 +1594,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags: if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
("'" & proto.name.s & "' from " & c.config$proto.info)) ("'" & proto.name.s & "' from " & c.config$proto.info))
if sfForward notin proto.flags: if sfForward notin proto.flags and proto.magic == mNone:
wrongRedefinition(c, n.info, proto.name.s) wrongRedefinition(c, n.info, proto.name.s)
excl(proto.flags, sfForward) excl(proto.flags, sfForward)
closeScope(c) # close scope with wrong parameter symbols closeScope(c) # close scope with wrong parameter symbols
@ -1609,7 +1611,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[pragmasPos] = proto.ast.sons[pragmasPos] n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
if n.sons[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux") if n.sons[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux")
n.sons[namePos].sym = proto n.sons[namePos].sym = proto
if importantComments(c.config) and not isNil(proto.ast.comment): if importantComments(c.config) and proto.ast.comment.len > 0:
n.comment = proto.ast.comment n.comment = proto.ast.comment
proto.ast = n # needed for code generation proto.ast = n # needed for code generation
popOwner(c) popOwner(c)
@ -1658,6 +1660,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
openScope(c) openScope(c)
n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
closeScope(c) closeScope(c)
if s.magic == mNone:
fixupInstantiatedSymbols(c, s) fixupInstantiatedSymbols(c, s)
if s.kind == skMethod: semMethodPrototype(c, s, n) if s.kind == skMethod: semMethodPrototype(c, s, n)
if sfImportc in s.flags: if sfImportc in s.flags:

View file

@ -210,7 +210,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
if s != nil and s.owner == c.owner and sfGenSym in s.flags: if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s) styleCheckUse(n.info, s)
replaceIdentBySym(c.c, n, newSymNode(s, n.info)) replaceIdentBySym(c.c, n, newSymNode(s, n.info))
else: elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
let local = newGenSym(k, ident, c) let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local) addPrelimDecl(c.c, local)
styleCheckDef(c.c.config, n.info, local) styleCheckDef(c.c.config, n.info, local)

View file

@ -145,9 +145,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, errXExpectsOneTypeParam % "set") localError(c.config, n.info, errXExpectsOneTypeParam % "set")
addSonSkipIntLit(result, errorType(c)) addSonSkipIntLit(result, errorType(c))
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, proc semContainerArg(c: PContext; n: PNode, kindStr: string; result: PType) =
prev: PType): PType =
result = newOrPrevType(kind, prev, c)
if sonsLen(n) == 2: if sonsLen(n) == 2:
var base = semTypeNode(c, n.sons[1], nil) var base = semTypeNode(c, n.sons[1], nil)
if base.kind == tyVoid: if base.kind == tyVoid:
@ -157,6 +155,11 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
localError(c.config, n.info, errXExpectsOneTypeParam % kindStr) localError(c.config, n.info, errXExpectsOneTypeParam % kindStr)
addSonSkipIntLit(result, errorType(c)) addSonSkipIntLit(result, errorType(c))
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
prev: PType): PType =
result = newOrPrevType(kind, prev, c)
semContainerArg(c, n, kindStr, result)
proc semVarargs(c: PContext, n: PNode, prev: PType): PType = proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyVarargs, prev, c) result = newOrPrevType(tyVarargs, prev, c)
if sonsLen(n) == 2 or sonsLen(n) == 3: if sonsLen(n) == 2 or sonsLen(n) == 3:
@ -1507,7 +1510,24 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of mRange: result = semRange(c, n, prev) of mRange: result = semRange(c, n, prev)
of mSet: result = semSet(c, n, prev) of mSet: result = semSet(c, n, prev)
of mOrdinal: result = semOrdinal(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev)
of mSeq: result = semContainer(c, n, tySequence, "seq", prev) of mSeq:
if c.config.selectedGc == gcDestructors:
let s = c.graph.sysTypes[tySequence]
assert s != nil
assert prev == nil
result = copyType(s, s.owner, keepId=false)
# XXX figure out why this has children already...
result.sons.setLen 0
result.n = nil
if c.config.selectedGc == gcDestructors:
result.flags = {tfHasAsgn}
else:
result.flags = {}
semContainerArg(c, n, "seq", result)
else:
result = semContainer(c, n, tySequence, "seq", prev)
if c.config.selectedGc == gcDestructors:
incl result.flags, tfHasAsgn
of mOpt: result = semContainer(c, n, tyOpt, "opt", prev) of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
of mVarargs: result = semVarargs(c, n, prev) of mVarargs: result = semVarargs(c, n, prev)
of mTypeDesc, mTypeTy: of mTypeDesc, mTypeTy:
@ -1687,6 +1707,9 @@ proc processMagicType(c: PContext, m: PSym) =
of mString: of mString:
setMagicType(c.config, m, tyString, c.config.target.ptrSize) setMagicType(c.config, m, tyString, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
when false:
if c.config.selectedGc == gcDestructors:
incl m.typ.flags, tfHasAsgn
of mCstring: of mCstring:
setMagicType(c.config, m, tyCString, c.config.target.ptrSize) setMagicType(c.config, m, tyCString, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
@ -1726,6 +1749,10 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicType(c.config, m, tySet, 0) setMagicType(c.config, m, tySet, 0)
of mSeq: of mSeq:
setMagicType(c.config, m, tySequence, 0) setMagicType(c.config, m, tySequence, 0)
if c.config.selectedGc == gcDestructors:
incl m.typ.flags, tfHasAsgn
assert c.graph.sysTypes[tySequence] == nil
c.graph.sysTypes[tySequence] = m.typ
of mOpt: of mOpt:
setMagicType(c.config, m, tyOpt, 0) setMagicType(c.config, m, tyOpt, 0)
of mOrdinal: of mOrdinal:

View file

@ -1921,6 +1921,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
result.typ.n = arg result.typ.n = arg
return return
let oldInheritancePenalty = m.inheritancePenalty
var r = typeRel(m, f, a) var r = typeRel(m, f, a)
# This special typing rule for macros and templates is not documented # This special typing rule for macros and templates is not documented
@ -2002,7 +2003,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
if arg.typ == nil: if arg.typ == nil:
result = arg result = arg
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
m.inheritancePenalty > 0: m.inheritancePenalty > oldInheritancePenalty:
result = implicitConv(nkHiddenSubConv, f, arg, m, c) result = implicitConv(nkHiddenSubConv, f, arg, m, c)
elif arg.typ.isEmptyContainer: elif arg.typ.isEmptyContainer:
result = arg.copyTree result = arg.copyTree
@ -2131,6 +2132,10 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
styleCheckUse(arg.info, arg.sons[best].sym) styleCheckUse(arg.info, arg.sons[best].sym)
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
when false:
if m.calleeSym != nil and m.calleeSym.name.s == "[]":
echo m.c.config $ arg.info, " for ", m.calleeSym.name.s, " ", m.c.config $ m.calleeSym.info
writeMatches(m)
proc setSon(father: PNode, at: int, son: PNode) = proc setSon(father: PNode, at: int, son: PNode) =
let oldLen = father.len let oldLen = father.len
@ -2226,6 +2231,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped:
formal = m.callee.n.sons[f].sym formal = m.callee.n.sons[f].sym
incl(marker, formal.position) incl(marker, formal.position)
if n.sons[a].kind == nkHiddenStdConv:
doAssert n.sons[a].sons[0].kind == nkEmpty and
n.sons[a].sons[1].kind == nkArgList and
n.sons[a].sons[1].len == 0
# Steal the container and pass it along
setSon(m.call, formal.position + 1, n.sons[a].sons[1])
else:
if container.isNil: if container.isNil:
container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info)) container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, container) setSon(m.call, formal.position + 1, container)
@ -2239,11 +2252,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if n.sons[a].sons[0].kind != nkIdent: if n.sons[a].sons[0].kind != nkIdent:
localError(c.config, n.sons[a].info, "named parameter has to be an identifier") localError(c.config, n.sons[a].info, "named parameter has to be an identifier")
m.state = csNoMatch m.state = csNoMatch
m.firstMismatch = -a
return return
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
if formal == nil: if formal == nil:
# no error message! # no error message!
m.state = csNoMatch m.state = csNoMatch
m.firstMismatch = -a
return return
if containsOrIncl(marker, formal.position): if containsOrIncl(marker, formal.position):
# already in namedParams, so no match # already in namedParams, so no match
@ -2261,6 +2276,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
n.sons[a].sons[1], n.sons[a].sons[1]) n.sons[a].sons[1], n.sons[a].sons[1])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
m.firstMismatch = a
return return
checkConstraint(n.sons[a].sons[1]) checkConstraint(n.sons[a].sons[1])
if m.baseTypeMatch: if m.baseTypeMatch:
@ -2379,6 +2395,11 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if m.magic in {mArrGet, mArrPut}: if m.magic in {mArrGet, mArrPut}:
m.state = csMatch m.state = csMatch
m.call = n m.call = n
# Note the following doesn't work as it would produce ambiguities.
# Instead we patch system.nim, see bug #8049.
when false:
inc m.genericMatches
inc m.exactMatches
return return
var marker = initIntSet() var marker = initIntSet()
matchesAux(c, n, nOrig, m, marker) matchesAux(c, n, nOrig, m, marker)
@ -2390,7 +2411,10 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if not containsOrIncl(marker, formal.position): if not containsOrIncl(marker, formal.position):
if formal.ast == nil: if formal.ast == nil:
if formal.typ.kind == tyVarargs: if formal.typ.kind == tyVarargs:
var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) # For consistency with what happens in `matchesAux` select the
# container node kind accordingly
let cnKind = if formal.typ.isVarargsUntyped: nkArgList else: nkBracket
var container = newNodeIT(cnKind, n.info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
else: else:

View file

@ -47,7 +47,7 @@ template origModuleName(m: PSym): string = m.name.s
proc findDocComment(n: PNode): PNode = proc findDocComment(n: PNode): PNode =
if n == nil: return nil if n == nil: return nil
if not isNil(n.comment): return n if n.comment.len > 0: return n
if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0: if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0:
result = findDocComment(n.sons[0]) result = findDocComment(n.sons[0])
if result != nil: return if result != nil: return
@ -434,7 +434,7 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym;
## misnamed: should be 'symDeclared' ## misnamed: should be 'symDeclared'
when defined(nimsuggest): when defined(nimsuggest):
if conf.suggestVersion == 0: if conf.suggestVersion == 0:
if s.allUsages.isNil: if s.allUsages.len == 0:
s.allUsages = @[info] s.allUsages = @[info]
else: else:
s.addNoDup(info) s.addNoDup(info)

View file

@ -39,24 +39,24 @@ proc setupEnvironment =
addIncludePath(gTinyC, libpath) addIncludePath(gTinyC, libpath)
when defined(windows): when defined(windows):
addSysincludePath(gTinyC, nimrodDir / "tinyc/win32/include") addSysincludePath(gTinyC, nimDir / "tinyc/win32/include")
addSysincludePath(gTinyC, nimrodDir / "tinyc/include") addSysincludePath(gTinyC, nimDir / "tinyc/include")
when defined(windows): when defined(windows):
defineSymbol(gTinyC, "_WIN32", nil) defineSymbol(gTinyC, "_WIN32", nil)
# we need Mingw's headers too: # we need Mingw's headers too:
var gccbin = getConfigVar("gcc.path") % ["nim", nimDir] var gccbin = getConfigVar("gcc.path") % ["nim", nimDir]
addSysincludePath(gTinyC, gccbin /../ "include") addSysincludePath(gTinyC, gccbin /../ "include")
#addFile(nimrodDir / r"tinyc\win32\wincrt1.o") #addFile(nimDir / r"tinyc\win32\wincrt1.o")
addFile(nimrodDir / r"tinyc\win32\alloca86.o") addFile(nimDir / r"tinyc\win32\alloca86.o")
addFile(nimrodDir / r"tinyc\win32\chkstk.o") addFile(nimDir / r"tinyc\win32\chkstk.o")
#addFile(nimrodDir / r"tinyc\win32\crt1.o") #addFile(nimDir / r"tinyc\win32\crt1.o")
#addFile(nimrodDir / r"tinyc\win32\dllcrt1.o") #addFile(nimDir / r"tinyc\win32\dllcrt1.o")
#addFile(nimrodDir / r"tinyc\win32\dllmain.o") #addFile(nimDir / r"tinyc\win32\dllmain.o")
addFile(nimrodDir / r"tinyc\win32\libtcc1.o") addFile(nimDir / r"tinyc\win32\libtcc1.o")
#addFile(nimrodDir / r"tinyc\win32\lib\crt1.c") #addFile(nimDir / r"tinyc\win32\lib\crt1.c")
#addFile(nimrodDir / r"tinyc\lib\libtcc1.c") #addFile(nimDir / r"tinyc\lib\libtcc1.c")
else: else:
addSysincludePath(gTinyC, "/usr/include") addSysincludePath(gTinyC, "/usr/include")
when defined(amd64): when defined(amd64):

View file

@ -1050,8 +1050,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
when useEffectSystem: trackTopLevelStmt(g, module, result) when useEffectSystem: trackTopLevelStmt(g, module, result)
#if n.info ?? "temp.nim": #if n.info ?? "temp.nim":
# echo renderTree(result, {renderIds}) # echo renderTree(result, {renderIds})
if c.needsDestroyPass: #if c.needsDestroyPass:
result = injectDestructorCalls(g, module, result) # result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf) incl(result.flags, nfTransf)
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
@ -1063,6 +1063,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
liftDefer(c, result) liftDefer(c, result)
# expressions are not to be injected with destructor calls as that # expressions are not to be injected with destructor calls as that
# the list of top level statements needs to be collected before. # the list of top level statements needs to be collected before.
if c.needsDestroyPass: #if c.needsDestroyPass:
result = injectDestructorCalls(g, module, result) # result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf) incl(result.flags, nfTransf)

View file

@ -29,7 +29,6 @@ proc hashTree(n: PNode): Hash =
if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0): if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0):
result = result !& toInt(n.floatVal) result = result !& toInt(n.floatVal)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if not n.strVal.isNil:
result = result !& hash(n.strVal) result = result !& hash(n.strVal)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):

View file

@ -278,6 +278,8 @@ proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
proc isGCRef(t: PType): bool = proc isGCRef(t: PType): bool =
result = t.kind in GcTypeKinds or result = t.kind in GcTypeKinds or
(t.kind == tyProc and t.callConv == ccClosure) (t.kind == tyProc and t.callConv == ccClosure)
if result and t.kind in {tyString, tySequence} and tfHasAsgn in t.flags:
result = false
proc containsGarbageCollectedRef*(typ: PType): bool = proc containsGarbageCollectedRef*(typ: PType): bool =
# returns true if typ contains a reference, sequence or string (all the # returns true if typ contains a reference, sequence or string (all the
@ -759,8 +761,9 @@ proc initSameTypeClosure: TSameTypeClosure =
discard discard
proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
result = not isNil(c.s) and c.s.contains((a.id, b.id)) result = c.s.len > 0 and c.s.contains((a.id, b.id))
if not result: if not result:
when not defined(nimNoNilSeqs):
if isNil(c.s): c.s = @[] if isNil(c.s): c.s = @[]
c.s.add((a.id, b.id)) c.s.add((a.id, b.id))
@ -1341,14 +1344,23 @@ proc computeSizeAux(conf: ConfigRef; typ: PType, a: var BiggestInt): BiggestInt
if typ.callConv == ccClosure: result = 2 * conf.target.ptrSize if typ.callConv == ccClosure: result = 2 * conf.target.ptrSize
else: result = conf.target.ptrSize else: result = conf.target.ptrSize
a = conf.target.ptrSize a = conf.target.ptrSize
of tyString, tyNil: of tyString:
if tfHasAsgn in typ.flags:
result = conf.target.ptrSize * 2
else:
result = conf.target.ptrSize
of tyNil:
result = conf.target.ptrSize result = conf.target.ptrSize
a = result a = result
of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray:
let base = typ.lastSon let base = typ.lastSon
if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion): if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion):
result = szIllegalRecursion result = szIllegalRecursion
else: result = conf.target.ptrSize else:
if typ.kind == tySequence and tfHasAsgn in typ.flags:
result = conf.target.ptrSize * 2
else:
result = conf.target.ptrSize
a = result a = result
of tyArray: of tyArray:
let elemSize = computeSizeAux(conf, typ.sons[1], a) let elemSize = computeSizeAux(conf, typ.sons[1], a)

View file

@ -29,7 +29,6 @@ proc renderPlainSymbolName*(n: PNode): string =
else: else:
result = "" result = ""
#internalError(n.info, "renderPlainSymbolName() with " & $n.kind) #internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
assert(not result.isNil)
proc renderType(n: PNode): string = proc renderType(n: PNode): string =
## Returns a string with the node type or the empty string. ## Returns a string with the node type or the empty string.
@ -80,7 +79,6 @@ proc renderType(n: PNode): string =
for i in 1 ..< len(n): result.add(renderType(n[i]) & ',') for i in 1 ..< len(n): result.add(renderType(n[i]) & ',')
result[len(result)-1] = ']' result[len(result)-1] = ']'
else: result = "" else: result = ""
assert(not result.isNil)
proc renderParamTypes(found: var seq[string], n: PNode) = proc renderParamTypes(found: var seq[string], n: PNode) =

View file

@ -81,14 +81,16 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
msgWriteln(c.config, s) msgWriteln(c.config, s)
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: string, n: PNode = nil) = msg: string, lineInfo: TLineInfo) =
msgWriteln(c.config, "stack trace: (most recent call last)") msgWriteln(c.config, "stack trace: (most recent call last)")
stackTraceAux(c, tos, pc) stackTraceAux(c, tos, pc)
# XXX test if we want 'globalError' for every mode # XXX test if we want 'globalError' for every mode
let lineInfo = if n == nil: c.debug[pc] else: n.info
if c.mode == emRepl: globalError(c.config, lineInfo, msg) if c.mode == emRepl: globalError(c.config, lineInfo, msg)
else: localError(c.config, lineInfo, msg) else: localError(c.config, lineInfo, msg)
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) =
stackTrace(c, tos, pc, msg, c.debug[pc])
proc bailOut(c: PCtx; tos: PStackFrame) = proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " & stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
c.currentExceptionA.sons[3].skipColon.strVal) c.currentExceptionA.sons[3].skipColon.strVal)
@ -242,6 +244,7 @@ template getstr(a: untyped): untyped =
(if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal))) (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
proc pushSafePoint(f: PStackFrame; pc: int) = proc pushSafePoint(f: PStackFrame; pc: int) =
when not defined(nimNoNilSeqs):
if f.safePoints.isNil: f.safePoints = @[] if f.safePoints.isNil: f.safePoints = @[]
f.safePoints.add(pc) f.safePoints.add(pc)
@ -255,7 +258,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs) let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
var f = tos var f = tos
while true: while true:
while f.safePoints.isNil or f.safePoints.len == 0: while f.safePoints.len == 0:
f = f.next f = f.next
if f.isNil: return (-1, nil) if f.isNil: return (-1, nil)
var pc2 = f.safePoints[f.safePoints.high] var pc2 = f.safePoints[f.safePoints.high]
@ -270,7 +273,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
abstractPtrs) abstractPtrs)
else: nil else: nil
#echo typeToString(exceptType), " ", typeToString(raisedType) #echo typeToString(exceptType), " ", typeToString(raisedType)
if exceptType.isNil or inheritanceDiff(exceptType, raisedType) <= 0: if exceptType.isNil or inheritanceDiff(raisedType, exceptType) <= 0:
# mark exception as handled but keep it in B for # mark exception as handled but keep it in B for
# the getCurrentException() builtin: # the getCurrentException() builtin:
c.currentExceptionB = c.currentExceptionA c.currentExceptionB = c.currentExceptionA
@ -297,7 +300,6 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
discard f.safePoints.pop discard f.safePoints.pop
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
if f.safePoints.isNil: return -1
for s in f.safePoints: for s in f.safePoints:
var pc = s var pc = s
while c.code[pc].opcode == opcExcept: while c.code[pc].opcode == opcExcept:
@ -531,9 +533,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeBC(rkInt) decodeBC(rkInt)
let idx = regs[rc].intVal.int let idx = regs[rc].intVal.int
let s = regs[rb].node.strVal let s = regs[rb].node.strVal
if s.isNil: if idx <% s.len:
stackTrace(c, tos, pc, errNilAccess)
elif idx <% s.len:
regs[ra].intVal = s[idx].ord regs[ra].intVal = s[idx].ord
elif idx == s.len and optLaxStrings in c.config.options: elif idx == s.len and optLaxStrings in c.config.options:
regs[ra].intVal = 0 regs[ra].intVal = 0
@ -820,7 +820,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
regs[rc].node.kind == nkNilLit) or regs[rc].node.kind == nkNilLit) or
regs[rb].node == regs[rc].node) regs[rb].node == regs[rc].node)
of opcEqNimrodNode: of opcEqNimNode:
decodeBC(rkInt) decodeBC(rkInt)
regs[ra].intVal = regs[ra].intVal =
ord(exprStructuralEquivalent(regs[rb].node, regs[rc].node, ord(exprStructuralEquivalent(regs[rb].node, regs[rc].node,
@ -920,6 +920,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.flags.incl nfIsRef regs[ra].node.flags.incl nfIsRef
else: else:
stackTrace(c, tos, pc, "node is not a symbol") stackTrace(c, tos, pc, "node is not a symbol")
of opcSymOwner:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkSym:
regs[ra].node = if a.sym.owner.isNil: newNode(nkNilLit)
else: newSymNode(a.sym.skipGenericOwner)
regs[ra].node.flags.incl nfIsRef
else:
stackTrace(c, tos, pc, "node is not a symbol")
of opcEcho: of opcEcho:
let rb = instr.regB let rb = instr.regB
if rb == 1: if rb == 1:
@ -1220,7 +1229,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# Note that `nfIsRef` + `nkNilLit` represents an allocated # Note that `nfIsRef` + `nkNilLit` represents an allocated
# reference with the value `nil`, so `isNil` should be false! # reference with the value `nil`, so `isNil` should be false!
(node.kind == nkNilLit and nfIsRef notin node.flags) or (node.kind == nkNilLit and nfIsRef notin node.flags) or
(node.kind in {nkStrLit..nkTripleStrLit} and node.strVal.isNil) or
(not node.typ.isNil and node.typ.kind == tyProc and (not node.typ.isNil and node.typ.kind == tyProc and
node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and
node.sons[1].kind == nkNilLit)) node.sons[1].kind == nkNilLit))
@ -1325,6 +1333,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(c.cache, regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeToAst(c.cache, regs[rb].node.typ, c.debug[pc])
elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil:
regs[ra].node = opMapTypeToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, "node has no type") stackTrace(c, tos, pc, "node has no type")
of 1: of 1:
@ -1332,6 +1342,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
ensureKind(rkInt) ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind) regs[ra].intVal = ord(regs[rb].node.typ.kind)
elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil:
regs[ra].intVal = ord(regs[rb].node.sym.typ.kind)
#else: #else:
# stackTrace(c, tos, pc, "node has no type") # stackTrace(c, tos, pc, "node has no type")
of 2: of 2:
@ -1339,6 +1351,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.typ, c.debug[pc])
elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil:
regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, "node has no type") stackTrace(c, tos, pc, "node has no type")
else: else:
@ -1346,6 +1360,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.typ, c.debug[pc])
elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil:
regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, "node has no type") stackTrace(c, tos, pc, "node has no type")
of opcNStrVal: of opcNStrVal:
@ -1380,15 +1396,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
c.debug[pc], c.config)[0] c.debug[pc], c.config)[0]
else: else:
globalError(c.config, c.debug[pc], "VM is not built with 'gorge' support") globalError(c.config, c.debug[pc], "VM is not built with 'gorge' support")
of opcNError: of opcNError, opcNWarning, opcNHint:
decodeB(rkNode) decodeB(rkNode)
let a = regs[ra].node let a = regs[ra].node
let b = regs[rb].node let b = regs[rb].node
stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b) let info = if b.kind == nkNilLit: c.debug[pc] else: b.info
of opcNWarning: if instr.opcode == opcNError:
message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal) stackTrace(c, tos, pc, a.strVal, info)
of opcNHint: elif instr.opcode == opcNWarning:
message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal) message(c.config, info, warnUser, a.strVal)
elif instr.opcode == opcNHint:
message(c.config, info, hintUser, a.strVal)
of opcParseExprToAst: of opcParseExprToAst:
decodeB(rkNode) decodeB(rkNode)
# c.debug[pc].line.int - countLines(regs[rb].strVal) ? # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
@ -1396,9 +1414,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let ast = parseString(regs[rb].node.strVal, c.cache, c.config, let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int,
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax: if error.len == 0 and msg <= errMax:
error = formatMsg(conf, info, msg, arg)) error = formatMsg(conf, info, msg, arg))
if not error.isNil: if error.len > 0:
c.errorFlag = error c.errorFlag = error
elif sonsLen(ast) != 1: elif sonsLen(ast) != 1:
c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated, c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated,
@ -1411,9 +1429,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let ast = parseString(regs[rb].node.strVal, c.cache, c.config, let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int, toFullPath(c.config, c.debug[pc]), c.debug[pc].line.int,
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax: if error.len == 0 and msg <= errMax:
error = formatMsg(conf, info, msg, arg)) error = formatMsg(conf, info, msg, arg))
if not error.isNil: if error.len > 0:
c.errorFlag = error c.errorFlag = error
else: else:
regs[ra].node = ast regs[ra].node = ast
@ -1726,6 +1744,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
inc pc inc pc
let typ = c.types[c.code[pc].regBx - wordExcess] let typ = c.types[c.code[pc].regBx - wordExcess]
createStrKeepNode(regs[ra]) createStrKeepNode(regs[ra])
when not defined(nimNoNilSeqs):
if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
of opcToNarrowInt: of opcToNarrowInt:

View file

@ -62,7 +62,7 @@ type
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcLeFloat, opcLtFloat, opcLeu, opcLtu,
opcEqRef, opcEqNimrodNode, opcSameNodeType, opcEqRef, opcEqNimNode, opcSameNodeType,
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
@ -141,7 +141,8 @@ type
opcSetType, # dest.typ = types[Bx] opcSetType, # dest.typ = types[Bx]
opcTypeTrait, opcTypeTrait,
opcMarshalLoad, opcMarshalStore, opcMarshalLoad, opcMarshalStore,
opcToNarrowInt opcToNarrowInt,
opcSymOwner
TBlock* = object TBlock* = object
label*: PSym label*: PSym

View file

@ -1118,6 +1118,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mStaticExec: genBinaryABCD(c, n, dest, opcGorge) of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag) of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNChild: genBinaryABC(c, n, dest, opcNChild)
of mNSetChild: genVoidABC(c, n, dest, opcNSetChild) of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
of mNDel: genVoidABC(c, n, dest, opcNDel) of mNDel: genVoidABC(c, n, dest, opcNDel)
@ -1178,7 +1179,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNBindSym: genBindSym(c, n, dest) of mNBindSym: genBindSym(c, n, dest)
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent) of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent) of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode) of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimNode)
of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType) of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
of mNLineInfo: of mNLineInfo:
case n[0].sym.name.s case n[0].sym.name.s
@ -1192,10 +1193,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
else: internalAssert c.config, false else: internalAssert c.config, false
of mNHint: of mNHint:
unused(c, n, dest) unused(c, n, dest)
genUnaryStmt(c, n, opcNHint) genBinaryStmt(c, n, opcNHint)
of mNWarning: of mNWarning:
unused(c, n, dest) unused(c, n, dest)
genUnaryStmt(c, n, opcNWarning) genBinaryStmt(c, n, opcNWarning)
of mNError: of mNError:
if n.len <= 1: if n.len <= 1:
# query error condition: # query error condition:

View file

@ -127,7 +127,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
storeAny(s, t.lastSon, a, stored, conf) storeAny(s, t.lastSon, a, stored, conf)
s.add("]") s.add("]")
of tyString, tyCString: of tyString, tyCString:
if a.kind == nkNilLit or a.strVal.isNil: s.add("null") if a.kind == nkNilLit: s.add("null")
else: s.add(escapeJson(a.strVal)) else: s.add(escapeJson(a.strVal))
of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal) of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
of tyFloat..tyFloat128: s.add($a.floatVal) of tyFloat..tyFloat128: s.add($a.floatVal)

View file

@ -17,8 +17,7 @@ About this document
=================== ===================
**Note**: This document is a draft! Several of Nim's features may need more **Note**: This document is a draft! Several of Nim's features may need more
precise wording. This manual is constantly evolving until the 1.0 release and is precise wording. This manual is constantly evolving into a proper specification.
not to be considered as the final proper specification.
This document describes the lexis, the syntax, and the semantics of Nim. This document describes the lexis, the syntax, and the semantics of Nim.
@ -433,7 +432,7 @@ Numerical constants are of a single type and have the form::
UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64' UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'
exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent) FLOAT_LIT = digit (['_'] digit)* (('.' digit (['_'] digit)* [exponent]) |exponent)
FLOAT32_SUFFIX = ('f' | 'F') ['32'] FLOAT32_SUFFIX = ('f' | 'F') ['32']
FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX
| (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX
@ -504,7 +503,7 @@ following characters::
These keywords are also operators: These keywords are also operators:
``and or not xor shl shr div mod in notin is isnot of``. ``and or not xor shl shr div mod in notin is isnot of``.
`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they `.`:tok: `=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they
are used for other notational purposes. are used for other notational purposes.
``*:`` is as a special case treated as the two tokens `*`:tok: and `:`:tok: ``*:`` is as a special case treated as the two tokens `*`:tok: and `:`:tok:
@ -618,6 +617,55 @@ The grammar's start symbol is ``module``.
Order of evaluation
===================
Order of evaluation is strictly left-to-right, inside-out as it is typical for most others
imperative programming languages:
.. code-block:: nim
:test: "nim c $1"
var s = ""
proc p(arg: int): int =
s.add $arg
result = arg
discard p(p(1) + p(2))
doAssert s == "123"
Assignments are not special, the left-hand-side expression is evaluated before the
right-hand side:
.. code-block:: nim
:test: "nim c $1"
var v = 0
proc getI(): int =
result = v
inc v
var a, b: array[0..2, int]
proc someCopy(a: var int; b: int) = a = b
a[getI()] = getI()
doAssert a == [1, 0, 0]
v = 0
someCopy(b[getI()], getI())
doAssert b == [1, 0, 0]
Rationale: Consistency with overloaded assignment or assignment-like operations,
``a = b`` can be read as ``performSomeCopy(a, b)``.
Types Types
===== =====
@ -888,8 +936,12 @@ Now the following holds::
ord(south) == 2 ord(south) == 2
ord(west) == 3 ord(west) == 3
# Also allowed:
ord(Direction.west) == 3
Thus, north < east < south < west. The comparison operators can be used Thus, north < east < south < west. The comparison operators can be used
with enumeration types. with enumeration types. Instead of ``north`` etc, the enum value can also
be qualified with the enum type that it resides in, ``Direction.north``.
For better interfacing to other programming languages, the fields of enum For better interfacing to other programming languages, the fields of enum
types can be assigned an explicit ordinal value. However, the ordinal values types can be assigned an explicit ordinal value. However, the ordinal values
@ -925,18 +977,25 @@ As can be seen from the example, it is possible to both specify a field's
ordinal value and its string value by using a tuple. It is also ordinal value and its string value by using a tuple. It is also
possible to only specify one of them. possible to only specify one of them.
An enum can be marked with the ``pure`` pragma so that it's fields are not An enum can be marked with the ``pure`` pragma so that it's fields are
added to the current scope, so they always need to be accessed added to a special module specific hidden scope that is only queried
via ``MyEnum.value``: as the last attempt. Only non-ambiguous symbols are added to this scope.
But one can always access these via type qualification written
as ``MyEnum.value``:
.. code-block:: nim .. code-block:: nim
type type
MyEnum {.pure.} = enum MyEnum {.pure.} = enum
valueA, valueB, valueC, valueD valueA, valueB, valueC, valueD, amb
echo valueA # error: Unknown identifier OtherEnum {.pure.} = enum
echo MyEnum.valueA # works valueX, valueY, valueZ, amb
echo valueA # MyEnum.valueA
echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
echo MyEnum.amb # OK.
String type String type
@ -945,6 +1004,11 @@ All string literals are of the type ``string``. A string in Nim is very
similar to a sequence of characters. However, strings in Nim are both similar to a sequence of characters. However, strings in Nim are both
zero-terminated and have a length field. One can retrieve the length with the zero-terminated and have a length field. One can retrieve the length with the
builtin ``len`` procedure; the length never counts the terminating zero. builtin ``len`` procedure; the length never counts the terminating zero.
The terminating zero cannot be accessed unless the string is converted
to the ``cstring`` type first. The terminating zero assures that this
conversion can be done in O(1) and without any allocations.
The assignment operator for strings always copies the string. The assignment operator for strings always copies the string.
The ``&`` operator concatenates strings. The ``&`` operator concatenates strings.
@ -2925,6 +2989,10 @@ name ``c`` should default to type ``Context``, ``n`` should default to
proc bar(c, n, counter) = ... proc bar(c, n, counter) = ...
proc baz(c, n) = ... proc baz(c, n) = ...
proc mixedMode(c, n; x, y: int) =
# 'c' is inferred to be of the type 'Context'
# 'n' is inferred to be of the type 'Node'
# But 'x' and 'y' are of type 'int'.
The ``using`` section uses the same indentation based grouping syntax as The ``using`` section uses the same indentation based grouping syntax as
a ``var`` or ``let`` section. a ``var`` or ``let`` section.
@ -2932,6 +3000,9 @@ a ``var`` or ``let`` section.
Note that ``using`` is not applied for ``template`` since untyped template Note that ``using`` is not applied for ``template`` since untyped template
parameters default to the type ``system.untyped``. parameters default to the type ``system.untyped``.
Mixing parameters that should use the ``using`` declaration with parameters
that are explicitly typed is possible and requires a semicolon between them.
If expression If expression
------------- -------------
@ -3045,6 +3116,19 @@ the address of variables, but one can't use it on variables declared through
# Error: expression has no address # Error: expression has no address
The unsafeAddr operator
-----------------------
For easier interoperability with other compiled languages such as C, retrieving
the address of a ``let`` variable, a parameter or a ``for`` loop variable, the
``unsafeAddr`` operation can be used:
.. code-block:: nim
let myArray = [1, 2, 3]
foreignProcThatTakesAnAddr(unsafeAddr myArray)
Procedures Procedures
========== ==========
@ -4327,6 +4411,34 @@ be inferred to have the equivalent of the `any` type class and thus they will
match anything without discrimination. match anything without discrimination.
Generic inference restrictions
------------------------------
The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic
instantiation. The following is not allowed:
.. code-block:: nim
:test: "nim c $1"
:status: 1
proc g[T](f: proc(x: T); x: T) =
f(x)
proc c(y: int) = echo y
proc v(y: var int) =
y += 100
var i: int
# allowed: infers 'T' to be of type 'int'
g(c, 42)
# not valid: 'T' is not inferred to be of type 'var int'
g(v, i)
# also not allowed: explict instantiation via 'var int'
g[var int](v, i)
Concepts Concepts
-------- --------
@ -4573,7 +4685,7 @@ type is an instance of it:
.. code-block:: nim .. code-block:: nim
:test: "nim c $1" :test: "nim c $1"
import future, typetraits import sugar, typetraits
type type
Functor[A] = concept f Functor[A] = concept f
@ -5399,12 +5511,17 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
newFor.add x[^2][1] newFor.add x[^2][1]
newFor.add body newFor.add body
result.add newFor result.add newFor
# now wrap the whole macro in a block to create a new scope
result = quote do:
block: `result`
for a, b in enumerate(items([1, 2, 3])): for a, b in enumerate(items([1, 2, 3])):
echo a, " ", b echo a, " ", b
for a2, b2 in enumerate([1, 2, 3, 5]): # without wrapping the macro in a block, we'd need to choose different
echo a2, " ", b2 # names for `a` and `b` here to avoid redefinition errors
for a, b in enumerate([1, 2, 3, 5]):
echo a, " ", b
Currently for loop macros must be enabled explicitly Currently for loop macros must be enabled explicitly
@ -5414,12 +5531,11 @@ via ``{.experimental: "forLoopMacros".}``.
Case statement macros Case statement macros
--------------------- ---------------------
A macro that needs to be called `match`:idx: can be used to A macro that needs to be called `match`:idx: can be used to rewrite
rewrite ``case`` statements in order to ``case`` statements in order to implement `pattern matching`:idx: for
implement `pattern matching`:idx: for certain types. The following certain types. The following example implements a simplistic form of
example implements a simplistic form of pattern matching for tuples, pattern matching for tuples, leveraging the existing equality operator
leveraging the existing equality operator for tuples (as provided in for tuples (as provided in ``system.==``):
``system.==``):
.. code-block:: nim .. code-block:: nim
:test: "nim c $1" :test: "nim c $1"
@ -6448,6 +6564,11 @@ The deprecated pragma is used to mark a symbol as deprecated:
proc p() {.deprecated.} proc p() {.deprecated.}
var x {.deprecated.}: char var x {.deprecated.}: char
This pragma can also take in an optional warning string to relay to developers.
.. code-block:: nim
proc thing(x: bool) {.deprecated: "See arguments of otherThing()".}
It can also be used as a statement, in that case it takes a list of *renamings*. It can also be used as a statement, in that case it takes a list of *renamings*.
.. code-block:: nim .. code-block:: nim
@ -6456,7 +6577,6 @@ It can also be used as a statement, in that case it takes a list of *renamings*.
Stream = ref object Stream = ref object
{.deprecated: [TFile: File, PStream: Stream].} {.deprecated: [TFile: File, PStream: Stream].}
noSideEffect pragma noSideEffect pragma
------------------- -------------------
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
@ -6942,12 +7062,36 @@ Example:
.. code-block:: nim .. code-block:: nim
{.experimental: "parallel".} {.experimental: "parallel".}
proc useUsing(bar, foo) = proc useParallel() =
parallel: parallel:
for i in 0..4: for i in 0..4:
echo "echo in parallel" echo "echo in parallel"
As a top level statement, the experimental pragma enables a feature for the
rest of the module it's enabled in. This is problematic for macro and generic
instantiations that cross a module scope. Currently these usages have to be
put into a ``.push/pop`` environment:
.. code-block:: nim
# client.nim
proc useParallel*[T](unused: T) =
# use a generic T here to show the problem.
{.push experimental: "parallel".}
parallel:
for i in 0..4:
echo "echo in parallel"
{.pop.}
.. code-block:: nim
import client
useParallel(1)
Implementation Specific Pragmas Implementation Specific Pragmas
=============================== ===============================

View file

@ -60,7 +60,7 @@ Spacing and Whitespace Conventions
Naming Conventions Naming Conventions
------------------------- ------------------
Note: While the rules outlined below are the *current* naming conventions, Note: While the rules outlined below are the *current* naming conventions,
these conventions have not always been in place. Previously, the naming these conventions have not always been in place. Previously, the naming
@ -147,6 +147,80 @@ changed in the future.
an in-place version should get an ``-In`` suffix (``replaceIn`` for this example). an in-place version should get an ``-In`` suffix (``replaceIn`` for this example).
The stdlib API is designed to be **easy to use** and consistent. Ease of use is
measured by the number of calls to achieve a concrete high level action. The
ultimate goal is that the programmer can *guess* a name.
The library uses a simple naming scheme that makes use of common abbreviations
to keep the names short but meaningful.
------------------- ------------ --------------------------------------
English word To use Notes
------------------- ------------ --------------------------------------
initialize initT ``init`` is used to create a
value type ``T``
new newP ``new`` is used to create a
reference type ``P``
find find should return the position where
something was found; for a bool result
use ``contains``
contains contains often short for ``find() >= 0``
append add use ``add`` instead of ``append``
compare cmp should return an int with the
``< 0`` ``== 0`` or ``> 0`` semantics;
for a bool result use ``sameXYZ``
put put, ``[]=`` consider overloading ``[]=`` for put
get get, ``[]`` consider overloading ``[]`` for get;
consider to not use ``get`` as a
prefix: ``len`` instead of ``getLen``
length len also used for *number of elements*
size size, len size should refer to a byte size
capacity cap
memory mem implies a low-level operation
items items default iterator over a collection
pairs pairs iterator over (key, value) pairs
delete delete, del del is supposed to be faster than
delete, because it does not keep
the order; delete keeps the order
remove delete, del inconsistent right now
include incl
exclude excl
command cmd
execute exec
environment env
variable var
value value, val val is preferred, inconsistent right
now
executable exe
directory dir
path path path is the string "/usr/bin" (for
example), dir is the content of
"/usr/bin"; inconsistent right now
extension ext
separator sep
column col, column col is preferred, inconsistent right
now
application app
configuration cfg
message msg
argument arg
object obj
parameter param
operator opr
procedure proc
function func
coordinate coord
rectangle rect
point point
symbol sym
literal lit
string str
identifier ident
indentation indent
------------------- ------------ --------------------------------------
Coding Conventions Coding Conventions
------------------ ------------------

View file

@ -143,6 +143,9 @@ which may be used in conjunction with the `compile time define
pragmas<manual.html#implementation-specific-pragmas-compile-time-define-pragmas>`_ pragmas<manual.html#implementation-specific-pragmas-compile-time-define-pragmas>`_
to override symbols during build time. to override symbols during build time.
Compile time symbols are completely **case insensitive** and underscores are
ignored too. ``--define:FOO`` and ``--define:foo`` are identical.
Configuration files Configuration files
------------------- -------------------
@ -326,9 +329,9 @@ The standard library supports a growing number of ``useX`` conditional defines
affecting how some features are implemented. This section tries to give a affecting how some features are implemented. This section tries to give a
complete list. complete list.
================== ========================================================= ====================== =========================================================
Define Effect Define Effect
================== ========================================================= ====================== =========================================================
``release`` Turns off runtime checks and turns on the optimizer. ``release`` Turns off runtime checks and turns on the optimizer.
``useWinAnsi`` Modules like ``os`` and ``osproc`` use the Ansi versions ``useWinAnsi`` Modules like ``os`` and ``osproc`` use the Ansi versions
of the Windows API. The default build uses the Unicode of the Windows API. The default build uses the Unicode
@ -358,8 +361,9 @@ Define Effect
``useShPath`` This symbol takes a string as its value, like ``useShPath`` This symbol takes a string as its value, like
``--define:useShPath:/opt/sh/bin/sh`` to override the ``--define:useShPath:/opt/sh/bin/sh`` to override the
path for the ``sh`` binary, in cases where it is not path for the ``sh`` binary, in cases where it is not
located in the default location ``/bin/sh`` located in the default location ``/bin/sh``.
================== ========================================================= ``noSignalHandler`` Disable the crash handler from ``system.nim``.
====================== =========================================================
@ -529,6 +533,16 @@ See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
information. information.
Signal handling in Nim
======================
The Nim programming language has no concept of Posix's signal handling
mechanisms. However, the standard library offers some rudimentary support
for signal handling, in particular, segmentation faults are turned into
fatal errors that produce a stack trace. This can be disabled with the
``-d:noSignalHandler`` switch.
Debugging with Nim Debugging with Nim
================== ==================

View file

@ -1112,21 +1112,12 @@ proc can convert it to its underlying integer value.
For better interfacing to other programming languages, the symbols of enum For better interfacing to other programming languages, the symbols of enum
types can be assigned an explicit ordinal value. However, the ordinal values types can be assigned an explicit ordinal value. However, the ordinal values
must be in ascending order. A symbol whose ordinal value is not must be in ascending order.
explicitly given is assigned the value of the previous symbol + 1.
An explicit ordered enum can have *holes*:
.. code-block:: nim
:test: "nim c $1"
type
MyEnum = enum
a = 2, b = 4, c = 89
Ordinal types Ordinal types
------------- -------------
Enumerations without holes, integer types, ``char`` and ``bool`` (and Enumerations, integer types, ``char`` and ``bool`` (and
subranges) are called ordinal types. Ordinal types have quite subranges) are called ordinal types. Ordinal types have quite
a few special operations: a few special operations:

View file

@ -1,114 +0,0 @@
# Horrible example of how to interface with a C++ engine ... ;-)
{.link: "/usr/lib/libIrrlicht.so".}
{.emit: """
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
""".}
const
irr = "<irrlicht/irrlicht.h>"
type
TDimension2d {.final, header: irr, importc: "dimension2d".} = object
Tvector3df {.final, header: irr, importc: "vector3df".} = object
TColor {.final, header: irr, importc: "SColor".} = object
TIrrlichtDevice {.final, header: irr, importc: "IrrlichtDevice".} = object
TIVideoDriver {.final, header: irr, importc: "IVideoDriver".} = object
TISceneManager {.final, header: irr, importc: "ISceneManager".} = object
TIGUIEnvironment {.final, header: irr, importc: "IGUIEnvironment".} = object
TIAnimatedMesh {.final, header: irr, importc: "IAnimatedMesh".} = object
TIAnimatedMeshSceneNode {.final, header: irr,
importc: "IAnimatedMeshSceneNode".} = object
TITexture {.final, header: irr, importc: "ITexture".} = object
PIrrlichtDevice = ptr TIrrlichtDevice
PIVideoDriver = ptr TIVideoDriver
PISceneManager = ptr TISceneManager
PIGUIEnvironment = ptr TIGUIEnvironment
PIAnimatedMesh = ptr TIAnimatedMesh
PIAnimatedMeshSceneNode = ptr TIAnimatedMeshSceneNode
PITexture = ptr TITexture
proc dimension2d(x, y: cint): TDimension2d {.
header: irr, importc: "dimension2d<u32>".}
proc vector3df(x,y,z: cint): Tvector3df {.
header: irr, importc: "vector3df".}
proc SColor(r,g,b,a: cint): TColor {.
header: irr, importc: "SColor".}
proc createDevice(): PIrrlichtDevice {.
header: irr, importc: "createDevice".}
proc run(device: PIrrlichtDevice): bool {.
header: irr, importcpp: "run".}
proc getVideoDriver(dev: PIrrlichtDevice): PIVideoDriver {.
header: irr, importcpp: "getVideoDriver".}
proc getSceneManager(dev: PIrrlichtDevice): PISceneManager {.
header: irr, importcpp: "getSceneManager".}
proc getGUIEnvironment(dev: PIrrlichtDevice): PIGUIEnvironment {.
header: irr, importcpp: "getGUIEnvironment".}
proc getMesh(smgr: PISceneManager, path: cstring): PIAnimatedMesh {.
header: irr, importcpp: "getMesh".}
proc drawAll(smgr: PISceneManager) {.
header: irr, importcpp: "drawAll".}
proc drawAll(guienv: PIGUIEnvironment) {.
header: irr, importcpp: "drawAll".}
proc drop(dev: PIrrlichtDevice) {.
header: irr, importcpp: "drop".}
proc getTexture(driver: PIVideoDriver, path: cstring): PITexture {.
header: irr, importcpp: "getTexture".}
proc endScene(driver: PIVideoDriver) {.
header: irr, importcpp: "endScene".}
proc beginScene(driver: PIVideoDriver, a, b: bool, c: TColor) {.
header: irr, importcpp: "beginScene".}
proc addAnimatedMeshSceneNode(
smgr: PISceneManager, mesh: PIAnimatedMesh): PIAnimatedMeshSceneNode {.
header: irr, importcpp: "addAnimatedMeshSceneNode".}
proc setMaterialTexture(n: PIAnimatedMeshSceneNode, x: cint, t: PITexture) {.
header: irr, importcpp: "setMaterialTexture".}
proc addCameraSceneNode(smgr: PISceneManager, x: cint, a, b: TVector3df) {.
header: irr, importcpp: "addCameraSceneNode".}
var device = createDevice()
if device == nil: quit "device is nil"
var driver = device.getVideoDriver()
var smgr = device.getSceneManager()
var guienv = device.getGUIEnvironment()
var mesh = smgr.getMesh("/home/andreas/download/irrlicht-1.7.2/media/sydney.md2")
if mesh == nil:
device.drop()
quit "no mesh!"
var node = smgr.addAnimatedMeshSceneNode(mesh)
if node != nil:
#node->setMaterialFlag(EMF_LIGHTING, false)
#node->setMD2Animation(scene::EMAT_STAND)
node.setMaterialTexture(0,
driver.getTexture(
"/home/andreas/download/irrlicht-1.7.2/media/media/sydney.bmp"))
smgr.addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0))
while device.run():
driver.beginScene(true, true, SColor(255,100,101,140))
smgr.drawAll()
guienv.drawAll()
driver.endScene()
device.drop()

View file

@ -1,11 +0,0 @@
#!/usr/bin/env python
import BaseHTTPServer
import CGIHTTPServer
server = BaseHTTPServer.HTTPServer
handler = CGIHTTPServer.CGIHTTPRequestHandler
server_address = ('localhost', 8008)
handler.cgi_directories = ['/']
httpd = server(server_address, handler)
httpd.serve_forever()

View file

@ -1,5 +0,0 @@
import cgi
cgi.setStackTraceStdout()
var a: string = nil
a.add "foobar"

View file

@ -1,7 +0,0 @@
import cgi
write(stdout, "Content-type: text/html\n\n")
write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
write(stdout, "<html><head><title>Test</title></head><body>\n")
write(stdout, "Hello!")
writeLine(stdout, "</body></html>")

View file

@ -1,12 +0,0 @@
# Test/show CGI module
import strtabs, cgi
var myData = readData()
validateData(myData, "name", "password")
writeContentType()
write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
write(stdout, "<html><head><title>Test</title></head><body>\n")
writeLine(stdout, "name: " & myData["name"])
writeLine(stdout, "password: " & myData["password"])
writeLine(stdout, "</body></html>")

View file

@ -1,12 +0,0 @@
# Android specific absolute paths.
android/bin/
android/gen/
android/jni/backend-jni.h
android/libs/
android/local.properties
android/obj/
android/tags
# iOS specific absolute paths
ios/resources/ui/*.m
ios/tags

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.nimrod.crosscalculator"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="3" />
<application android:label="@string/app_name" android:debuggable="true">
<activity android:name=".CrossCalculator"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="CrossCalculator" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules" default="debug">
<target name="nim">
<exec executable="scripts/nimbuild.sh" failonerror="true">
</exec>
</target>
<target name="jni">
<exec executable="scripts/jnibuild.sh" failonerror="true">
</exec>
</target>
<target name="ndk">
<exec executable="ndk-build" failonerror="true">
</exec>
</target>
<target name="-post-compile" depends="nim, jni, ndk">
</target>
</project>

View file

@ -1,32 +0,0 @@
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nimrod
LOCAL_SRC_FILES := nimcache/backend.c nimcache/system.c
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/nimcache
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := backend-jni
LOCAL_SRC_FILES := backend-jni.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_STATIC_LIBRARIES := nimrod
include $(BUILD_SHARED_LIBRARY)

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <android/log.h>
#include <string.h>
#include "backend-jni.h"
#include "backend.h"
#define TAG "backend-jni.c"
jint JNICALL Java_com_github_nimrod_crosscalculator_CrossCalculator_myAdd
(JNIEnv *env, jobject thiz, jint a, jint b)
{
char buf[256];
const jint ret = myAdd(a, b);
// Using logging from inside the native bridge to log-debug.
sprintf(buf, "a %d + b %d = ret %d", a, b, ret);
__android_log_write(ANDROID_LOG_DEBUG, TAG, buf);
return ret;
}
void JNICALL Java_com_github_nimrod_crosscalculator_CrossCalculator_initNimMain
(JNIEnv *env, jclass thiz)
{
NimMain();
__android_log_write(ANDROID_LOG_DEBUG, TAG, "Nimrod initialised");
}
// vim:tabstop=2 shiftwidth=2 syntax=c

View file

@ -1,14 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-3

View file

@ -1,24 +0,0 @@
In this directory you will find the Android platform cross-calculator sample.
Due to the nature of Android being java and Nim generating C code, the build
process is slightly more complex because jni code has to be written to bridge
both languages. In a distant future it may be possible for Nim to generate
the whole jni bridge, but for the moment this is manual work.
For the jni bridge to work first the java code is compiled with the Nim code
just declared as a native method which will be resolved at runtime. The scripts
nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
generating the jni bridge from the java code respectively. Finally, the
ndk-build command from the android ndk tools has to be run to build the binary
library which will be installed along the final apk.
All these steps are wrapped in the ant build script through the customization
of the -post-compile rule. If you have the android ndk tools installed and you
modify scripts/nimbuild.sh to point to the directory where you have Nim
installed on your system, you can simply run "ant debug" to build everything.
Once the apk is built you can install it on your device or emulator with the
command "adb install bin/CrossCalculator-debug.apk".
This example runs against the Android level 3 API, meaning devices from
Android 1.5 and above should be able to run the generated binary.

View file

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="Crossplatform Nimrod calculator"
android:textSize="20dip" >
</TextView>
<TextView
android:id="@+id/value_a"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/title"
android:text="Value A: " >
</TextView>
<EditText
android:id="@+id/edit_text_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/title"
android:ems="10"
android:inputType="number" />
<TextView
android:id="@+id/value_b"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/edit_text_a"
android:text="Value B: " >
</TextView>
<EditText
android:id="@+id/edit_text_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/edit_text_a"
android:ems="10"
android:inputType="number" />
<Button
android:id="@+id/add_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/edit_text_b"
android:scrollbarAlwaysDrawVerticalTrack="false"
android:selectAllOnFocus="false"
android:text="Add!"
android:visibility="visible" />
<TextView
android:id="@+id/result_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/add_button" />
</RelativeLayout>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">CrossCalculator</string>
</resources>

View file

@ -1,22 +0,0 @@
#!/bin/sh
# Force errors to fail script.
set -e
# If we are running from inside the scripts subdir, get out.
if [ ! -d src ]
then
cd ..
fi
# Ok, are we out now?
if [ -d src ]
then
javah -classpath bin/classes \
-o jni/backend-jni.h \
com.github.nimrod.crosscalculator.CrossCalculator
else
echo "Uh oh, bin/classes directory not found?"
echo "Try compiling your java code, or opening in eclipse."
exit 1
fi

View file

@ -1,34 +0,0 @@
#!/bin/sh
# Set this to the local or full path of your nimrod compiler
PATH_TO_NIMROD=~/project/nimrod/bin/nimrod
# Set this to the location of the nimbase.h file so
# the script can update it if it changes.
PATH_TO_NIMBASE=~/project/nimrod/lib/nimbase.h
# Force errors to fail script.
set -e
# If we are running from inside the scripts subdir, get out.
if [ ! -d src ]
then
cd ..
fi
DEST_NIMBASE=jni/nimcache/nimbase.h
# Ok, are we out now?
if [ -d src ]
then
$PATH_TO_NIMROD c --noMain --app:lib \
--nimcache:jni/nimcache --cpu:arm --os:linux \
--compileOnly --header ../nimrod_backend/*.nim
if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
then
echo "Updating nimbase.h"
cp "${PATH_TO_NIMBASE}" "${DEST_NIMBASE}"
fi
else
echo "Uh oh, src directory not found?"
exit 1
fi

View file

@ -1,13 +0,0 @@
#!/bin/sh
if [ ! -d src ]
then
cd ..
fi
if [ -d src ]
then
~/bin/objctags -R \
jni \
src
fi

View file

@ -1,80 +0,0 @@
package com.github.nimrod.crosscalculator;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class CrossCalculator extends Activity
{
private static final String TAG = "CrossCalculator";
private TextView result_text;
private EditText edit_text_a, edit_text_b;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.cross_calculator);
final Button button = (Button)findViewById(R.id.add_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { addButtonClicked(); } });
result_text = (TextView)findViewById(R.id.result_text);
edit_text_a = (EditText)findViewById(R.id.edit_text_a);
edit_text_b = (EditText)findViewById(R.id.edit_text_b);
}
/** Handles clicks on the addition button.
* Reads the values form the input fields and performs the calculation.
*/
private void addButtonClicked()
{
int a = 0, b = 0;
String errors = "";
final String a_text = edit_text_a.getText().toString();
final String b_text = edit_text_b.getText().toString();
try {
a = Integer.valueOf(a_text, 10);
} catch (NumberFormatException e) {
errors += "Can't parse a value '" + a_text + "'. ";
}
try {
b = Integer.valueOf(b_text, 10);
} catch (NumberFormatException e) {
errors += "Can't parse b value '" + b_text + "'";
}
final int c = myAdd(a, b);
result_text.setText("myAdd(" + a + ", " + b + ") = " + c);
if (errors.length() > 0) {
Log.e(TAG, errors);
Toast.makeText(this, errors, Toast.LENGTH_SHORT).show();
}
}
/* A native method that is implemented by the
* 'backend-jni' native library, which is packaged
* with this application. Adds to integers.
*/
public native int myAdd(int a, int b);
/* A native method used to initialise Nimrod.
*/
static public native void initNimMain();
/* this is used to load the 'backend-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.github.nimrod.backendjni/lib/libbackend-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("backend-jni");
initNimMain();
}
}

View file

@ -1,337 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D531422A15BC8611005EFF20 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422915BC8611005EFF20 /* UIKit.framework */; };
D531422C15BC8611005EFF20 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422B15BC8611005EFF20 /* Foundation.framework */; };
D531422E15BC8611005EFF20 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422D15BC8611005EFF20 /* CoreGraphics.framework */; };
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424A15BC87B6005EFF20 /* AppDelegate.m */; };
D531424E15BC87B6005EFF20 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424B15BC87B6005EFF20 /* main.m */; };
D531427215BC94B1005EFF20 /* backend.m in Sources */ = {isa = PBXBuildFile; fileRef = D531426F15BC94B1005EFF20 /* backend.m */; };
D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */ = {isa = PBXBuildFile; fileRef = D531427115BC94B1005EFF20 /* stdlib_system.m */; };
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B6F94615FA8D4C0084A85B /* NRViewController.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
D531422515BC8611005EFF20 /* cross-calculator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "cross-calculator.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D531422915BC8611005EFF20 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
D531422B15BC8611005EFF20 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D531422D15BC8611005EFF20 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
D531424715BC87A5005EFF20 /* cross-calculator-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "cross-calculator-Info.plist"; path = "resources/plist/cross-calculator-Info.plist"; sourceTree = "<group>"; };
D531424915BC87B6005EFF20 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = src/AppDelegate.h; sourceTree = "<group>"; };
D531424A15BC87B6005EFF20 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = src/AppDelegate.m; sourceTree = "<group>"; };
D531424B15BC87B6005EFF20 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = src/main.m; sourceTree = "<group>"; };
D531424C15BC87B6005EFF20 /* cross-calculator-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cross-calculator-Prefix.pch"; path = "src/cross-calculator-Prefix.pch"; sourceTree = "<group>"; };
D531426715BC91EF005EFF20 /* tags.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = tags.sh; path = scripts/tags.sh; sourceTree = "<group>"; };
D531426815BC91EF005EFF20 /* xcode_prebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = xcode_prebuild.sh; path = scripts/xcode_prebuild.sh; sourceTree = "<group>"; };
D531426F15BC94B1005EFF20 /* backend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = backend.m; path = build/nimcache/backend.m; sourceTree = "<group>"; };
D531427115BC94B1005EFF20 /* stdlib_system.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = stdlib_system.m; path = build/nimcache/stdlib_system.m; sourceTree = "<group>"; };
D592E19015C7120F005258EA /* backend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = backend.h; path = build/nimcache/backend.h; sourceTree = "<group>"; };
D592E19115C71415005258EA /* nimbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nimbase.h; path = build/nimcache/nimbase.h; sourceTree = "<group>"; };
D5B6F94515FA8D4C0084A85B /* NRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NRViewController.h; path = src/NRViewController.h; sourceTree = "<group>"; };
D5B6F94615FA8D4C0084A85B /* NRViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NRViewController.m; path = src/NRViewController.m; sourceTree = "<group>"; };
D5B6F96315FB448D0084A85B /* NRViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = NRViewController.xib; path = resources/ui/NRViewController.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D531422215BC8610005EFF20 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D531422A15BC8611005EFF20 /* UIKit.framework in Frameworks */,
D531422C15BC8611005EFF20 /* Foundation.framework in Frameworks */,
D531422E15BC8611005EFF20 /* CoreGraphics.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D531421A15BC8610005EFF20 = {
isa = PBXGroup;
children = (
D531426A15BC93D5005EFF20 /* build */,
D531424515BC874E005EFF20 /* resources */,
D531426615BC91E1005EFF20 /* scripts */,
D531424815BC87AD005EFF20 /* src */,
D531422815BC8611005EFF20 /* Frameworks */,
D531422615BC8611005EFF20 /* Products */,
);
sourceTree = "<group>";
};
D531422615BC8611005EFF20 /* Products */ = {
isa = PBXGroup;
children = (
D531422515BC8611005EFF20 /* cross-calculator.app */,
);
name = Products;
sourceTree = "<group>";
};
D531422815BC8611005EFF20 /* Frameworks */ = {
isa = PBXGroup;
children = (
D531422915BC8611005EFF20 /* UIKit.framework */,
D531422B15BC8611005EFF20 /* Foundation.framework */,
D531422D15BC8611005EFF20 /* CoreGraphics.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
D531424515BC874E005EFF20 /* resources */ = {
isa = PBXGroup;
children = (
D531424615BC8756005EFF20 /* plist */,
D5B6F96115FB447C0084A85B /* ui */,
);
name = resources;
sourceTree = "<group>";
};
D531424615BC8756005EFF20 /* plist */ = {
isa = PBXGroup;
children = (
D531424715BC87A5005EFF20 /* cross-calculator-Info.plist */,
);
name = plist;
sourceTree = "<group>";
};
D531424815BC87AD005EFF20 /* src */ = {
isa = PBXGroup;
children = (
D531424915BC87B6005EFF20 /* AppDelegate.h */,
D531424A15BC87B6005EFF20 /* AppDelegate.m */,
D531424C15BC87B6005EFF20 /* cross-calculator-Prefix.pch */,
D531424B15BC87B6005EFF20 /* main.m */,
D5B6F94515FA8D4C0084A85B /* NRViewController.h */,
D5B6F94615FA8D4C0084A85B /* NRViewController.m */,
);
name = src;
sourceTree = "<group>";
};
D531426615BC91E1005EFF20 /* scripts */ = {
isa = PBXGroup;
children = (
D531426715BC91EF005EFF20 /* tags.sh */,
D531426815BC91EF005EFF20 /* xcode_prebuild.sh */,
);
name = scripts;
sourceTree = "<group>";
};
D531426A15BC93D5005EFF20 /* build */ = {
isa = PBXGroup;
children = (
D531426E15BC94A6005EFF20 /* nimrod */,
);
name = build;
sourceTree = "<group>";
};
D531426E15BC94A6005EFF20 /* nimrod */ = {
isa = PBXGroup;
children = (
D592E19015C7120F005258EA /* backend.h */,
D531426F15BC94B1005EFF20 /* backend.m */,
D592E19115C71415005258EA /* nimbase.h */,
D531427115BC94B1005EFF20 /* stdlib_system.m */,
);
name = nimrod;
sourceTree = "<group>";
};
D5B6F96115FB447C0084A85B /* ui */ = {
isa = PBXGroup;
children = (
D5B6F96315FB448D0084A85B /* NRViewController.xib */,
);
name = ui;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
D531422415BC8610005EFF20 /* cross-calculator */ = {
isa = PBXNativeTarget;
buildConfigurationList = D531423D15BC8611005EFF20 /* Build configuration list for PBXNativeTarget "cross-calculator" */;
buildPhases = (
D531426915BC926C005EFF20 /* ShellScript */,
D531422115BC8610005EFF20 /* Sources */,
D531422215BC8610005EFF20 /* Frameworks */,
D531422315BC8610005EFF20 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "cross-calculator";
productName = "cross-calculator";
productReference = D531422515BC8611005EFF20 /* cross-calculator.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D531421C15BC8610005EFF20 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0420;
ORGANIZATIONNAME = "Electric Hands Software";
};
buildConfigurationList = D531421F15BC8610005EFF20 /* Build configuration list for PBXProject "cross-calculator" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = D531421A15BC8610005EFF20;
productRefGroup = D531422615BC8611005EFF20 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D531422415BC8610005EFF20 /* cross-calculator */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D531422315BC8610005EFF20 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
D531426915BC926C005EFF20 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = scripts/xcode_prebuild.sh;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D531422115BC8610005EFF20 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */,
D531424E15BC87B6005EFF20 /* main.m in Sources */,
D531427215BC94B1005EFF20 /* backend.m in Sources */,
D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */,
D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
D531423B15BC8611005EFF20 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = (
armv7,
armv6,
);
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
D531423C15BC8611005EFF20 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = (
armv7,
armv6,
);
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D531423E15BC8611005EFF20 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "src/cross-calculator-Prefix.pch";
INFOPLIST_FILE = "resources/plist/cross-calculator-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
D531423F15BC8611005EFF20 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "src/cross-calculator-Prefix.pch";
INFOPLIST_FILE = "resources/plist/cross-calculator-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D531421F15BC8610005EFF20 /* Build configuration list for PBXProject "cross-calculator" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D531423B15BC8611005EFF20 /* Debug */,
D531423C15BC8611005EFF20 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D531423D15BC8611005EFF20 /* Build configuration list for PBXNativeTarget "cross-calculator" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D531423E15BC8611005EFF20 /* Debug */,
D531423F15BC8611005EFF20 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D531421C15BC8610005EFF20 /* Project object */;
}

View file

@ -1,13 +0,0 @@
In this directory you will find the iOS platform cross-calculator sample.
The iOS version of the code builds a view controller in charge of displaying
the interface to the user. The Nim backend code is compiled into C code and
put into build/nimrod as a pre-build phase of the project.
When the calculate button is used the view controller calls the Nim code to
delegate the logic of the operation and puts the result in a label for display.
All interface error checks are implemented in the view controller.
This version of the iOS project is known to work with Xcode 4.2 and Xcode
4.4.1. The final binary can be deployed on iOS 3.x to 5.x supporting all iOS
platforms and versions available at the moment.

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFiles</key>
<array/>
<key>CFBundleIdentifier</key>
<string>com.github.nimrod.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIApplicationExitsOnSuspend</key>
<true/>
</dict>
</plist>

View file

@ -1,479 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
<data>
<int key="IBDocument.SystemTarget">0</int>
<string key="IBDocument.SystemVersion">11E53</string>
<string key="IBDocument.InterfaceBuilderVersion">2549</string>
<string key="IBDocument.AppKitVersion">1138.47</string>
<string key="IBDocument.HIToolboxVersion">569.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="NS.object.0">1498</string>
</object>
<array key="IBDocument.IntegratedClassDependencies">
<string>IBProxyObject</string>
<string>IBUIButton</string>
<string>IBUILabel</string>
<string>IBUITextField</string>
<string>IBUIView</string>
</array>
<array key="IBDocument.PluginDependencies">
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</array>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
<integer value="1" key="NS.object.0"/>
</object>
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<object class="IBProxyObject" id="372490531">
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBProxyObject" id="975951072">
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBUIView" id="191373211">
<reference key="NSNextResponder"/>
<int key="NSvFlags">274</int>
<array class="NSMutableArray" key="NSSubviews">
<object class="IBUIButton" id="467453084">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">292</int>
<string key="NSFrame">{{0, -10}, {320, 480}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">1</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
<object class="NSColor" key="IBUIHighlightedTitleColor" id="95215378">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes>
</object>
<object class="NSColor" key="IBUINormalTitleColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
</object>
<object class="NSColor" key="IBUINormalTitleShadowColor" id="1056499111">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC41AA</bytes>
</object>
<object class="IBUIFontDescription" key="IBUIFontDescription" id="686052398">
<int key="type">2</int>
<double key="pointSize">15</double>
</object>
<object class="NSFont" key="IBUIFont" id="594372787">
<string key="NSName">Helvetica-Bold</string>
<double key="NSSize">15</double>
<int key="NSfFlags">16</int>
</object>
</object>
<object class="IBUILabel" id="353054360">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">306</int>
<string key="NSFrameSize">{320, 34}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="525225214"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUIContentMode">7</int>
<int key="IBUITag">2</int>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText">Nim Crossplatform Calculator</string>
<object class="NSColor" key="IBUITextColor" id="128895179">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MCAwIDAAA</bytes>
</object>
<nil key="IBUIHighlightedColor"/>
<int key="IBUIBaselineAdjustment">0</int>
<float key="IBUIMinimumFontSize">10</float>
<int key="IBUITextAlignment">1</int>
<object class="IBUIFontDescription" key="IBUIFontDescription">
<int key="type">2</int>
<double key="pointSize">18</double>
</object>
<object class="NSFont" key="IBUIFont">
<string key="NSName">Helvetica-Bold</string>
<double key="NSSize">18</double>
<int key="NSfFlags">16</int>
</object>
</object>
<object class="IBUILabel" id="525225214">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">294</int>
<string key="NSFrame">{{20, 42}, {165, 31}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="1040444341"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUIContentMode">7</int>
<int key="IBUITag">3</int>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText">Value A:</string>
<reference key="IBUITextColor" ref="128895179"/>
<nil key="IBUIHighlightedColor"/>
<int key="IBUIBaselineAdjustment">0</int>
<float key="IBUIMinimumFontSize">10</float>
<object class="IBUIFontDescription" key="IBUIFontDescription" id="768572949">
<int key="type">1</int>
<double key="pointSize">17</double>
</object>
<object class="NSFont" key="IBUIFont" id="972319481">
<string key="NSName">Helvetica</string>
<double key="NSSize">17</double>
<int key="NSfFlags">16</int>
</object>
</object>
<object class="IBUILabel" id="904781109">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">294</int>
<string key="NSFrame">{{20, 81}, {165, 31}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="1041721572"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUIContentMode">7</int>
<int key="IBUITag">4</int>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText">Value B:</string>
<reference key="IBUITextColor" ref="128895179"/>
<nil key="IBUIHighlightedColor"/>
<int key="IBUIBaselineAdjustment">0</int>
<float key="IBUIMinimumFontSize">10</float>
<reference key="IBUIFontDescription" ref="768572949"/>
<reference key="IBUIFont" ref="972319481"/>
</object>
<object class="IBUIButton" id="557594991">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">291</int>
<string key="NSFrame">{{193, 124}, {107, 37}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<int key="IBUITag">5</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
<int key="IBUIContentVerticalAlignment">0</int>
<int key="IBUIButtonType">1</int>
<string key="IBUINormalTitle">Add!</string>
<reference key="IBUIHighlightedTitleColor" ref="95215378"/>
<object class="NSColor" key="IBUINormalTitleColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
</object>
<reference key="IBUINormalTitleShadowColor" ref="1056499111"/>
<reference key="IBUIFontDescription" ref="686052398"/>
<reference key="IBUIFont" ref="594372787"/>
</object>
<object class="IBUILabel" id="360864196">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 124}, {60, 37}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="521073831"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUIContentMode">7</int>
<int key="IBUITag">6</int>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText">Result:</string>
<reference key="IBUITextColor" ref="128895179"/>
<nil key="IBUIHighlightedColor"/>
<int key="IBUIBaselineAdjustment">0</int>
<float key="IBUIMinimumFontSize">10</float>
<reference key="IBUIFontDescription" ref="768572949"/>
<reference key="IBUIFont" ref="972319481"/>
</object>
<object class="IBUILabel" id="521073831">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">294</int>
<string key="NSFrame">{{88, 124}, {97, 37}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="557594991"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUIContentMode">7</int>
<int key="IBUITag">7</int>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<string key="IBUIText"/>
<reference key="IBUITextColor" ref="128895179"/>
<nil key="IBUIHighlightedColor"/>
<int key="IBUIBaselineAdjustment">0</int>
<float key="IBUIMinimumFontSize">10</float>
<reference key="IBUIFontDescription" ref="768572949"/>
<reference key="IBUIFont" ref="972319481"/>
</object>
<object class="IBUITextField" id="1040444341">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">291</int>
<string key="NSFrame">{{193, 42}, {107, 31}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="904781109"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUITag">8</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentVerticalAlignment">0</int>
<string key="IBUIText"/>
<int key="IBUIBorderStyle">3</int>
<string key="IBUIPlaceholder">Integer</string>
<object class="NSColor" key="IBUITextColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
<object class="NSColorSpace" key="NSCustomColorSpace" id="433120901">
<int key="NSID">2</int>
</object>
</object>
<int key="IBUITextAlignment">1</int>
<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
<float key="IBUIMinimumFontSize">17</float>
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
<int key="IBUIKeyboardType">4</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<int key="IBUIClearButtonMode">1</int>
<object class="IBUIFontDescription" key="IBUIFontDescription" id="836805198">
<int key="type">1</int>
<double key="pointSize">14</double>
</object>
<object class="NSFont" key="IBUIFont" id="700927782">
<string key="NSName">Helvetica</string>
<double key="NSSize">14</double>
<int key="NSfFlags">16</int>
</object>
</object>
<object class="IBUITextField" id="1041721572">
<reference key="NSNextResponder" ref="191373211"/>
<int key="NSvFlags">291</int>
<string key="NSFrame">{{193, 81}, {107, 31}}</string>
<reference key="NSSuperview" ref="191373211"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="360864196"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
<int key="IBUITag">9</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentVerticalAlignment">0</int>
<string key="IBUIText"/>
<int key="IBUIBorderStyle">3</int>
<string key="IBUIPlaceholder">Integer</string>
<object class="NSColor" key="IBUITextColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
<reference key="NSCustomColorSpace" ref="433120901"/>
</object>
<int key="IBUITextAlignment">1</int>
<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
<float key="IBUIMinimumFontSize">17</float>
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
<int key="IBUIKeyboardType">4</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<int key="IBUIClearButtonMode">1</int>
<reference key="IBUIFontDescription" ref="836805198"/>
<reference key="IBUIFont" ref="700927782"/>
</object>
</array>
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="353054360"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes>
<reference key="NSCustomColorSpace" ref="433120901"/>
</object>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
</array>
<object class="IBObjectContainer" key="IBDocument.Objects">
<array class="NSMutableArray" key="connectionRecords"/>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
<object class="IBObjectRecord">
<int key="objectID">0</int>
<array key="object" id="0"/>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1</int>
<reference key="object" ref="191373211"/>
<array class="NSMutableArray" key="children">
<reference ref="353054360"/>
<reference ref="525225214"/>
<reference ref="904781109"/>
<reference ref="557594991"/>
<reference ref="360864196"/>
<reference ref="521073831"/>
<reference ref="1040444341"/>
<reference ref="1041721572"/>
<reference ref="467453084"/>
</array>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="372490531"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="975951072"/>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">14</int>
<reference key="object" ref="1041721572"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">13</int>
<reference key="object" ref="1040444341"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">12</int>
<reference key="object" ref="521073831"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">11</int>
<reference key="object" ref="360864196"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">10</int>
<reference key="object" ref="557594991"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">8</int>
<reference key="object" ref="904781109"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">7</int>
<reference key="object" ref="525225214"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">4</int>
<reference key="object" ref="353054360"/>
<reference key="parent" ref="191373211"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">22</int>
<reference key="object" ref="467453084"/>
<reference key="parent" ref="191373211"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
<string key="-1.CustomClassName">NRViewController</string>
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="-2.CustomClassName">UIResponder</string>
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="10.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="12.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="13.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="14.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="22.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="7.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="8.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">22</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">NRViewController</string>
<string key="superclassName">UIViewController</string>
<dictionary class="NSMutableDictionary" key="actions">
<string key="backgroundTouched">id</string>
<string key="calculateButtonTouched">id</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="actionInfosByName">
<object class="IBActionInfo" key="backgroundTouched">
<string key="name">backgroundTouched</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo" key="calculateButtonTouched">
<string key="name">calculateButtonTouched</string>
<string key="candidateClassName">id</string>
</object>
</dictionary>
<dictionary class="NSMutableDictionary" key="outlets">
<string key="aText">UITextField</string>
<string key="bText">UITextField</string>
<string key="calculateButton">UIButton</string>
<string key="resultLabel">UILabel</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
<object class="IBToOneOutletInfo" key="aText">
<string key="name">aText</string>
<string key="candidateClassName">UITextField</string>
</object>
<object class="IBToOneOutletInfo" key="bText">
<string key="name">bText</string>
<string key="candidateClassName">UITextField</string>
</object>
<object class="IBToOneOutletInfo" key="calculateButton">
<string key="name">calculateButton</string>
<string key="candidateClassName">UIButton</string>
</object>
<object class="IBToOneOutletInfo" key="resultLabel">
<string key="name">resultLabel</string>
<string key="candidateClassName">UILabel</string>
</object>
</dictionary>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/NRViewController.h</string>
</object>
</object>
</array>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
<real value="0.0" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<string key="IBCocoaTouchPluginVersion">1498</string>
</data>
</archive>

View file

@ -1,13 +0,0 @@
#!/bin/sh
if [ ! -d src ]
then
cd ..
fi
if [ -d src ]
then
~/bin/objctags -R \
build/nimcache \
src
fi

View file

@ -1,35 +0,0 @@
#!/bin/sh
# Set this to the full path of your nimrod compiler
# since Xcode doesn't inherit your user environment.
PATH_TO_NIMROD=~/project/nimrod/bin/nimrod
# Set this to the location of the nimbase.h file so
# the script can update it if it changes.
PATH_TO_NIMBASE=~/project/nimrod/lib/nimbase.h
# Force errors to fail script.
set -e
# If we are running from inside the scripts subdir, get out.
if [ ! -d src ]
then
cd ..
fi
DEST_NIMBASE=build/nimcache/nimbase.h
# Ok, are we out now?
if [ -d src ]
then
$PATH_TO_NIMROD objc --noMain --app:lib \
--nimcache:./build/nimcache --compileOnly \
--header --cpu:i386 ../nimrod_backend/backend.nim
if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
then
echo "Updating nimbase.h"
cp "${PATH_TO_NIMBASE}" "${DEST_NIMBASE}"
fi
else
echo "Uh oh, src directory not found?"
exit 1
fi

View file

@ -1,7 +0,0 @@
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View file

@ -1,39 +0,0 @@
#import "AppDelegate.h"
#import "NRViewController.h"
@interface AppDelegate ()
@property (nonatomic, retain) NRViewController *viewController;
@end
@implementation AppDelegate
@synthesize viewController = _viewController;
@synthesize window = _window;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController = [[NRViewController new] autorelease];
if ([self.window respondsToSelector:@selector(setRootViewController:)])
self.window.rootViewController = self.viewController;
else
[self.window addSubview:self.viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
@end

View file

@ -1,11 +0,0 @@
@interface NRViewController : UIViewController
@property (nonatomic, retain) IBOutlet UIButton *calculateButton;
@property (nonatomic, retain) IBOutlet UITextField *aText;
@property (nonatomic, retain) IBOutlet UITextField *bText;
@property (nonatomic, retain) IBOutlet UILabel *resultLabel;
- (IBAction)calculateButtonTouched;
- (IBAction)backgroundTouched;
@end

View file

@ -1,210 +0,0 @@
#import "NRViewController.h"
#import "backend.h"
@implementation NRViewController
@synthesize aText = _aText;
@synthesize bText = _bText;
@synthesize calculateButton = _calculateButton;
@synthesize resultLabel = _resultLabel;
- (void)dealloc
{
[_aText release];
[_bText release];
[_calculateButton release];
[_resultLabel release];
[super dealloc];
}
- (void)viewDidUnload
{
self.calculateButton = nil;
self.aText = nil;
self.bText = nil;
self.resultLabel = nil;
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
/// User wants to calculate the inputs. Well, do it!
- (IBAction)calculateButtonTouched
{
// Dismiss all keyboards.
[self backgroundTouched];
// Call Nim code, store the result and display it.
const int a = [self.aText.text intValue];
const int b = [self.bText.text intValue];
const int c = myAdd(a, b);
self.resultLabel.text = [NSString stringWithFormat:@"%d + %d = %d",
a, b, c];
}
/// If the user touches the background, dismiss any visible keyboard.
- (IBAction)backgroundTouched
{
[self.aText resignFirstResponder];
[self.bText resignFirstResponder];
}
/** Custom loadView method for backwards compatibility.
* Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
* which are compatible with my trusty iOS 3.0 ipod touch so in order to be
* fully compatible for all devices we have to build the interface manually in
* code rather than through the keyed archivers provided by the interface
* builder.
*
* Rather than recreating the user interface manually in code the tool nib2obj
* was used on the xib file and slightly modified to fit the original property
* names. Which means here is a lot of garbage you would never write in real
* life. Please ignore the following "wall of code" for the purposes of
* learning Nim, this is all just because Apple can't be bothered to
* maintain backwards compatibility properly.
*/
- (void)loadView
{
[super loadView];
self.calculateButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.calculateButton.autoresizesSubviews = YES;
self.calculateButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.calculateButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
self.calculateButton.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.calculateButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.calculateButton.frame = CGRectMake(193.0, 124.0, 107.0, 37.0);
self.calculateButton.tag = 5;
[self.calculateButton setTitle:@"Add!" forState:UIControlStateNormal];
[self.calculateButton addTarget:self
action:@selector(calculateButtonTouched)
forControlEvents:UIControlEventTouchUpInside];
UILabel *label11 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 124.0, 60.0, 37.0)];
label11.adjustsFontSizeToFitWidth = YES;
label11.autoresizesSubviews = YES;
label11.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
label11.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
label11.frame = CGRectMake(20.0, 124.0, 60.0, 37.0);
label11.tag = 6;
label11.text = @"Result:";
UILabel *label4 = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 34.0)];
label4.adjustsFontSizeToFitWidth = YES;
label4.autoresizesSubviews = YES;
label4.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
label4.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
label4.frame = CGRectMake(0.0, 0.0, 320.0, 34.0);
label4.tag = 2;
label4.text = @"Nim Crossplatform Calculator";
label4.textAlignment = UITextAlignmentCenter;
UIButton *background_button = [UIButton buttonWithType:UIButtonTypeCustom];
background_button.autoresizesSubviews = YES;
background_button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
background_button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
background_button.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
background_button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
background_button.frame = CGRectMake(0.0, -10.0, 320.0, 480.0);
background_button.tag = 1;
[background_button addTarget:self action:@selector(backgroundTouched)
forControlEvents:UIControlEventTouchDown];
self.resultLabel = [[[UILabel alloc] initWithFrame:CGRectMake(88.0, 124.0, 97.0, 37.0)] autorelease];
self.resultLabel.adjustsFontSizeToFitWidth = YES;
self.resultLabel.autoresizesSubviews = YES;
self.resultLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
self.resultLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.resultLabel.frame = CGRectMake(88.0, 124.0, 97.0, 37.0);
self.resultLabel.tag = 7;
self.resultLabel.text = @"";
self.aText = [[[UITextField alloc] initWithFrame:CGRectMake(193.0, 42.0, 107.0, 31.0)] autorelease];
self.aText.adjustsFontSizeToFitWidth = YES;
self.aText.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.aText.autocorrectionType = UITextAutocorrectionTypeDefault;
self.aText.autoresizesSubviews = YES;
self.aText.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.aText.borderStyle = UITextBorderStyleRoundedRect;
self.aText.clearButtonMode = UITextFieldViewModeWhileEditing;
self.aText.clearsOnBeginEditing = NO;
self.aText.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
self.aText.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.aText.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.aText.enablesReturnKeyAutomatically = NO;
self.aText.frame = CGRectMake(193.0, 42.0, 107.0, 31.0);
self.aText.keyboardAppearance = UIKeyboardAppearanceDefault;
self.aText.keyboardType = UIKeyboardTypeNumberPad;
self.aText.placeholder = @"Integer";
self.aText.returnKeyType = UIReturnKeyDefault;
self.aText.tag = 8;
self.aText.text = @"";
self.aText.textAlignment = UITextAlignmentCenter;
UILabel *label7 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 42.0, 165.0, 31.0)];
label7.adjustsFontSizeToFitWidth = YES;
label7.autoresizesSubviews = YES;
label7.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
label7.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
label7.frame = CGRectMake(20.0, 42.0, 165.0, 31.0);
label7.tag = 3;
label7.text = @"Value A:";
UILabel *label8 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 81.0, 165.0, 31.0)];
label8.adjustsFontSizeToFitWidth = YES;
label8.autoresizesSubviews = YES;
label8.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
label8.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
label8.frame = CGRectMake(20.0, 81.0, 165.0, 31.0);
label8.tag = 4;
label8.text = @"Value B:";
self.bText = [[[UITextField alloc]
initWithFrame:CGRectMake(193.0, 81.0, 107.0, 31.0)] autorelease];
self.bText.adjustsFontSizeToFitWidth = YES;
self.bText.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.bText.autocorrectionType = UITextAutocorrectionTypeDefault;
self.bText.autoresizesSubviews = YES;
self.bText.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.bText.borderStyle = UITextBorderStyleRoundedRect;
self.bText.clearButtonMode = UITextFieldViewModeWhileEditing;
self.bText.clearsOnBeginEditing = NO;
self.bText.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
self.bText.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.bText.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.bText.enablesReturnKeyAutomatically = NO;
self.bText.frame = CGRectMake(193.0, 81.0, 107.0, 31.0);
self.bText.keyboardAppearance = UIKeyboardAppearanceDefault;
self.bText.keyboardType = UIKeyboardTypeNumberPad;
self.bText.placeholder = @"Integer";
self.bText.returnKeyType = UIReturnKeyDefault;
self.bText.tag = 9;
self.bText.text = @"";
self.bText.textAlignment = UITextAlignmentCenter;
self.view.frame = CGRectMake(0.0, 20.0, 320.0, 460.0);
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.backgroundColor = [UIColor colorWithWhite:1.000 alpha:1.000];
self.view.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.view.frame = CGRectMake(0.0, 20.0, 320.0, 460.0);
self.view.tag = 0;
[self.view addSubview:background_button];
[self.view addSubview:label4];
[self.view addSubview:label7];
[self.view addSubview:label8];
[self.view addSubview:self.calculateButton];
[self.view addSubview:label11];
[self.view addSubview:self.resultLabel];
[self.view addSubview:self.aText];
[self.view addSubview:self.bText];
}
@end

View file

@ -1,10 +0,0 @@
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif

View file

@ -1,13 +0,0 @@
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "backend.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
NimMain();
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
}
}

View file

@ -1,140 +0,0 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="7"/>
<General>
<Flags>
<LRSInOutputDirectory Value="False"/>
</Flags>
<MainUnit Value="0"/>
<TargetFileExt Value=".exe"/>
<UseXPManifest Value="True"/>
<ActiveEditorIndexAtStart Value="1"/>
</General>
<VersionInfo>
<ProjectVersion Value=""/>
<Language Value=""/>
<CharSet Value=""/>
</VersionInfo>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="nimlaz.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="nimlaz"/>
<CursorPos X="17" Y="21"/>
<TopLine Value="1"/>
<EditorIndex Value="1"/>
<UsageCount Value="21"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="unit1.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="Unit1"/>
<CursorPos X="26" Y="27"/>
<TopLine Value="2"/>
<EditorIndex Value="0"/>
<UsageCount Value="21"/>
<Loaded Value="True"/>
</Unit1>
</Units>
<JumpHistory Count="12" HistoryIndex="11">
<Position1>
<Filename Value="unit1.pas"/>
<Caret Line="27" Column="1" TopLine="1"/>
</Position1>
<Position2>
<Filename Value="unit1.pas"/>
<Caret Line="15" Column="3" TopLine="1"/>
</Position2>
<Position3>
<Filename Value="unit1.pas"/>
<Caret Line="17" Column="26" TopLine="1"/>
</Position3>
<Position4>
<Filename Value="unit1.pas"/>
<Caret Line="16" Column="18" TopLine="1"/>
</Position4>
<Position5>
<Filename Value="unit1.pas"/>
<Caret Line="20" Column="43" TopLine="2"/>
</Position5>
<Position6>
<Filename Value="unit1.pas"/>
<Caret Line="21" Column="48" TopLine="16"/>
</Position6>
<Position7>
<Filename Value="nimlaz.lpr"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position7>
<Position8>
<Filename Value="unit1.pas"/>
<Caret Line="52" Column="17" TopLine="9"/>
</Position8>
<Position9>
<Filename Value="unit1.pas"/>
<Caret Line="51" Column="12" TopLine="9"/>
</Position9>
<Position10>
<Filename Value="nimlaz.lpr"/>
<Caret Line="21" Column="3" TopLine="1"/>
</Position10>
<Position11>
<Filename Value="nimlaz.lpr"/>
<Caret Line="20" Column="1" TopLine="1"/>
</Position11>
<Position12>
<Filename Value="nimlaz.lpr"/>
<Caret Line="21" Column="7" TopLine="1"/>
</Position12>
</JumpHistory>
</ProjectOptions>
<CompilerOptions>
<Version Value="8"/>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)/"/>
</SearchPaths>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View file

@ -1,21 +0,0 @@
program nimlaz;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms
{ you can add units after this }, Unit1, LResources;
{$IFDEF WINDOWS}{$R nimlaz.rc}{$ENDIF}
begin
{$I nimlaz.lrs}
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2
#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "nimlaz.manifest"

View file

@ -1,8 +0,0 @@
This example demonstrates how to use Nim with Lazarus. The GUI is generated
with Lazarus, while the "backend" is written in Nim. To compile the example,
use this command:
nim c --app:gui --no_main --no_linking backend.nim
Open the ``nimlaz.lpi`` file in Lazarus and run the program.

View file

@ -1,46 +0,0 @@
object Form1: TForm1
Left = 553
Height = 111
Top = 464
Width = 448
ActiveControl = SpinEdit1
Caption = 'Sum'
ClientHeight = 111
ClientWidth = 448
OnCreate = FormCreate
LCLVersion = '0.9.28.2'
object Label1: TLabel
Left = 8
Height = 18
Top = 72
Width = 34
Caption = 'Sum:'
ParentColor = False
end
object SpinEdit1: TSpinEdit
Left = 8
Height = 27
Top = 8
Width = 436
Anchors = [akTop, akLeft, akRight]
OnChange = SpinEdit1Change
TabOrder = 0
end
object SpinEdit2: TSpinEdit
Left = 8
Height = 27
Top = 40
Width = 436
Anchors = [akTop, akLeft, akRight]
OnChange = SpinEdit1Change
TabOrder = 1
end
object Edit1: TEdit
Left = 48
Height = 27
Top = 72
Width = 396
Anchors = [akTop, akLeft, akRight]
TabOrder = 2
end
end

View file

@ -1,58 +0,0 @@
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
Spin, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
procedure FormCreate(Sender: TObject);
procedure SpinEdit1Change(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
{$link nimcache/lib/system.o}
{$link nimcache/backend.o}
{$link nimcache/nim__dat.o}
{$linklib c}
procedure NimMain; cdecl; external;
function myAdd(x, y: longint): longint; cdecl; external;
procedure TForm1.FormCreate(Sender: TObject);
begin
// we initialize the Nim data structures here:
NimMain();
end;
procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
Edit1.text := IntToStr(myAdd(SpinEdit1.Value, SpinEdit2.Value));
end;
initialization
{$I unit1.lrs}
end.

View file

@ -1,5 +0,0 @@
# Backend for the different user interfaces.
proc myAdd*(x, y: int): int {.cdecl, exportc.} =
result = x + y

Some files were not shown because too many files have changed in this diff Show more