mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 06:18:51 +00:00
first steps to implement object construction expressions
This commit is contained in:
@@ -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 []
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
6
todo.txt
6
todo.txt
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user