next steps to hygienic templates

This commit is contained in:
Araq 2012-08-20 08:44:17 +02:00
commit da190876de
17 changed files with 97 additions and 76 deletions

View file

@ -260,6 +260,9 @@ const
# macro or template is immediately expanded # macro or template is immediately expanded
# without considering any possible overloads # without considering any possible overloads
sfDirty* = sfPure
# template is not hygienic (old styled template)
sfAnon* = sfDiscardable sfAnon* = sfDiscardable
# symbol name that was generated by the compiler # symbol name that was generated by the compiler
# the compiler will avoid printing such names # the compiler will avoid printing such names
@ -691,7 +694,8 @@ const
# creator procs: # creator procs:
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym
proc NewType*(kind: TTypeKind, owner: PSym): PType proc NewType*(kind: TTypeKind, owner: PSym): PType
proc newNode*(kind: TNodeKind): PNode proc newNode*(kind: TNodeKind): PNode
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
@ -922,9 +926,8 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
result.sym = t.sym # backend-info should not be copied result.sym = t.sym # backend-info should not be copied
proc copySym(s: PSym, keepId: bool = false): PSym = proc copySym(s: PSym, keepId: bool = false): PSym =
result = newSym(s.kind, s.name, s.owner) result = newSym(s.kind, s.name, s.owner, s.info)
result.ast = nil # BUGFIX; was: s.ast which made problems result.ast = nil # BUGFIX; was: s.ast which made problems
result.info = s.info
result.typ = s.typ result.typ = s.typ
if keepId: if keepId:
result.id = s.id result.id = s.id
@ -939,13 +942,14 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
result.loc = s.loc result.loc = s.loc
result.annex = s.annex # BUGFIX result.annex = s.annex # BUGFIX
proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym): PSym = proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too # generates a symbol and initializes the hash field too
new(result) new(result)
result.Name = Name result.Name = Name
result.Kind = symKind result.Kind = symKind
result.flags = {} result.flags = {}
result.info = UnknownLineInfo() result.info = info
result.options = gOptions result.options = gOptions
result.owner = owner result.owner = owner
result.offset = - 1 result.offset = - 1

View file

@ -254,7 +254,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
var p = newNodeIT(nkExprColonExpr, info, t.sons[i]) var p = newNodeIT(nkExprColonExpr, info, t.sons[i])
var field = if t.n != nil: t.n.sons[i].sym else: newSym( var field = if t.n != nil: t.n.sons[i].sym else: newSym(
skField, getIdent(":tmp" & $i), t.owner) skField, getIdent(":tmp" & $i), t.owner, info)
addSon(p, newSymNode(field, info)) addSon(p, newSymNode(field, info))
addSon(p, getNullValue(t.sons[i], info)) addSon(p, getNullValue(t.sons[i], info))
addSon(result, p) addSon(result, p)
@ -1358,7 +1358,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested) GlobalError(n.info, errTemplateInstantiationTooNested)
inc genSymBaseId #inc genSymBaseId
var s = newStackFrame() var s = newStackFrame()
s.call = n s.call = n
setlen(s.params, 2) setlen(s.params, 2)

View file

@ -11,7 +11,7 @@
import idents, strutils, os, options import idents, strutils, os, options
var gFrontEndId, gBackendId*, genSymBaseId*: int var gFrontEndId, gBackendId*: int
const const
debugIds* = false debugIds* = false
@ -34,9 +34,6 @@ proc backendId*(): int {.inline.} =
result = gBackendId result = gBackendId
inc(gBackendId) inc(gBackendId)
proc genSym*(basename: string): PIdent =
result = getIdent(basename & $genSymBaseId)
proc setId*(id: int) {.inline.} = proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1) gFrontEndId = max(gFrontEndId, id + 1)
@ -66,4 +63,3 @@ proc loadMaxIds*(project: string) =
gFrontEndId = max(gFrontEndId, frontEndId) gFrontEndId = max(gFrontEndId, frontEndId)
gBackEndId = max(gBackEndId, backEndId) gBackEndId = max(gBackEndId, backEndId)
f.close() f.close()

View file

