object constructors work now
This commit is contained in:
parent
296e7c9f40
commit
2b4922aea0
5 changed files with 160 additions and 84 deletions
|
|
@ -680,14 +680,40 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
putIntoDest(p, d, field.typ, r)
|
putIntoDest(p, d, field.typ, r)
|
||||||
|
|
||||||
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
|
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
|
||||||
|
|
||||||
|
proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
|
||||||
|
var test, u, v: TLoc
|
||||||
|
for i in countup(1, sonsLen(e) - 1):
|
||||||
|
var it = e.sons[i]
|
||||||
|
assert(it.kind in nkCallKinds)
|
||||||
|
assert(it.sons[0].kind == nkSym)
|
||||||
|
let op = it.sons[0].sym
|
||||||
|
if op.magic == mNot: it = it.sons[1]
|
||||||
|
assert(it.sons[2].kind == nkSym)
|
||||||
|
initLoc(test, locNone, it.typ, OnStack)
|
||||||
|
InitLocExpr(p, it.sons[1], u)
|
||||||
|
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
|
||||||
|
v.r = ropef("$1.$2", [obj, it.sons[2].sym.loc.r])
|
||||||
|
genInExprAux(p, it, u, v, test)
|
||||||
|
let id = NodeTableTestOrSet(p.module.dataCache,
|
||||||
|
newStrNode(nkStrLit, field.name.s), gBackendId)
|
||||||
|
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
|
||||||
|
else: con("TMP", toRope(id))
|
||||||
|
if op.magic == mNot:
|
||||||
|
linefmt(p, cpsStmts,
|
||||||
|
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
||||||
|
rdLoc(test), strLit)
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts,
|
||||||
|
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
||||||
|
rdLoc(test), strLit)
|
||||||
|
|
||||||
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var
|
var
|
||||||
a, u, v, test: TLoc
|
a: TLoc
|
||||||
f, field, op: PSym
|
f, field: PSym
|
||||||
ty: PType
|
ty: PType
|
||||||
r, strLit: PRope
|
r: PRope
|
||||||
id: int
|
|
||||||
it: PNode
|
|
||||||
if optFieldCheck in p.options:
|
if optFieldCheck in p.options:
|
||||||
ty = genRecordFieldAux(p, e.sons[0], d, a)
|
ty = genRecordFieldAux(p, e.sons[0], d, a)
|
||||||
r = rdLoc(a)
|
r = rdLoc(a)
|
||||||
|
|
@ -702,69 +728,37 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if field == nil: InternalError(e.info, "genCheckedRecordField")
|
if field == nil: InternalError(e.info, "genCheckedRecordField")
|
||||||
if field.loc.r == nil:
|
if field.loc.r == nil:
|
||||||
InternalError(e.info, "genCheckedRecordField") # generate the checks:
|
InternalError(e.info, "genCheckedRecordField") # generate the checks:
|
||||||
for i in countup(1, sonsLen(e) - 1):
|
genFieldCheck(p, e, r, field)
|
||||||
it = e.sons[i]
|
when false:
|
||||||
assert(it.kind in nkCallKinds)
|
for i in countup(1, sonsLen(e) - 1):
|
||||||
assert(it.sons[0].kind == nkSym)
|
it = e.sons[i]
|
||||||
op = it.sons[0].sym
|
assert(it.kind in nkCallKinds)
|
||||||
if op.magic == mNot: it = it.sons[1]
|
assert(it.sons[0].kind == nkSym)
|
||||||
assert(it.sons[2].kind == nkSym)
|
op = it.sons[0].sym
|
||||||
initLoc(test, locNone, it.typ, OnStack)
|
if op.magic == mNot: it = it.sons[1]
|
||||||
InitLocExpr(p, it.sons[1], u)
|
assert(it.sons[2].kind == nkSym)
|
||||||
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
|
initLoc(test, locNone, it.typ, OnStack)
|
||||||
v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
|
InitLocExpr(p, it.sons[1], u)
|
||||||
genInExprAux(p, it, u, v, test)
|
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
|
||||||
id = NodeTableTestOrSet(p.module.dataCache,
|
v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
|
||||||
newStrNode(nkStrLit, field.name.s), gBackendId)
|
genInExprAux(p, it, u, v, test)
|
||||||
if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
|
id = NodeTableTestOrSet(p.module.dataCache,
|
||||||
else: strLit = con("TMP", toRope(id))
|
newStrNode(nkStrLit, field.name.s), gBackendId)
|
||||||
if op.magic == mNot:
|
if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
|
||||||
linefmt(p, cpsStmts,
|
else: strLit = con("TMP", toRope(id))
|
||||||
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
if op.magic == mNot:
|
||||||
rdLoc(test), strLit)
|
linefmt(p, cpsStmts,
|
||||||
else:
|
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
||||||
linefmt(p, cpsStmts,
|
rdLoc(test), strLit)
|
||||||
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
else:
|
||||||
rdLoc(test), strLit)
|
linefmt(p, cpsStmts,
|
||||||
|
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
||||||
|
rdLoc(test), strLit)
|
||||||
app(r, rfmt(nil, ".$1", field.loc.r))
|
app(r, rfmt(nil, ".$1", field.loc.r))
|
||||||
putIntoDest(p, d, field.typ, r)
|
putIntoDest(p, d, field.typ, r)
|
||||||
else:
|
else:
|
||||||
genRecordField(p, e.sons[0], d)
|
genRecordField(p, e.sons[0], d)
|
||||||
|
|
||||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
|
||||||
var tmp: TLoc
|
|
||||||
var t = e.typ.skipTypes(abstractInst)
|
|
||||||
getTemp(p, t, tmp)
|
|
||||||
let isRef = t.kind == tyRef
|
|
||||||
var r = rdLoc(tmp)
|
|
||||||
if isRef:
|
|
||||||
t = t.sons[0].skipTypes(abstractInst)
|
|
||||||
r = ropef("(*$1)", r)
|
|
||||||
# XXX generate 'new' call here
|
|
||||||
|
|
||||||
discard getTypeDesc(p.module, t)
|
|
||||||
for i in 1 .. <e.len:
|
|
||||||
let it = e.sons[i]
|
|
||||||
# XXX field check here
|
|
||||||
var field: PSym = nil
|
|
||||||
var ty = t
|
|
||||||
while ty != nil:
|
|
||||||
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
|
||||||
if field != nil: break
|
|
||||||
if gCmd != cmdCompileToCpp: app(r, ".Sup")
|
|
||||||
ty = GetUniqueType(ty.sons[0])
|
|
||||||
if field == nil or field.loc.r == nil: InternalError(e.info, "genObjConstr")
|
|
||||||
app(r, ".")
|
|
||||||
app(r, field.loc.r)
|
|
||||||
var tmp2: TLoc
|
|
||||||
tmp2.r = r
|
|
||||||
tmp2.k = locTemp
|
|
||||||
tmp2.t = field.loc.t
|
|
||||||
tmp2.s = onHeap
|
|
||||||
tmp2.heapRoot = tmp.r
|
|
||||||
expr(p, it.sons[1], tmp2)
|
|
||||||
genAssignment(p, d, tmp, {})
|
|
||||||
|
|
||||||
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
|
|
@ -1006,10 +1000,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
||||||
# seq->data[seq->len-1] = x;
|
# seq->data[seq->len-1] = x;
|
||||||
let seqAppendPattern = if gCmd != cmdCompileToCpp:
|
let seqAppendPattern = if gCmd != cmdCompileToCpp:
|
||||||
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
||||||
else:
|
else:
|
||||||
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
||||||
|
|
||||||
var a, b, dest: TLoc
|
var a, b, dest: TLoc
|
||||||
InitLocExpr(p, e.sons[1], a)
|
InitLocExpr(p, e.sons[1], a)
|
||||||
InitLocExpr(p, e.sons[2], b)
|
InitLocExpr(p, e.sons[2], b)
|
||||||
|
|
@ -1028,20 +1021,12 @@ proc genReset(p: BProc, n: PNode) =
|
||||||
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||||
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
|
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
|
||||||
|
|
||||||
proc genNew(p: BProc, e: PNode) =
|
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
|
||||||
var
|
var sizeExpr = sizeExpr
|
||||||
a, b: TLoc
|
let refType = skipTypes(a.t, abstractVarRange)
|
||||||
reftype, bt: PType
|
var b: TLoc
|
||||||
sizeExpr: PRope
|
|
||||||
refType = skipTypes(e.sons[1].typ, abstractVarRange)
|
|
||||||
InitLocExpr(p, e.sons[1], a)
|
|
||||||
initLoc(b, locExpr, a.t, OnHeap)
|
initLoc(b, locExpr, a.t, OnHeap)
|
||||||
# 'genNew' also handles 'unsafeNew':
|
if sizeExpr.isNil:
|
||||||
if e.len == 3:
|
|
||||||
var se: TLoc
|
|
||||||
InitLocExpr(p, e.sons[2], se)
|
|
||||||
sizeExpr = se.rdLoc
|
|
||||||
else:
|
|
||||||
sizeExpr = ropef("sizeof($1)",
|
sizeExpr = ropef("sizeof($1)",
|
||||||
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
|
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
|
||||||
let args = [getTypeDesc(p.module, reftype),
|
let args = [getTypeDesc(p.module, reftype),
|
||||||
|
|
@ -1058,9 +1043,20 @@ proc genNew(p: BProc, e: PNode) =
|
||||||
else:
|
else:
|
||||||
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
||||||
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
|
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
|
||||||
bt = skipTypes(refType.sons[0], abstractRange)
|
let bt = skipTypes(refType.sons[0], abstractRange)
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, false)
|
||||||
|
|
||||||
|
proc genNew(p: BProc, e: PNode) =
|
||||||
|
var a: TLoc
|
||||||
|
InitLocExpr(p, e.sons[1], a)
|
||||||
|
# 'genNew' also handles 'unsafeNew':
|
||||||
|
if e.len == 3:
|
||||||
|
var se: TLoc
|
||||||
|
InitLocExpr(p, e.sons[2], se)
|
||||||
|
rawGenNew(p, a, se.rdLoc)
|
||||||
|
else:
|
||||||
|
rawGenNew(p, a, nil)
|
||||||
|
|
||||||
proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
||||||
let seqtype = skipTypes(dest.t, abstractVarRange)
|
let seqtype = skipTypes(dest.t, abstractVarRange)
|
||||||
let args = [getTypeDesc(p.module, seqtype),
|
let args = [getTypeDesc(p.module, seqtype),
|
||||||
|
|
@ -1068,7 +1064,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
||||||
var call: TLoc
|
var call: TLoc
|
||||||
initLoc(call, locExpr, dest.t, OnHeap)
|
initLoc(call, locExpr, dest.t, OnHeap)
|
||||||
if dest.s == OnHeap and usesNativeGC():
|
if dest.s == OnHeap and usesNativeGC():
|
||||||
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
|
if canFormAcycle(dest.t):
|
||||||
|
linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc)
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
|
||||||
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
|
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1081,6 +1080,41 @@ proc genNewSeq(p: BProc, e: PNode) =
|
||||||
InitLocExpr(p, e.sons[2], b)
|
InitLocExpr(p, e.sons[2], b)
|
||||||
genNewSeqAux(p, a, b.rdLoc)
|
genNewSeqAux(p, a, b.rdLoc)
|
||||||
|
|
||||||
|
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
var tmp: TLoc
|
||||||
|
var t = e.typ.skipTypes(abstractInst)
|
||||||
|
getTemp(p, t, tmp)
|
||||||
|
let isRef = t.kind == tyRef
|
||||||
|
var r = rdLoc(tmp)
|
||||||
|
if isRef:
|
||||||
|
rawGenNew(p, tmp, nil)
|
||||||
|
t = t.sons[0].skipTypes(abstractInst)
|
||||||
|
r = ropef("(*$1)", r)
|
||||||
|
# XXX object initialization? but not necessary for temps, is it?
|
||||||
|
discard getTypeDesc(p.module, t)
|
||||||
|
for i in 1 .. <e.len:
|
||||||
|
let it = e.sons[i]
|
||||||
|
var tmp2: TLoc
|
||||||
|
tmp2.r = r
|
||||||
|
var field: PSym = nil
|
||||||
|
var ty = t
|
||||||
|
while ty != nil:
|
||||||
|
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
||||||
|
if field != nil: break
|
||||||
|
if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
|
||||||
|
ty = GetUniqueType(ty.sons[0])
|
||||||
|
if field == nil or field.loc.r == nil: InternalError(e.info, "genObjConstr")
|
||||||
|
if it.len == 3 and optFieldCheck in p.options:
|
||||||
|
genFieldCheck(p, it.sons[2], r, field)
|
||||||
|
app(tmp2.r, ".")
|
||||||
|
app(tmp2.r, field.loc.r)
|
||||||
|
tmp2.k = locTemp
|
||||||
|
tmp2.t = field.loc.t
|
||||||
|
tmp2.s = onHeap
|
||||||
|
tmp2.heapRoot = tmp.r
|
||||||
|
expr(p, it.sons[1], tmp2)
|
||||||
|
genAssignment(p, d, tmp, {})
|
||||||
|
|
||||||
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
||||||
var arr: TLoc
|
var arr: TLoc
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
|
|
|
||||||
|
|
@ -744,7 +744,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||||
if objType.sym == nil:
|
if objType.sym == nil:
|
||||||
InternalError(d.info, "anonymous obj with discriminator")
|
InternalError(d.info, "anonymous obj with discriminator")
|
||||||
result = ropef("NimDT_$1_$2", [
|
result = ropef("NimDT_$1_$2", [
|
||||||
toRope(objType.sym.name.s), toRope(d.name.s)])
|
toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
|
||||||
|
|
||||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
||||||
discard cgsym(m, "TNimNode")
|
discard cgsym(m, "TNimNode")
|
||||||
|
|
|
||||||
|
|
@ -1557,6 +1557,7 @@ proc semObjConstr(c: PContext, n: PNode): PNode =
|
||||||
var t = semTypeNode(c, n.sons[0], nil)
|
var t = semTypeNode(c, n.sons[0], nil)
|
||||||
result = n
|
result = n
|
||||||
result.typ = t
|
result.typ = t
|
||||||
|
result.kind = nkObjConstr
|
||||||
t = skipTypes(t, abstractInst)
|
t = skipTypes(t, abstractInst)
|
||||||
if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
|
if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
|
||||||
if t.kind != tyObject:
|
if t.kind != tyObject:
|
||||||
|
|
|
||||||
41
tests/run/tobjconstr.nim
Normal file
41
tests/run/tobjconstr.nim
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
discard """
|
||||||
|
output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 2, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 3, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 4, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 5, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 6, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 7, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 8, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 9, 3]), empty: ())
|
||||||
|
(k: kindA, a: (x: abc, z: [1, 10, 3]), empty: ())'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TArg = object
|
||||||
|
x: string
|
||||||
|
z: seq[int]
|
||||||
|
TKind = enum kindXY, kindA
|
||||||
|
TEmpty = object
|
||||||
|
TDummy = ref object
|
||||||
|
case k: TKind
|
||||||
|
of kindXY: x, y: int
|
||||||
|
of kindA:
|
||||||
|
a: TArg
|
||||||
|
empty: TEmpty
|
||||||
|
|
||||||
|
proc `$`[T](s: seq[T]): string =
|
||||||
|
# XXX why is that not in the stdlib?
|
||||||
|
result = "["
|
||||||
|
for i, x in s:
|
||||||
|
if i > 0: result.add(", ")
|
||||||
|
result.add($x)
|
||||||
|
result.add("]")
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
for i in 1..10:
|
||||||
|
let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), empty: TEmpty())
|
||||||
|
echo d[]
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -10,7 +10,6 @@ version 0.9.2
|
||||||
- acyclic vs prunable; introduce GC hints
|
- acyclic vs prunable; introduce GC hints
|
||||||
- implement constructors
|
- implement constructors
|
||||||
- more checks
|
- more checks
|
||||||
- C codegen for them
|
|
||||||
- document them
|
- document them
|
||||||
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
||||||
- fix:
|
- fix:
|
||||||
|
|
@ -128,6 +127,7 @@ Optimizations
|
||||||
Bugs
|
Bugs
|
||||||
====
|
====
|
||||||
|
|
||||||
|
- instantiated generics are listed in error messages
|
||||||
- sneaking with qualifiedLookup() is really broken!
|
- sneaking with qualifiedLookup() is really broken!
|
||||||
- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' --
|
- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' --
|
||||||
use a qualifier
|
use a qualifier
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue