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,
|
||||
skConverter, skMacro, skTemplate}
|
||||
tfIncompleteStruct* = tfVarargs
|
||||
tfUncheckedArray* = tfVarargs
|
||||
tfUnion* = tfNoSideEffect
|
||||
skError* = skUnknown
|
||||
|
||||
# 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)
|
||||
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,
|
||||
kind: TNodeKind = nkRecList): PNode =
|
||||
result = newNodeP(kind, p)
|
||||
|
|
@ -698,8 +693,7 @@ proc parseStructBody(p: var TParser, isUnion: bool,
|
|||
var i = parseField(p, kind)
|
||||
t = parseTypeSuffix(p, t)
|
||||
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
|
||||
getTok(p, def)
|
||||
eat(p, pxSemicolon, lastSon(result))
|
||||
|
|
@ -710,11 +704,12 @@ proc structPragmas(p: TParser, name: PNode, origName: string): PNode =
|
|||
result = newNodeP(nkPragmaExpr, p)
|
||||
addSon(result, exportSym(p, name, origName))
|
||||
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:
|
||||
addSon(pragmas, newIdentStrLitPair("importc", origName, 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 =
|
||||
result = newNodeP(nkPragmaExpr, p)
|
||||
|
|
@ -726,9 +721,13 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
|
|||
addSon(pragmas, e)
|
||||
addSon(result, pragmas)
|
||||
|
||||
proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
||||
proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
||||
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:
|
||||
addSon(result, parseStructBody(p, isUnion))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -161,6 +161,13 @@ proc hashType(c: var MD5Context, t: PType) =
|
|||
if tfShared in t.flags: c &= "shared"
|
||||
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
|
||||
var c: MD5Context
|
||||
md5Init(c)
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
||||
var first = intLiteral(firstOrd(ty))
|
||||
# emit range check:
|
||||
if (optBoundsCheck in p.options):
|
||||
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
|
||||
if not isConstExpr(e.sons[1]):
|
||||
# semantic pass has already checked for const index expressions
|
||||
if firstOrd(ty) == 0:
|
||||
|
|
|
|||
|
|
@ -376,10 +376,13 @@ proc getTypePre(m: BModule, typ: PType): PRope =
|
|||
else:
|
||||
result = getSimpleTypeDesc(m, typ)
|
||||
if result == nil: result = cacheGetType(m.typeCache, typ)
|
||||
|
||||
|
||||
proc structOrUnion(t: PType): PRope =
|
||||
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||
|
||||
proc getForwardStructFormat(): string =
|
||||
if gCmd == cmdCompileToCpp: result = "struct $1;$n"
|
||||
else: result = "typedef struct $1 $1;$n"
|
||||
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
|
||||
else: result = "typedef $1 $2 $2;$n"
|
||||
|
||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
result = cacheGetType(m.forwTypeCache, typ)
|
||||
|
|
@ -390,7 +393,8 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
|||
of tySequence, tyTuple, tyObject:
|
||||
result = getTypeName(typ)
|
||||
if not isImportedType(typ):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
[structOrUnion(typ), result])
|
||||
idTablePut(m.forwTypeCache, typ, result)
|
||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||
|
||||
|
|
@ -445,7 +449,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
|||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||
else: ae = sname
|
||||
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()")
|
||||
|
||||
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 =
|
||||
# declare the record:
|
||||
var hasField = false
|
||||
let aStruct = structOrUnion(typ)
|
||||
if typ.kind == tyObject:
|
||||
if typ.sons[0] == nil:
|
||||
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:
|
||||
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
|
||||
elif gCmd == cmdCompileToCpp:
|
||||
result = ropecg(m, "struct $1 : public $2 {$n",
|
||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
result = ropecg(m, "$1 $2 : public $3 {$n",
|
||||
[aStruct, name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
else:
|
||||
result = ropecg(m, "struct $1 {$n $2 Sup;$n",
|
||||
[name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
result = ropecg(m, "$1 $2 {$n $3 Sup;$n",
|
||||
[aStruct, name, getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
else:
|
||||
result = ropef("struct $1 {$n", [name])
|
||||
result = ropef("$1 $2 {$n", [aStruct, name])
|
||||
var desc = getRecordFields(m, typ, check)
|
||||
if (desc == nil) and not hasField:
|
||||
appf(result, "char dummy;$n", [])
|
||||
|
|
@ -480,8 +490,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
|||
app(result, "};" & tnl)
|
||||
|
||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var TIntSet): PRope =
|
||||
result = ropef("struct $1 {$n", [name])
|
||||
check: var TIntSet): PRope =
|
||||
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||
var desc: PRope = nil
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
appf(desc, "$1 Field$2;$n",
|
||||
|
|
@ -557,7 +567,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
|||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result])
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
assert(cacheGetType(m.typeCache, t) == nil)
|
||||
idTablePut(m.typeCache, t, con(result, "*"))
|
||||
|
|
@ -588,7 +599,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
|||
if result == nil:
|
||||
result = getTypeName(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.typeCache, t, result) # always call for sideeffects:
|
||||
if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ proc initDefines*() =
|
|||
defineSymbol("nimeffects")
|
||||
defineSymbol("nimbabel")
|
||||
defineSymbol("nimcomputedgoto")
|
||||
defineSymbol("nimunion")
|
||||
|
||||
# add platform specific symbols:
|
||||
case targetCPU
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
|||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# 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)
|
||||
|
||||
type
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ const
|
|||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||
wRaises, wTags}
|
||||
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,
|
||||
wInheritable, wGensym, wInject, wRequiresInit}
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
|
|
@ -718,6 +718,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
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:
|
||||
noVal(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]):
|
||||
voidContext = true
|
||||
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
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
elif i != last or voidContext or c.inTypeClass > 0:
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ type
|
|||
|
||||
PProc* = ref object
|
||||
blocks*: seq[TBlock] # blocks; temp data structure
|
||||
sym*: PSym
|
||||
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
|
||||
maxSlots*: int
|
||||
|
||||
|
|
|
|||
|
|
@ -980,6 +980,25 @@ proc setSlot(c: PCtx; v: PSym) =
|
|||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||
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) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
|
|
@ -1007,6 +1026,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
|||
c.freeTemp(tmp)
|
||||
of nkSym:
|
||||
let s = le.sym
|
||||
checkCanEval(c, le)
|
||||
if s.isGlobal:
|
||||
withTemp(tmp, le.typ):
|
||||
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.freeTemp(val)
|
||||
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
|
||||
s.kind in {skParam,skResult})
|
||||
var dest: TRegister = s.position + ord(s.kind == skParam)
|
||||
|
|
@ -1046,10 +1066,6 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
|
|||
localError(info, errGenerated,
|
||||
"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 genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||
|
|
@ -1190,12 +1206,14 @@ proc genVarSection(c: PCtx; n: PNode) =
|
|||
setSlot(c, a[i].sym)
|
||||
# v = t[i]
|
||||
var v: TDest = -1
|
||||
checkCanEval(c, a[i])
|
||||
genRdVar(c, a[i], v, {gfAddrOf})
|
||||
c.gABC(n, opcWrObj, v, tmp, i)
|
||||
# XXX globals?
|
||||
c.freeTemp(tmp)
|
||||
elif a.sons[0].kind == nkSym:
|
||||
let s = a.sons[0].sym
|
||||
checkCanEval(c, a.sons[0])
|
||||
if s.isGlobal:
|
||||
if s.position == 0:
|
||||
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
|
||||
of nkSym:
|
||||
let s = n.sym
|
||||
checkCanEval(c, n)
|
||||
case s.kind
|
||||
of skVar, skForVar, skTemp, skLet, skParam, skResult:
|
||||
genRdVar(c, n, dest, flags)
|
||||
|
|
@ -1525,7 +1544,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
|||
# procs easily:
|
||||
let body = s.getBody
|
||||
let procStart = c.xjmp(body, opcJmp, 0)
|
||||
var p = PProc(blocks: @[])
|
||||
var p = PProc(blocks: @[], sym: s)
|
||||
let oldPrc = c.prc
|
||||
c.prc = p
|
||||
# iterate over the parameters and allocate space for them:
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ type
|
|||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||
wAsmNoStackFrame,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked,
|
||||
|
||||
wAuto, wBool, wCatch, wChar, wClass,
|
||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||
|
|
@ -145,7 +145,7 @@ const
|
|||
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||
"computedgoto", "injectstmt",
|
||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||
"asmnostackframe", "implicitstatic", "global", "codegendecl",
|
||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||
|
||||
"auto", "bool", "catch", "char", "class",
|
||||
"const_cast", "default", "delete", "double",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue