first steps towards term rewriting macros

This commit is contained in:
Araq
2012-08-30 10:55:40 +02:00
parent b4844a189d
commit 1786e30991
17 changed files with 264 additions and 58 deletions

View File

@@ -176,6 +176,7 @@ type
nkFromStmt, # a from * import statement
nkIncludeStmt, # an include statement
nkBindStmt, # a bind statement
nkPatternStmt, # a pattern statement ('as' statement)
nkCommentStmt, # a comment statement
nkStmtListExpr, # a statement list followed by an expr; this is used
# to allow powerful multi-line templates
@@ -246,8 +247,8 @@ type
# for interfacing with C++, JS
sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C
sfDiscardable # returned value may be discarded implicitely
sfDestructor # proc is destructor
sfDiscardable, # returned value may be discarded implicitely
sfDestructor, # proc is destructor
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
TSymFlags* = set[TSymFlag]
@@ -689,9 +690,10 @@ const
genericParamsPos* = 1
paramsPos* = 2
pragmasPos* = 3
bodyPos* = 4 # position of body; use rodread.getBody() instead!
resultPos* = 5
dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5!
patternPos* = 4 # empty except for term rewriting macros
bodyPos* = 5 # position of body; use rodread.getBody() instead!
resultPos* = 6
dispatcherPos* = 7 # caution: if method has no 'result' it can be position 5!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit}
@@ -1175,6 +1177,9 @@ proc isRoutine*(s: PSym): bool {.inline.} =
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
skConverter}
proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
iterator items*(n: PNode): PNode =
for i in 0.. <n.len: yield n.sons[i]

View File

@@ -834,8 +834,8 @@ proc writeIdNodeTable(t: TIdNodeTable) =
proc IdNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
if (t.data[h].key.id == key.id):
while t.data[h].key != nil:
if t.data[h].key.id == key.id:
return h
h = nextTry(h, high(t.data))
result = - 1
@@ -845,6 +845,10 @@ proc IdNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
index = IdNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc IdNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
if not isNil(t.data):
result = IdNodeTableGet(t, key)
proc IdNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash
@@ -872,6 +876,10 @@ proc IdNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
IdNodeTableRawInsert(t.data, key, val)
inc(t.counter)
proc IdNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
if isNil(t.data): initIdNodeTable(t)
IdNodeTablePut(t, key, val)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)

View File

@@ -45,8 +45,8 @@ proc rawImportSymbol(c: PContext, s: PSym) =
var copy = s # do not copy symbols when importing!
# check if we have already a symbol of the same name:
var check = StrTableGet(c.tab.stack[importTablePos], s.name)
if (check != nil) and (check.id != copy.id):
if not (s.kind in OverloadableSyms):
if check != nil and check.id != copy.id:
if s.kind notin OverloadableSyms:
# s and check need to be qualified:
Incl(c.AmbiguousSymbols, copy.id)
Incl(c.AmbiguousSymbols, check.id)
@@ -70,8 +70,10 @@ proc rawImportSymbol(c: PContext, s: PSym) =
check = NextIdentIter(it, c.tab.stack[importTablePos])
if e != nil:
rawImportSymbol(c, e)
elif s.kind == skConverter:
addConverter(c, s) # rodgen assures that converters are no stubs
else:
# rodgen assures that converters and patterns are no stubs
if s.kind == skConverter: addConverter(c, s)
if hasPattern(s): addPattern(c, s)
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerAcc(n)

View File

