Merge branch 'devel' of github.com:Araq/Nimrod into devel
This commit is contained in:
commit
2cbe46daff
23 changed files with 280 additions and 55 deletions
|
|
@ -489,6 +489,8 @@ const
|
||||||
routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
|
routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||||
skConverter, skMacro, skTemplate}
|
skConverter, skMacro, skTemplate}
|
||||||
tfIncompleteStruct* = tfVarargs
|
tfIncompleteStruct* = tfVarargs
|
||||||
|
tfUncheckedArray* = tfVarargs
|
||||||
|
tfUnion* = tfNoSideEffect
|
||||||
skError* = skUnknown
|
skError* = skUnknown
|
||||||
|
|
||||||
# type flags that are essential for type equality:
|
# type flags that are essential for type equality:
|
||||||
|
|
|
||||||
|
|
@ -681,11 +681,6 @@ proc parseField(p: var TParser, kind: TNodeKind): PNode =
|
||||||
else: result = mangledIdent(p.tok.s, p)
|
else: result = mangledIdent(p.tok.s, p)
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
|
|
||||||
proc takeOnlyFirstField(p: TParser, isUnion: bool): bool =
|
|
||||||
# if we generate an interface to a header file, *all* fields can be
|
|
||||||
# generated:
|
|
||||||
result = isUnion and p.options.header.len == 0
|
|
||||||
|
|
||||||
proc parseStructBody(p: var TParser, isUnion: bool,
|
proc parseStructBody(p: var TParser, isUnion: bool,
|
||||||
kind: TNodeKind = nkRecList): PNode =
|
kind: TNodeKind = nkRecList): PNode =
|
||||||
result = newNodeP(kind, p)
|
result = newNodeP(kind, p)
|
||||||
|
|
@ -698,8 +693,7 @@ proc parseStructBody(p: var TParser, isUnion: bool,
|
||||||
var i = parseField(p, kind)
|
var i = parseField(p, kind)
|
||||||
t = parseTypeSuffix(p, t)
|
t = parseTypeSuffix(p, t)
|
||||||
addSon(def, i, t, ast.emptyNode)
|
addSon(def, i, t, ast.emptyNode)
|
||||||
if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1:
|
addSon(result, def)
|
||||||
addSon(result, def)
|
|
||||||
if p.tok.xkind != pxComma: break
|
if p.tok.xkind != pxComma: break
|
||||||
getTok(p, def)
|
getTok(p, def)
|
||||||
eat(p, pxSemicolon, lastSon(result))
|
eat(p, pxSemicolon, lastSon(result))
|
||||||
|
|
@ -710,11 +704,12 @@ proc structPragmas(p: TParser, name: PNode, origName: string): PNode =
|
||||||
result = newNodeP(nkPragmaExpr, p)
|
result = newNodeP(nkPragmaExpr, p)
|
||||||
addSon(result, exportSym(p, name, origName))
|
addSon(result, exportSym(p, name, origName))
|
||||||
var pragmas = newNodeP(nkPragma, p)
|
var pragmas = newNodeP(nkPragma, p)
|
||||||
addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
|
#addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
|
||||||
if p.options.header.len > 0:
|
if p.options.header.len > 0:
|
||||||
addSon(pragmas, newIdentStrLitPair("importc", origName, p),
|
addSon(pragmas, newIdentStrLitPair("importc", origName, p),
|
||||||
newIdentStrLitPair("header", p.options.header, p))
|
newIdentStrLitPair("header", p.options.header, p))
|
||||||
addSon(result, pragmas)
|
if pragmas.len > 0: addSon(result, pragmas)
|
||||||
|
else: addSon(result, ast.emptyNode)
|
||||||
|
|
||||||
proc enumPragmas(p: TParser, name: PNode): PNode =
|
proc enumPragmas(p: TParser, name: PNode): PNode =
|
||||||
result = newNodeP(nkPragmaExpr, p)
|
result = newNodeP(nkPragmaExpr, p)
|
||||||
|
|
@ -726,9 +721,13 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
|
||||||
addSon(pragmas, e)
|
addSon(pragmas, e)
|
||||||
addSon(result, pragmas)
|
addSon(result, pragmas)
|
||||||
|
|
||||||
proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
||||||
result = newNodeP(nkObjectTy, p)
|
result = newNodeP(nkObjectTy, p)
|
||||||
addSon(result, ast.emptyNode, ast.emptyNode) # no pragmas, no inheritance
|
var pragmas = ast.emptyNode
|
||||||
|
if isUnion:
|
||||||
|
pragmas = newNodeP(nkPragma, p)
|
||||||
|
addSon(pragmas, newIdentNodeP("union", p))
|
||||||
|
addSon(result, pragmas, ast.emptyNode) # no inheritance
|
||||||
if p.tok.xkind == pxCurlyLe:
|
if p.tok.xkind == pxCurlyLe:
|
||||||
addSon(result, parseStructBody(p, isUnion))
|
addSon(result, parseStructBody(p, isUnion))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,13 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||||
if tfShared in t.flags: c &= "shared"
|
if tfShared in t.flags: c &= "shared"
|
||||||
if tfNotNil in t.flags: c &= "not nil"
|
if tfNotNil in t.flags: c &= "not nil"
|
||||||
|
|
||||||
|
proc canonConst(n: PNode): TUid =
|
||||||
|
var c: MD5Context
|
||||||
|
md5Init(c)
|
||||||
|
c.hashTree(n)
|
||||||
|
c.hashType(n.typ)
|
||||||
|
md5Final(c, MD5Digest(result))
|
||||||
|
|
||||||
proc canonSym(s: PSym): TUid
|
proc canonSym(s: PSym): TUid
|
||||||
var c: MD5Context
|
var c: MD5Context
|
||||||
md5Init(c)
|
md5Init(c)
|
||||||
|
|
|
||||||
|
|
@ -736,7 +736,7 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
||||||
var first = intLiteral(firstOrd(ty))
|
var first = intLiteral(firstOrd(ty))
|
||||||
# emit range check:
|
# emit range check:
|
||||||
if (optBoundsCheck in p.options):
|
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
|
||||||
if not isConstExpr(e.sons[1]):
|
if not isConstExpr(e.sons[1]):
|
||||||
# semantic pass has already checked for const index expressions
|
# semantic pass has already checked for const index expressions
|
||||||
if firstOrd(ty) == 0:
|
if firstOrd(ty) == 0:
|
||||||
|
|
|
||||||
|
|
@ -376,10 +376,13 @@ proc getTypePre(m: BModule, typ: PType): PRope =
|
||||||
else:
|
else:
|
||||||
result = getSimpleTypeDesc(m, typ)
|
result = getSimpleTypeDesc(m, typ)
|
||||||
if result == nil: result = cacheGetType(m.typeCache, typ)
|
if result == nil: result = cacheGetType(m.typeCache, typ)
|
||||||
|
|
||||||
|
proc structOrUnion(t: PType): PRope =
|
||||||
|
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||||
|
|
||||||
proc getForwardStructFormat(): string =
|
proc getForwardStructFormat(): string =
|
||||||
if gCmd == cmdCompileToCpp: result = "struct $1;$n"
|
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
|
||||||
else: result = "typedef struct $1 $1;$n"
|
else: result = "typedef $1 $2 $2;$n"
|
||||||
|
|
||||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||||
result = cacheGetType(m.forwTypeCache, typ)
|
result = cacheGetType(m.forwTypeCache, typ)
|
||||||
|
|
@ -390,7 +393,8 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||||
of tySequence, tyTuple, tyObject:
|
of tySequence, tyTuple, tyObject:
|
||||||
result = getTypeName(typ)
|
result = getTypeName(typ)
|
||||||
if not isImportedType(typ):
|
if not isImportedType(typ):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||||
|
[structOrUnion(typ), result])
|
||||||
idTablePut(m.forwTypeCache, typ, result)
|
idTablePut(m.forwTypeCache, typ, result)
|
||||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||||
|
|
||||||
|
|
@ -445,7 +449,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||||
else: ae = sname
|
else: ae = sname
|
||||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
let fieldType = field.loc.t
|
||||||
|
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||||
|
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||||
|
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||||
|
else:
|
||||||
|
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
|
||||||
else: internalError(n.info, "genRecordFieldsAux()")
|
else: internalError(n.info, "genRecordFieldsAux()")
|
||||||
|
|
||||||
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
|
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
|
|
@ -455,23 +464,24 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
check: var TIntSet): PRope =
|
check: var TIntSet): PRope =
|
||||||
# declare the record:
|
# declare the record:
|
||||||
var hasField = false
|
var hasField = false
|
||||||
|
let aStruct = structOrUnion(typ)
|
||||||
if typ.kind == tyObject:
|
if typ.kind == tyObject:
|
||||||
if typ.sons[0] == nil:
|
if typ.sons[0] == nil:
|
||||||
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
|
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
|
||||||
result = ropecg(m, "struct $1 {$n", [name])
|
result = ropecg(m, "$1 $2 {$n", [aStruct, name])
|
||||||
else:
|
else:
|
||||||
result = ropecg(m, "struct $1 {$n#TNimType* m_type;$n", [name])
|
result = ropecg(m, "$1 $2 {$n#TNimType* m_type;$n", [aStruct, name])
|
||||||
hasField = true
|
hasField = true
|
||||||
elif gCmd == cmdCompileToCpp:
|
elif gCmd == cmdCompileToCpp:
|
||||||
result = ropecg(m, "struct $1 : public $2 {$n",
|
result = ropecg(m, "$1 $2 : public $3 {$n",
|
||||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
[aStruct, name, getTypeDescAux(m, typ.sons[0], check)])
|
||||||
hasField = true
|
hasField = true
|
||||||
else:
|
else:
|
||||||
result = ropecg(m, "struct $1 {$n $2 Sup;$n",
|
result = ropecg(m, "$1 $2 {$n $3 Sup;$n",
|
||||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
[aStruct, name, getTypeDescAux(m, typ.sons[0], check)])
|
||||||
hasField = true
|
hasField = true
|
||||||
else:
|
else:
|
||||||
result = ropef("struct $1 {$n", [name])
|
result = ropef("$1 $2 {$n", [aStruct, name])
|
||||||
var desc = getRecordFields(m, typ, check)
|
var desc = getRecordFields(m, typ, check)
|
||||||
if (desc == nil) and not hasField:
|
if (desc == nil) and not hasField:
|
||||||
appf(result, "char dummy;$n", [])
|
appf(result, "char dummy;$n", [])
|
||||||
|
|
@ -480,8 +490,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
app(result, "};" & tnl)
|
app(result, "};" & tnl)
|
||||||
|
|
||||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||||
check: var TIntSet): PRope =
|
check: var TIntSet): PRope =
|
||||||
result = ropef("struct $1 {$n", [name])
|
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||||
var desc: PRope = nil
|
var desc: PRope = nil
|
||||||
for i in countup(0, sonsLen(typ) - 1):
|
for i in countup(0, sonsLen(typ) - 1):
|
||||||
appf(desc, "$1 Field$2;$n",
|
appf(desc, "$1 Field$2;$n",
|
||||||
|
|
@ -557,7 +567,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = getTypeName(t)
|
result = getTypeName(t)
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||||
|
[structOrUnion(t), result])
|
||||||
idTablePut(m.forwTypeCache, t, result)
|
idTablePut(m.forwTypeCache, t, result)
|
||||||
assert(cacheGetType(m.typeCache, t) == nil)
|
assert(cacheGetType(m.typeCache, t) == nil)
|
||||||
idTablePut(m.typeCache, t, con(result, "*"))
|
idTablePut(m.typeCache, t, con(result, "*"))
|
||||||
|
|
@ -588,7 +599,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = getTypeName(t)
|
result = getTypeName(t)
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||||
|
[structOrUnion(t), 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.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
|
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ proc initDefines*() =
|
||||||
defineSymbol("nimeffects")
|
defineSymbol("nimeffects")
|
||||||
defineSymbol("nimbabel")
|
defineSymbol("nimbabel")
|
||||||
defineSymbol("nimcomputedgoto")
|
defineSymbol("nimcomputedgoto")
|
||||||
|
defineSymbol("nimunion")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
case targetCPU
|
case targetCPU
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
incl(result.flags, sfDiscardable)
|
incl(result.flags, sfDiscardable)
|
||||||
# pretend it's imported from some unknown module to prevent cascading errors:
|
# pretend it's imported from some unknown module to prevent cascading errors:
|
||||||
if gCmd != cmdInteractive:
|
if gCmd != cmdInteractive and c.inCompilesContext == 0:
|
||||||
c.importTable.addSym(result)
|
c.importTable.addSym(result)
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ const
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
wRaises, wTags}
|
wRaises, wTags}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||||
wInheritable, wGensym, wInject, wRequiresInit}
|
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportCpp, wImportObjC, wError}
|
wImportCpp, wImportObjC, wError}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
|
|
@ -718,6 +718,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
else: incl(sym.typ.flags, tfIncompleteStruct)
|
else: incl(sym.typ.flags, tfIncompleteStruct)
|
||||||
|
of wUnchecked:
|
||||||
|
noVal(it)
|
||||||
|
if sym.typ == nil: invalidPragma(it)
|
||||||
|
else: incl(sym.typ.flags, tfUncheckedArray)
|
||||||
|
of wUnion:
|
||||||
|
noVal(it)
|
||||||
|
if sym.typ == nil: invalidPragma(it)
|
||||||
|
else: incl(sym.typ.flags, tfUnion)
|
||||||
of wRequiresInit:
|
of wRequiresInit:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
|
|
|
||||||
|
|
@ -1323,7 +1323,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = enforceVoidContext
|
n.typ = enforceVoidContext
|
||||||
if i == last and efWantValue in flags:
|
if i == last and (length == 1 or efWantValue in flags):
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
elif i != last or voidContext or c.inTypeClass > 0:
|
elif i != last or voidContext or c.inTypeClass > 0:
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ type
|
||||||
|
|
||||||
PProc* = ref object
|
PProc* = ref object
|
||||||
blocks*: seq[TBlock] # blocks; temp data structure
|
blocks*: seq[TBlock] # blocks; temp data structure
|
||||||
|
sym*: PSym
|
||||||
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
|
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
|
||||||
maxSlots*: int
|
maxSlots*: int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -980,6 +980,25 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||||
inc c.prc.maxSlots
|
inc c.prc.maxSlots
|
||||||
|
|
||||||
|
proc cannotEval(n: PNode) {.noinline.} =
|
||||||
|
globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
|
||||||
|
n.renderTree)
|
||||||
|
|
||||||
|
proc isOwnedBy(a, b: PSym): bool =
|
||||||
|
var a = a.owner
|
||||||
|
while a != nil and a.kind != skModule:
|
||||||
|
if a == b: return true
|
||||||
|
a = a.owner
|
||||||
|
|
||||||
|
proc checkCanEval(c: PCtx; n: PNode) =
|
||||||
|
# we need to ensure that we don't evaluate 'x' here:
|
||||||
|
# proc foo() = var x ...
|
||||||
|
let s = n.sym
|
||||||
|
if s.position == 0:
|
||||||
|
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
|
||||||
|
not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
|
||||||
|
cannotEval(n)
|
||||||
|
|
||||||
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
case le.kind
|
case le.kind
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
|
|
@ -1007,6 +1026,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let s = le.sym
|
let s = le.sym
|
||||||
|
checkCanEval(c, le)
|
||||||
if s.isGlobal:
|
if s.isGlobal:
|
||||||
withTemp(tmp, le.typ):
|
withTemp(tmp, le.typ):
|
||||||
c.gen(le, tmp, {gfAddrOf})
|
c.gen(le, tmp, {gfAddrOf})
|
||||||
|
|
@ -1014,7 +1034,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
c.gABC(le, opcWrDeref, tmp, val)
|
c.gABC(le, opcWrDeref, tmp, val)
|
||||||
c.freeTemp(val)
|
c.freeTemp(val)
|
||||||
else:
|
else:
|
||||||
if s.kind == skForVar and c.mode == emRepl: c.setSlot s
|
if s.kind == skForVar: c.setSlot s
|
||||||
internalAssert s.position > 0 or (s.position == 0 and
|
internalAssert s.position > 0 or (s.position == 0 and
|
||||||
s.kind in {skParam,skResult})
|
s.kind in {skParam,skResult})
|
||||||
var dest: TRegister = s.position + ord(s.kind == skParam)
|
var dest: TRegister = s.position + ord(s.kind == skParam)
|
||||||
|
|
@ -1046,10 +1066,6 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
|
||||||
localError(info, errGenerated,
|
localError(info, errGenerated,
|
||||||
"cannot 'importc' variable at compile time")
|
"cannot 'importc' variable at compile time")
|
||||||
|
|
||||||
proc cannotEval(n: PNode) {.noinline.} =
|
|
||||||
globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
|
|
||||||
n.renderTree)
|
|
||||||
|
|
||||||
proc getNullValue*(typ: PType, info: TLineInfo): PNode
|
proc getNullValue*(typ: PType, info: TLineInfo): PNode
|
||||||
|
|
||||||
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||||
|
|
@ -1190,12 +1206,14 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||||
setSlot(c, a[i].sym)
|
setSlot(c, a[i].sym)
|
||||||
# v = t[i]
|
# v = t[i]
|
||||||
var v: TDest = -1
|
var v: TDest = -1
|
||||||
|
checkCanEval(c, a[i])
|
||||||
genRdVar(c, a[i], v, {gfAddrOf})
|
genRdVar(c, a[i], v, {gfAddrOf})
|
||||||
c.gABC(n, opcWrObj, v, tmp, i)
|
c.gABC(n, opcWrObj, v, tmp, i)
|
||||||
# XXX globals?
|
# XXX globals?
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
elif a.sons[0].kind == nkSym:
|
elif a.sons[0].kind == nkSym:
|
||||||
let s = a.sons[0].sym
|
let s = a.sons[0].sym
|
||||||
|
checkCanEval(c, a.sons[0])
|
||||||
if s.isGlobal:
|
if s.isGlobal:
|
||||||
if s.position == 0:
|
if s.position == 0:
|
||||||
if sfImportc in s.flags: c.importcSym(a.info, s)
|
if sfImportc in s.flags: c.importcSym(a.info, s)
|
||||||
|
|
@ -1308,6 +1326,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
|
checkCanEval(c, n)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skVar, skForVar, skTemp, skLet, skParam, skResult:
|
of skVar, skForVar, skTemp, skLet, skParam, skResult:
|
||||||
genRdVar(c, n, dest, flags)
|
genRdVar(c, n, dest, flags)
|
||||||
|
|
@ -1525,7 +1544,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
# procs easily:
|
# procs easily:
|
||||||
let body = s.getBody
|
let body = s.getBody
|
||||||
let procStart = c.xjmp(body, opcJmp, 0)
|
let procStart = c.xjmp(body, opcJmp, 0)
|
||||||
var p = PProc(blocks: @[])
|
var p = PProc(blocks: @[], sym: s)
|
||||||
let oldPrc = c.prc
|
let oldPrc = c.prc
|
||||||
c.prc = p
|
c.prc = p
|
||||||
# iterate over the parameters and allocate space for them:
|
# iterate over the parameters and allocate space for them:
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ type
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||||
wAsmNoStackFrame,
|
wAsmNoStackFrame,
|
||||||
wImplicitStatic, wGlobal, wCodegenDecl,
|
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked,
|
||||||
|
|
||||||
wAuto, wBool, wCatch, wChar, wClass,
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||||
|
|
@ -145,7 +145,7 @@ const
|
||||||
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||||
"computedgoto", "injectstmt",
|
"computedgoto", "injectstmt",
|
||||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||||
"asmnostackframe", "implicitstatic", "global", "codegendecl",
|
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||||
|
|
||||||
"auto", "bool", "catch", "char", "class",
|
"auto", "bool", "catch", "char", "class",
|
||||||
"const_cast", "default", "delete", "double",
|
"const_cast", "default", "delete", "double",
|
||||||
|
|
|
||||||
|
|
@ -5320,6 +5320,53 @@ strings automatically:
|
||||||
printf("hallo %s", "world") # "world" will be passed as C string
|
printf("hallo %s", "world") # "world" will be passed as C string
|
||||||
|
|
||||||
|
|
||||||
|
Union pragma
|
||||||
|
------------
|
||||||
|
The `union`:idx: pragma can be applied to any ``object`` type. It means all
|
||||||
|
of the object's fields are overlaid in memory. This produces a ``union``
|
||||||
|
instead of a ``struct`` in the generated C/C++ code. The object declaration
|
||||||
|
then must not use inheritance or any GC'ed memory but this is currently not
|
||||||
|
checked.
|
||||||
|
|
||||||
|
**Future directions**: GC'ed memory should be allowed in unions and the GC
|
||||||
|
should scan unions conservatively.
|
||||||
|
|
||||||
|
|
||||||
|
Unchecked pragma
|
||||||
|
----------------
|
||||||
|
The `unchecked`:idx: pragma can be used to mark a named array as ``unchecked``
|
||||||
|
meaning its bounds are not checked. This is often useful when one wishes to
|
||||||
|
implement his own flexibly sized arrays. Additionally an unchecked array is
|
||||||
|
translated into a C array of undetermined size:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
ArrayPart{.unchecked.} = array[0..0, int]
|
||||||
|
MySeq = object
|
||||||
|
len, cap: int
|
||||||
|
data: ArrayPart
|
||||||
|
|
||||||
|
Produces roughly this C code:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
typedef struct {
|
||||||
|
NI len;
|
||||||
|
NI cap;
|
||||||
|
NI data[];
|
||||||
|
} MySeq;
|
||||||
|
|
||||||
|
The bounds checking done at compile time is not disabled for now, so to access
|
||||||
|
``s.data[C]`` (where ``C`` is a constant) the array's index needs needs to
|
||||||
|
include ``C``.
|
||||||
|
|
||||||
|
The base type of the unchecked array may not contain any GC'ed memory but this
|
||||||
|
is currently not checked.
|
||||||
|
|
||||||
|
**Future directions**: GC'ed memory should be allowed in unchecked arrays and
|
||||||
|
there should be an explicit annotation of how the GC is to determine the
|
||||||
|
runtime size of the array.
|
||||||
|
|
||||||
|
|
||||||
Dynlib pragma for import
|
Dynlib pragma for import
|
||||||
------------------------
|
------------------------
|
||||||
With the `dynlib`:idx: pragma a procedure or a variable can be imported from
|
With the `dynlib`:idx: pragma a procedure or a variable can be imported from
|
||||||
|
|
|
||||||
|
|
@ -285,8 +285,8 @@ static N_INLINE(NI32, float32ToInt32)(float x) {
|
||||||
|
|
||||||
typedef struct TStringDesc* string;
|
typedef struct TStringDesc* string;
|
||||||
|
|
||||||
/* declared size of a sequence: */
|
/* declared size of a sequence/variable length array: */
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
|
||||||
# define SEQ_DECL_SIZE /* empty is correct! */
|
# define SEQ_DECL_SIZE /* empty is correct! */
|
||||||
#else
|
#else
|
||||||
# define SEQ_DECL_SIZE 1000000
|
# define SEQ_DECL_SIZE 1000000
|
||||||
|
|
@ -373,5 +373,8 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
|
||||||
# define GC_GUARD
|
# define GC_GUARD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Test to see if nimrod and the C compiler agrees on the size of a pointer.
|
||||||
|
On disagreement, your C compiler will say something like:
|
||||||
|
"error: 'assert_numbits' declared as an array with a negative size" */
|
||||||
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,8 @@ proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} =
|
||||||
|
|
||||||
when not defined(niminheritable):
|
when not defined(niminheritable):
|
||||||
{.pragma: inheritable.}
|
{.pragma: inheritable.}
|
||||||
|
when not defined(nimunion):
|
||||||
|
{.pragma: unchecked.}
|
||||||
|
|
||||||
const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
|
const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
|
||||||
## "fake variables" like 'var EBADF {.importc.}: cint'.
|
## "fake variables" like 'var EBADF {.importc.}: cint'.
|
||||||
|
|
@ -194,9 +196,10 @@ when not defined(JS):
|
||||||
TGenericSeq {.compilerproc, pure, inheritable.} = object
|
TGenericSeq {.compilerproc, pure, inheritable.} = object
|
||||||
len, reserved: int
|
len, reserved: int
|
||||||
PGenericSeq {.exportc.} = ptr TGenericSeq
|
PGenericSeq {.exportc.} = ptr TGenericSeq
|
||||||
|
UncheckedCharArray {.unchecked.} = array[0..100_000_000, char]
|
||||||
# len and space without counting the terminating zero:
|
# len and space without counting the terminating zero:
|
||||||
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
|
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
|
||||||
data: array[0..100_000_000, char]
|
data: UncheckedCharArray
|
||||||
NimString = ptr NimStringDesc
|
NimString = ptr NimStringDesc
|
||||||
|
|
||||||
when not defined(JS) and not defined(NimrodVM):
|
when not defined(JS) and not defined(NimrodVM):
|
||||||
|
|
@ -1161,6 +1164,14 @@ when not defined(nimrodVM):
|
||||||
## from it before writing to it is undefined behaviour!
|
## from it before writing to it is undefined behaviour!
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `allocShared` to allocate from a shared heap.
|
## Use `allocShared` to allocate from a shared heap.
|
||||||
|
proc alloc*(T: typedesc, size = 1): ptr T {.inline.} =
|
||||||
|
## allocates a new memory block with at least ``T.sizeof * size``
|
||||||
|
## bytes. The block has to be freed with ``realloc(block, 0)`` or
|
||||||
|
## ``dealloc(block)``. The block is not initialized, so reading
|
||||||
|
## from it before writing to it is undefined behaviour!
|
||||||
|
## The allocated memory belongs to its allocating thread!
|
||||||
|
## Use `allocShared` to allocate from a shared heap.
|
||||||
|
cast[ptr T](alloc(T.sizeof * size))
|
||||||
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
|
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
|
||||||
## allocates a new memory block with at least ``size`` bytes. The
|
## allocates a new memory block with at least ``size`` bytes. The
|
||||||
## block has to be freed with ``realloc(block, 0)`` or
|
## block has to be freed with ``realloc(block, 0)`` or
|
||||||
|
|
@ -1168,14 +1179,31 @@ when not defined(nimrodVM):
|
||||||
## containing zero, so it is somewhat safer than ``alloc``.
|
## containing zero, so it is somewhat safer than ``alloc``.
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `allocShared0` to allocate from a shared heap.
|
## Use `allocShared0` to allocate from a shared heap.
|
||||||
proc realloc*(p: pointer, newsize: int): pointer {.noconv, rtl, tags: [].}
|
proc alloc0*(T: typedesc, size = 1): ptr T {.inline.} =
|
||||||
|
## allocates a new memory block with at least ``T.sizeof * size``
|
||||||
|
## bytes. The block has to be freed with ``realloc(block, 0)`` or
|
||||||
|
## ``dealloc(block)``. The block is initialized with all bytes
|
||||||
|
## containing zero, so it is somewhat safer than ``alloc``.
|
||||||
|
## The allocated memory belongs to its allocating thread!
|
||||||
|
## Use `allocShared0` to allocate from a shared heap.
|
||||||
|
cast[ptr T](alloc0(T.sizeof * size))
|
||||||
|
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
## memory block is returned. In either way the block has at least
|
## memory block is returned. In either way the block has at least
|
||||||
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
|
||||||
## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
|
## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
|
||||||
## be freed with ``dealloc``.
|
## be freed with ``dealloc``.
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `reallocShared` to reallocate from a shared heap.
|
## Use `reallocShared` to reallocate from a shared heap.
|
||||||
|
proc reallocType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
|
||||||
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
|
## memory block is returned. In either way the block has at least
|
||||||
|
## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
|
||||||
|
## **nil** ``realloc`` calls ``dealloc(p)``. In other cases the block
|
||||||
|
## has to be freed with ``dealloc``. The allocated memory belongs to
|
||||||
|
## its allocating thread!
|
||||||
|
## Use `reallocShared` to reallocate from a shared heap.
|
||||||
|
cast[ptr T](realloc(p, T.sizeof * newSize))
|
||||||
proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
|
proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
|
||||||
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
||||||
## ``realloc``. This procedure is dangerous! If one forgets to
|
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||||
|
|
@ -1184,25 +1212,45 @@ when not defined(nimrodVM):
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
## The freed memory must belong to its allocating thread!
|
## The freed memory must belong to its allocating thread!
|
||||||
## Use `deallocShared` to deallocate from a shared heap.
|
## Use `deallocShared` to deallocate from a shared heap.
|
||||||
|
|
||||||
proc allocShared*(size: int): pointer {.noconv, rtl.}
|
proc allocShared*(size: int): pointer {.noconv, rtl.}
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
||||||
## is not initialized, so reading from it before writing to it is
|
## is not initialized, so reading from it before writing to it is
|
||||||
## undefined behaviour!
|
## undefined behaviour!
|
||||||
|
proc allocShared*(T: typedesc, size: int): ptr T {.inline.} =
|
||||||
|
## allocates a new memory block on the shared heap with at
|
||||||
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
||||||
|
## is not initialized, so reading from it before writing to it is
|
||||||
|
## undefined behaviour!
|
||||||
|
cast[ptr T](allocShared(T.sizeof * size))
|
||||||
proc allocShared0*(size: int): pointer {.noconv, rtl.}
|
proc allocShared0*(size: int): pointer {.noconv, rtl.}
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``allocShared``.
|
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||||
proc reallocShared*(p: pointer, newsize: int): pointer {.noconv, rtl.}
|
proc allocShared0*(T: typedesc, size: int): ptr T {.inline.} =
|
||||||
|
## allocates a new memory block on the shared heap with at
|
||||||
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||||
|
## The block is initialized with all bytes
|
||||||
|
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||||
|
cast[ptr T](allocShared(T.sizeof * size))
|
||||||
|
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.}
|
||||||
## grows or shrinks a given memory block on the heap. If p is **nil**
|
## grows or shrinks a given memory block on the heap. If p is **nil**
|
||||||
## then a new memory block is returned. In either way the block has at least
|
## then a new memory block is returned. In either way the block has at
|
||||||
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
|
||||||
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
|
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
|
||||||
## block has to be freed with ``deallocShared``.
|
## block has to be freed with ``deallocShared``.
|
||||||
|
proc reallocSharedType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
|
||||||
|
## grows or shrinks a given memory block on the heap. If p is **nil**
|
||||||
|
## then a new memory block is returned. In either way the block has at
|
||||||
|
## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
|
||||||
|
## not **nil** ``reallocShared`` calls ``deallocShared(p)``. In other
|
||||||
|
## cases the block has to be freed with ``deallocShared``.
|
||||||
|
cast[ptr T](reallocShared(p, T.sizeof * newSize))
|
||||||
proc deallocShared*(p: pointer) {.noconv, rtl.}
|
proc deallocShared*(p: pointer) {.noconv, rtl.}
|
||||||
## frees the memory allocated with ``allocShared``, ``allocShared0`` or
|
## frees the memory allocated with ``allocShared``, ``allocShared0`` or
|
||||||
## ``reallocShared``. This procedure is dangerous! If one forgets to
|
## ``reallocShared``. This procedure is dangerous! If one forgets to
|
||||||
|
|
|
||||||
|
|
@ -299,12 +299,12 @@ proc open*(address: string, server: bool, mode: TConnectionMode = conDEALER,
|
||||||
else:
|
else:
|
||||||
if connect(result.s, address) != 0'i32: zmqError()
|
if connect(result.s, address) != 0'i32: zmqError()
|
||||||
|
|
||||||
proc close*(c: var TConnection) =
|
proc close*(c: TConnection) =
|
||||||
## closes the connection.
|
## closes the connection.
|
||||||
if close(c.s) != 0'i32: zmqError()
|
if close(c.s) != 0'i32: zmqError()
|
||||||
if term(c.c) != 0'i32: zmqError()
|
if term(c.c) != 0'i32: zmqError()
|
||||||
|
|
||||||
proc send*(c: var TConnection, msg: string) =
|
proc send*(c: TConnection, msg: string) =
|
||||||
## sends a message over the connection.
|
## sends a message over the connection.
|
||||||
var m: TMsg
|
var m: TMsg
|
||||||
if msg_init(m, msg.len) != 0'i32: zmqError()
|
if msg_init(m, msg.len) != 0'i32: zmqError()
|
||||||
|
|
@ -312,7 +312,7 @@ proc send*(c: var TConnection, msg: string) =
|
||||||
if send(c.s, m, 0'i32) != 0'i32: zmqError()
|
if send(c.s, m, 0'i32) != 0'i32: zmqError()
|
||||||
discard msg_close(m)
|
discard msg_close(m)
|
||||||
|
|
||||||
proc receive*(c: var TConnection): string =
|
proc receive*(c: TConnection): string =
|
||||||
## receives a message from a connection.
|
## receives a message from a connection.
|
||||||
var m: TMsg
|
var m: TMsg
|
||||||
if msg_init(m) != 0'i32: zmqError()
|
if msg_init(m) != 0'i32: zmqError()
|
||||||
|
|
@ -320,4 +320,3 @@ proc receive*(c: var TConnection): string =
|
||||||
result = newString(msg_size(m))
|
result = newString(msg_size(m))
|
||||||
copyMem(addr(result[0]), msg_data(m), result.len)
|
copyMem(addr(result[0]), msg_data(m), result.len)
|
||||||
discard msg_close(m)
|
discard msg_close(m)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ If you are on a fairly modern *nix system, the following steps should work:
|
||||||
$ git clone git://github.com/Araq/Nimrod.git
|
$ git clone git://github.com/Araq/Nimrod.git
|
||||||
$ cd Nimrod
|
$ cd Nimrod
|
||||||
$ git clone --depth 1 git://github.com/nimrod-code/csources
|
$ git clone --depth 1 git://github.com/nimrod-code/csources
|
||||||
$ cd csources && ./build.sh
|
$ cd csources && sh build.sh
|
||||||
$ cd ..
|
$ cd ..
|
||||||
$ bin/nimrod c koch
|
$ bin/nimrod c koch
|
||||||
$ ./koch boot -d:release
|
$ ./koch boot -d:release
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,5 @@ ok supports(`+`, 34)
|
||||||
|
|
||||||
no compiles(4+5.0 * "hallo")
|
no compiles(4+5.0 * "hallo")
|
||||||
|
|
||||||
|
no compiles(undeclaredIdentifier)
|
||||||
|
no compiles(undeclaredIdentifier)
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,19 @@ proc q[T](x, y: T): T {.discardable.} =
|
||||||
p(8, 2)
|
p(8, 2)
|
||||||
q[float](0.8, 0.2)
|
q[float](0.8, 0.2)
|
||||||
|
|
||||||
|
# bug #942
|
||||||
|
|
||||||
|
template maybeMod(x: Tinteger, module:Natural):expr =
|
||||||
|
if module > 0: x mod module
|
||||||
|
else: x
|
||||||
|
|
||||||
|
proc foo(b: int):int =
|
||||||
|
var x = 1
|
||||||
|
result = x.maybeMod(b) # Works fine
|
||||||
|
|
||||||
|
proc bar(b: int):int =
|
||||||
|
result = 1
|
||||||
|
result = result.maybeMod(b) # Error: value returned by statement has to be discarded
|
||||||
|
|
||||||
|
echo foo(0)
|
||||||
|
echo bar(0)
|
||||||
|
|
|
||||||
45
tests/system/alloc.nim
Normal file
45
tests/system/alloc.nim
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
var x: ptr int
|
||||||
|
|
||||||
|
x = cast[ptr int](alloc(7))
|
||||||
|
assert x != nil
|
||||||
|
|
||||||
|
x = alloc(int, 3)
|
||||||
|
assert x != nil
|
||||||
|
x.dealloc()
|
||||||
|
|
||||||
|
x = alloc0(int, 4)
|
||||||
|
assert cast[ptr array[4, int]](x)[0] == 0
|
||||||
|
assert cast[ptr array[4, int]](x)[1] == 0
|
||||||
|
assert cast[ptr array[4, int]](x)[2] == 0
|
||||||
|
assert cast[ptr array[4, int]](x)[3] == 0
|
||||||
|
|
||||||
|
x = cast[ptr int](x.realloc(2))
|
||||||
|
assert x != nil
|
||||||
|
|
||||||
|
x = x.reallocType(4)
|
||||||
|
assert x != nil
|
||||||
|
x.dealloc()
|
||||||
|
|
||||||
|
x = cast[ptr int](allocShared(100))
|
||||||
|
assert x != nil
|
||||||
|
deallocShared(x)
|
||||||
|
|
||||||
|
x = allocShared(int, 3)
|
||||||
|
assert x != nil
|
||||||
|
x.deallocShared()
|
||||||
|
|
||||||
|
x = allocShared0(int, 3)
|
||||||
|
assert x != nil
|
||||||
|
assert cast[ptr array[3, int]](x)[0] == 0
|
||||||
|
assert cast[ptr array[3, int]](x)[1] == 0
|
||||||
|
assert cast[ptr array[3, int]](x)[2] == 0
|
||||||
|
|
||||||
|
x = cast[ptr int](reallocShared(x, 2))
|
||||||
|
assert x != nil
|
||||||
|
|
||||||
|
x = reallocType(x, 12)
|
||||||
|
assert x != nil
|
||||||
|
|
||||||
|
x = reallocSharedType(x, 1)
|
||||||
|
assert x != nil
|
||||||
|
x.deallocShared()
|
||||||
13
tests/vm/twrongwhen.nim
Normal file
13
tests/vm/twrongwhen.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: "Error: cannot evaluate at compile time: x"
|
||||||
|
line: 7
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc bla(x:int) =
|
||||||
|
when x == 0:
|
||||||
|
echo "oops"
|
||||||
|
else:
|
||||||
|
echo "good"
|
||||||
|
|
||||||
|
bla(2) # echos "oops"
|
||||||
|
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -27,7 +27,7 @@ version 0.9.x
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- memory manager: add a measure of fragmentation
|
- memory manager: add a measure of fragmentation
|
||||||
- implement 'union' and 'bits' pragmas
|
- implement 'bits' pragmas
|
||||||
- fix closures/lambdalifting
|
- fix closures/lambdalifting
|
||||||
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
- ensure (ref T)(a, b) works as a type conversion and type constructor
|
||||||
- optimize 'genericReset'; 'newException' leads to code bloat
|
- optimize 'genericReset'; 'newException' leads to code bloat
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@ News
|
||||||
virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
|
virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
|
||||||
evaluation.
|
evaluation.
|
||||||
- ``--gc:none`` produces warnings when code uses the GC.
|
- ``--gc:none`` produces warnings when code uses the GC.
|
||||||
|
- A ``union`` pragma for better C interoperability is now supported.
|
||||||
|
- Arrays can be annotated to be ``unchecked`` for easier low level
|
||||||
|
manipulations of memory.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue