first steps to implement object construction expressions

This commit is contained in:
Araq 2013-03-07 01:52:17 +01:00
commit 225d657019
12 changed files with 132 additions and 41 deletions

View file

@ -89,6 +89,7 @@ type
# formal parameters, var statements, etc. # formal parameters, var statements, etc.
nkVarTuple, # a ``var (a, b) = expr`` construct nkVarTuple, # a ``var (a, b) = expr`` construct
nkPar, # syntactic (); may be a tuple constructor nkPar, # syntactic (); may be a tuple constructor
nkObjConstr, # object constructor: T(a: 1, b: 2)
nkCurly, # syntactic {} nkCurly, # syntactic {}
nkCurlyExpr, # an expression like a{i} nkCurlyExpr, # an expression like a{i}
nkBracket, # syntactic [] nkBracket, # syntactic []

View file

@ -142,10 +142,10 @@ proc getField(n: PNode; position: int): PSym =
else: nil else: nil
proc packObject(x: PNode, typ: PType, res: pointer) = proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind == nkPar InternalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets: # compute the field's offsets:
discard typ.getSize discard typ.getSize
for i in countup(0, sonsLen(x) - 1): for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
var it = x.sons[i] var it = x.sons[i]
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym internalAssert it.sons[0].kind == nkSym
@ -257,11 +257,11 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
unpackObjectAdd(x, typ.n, result) unpackObjectAdd(x, typ.n, result)
else: else:
result = n result = n
if result.kind != nkPar: if result.kind notin {nkObjConstr, nkPar}:
GlobalError(n.info, "cannot map value from FFI") GlobalError(n.info, "cannot map value from FFI")
if typ.n.isNil: if typ.n.isNil:
GlobalError(n.info, "cannot unpack unnamed tuple") GlobalError(n.info, "cannot unpack unnamed tuple")
for i in countup(0, sonsLen(n) - 1): for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym internalAssert it.sons[0].kind == nkSym

View file

@ -274,6 +274,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
for i in countup(0, int(lengthOrd(t)) - 1): for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info)) addSon(result, getNullValue(elemType(t), info))
of tyTuple: of tyTuple:
# XXX nkExprColonExpr is out of fashion ...
result = newNodeIT(nkPar, info, t) result = newNodeIT(nkPar, info, t)
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
var p = newNodeIT(nkExprColonExpr, info, t.sons[i]) var p = newNodeIT(nkExprColonExpr, info, t.sons[i])
@ -1385,6 +1386,23 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return if isSpecial(result): return
a.sons[i] = result a.sons[i] = result
result = a result = a
of nkObjConstr:
let t = skipTypes(n.typ, abstractInst)
var a: PNode
if t.kind == tyRef:
result = newNodeIT(nkRefTy, n.info, t)
a = getNullValue(t.sons[0], n.info)
addSon(result, a)
else:
a = getNullValue(t, n.info)
result = a
for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i]
if it.kind == nkExprColonExpr:
let value = evalAux(c, it.sons[1], flags)
if isSpecial(value): return value
a.sons[it.sons[0].sym.position] = value
else: return raiseCannotEval(c, n.info)
of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n) of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
of nkWhileStmt: result = evalWhile(c, n) of nkWhileStmt: result = evalWhile(c, n)
of nkCaseStmt: result = evalCase(c, n) of nkCaseStmt: result = evalCase(c, n)

View file

@ -758,7 +758,7 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
const const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
nkCommand, nkHiddenCallConv, nkCallStrLit} nkCommand, nkHiddenCallConv, nkCallStrLit}
@ -1367,6 +1367,21 @@ proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) =
appf(r.res, "Field$1: $2", [i.toRope, a.res]) appf(r.res, "Field$1: $2", [i.toRope, a.res])
r.res.app("}") r.res.app("}")
proc genObjConstr(p: var TProc, n: PNode, r: var TCompRes) =
# XXX inheritance?
var a: TCompRes
r.res = toRope("{")
for i in countup(0, sonsLen(n) - 1):
if i > 0: app(r.res, ", ")
var it = n.sons[i]
InternalAssert it.kind == nkExprColonExpr
gen(p, it.sons[1], a)
r.com = mergeExpr(r.com, a.com)
var f = it.sons[0].sym
if f.loc.r == nil: f.loc.r = mangleName(f)
appf(r.res, "$1: $2", [f.loc.r, a.res])
r.res.app("}")
proc genConv(p: var TProc, n: PNode, r: var TCompRes) = proc genConv(p: var TProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange) var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].typ, abstractVarRange) var src = skipTypes(n.sons[1].typ, abstractVarRange)
@ -1566,6 +1581,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
of nkCurly: genSetConstr(p, n, r) of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r)
of nkPar: genTupleConstr(p, n, r) of nkPar: genTupleConstr(p, n, r)
of nkObjConstr: genObjConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr: genAddr(p, n, r) of nkAddr, nkHiddenAddr: genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)

View file

