Merge branch 'master' of github.com:Araq/Nimrod into upstream

This commit is contained in:
Zahary Karadjov 2012-06-02 19:52:06 +03:00
commit 88f7b7bc50
31 changed files with 459 additions and 114 deletions

View file

@ -145,6 +145,7 @@ type
nkIfStmt, # an if statement nkIfStmt, # an if statement
nkWhenStmt, # a when expression or statement nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement nkForStmt, # a for statement
nkParForStmt, # a parallel for statement
nkWhileStmt, # a while statement nkWhileStmt, # a while statement
nkCaseStmt, # a case statement nkCaseStmt, # a case statement
nkTypeSection, # a type section (consists of type definitions) nkTypeSection, # a type section (consists of type definitions)
@ -396,7 +397,7 @@ type
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mSlice, mConTArr, mConTT, mSlice,
mFields, mFieldPairs, mFields, mFieldPairs, mOmpParFor,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mRand, mIsPartOf, mAstToStr, mRand,

View file

@ -20,7 +20,8 @@ proc hasNoInit(call: PNode): bool {.inline.} =
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) = proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
var pl = pl var pl = pl
var typ = ri.sons[0].typ # getUniqueType() is too expensive here! # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ", ") if sonsLen(ri) > 1: app(pl, ", ")
@ -124,7 +125,8 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# this is a hotspot in the compiler # this is a hotspot in the compiler
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl = con(op.r, "(") var pl = con(op.r, "(")
var typ = ri.sons[0].typ # getUniqueType() is too expensive here! # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
var length = sonsLen(ri) var length = sonsLen(ri)
for i in countup(1, length - 1): for i in countup(1, length - 1):
@ -150,7 +152,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc var op: TLoc
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl: PRope var pl: PRope
var typ = ri.sons[0].typ
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
var length = sonsLen(ri) var length = sonsLen(ri)
for i in countup(1, length - 1): for i in countup(1, length - 1):
@ -201,7 +204,8 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc var op, a: TLoc
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl: PRope = nil var pl: PRope = nil
var typ = ri.sons[0].typ # getUniqueType() is too expensive here! # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
var length = sonsLen(ri) var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
@ -228,7 +232,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
var op, a: TLoc var op, a: TLoc
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl = toRope"[" var pl = toRope"["
var typ = ri.sons[0].typ # getUniqueType() is too expensive here! # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
var length = sonsLen(ri) var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))

View file

@ -283,7 +283,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
proc expr(p: BProc, e: PNode, d: var TLoc) proc expr(p: BProc, e: PNode, d: var TLoc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, getUniqueType(e.typ), OnUnknown) initLoc(result, locNone, e.typ, OnUnknown)
expr(p, e, result) expr(p, e, result)
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) = proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
@ -543,17 +543,17 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType = proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
if (e.sons[1].kind != nkSym): InternalError(e.info, "genRecordFieldAux") if e.sons[1].kind != nkSym: InternalError(e.info, "genRecordFieldAux")
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = getUniqueType(a.t) result = a.t
proc genRecordField(p: BProc, e: PNode, d: var TLoc) = proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
var ty = genRecordFieldAux(p, e, d, a) var ty = genRecordFieldAux(p, e, d, a)
var r = rdLoc(a) var r = rdLoc(a)
var f = e.sons[1].sym var f = e.sons[1].sym
if ty.n == nil: if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information # we found a unique tuple type which lacks field information
# so we use Field$i # so we use Field$i
appf(r, ".Field$1", [toRope(f.position)]) appf(r, ".Field$1", [toRope(f.position)])
@ -561,14 +561,14 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
else: else:
var field: PSym = nil var field: PSym = nil
while ty != nil: while ty != nil:
if not (ty.kind in {tyTuple, tyObject}): if ty.kind notin {tyTuple, tyObject}:
InternalError(e.info, "genRecordField") InternalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name) field = lookupInRecord(ty.n, f.name)
if field != nil: break if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup") if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = GetUniqueType(ty.sons[0]) ty = GetUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genRecordField") if field == nil: InternalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: InternalError(e.info, "genRecordField") if field.loc.r == nil: InternalError(e.info, "genRecordField 3")
appf(r, ".$1", [field.loc.r]) appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r)
@ -579,16 +579,17 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = getUniqueType(a.t) var ty = a.t
var r = rdLoc(a) var r = rdLoc(a)
case e.sons[1].kind case e.sons[1].kind
of nkIntLit..nkInt64Lit: i = int(e.sons[1].intVal) of nkIntLit..nkInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem") else: internalError(e.info, "genTupleElem")
if ty.n != nil: when false:
var field = ty.n.sons[i].sym if ty.n != nil:
if field == nil: InternalError(e.info, "genTupleElem") var field = ty.n.sons[i].sym
if field.loc.r == nil: InternalError(e.info, "genTupleElem") if field == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r]) if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
else: else:
appf(r, ".Field$1", [toRope(i)]) appf(r, ".Field$1", [toRope(i)])
putIntoDest(p, d, ty.sons[i], r) putIntoDest(p, d, ty.sons[i], r)
@ -1510,11 +1511,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1] if it.kind == nkExprColonExpr: it = it.sons[1]
if t.n == nil: initLoc(rec, locExpr, it.typ, d.s)
initLoc(rec, locExpr, it.typ, d.s) rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)]) expr(p, it, rec)
expr(p, it, rec) when false:
else:
initLoc(rec, locExpr, it.typ, d.s) initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr") if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
rec.r = ropef("$1.$2", rec.r = ropef("$1.$2",

View file

@ -32,7 +32,7 @@ proc genVarTuple(p: BProc, n: PNode) =
assignLocalVar(p, v) assignLocalVar(p, v)
initLocalVar(p, v, immediateAsgn=true) initLocalVar(p, v, immediateAsgn=true)
initLoc(field, locExpr, t.sons[i], tup.s) initLoc(field, locExpr, t.sons[i], tup.s)
if t.n == nil: if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)]) field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
else: else:
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple") if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple")
@ -258,6 +258,34 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
else: genStmts(p, t.sons[1]) else: genStmts(p, t.sons[1])
endBlock(p) endBlock(p)
proc genParForStmt(p: BProc, t: PNode) =
assert(sonsLen(t) == 3)
inc(p.withinLoop)
genLineDir(p, t)
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(P, forLoopVar)
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
initLocExpr(p, call.sons[1], rangeA)
initLocExpr(p, call.sons[2], rangeB)
appf(p.s(cpsStmts), "#pragma omp parallel for $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)",
forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
call.sons[3].getStr.toRope)
p.breakIdx = startBlock(p)
p.blocks[p.breakIdx].isLoop = true
genStmts(p, t.sons[2])
endBlock(p)
dec(p.withinLoop)
proc genBreakStmt(p: BProc, t: PNode) = proc genBreakStmt(p: BProc, t: PNode) =
var idx = p.breakIdx var idx = p.breakIdx
if t.sons[0].kind != nkEmpty: if t.sons[0].kind != nkEmpty:
@ -815,5 +843,6 @@ proc genStmts(p: BProc, t: PNode) =
# we have not only the header: # we have not only the header:
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
genProc(p.module, prc) genProc(p.module, prc)
of nkParForStmt: genParForStmt(p, t)
else: internalError(t.info, "genStmts(" & $t.kind & ')') else: internalError(t.info, "genStmts(" & $t.kind & ')')

View file

@ -144,7 +144,7 @@ proc mapSetType(typ: PType): TCTypeKind =
proc mapType(typ: PType): TCTypeKind = proc mapType(typ: PType): TCTypeKind =
case typ.kind case typ.kind
of tyNone: result = ctVoid of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool of tyBool: result = ctBool
of tyChar: result = ctChar of tyChar: result = ctChar
of tySet: result = mapSetType(typ) of tySet: result = mapSetType(typ)
@ -561,7 +561,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]) appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
IdTablePut(m.forwTypeCache, t, result) IdTablePut(m.forwTypeCache, t, result)
IdTablePut(m.typeCache, t, result) # always call for sideeffects: IdTablePut(m.typeCache, t, result) # always call for sideeffects:
if t.n != nil: recdesc = getRecordDesc(m, t, result, check) if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
else: recdesc = getTupleDesc(m, t, result, check) else: recdesc = getTupleDesc(m, t, result, check)
if not isImportedType(t): app(m.s[cfsTypes], recdesc) if not isImportedType(t): app(m.s[cfsTypes], recdesc)
of tySet: of tySet:
@ -889,8 +889,11 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
of tyEnum: genEnumInfo(gNimDat, t, result) of tyEnum: genEnumInfo(gNimDat, t, result)
of tyObject: genObjectInfo(gNimDat, t, result) of tyObject: genObjectInfo(gNimDat, t, result)
of tyTuple: of tyTuple:
if t.n != nil: genObjectInfo(gNimDat, t, result) # if t.n != nil: genObjectInfo(gNimDat, t, result)
else: genTupleInfo(gNimDat, t, result) # else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(gNimDat, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')') else: InternalError("genTypeInfo(" & $t.kind & ')')
proc genTypeSection(m: BModule, n: PNode) = proc genTypeSection(m: BModule, n: PNode) =

View file

@ -87,14 +87,19 @@ proc GetUniqueType*(key: PType): PType =
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key)) result = GetUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody, of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tyTuple, tySet, tyRange, tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar: tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
# tuples are quite horrible as C does not support them directly and
# tuple[string, string] is a (strange) subtype of
# tuple[nameA, nameB: string]. This bites us here, so we
# use 'sameBackendType' instead of 'sameType'.
# we have to do a slow linear search because types may need # we have to do a slow linear search because types may need
# to be compared by their structure: # to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key if IdTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)): for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key) var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key): if t != nil and sameBackendType(t, key):
return t return t
IdTablePut(gTypeTable[k], key, key) IdTablePut(gTypeTable[k], key, key)
result = key result = key

View file

@ -1343,7 +1343,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkWhileStmt: genWhileStmt(p, n, r) of nkWhileStmt: genWhileStmt(p, n, r)
of nkVarSection, nkLetSection: genVarStmt(p, n, r) of nkVarSection, nkLetSection: genVarStmt(p, n, r)
of nkConstSection: genConstStmt(p, n, r) of nkConstSection: genConstStmt(p, n, r)
of nkForStmt: internalError(n.info, "for statement not eliminated") of nkForStmt, nkParForStmt:
internalError(n.info, "for statement not eliminated")
of nkCaseStmt: genCaseStmt(p, n, r) of nkCaseStmt: genCaseStmt(p, n, r)
of nkReturnStmt: genReturnStmt(p, n, r) of nkReturnStmt: genReturnStmt(p, n, r)
of nkBreakStmt: genBreakStmt(p, n, r) of nkBreakStmt: genBreakStmt(p, n, r)

View file

@ -1331,7 +1331,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkPragmaBlock: of nkPragmaBlock:
result = evalAux(c, n.sons[1], flags) result = evalAux(c, n.sons[1], flags)
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkLambdaKinds, nkContinueStmt, nkIdent: nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt:
result = raiseCannotEval(c, n.info) result = raiseCannotEval(c, n.info)
of nkRefTy: of nkRefTy:
result = evalAux(c, n.sons[0], flags) result = evalAux(c, n.sons[0], flags)

View file

@ -21,18 +21,19 @@ proc considerAcc*(n: PNode): PIdent =
case n.len case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n)) of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0]) of 1: result = considerAcc(n.sons[0])
of 2: else:
if n[0].ident.id == ord(wStar): if n.len == 2 and n[0].kind == nkIdent and n[0].ident.id == ord(wStar):
# XXX find a better way instead of `*x` for 'genSym'
result = genSym(n[1].ident.s) result = genSym(n[1].ident.s)
else: else:
result = getIdent(n[0].ident.s & n[1].ident.s) var id = ""
else: for i in 0.. <n.len:
var id = "" let x = n.sons[i]
for i in 0.. <n.len: case x.kind
if n.sons[i].kind != nkIdent: of nkIdent: id.add(x.ident.s)
GlobalError(n.info, errIdentifierExpected, renderTree(n)) of nkSym: id.add(x.sym.name.s)
id.add(n.sons[i].ident.s) else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id) result = getIdent(id)
else: else:
GlobalError(n.info, errIdentifierExpected, renderTree(n)) GlobalError(n.info, errIdentifierExpected, renderTree(n))

