first steps to allow easy functors via macros

This commit is contained in:
Andreas Rumpf 2017-06-04 11:17:41 +02:00
commit c59bc0cc18
5 changed files with 65 additions and 20 deletions

View file

@ -846,6 +846,7 @@ type
TDeclaredIdentFlag = enum TDeclaredIdentFlag = enum
withPragma, # identifier may have pragma withPragma, # identifier may have pragma
withBothOptional # both ':' and '=' parts are optional withBothOptional # both ':' and '=' parts are optional
withDot # allow 'var ident.ident = value'
TDeclaredIdentFlags = set[TDeclaredIdentFlag] TDeclaredIdentFlags = set[TDeclaredIdentFlag]
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
@ -859,7 +860,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
if withPragma in flags: a = identWithPragma(p) if withPragma in flags: a = identWithPragma(p, allowDot=withdot in flags)
else: a = parseSymbol(p) else: a = parseSymbol(p)
if a.kind == nkEmpty: return if a.kind == nkEmpty: return
else: break else: break
@ -1889,7 +1890,7 @@ proc parseVarTuple(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
# progress guaranteed # progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}: while p.tok.tokType in {tkSymbol, tkAccent}:
var a = identWithPragma(p) var a = identWithPragma(p, allowDot=true)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -1905,7 +1906,7 @@ proc parseVariable(p: var TParser): PNode =
#| colonBody = colcom stmt doBlocks? #| colonBody = colcom stmt doBlocks?
#| variable = (varTuple / identColonEquals) colonBody? indAndComment #| variable = (varTuple / identColonEquals) colonBody? indAndComment
if p.tok.tokType == tkParLe: result = parseVarTuple(p) if p.tok.tokType == tkParLe: result = parseVarTuple(p)
else: result = parseIdentColonEquals(p, {withPragma}) else: result = parseIdentColonEquals(p, {withPragma, withDot})
result{-1} = postExprBlocks(p, result{-1}) result{-1} = postExprBlocks(p, result{-1})
indAndComment(p, result) indAndComment(p, result)

View file

@ -880,20 +880,6 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
if r.sym.name.id == field.id: result = r.sym if r.sym.name.id == field.id: result = r.sym
else: illFormedAst(n) else: illFormedAst(n)
proc makeDeref(n: PNode): PNode =
var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
result = n
if t.kind == tyVar:
result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
addSon(result, n)
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
while t.kind in {tyPtr, tyRef}:
var a = result
let baseTyp = t.lastSon
result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
addSon(result, a)
t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
const const
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass} tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias} tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}

View file

@ -465,6 +465,38 @@ proc hasEmpty(typ: PType): bool =
for s in typ.sons: for s in typ.sons:
result = result or hasEmpty(s) result = result or hasEmpty(s)
proc makeDeref(n: PNode): PNode =
var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
result = n
if t.kind == tyVar:
result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
addSon(result, n)
t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
while t.kind in {tyPtr, tyRef}:
var a = result
let baseTyp = t.lastSon
result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
addSon(result, a)
t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
if n.len == 2:
let x = semExprWithType(c, n[0])
let y = considerQuotedIdent(n[1])
let obj = x.typ.skipTypes(abstractPtrs)
if obj.kind == tyObject and tfPartial in obj.flags:
let field = newSym(skField, getIdent(y.s & $obj.n.len), obj.sym, n[1].info)
field.typ = skipIntLit(typ)
field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field))
n.sons[0] = makeDeref x
n.sons[1] = newSymNode(field)
else:
localError(n.info, "implicit object field construction " &
"requires a .partial object, but got " & typeToString(obj))
else:
localError(n.info, "nkDotNode requires 2 children")
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode var b: PNode
result = copyNode(n) result = copyNode(n)
@ -529,6 +561,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
message(a.info, warnEachIdentIsTuple) message(a.info, warnEachIdentIsTuple)
for j in countup(0, length-3): for j in countup(0, length-3):
if a[j].kind == nkDotExpr:
fillPartialObject(c, a[j],
if a.kind != nkVarTuple: typ else: tup.sons[j])
addToVarSection(c, result, n, a)
continue
var v = semIdentDef(c, a.sons[j], symkind) var v = semIdentDef(c, a.sons[j], symkind)
if sfGenSym notin v.flags and not isDiscardUnderscore(v): if sfGenSym notin v.flags and not isDiscardUnderscore(v):
addInterfaceDecl(c, v) addInterfaceDecl(c, v)

View file

@ -152,6 +152,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
message n[i].info, errGenerated, "region needs to be an object type" message n[i].info, errGenerated, "region needs to be an object type"
addSonSkipIntLit(result, region) addSonSkipIntLit(result, region)
addSonSkipIntLit(result, t) addSonSkipIntLit(result, t)
if tfPartial in result.flags:
if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial)
#if not isNilable: result.flags.incl tfNotNil #if not isNilable: result.flags.incl tfNotNil
proc semVarType(c: PContext, n: PNode, prev: PType): PType = proc semVarType(c: PContext, n: PNode, prev: PType): PType =

View file

@ -0,0 +1,19 @@
discard """
out: '''(foo0: 38, other1: string here)
43'''
"""
type
Base = ref object of RootObj
Foo {.partial.} = ref object of Base
proc my(f: Foo) =
#var f.next = f
let f.foo = 38
let f.other = "string here"
echo f[]
echo f.foo0 + 5
var g: Foo
new(g)
my(g)