@ -254,10 +254,16 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
optPar(p) optPar(p)
eat(p, endToken) eat(p, endToken)
proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode = proc exprColonEqExpr(p: var TParser): PNode =
var a = parseExpr(p) var a = parseExpr(p)
if p.tok.tokType == tok: if p.tok.tokType == tkColon:
result = newNodeP(kind, p) result = newNodeP(nkExprColonExpr, p)
getTok(p)
#optInd(p, result)
addSon(result, a)
addSon(result, parseExpr(p))
elif p.tok.tokType == tkEquals:
result = newNodeP(nkExprEqExpr, p)
getTok(p) getTok(p)
#optInd(p, result) #optInd(p, result)
addSon(result, a) addSon(result, a)
@ -309,14 +315,13 @@ proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) =
optInd(p, a) optInd(p, a)
eat(p, endTok) eat(p, endTok)
proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind, proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
endTok, sepTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof) and
(p.tok.tokType != tkSad) and (p.tok.tokType != tkInd): (p.tok.tokType != tkSad) and (p.tok.tokType != tkInd):
var a = exprColonEqExpr(p, elemKind, sepTok) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -324,10 +329,10 @@ proc exprColonEqExprListAux(p: var TParser, elemKind: TNodeKind,
optPar(p) optPar(p)
eat(p, endTok) eat(p, endTok)
proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind, proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
endTok, sepTok: TTokType): PNode = endTok: TTokType): PNode =
result = newNodeP(kind, p) result = newNodeP(kind, p)
exprColonEqExprListAux(p, elemKind, endTok, sepTok, result) exprColonEqExprListAux(p, endTok, result)
proc setOrTableConstr(p: var TParser): PNode = proc setOrTableConstr(p: var TParser): PNode =
result = newNodeP(nkCurly, p) result = newNodeP(nkCurly, p)
@ -338,7 +343,7 @@ proc setOrTableConstr(p: var TParser): PNode =
result.kind = nkTableConstr result.kind = nkTableConstr
else: else:
while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}: while p.tok.tokType notin {tkCurlyRi, tkEof, tkSad, tkInd}:
var a = exprColonEqExpr(p, nkExprColonExpr, tkColon) var a = exprColonEqExpr(p)
if a.kind == nkExprColonExpr: result.kind = nkTableConstr if a.kind == nkExprColonExpr: result.kind = nkTableConstr
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -473,14 +478,13 @@ proc identOrLiteral(p: var TParser): PNode =
getTok(p) getTok(p)
of tkParLe: of tkParLe:
# () constructor # () constructor
result = exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon) result = exprColonEqExprList(p, nkPar, tkParRi)
of tkCurlyLe: of tkCurlyLe:
# {} constructor # {} constructor
result = setOrTableConstr(p) result = setOrTableConstr(p)
of tkBracketLe: of tkBracketLe:
# [] constructor # [] constructor
result = exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi, result = exprColonEqExprList(p, nkBracket, tkBracketRi)
tkColon)
of tkCast: of tkCast:
result = parseCast(p) result = parseCast(p)
else: else:
@ -496,7 +500,10 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
var a = result var a = result
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
addSon(result, a) addSon(result, a)
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) exprColonEqExprListAux(p, tkParRi, result)
if result.len > 1 and result.sons[0].kind == nkExprColonExpr:
result.kind = nkObjConstr
else:
parseDoBlocks(p, result) parseDoBlocks(p, result)
of tkDo: of tkDo:
var a = result var a = result
@ -564,7 +571,7 @@ proc parsePragma(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and
(p.tok.tokType != tkEof) and (p.tok.tokType != tkSad): (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad):
var a = exprColonEqExpr(p, nkExprColonExpr, tkColon) var a = exprColonEqExpr(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
getTok(p) getTok(p)

View file

@ -367,7 +367,7 @@ proc lsub(n: PNode): int =
else: result = len(atom(n)) else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n)) result = len(atom(n))
of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern: of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
result = lsub(n.sons[0]) + lcomma(n, 1) + 2 result = lsub(n.sons[0]) + lcomma(n, 1) + 2
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1]) of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()") of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
@ -779,7 +779,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkRStrLit: put(g, tkRStrLit, atom(n)) of nkRStrLit: put(g, tkRStrLit, atom(n))
of nkCharLit: put(g, tkCharLit, atom(n)) of nkCharLit: put(g, tkCharLit, atom(n))
of nkNilLit: put(g, tkNil, atom(n)) # complex expressions of nkNilLit: put(g, tkNil, atom(n)) # complex expressions
of nkCall, nkConv, nkDotCall, nkPattern: of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
if sonsLen(n) >= 1: gsub(g, n.sons[0]) if sonsLen(n) >= 1: gsub(g, n.sons[0])
put(g, tkParLe, "(") put(g, tkParLe, "(")
gcomma(g, n, 1) gcomma(g, n, 1)

View file