View file

@ -984,7 +984,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkCaseStmt, nkRecCase: gcase(g, n) of nkCaseStmt, nkRecCase: gcase(g, n)
of nkMacroStmt: gmacro(g, n) of nkMacroStmt: gmacro(g, n)
of nkTryStmt: gtry(g, n) of nkTryStmt: gtry(g, n)
of nkForStmt: gfor(g, n) of nkForStmt, nkParForStmt: gfor(g, n)
of nkBlockStmt, nkBlockExpr: gblock(g, n) of nkBlockStmt, nkBlockExpr: gblock(g, n)
of nkStaticStmt: gstaticStmt(g, n) of nkStaticStmt: gstaticStmt(g, n)
of nkAsmStmt: gasm(g, n) of nkAsmStmt: gasm(g, n)

View file

@ -142,7 +142,7 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind) a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind)
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind)
closeScope(c.tab) closeScope(c.tab)
of nkForStmt: of nkForStmt, nkParForStmt:
var L = sonsLen(n) var L = sonsLen(n)
openScope(c.tab) openScope(c.tab)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind)

View file

@ -465,7 +465,11 @@ proc semFor(c: PContext, n: PNode): PNode =
else: else:
GlobalError(n.sons[length - 2].info, errIteratorExpected) GlobalError(n.sons[length - 2].info, errIteratorExpected)
elif call.sons[0].sym.magic != mNone: elif call.sons[0].sym.magic != mNone:
result = semForFields(c, n, call.sons[0].sym.magic) if call.sons[0].sym.magic == mOmpParFor:
result = semForVars(c, n)
result.kind = nkParForStmt
else:
result = semForFields(c, n, call.sons[0].sym.magic)
else: else:
result = semForVars(c, n) result = semForVars(c, n)
closeScope(c.tab) closeScope(c.tab)
@ -979,7 +983,7 @@ proc SemStmt(c: PContext, n: PNode): PNode =
of nkWhileStmt: result = semWhile(c, n) of nkWhileStmt: result = semWhile(c, n)
of nkTryStmt: result = semTry(c, n) of nkTryStmt: result = semTry(c, n)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt: result = semFor(c, n) of nkForStmt, nkParForStmt: result = semFor(c, n)
of nkCaseStmt: result = semCase(c, n) of nkCaseStmt: result = semCase(c, n)
of nkReturnStmt: result = semReturn(c, n) of nkReturnStmt: result = semReturn(c, n)
of nkAsmStmt: result = semAsm(c, n) of nkAsmStmt: result = semAsm(c, n)

View file

@ -247,7 +247,7 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
proc hasContinue(n: PNode): bool = proc hasContinue(n: PNode): bool =
case n.kind case n.kind
of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: nil of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: nil
of nkContinueStmt: result = true of nkContinueStmt: result = true
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -659,6 +659,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
inc c.inLoop inc c.inLoop
result = transformFor(c, n) result = transformFor(c, n)
dec c.inLoop dec c.inLoop
of nkParForStmt:
inc c.inLoop
result = transformSons(c, n)
dec c.inLoop
of nkCaseStmt: result = transformCase(c, n) of nkCaseStmt: result = transformCase(c, n)
of nkContinueStmt: of nkContinueStmt:
result = PTransNode(newNode(nkBreakStmt)) result = PTransNode(newNode(nkBreakStmt))

View file

@ -550,6 +550,7 @@ type
TSameTypeClosure = object {.pure.} TSameTypeClosure = object {.pure.}
cmp: TDistinctCompare cmp: TDistinctCompare
ignoreTupleFields: bool
recCheck: int recCheck: int
s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
# (few elements expected) # (few elements expected)
@ -645,7 +646,7 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
for i in countup(0, sonsLen(a) - 1): for i in countup(0, sonsLen(a) - 1):
result = SameTypeAux(a.sons[i], b.sons[i], c) result = SameTypeAux(a.sons[i], b.sons[i], c)
if not result: return if not result: return
if a.n != nil and b.n != nil: if a.n != nil and b.n != nil and not c.ignoreTupleFields:
for i in countup(0, sonsLen(a.n) - 1): for i in countup(0, sonsLen(a.n) - 1):
# check field names: # check field names:
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple") if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
@ -787,6 +788,11 @@ proc SameType*(x, y: PType): bool =
var c = initSameTypeClosure() var c = initSameTypeClosure()
result = sameTypeAux(x, y, c) result = sameTypeAux(x, y, c)
proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure()
c.ignoreTupleFields = true
result = sameTypeAux(x, y, c)
proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool = proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool =
## compares two type for equality (modulo type distinction) ## compares two type for equality (modulo type distinction)
var c = initSameTypeClosure() var c = initSameTypeClosure()
@ -863,8 +869,9 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = typeAllowedAux(marker, t.sons[0], skResult) result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc: of tyExpr, tyStmt, tyTypeDesc:
result = true result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass: of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation,
result = false #InternalError('shit found'); tyTypeClass:
result = false
of tyEmpty, tyNil: of tyEmpty, tyNil:
result = kind == skConst result = kind == skConst
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:

View file

@ -60,6 +60,7 @@ hint[LineTooLong]=off
@if unix: @if unix:
@if not bsd: @if not bsd:
# -fopenmp
gcc.options.linker = "-ldl" gcc.options.linker = "-ldl"
clang.options.linker = "-ldl" clang.options.linker = "-ldl"
tcc.options.linker = "-ldl" tcc.options.linker = "-ldl"

View file

