first steps to make templates hygienic
This commit is contained in:
parent
0cac8d9b6f
commit
5e15dec175
23 changed files with 486 additions and 187 deletions
|
|
@ -234,7 +234,7 @@ type
|
||||||
sfDiscriminant, # field is a discriminant in a record/object
|
sfDiscriminant, # field is a discriminant in a record/object
|
||||||
sfDeprecated, # symbol is deprecated
|
sfDeprecated, # symbol is deprecated
|
||||||
sfError, # usage of symbol should trigger a compile-time error
|
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
|
sfThread, # proc will run as a thread
|
||||||
# variable is a thread variable
|
# variable is a thread variable
|
||||||
sfCompileTime, # proc can be evaluated at compile time
|
sfCompileTime, # proc can be evaluated at compile time
|
||||||
|
|
@ -247,7 +247,7 @@ type
|
||||||
# language; for interfacing with Objective C
|
# language; for interfacing with Objective C
|
||||||
sfDiscardable # returned value may be discarded implicitely
|
sfDiscardable # returned value may be discarded implicitely
|
||||||
sfDestructor # proc is destructor
|
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]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
||||||
|
|
@ -265,9 +265,6 @@ const
|
||||||
# the compiler will avoid printing such names
|
# the compiler will avoid printing such names
|
||||||
# in user messages.
|
# in user messages.
|
||||||
|
|
||||||
sfShadowed* = sfInnerProc
|
|
||||||
# a variable that was shadowed in some inner scope
|
|
||||||
|
|
||||||
sfHoist* = sfVolatile ## proc return value can be hoisted
|
sfHoist* = sfVolatile ## proc return value can be hoisted
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -785,15 +782,6 @@ const # for all kind of hash tables:
|
||||||
GrowthFactor* = 2 # must be power of 2, > 0
|
GrowthFactor* = 2 # must be power of 2, > 0
|
||||||
StartSize* = 8 # 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) =
|
proc copyStrTable(dest: var TStrTable, src: TStrTable) =
|
||||||
dest.counter = src.counter
|
dest.counter = src.counter
|
||||||
if isNil(src.data): return
|
if isNil(src.data): return
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,9 @@ proc SameValue*(a, b: PNode): bool =
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
|
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
|
||||||
else:
|
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 =
|
proc leValue*(a, b: PNode): bool =
|
||||||
# a <= b?
|
# a <= b?
|
||||||
|
|
@ -178,7 +180,10 @@ proc leValue*(a, b: PNode): bool =
|
||||||
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
|
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
|
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 =
|
proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
|
||||||
|
|
@ -225,12 +225,15 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||||
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||||
else: InternalError("ccgmerge: unkown key: " & k)
|
else: InternalError("ccgmerge: unkown key: " & k)
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: inject.}
|
||||||
|
|
||||||
template withCFile(cfilename: string, body: stmt) =
|
template withCFile(cfilename: string, body: stmt) =
|
||||||
var s = LLStreamOpen(cfilename, fmRead)
|
var s = LLStreamOpen(cfilename, fmRead)
|
||||||
if s == nil: return
|
if s == nil: return
|
||||||
var L: TBaseLexer
|
var L {.inject.}: TBaseLexer
|
||||||
openBaseLexer(L, s)
|
openBaseLexer(L, s)
|
||||||
var k = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
|
var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
|
||||||
while true:
|
while true:
|
||||||
skipUntilCmd(L)
|
skipUntilCmd(L)
|
||||||
if ^L.bufpos == '\0': break
|
if ^L.bufpos == '\0': break
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ proc countDefinedSymbols*(): int =
|
||||||
proc InitDefines*() =
|
proc InitDefines*() =
|
||||||
initStrTable(gSymbols)
|
initStrTable(gSymbols)
|
||||||
DefineSymbol("nimrod") # 'nimrod' is always defined
|
DefineSymbol("nimrod") # 'nimrod' is always defined
|
||||||
|
# for bootstrapping purposes and old code:
|
||||||
|
DefineSymbol("nimhygiene")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
case targetCPU
|
case targetCPU
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
import
|
import
|
||||||
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
|
||||||
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
|
||||||
parser, ropes, rodread, idgen, osproc, streams
|
parser, ropes, rodread, idgen, osproc, streams, evaltempl
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
|
|
@ -851,56 +851,6 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
|
||||||
code.stringStartingLine)
|
code.stringStartingLine)
|
||||||
result.typ = newType(tyStmt, c.module)
|
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 =
|
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
|
||||||
## XXX: This should be pretty much guaranteed to be true
|
## XXX: This should be pretty much guaranteed to be true
|
||||||
# by the type traits procs' signatures, but until the
|
# by the type traits procs' signatures, but until the
|
||||||
|
|
@ -964,7 +914,11 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
||||||
|
|
||||||
case expandedSym.kind
|
case expandedSym.kind
|
||||||
of skTemplate:
|
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:
|
of skMacro:
|
||||||
# At this point macroCall.sons[0] is nkSym node.
|
# At this point macroCall.sons[0] is nkSym node.
|
||||||
# To be completely compatible with normal macro invocation,
|
# To be completely compatible with normal macro invocation,
|
||||||
|
|
|
||||||
83
compiler/evaltempl.nim
Normal file
83
compiler/evaltempl.nim
Normal file
|
|
@ -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)
|
||||||
|
|
@ -471,7 +471,8 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
|
||||||
# add assignment statements:
|
# add assignment statements:
|
||||||
for local in scope.capturedVars:
|
for local in scope.capturedVars:
|
||||||
let fieldAccess = indirectAccess(env, local, env.info)
|
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``
|
# add ``env.param = param``
|
||||||
result.add(newAsgnStmt(fieldAccess, newSymNode(local)))
|
result.add(newAsgnStmt(fieldAccess, newSymNode(local)))
|
||||||
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
|
IdNodeTablePut(o.localsToAccess, local, fieldAccess)
|
||||||
|
|
@ -515,7 +516,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
scope.sons[0] = generateClosureCreation(o, env)
|
scope.sons[0] = generateClosureCreation(o, env)
|
||||||
|
|
||||||
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
|
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
|
||||||
if sfByCopy notin local.flags:
|
# if sfByCopy notin local.flags:
|
||||||
result = IdNodeTableGet(o.localsToAccess, local)
|
result = IdNodeTableGet(o.localsToAccess, local)
|
||||||
assert result != nil, "cannot find: " & local.name.s
|
assert result != nil, "cannot find: " & local.name.s
|
||||||
# else it is captured by copy and this means that 'outer' should continue
|
# else it is captured by copy and this means that 'outer' should continue
|
||||||
|
|
|
||||||
|
|
@ -123,19 +123,21 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
msgs.MsgWriteln(tokToStr(tok))
|
msgs.MsgWriteln(tokToStr(tok))
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
of wPutEnv:
|
else:
|
||||||
|
case tok.ident.s.normalize
|
||||||
|
of "putenv":
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
var key = tokToStr(tok)
|
var key = tokToStr(tok)
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
os.putEnv(key, tokToStr(tok))
|
os.putEnv(key, tokToStr(tok))
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
of wPrependEnv:
|
of "prependenv":
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
var key = tokToStr(tok)
|
var key = tokToStr(tok)
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
os.putEnv(key, tokToStr(tok) & os.getenv(key))
|
os.putEnv(key, tokToStr(tok) & os.getenv(key))
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
of wAppendenv:
|
of "appendenv":
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
var key = tokToStr(tok)
|
var key = tokToStr(tok)
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,17 @@ const
|
||||||
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
||||||
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||||
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist}
|
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist,
|
||||||
|
wGenSym, wInject}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas
|
methodPragmas* = procPragmas
|
||||||
templatePragmas* = {wImmediate, wDeprecated, wError}
|
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject}
|
||||||
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
||||||
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc, wError, wDiscardable}
|
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportcpp, wImportobjc, wError, wDiscardable}
|
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
|
||||||
exprPragmas* = {wLine}
|
exprPragmas* = {wLine}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
|
|
@ -46,14 +47,16 @@ const
|
||||||
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame}
|
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
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,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc, wError}
|
wImportcpp, wImportobjc, wError}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
|
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,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportcpp, wImportobjc, wError}
|
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
|
||||||
letPragmas* = varPragmas
|
letPragmas* = varPragmas
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
||||||
wThread}
|
wThread}
|
||||||
|
|
@ -655,9 +658,13 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
incl(sym.typ.flags, tfByRef)
|
incl(sym.typ.flags, tfByRef)
|
||||||
of wByCopy:
|
of wByCopy:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.kind != skType: incl(sym.flags, sfByCopy)
|
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
|
||||||
elif sym.typ == nil: invalidPragma(it)
|
|
||||||
else: incl(sym.typ.flags, tfByCopy)
|
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)
|
of wLine: PragmaLine(c, it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ import
|
||||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
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
|
proc semPass*(): TPass
|
||||||
# implementation
|
# implementation
|
||||||
|
|
@ -57,6 +58,16 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
result = newSym(kind, considerAcc(n), getCurrOwner())
|
result = newSym(kind, considerAcc(n), getCurrOwner())
|
||||||
result.info = n.info
|
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,
|
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
# identifier with visability
|
# identifier with visability
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ proc restoreOldStyleType(n: PNode) =
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(n, s)
|
result = evalTemplate(n, s, getCurrOwner())
|
||||||
if semCheck: result = semAfterMacroCall(c, result, s)
|
if semCheck: result = semAfterMacroCall(c, result, s)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
|
|
@ -1372,7 +1372,9 @@ proc semBlockExpr(c: PContext, n: PNode): PNode =
|
||||||
Inc(c.p.nestedBlockCounter)
|
Inc(c.p.nestedBlockCounter)
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c.tab) # BUGFIX: label is in the scope of block!
|
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.sons[1] = semStmtListExpr(c, n.sons[1])
|
||||||
n.typ = n.sons[1].typ
|
n.typ = n.sons[1].typ
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,15 @@ type
|
||||||
withinBind, withinTypeDesc
|
withinBind, withinTypeDesc
|
||||||
TSemGenericFlags = set[TSemGenericFlag]
|
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,
|
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
toBind: var TIntSet): PNode
|
toBind: var TIntSet): PNode
|
||||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||||
|
|
@ -54,15 +63,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
result = n
|
result = n
|
||||||
else: result = newSymNode(s, n.info)
|
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,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags, toBind: var TIntSet): PNode =
|
flags: TSemGenericFlags, toBind: var TIntSet): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,10 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c.tab) # BUGFIX: label is in the scope of block!
|
openScope(c.tab) # BUGFIX: label is in the scope of block!
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
var labl = newSymS(skLabel, n.sons[0], c)
|
var labl = newSymG(skLabel, n.sons[0], c)
|
||||||
|
if sfGenSym notin labl.flags:
|
||||||
addDecl(c, labl)
|
addDecl(c, labl)
|
||||||
n.sons[0] = newSymNode(labl)
|
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
||||||
suggestSym(n.sons[0], labl)
|
suggestSym(n.sons[0], labl)
|
||||||
n.sons[1] = semStmt(c, n.sons[1])
|
n.sons[1] = semStmt(c, n.sons[1])
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
|
|
@ -284,7 +285,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
Message(a.info, warnEachIdentIsTuple)
|
Message(a.info, warnEachIdentIsTuple)
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var v = semIdentDef(c, a.sons[j], symkind)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
addInterfaceDecl(c, v)
|
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||||
when oKeepVariableNames:
|
when oKeepVariableNames:
|
||||||
if c.InUnrolledContext > 0: v.flags.incl(sfShadowed)
|
if c.InUnrolledContext > 0: v.flags.incl(sfShadowed)
|
||||||
else:
|
else:
|
||||||
|
|
@ -332,7 +333,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
continue
|
continue
|
||||||
v.typ = typ
|
v.typ = typ
|
||||||
v.ast = def # no need to copy
|
v.ast = def # no need to copy
|
||||||
addInterfaceDecl(c, v)
|
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||||
var b = newNodeI(nkConstDef, a.info)
|
var b = newNodeI(nkConstDef, a.info)
|
||||||
addSon(b, newSymNode(v))
|
addSon(b, newSymNode(v))
|
||||||
addSon(b, ast.emptyNode) # no type description
|
addSon(b, ast.emptyNode) # no type description
|
||||||
|
|
@ -422,25 +423,25 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
# and thus no tuple unpacking:
|
# and thus no tuple unpacking:
|
||||||
if iter.kind != tyTuple or length == 3:
|
if iter.kind != tyTuple or length == 3:
|
||||||
if 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)
|
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
||||||
# BUGFIX: don't use `iter` here as that would strip away
|
# BUGFIX: don't use `iter` here as that would strip away
|
||||||
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
|
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
|
||||||
# for an example:
|
# for an example:
|
||||||
v.typ = n.sons[length-2].typ
|
v.typ = n.sons[length-2].typ
|
||||||
n.sons[0] = newSymNode(v)
|
n.sons[0] = newSymNode(v)
|
||||||
addDecl(c, v)
|
if sfGenSym notin v.flags: addDecl(c, v)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errWrongNumberOfVariables)
|
LocalError(n.info, errWrongNumberOfVariables)
|
||||||
elif length-2 != sonsLen(iter):
|
elif length-2 != sonsLen(iter):
|
||||||
LocalError(n.info, errWrongNumberOfVariables)
|
LocalError(n.info, errWrongNumberOfVariables)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, length - 3):
|
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)
|
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
||||||
v.typ = iter.sons[i]
|
v.typ = iter.sons[i]
|
||||||
n.sons[i] = newSymNode(v)
|
n.sons[i] = newSymNode(v)
|
||||||
addDecl(c, v)
|
if sfGenSym notin v.flags: addDecl(c, v)
|
||||||
Inc(c.p.nestedLoopCounter)
|
Inc(c.p.nestedLoopCounter)
|
||||||
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||||
Dec(c.p.nestedLoopCounter)
|
Dec(c.p.nestedLoopCounter)
|
||||||
|
|
@ -539,7 +540,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
if a.sons[0].kind == nkPragmaExpr:
|
if a.sons[0].kind == nkPragmaExpr:
|
||||||
pragma(c, s, a.sons[0].sons[1], typePragmas)
|
pragma(c, s, a.sons[0].sons[1], typePragmas)
|
||||||
# add it here, so that recursive types are possible:
|
# 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)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
|
|
@ -780,7 +781,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
s.typ.callConv = lastOptionEntry(c).defaultCC
|
s.typ.callConv = lastOptionEntry(c).defaultCC
|
||||||
# add it here, so that recursive procs are possible:
|
# add it here, so that recursive procs are possible:
|
||||||
# -2 because we have a scope open for parameters
|
# -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)
|
addInterfaceOverloadableSymAt(c, s, c.tab.tos - 2)
|
||||||
else:
|
else:
|
||||||
addInterfaceDeclAt(c, s, c.tab.tos - 2)
|
addInterfaceDeclAt(c, s, c.tab.tos - 2)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,37 @@
|
||||||
|
|
||||||
# included from sem.nim
|
# 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 =
|
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
var
|
var
|
||||||
a: PSym
|
a: PSym
|
||||||
|
|
@ -20,8 +51,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
inc(i)
|
inc(i)
|
||||||
if i > 1: break
|
if i > 1: break
|
||||||
if i <= 1:
|
if i <= 1:
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
result.info = n.info
|
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
else:
|
else:
|
||||||
# semantic checking requires a type; ``fitNode`` deals with it
|
# semantic checking requires a type; ``fitNode`` deals with it
|
||||||
|
|
@ -30,7 +60,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
a = initOverloadIter(o, c, n)
|
a = initOverloadIter(o, c, n)
|
||||||
while a != nil:
|
while a != nil:
|
||||||
incl(a.flags, sfUsed)
|
incl(a.flags, sfUsed)
|
||||||
addSon(result, newSymNode(a))
|
addSon(result, newSymNode(a, n.info))
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
|
|
||||||
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||||
|
|
@ -46,36 +76,216 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||||
illFormedAst(a)
|
illFormedAst(a)
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
|
||||||
proc resolveTemplateParams(c: PContext, n: PNode, owner: PSym,
|
proc replaceIdentBySym(n: var PNode, s: PNode) =
|
||||||
toBind: var TIntSet): PNode =
|
|
||||||
var s: PSym
|
|
||||||
case n.kind
|
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)
|
||||||
|
|
||||||
|
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:
|
of nkIdent:
|
||||||
result = n
|
result = n
|
||||||
let s = QualifiedLookUp(c, n, {})
|
let s = QualifiedLookUp(c.c, n, {})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
if s.owner == owner and s.kind == skParam:
|
if s.owner == c.owner and s.kind == skParam:
|
||||||
result = newSymNode(s)
|
result = newSymNode(s, n.info)
|
||||||
result.info = n.info
|
of nkAccQuoted, nkSym: result = n
|
||||||
elif Contains(toBind, s.id):
|
else:
|
||||||
result = symChoice(c, n, s)
|
illFormedAst(n)
|
||||||
|
|
||||||
of nkEmpty, nkSym..nkNilLit: # atom
|
|
||||||
result = 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:
|
of nkBind:
|
||||||
result = resolveTemplateParams(c, n.sons[0], owner, toBind)
|
result = semTemplBody(c, n.sons[0])
|
||||||
of nkBindStmt:
|
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:
|
else:
|
||||||
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
||||||
# so we use the generic code for nkDotExpr too
|
# so we use the generic code for nkDotExpr too
|
||||||
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
||||||
let s = QualifiedLookUp(c, n, {})
|
let s = QualifiedLookUp(c.c, n, {})
|
||||||
if s != nil and Contains(toBind, s.id):
|
if s != nil and Contains(c.toBind, s.id):
|
||||||
return symChoice(c, n, s)
|
return symChoice(c.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], owner, toBind)
|
result.sons[i] = semTemplBody(c, n.sons[i])
|
||||||
|
|
||||||
proc transformToExpr(n: PNode): PNode =
|
proc transformToExpr(n: PNode): PNode =
|
||||||
var realStmt: int
|
var realStmt: int
|
||||||
|
|
@ -94,7 +304,7 @@ proc transformToExpr(n: PNode): PNode =
|
||||||
else: n.kind = nkStmtListExpr
|
else: n.kind = nkStmtListExpr
|
||||||
of nkBlockStmt:
|
of nkBlockStmt:
|
||||||
n.kind = nkBlockExpr
|
n.kind = nkBlockExpr
|
||||||
#nkIfStmt: n.kind := nkIfExpr; // this is not correct!
|
#nkIfStmt: n.kind = nkIfExpr // this is not correct!
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
|
@ -108,7 +318,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
# check parameter list:
|
# check parameter list:
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
n.sons[namePos] = newSymNode(s)
|
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
pragma(c, s, n.sons[pragmasPos], templatePragmas)
|
pragma(c, s, n.sons[pragmasPos], templatePragmas)
|
||||||
# check that no generic parameters exist:
|
# check that no generic parameters exist:
|
||||||
|
|
@ -126,8 +336,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
# use ``stmt`` as implicit result type
|
# use ``stmt`` as implicit result type
|
||||||
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 ctx: TemplCtx
|
||||||
n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], s, toBind)
|
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}:
|
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
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
incl(e.flags, sfExported) # BUGFIX
|
incl(e.flags, sfExported) # BUGFIX
|
||||||
StrTableAdd(c.module.tab, e) # BUGFIX
|
StrTableAdd(c.module.tab, e) # BUGFIX
|
||||||
addSon(result.n, newSymNode(e))
|
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)
|
inc(counter)
|
||||||
|
|
||||||
proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
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:
|
if a.sons[length - 1].kind != nkEmpty:
|
||||||
LocalError(a.sons[length - 1].info, errInitHereNotAllowed)
|
LocalError(a.sons[length - 1].info, errInitHereNotAllowed)
|
||||||
for j in countup(0, length - 3):
|
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.typ = typ
|
||||||
field.position = counter
|
field.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
|
|
@ -279,7 +279,9 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
# identifier with visibility
|
# identifier with visibility
|
||||||
if n.kind == nkPostfix:
|
if n.kind == nkPostfix:
|
||||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
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
|
var v = n.sons[0].ident
|
||||||
if sfExported in allowed and v.id == ord(wStar):
|
if sfExported in allowed and v.id == ord(wStar):
|
||||||
incl(result.flags, sfExported)
|
incl(result.flags, sfExported)
|
||||||
|
|
@ -288,7 +290,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
else:
|
else:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
else:
|
else:
|
||||||
result = newSymS(kind, n, c)
|
result = newSymG(kind, n, c)
|
||||||
|
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym =
|
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)
|
typ = semTypeNode(c, n.sons[length-2], nil)
|
||||||
for i in countup(0, sonsLen(n)-3):
|
for i in countup(0, sonsLen(n)-3):
|
||||||
var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
|
var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
|
||||||
|
suggestSym(n.sons[i], f)
|
||||||
f.typ = typ
|
f.typ = typ
|
||||||
f.position = pos
|
f.position = pos
|
||||||
if (rectype != nil) and ({sfImportc, sfExportc} * rectype.flags != {}) and
|
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"
|
let nn = getSysSym"PNimrodNode"
|
||||||
var a = copySym(param)
|
var a = copySym(param)
|
||||||
a.typ = nn.typ
|
a.typ = nn.typ
|
||||||
addDecl(c, a)
|
if sfGenSym notin a.flags: addDecl(c, a)
|
||||||
else:
|
else:
|
||||||
addDecl(c, param)
|
if sfGenSym notin param.flags: addDecl(c, param)
|
||||||
|
|
||||||
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
||||||
tuple[typ: PType, id: PIdent] =
|
tuple[typ: PType, id: PIdent] =
|
||||||
|
|
@ -672,7 +675,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
|
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
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,
|
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
|
||||||
arg.info).skipIntLit
|
arg.info).skipIntLit
|
||||||
arg.typ = finalType
|
arg.typ = finalType
|
||||||
|
|
@ -711,7 +714,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
Inc(c.p.nestedBlockCounter)
|
Inc(c.p.nestedBlockCounter)
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c.tab)
|
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))
|
addDecl(c, newSymS(skLabel, n.sons[0], c))
|
||||||
result = semStmtListType(c, n.sons[1], prev)
|
result = semStmtListType(c, n.sons[1], prev)
|
||||||
n.sons[1].typ = result
|
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 =
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
if n.kind != nkGenericParams:
|
if n.kind != nkGenericParams:
|
||||||
InternalError(n.info, "semGenericParamList")
|
illFormedAst(n)
|
||||||
return
|
return
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
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):
|
for j in countup(0, L-3):
|
||||||
var s: PSym
|
var s: PSym
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
s = newSymS(skType, a.sons[j], c)
|
s = newSymG(skType, a.sons[j], c)
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
s.typ = newTypeS(tyGenericParam, c)
|
||||||
else:
|
else:
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
s = newSymS(skType, a.sons[j], c)
|
s = newSymG(skType, a.sons[j], c)
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
s.typ = newTypeS(tyGenericParam, c)
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
#echo "GENERIC EXPR ", a.info.toFileLineCol
|
#echo "GENERIC EXPR ", a.info.toFileLineCol
|
||||||
# not a type param, but an expression
|
# not a type param, but an expression
|
||||||
# proc foo[x: expr](bar: int) what is this?
|
# 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
|
s.typ = typ
|
||||||
else:
|
else:
|
||||||
# This handles cases like proc foo[t: tuple]
|
# This handles cases like proc foo[t: tuple]
|
||||||
# XXX: we want to turn that into a type class
|
# 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
|
s.typ = typ
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
s.typ.sym = s
|
s.typ.sym = s
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = i
|
s.position = i
|
||||||
addSon(result, newSymNode(s))
|
addSon(result, newSymNode(s))
|
||||||
addDecl(c, s)
|
if sfGenSym notin s.flags: addDecl(c, s)
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,13 @@ proc suggestField(c: PContext, s: PSym, outputs: var int) =
|
||||||
OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
|
OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
|
||||||
inc outputs
|
inc outputs
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: inject.}
|
||||||
|
|
||||||
template wholeSymTab(cond, section: expr) {.immediate.} =
|
template wholeSymTab(cond, section: expr) {.immediate.} =
|
||||||
for i in countdown(c.tab.tos-1, 0):
|
for i in countdown(c.tab.tos-1, 0):
|
||||||
for it in items(c.tab.stack[i]):
|
for item in items(c.tab.stack[i]):
|
||||||
|
let it {.inject.} = item
|
||||||
if cond:
|
if cond:
|
||||||
OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
|
OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
|
||||||
inc outputs
|
inc outputs
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,13 @@ proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType =
|
||||||
var marker = InitIntSet()
|
var marker = InitIntSet()
|
||||||
result = mutateTypeAux(marker, t, iter, closure)
|
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 =
|
proc rangeToStr(n: PNode): string =
|
||||||
assert(n.kind == nkRange)
|
assert(n.kind == nkRange)
|
||||||
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
|
result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ type
|
||||||
wFieldChecks,
|
wFieldChecks,
|
||||||
wWatchPoint, wSubsChar,
|
wWatchPoint, wSubsChar,
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
||||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame,
|
wWrite, wGensym, wInject, wInheritable, wThreadVar, wEmit, wNoStackFrame,
|
||||||
wImplicitStatic, wGlobal, wHoist
|
wImplicitStatic, wGlobal, wHoist
|
||||||
|
|
||||||
wAuto, wBool, wCatch, wChar, wClass,
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
|
|
@ -138,7 +138,7 @@ const
|
||||||
"passc", "passl", "borrow", "discardable", "fieldchecks",
|
"passc", "passl", "borrow", "discardable", "fieldchecks",
|
||||||
"watchpoint",
|
"watchpoint",
|
||||||
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||||
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
"write", "gensym", "inject", "inheritable", "threadvar", "emit",
|
||||||
"nostackframe", "implicitstatic", "global", "hoist",
|
"nostackframe", "implicitstatic", "global", "hoist",
|
||||||
|
|
||||||
"auto", "bool", "catch", "char", "class",
|
"auto", "bool", "catch", "char", "class",
|
||||||
|
|
|
||||||
|
|
@ -908,7 +908,7 @@ converts the list of arguments to an array implicitely:
|
||||||
write(f, "\n")
|
write(f, "\n")
|
||||||
|
|
||||||
myWriteln(stdout, "abc", "def", "xyz")
|
myWriteln(stdout, "abc", "def", "xyz")
|
||||||
# is transformed by the compiler to:
|
# is transformed to:
|
||||||
myWriteln(stdout, ["abc", "def", "xyz"])
|
myWriteln(stdout, ["abc", "def", "xyz"])
|
||||||
|
|
||||||
This transformation is only done if the varargs parameter is the
|
This transformation is only done if the varargs parameter is the
|
||||||
|
|
@ -922,7 +922,7 @@ type conversions in this context:
|
||||||
write(f, "\n")
|
write(f, "\n")
|
||||||
|
|
||||||
myWriteln(stdout, 123, "abc", 4.0)
|
myWriteln(stdout, 123, "abc", 4.0)
|
||||||
# is transformed by the compiler to:
|
# is transformed to:
|
||||||
myWriteln(stdout, [$123, $"def", $4.0])
|
myWriteln(stdout, [$123, $"def", $4.0])
|
||||||
|
|
||||||
In this example ``$`` is applied to any argument that is passed to the
|
In this example ``$`` is applied to any argument that is passed to the
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,9 @@ proc findAll*(s: string, pattern: TRegEx, start = 0): seq[string] =
|
||||||
## If it does not match, @[] is returned.
|
## If it does not match, @[] is returned.
|
||||||
accumulateResult(findAll(s, pattern, start))
|
accumulateResult(findAll(s, pattern, start))
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: inject.}
|
||||||
|
|
||||||
template `=~` *(s: string, pattern: TRegEx): expr =
|
template `=~` *(s: string, pattern: TRegEx): expr =
|
||||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||||
## can be used in the scope of the ``=~`` call:
|
## can be used in the scope of the ``=~`` call:
|
||||||
|
|
@ -237,7 +240,7 @@ template `=~` *(s: string, pattern: TRegEx): expr =
|
||||||
## echo("syntax error")
|
## echo("syntax error")
|
||||||
##
|
##
|
||||||
when not definedInScope(matches):
|
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)
|
match(s, pattern, matches)
|
||||||
|
|
||||||
# ------------------------- more string handling ------------------------------
|
# ------------------------- more string handling ------------------------------
|
||||||
|
|
|
||||||
|
|
@ -846,6 +846,9 @@ proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
|
||||||
## If it does not match, @[] is returned.
|
## If it does not match, @[] is returned.
|
||||||
accumulateResult(findAll(s, pattern, start))
|
accumulateResult(findAll(s, pattern, start))
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: inject.}
|
||||||
|
|
||||||
template `=~`*(s: string, pattern: TPeg): bool =
|
template `=~`*(s: string, pattern: TPeg): bool =
|
||||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||||
## can be used in the scope of the ``=~`` call:
|
## can be used in the scope of the ``=~`` call:
|
||||||
|
|
@ -865,7 +868,7 @@ template `=~`*(s: string, pattern: TPeg): bool =
|
||||||
## echo("syntax error")
|
## echo("syntax error")
|
||||||
##
|
##
|
||||||
when not definedInScope(matches):
|
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)
|
match(s, pattern, matches)
|
||||||
|
|
||||||
# ------------------------- more string handling ------------------------------
|
# ------------------------- more string handling ------------------------------
|
||||||
|
|
|
||||||
|
|
@ -62,12 +62,15 @@ proc extractSpec(filename: string): string =
|
||||||
#echo "warning: file does not contain spec: " & filename
|
#echo "warning: file does not contain spec: " & filename
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: inject.}
|
||||||
|
|
||||||
template parseSpecAux(fillResult: stmt) =
|
template parseSpecAux(fillResult: stmt) =
|
||||||
var ss = newStringStream(extractSpec(filename))
|
var ss = newStringStream(extractSpec(filename))
|
||||||
var p: TCfgParser
|
var p {.inject.}: TCfgParser
|
||||||
open(p, ss, filename, 1)
|
open(p, ss, filename, 1)
|
||||||
while true:
|
while true:
|
||||||
var e = next(p)
|
var e {.inject.} = next(p)
|
||||||
case e.kind
|
case e.kind
|
||||||
of cfgEof: break
|
of cfgEof: break
|
||||||
of cfgSectionStart, cfgOption, cfgError:
|
of cfgSectionStart, cfgOption, cfgError:
|
||||||
|
|
|
||||||
9
todo.txt
9
todo.txt
|
|
@ -1,16 +1,19 @@
|
||||||
version 0.9.0
|
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 "closure tuple consists of a single 'ref'" optimization
|
||||||
- implement for loop transformation for first class iterators
|
- implement for loop transformation for first class iterators
|
||||||
- make templates hygienic by default: 'gensym', 'inject' pragmas
|
|
||||||
|
|
||||||
- implicit deref for parameter matching
|
- implicit deref for parameter matching
|
||||||
- ``final`` should be the default for objects
|
|
||||||
- optimize genericAssign in the code generator
|
- optimize genericAssign in the code generator
|
||||||
- the lookup rules for generics really are too permissive
|
- the lookup rules for generics really are too permissive
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
- fix evals.nim with closures
|
- test evals.nim with closures
|
||||||
|
- what about macros with closures?
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue