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.
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