@ -36,7 +36,7 @@ type
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt, nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt, nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
nnkConstDef, nnkTypeDef, nnkConstDef, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
@ -221,6 +221,15 @@ template emit*(s: expr): stmt =
block: block:
const evaluated = s const evaluated = s
eval: result = evaluated.parseStmt eval: result = evaluated.parseStmt
when false:
template once(x: expr): expr =
block:
const y = x
y
macro `payload`(x: stmt): stmt = result = once(s).parseStmt
`payload`()
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} = proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case, ## checks that `n` is of kind `k`. If this is not the case,
@ -323,7 +332,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax ## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toTree` function. ## tree using the `toTree` function. Printing is done *at compile time*.
## ##
## You can use this as a tool to explore the Nimrod's abstract syntax ## You can use this as a tool to explore the Nimrod's abstract syntax
## tree and to discover what kind of nodes must be created to represent ## tree and to discover what kind of nodes must be created to represent
@ -331,7 +340,7 @@ macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax ## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toLisp` function. ## tree using the `toLisp` function. Printing is done *at compile time*.
## ##
## See `dumpTree`. ## See `dumpTree`.

View file

@ -479,7 +479,8 @@ proc setBiggestFloat*(x: TAny, y: biggestFloat) =
proc getString*(x: TAny): string = proc getString*(x: TAny): string =
## retrieve the string value out of `x`. `x` needs to represent a string. ## retrieve the string value out of `x`. `x` needs to represent a string.
assert x.rawtype.kind == tyString assert x.rawtype.kind == tyString
result = cast[ptr string](x.value)[] if not isNil(cast[ptr pointer](x.value)[]):
result = cast[ptr string](x.value)[]
proc setString*(x: TAny, y: string) = proc setString*(x: TAny, y: string) =
## sets the string value of `x`. `x` needs to represent a string. ## sets the string value of `x`. `x` needs to represent a string.

View file

@ -25,6 +25,10 @@ type
TWeekDay* = enum ## represents a weekday TWeekDay* = enum ## represents a weekday
dMon, dTue, dWed, dThu, dFri, dSat, dSun dMon, dTue, dWed, dThu, dFri, dSat, dSun
var
timezone {.importc, header: "<time.h>".}: int
tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
when defined(posix): when defined(posix):
type type
TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
@ -112,6 +116,20 @@ type
yearday*: range[0..365] ## The number of days since January 1, yearday*: range[0..365] ## The number of days since January 1,
## in the range 0 to 365. ## in the range 0 to 365.
## Always 0 if the target is ECMAScript. ## Always 0 if the target is ECMAScript.
isDST*: bool ## Determines whether DST is in effect. Always
## ``False`` if time is UTC.
tzname*: string ## The timezone this time is in. E.g. GMT
timezone*: int ## The offset of the (non-DST) timezone in seconds
## west of UTC.
TTimeInterval* = object
miliseconds*: int ## The number of miliseconds
seconds*: int ## The number of seconds
minutes*: int ## The number of minutes
hours*: int ## The number of hours
days*: int ## The number of days
months*: int ## The number of months
years*: int ## The number of years
proc getTime*(): TTime ## gets the current calendar time proc getTime*(): TTime ## gets the current calendar time
proc getLocalTime*(t: TTime): TTimeInfo proc getLocalTime*(t: TTime): TTimeInfo
@ -122,7 +140,7 @@ proc getGMTime*(t: TTime): TTimeInfo
## expressed in Coordinated Universal Time (UTC). ## expressed in Coordinated Universal Time (UTC).
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
## converts a broken-down time structure, expressed as local time, to ## converts a broken-down time structure to
## calendar time representation. The function ignores the specified ## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes ## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure. ## them from the other information in the broken-down time structure.
@ -146,10 +164,90 @@ proc `<=` * (a, b: TTime): bool {.
## returns true iff ``a <= b``. ## returns true iff ``a <= b``.
result = a - b <= 0 result = a - b <= 0
proc getTzname*(): tuple[nonDST, DST: string]
## returns the local timezone; ``nonDST`` is the name of the local non-DST
## timezone, ``DST`` is the name of the local DST timezone.
proc getTimezone*(): int
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
proc getStartMilsecs*(): int {.deprecated.} proc getStartMilsecs*(): int {.deprecated.}
## get the miliseconds from the start of the program. **Deprecated since ## get the miliseconds from the start of the program. **Deprecated since
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
proc newInterval*(miliseconds, seconds, minutes, hours, days, months,
years: int = 0): TTimeInterval =
## creates a new ``TTimeInterval``.
result.miliseconds = miliseconds
result.seconds = seconds
result.minutes = minutes
result.hours = hours
result.days = days
result.months = months
result.years = years
proc isLeapYear(year: int): bool =
if year mod 400 == 0:
return true
elif year mod 100 == 0:
return false
elif year mod 4 == 0:
return true
else:
return false
proc getDaysInMonth(month: TMonth, year: int): int =
# http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
if month == mFeb: # Feb
if isLeapYear(year):
result = 29
else:
result = 28
elif month in [mApr, mJun, mSep, mNov]: result = 30
else: result = 31
proc calculateSeconds(a: TTimeInfo, interval: TTimeInterval): float =
var anew = a
var newinterv = interval
result = 0.0
newinterv.months += interval.years * 12
var curMonth = anew.month
for mth in 1 .. newinterv.months:
result += float(getDaysInMonth(curMonth, anew.year) * 24 * 60 * 60)
if curMonth == mDec:
curMonth = mJan
anew.year.inc()
else:
curMonth.inc()
result += float(newinterv.days * 24 * 60 * 60)
result += float(newinterv.minutes * 60 * 60)
result += newinterv.seconds.float
result += newinterv.miliseconds / 1000
proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
## adds ``interval`` time.
##
## **Note:** This has been only briefly tested and it may not be very accurate.
let t = timeInfoToTime(a)
var secs = calculateSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(TTime(float(t) + secs))
else:
result = getLocalTime(TTime(float(t) + secs))
proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
## subtracts ``interval`` time.
##
## **Note:** This has been only briefly tested, it is inaccurate especially
## when you subtract so much that you reach the Julian calendar.
let t = timeInfoToTime(a)
var secs = calculateSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(TTime(float(t) - secs))
else:
result = getLocalTime(TTime(float(t) - secs))
when not defined(ECMAScript): when not defined(ECMAScript):
proc epochTime*(): float {.rtl, extern: "nt$1".} proc epochTime*(): float {.rtl, extern: "nt$1".}
## gets time after the UNIX epoch (1970) in seconds. It is a float ## gets time after the UNIX epoch (1970) in seconds. It is a float
@ -170,6 +268,7 @@ when not defined(ECMAScript):
## echo "CPU time [s] ", cpuTime() - t0 ## echo "CPU time [s] ", cpuTime() - t0
when not defined(ECMAScript): when not defined(ECMAScript):
# C wrapper: # C wrapper:
type type
structTM {.importc: "struct tm", final.} = object structTM {.importc: "struct tm", final.} = object
@ -205,7 +304,7 @@ when not defined(ECMAScript):
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
# our own procs on top of that: # our own procs on top of that:
proc tmToTimeInfo(tm: structTM): TTimeInfo = proc tmToTimeInfo(tm: structTM, local: bool): TTimeInfo =
const const
weekDays: array [0..6, TWeekDay] = [ weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat] dSun, dMon, dTue, dWed, dThu, dFri, dSat]
@ -217,6 +316,18 @@ when not defined(ECMAScript):
result.year = tm.year + 1900'i32 result.year = tm.year + 1900'i32
result.weekday = weekDays[int(tm.weekDay)] result.weekday = weekDays[int(tm.weekDay)]
result.yearday = int(tm.yearday) result.yearday = int(tm.yearday)
result.isDST = tm.isDST > 0
#result.tzname = if local: getTzname()[if result.isDST: 0 else: 1] else: "UTC"
# TODO: ^^^ Crashes the compiler.
if local:
if result.isDST:
result.tzname = getTzname()[0]
if not result.isDST:
result.tzname = getTzname()[1]
else:
result.tzname = "UTC"
result.timezone = if local: getTimezone() else: 0
proc timeInfoToTM(t: TTimeInfo): structTM = proc timeInfoToTM(t: TTimeInfo): structTM =
const const
@ -229,7 +340,7 @@ when not defined(ECMAScript):
result.year = t.year - 1900 result.year = t.year - 1900
result.weekday = weekDays[t.weekDay] result.weekday = weekDays[t.weekDay]
result.yearday = t.yearday result.yearday = t.yearday
result.isdst = -1 result.isdst = if t.isDST: 1 else: 0
when not defined(useNimRtl): when not defined(useNimRtl):
proc `-` (a, b: TTime): int64 = proc `-` (a, b: TTime): int64 =
@ -251,13 +362,13 @@ when not defined(ECMAScript):
proc getTime(): TTime = return timec(nil) proc getTime(): TTime = return timec(nil)
proc getLocalTime(t: TTime): TTimeInfo = proc getLocalTime(t: TTime): TTimeInfo =
var a = t var a = t
result = tmToTimeInfo(localtime(addr(a))[]) result = tmToTimeInfo(localtime(addr(a))[], true)
# copying is needed anyway to provide reentrancity; thus # copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive # the convertion is not expensive
proc getGMTime(t: TTime): TTimeInfo = proc getGMTime(t: TTime): TTimeInfo =
var a = t var a = t
result = tmToTimeInfo(gmtime(addr(a))[]) result = tmToTimeInfo(gmtime(addr(a))[], false)
# copying is needed anyway to provide reentrancity; thus # copying is needed anyway to provide reentrancity; thus
# the convertion is not expensive # the convertion is not expensive
@ -295,6 +406,12 @@ when not defined(ECMAScript):
## converts a Windows time to a UNIX `TTime` (``time_t``) ## converts a Windows time to a UNIX `TTime` (``time_t``)
result = TTime((t - epochDiff) div rateDiff) result = TTime((t - epochDiff) div rateDiff)
proc getTzname(): tuple[nonDST, DST: string] =
return ($tzname[0], $tzname[1])
proc getTimezone(): int =
return timezone
when not defined(useNimRtl): when not defined(useNimRtl):
proc epochTime(): float = proc epochTime(): float =
when defined(posix): when defined(posix):
@ -418,17 +535,20 @@ proc format*(info: TTimeInfo, f: string): string =
## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's ## y(yyyy) This displays the year to different digits. You most likely only want 2 or 4 'y's
## yy Displays the year to two digits. ``2012 -> 12`` ## yy Displays the year to two digits. ``2012 -> 12``
## yyyy Displays the year to four digits. ``2012 -> 2012`` ## yyyy Displays the year to four digits. ``2012 -> 2012``
## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5``
## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05``
## zzz Same as above but with ``:00``. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST``
## ========== ================================================================================= ================================================ ## ========== ================================================================================= ================================================
##
## Other strings can be inserted by putting them in ``''``. For example ``hh'->'mm`` will give ``01->56``.
result = "" result = ""
var i = 0 var i = 0
var currentF = "" var currentF = ""
while True: while True:
case f[i] case f[i]
of '\0': of ' ', '-', '/', ':', '\'', '\0':
break
of ' ', '-', '/', ':', '\'':
case currentF case currentF
of "d": of "d":
result.add($info.monthday) result.add($info.monthday)
@ -437,9 +557,9 @@ proc format*(info: TTimeInfo, f: string): string =
result.add("0") result.add("0")
result.add($info.monthday) result.add($info.monthday)
of "ddd": of "ddd":
result.add(($info.month)[0 .. 2]) result.add(($info.monthday)[0 .. 2])
of "dddd": of "dddd":
result.add($info.month) result.add($info.monthday)
of "h": of "h":
result.add($(info.hour - 12)) result.add($(info.hour - 12))
of "hh": of "hh":
@ -460,11 +580,11 @@ proc format*(info: TTimeInfo, f: string): string =
result.add('0') result.add('0')
result.add($info.minute) result.add($info.minute)
of "M": of "M":
result.add($(int(info.month))) result.add($(int(info.month)+1))
of "MM": of "MM":
if int(info.month) < 10: if int(info.month) < 10:
result.add('0') result.add('0')
result.add($(int(info.month))) result.add($(int(info.month)+1))
of "MMM": of "MMM":
result.add(($info.month)[0..2]) result.add(($info.month)[0..2])
of "MMMM": of "MMMM":
@ -500,12 +620,32 @@ proc format*(info: TTimeInfo, f: string): string =
of "yyyyy": of "yyyyy":
result.add('0') result.add('0')
result.add($info.year) result.add($info.year)
of "z":
let hrs = (info.timezone div 60) div 60
result.add($hrs)
of "zz":
let hrs = (info.timezone div 60) div 60
result.add($hrs)
if hrs.abs < 10:
var atIndex = result.len-(($hrs).len-(if hrs < 0: 1 else: 0))
result.insert("0", atIndex)
of "zzz":
let hrs = (info.timezone div 60) div 60
result.add($hrs & ":00")
if hrs.abs < 10:
var atIndex = result.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
result.insert("0", atIndex)
of "ZZZ":
result.add(info.tzname)
of "": of "":
nil # Do nothing. nil # Do nothing.
else: else:
raise newException(EInvalidValue, "Invalid format string: " & currentF) raise newException(EInvalidValue, "Invalid format string: " & currentF)
currentF = "" currentF = ""
if f[i] == '\0': break
if f[i] == '\'': if f[i] == '\'':
inc(i) # Skip ' inc(i) # Skip '

