diff options
-rwxr-xr-x | compiler/ast.nim | 18 | ||||
-rwxr-xr-x | compiler/astalgo.nim | 9 | ||||
-rw-r--r-- | compiler/ccgmerge.nim | 7 | ||||
-rwxr-xr-x | compiler/condsyms.nim | 2 | ||||
-rwxr-xr-x | compiler/evals.nim | 58 | ||||
-rw-r--r-- | compiler/evaltempl.nim | 83 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 9 | ||||
-rwxr-xr-x | compiler/nimconf.nim | 42 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 25 | ||||
-rwxr-xr-x | compiler/sem.nim | 15 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 6 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 22 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 26 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 267 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 31 | ||||
-rwxr-xr-x | compiler/suggest.nim | 10 | ||||
-rwxr-xr-x | compiler/types.nim | 7 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 4 | ||||
-rwxr-xr-x | doc/manual.txt | 4 | ||||
-rwxr-xr-x | lib/impure/re.nim | 5 | ||||
-rwxr-xr-x | lib/pure/pegs.nim | 5 | ||||
-rwxr-xr-x | tests/tester.nim | 7 | ||||
-rwxr-xr-x | todo.txt | 9 |
23 files changed, 485 insertions, 186 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index cf1737c32..90885a71f 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -234,7 +234,7 @@ type sfDiscriminant, # field is a discriminant in a record/object sfDeprecated, # symbol is deprecated sfError, # usage of symbol should trigger a compile-time error - sfInnerProc, # proc is an inner proc + sfShadowed, # a symbol that was shadowed in some inner scope sfThread, # proc will run as a thread # variable is a thread variable sfCompileTime, # proc can be evaluated at compile time @@ -247,7 +247,7 @@ type # language; for interfacing with Objective C sfDiscardable # returned value may be discarded implicitely sfDestructor # proc is destructor - sfByCopy # a variable is to be captured by value in a closure + sfGenSym # symbol is 'gensym'ed; do not add to symbol table TSymFlags* = set[TSymFlag] @@ -264,10 +264,7 @@ const # symbol name that was generated by the compiler # the compiler will avoid printing such names # in user messages. - - sfShadowed* = sfInnerProc - # a variable that was shadowed in some inner scope - + sfHoist* = sfVolatile ## proc return value can be hoisted const @@ -785,15 +782,6 @@ const # for all kind of hash tables: GrowthFactor* = 2 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0 -proc ValueToString*(a: PNode): string = - case a.kind - of nkCharLit..nkUInt64Lit: result = $(a.intVal) - of nkFloatLit..nkFloat128Lit: result = $(a.floatVal) - of nkStrLit..nkTripleStrLit: result = a.strVal - else: - InternalError(a.info, "valueToString") - result = "" - proc copyStrTable(dest: var TStrTable, src: TStrTable) = dest.counter = src.counter if isNil(src.data): return diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index c40d89d84..9da3e21e4 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -166,7 +166,9 @@ proc SameValue*(a, b: PNode): bool = of nkStrLit..nkTripleStrLit: if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal else: - InternalError(a.info, "SameValue") + # don't raise an internal error for 'nimrod check': + #InternalError(a.info, "SameValue") + nil proc leValue*(a, b: PNode): bool = # a <= b? @@ -178,7 +180,10 @@ proc leValue*(a, b: PNode): bool = if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal of nkStrLit..nkTripleStrLit: if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal - else: InternalError(a.info, "leValue") + else: + # don't raise an internal error for 'nimrod check': + #InternalError(a.info, "leValue") + nil proc lookupInRecord(n: PNode, field: PIdent): PSym = result = nil diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 311711f5a..8c490a693 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -224,13 +224,16 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = of "labels": m.labels = decodeVInt(L.buf, L.bufpos) of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0 else: InternalError("ccgmerge: unkown key: " & k) + +when not defined(nimhygiene): + {.pragma: inject.} template withCFile(cfilename: string, body: stmt) = var s = LLStreamOpen(cfilename, fmRead) if s == nil: return - var L: TBaseLexer + var L {.inject.}: TBaseLexer openBaseLexer(L, s) - var k = newStringOfCap("NIM_merge_FORWARD_TYPES".len) + var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len) while true: skipUntilCmd(L) if ^L.bufpos == '\0': break diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b0ecef816..d273f5335 100755 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -55,6 +55,8 @@ proc countDefinedSymbols*(): int = proc InitDefines*() = initStrTable(gSymbols) DefineSymbol("nimrod") # 'nimrod' is always defined + # for bootstrapping purposes and old code: + DefineSymbol("nimhygiene") # add platform specific symbols: case targetCPU diff --git a/compiler/evals.nim b/compiler/evals.nim index 04e8cd650..e17ab2c6c 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -16,7 +16,7 @@ import strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, - parser, ropes, rodread, idgen, osproc, streams + parser, ropes, rodread, idgen, osproc, streams, evaltempl type PStackFrame* = ref TStackFrame @@ -850,56 +850,6 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode = result = parseString(code.getStrValue, code.info.toFilename, code.stringStartingLine) result.typ = newType(tyStmt, c.module) - -proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = - inc genSymBaseId - case templ.kind - of nkSym: - var p = templ.sym - if (p.kind == skParam) and (p.owner.id == sym.id): - result = copyTree(actual.sons[p.position]) - else: - result = copyNode(templ) - of nkNone..nkIdent, nkType..nkNilLit: # atom - result = copyNode(templ) - else: - result = copyNode(templ) - newSons(result, sonsLen(templ)) - for i in countup(0, sonsLen(templ) - 1): - result.sons[i] = evalTemplateAux(templ.sons[i], actual, sym) - -proc evalTemplateArgs(n: PNode, s: PSym): PNode = - # if the template has zero arguments, it can be called without ``()`` - # `n` is then a nkSym or something similar - var a: int - case n.kind - of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: - a = sonsLen(n) - else: a = 0 - var f = s.typ.sonsLen - if a > f: GlobalError(n.info, errWrongNumberOfArguments) - - result = copyNode(n) - for i in countup(1, f - 1): - var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast) - if arg == nil or arg.kind == nkEmpty: - LocalError(n.info, errWrongNumberOfArguments) - addSon(result, arg) - -var evalTemplateCounter* = 0 - # to prevent endless recursion in templates instantation - -proc evalTemplate*(n: PNode, sym: PSym): PNode = - inc(evalTemplateCounter) - if evalTemplateCounter > 100: - GlobalError(n.info, errTemplateInstantiationTooNested) - result = n - - # replace each param by the corresponding node: - var args = evalTemplateArgs(n, sym) - result = evalTemplateAux(sym.getBody, args, sym) - - dec(evalTemplateCounter) proc evalTypeTrait*(n: PNode, context: PSym): PNode = ## XXX: This should be pretty much guaranteed to be true @@ -964,7 +914,11 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = case expandedSym.kind of skTemplate: - result = evalTemplate(macroCall, expandedSym) + let genSymOwner = if c.tos != nil and c.tos.prc != nil: + c.tos.prc + else: + c.module + result = evalTemplate(macroCall, expandedSym, genSymOwner) of skMacro: # At this point macroCall.sons[0] is nkSym node. # To be completely compatible with normal macro invocation, diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim new file mode 100644 index 000000000..d7006d34d --- /dev/null +++ b/compiler/evaltempl.nim @@ -0,0 +1,83 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Template evaluation engine. Now hygienic. + +import + strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, + rodread + +type + TemplCtx {.pure, final.} = object + owner, genSymOwner: PSym + mapping: TIdTable # every gensym'ed symbol needs to be mapped to some + # new symbol + +proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx): PNode = + #inc genSymBaseId + case templ.kind + of nkSym: + var s = templ.sym + if s.owner.id == c.owner.id: + if s.kind == skParam: + result = copyTree(actual.sons[s.position]) + else: + InternalAssert sfGenSym in s.flags + var x = PSym(IdTableGet(c.mapping, s)) + if x == nil: + x = copySym(s, false) + x.owner = c.genSymOwner + IdTablePut(c.mapping, s, x) + result = newSymNode(x, templ.info) + else: + result = copyNode(templ) + of nkNone..nkIdent, nkType..nkNilLit: # atom + result = copyNode(templ) + else: + result = copyNode(templ) + newSons(result, sonsLen(templ)) + for i in countup(0, sonsLen(templ) - 1): + result.sons[i] = evalTemplateAux(templ.sons[i], actual, c) + +proc evalTemplateArgs(n: PNode, s: PSym): PNode = + # if the template has zero arguments, it can be called without ``()`` + # `n` is then a nkSym or something similar + var a: int + case n.kind + of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: + a = sonsLen(n) + else: a = 0 + var f = s.typ.sonsLen + if a > f: GlobalError(n.info, errWrongNumberOfArguments) + + result = copyNode(n) + for i in countup(1, f - 1): + var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast) + if arg == nil or arg.kind == nkEmpty: + LocalError(n.info, errWrongNumberOfArguments) + addSon(result, arg) + +var evalTemplateCounter* = 0 + # to prevent endless recursion in templates instantiation + +proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode = + inc(evalTemplateCounter) + if evalTemplateCounter > 100: + GlobalError(n.info, errTemplateInstantiationTooNested) + result = n + + # replace each param by the corresponding node: + var args = evalTemplateArgs(n, tmpl) + var ctx: TemplCtx + ctx.owner = tmpl + ctx.genSymOwner = genSymOwner + initIdTable(ctx.mapping) + result = evalTemplateAux(tmpl.getBody, args, ctx) + + dec(evalTemplateCounter) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 68d7e62c2..057444b2a 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -471,7 +471,8 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode = # add assignment statements: for local in scope.capturedVars: let fieldAccess = indirectAccess(env, local, env.info) - if sfByCopy in local.flags or local.kind == skParam: + if local.kind == skParam: + # maybe later: (sfByCopy in local.flags) # add ``env.param = param`` result.add(newAsgnStmt(fieldAccess, newSymNode(local))) IdNodeTablePut(o.localsToAccess, local, fieldAccess) @@ -515,9 +516,9 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode = scope.sons[0] = generateClosureCreation(o, env) # change 'local' to 'closure.local', unless it's a 'byCopy' variable: - if sfByCopy notin local.flags: - result = IdNodeTableGet(o.localsToAccess, local) - assert result != nil, "cannot find: " & local.name.s + # if sfByCopy notin local.flags: + result = IdNodeTableGet(o.localsToAccess, local) + assert result != nil, "cannot find: " & local.name.s # else it is captured by copy and this means that 'outer' should continue # to access the local as a local. of nkLambdaKinds: diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index c3592e03a..f4f6d0a42 100755 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -111,7 +111,7 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = proc parseDirective(L: var TLexer, tok: var TToken) = ppGetTok(L, tok) # skip @ case whichKeyword(tok.ident) - of wIf: + of wIf: setlen(condStack, len(condStack) + 1) var res = EvalppIf(L, tok) condStack[high(condStack)] = res @@ -123,25 +123,27 @@ proc parseDirective(L: var TLexer, tok: var TToken) = ppGetTok(L, tok) msgs.MsgWriteln(tokToStr(tok)) ppGetTok(L, tok) - of wPutEnv: - ppGetTok(L, tok) - var key = tokToStr(tok) - ppGetTok(L, tok) - os.putEnv(key, tokToStr(tok)) - ppGetTok(L, tok) - of wPrependEnv: - ppGetTok(L, tok) - var key = tokToStr(tok) - ppGetTok(L, tok) - os.putEnv(key, tokToStr(tok) & os.getenv(key)) - ppGetTok(L, tok) - of wAppendenv: - ppGetTok(L, tok) - var key = tokToStr(tok) - ppGetTok(L, tok) - os.putEnv(key, os.getenv(key) & tokToStr(tok)) - ppGetTok(L, tok) - else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok)) + else: + case tok.ident.s.normalize + of "putenv": + ppGetTok(L, tok) + var key = tokToStr(tok) + ppGetTok(L, tok) + os.putEnv(key, tokToStr(tok)) + ppGetTok(L, tok) + of "prependenv": + ppGetTok(L, tok) + var key = tokToStr(tok) + ppGetTok(L, tok) + os.putEnv(key, tokToStr(tok) & os.getenv(key)) + ppGetTok(L, tok) + of "appendenv": + ppGetTok(L, tok) + var key = tokToStr(tok) + ppGetTok(L, tok) + os.putEnv(key, os.getenv(key) & tokToStr(tok)) + ppGetTok(L, tok) + else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok)) proc confTok(L: var TLexer, tok: var TToken) = ppGetTok(L, tok) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 107660762..08cdb46c5 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -23,16 +23,17 @@ const wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, - wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist} + wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist, + wGenSym, wInject} converterPragmas* = procPragmas methodPragmas* = procPragmas - templatePragmas* = {wImmediate, wDeprecated, wError} + templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, - wImportcpp, wImportobjc, wError, wDiscardable} + wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, - wImportcpp, wImportobjc, wError, wDiscardable} + wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject} exprPragmas* = {wLine} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, @@ -46,14 +47,16 @@ const wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame} typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow, - wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef} + wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef, + wGenSym, wInject} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, wImportcpp, wImportobjc, wError} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern, - wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal} + wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal, + wGenSym, wInject} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, - wExtern, wImportcpp, wImportobjc, wError} + wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect, wThread} @@ -655,9 +658,13 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = incl(sym.typ.flags, tfByRef) of wByCopy: noVal(it) - if sym.kind != skType: incl(sym.flags, sfByCopy) - elif sym.typ == nil: invalidPragma(it) + if sym.kind != skType or sym.typ == nil: invalidPragma(it) else: incl(sym.typ.flags, tfByCopy) + of wInject, wGenSym: + # We check for errors, but do nothing with these pragmas otherwise + # as they are handled directly in 'evalTemplate'. + noVal(it) + if sym == nil: invalidPragma(it) of wLine: PragmaLine(c, it) else: invalidPragma(it) else: invalidPragma(it) diff --git a/compiler/sem.nim b/compiler/sem.nim index 391bf840c..cfdd936ad 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -14,7 +14,8 @@ import wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, - semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting + semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting, + evaltempl proc semPass*(): TPass # implementation @@ -56,7 +57,17 @@ proc isTopLevel(c: PContext): bool {.inline.} = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerAcc(n), getCurrOwner()) result.info = n.info - + +proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = + # like newSymS, but considers gensym'ed symbols + if n.kind == nkSym: + result = n.sym + InternalAssert sfGenSym in result.flags + InternalAssert result.kind == kind + else: + result = newSym(kind, considerAcc(n), getCurrOwner()) + result.info = n.info + proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym # identifier with visability diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c0b890ffb..e4e449c9e 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -24,7 +24,7 @@ proc restoreOldStyleType(n: PNode) = proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) pushInfoContext(n.info) - result = evalTemplate(n, s) + result = evalTemplate(n, s, getCurrOwner()) if semCheck: result = semAfterMacroCall(c, result, s) popInfoContext() @@ -1372,7 +1372,9 @@ proc semBlockExpr(c: PContext, n: PNode): PNode = Inc(c.p.nestedBlockCounter) checkSonsLen(n, 2) openScope(c.tab) # BUGFIX: label is in the scope of block! - if n.sons[0].kind != nkEmpty: addDecl(c, newSymS(skLabel, n.sons[0], c)) + if n.sons[0].kind notin {nkEmpty, nkSym}: + # nkSym for gensym'ed labels: + addDecl(c, newSymS(skLabel, n.sons[0], c)) n.sons[1] = semStmtListExpr(c, n.sons[1]) n.typ = n.sons[1].typ closeScope(c.tab) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 59e8a2dff..de73d6d86 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -17,11 +17,20 @@ # included from sem.nim -type - TSemGenericFlag = enum +type + TSemGenericFlag = enum withinBind, withinTypeDesc TSemGenericFlags = set[TSemGenericFlag] +proc getIdentNode(n: PNode): PNode = + case n.kind + of nkPostfix: result = getIdentNode(n.sons[1]) + of nkPragmaExpr: result = getIdentNode(n.sons[0]) + of nkIdent, nkAccQuoted, nkSym: result = n + else: + illFormedAst(n) + result = n + proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, toBind: var TIntSet): PNode proc semGenericStmtScope(c: PContext, n: PNode, @@ -54,15 +63,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = result = n else: result = newSymNode(s, n.info) -proc getIdentNode(n: PNode): PNode = - case n.kind - of nkPostfix: result = getIdentNode(n.sons[1]) - of nkPragmaExpr: result = getIdentNode(n.sons[0]) - of nkIdent, nkAccQuoted: result = n - else: - illFormedAst(n) - result = n - proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, toBind: var TIntSet): PNode = result = n diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index df51b94df..d531118c5 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -91,10 +91,11 @@ proc semBlock(c: PContext, n: PNode): PNode = Inc(c.p.nestedBlockCounter) checkSonsLen(n, 2) openScope(c.tab) # BUGFIX: label is in the scope of block! - if n.sons[0].kind != nkEmpty: - var labl = newSymS(skLabel, n.sons[0], c) - addDecl(c, labl) - n.sons[0] = newSymNode(labl) + if n.sons[0].kind != nkEmpty: + var labl = newSymG(skLabel, n.sons[0], c) + if sfGenSym notin labl.flags: + addDecl(c, labl) + n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(n.sons[0], labl) n.sons[1] = semStmt(c, n.sons[1]) closeScope(c.tab) @@ -284,7 +285,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = Message(a.info, warnEachIdentIsTuple) for j in countup(0, length-3): var v = semIdentDef(c, a.sons[j], symkind) - addInterfaceDecl(c, v) + if sfGenSym notin v.flags: addInterfaceDecl(c, v) when oKeepVariableNames: if c.InUnrolledContext > 0: v.flags.incl(sfShadowed) else: @@ -332,7 +333,7 @@ proc semConst(c: PContext, n: PNode): PNode = continue v.typ = typ v.ast = def # no need to copy - addInterfaceDecl(c, v) + if sfGenSym notin v.flags: addInterfaceDecl(c, v) var b = newNodeI(nkConstDef, a.info) addSon(b, newSymNode(v)) addSon(b, ast.emptyNode) # no type description @@ -422,25 +423,25 @@ proc semForVars(c: PContext, n: PNode): PNode = # and thus no tuple unpacking: if iter.kind != tyTuple or length == 3: if length == 3: - var v = newSymS(skForVar, n.sons[0], c) + var v = newSymG(skForVar, n.sons[0], c) if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) # BUGFIX: don't use `iter` here as that would strip away # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim`` # for an example: v.typ = n.sons[length-2].typ n.sons[0] = newSymNode(v) - addDecl(c, v) + if sfGenSym notin v.flags: addDecl(c, v) else: LocalError(n.info, errWrongNumberOfVariables) elif length-2 != sonsLen(iter): LocalError(n.info, errWrongNumberOfVariables) else: for i in countup(0, length - 3): - var v = newSymS(skForVar, n.sons[i], c) + var v = newSymG(skForVar, n.sons[i], c) if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) v.typ = iter.sons[i] n.sons[i] = newSymNode(v) - addDecl(c, v) + if sfGenSym notin v.flags: addDecl(c, v) Inc(c.p.nestedLoopCounter) n.sons[length-1] = SemStmt(c, n.sons[length-1]) Dec(c.p.nestedLoopCounter) @@ -539,7 +540,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = if a.sons[0].kind == nkPragmaExpr: pragma(c, s, a.sons[0].sons[1], typePragmas) # add it here, so that recursive types are possible: - addInterfaceDecl(c, s) + if sfGenSym notin s.flags: addInterfaceDecl(c, s) a.sons[0] = newSymNode(s) proc typeSectionRightSidePass(c: PContext, n: PNode) = @@ -780,7 +781,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, s.typ.callConv = lastOptionEntry(c).defaultCC # add it here, so that recursive procs are possible: # -2 because we have a scope open for parameters - if kind in OverloadableSyms: + if sfGenSym in s.flags: nil + elif kind in OverloadableSyms: addInterfaceOverloadableSymAt(c, s, c.tab.tos - 2) else: addInterfaceDeclAt(c, s, c.tab.tos - 2) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 960650a61..4849f6d6c 100755 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -9,6 +9,37 @@ # included from sem.nim +discard """ + hygienic templates: + + template `||` (a, b: expr): expr = + let aa = a + (if aa: aa else: b) + + var + a, b: T + + a || b || a + + Each evaluation context has to be different and we need to perform + some form of preliminary symbol lookup in template definitions. Hygiene is + a way to achieve lexical scoping at compile time. +""" + +type + TSymBinding = enum + spNone, spGenSym, spInject + +proc symBinding(n: PNode): TSymBinding = + for i in countup(0, sonsLen(n) - 1): + var it = n.sons[i] + var key = if it.kind == nkExprColonExpr: it.sons[0] else: it + if key.kind == nkIdent: + case whichKeyword(key.ident) + of wGenSym: return spGenSym + of wInject: return spInject + else: nil + proc symChoice(c: PContext, n: PNode, s: PSym): PNode = var a: PSym @@ -20,17 +51,16 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode = inc(i) if i > 1: break if i <= 1: - result = newSymNode(s) - result.info = n.info + result = newSymNode(s, n.info) markUsed(n, s) - else: + else: # semantic checking requires a type; ``fitNode`` deals with it # appropriately result = newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c)) a = initOverloadIter(o, c, n) while a != nil: incl(a.flags, sfUsed) - addSon(result, newSymNode(a)) + addSon(result, newSymNode(a, n.info)) a = nextOverloadIter(o, c, n) proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = @@ -45,37 +75,217 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = else: illFormedAst(a) result = newNodeI(nkEmpty, n.info) + +proc replaceIdentBySym(n: var PNode, s: PNode) = + case n.kind + of nkPostfix: replaceIdentBySym(n.sons[1], s) + of nkPragmaExpr: replaceIdentBySym(n.sons[0], s) + of nkIdent, nkAccQuoted, nkSym: n = s + else: illFormedAst(n) -proc resolveTemplateParams(c: PContext, n: PNode, owner: PSym, - toBind: var TIntSet): PNode = - var s: PSym +type + TemplCtx {.pure, final.} = object + c: PContext + toBind: TIntSet + owner: PSym + +proc getIdentNode(c: var TemplCtx, n: PNode): PNode = case n.kind + of nkPostfix: result = getIdentNode(c, n.sons[1]) + of nkPragmaExpr: result = getIdentNode(c, n.sons[0]) of nkIdent: result = n - let s = QualifiedLookUp(c, n, {}) + let s = QualifiedLookUp(c.c, n, {}) if s != nil: - if s.owner == owner and s.kind == skParam: - result = newSymNode(s) - result.info = n.info - elif Contains(toBind, s.id): - result = symChoice(c, n, s) - - of nkEmpty, nkSym..nkNilLit: # atom + if s.owner == c.owner and s.kind == skParam: + result = newSymNode(s, n.info) + of nkAccQuoted, nkSym: result = n + else: + illFormedAst(n) result = n + +proc isTemplParam(n: PNode): bool {.inline.} = + result = n.kind == nkSym and n.sym.kind == skParam and + n.sym.owner.kind == skTemplate + +proc semTemplBody(c: var TemplCtx, n: PNode): PNode + +proc openScope(c: var TemplCtx) = openScope(c.c.tab) +proc closeScope(c: var TemplCtx) = closeScope(c.c.tab) + +proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode = + openScope(c) + result = semTemplBody(c, n) + closeScope(c) + +proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = + result = newSym(kind, considerAcc(n), c.owner) + incl(result.flags, sfGenSym) + incl(result.flags, sfShadowed) + +proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = + # locals default to 'gensym': + if n.kind != nkPragmaExpr or symBinding(n.sons[1]) != spInject: + let ident = getIdentNode(c, n) + if not isTemplParam(ident): + let local = newGenSym(k, ident, c) + addPrelimDecl(c.c, local) + replaceIdentBySym(n, newSymNode(local, n.info)) + else: + replaceIdentBySym(n, ident) + else: + n = semTemplBody(c, n) + +proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = + result = n + checkSonsLen(n, bodyPos + 1) + # routines default to 'inject': + if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym: + let ident = getIdentNode(c, n.sons[namePos]) + if not isTemplParam(ident): + let s = newGenSym(k, ident, c) + addPrelimDecl(c.c, s) + n.sons[namePos] = newSymNode(s, n.sons[namePos].info) + else: + n.sons[namePos] = ident + 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]) + closeScope(c) + +proc semTemplBody(c: var TemplCtx, n: PNode): PNode = + result = n + case n.kind + of nkIdent: + let s = QualifiedLookUp(c.c, n, {}) + if s != nil: + if s.owner == c.owner and s.kind == skParam: + result = newSymNode(s, n.info) + elif Contains(c.toBind, s.id): + result = symChoice(c.c, n, s) + elif s.owner == c.owner: + InternalAssert sfGenSym in s.flags + incl(s.flags, sfUsed) + result = newSymNode(s, n.info) of nkBind: - result = resolveTemplateParams(c, n.sons[0], owner, toBind) + result = semTemplBody(c, n.sons[0]) of nkBindStmt: - result = semBindStmt(c, n, toBind) + result = semBindStmt(c.c, n, c.toBind) + of nkEmpty, nkSym..nkNilLit: + nil + of nkIfStmt: + for i in countup(0, sonsLen(n)-1): + n.sons[i] = semTemplBodyScope(c, n.sons[i]) + of nkWhileStmt: + openScope(c) + for i in countup(0, sonsLen(n)-1): + n.sons[i] = semTemplBody(c, n.sons[i]) + closeScope(c) + of nkCaseStmt: + openScope(c) + n.sons[0] = semTemplBody(c, n.sons[0]) + for i in countup(1, sonsLen(n)-1): + var a = n.sons[i] + checkMinSonsLen(a, 1) + var L = sonsLen(a) + for j in countup(0, L-2): + a.sons[j] = semTemplBody(c, a.sons[j]) + a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1]) + closeScope(c) + of nkForStmt, nkParForStmt: + var L = sonsLen(n) + openScope(c) + n.sons[L-2] = semTemplBody(c, n.sons[L-2]) + for i in countup(0, L - 3): + addLocalDecl(c, n.sons[i], skForVar) + n.sons[L-1] = semTemplBody(c, n.sons[L-1]) + closeScope(c) + of nkBlockStmt, nkBlockExpr, nkBlockType: + checkSonsLen(n, 2) + openScope(c) + if n.sons[0].kind != nkEmpty: + # labels are always 'gensym'ed: + let s = newGenSym(skLabel, n.sons[0], c) + addPrelimDecl(c.c, s) + n.sons[0] = newSymNode(s, n.sons[0].info) + n.sons[1] = semTemplBody(c, n.sons[1]) + closeScope(c) + of nkTryStmt: + checkMinSonsLen(n, 2) + n.sons[0] = semTemplBodyScope(c, n.sons[0]) + for i in countup(1, sonsLen(n)-1): + var a = n.sons[i] + checkMinSonsLen(a, 1) + var L = sonsLen(a) + for j in countup(0, L-2): + a.sons[j] = semTemplBody(c, a.sons[j]) + a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1]) + of nkVarSection, nkLetSection: + let symKind = if n.kind == nkLetSection: skLet else: skVar + for i in countup(0, sonsLen(n) - 1): + var a = n.sons[i] + if a.kind == nkCommentStmt: continue + if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a) + checkMinSonsLen(a, 3) + var L = sonsLen(a) + a.sons[L-2] = semTemplBody(c, a.sons[L-2]) + a.sons[L-1] = semTemplBody(c, a.sons[L-1]) + for j in countup(0, L-3): + addLocalDecl(c, a.sons[j], symKind) + of nkConstSection: + for i in countup(0, sonsLen(n) - 1): + var a = n.sons[i] + if a.kind == nkCommentStmt: continue + if (a.kind != nkConstDef): IllFormedAst(a) + checkSonsLen(a, 3) + addLocalDecl(c, a.sons[0], skConst) + a.sons[1] = semTemplBody(c, a.sons[1]) + a.sons[2] = semTemplBody(c, a.sons[2]) + of nkTypeSection: + for i in countup(0, sonsLen(n) - 1): + var a = n.sons[i] + if a.kind == nkCommentStmt: continue + if (a.kind != nkTypeDef): IllFormedAst(a) + checkSonsLen(a, 3) + addLocalDecl(c, a.sons[0], skType) + for i in countup(0, sonsLen(n) - 1): + var a = n.sons[i] + if a.kind == nkCommentStmt: continue + if (a.kind != nkTypeDef): IllFormedAst(a) + checkSonsLen(a, 3) + if a.sons[1].kind != nkEmpty: + openScope(c) + a.sons[1] = semTemplBody(c, a.sons[1]) + a.sons[2] = semTemplBody(c, a.sons[2]) + closeScope(c) + else: + a.sons[2] = semTemplBody(c, a.sons[2]) + of nkProcDef, nkLambdaKinds: + result = semRoutineInTemplBody(c, n, skProc) + of nkMethodDef: + result = semRoutineInTemplBody(c, n, skMethod) + of nkIteratorDef: + result = semRoutineInTemplBody(c, n, skIterator) + of nkTemplateDef: + result = semRoutineInTemplBody(c, n, skTemplate) + of nkMacroDef: + result = semRoutineInTemplBody(c, n, skMacro) + of nkConverterDef: + result = semRoutineInTemplBody(c, n, skConverter) else: # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam', # so we use the generic code for nkDotExpr too if n.kind == nkDotExpr or n.kind == nkAccQuoted: - let s = QualifiedLookUp(c, n, {}) - if s != nil and Contains(toBind, s.id): - return symChoice(c, n, s) + let s = QualifiedLookUp(c.c, n, {}) + if s != nil and Contains(c.toBind, s.id): + return symChoice(c.c, n, s) result = n - for i in countup(0, sonsLen(n) - 1): - result.sons[i] = resolveTemplateParams(c, n.sons[i], owner, toBind) + for i in countup(0, sonsLen(n) - 1): + result.sons[i] = semTemplBody(c, n.sons[i]) proc transformToExpr(n: PNode): PNode = var realStmt: int @@ -94,8 +304,8 @@ proc transformToExpr(n: PNode): PNode = else: n.kind = nkStmtListExpr of nkBlockStmt: n.kind = nkBlockExpr - #nkIfStmt: n.kind := nkIfExpr; // this is not correct! - else: + #nkIfStmt: n.kind = nkIfExpr // this is not correct! + else: nil proc semTemplateDef(c: PContext, n: PNode): PNode = @@ -108,7 +318,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # check parameter list: pushOwner(s) openScope(c.tab) - n.sons[namePos] = newSymNode(s) + n.sons[namePos] = newSymNode(s, n.sons[namePos].info) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], templatePragmas) # check that no generic parameters exist: @@ -126,8 +336,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # use ``stmt`` as implicit result type s.typ.sons[0] = newTypeS(tyStmt, c) s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0]) - var toBind = initIntSet() - n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], s, toBind) + var ctx: TemplCtx + ctx.toBind = initIntSet() + ctx.c = c + ctx.owner = s + n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos]) if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}: n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) # only parameters are resolved, no type checking is performed diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 35b841c71..a54c3a297 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -78,7 +78,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = incl(e.flags, sfExported) # BUGFIX StrTableAdd(c.module.tab, e) # BUGFIX addSon(result.n, newSymNode(e)) - addDeclAt(c, e, c.tab.tos - 1) + if sfGenSym notin e.flags: addDeclAt(c, e, c.tab.tos - 1) inc(counter) proc semSet(c: PContext, n: PNode, prev: PType): PType = @@ -264,7 +264,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = if a.sons[length - 1].kind != nkEmpty: LocalError(a.sons[length - 1].info, errInitHereNotAllowed) for j in countup(0, length - 3): - var field = newSymS(skField, a.sons[j], c) + var field = newSymG(skField, a.sons[j], c) field.typ = typ field.position = counter inc(counter) @@ -279,7 +279,9 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, # identifier with visibility if n.kind == nkPostfix: if sonsLen(n) == 2 and n.sons[0].kind == nkIdent: - result = newSymS(kind, n.sons[1], c) + # for gensym'ed identifiers the identifier may already have been + # transformed to a symbol and we need to use that here: + result = newSymG(kind, n.sons[1], c) var v = n.sons[0].ident if sfExported in allowed and v.id == ord(wStar): incl(result.flags, sfExported) @@ -288,7 +290,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, else: illFormedAst(n) else: - result = newSymS(kind, n, c) + result = newSymG(kind, n, c) proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = @@ -469,6 +471,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, typ = semTypeNode(c, n.sons[length-2], nil) for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) + suggestSym(n.sons[i], f) f.typ = typ f.position = pos if (rectype != nil) and ({sfImportc, sfExportc} * rectype.flags != {}) and @@ -548,9 +551,9 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = let nn = getSysSym"PNimrodNode" var a = copySym(param) a.typ = nn.typ - addDecl(c, a) + if sfGenSym notin a.flags: addDecl(c, a) else: - addDecl(c, param) + if sfGenSym notin param.flags: addDecl(c, param) proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): tuple[typ: PType, id: PIdent] = @@ -672,7 +675,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue for j in countup(0, length-3): - var arg = newSymS(skParam, a.sons[j], c) + var arg = newSymG(skParam, a.sons[j], c) var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info).skipIntLit arg.typ = finalType @@ -711,7 +714,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType = Inc(c.p.nestedBlockCounter) checkSonsLen(n, 2) openScope(c.tab) - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind notin {nkEmpty, nkSym}: addDecl(c, newSymS(skLabel, n.sons[0], c)) result = semStmtListType(c, n.sons[1], prev) n.sons[1].typ = result @@ -947,7 +950,7 @@ proc semGenericConstraints(c: PContext, n: PNode, result: PType) = proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) if n.kind != nkGenericParams: - InternalError(n.info, "semGenericParamList") + illFormedAst(n) return for i in countup(0, sonsLen(n)-1): var a = n.sons[i] @@ -965,27 +968,27 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = for j in countup(0, L-3): var s: PSym if typ == nil: - s = newSymS(skType, a.sons[j], c) + s = newSymG(skType, a.sons[j], c) s.typ = newTypeS(tyGenericParam, c) else: case typ.kind of tyTypeDesc: - s = newSymS(skType, a.sons[j], c) + s = newSymG(skType, a.sons[j], c) s.typ = newTypeS(tyGenericParam, c) of tyExpr: #echo "GENERIC EXPR ", a.info.toFileLineCol # not a type param, but an expression # proc foo[x: expr](bar: int) what is this? - s = newSymS(skGenericParam, a.sons[j], c) + s = newSymG(skGenericParam, a.sons[j], c) s.typ = typ else: # This handles cases like proc foo[t: tuple] # XXX: we want to turn that into a type class - s = newSymS(skType, a.sons[j], c) + s = newSymG(skType, a.sons[j], c) s.typ = typ if def.kind != nkEmpty: s.ast = def s.typ.sym = s if father != nil: addSonSkipIntLit(father, s.typ) s.position = i addSon(result, newSymNode(s)) - addDecl(c, s) + if sfGenSym notin s.flags: addDecl(c, s) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 9ca02689e..3b9c77336 100755 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -54,9 +54,13 @@ proc suggestField(c: PContext, s: PSym, outputs: var int) = OutWriteln(SymToStr(s, isLocal=true, sectionSuggest)) inc outputs -template wholeSymTab(cond, section: expr) {.immediate.} = - for i in countdown(c.tab.tos-1, 0): - for it in items(c.tab.stack[i]): +when not defined(nimhygiene): + {.pragma: inject.} + +template wholeSymTab(cond, section: expr) {.immediate.} = + for i in countdown(c.tab.tos-1, 0): + for item in items(c.tab.stack[i]): + let it {.inject.} = item if cond: OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section)) inc outputs diff --git a/compiler/types.nim b/compiler/types.nim index 69ace9772..8dae14924 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -380,6 +380,13 @@ proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = var marker = InitIntSet() result = mutateTypeAux(marker, t, iter, closure) +proc ValueToString(a: PNode): string = + case a.kind + of nkCharLit..nkUInt64Lit: result = $(a.intVal) + of nkFloatLit..nkFloat128Lit: result = $(a.floatVal) + of nkStrLit..nkTripleStrLit: result = a.strVal + else: result = "<invalid value>" + proc rangeToStr(n: PNode): string = assert(n.kind == nkRange) result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1]) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 382b6c765..43bdf4fa4 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -60,7 +60,7 @@ type wFieldChecks, wWatchPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, - wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, + wWrite, wGensym, wInject, wInheritable, wThreadVar, wEmit, wNoStackFrame, wImplicitStatic, wGlobal, wHoist wAuto, wBool, wCatch, wChar, wClass, @@ -138,7 +138,7 @@ const "passc", "passl", "borrow", "discardable", "fieldchecks", "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", - "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", + "write", "gensym", "inject", "inheritable", "threadvar", "emit", "nostackframe", "implicitstatic", "global", "hoist", "auto", "bool", "catch", "char", "class", diff --git a/doc/manual.txt b/doc/manual.txt index 5933691b0..813f1a5b4 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -908,7 +908,7 @@ converts the list of arguments to an array implicitely: write(f, "\n") myWriteln(stdout, "abc", "def", "xyz") - # is transformed by the compiler to: + # is transformed to: myWriteln(stdout, ["abc", "def", "xyz"]) This transformation is only done if the varargs parameter is the @@ -922,7 +922,7 @@ type conversions in this context: write(f, "\n") myWriteln(stdout, 123, "abc", 4.0) - # is transformed by the compiler to: + # is transformed to: myWriteln(stdout, [$123, $"def", $4.0]) In this example ``$`` is applied to any argument that is passed to the diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 7ef3d247a..57dc3a313 100755 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -218,6 +218,9 @@ proc findAll*(s: string, pattern: TRegEx, start = 0): seq[string] = ## If it does not match, @[] is returned. accumulateResult(findAll(s, pattern, start)) +when not defined(nimhygiene): + {.pragma: inject.} + template `=~` *(s: string, pattern: TRegEx): expr = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: @@ -237,7 +240,7 @@ template `=~` *(s: string, pattern: TRegEx): expr = ## echo("syntax error") ## when not definedInScope(matches): - var matches: array[0..re.maxSubPatterns-1, string] + var matches {.inject.}: array[0..re.maxSubPatterns-1, string] match(s, pattern, matches) # ------------------------- more string handling ------------------------------ diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index efa77199b..e37c072f1 100755 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -845,6 +845,9 @@ proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. ## returns all matching *substrings* of `s` that match `pattern`. ## If it does not match, @[] is returned. accumulateResult(findAll(s, pattern, start)) + +when not defined(nimhygiene): + {.pragma: inject.} template `=~`*(s: string, pattern: TPeg): bool = ## This calls ``match`` with an implicit declared ``matches`` array that @@ -865,7 +868,7 @@ template `=~`*(s: string, pattern: TPeg): bool = ## echo("syntax error") ## when not definedInScope(matches): - var matches: array[0..pegs.maxSubpatterns-1, string] + var matches {.inject.}: array[0..pegs.maxSubpatterns-1, string] match(s, pattern, matches) # ------------------------- more string handling ------------------------------ diff --git a/tests/tester.nim b/tests/tester.nim index 725e76ead..8c9f7f782 100755 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -62,12 +62,15 @@ proc extractSpec(filename: string): string = #echo "warning: file does not contain spec: " & filename result = "" +when not defined(nimhygiene): + {.pragma: inject.} + template parseSpecAux(fillResult: stmt) = var ss = newStringStream(extractSpec(filename)) - var p: TCfgParser + var p {.inject.}: TCfgParser open(p, ss, filename, 1) while true: - var e = next(p) + var e {.inject.} = next(p) case e.kind of cfgEof: break of cfgSectionStart, cfgOption, cfgError: diff --git a/todo.txt b/todo.txt index fadd7fb9e..7ddd2c573 100755 --- a/todo.txt +++ b/todo.txt @@ -1,16 +1,19 @@ version 0.9.0 ============= +- make templates hygienic by default: 'gensym', 'inject' pragmas +- make 'bind' default for templates and introduce 'mixin' +- use ``\`` for comment continuations +- ``final`` should be the default for objects - implement "closure tuple consists of a single 'ref'" optimization - implement for loop transformation for first class iterators -- make templates hygienic by default: 'gensym', 'inject' pragmas - implicit deref for parameter matching -- ``final`` should be the default for objects - optimize genericAssign in the code generator - the lookup rules for generics really are too permissive - fix remaining closure bugs: - - fix evals.nim with closures + - test evals.nim with closures + - what about macros with closures? Bugs |