@@ -183,7 +183,7 @@ proc getPrecedence(tok: TToken): int =
of '?': result = 2
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf: result = 5
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = 6
of tkAnd: result = 4
of tkOr, tkXor: result = 3
@@ -969,9 +969,18 @@ proc parseBreakOrContinue(p: var TParser, kind: TNodeKind): PNode =
of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode)
else: addSon(result, parseSymbol(p))
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
proc parseAs(p: var TParser): PNode =
result = newNodeP(nkPatternStmt, p)
getTok(p) # skip `as`
if p.tok.tokType == tkColon:
eat(p, tkColon)
addSon(result, parseStmt(p))
else:
addSon(result, parseExpr(p))
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
while true:
while true:
getTok(p) # skip `if`, `when`, `elif`
var branch = newNodeP(nkElifBranch, p)
optInd(p, branch)
@@ -981,8 +990,8 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
addSon(branch, parseStmt(p))
skipComment(p, branch)
addSon(result, branch)
if p.tok.tokType != tkElif: break
if p.tok.tokType == tkElse:
if p.tok.tokType != tkElif: break
if p.tok.tokType == tkElse:
var branch = newNodeP(nkElse, p)
eat(p, tkElse)
eat(p, tkColon)
@@ -1176,6 +1185,8 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
addSon(result, parseParamList(p))
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, ast.emptyNode)
# empty pattern:
addSon(result, ast.emptyNode)
if p.tok.tokType == tkEquals:
getTok(p)
skipComment(p, result)
@@ -1511,6 +1522,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p)
of tkAs: result = parseAs(p)
else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode =

View File

@@ -15,13 +15,8 @@ import
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, semthreads, idgen
type
TPassComm* = object {.pure.} ## communication object between passes
optimizers*: TSymSeq ## filled by semantic pass; used in HLO
PPassComm* = ref TPassComm
type
TPassContext* = object of TObject # the pass's context
comm*: PPassComm
fromCache*: bool # true if created by "openCached"
PPassContext* = ref TPassContext
@@ -85,26 +80,18 @@ proc registerPass(p: TPass) =
gPasses[gPassesLen] = p
inc(gPassesLen)
proc newPassComm(): PPassComm =
new(result)
result.optimizers = @[]
proc openPasses(a: var TPassContextArray, module: PSym, filename: string) =
var comm = newPassComm()
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].open):
a[i] = gPasses[i].open(module, filename)
if a[i] != nil: a[i].comm = comm
else: a[i] = nil
proc openPassesCached(a: var TPassContextArray, module: PSym, filename: string,
rd: PRodReader) =
var comm = newPassComm()
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached):
a[i] = gPasses[i].openCached(module, filename, rd)
if a[i] != nil:
a[i].comm = comm
a[i].fromCache = true
else:
a[i] = nil

128
compiler/patterns.nim Normal file
View File