View file

@ -49,9 +49,13 @@ type
## a type description (for templates) ## a type description (for templates)
void* {.magic: "VoidType".} ## meta type to denote the absense of any type void* {.magic: "VoidType".} ## meta type to denote the absense of any type
TInteger* = int|char|int8|int16|int32|int64|bool|enum TInteger* = int|int8|int16|int32|int64
## type class matching all integer types ## type class matching all integer types
TOrdinal* = TInteger|bool|enum
## type class matching all ordinal types; however this includes enums with
## holes.
TNumber* = TInteger|float|float32|float64 TNumber* = TInteger|float|float32|float64
## type class matching all number types ## type class matching all number types
@ -190,6 +194,7 @@ type
msg* {.exportc: "message".}: string ## the exception's message. Not msg* {.exportc: "message".}: string ## the exception's message. Not
## providing an exception message ## providing an exception message
## is bad style. ## is bad style.
trace: string
EAsynch* = object of E_Base ## Abstract exception class for EAsynch* = object of E_Base ## Abstract exception class for
## *asynchronous exceptions* (interrupts). ## *asynchronous exceptions* (interrupts).
@ -1195,6 +1200,15 @@ iterator `..`*[S, T](a: S, b: T): T {.inline.} =
yield res yield res
inc res inc res
iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
inline, magic: "OmpParFor", sideEffect.} =
## parallel loop iterator. Same as `..` but the loop may run in parallel.
## `annotation` is an additional annotation for the code generator to use.
## Note that the compiler maps that to
## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as
## such isn't aware of the parallelism in your code. Be careful.
nil
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} proc min*(x, y: int): int {.magic: "MinI", noSideEffect.}
proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.}
proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.}
@ -1901,6 +1915,10 @@ when not defined(EcmaScript) and not defined(NimrodVM):
proc getStackTrace*(): string proc getStackTrace*(): string
## gets the current stack trace. This is only works for debug builds. ## gets the current stack trace. This is only works for debug builds.
proc getStackTrace*(e: ref E_Base): string
## gets the stack trace associated with `e`, which is the stack that
## lead to the ``raise`` statement. This is only works for debug builds.
{.push stack_trace: off.} {.push stack_trace: off.}
when hostOS == "standalone": when hostOS == "standalone":
include "system/embedded" include "system/embedded"
@ -2177,19 +2195,19 @@ proc `*=`*[T](x: var ordinal[T], y: ordinal[T]) {.inline, noSideEffect.} =
## Binary `*=` operator for ordinals ## Binary `*=` operator for ordinals
x = x * y x = x * y
proc `+=` *(x: var float, y:float) {.inline, noSideEffect.} = proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Increments in placee a floating point number ## Increments in placee a floating point number
x = x + y x = x + y
proc `-=` *(x: var float, y:float) {.inline, noSideEffect.} = proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Decrements in place a floating point number ## Decrements in place a floating point number
x = x - y x = x - y
proc `*=` *(x: var float, y:float) {.inline, noSideEffect.} = proc `*=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Multiplies in place a floating point number ## Multiplies in place a floating point number
x = x * y x = x * y
proc `/=` *(x: var float, y:float) {.inline, noSideEffect.} = proc `/=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
## Divides in place a floating point number ## Divides in place a floating point number
x = x / y x = x / y
@ -2283,5 +2301,18 @@ template eval*(blk: stmt): stmt =
macro payload(x: stmt): stmt = blk macro payload(x: stmt): stmt = blk
payload() payload()
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
## inserts `item` into `x` at position `i`.
var xl = x.len
setLen(x, xl+item.len)
var j = xl-1
while j >= i:
shallowCopy(x[j+item.len], x[j])
dec(j)
j = 0
while j < item.len:
x[j+i] = item[j]
inc(j)
when defined(initDebugger): when defined(initDebugger):
initDebugger() initDebugger()

View file

@ -7,6 +7,8 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
proc genericResetAux(dest: Pointer, n: ptr TNimNode)
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool) proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool)
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) = proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
var var
@ -20,10 +22,16 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
for i in 0..n.len-1: for i in 0..n.len-1:
genericAssignAux(dest, src, n.sons[i], shallow) genericAssignAux(dest, src, n.sons[i], shallow)
of nkCase: of nkCase:
var dd = selectBranch(dest, n)
var m = selectBranch(src, n)
# reset if different branches are in use; note different branches also
# imply that's not self-assignment (``x = x``)!
if m != dd and dd != nil:
genericResetAux(dest, dd)
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size) n.typ.size)
var m = selectBranch(src, n) if m != nil:
if m != nil: genericAssignAux(dest, src, m, shallow) genericAssignAux(dest, src, m, shallow)
of nkNone: sysAssert(false, "genericAssignAux") of nkNone: sysAssert(false, "genericAssignAux")
#else: #else:
# echo "ugh memory corruption! ", n.kind # echo "ugh memory corruption! ", n.kind

