term rewriting macros fully implemented; still buggy

This commit is contained in:
Araq 2012-09-03 00:55:44 +02:00
commit af7c92c003
22 changed files with 676 additions and 138 deletions

View file

@ -89,7 +89,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
for x in items(sc): toBind.incl(x.sym.id)
else:
illFormedAst(a)
result = newNodeI(nkEmpty, n.info)
result = newNodeI(nkNilLit, n.info)
proc replaceIdentBySym(n: var PNode, s: PNode) =
case n.kind
@ -98,16 +98,10 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
of nkIdent, nkAccQuoted, nkSym: n = s
else: illFormedAst(n)
# This code here is the first pass over a template's body. The same code also
# implements the first pass over a pattern's body:
type
TBodyKind = enum
bkTemplate, bkPattern
TemplCtx {.pure, final.} = object
c: PContext
toBind: TIntSet
bodyKind: TBodyKind
owner: PSym
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
@ -188,8 +182,6 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
elif c.bodyKind == bkPattern:
result = symChoice(c.c, n, s, scOpen)
elif s.owner == c.owner and sfGenSym in s.flags:
# template tmp[T](x: var seq[T]) =
# var yz: T
@ -305,8 +297,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
if s != nil and Contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
if s != nil:
if Contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semTemplBody(c, n.sons[i])
@ -405,7 +398,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
ctx.toBind = initIntSet()
ctx.c = c
ctx.owner = s
ctx.bodyKind = bkTemplate
if sfDirty in s.flags:
n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
else:
@ -426,17 +418,109 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else:
SymTabReplace(c.tab.stack[curScope], proto, s)
proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
template templToExpand(s: expr): expr =
s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags)
proc handleSym(c: var TemplCtx, n: PNode, s: PSym): PNode =
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
elif templToExpand(s):
result = semPatternBody(c, semTemplateExpr(c.c, n, s, false))
else:
result = symChoice(c.c, n, s, scOpen)
else:
result = n
proc expectParam(c: var TemplCtx, n: PNode): PNode =
let s = QualifiedLookUp(c.c, n, {})
if s != nil and s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
else:
localError(n.info, errInvalidExpression)
result = n
result = n
case n.kind
of nkIdent:
let s = QualifiedLookUp(c.c, n, {})
result = handleSym(c, n, s)
of nkBindStmt:
result = semBindStmt(c.c, n, c.toBind)
of nkEmpty, nkSym..nkNilLit: nil
of nkCurlyExpr:
# we support '(pattern){x}' to bind a subpattern to a parameter 'x':
if n.len != 2 or n.sons[1].kind != nkIdent:
localError(n.info, errInvalidExpression)
else:
n.sons[0] = semPatternBody(c, n.sons[0])
n.sons[1] = expectParam(c, n.sons[1])
of nkCallKinds:
let s = QualifiedLookUp(c.c, n.sons[0], {})
if s != nil:
if s.owner == c.owner and s.kind == skParam: nil
elif Contains(c.toBind, s.id): nil
elif templToExpand(s):
return semPatternBody(c, semTemplateExpr(c.c, n, s, false))
if n.kind == nkInfix and n.sons[0].kind == nkIdent:
# we interpret `*` and `|` only as pattern operators if they occur in
# infix notation, so that '`*`(a, b)' can be used for verbatim matching:
let opr = n.sons[0]
if opr.ident.s == "*":
result = newNodeI(nkPattern, n.info, n.len)
result.sons[0] = opr
result.sons[1] = semPatternBody(c, n.sons[1])
result.sons[2] = expectParam(c, n.sons[2])
return
elif opr.ident.s == "|":
result = newNodeI(nkPattern, n.info, n.len)
result.sons[0] = opr
result.sons[1] = semPatternBody(c, n.sons[1])
result.sons[2] = semPatternBody(c, n.sons[2])
return
if n.kind == nkPrefix and n.sons[0].kind == nkIdent:
let opr = n.sons[0]
if opr.ident.s == "~":
result = newNodeI(nkPattern, n.info, n.len)
result.sons[0] = opr
result.sons[1] = semPatternBody(c, n.sons[1])
return
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semPatternBody(c, n.sons[i])
else:
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
# so we use the generic code for nkDotExpr too
case n.kind
of nkDotExpr, nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
if s != nil:
if Contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
return symChoice(c.c, n, s, scOpen)
of nkPar:
if n.len == 1: return semPatternBody(c, n.sons[0])
else: nil
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semPatternBody(c, n.sons[i])
proc semPattern(c: PContext, n: PNode): PNode =
# not much to do here: We don't replace operators ``$``, ``*``, ``+``,
# ``|``, ``~`` as meta operators and strip the leading ``\`` of all
# operators.
openScope(c.tab)
var ctx: TemplCtx
ctx.toBind = initIntSet()
ctx.c = c
ctx.owner = getCurrOwner()
ctx.bodyKind = bkPattern
result = semTemplBody(ctx, n)
if result.kind in {nkStmtList, nkStmtListExpr} and result.len == 1:
result = result.sons[0]
result = flattenStmts(semPatternBody(ctx, n))
if result.kind in {nkStmtList, nkStmtListExpr}:
if result.len == 1:
result = result.sons[0]
elif result.len == 0:
LocalError(n.info, errInvalidExpression)
closeScope(c.tab)