@ -162,7 +162,7 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
result.attachedNode = n result.attachedNode = n
proc addField(tup: PType, s: PSym) = proc addField(tup: PType, s: PSym) =
var field = newSym(skField, s.name, s.owner) var field = newSym(skField, s.name, s.owner, s.info)
let t = skipIntLit(s.typ) let t = skipIntLit(s.typ)
field.typ = t field.typ = t
field.position = sonsLen(tup) field.position = sonsLen(tup)
@ -179,7 +179,7 @@ proc addDep(e, d: PEnv, owner: PSym): PSym =
for x, field in items(e.deps): for x, field in items(e.deps):
if x == d: return field if x == d: return field
var pos = sonsLen(e.tup) var pos = sonsLen(e.tup)
result = newSym(skField, getIdent(upName & $pos), owner) result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
result.typ = newType(tyRef, owner) result.typ = newType(tyRef, owner)
result.position = pos result.position = pos
assert d.tup != nil assert d.tup != nil
@ -220,8 +220,7 @@ proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
#s.typ.callConv == ccClosure #s.typ.callConv == ccClosure
proc addClosureParam(i: PInnerContext, e: PEnv) = proc addClosureParam(i: PInnerContext, e: PEnv) =
var cp = newSym(skParam, getIdent(paramname), i.fn) var cp = newSym(skParam, getIdent(paramname), i.fn, i.fn.info)
cp.info = i.fn.info
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, i.fn) cp.typ = newType(tyRef, i.fn)
rawAddSon(cp.typ, e.tup) rawAddSon(cp.typ, e.tup)
@ -449,9 +448,8 @@ proc addVar*(father, v: PNode) =
proc getClosureVar(o: POuterContext, e: PEnv): PSym = proc getClosureVar(o: POuterContext, e: PEnv): PSym =
if e.closure == nil: if e.closure == nil:
result = newSym(skVar, getIdent(envName), o.fn) result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
incl(result.flags, sfShadowed) incl(result.flags, sfShadowed)
result.info = e.attachedNode.info
result.typ = newType(tyRef, o.fn) result.typ = newType(tyRef, o.fn)
result.typ.rawAddSon(e.tup) result.typ.rawAddSon(e.tup)
e.closure = result e.closure = result
@ -590,8 +588,7 @@ type
tup: PType tup: PType
proc newIterResult(iter: PSym): PSym = proc newIterResult(iter: PSym): PSym =
result = newSym(skResult, getIdent":result", iter) result = newSym(skResult, getIdent":result", iter, iter.info)
result.info = iter.info
result.typ = iter.typ.sons[0] result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
@ -650,15 +647,14 @@ proc liftIterator*(iter: PSym, body: PNode): PNode =
c.tup = newType(tyTuple, iter) c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info) c.tup.n = newNodeI(nkRecList, iter.info)
var cp = newSym(skParam, getIdent(paramname), iter) var cp = newSym(skParam, getIdent(paramname), iter, iter.info)
cp.info = iter.info
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter) cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup) rawAddSon(cp.typ, c.tup)
c.closureParam = cp c.closureParam = cp
addHiddenParam(iter, cp) addHiddenParam(iter, cp)
c.state = newSym(skField, getIdent(":state"), iter) c.state = newSym(skField, getIdent(":state"), iter, iter.info)
c.state.typ = getStateType(iter) c.state.typ = getStateType(iter)
addField(c.tup, c.state) addField(c.tup, c.state)

View file

@ -22,18 +22,14 @@ proc considerAcc*(n: PNode): PIdent =
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n)) of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0]) of 1: result = considerAcc(n.sons[0])
else: else:
if n.len == 2 and n[0].kind == nkIdent and n[0].ident.id == ord(wStar): var id = ""
# XXX find a better way instead of `*x` for 'genSym' for i in 0.. <n.len:
result = genSym(n[1].ident.s) let x = n.sons[i]
else: case x.kind
var id = "" of nkIdent: id.add(x.ident.s)
for i in 0.. <n.len: of nkSym: id.add(x.sym.name.s)
let x = n.sons[i] else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
case x.kind result = getIdent(id)
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id)
else: else:
GlobalError(n.info, errIdentifierExpected, renderTree(n)) GlobalError(n.info, errIdentifierExpected, renderTree(n))
@ -46,8 +42,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerAcc(m) considerAcc(m)
else: else:
getIdent("err:" & renderTree(m)) getIdent("err:" & renderTree(m))
result = newSym(skError, ident, getCurrOwner()) result = newSym(skError, ident, getCurrOwner(), n.info)
result.info = n.info
result.typ = errorType(c) result.typ = errorType(c)
incl(result.flags, sfDiscardable) incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors: # pretend it's imported from some unknown module to prevent cascading errors:

