improvements for 'bind', fixes #166

This commit is contained in:
Araq 2012-07-18 17:21:10 +02:00
commit e68830a952
6 changed files with 61 additions and 32 deletions

View file

@ -1412,9 +1412,8 @@ proc parseBind(p: var TParser): PNode =
result = newNodeP(nkBindStmt, p) result = newNodeP(nkBindStmt, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while p.tok.tokType == tkSymbol: while true:
var a = newIdentNodeP(p.tok.ident, p) var a = qualifiedIdent(p)
getTok(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)

View file

@ -13,12 +13,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
var var
a: PSym a: PSym
o: TOverloadIter o: TOverloadIter
i: int var i = 0
i = 0
a = initOverloadIter(o, c, n) a = initOverloadIter(o, c, n)
while a != nil: while a != nil:
a = nextOverloadIter(o, c, n) a = nextOverloadIter(o, c, n)
inc(i) inc(i)
if i > 1: break
if i <= 1: if i <= 1:
result = newSymNode(s) result = newSymNode(s)
result.info = n.info result.info = n.info
@ -36,41 +36,45 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
for i in 0 .. < n.len: for i in 0 .. < n.len:
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkIdent: # If 'a' is an overloaded symbol, we use the first symbol as a 'witness'
var s = SymtabGet(c.Tab, a.ident) # and use the fact that subsequent lookups will yield the same symbol!
if s != nil: # This is currently the case due to the hash table's implementation...
toBind.incl(s.name.id) let s = QualifiedLookUp(c, a)
else: if s != nil:
localError(a.info, errUndeclaredIdentifier, a.ident.s) toBind.incl(s.id)
else: else:
illFormedAst(a) illFormedAst(a)
result = newNodeI(nkEmpty, n.info) result = newNodeI(nkEmpty, n.info)
proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool, proc resolveTemplateParams(c: PContext, n: PNode, owner: PSym,
toBind: var TIntSet): PNode = toBind: var TIntSet): PNode =
var s: PSym var s: PSym
case n.kind case n.kind
of nkIdent: of nkIdent, nkAccQuoted:
if not withinBind and not Contains(toBind, n.ident.id): result = n
s = SymTabLocalGet(c.Tab, n.ident) let s = QualifiedLookUp(c, n, {})
if s != nil: if s != nil:
if s.owner == owner and s.kind == skParam:
result = newSymNode(s) result = newSymNode(s)
result.info = n.info result.info = n.info
else: elif Contains(toBind, s.id):
result = n result = symChoice(c, n, s)
else:
Incl(toBind, n.ident.id)
result = symChoice(c, n, lookup(c, n))
of nkEmpty, nkSym..nkNilLit: # atom of nkEmpty, nkSym..nkNilLit: # atom
result = n result = n
of nkBind: of nkBind:
result = resolveTemplateParams(c, n.sons[0], true, toBind) result = resolveTemplateParams(c, n.sons[0], owner, toBind)
of nkBindStmt: of nkBindStmt:
result = semBindStmt(c, n, toBind) result = semBindStmt(c, n, toBind)
else: else:
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
# so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr:
let s = QualifiedLookUp(c, n, {})
if s != nil and Contains(toBind, s.id):
return symChoice(c, n, s)
result = n result = n
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result.sons[i] = resolveTemplateParams(c, n.sons[i], withinBind, toBind) result.sons[i] = resolveTemplateParams(c, n.sons[i], owner, toBind)
proc transformToExpr(n: PNode): PNode = proc transformToExpr(n: PNode): PNode =
var realStmt: int var realStmt: int
@ -122,7 +126,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s.typ.sons[0] = newTypeS(tyStmt, c) s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0]) s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
var toBind = initIntSet() var toBind = initIntSet()
n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], false, toBind) n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], s, toBind)
if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}: if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) n.sons[bodyPos] = transformToExpr(n.sons[bodyPos])
# only parameters are resolved, no type checking is performed # only parameters are resolved, no type checking is performed

View file

@ -137,7 +137,7 @@ staticStmt ::= 'static' ':' stmt
filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
importStmt ::= 'import' filename (comma filename)* importStmt ::= 'import' filename (comma filename)*
includeStmt ::= 'include' filename (comma filename)* includeStmt ::= 'include' filename (comma filename)*
bindStmt ::= 'bind' IDENT (comma IDENT)* bindStmt ::= 'bind' qualifiedIdent (comma qualifiedIdent)*
fromStmt ::= 'from' filename 'import' symbol (comma symbol)* fromStmt ::= 'from' filename 'import' symbol (comma symbol)*
pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}') pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}')

24
tests/run/tstempl.nim Normal file
View file

@ -0,0 +1,24 @@
discard """
output: '''global = levB, arg = levA, test = false
levB'''
"""
# tstempl.nim
import strutils
type
TLev = enum
levA,
levB
var abclev = levB
template tstLev(abclev: TLev) =
bind tstempl.abclev, `%`
writeln(stdout, "global = $1, arg = $2, test = $3" % [
$tstempl.abclev, $abclev, $(tstempl.abclev == abclev)])
# evaluates to true, but must be false
tstLev(levA)
writeln(stdout, $abclev)

View file

@ -2,7 +2,6 @@ version 0.9.0
============= =============
- fix DLLs - fix DLLs
- fix 'bind' for templates
- implicit deref for parameter matching - implicit deref for parameter matching
- deprecate ``var x, y = 0`` as it's confusing for tuple consistency - deprecate ``var x, y = 0`` as it's confusing for tuple consistency
@ -35,7 +34,7 @@ Bugs
but this can lead to compilation errors but this can lead to compilation errors
- bug: the parser is not strict enough with newlines: 'echo "a" echo "b"' - bug: the parser is not strict enough with newlines: 'echo "a" echo "b"'
compiles compiles
- bug: blocks can "export" an identifier but the CCG generates {} for them ...
version 0.9.XX version 0.9.XX
============== ==============

View file

@ -95,6 +95,8 @@ Changes affecting backwards compatibility
conversions from ``int`` to ``int32`` are now forbidden. conversions from ``int`` to ``int32`` are now forbidden.
- ``system.byte`` is now an alias for ``uint8``; it used to be an alias - ``system.byte`` is now an alias for ``uint8``; it used to be an alias
to ``int8``. to ``int8``.
- ``bind`` expressions in templates are not properly supported anymore. Use
the declarative ``bind`` statement instead.
Compiler Additions Compiler Additions
@ -136,6 +138,7 @@ Language Additions
readability: ``proc divmod(a, b: int; resA, resB: var int)``. readability: ``proc divmod(a, b: int; resA, resB: var int)``.
- A semicolon can now be used to have multiple simple statements on a single - A semicolon can now be used to have multiple simple statements on a single
line: ``inc i; inc j``. line: ``inc i; inc j``.
- ``bind`` supports overloaded symbols and operators.
2012-02-09 Version 0.8.14 released 2012-02-09 Version 0.8.14 released