@@ -0,0 +1,128 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the pattern matching features for term rewriting
## macro support.
import ast, astalgo, types, semdata, sigmatch, msgs, idents
type
TPatternContext = object
owner: PSym
mapping: TIdNodeTable # maps formal parameters to nodes
c: PContext
PPatternContext = var TPatternContext
proc matches(c: PPatternContext, p, n: PNode): bool
proc checkConstraints(c: PPatternContext, p, n: PNode): bool =
# XXX create a new mapping here? --> need use cases
result = matches(c, p, n)
proc canonKind(n: PNode): TNodeKind =
## nodekind canonilization for pattern matching
result = n.kind
case result
of nkCallKinds: result = nkCall
of nkStrLit..nkTripleStrLit: result = nkStrLit
of nkFastAsgn: result = nkAsgn
else: nil
proc sameKinds(a, b: PNode): bool {.inline.} =
result = a.kind == b.kind or a.canonKind == b.canonKind
proc sameTrees(a, b: PNode): bool =
if sameKinds(a, b):
case a.kind
of nkSym: result = a.sym == b.sym
of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkEmpty, nkNilLit: result = true
of nkType: result = sameTypeOrNil(a.typ, b.typ)
else:
if sonsLen(a) == sonsLen(b):
for i in countup(0, sonsLen(a) - 1):
if not sameTrees(a.sons[i], b.sons[i]): return
result = true
proc inSymChoice(sc, x: PNode): bool =
if sc.kind in {nkOpenSymChoice, nkClosedSymChoice}:
for i in 0.. <sc.len:
if sc.sons[i].sym == x.sym: return true
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
# XXX tyVarargs is special here; lots of other special cases
if isNil(n.typ):
result = p.typ.kind == tyStmt
else:
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
proc matches(c: PPatternContext, p, n: PNode): bool =
# XXX special treatment: statement list,
# ignore comments, nkPar, hidden conversions
# f(..X) ~> how can 'X' stand for all remaining parameters? -> introduce
# a new local node kind (alias of nkReturnToken or something)
if p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner:
var pp = IdNodeTableGetLazy(c.mapping, p.sym)
if pp != nil:
# check if we got the same pattern (already unified):
result = matches(c, pp, n)
elif checkTypes(c, p.sym, n) and
(p.sym.ast == nil or checkConstraints(c, p.sym.ast, n)):
IdNodeTablePutLazy(c.mapping, p.sym, n)
result = true
elif n.kind == nkSym and inSymChoice(p, n):
result = true
elif n.kind == nkSym and n.sym.kind == skConst:
# try both:
if sameTrees(p, n): result = true
elif matches(c, p, n.sym.ast):
result = true
elif sameKinds(p, n):
case p.kind
of nkSym: result = p.sym == n.sym
of nkIdent: result = p.ident.id == n.ident.id
of nkCharLit..nkInt64Lit: result = p.intVal == n.intVal
of nkFloatLit..nkFloat64Lit: result = p.floatVal == n.floatVal
of nkStrLit..nkTripleStrLit: result = p.strVal == n.strVal
of nkEmpty, nkNilLit, nkType: result = true
else:
if sonsLen(p) == sonsLen(n):
for i in countup(0, sonsLen(p) - 1):
if not matches(c, p.sons[i], n.sons[i]): return
result = true
# writeln(X, a); writeln(X, b); --> writeln(X, a, b)
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
## returns a tree to semcheck if the rule triggered; nil otherwise
var ctx: TPatternContext
ctx.owner = s
ctx.c = c
# we perform 'initIdNodeTable' lazily for performance
if matches(ctx, s.ast.sons[patternPos], n):
# each parameter should have been bound; we simply setup a call and
# let semantic checking deal with the rest :-)
# this also saves type checking if we allow for type checking errors
# as in 'system.compiles' and simply discard the results. But an error
# may have been desired in the first place! Meh, it's good enough for
# a first implementation:
result = newNodeI(nkCall, n.info)
result.add(newSymNode(s, n.info))
let params = s.typ.n
for i in 1 .. < params.len:
let param = params.sons[i].sym
let x = IdNodeTableGetLazy(ctx.mapping, param)
# couldn't bind parameter:
if isNil(x):
echo "couldn't bind ", param.name.s
return nil
result.add(x)

View File

@@ -586,6 +586,16 @@ proc gwhile(g: var TSrcGen, n: PNode) =
gcoms(g) # a good place for comments
gstmts(g, n.sons[1], c)
proc gpattern(g: var TSrcGen, n: PNode) =
var c: TContext
put(g, tkAs, "as")
putWithSpace(g, tkColon, ":")
initContext(c)
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
var c: TContext
gsub(g, n.sons[0])
@@ -656,20 +666,20 @@ proc gproc(g: var TSrcGen, n: PNode) =
put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
else:
gsub(g, n.sons[namePos])
gsub(g, n.sons[1])
gsub(g, n.sons[2])
gsub(g, n.sons[3])
gsub(g, n.sons[genericParamsPos])
gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos])
if renderNoBody notin g.flags:
if n.sons[4].kind != nkEmpty:
if n.sons[bodyPos].kind != nkEmpty:
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
indentNL(g)
gcoms(g)
dedent(g)
initContext(c)
gstmts(g, n.sons[4], c)
gstmts(g, n.sons[bodyPos], c)
putNL(g)
else:
else:
indentNL(g)
gcoms(g)
dedent(g)
@@ -1035,6 +1045,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkCaseStmt, nkRecCase: gcase(g, n)
of nkMacroStmt: gmacro(g, n)
of nkTryStmt: gtry(g, n)
of nkPatternStmt: gpattern(g, n)
of nkForStmt, nkParForStmt: gfor(g, n)
of nkBlockStmt, nkBlockExpr: gblock(g, n)
of nkStaticStmt: gstaticStmt(g, n)