@ -1551,6 +1551,36 @@ proc semTuplePositionsConstr(c: PContext, n: PNode): PNode =
addSonSkipIntLit(typ, n.sons[i].typ) addSonSkipIntLit(typ, n.sons[i].typ)
result.typ = typ result.typ = typ
proc semObjConstr(c: PContext, n: PNode): PNode =
var t = semTypeNode(c, n.sons[0], nil)
result = n
result.typ = t
t = skipTypes(t, abstractInst)
if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
if t.kind != tyObject:
localError(n.info, errGenerated, "object constructor needs an object type")
return
var ids = initIntSet()
for i in 1.. <n.len:
let it = n.sons[i]
if it.kind != nkExprColonExpr or it.sons[0].kind notin {nkSym, nkIdent}:
localError(n.info, errNamedExprExpected)
break
var id: PIdent
if it.sons[0].kind == nkIdent: id = it.sons[0].ident
else: id = it.sons[0].sym.name
if ContainsOrIncl(ids, id.id):
localError(it.info, errFieldInitTwice, id.s)
var e = semExprWithType(c, it.sons[1])
let field = lookupInRecord(t.n, id)
if field.isNil:
localError(it.info, errUndeclaredFieldX, id.s)
else:
it.sons[0] = newSymNode(field)
e = fitNode(c, field.typ, e)
it.sons[1] = e
# XXX object field name check for 'case objects' if the kind is static?
proc semStmtListExpr(c: PContext, n: PNode): PNode = proc semStmtListExpr(c: PContext, n: PNode): PNode =
result = n result = n
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -1801,6 +1831,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of paSingle: result = semExpr(c, n.sons[0], flags) of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n) of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n) of nkBracket: result = semArrayConstr(c, n)
of nkObjConstr: result = semObjConstr(c, n)
of nkLambdaKinds: result = semLambda(c, n, flags) of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n) of nkDerefExpr: result = semDeref(c, n)
of nkAddr: of nkAddr:

View file

@ -519,10 +519,10 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
proc foldFieldAccess(m: PSym, n: PNode): PNode = proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed # a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0]) var x = getConstExpr(m, n.sons[0])
if x == nil or x.kind != nkPar: return if x == nil or x.kind notin {nkObjConstr, nkPar}: return
var field = n.sons[1].sym var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1): for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
var it = x.sons[i] var it = x.sons[i]
if it.kind != nkExprColonExpr: if it.kind != nkExprColonExpr:
# lookup per index: # lookup per index:
@ -649,6 +649,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
of nkObjConstr:
result = copyTree(n)
for i in countup(1, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i].sons[1])
if a == nil: return nil
result.sons[i].sons[1] = a
incl(result.flags, nfAllConst)
of nkPar: of nkPar:
# tuple constructor # tuple constructor
result = copyTree(n) result = copyTree(n)

View file

@ -311,6 +311,12 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
# container construction: # container construction:
result = toNil # nothing until later result = toNil # nothing until later
for i in 0..n.len-1: aggregateOwner(result, analyse(c, n[i])) for i in 0..n.len-1: aggregateOwner(result, analyse(c, n[i]))
of nkObjConstr:
if n.typ != nil and containsGarbageCollectedRef(n.typ):
result = toMine
else:
result = toNil # nothing until later
for i in 1..n.len-1: aggregateOwner(result, analyse(c, n[i]))
of nkAddr, nkHiddenAddr: of nkAddr, nkHiddenAddr:
var a = lvalueSym(n) var a = lvalueSym(n)
if a.kind == nkSym: if a.kind == nkSym:

View file

@ -115,7 +115,7 @@ proc isDeepConstExpr*(n: PNode): bool =
result = true result = true
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv: of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1]) result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar, nkClosure: of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len: for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false if not isDeepConstExpr(n.sons[i]): return false
result = true result = true

View file

@ -24,7 +24,8 @@ type
nnkCommand, nnkCall, nnkCallStrLit, nnkInfix, nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
nnkPrefix, nnkPostfix, nnkHiddenCallConv, nnkPrefix, nnkPostfix, nnkHiddenCallConv,
nnkExprEqExpr, nnkExprEqExpr,
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkPar, nnkCurly, nnkCurlyExpr, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,

View file

@ -8,7 +8,10 @@ version 0.9.2
* test libffi on windows * test libffi on windows
* test: times.format with the FFI * test: times.format with the FFI
- acyclic vs prunable; introduce GC hints - acyclic vs prunable; introduce GC hints
- implement constructors + full 'not nil' checking - implement constructors
- more checks
- C codegen for them
- document them
- CGEN: ``restrict`` pragma + backend support; computed goto support - CGEN: ``restrict`` pragma + backend support; computed goto support
- fix: - fix:
- 'result' is not properly cleaned for NRVO - 'result' is not properly cleaned for NRVO
@ -24,6 +27,7 @@ version 0.9.4
- provide tool/API to track leaks/object counts - provide tool/API to track leaks/object counts
- hybrid GC - hybrid GC
- use big blocks in the allocator - use big blocks in the allocator
- implement full 'not nil' checking
- make 'bind' default for templates and introduce 'mixin'; - make 'bind' default for templates and introduce 'mixin';
special rule for ``[]=`` special rule for ``[]=``
- implicit deref for parameter matching; overloading based on 'var T' - implicit deref for parameter matching; overloading based on 'var T'