View file

@ -194,6 +194,9 @@ proc quitOrDebug() {.inline.} =
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
e.name = ename e.name = ename
when hasSomeStackTrace:
e.trace = ""
rawWriteStackTrace(e.trace)
if localRaiseHook != nil: if localRaiseHook != nil:
if not localRaiseHook(e): return if not localRaiseHook(e): return
if globalRaiseHook != nil: if globalRaiseHook != nil:
@ -253,6 +256,12 @@ proc getStackTrace(): string =
else: else:
result = "No stack traceback available\n" result = "No stack traceback available\n"
proc getStackTrace(e: ref E_Base): string =
if not isNil(e) and not isNil(e.trace):
result = e.trace
else:
result = ""
when defined(endb): when defined(endb):
var var
dbgAborting: bool # whether the debugger wants to abort dbgAborting: bool # whether the debugger wants to abort

View file

@ -608,9 +608,16 @@ proc parseSmiley(p: var TRstParser): PRstNode =
result.text = val result.text = val
return return
when false:
const
urlChars = {'A'..'Z', 'a'..'z', '0'..'9', ':', '#', '@', '%', '/', ';',
'$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
'\128'..'\255'}
proc isURL(p: TRstParser, i: int): bool = proc isURL(p: TRstParser, i: int): bool =
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
(p.tok[i+3].kind == tkWord) and (p.tok[i+4].symbol == ".") (p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "ftp", "gopher", "telnet", "file"])
proc parseURL(p: var TRstParser, father: PRstNode) = proc parseURL(p: var TRstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<': #if p.tok[p.idx].symbol[strStart] == '<':

View file

@ -40,3 +40,18 @@ template typedef(name: expr, typ: typeDesc) {.immediate.} =
typedef(myint, int) typedef(myint, int)
var x: PMyInt var x: PMyInt
# Test UFCS
type
Foo = object
arg: int
proc initFoo(arg: int): Foo =
result.arg = arg
template create(typ: typeDesc, arg: expr): expr = `init typ`(arg)
var ff = Foo.create(12)
echo ff.arg

11
tests/reject/tenummix.nim Normal file
View file

@ -0,0 +1,11 @@
discard """
file: "system.nim"
line: 640
errormsg: "type mismatch"
"""
type
TE1 = enum eA, eB
TE2 = enum eC, eD
assert eA != eC

27
tests/run/tdumptree.nim Normal file
View file

@ -0,0 +1,27 @@
discard """
disabled: true
output: '''StmtList
VarSection
IdentDefs
Ident !"x"
nil
Call
DotExpr
Ident !"foo"
Ident !"create"
IntLit 56'''
"""
# disabled; can't work as the output is done by the compiler
import macros
#emit("type\n TFoo = object\n bar: int")
#var f: TFoo
#f.bar = 5
#echo(f.bar)
dumpTree:
var x = foo.create(56)

View file

@ -1,5 +1,5 @@
discard """ discard """
output: "0false" output: "0false12"
""" """
# Test multiple generic instantiation of generic proc vars: # Test multiple generic instantiation of generic proc vars:
@ -17,3 +17,20 @@ proc threadProcWrapper[TMsg]() =
threadProcWrapper[int]() threadProcWrapper[int]()
threadProcWrapper[bool]() threadProcWrapper[bool]()
type
TFilterProc[T,D] = proc (item: T, env:D): bool
proc filter[T,D](data: seq[T], env:D, pred: TFilterProc[T,D]): seq[T] =
result = @[]
for e in data:
if pred(e, env): result.add(e)
proc predTest(item: int, value: int): Bool =
return item <= value
proc test(data: seq[int], value: int): seq[int] =
return filter(data, value, predTest)
for x in items(test(@[1,2,3], 2)):
stdout.write(x)

View file

@ -1,6 +1,6 @@
discard """ discard """
file: "tsequtils.nim" file: "tsequtils.nim"
output: '''Zip: [{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}] output: '''Zip: [{"Field0": 1, "Field1": 2}, {"Field0": 3, "Field1": 4}, {"Field0": 5, "Field1": 6}]
Filter Iterator: 3 Filter Iterator: 3
Filter Iterator: 5 Filter Iterator: 5
Filter Iterator: 7 Filter Iterator: 7

View file

@ -1,8 +1,10 @@
version 0.9.0 version 0.9.0
============= =============
- make stack traces part of the exception in debug builds - implement 'gorge'
- make templates hygienic by default - implement a warning message for shadowed 'result' variable
- make templates hygienic by default: try to gensym() everything in the 'block'
of a template
- ``bind`` for overloaded symbols does not work apparently - ``bind`` for overloaded symbols does not work apparently
- ``=`` should be overloadable; requires specialization for ``=`` - ``=`` should be overloadable; requires specialization for ``=``
- fix remaining generics bugs - fix remaining generics bugs
@ -24,6 +26,7 @@ version 0.9.0
- we need to support iteration of 2 different data structures in parallel - we need to support iteration of 2 different data structures in parallel
- make exceptions compatible with C++ exceptions - make exceptions compatible with C++ exceptions
- change how comments are part of the AST - change how comments are part of the AST
- find a better solution for gensym instead of `*ident`
- extract nimdoc properly and document it finally - extract nimdoc properly and document it finally
- rethink the syntax: distinction between expr and stmt is unfortunate; - rethink the syntax: distinction between expr and stmt is unfortunate;
indentation handling is quite complex too; problem with exception handling indentation handling is quite complex too; problem with exception handling
@ -32,17 +35,9 @@ version 0.9.0
error handling more light-weight error handling more light-weight
people also want ``inc a; inc b`` people also want ``inc a; inc b``
Bugs Bugs
---- ----
- bug: generic assign still buggy
- special case the generic assign that needs to care about case objects
- bug: returning a tyVar does not mean it is save to return it:
proc forward[T](x: var T): var T = result = x
proc p(): var int =
var x: int
# reject this call via alias analysis:
result = forward(x)
- bug: stress testing basic method example (eval example) - bug: stress testing basic method example (eval example)
without ``-d:release`` leaks memory? without ``-d:release`` leaks memory?

View file

@ -3,6 +3,9 @@
# result = "#! /bin/sh\n# Generated from niminst\n" & # result = "#! /bin/sh\n# Generated from niminst\n" &
# "# Template is in tools/buildsh.tmpl\n" & # "# Template is in tools/buildsh.tmpl\n" &
# "# To regenerate run ``niminst csource`` or ``koch csource``\n" # "# To regenerate run ``niminst csource`` or ``koch csource``\n"
set -e
while : while :
do do
case "$1" in case "$1" in
@ -108,11 +111,11 @@ case $myos in
# var linkCmd = "" # var linkCmd = ""
# for f in items(c.cfiles[osA][cpuA]): # for f in items(c.cfiles[osA][cpuA]):
echo "$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}" echo "$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}"
$CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")} || exit 1 $CC $COMP_FLAGS -Ibuild -c ?{f} -o ?{changeFileExt(f, "o")}
# add(linkCmd, " \\\n" & changeFileExt(f, "o")) # add(linkCmd, " \\\n" & changeFileExt(f, "o"))
# end for # end for
echo "$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd" echo "$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd"
$LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd || exit 1 $LINKER $LINK_FLAGS -o ?{firstBinPath(c)/toLower(c.name)} ?linkCmd
;; ;;
# end for # end for
*) *)