View File

@@ -11,7 +11,7 @@
#
# Reading and writing binary files are really hard to debug. Therefore we use
# a "creative" text/binary hybrid format. ROD-files are more efficient
# to process because symbols are can be loaded on demand.
# to process because symbols can be loaded on demand.
#
# A ROD file consists of:
#
@@ -65,10 +65,12 @@
# semantic checking:
# CONVERTERS:id id\n # symbol ID
#
# This is a misnomer now; it's really a "load unconditionally" section as
# it is also used for pattern templates.
#
# - a list of all (private or exported) methods because they are needed for
# correct dispatcher generation:
# METHODS: id id\n # symbol ID
#
# - an AST section that contains the module's AST:
# INIT(
# idx\n # position of the node in the DATA section

View File

@@ -357,10 +357,10 @@ proc symStack(w: PRodWriter): int =
add(w.compilerProcs, ' ')
encodeVInt(s.id, w.compilerProcs)
add(w.compilerProcs, rodNL)
if s.kind == skConverter:
if s.kind == skConverter or hasPattern(s):
if w.converters.len != 0: add(w.converters, ' ')
encodeVInt(s.id, w.converters)
elif s.kind == skMethod and sfDispatcher notin s.flags:
if s.kind == skMethod and sfDispatcher notin s.flags:
if w.methods.len != 0: add(w.methods, ' ')
encodeVInt(s.id, w.methods)
elif IiTableGet(w.imports.tab, s.id) == invalidKey:

View File

