first steps to implement object construction expressions

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

View File

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

View File

@@ -142,10 +142,10 @@ proc getField(n: PNode; position: int): PSym =
else: nil
proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind == nkPar
InternalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets:
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]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym
@@ -257,11 +257,11 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
unpackObjectAdd(x, typ.n, result)
else:
result = n
if result.kind != nkPar:
if result.kind notin {nkObjConstr, nkPar}:
GlobalError(n.info, "cannot map value from FFI")
if typ.n.isNil:
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]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym

View File

@@ -273,9 +273,10 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info))
of tyTuple:
of tyTuple:
# XXX nkExprColonExpr is out of fashion ...
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 field = if t.n != nil: t.n.sons[i].sym else: newSym(
skField, getIdent(":tmp" & $i), t.owner, info)
@@ -999,10 +1000,10 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
case expandedSym.kind
of skTemplate:
let genSymOwner = if c.tos != nil and c.tos.prc != nil:
c.tos.prc
else:
c.module
let genSymOwner = if c.tos != nil and c.tos.prc != nil:
c.tos.prc
else:
c.module
result = evalTemplate(macroCall, expandedSym, genSymOwner)
of skMacro:
# At this point macroCall.sons[0] is nkSym node.
@@ -1342,7 +1343,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
cc = result
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
else: result = evalOp(m, n, a, b, cc)
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode
dec(gNestedEvals)
@@ -1385,6 +1386,23 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return
a.sons[i] = result
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 nkWhileStmt: result = evalWhile(c, n)
of nkCaseStmt: result = evalCase(c, n)

View File

@@ -758,7 +758,7 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
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])
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) =
var dest = skipTypes(n.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 nkBracket: genArrayConstr(p, n, r)
of nkPar: genTupleConstr(p, n, r)
of nkObjConstr: genObjConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr: genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)

View File

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

View File

@@ -367,7 +367,7 @@ proc lsub(n: PNode): int =
else: result = len(atom(n))
of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
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
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
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 nkCharLit: put(g, tkCharLit, atom(n))
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])
put(g, tkParLe, "(")
gcomma(g, n, 1)

View File

@@ -1551,6 +1551,36 @@ proc semTuplePositionsConstr(c: PContext, n: PNode): PNode =
addSonSkipIntLit(typ, n.sons[i].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 =
result = n
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 nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n)
of nkObjConstr: result = semObjConstr(c, n)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:

View File

@@ -516,13 +516,13 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
LocalError(n.info, errIndexOutOfBounds)
else: nil
proc foldFieldAccess(m: PSym, n: PNode): PNode =
proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed
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
for i in countup(0, sonsLen(x) - 1):
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
@@ -649,7 +649,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
if a == nil: return nil
result.sons[i] = a
incl(result.flags, nfAllConst)
of nkPar:
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:
# tuple constructor
result = copyTree(n)
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):

View File

@@ -311,6 +311,12 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
# container construction:
result = toNil # nothing until later
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:
var a = lvalueSym(n)
if a.kind == nkSym:

View File

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

View File

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

View File

@@ -8,7 +8,10 @@ version 0.9.2
* test libffi on windows
* test: times.format with the FFI
- 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
- fix:
- 'result' is not properly cleaned for NRVO
@@ -24,6 +27,7 @@ version 0.9.4
- provide tool/API to track leaks/object counts
- hybrid GC
- use big blocks in the allocator
- implement full 'not nil' checking
- make 'bind' default for templates and introduce 'mixin';
special rule for ``[]=``
- implicit deref for parameter matching; overloading based on 'var T'