first steps to allow easy functors via macros

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

View File

@@ -846,6 +846,7 @@ type
TDeclaredIdentFlag = enum
withPragma, # identifier may have pragma
withBothOptional # both ':' and '=' parts are optional
withDot # allow 'var ident.ident = value'
TDeclaredIdentFlags = set[TDeclaredIdentFlag]
proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
@@ -859,7 +860,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
while true:
case p.tok.tokType
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)
if a.kind == nkEmpty: return
else: break
@@ -1889,7 +1890,7 @@ proc parseVarTuple(p: var TParser): PNode =
optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = identWithPragma(p)
var a = identWithPragma(p, allowDot=true)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
@@ -1905,7 +1906,7 @@ proc parseVariable(p: var TParser): PNode =
#| colonBody = colcom stmt doBlocks?
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
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})
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
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
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
@@ -920,7 +906,7 @@ proc readTypeParameter(c: PContext, typ: PType,
else:
discard
if typ.kind != tyUserTypeClass:
let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
else: typ.skipGenericAlias
@@ -2285,14 +2271,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
pragma = n[1]
pragmaName = considerQuotedIdent(pragma[0])
flags = flags
case whichKeyword(pragmaName)
of wExplain:
flags.incl efExplain
else:
# what other pragmas are allowed for expressions? `likely`, `unlikely`
invalidPragma(n)
result = semExpr(c, n[0], flags)
of nkPar:
case checkPar(n)

View File

@@ -465,6 +465,38 @@ proc hasEmpty(typ: PType): bool =
for s in typ.sons:
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 =
var b: PNode
result = copyNode(n)
@@ -529,6 +561,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
message(a.info, warnEachIdentIsTuple)
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)
if sfGenSym notin v.flags and not isDiscardUnderscore(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"
addSonSkipIntLit(result, region)
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
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)