@@ -15,7 +15,7 @@ import
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
evaltempl
evaltempl, patterns
proc semPass*(): TPass
# implementation
@@ -102,6 +102,19 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
return n
result = evalTypedExpr(c, e)
proc applyPatterns(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0: return n
result = n
# we apply the last pattern first, so that pattern overriding is possible;
# however the resulting AST would better not trigger the old rule then
# anymore ;-)
for i in countdown(<c.patterns.len, 0):
let x = applyRule(c, c.patterns[i], result)
if not isNil(x):
assert x.kind == nkCall
result = semExpr(c, x)
include seminst, semcall
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =

View File

@@ -67,6 +67,7 @@ type
InUnrolledContext*: int # > 0 if we are unrolling a loop
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
converters*: TSymSeq # sequence of converters
patterns*: TSymSeq # sequence of pattern matchers
optionStack*: TLinkedList
libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
@@ -93,7 +94,6 @@ proc newContext*(module: PSym, nimfile: string): PContext
proc lastOptionEntry*(c: PContext): POptionEntry
proc newOptionEntry*(): POptionEntry
proc addConverter*(c: PContext, conv: PSym)
proc newLib*(kind: TLibKind): PLib
proc addToLib*(lib: PLib, sym: PSym)
proc makePtrType*(c: PContext, baseType: PType): PType
@@ -158,6 +158,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
result.friendModule = module
result.threadEntries = @[]
result.converters = @[]
result.patterns = @[]
result.filename = nimfile
result.includedFiles = initIntSet()
initStrTable(result.userPragmas)
@@ -172,12 +173,18 @@ proc newContext(module: PSym, nimfile: string): PContext =
assert gGenericsCache == nil
result.UnknownIdents = initIntSet()
proc addConverter(c: PContext, conv: PSym) =
var L = len(c.converters)
proc inclSym(sq: var TSymSeq, s: PSym) =
var L = len(sq)
for i in countup(0, L - 1):
if c.converters[i].id == conv.id: return
setlen(c.converters, L + 1)
c.converters[L] = conv
if sq[i].id == s.id: return
setlen(sq, L + 1)
sq[L] = s
proc addConverter*(c: PContext, conv: PSym) =
inclSym(c.converters, conv)
proc addPattern*(c: PContext, p: PSym) =
inclSym(c.patterns, p)
proc newLib(kind: TLibKind): PLib =
new(result)

View File

@@ -1591,3 +1591,4 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
LocalError(n.info, errInvalidExpressionX,
renderTree(n, {renderNoComments}))
incl(result.flags, nfSem)
result = applyPatterns(c, result)

View File

@@ -1202,6 +1202,16 @@ proc SemStmt(c: PContext, n: PNode): PNode =
result = semPragmaBlock(c, n)
of nkStaticStmt:
result = semStaticStmt(c, n)
of nkPatternStmt:
let pat = semPatternStmt(c, n)
let s = getCurrOwner()
if s.kind in routineKinds and s.ast.sons[patternPos].kind == nkEmpty:
s.ast.sons[patternPos] = pat
c.patterns.add(s)
else:
LocalError(n.info, errXNotAllowedHere, "'as'")
# replace by an empty statement:
result = newNodeI(nkNilLit, n.info)
else:
# in interactive mode, we embed the expression in an 'echo':
if gCmd == cmdInteractive:
@@ -1214,10 +1224,11 @@ proc SemStmt(c: PContext, n: PNode): PNode =
InternalError(n.info, "SemStmt: result = nil")
# error correction:
result = emptyNode
else:
else:
incl(result.flags, nfSem)
result = applyPatterns(c, result)
proc semStmtScope(c: PContext, n: PNode): PNode =
proc semStmtScope(c: PContext, n: PNode): PNode =
openScope(c.tab)
result = semStmt(c, n)
closeScope(c.tab)

View File

@@ -98,10 +98,16 @@ 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 =
@@ -166,10 +172,8 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
else:
n.sons[namePos] = semTemplBody(c, n.sons[namePos])
openScope(c)
n.sons[genericParamsPos] = semTemplBody(c, n.sons[genericParamsPos])
n.sons[paramsPos] = semTemplBody(c, n.sons[paramsPos])
n.sons[pragmasPos] = semTemplBody(c, n.sons[pragmasPos])
n.sons[bodyPos] = semTemplBodyScope(c, n.sons[bodyPos])
for i in genericParamsPos..bodyPos:
n.sons[i] = semTemplBody(c, n.sons[i])
closeScope(c)
proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
@@ -183,6 +187,8 @@ 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
@@ -395,6 +401,7 @@ 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:
@@ -415,3 +422,15 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else:
SymTabReplace(c.tab.stack[curScope], proto, s)
proc semPatternStmt(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.sons[0])
closeScope(c.tab)

View File

@@ -647,7 +647,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isIntConv:
# too lazy to introduce another ``*matches`` field, so we conflate
# I'm too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here:
inc(m.intConvMatches)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)

View File

@@ -46,7 +46,7 @@ type
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
nnkIncludeStmt, nnkBindStmt,
nnkIncludeStmt, nnkBindStmt, nnkPatternStmt,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,

View File

@@ -14,9 +14,6 @@ version 0.9.0
- the lookup rules for generics really are too permissive; global scope only
doesn't fly with closures though; for a start add a warning when processing
generic code
- fix remaining closure bugs:
- test evals.nim with closures
- what about macros with closures?
Bugs
@@ -47,6 +44,9 @@ version 0.9.XX
- JS gen:
- fix exception handling
- fix remaining closure bugs:
- test evals.nim with closures
- what about macros with closures?
- document 'do' notation
- allow implicit forward declarations of procs via a pragma (so that the