View file

@ -27,7 +27,7 @@ const
wGenSym, wInject} wGenSym, wInject}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject} templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
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, wGenSym, wInject} wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
@ -454,8 +454,7 @@ proc processPragma(c: PContext, n: PNode, i: int) =
elif it.sons[0].kind != nkIdent: invalidPragma(n) elif it.sons[0].kind != nkIdent: invalidPragma(n)
elif it.sons[1].kind != nkIdent: invalidPragma(n) elif it.sons[1].kind != nkIdent: invalidPragma(n)
var userPragma = NewSym(skTemplate, it.sons[1].ident, nil) var userPragma = NewSym(skTemplate, it.sons[1].ident, nil, it.info)
userPragma.info = it.info
var body = newNodeI(nkPragma, n.info) var body = newNodeI(nkPragma, n.info)
for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j]) for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
userPragma.ast = body userPragma.ast = body
@ -488,6 +487,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wImmediate: of wImmediate:
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
else: invalidPragma(it) else: invalidPragma(it)
of wDirty:
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it)
of wImportCpp: of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, sym.name.s)) processImportCpp(sym, getOptionalStr(c, it, sym.name.s))
of wImportObjC: of wImportObjC:

View file

@ -55,8 +55,7 @@ proc isTopLevel(c: PContext): bool {.inline.} =
result = c.tab.tos <= 2 result = c.tab.tos <= 2
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerAcc(n), getCurrOwner()) result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
result.info = n.info
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# like newSymS, but considers gensym'ed symbols # like newSymS, but considers gensym'ed symbols
@ -65,8 +64,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
InternalAssert sfGenSym in result.flags InternalAssert sfGenSym in result.flags
InternalAssert result.kind == kind InternalAssert result.kind == kind
else: else:
result = newSym(kind, considerAcc(n), getCurrOwner()) result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
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

View file

@ -1470,7 +1470,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkTypeOfExpr: of nkTypeOfExpr:
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
typ = makeTypedesc(c, typ) typ = makeTypedesc(c, typ)
var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ) var sym = newSym(skType, getIdent"TypeOfExpr",
typ.owner, n.info).linkTo(typ)
sym.flags.incl(sfAnon) sym.flags.incl(sfAnon)
result = newSymNode(sym, n.info) result = newSymNode(sym, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:

View file

@ -255,7 +255,7 @@ proc semGenericStmt(c: PContext, n: PNode,
flags, toBind) flags, toBind)
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty: if n.sons[paramsPos].sons[0].kind != nkEmpty:
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil)) addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind)
var body: PNode var body: PNode

View file

@ -21,8 +21,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
InternalError(a.info, "instantiateGenericParamList; no symbol") InternalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
var s = newSym(skType, q.name, getCurrOwner()) var s = newSym(skType, q.name, getCurrOwner(), q.info)
s.info = q.info
s.flags = s.flags + {sfUsed, sfFromGeneric} s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(IdTableGet(pt, q.typ)) var t = PType(IdTableGet(pt, q.typ))
if t == nil: if t == nil:

View file