View file

@ -3,6 +3,8 @@
# result = "#! /bin/sh\n# Generated by niminst\n" # result = "#! /bin/sh\n# Generated by niminst\n"
# var proj = c.name.toLower # var proj = c.name.toLower
set -e
if [ $# -eq 1 ] ; then if [ $# -eq 1 ] ; then
# if c.cat[fcUnixBin].len > 0: # if c.cat[fcUnixBin].len > 0:
if test -f ?{c.cat[fcUnixBin][0]} if test -f ?{c.cat[fcUnixBin][0]}
@ -47,13 +49,13 @@ if [ $# -eq 1 ] ; then
docdir="$1/?proj/doc" docdir="$1/?proj/doc"
datadir="$1/?proj/data" datadir="$1/?proj/data"
mkdir -p $1/?proj || exit 1 mkdir -p $1/?proj
mkdir -p $bindir || exit 1 mkdir -p $bindir
mkdir -p $configdir || exit 1 mkdir -p $configdir
;; ;;
esac esac
mkdir -p $libdir || exit 1 mkdir -p $libdir
mkdir -p $docdir || exit 1 mkdir -p $docdir
echo "copying files..." echo "copying files..."
#var createdDirs = newStringTable() #var createdDirs = newStringTable()
#for cat in fcConfig..fcLib: #for cat in fcConfig..fcLib:
@ -63,30 +65,34 @@ if [ $# -eq 1 ] ; then
# mk = unixDirVars[cat] & "/" & mk # mk = unixDirVars[cat] & "/" & mk
# if not createdDirs.hasKey(mk): # if not createdDirs.hasKey(mk):
# createdDirs[mk] = "true" # createdDirs[mk] = "true"
mkdir -p ?mk || exit 1 mkdir -p ?mk
# end if # end if
# end if # end if
# end for # end for
#end for #end for
#for f in items(c.cat[fcUnixBin]): #for f in items(c.cat[fcUnixBin]):
cp ?f $bindir/?f.skipRoot || exit 1 cp ?f $bindir/?f.skipRoot
chmod 755 $bindir/?f.skipRoot chmod 755 $bindir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcConfig]): #for f in items(c.cat[fcConfig]):
cp ?f $configdir/?f.skipRoot || exit 1 cp ?f $configdir/?f.skipRoot
chmod 644 $configdir/?f.skipRoot chmod 644 $configdir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcData]): #for f in items(c.cat[fcData]):
cp ?f $datadir/?f.skipRoot || exit 1 if [ -f ?f ]; then
chmod 644 $datadir/?f.skipRoot cp ?f $datadir/?f.skipRoot
chmod 644 $datadir/?f.skipRoot
fi
#end for #end for
#for f in items(c.cat[fcDoc]): #for f in items(c.cat[fcDoc]):
cp ?f $docdir/?f.skipRoot || exit 1 if [ -f ?f ]; then
chmod 644 $docdir/?f.skipRoot cp ?f $docdir/?f.skipRoot
chmod 644 $docdir/?f.skipRoot
fi
#end for #end for
#for f in items(c.cat[fcLib]): #for f in items(c.cat[fcLib]):
cp ?f $libdir/?f.skipRoot || exit 1 cp ?f $libdir/?f.skipRoot
chmod 644 $libdir/?f.skipRoot chmod 644 $libdir/?f.skipRoot
#end for #end for

View file

@ -48,6 +48,7 @@ Library Additions
- Added ``system.clamp`` to limit a value within an interval ``[a, b]``. - Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
- Added ``strutils.continuesWith``. - Added ``strutils.continuesWith``.
- Added ``system.getStackTrace``. - Added ``system.getStackTrace``.
- Added ``system.||`` for parallel for loop support.
- The GC supports (soft) realtime systems via ``GC_setMaxPause`` - The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs. and ``GC_step`` procs.
@ -73,6 +74,9 @@ Changes affecting backwards compatibility
- Deprecated ``system.GC_setStrategy``. - Deprecated ``system.GC_setStrategy``.
- ``re.findAll`` and ``pegs.findAll`` don't return *captures* anymore but - ``re.findAll`` and ``pegs.findAll`` don't return *captures* anymore but
matching *substrings*. matching *substrings*.
- RTTI and thus the ``marshall`` module don't contain the proper field names
of tuples anymore. This had to be changed as the old behaviour never
produced consistent results.
Compiler Additions Compiler Additions
@ -86,6 +90,7 @@ Compiler Additions
option or pragma. option or pragma.
- The compiler now generates marker procs that the GC can use instead of RTTI. - The compiler now generates marker procs that the GC can use instead of RTTI.
This speeds up the GC quite a bit. This speeds up the GC quite a bit.
- The compiler now supports OpenMP's parallel for loop.
Language Additions Language Additions