@ -380,7 +380,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true") var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
if trueSymbol == nil: if trueSymbol == nil:
LocalError(n.info, errSystemNeeds, "true") LocalError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner()) trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool) trueSymbol.typ = getSysType(tyBool)
result.add(newSymNode(trueSymbol, n.info)) result.add(newSymNode(trueSymbol, n.info))
@ -620,10 +620,8 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
aa.sons[0].kind == nkObjectTy: aa.sons[0].kind == nkObjectTy:
# give anonymous object a dummy symbol: # give anonymous object a dummy symbol:
assert s.typ.sons[0].sym == nil assert s.typ.sons[0].sym == nil
var anonObj = newSym(skType, getIdent(s.name.s & ":ObjectType"), s.typ.sons[0].sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
getCurrOwner()) getCurrOwner(), s.info)
anonObj.info = s.info
s.typ.sons[0].sym = anonObj
proc SemTypeSection(c: PContext, n: PNode): PNode = proc SemTypeSection(c: PContext, n: PNode): PNode =
typeSectionLeftSidePass(c, n) typeSectionLeftSidePass(c, n)
@ -650,8 +648,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
if t != nil: if t != nil:
var s = newSym(skResult, getIdent"result", getCurrOwner()) var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
s.info = info
s.typ = t s.typ = t
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
addParamOrResult(c, s, owner) addParamOrResult(c, s, owner)
@ -697,8 +694,7 @@ proc semLambda(c: PContext, n: PNode): PNode =
if result != nil: return result if result != nil: return result
result = n result = n
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
var s = newSym(skProc, getIdent":anonymous", getCurrOwner()) var s = newSym(skProc, getIdent":anonymous", getCurrOwner(), n.info)
s.info = n.info
s.ast = n s.ast = n
n.sons[namePos] = newSymNode(s) n.sons[namePos] = newSymNode(s)
pushOwner(s) pushOwner(s)
@ -830,7 +826,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popProcCon(c) popProcCon(c)
else: else:
if s.typ.sons[0] != nil and kind != skIterator: if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil)) addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
var toBind = initIntSet() var toBind = initIntSet()
n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind) n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
fixupInstantiatedSymbols(c, s) fixupInstantiatedSymbols(c, s)

View file

@ -104,9 +104,9 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
illFormedAst(n) illFormedAst(n)
result = n result = n
proc isTemplParam(n: PNode): bool {.inline.} = proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
result = n.kind == nkSym and n.sym.kind == skParam and result = n.kind == nkSym and n.sym.kind == skParam and
n.sym.owner.kind == skTemplate n.sym.owner == c.owner
proc semTemplBody(c: var TemplCtx, n: PNode): PNode proc semTemplBody(c: var TemplCtx, n: PNode): PNode
@ -119,7 +119,7 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
closeScope(c) closeScope(c)
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerAcc(n), c.owner) result = newSym(kind, considerAcc(n), c.owner, n.info)
incl(result.flags, sfGenSym) incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed) incl(result.flags, sfShadowed)
@ -127,7 +127,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym': # locals default to 'gensym':
if n.kind != nkPragmaExpr or symBinding(n.sons[1]) != spInject: if n.kind != nkPragmaExpr or symBinding(n.sons[1]) != spInject:
let ident = getIdentNode(c, n) let ident = getIdentNode(c, n)
if not isTemplParam(ident): if not isTemplParam(c, ident):
let local = newGenSym(k, ident, c) let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local) addPrelimDecl(c.c, local)
replaceIdentBySym(n, newSymNode(local, n.info)) replaceIdentBySym(n, newSymNode(local, n.info))
@ -142,7 +142,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
# routines default to 'inject': # routines default to 'inject':
if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym: if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
let ident = getIdentNode(c, n.sons[namePos]) let ident = getIdentNode(c, n.sons[namePos])
if not isTemplParam(ident): if not isTemplParam(c, ident):
let s = newGenSym(k, ident, c) let s = newGenSym(k, ident, c)
addPrelimDecl(c.c, s) addPrelimDecl(c.c, s)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info) n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
@ -164,6 +164,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let s = QualifiedLookUp(c.c, n, {}) let s = QualifiedLookUp(c.c, n, {})
if s != nil: if s != nil:
if s.owner == c.owner and s.kind == skParam: if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id): elif Contains(c.toBind, s.id):
result = symChoice(c.c, n, s) result = symChoice(c.c, n, s)
@ -287,6 +288,33 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semTemplBody(c, n.sons[i]) result.sons[i] = semTemplBody(c, n.sons[i])
proc semTemplBodyDirty(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)
of nkBind:
result = semTemplBodyDirty(c, n.sons[0])
of nkBindStmt:
result = semBindStmt(c.c, n, c.toBind)
of nkEmpty, nkSym..nkNilLit:
nil
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.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] = semTemplBodyDirty(c, n.sons[i])
proc transformToExpr(n: PNode): PNode = proc transformToExpr(n: PNode): PNode =
var realStmt: int var realStmt: int
result = n result = n
@ -340,7 +368,10 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
ctx.toBind = initIntSet() ctx.toBind = initIntSet()
ctx.c = c ctx.c = c
ctx.owner = s ctx.owner = s
n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos]) if sfDirty in s.flags:
n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
else:
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

View file

@ -622,7 +622,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = genericParams.sons[i].typ result = genericParams.sons[i].typ
break addImplicitGeneric break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner()) var s = newSym(skType, paramTypId, getCurrOwner(), info)
if isAnon: s.flags.incl(sfAnon) if isAnon: s.flags.incl(sfAnon)
s.linkTo(typeClass) s.linkTo(typeClass)
s.position = genericParams.len s.position = genericParams.len

View file

@ -96,8 +96,7 @@ proc getCurrOwner(c: PTransf): PSym =
else: result = c.module else: result = c.module
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c)) result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
result.info = info
result.typ = skipTypes(typ, {tyGenericInst}) result.typ = skipTypes(typ, {tyGenericInst})
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
@ -205,9 +204,8 @@ proc hasContinue(n: PNode): bool =
if hasContinue(n.sons[i]): return true if hasContinue(n.sons[i]): return true
proc newLabel(c: PTransf, n: PNode): PSym = proc newLabel(c: PTransf, n: PNode): PSym =
result = newSym(skLabel, nil, getCurrOwner(c)) result = newSym(skLabel, nil, getCurrOwner(c), n.info)
result.name = getIdent(genPrefix & $result.id) result.name = getIdent(genPrefix & $result.id)
result.info = n.info
proc transformBlock(c: PTransf, n: PNode): PTransNode = proc transformBlock(c: PTransf, n: PNode): PTransNode =
var labl: PSym var labl: PSym

View file

@ -60,7 +60,8 @@ type
wFieldChecks, wFieldChecks,
wWatchPoint, wSubsChar, wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wGensym, wInject, wInheritable, wThreadVar, wEmit, wNoStackFrame, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wNoStackFrame,
wImplicitStatic, wGlobal, wHoist wImplicitStatic, wGlobal, wHoist
wAuto, wBool, wCatch, wChar, wClass, wAuto, wBool, wCatch, wChar, wClass,
@ -138,7 +139,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", "gensym", "inject", "inheritable", "threadvar", "emit", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
"nostackframe", "implicitstatic", "global", "hoist", "nostackframe", "implicitstatic", "global", "hoist",
"auto", "bool", "catch", "char", "class", "auto", "bool", "catch", "char", "class",

View file

@ -2290,6 +2290,9 @@ template doAssert*(cond: bool, msg = "") =
if not cond: if not cond:
raiseAssert(astToStr(cond) & ' ' & msg) raiseAssert(astToStr(cond) & ' ' & msg)
when not defined(nimhygiene):
{.pragma: inject.}
template onFailedAssert*(msg: expr, code: stmt): stmt = template onFailedAssert*(msg: expr, code: stmt): stmt =
## Sets an assertion failure handler that will intercept any assert statements ## Sets an assertion failure handler that will intercept any assert statements
## following `onFailedAssert` in the current lexical scope. ## following `onFailedAssert` in the current lexical scope.
@ -2310,7 +2313,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt =
## assert(...) ## assert(...)
## ##
template raiseAssert(msgIMPL: string): stmt = template raiseAssert(msgIMPL: string): stmt =
let `msg` = msgIMPL let msg {.inject.} = msgIMPL
code code
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =

View file

@ -1,7 +1,8 @@
version 0.9.0 version 0.9.0
============= =============
- make templates hygienic by default: 'gensym', 'inject' pragmas - make templates hygienic by default: 'gensym', 'inject' pragmas;
document 'gensym', 'inject' and 'dirty'
- make 'bind' default for templates and introduce 'mixin' - make 'bind' default for templates and introduce 'mixin'
- use ``\`` for comment continuations - use ``\`` for comment continuations
- ``final`` should be the default for objects - ``final`` should be the default for objects