diff options
author | Araq <rumpf_a@web.de> | 2012-09-08 15:43:21 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-09-08 15:43:21 +0200 |
commit | b64eeeb4303953f9fe1135cb9c3c61e23ec55afa (patch) | |
tree | 0f994de4a02afd9bed14dafcac24a3dd2df99d0d /compiler | |
parent | 355ae07b8f3362af4e90770477d344dcd2fef594 (diff) | |
download | Nim-b64eeeb4303953f9fe1135cb9c3c61e23ec55afa.tar.gz |
term rewriting improvements
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/hlo.nim | 91 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 59 | ||||
-rw-r--r-- | compiler/patterns.nim | 84 | ||||
-rwxr-xr-x | compiler/sem.nim | 51 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 45 | ||||
-rwxr-xr-x | compiler/seminst.nim | 1 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 8 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 22 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 13 |
9 files changed, 238 insertions, 136 deletions
diff --git a/compiler/hlo.nim b/compiler/hlo.nim new file mode 100644 index 000000000..152fd4414 --- /dev/null +++ b/compiler/hlo.nim @@ -0,0 +1,91 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This include implements the high level optimization pass. + +proc hlo(c: PContext, n: PNode): PNode + +proc evalPattern(c: PContext, n, orig: PNode): PNode = + InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym + # we need to ensure that the resulting AST is semchecked. However, it's + # aweful to semcheck before macro invocation, so we don't and treat + # templates and macros as immediate in this context. + var rule: string + if optHints in gOptions and hintPattern in gNotes: + rule = renderTree(n, {renderNoComments}) + let s = n.sons[0].sym + case s.kind + of skMacro: + result = semMacroExpr(c, n, orig, s) + of skTemplate: + result = semTemplateExpr(c, n, s) + else: + result = semDirectOp(c, n, {}) + if optHints in gOptions and hintPattern in gNotes: + Message(orig.info, hintPattern, rule & " --> '" & + renderTree(result, {renderNoComments}) & "'") + # check the resulting AST for optimization rules again: + result = hlo(c, result) + +proc applyPatterns(c: PContext, n: PNode): PNode = + result = n + # we apply the last pattern first, so that pattern overriding is possible; + # however the resulting AST would better not trigger the old rule then + # anymore ;-) + for i in countdown(<c.patterns.len, 0): + let pattern = c.patterns[i] + if not isNil(pattern): + let x = applyRule(c, pattern, result) + if not isNil(x): + assert x.kind in {nkStmtList, nkCall} + inc(evalTemplateCounter) + if evalTemplateCounter > 100: + GlobalError(n.info, errTemplateInstantiationTooNested) + # deactivate this pattern: + c.patterns[i] = nil + if x.kind == nkStmtList: + assert x.len == 3 + x.sons[1] = evalPattern(c, x.sons[1], result) + result = flattenStmts(x) + else: + result = evalPattern(c, x, result) + dec(evalTemplateCounter) + # activate this pattern again: + c.patterns[i] = pattern + +proc hlo(c: PContext, n: PNode): PNode = + case n.kind + of nkMacroDef, nkTemplateDef, procDefs: + # already processed (special cases in semstmts.nim) + result = n + else: + result = applyPatterns(c, n) + if result == n: + # no optimization applied, try subtrees: + for i in 0 .. < safeLen(result): + let a = result.sons[i] + let h = hlo(c, a) + if h != a: result.sons[i] = h + else: + # perform type checking, so that the replacement still fits: + if n.typ == nil and (result.typ == nil or + result.typ.kind in {tyStmt, tyEmpty}): + nil + else: + result = fitNode(c, n.typ, result) + +proc hloBody(c: PContext, n: PNode): PNode = + # fast exit: + if c.patterns.len == 0 or optPatterns notin gOptions: return n + result = hlo(c, n) + +proc hloStmt(c: PContext, n: PNode): PNode = + # fast exit: + if c.patterns.len == 0 or optPatterns notin gOptions: return n + result = hlo(c, n) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 44e41f7a0..ee1f69818 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -18,7 +18,7 @@ import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg type TAliasRequest* = enum # first byte of the bytecode determines alias checking aqNone = 1, # no alias analysis requested - aqShouldAlias, # with what? + aqShouldAlias, # with some other param aqNoAlias # request noalias TOpcode = enum ppEof = 1, # end of compiled pattern @@ -32,6 +32,8 @@ type ppCall, ppSymKind, ppNodeKind, + ppLValue, + ppLocal, ppSideEffect, ppNoSideEffect TPatternCode = string @@ -87,6 +89,8 @@ proc compileConstraints(p: PNode, result: var TPatternCode) = of "call": result.add(ppCall) of "alias": result[0] = chr(aqShouldAlias.ord) of "noalias": result[0] = chr(aqNoAlias.ord) + of "lvalue": result.add(ppLValue) + of "local": result.add(ppLocal) of "sideeffect": result.add(ppSideEffect) of "nosideeffect": result.add(ppNoSideEffect) else: @@ -144,8 +148,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis = # indirect call without side effects: result = seNoSideEffect else: - # indirect call: we don't know - result = seUnknown + # indirect call: assume side effect: + return seSideEffect # we need to check n[0] too: (FwithSideEffectButReturnsProcWithout)(args) for i in 0 .. <n.len: let ret = checkForSideEffects(n.sons[i]) @@ -162,6 +166,53 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis = elif ret == seUnknown and result == seNoSideEffect: result = seUnknown +type + TAssignableResult* = enum + arNone, # no l-value and no discriminant + arLValue, # is an l-value + arLocalLValue, # is an l-value, but local var; must not escape + # its stack frame! + arDiscriminant # is a discriminant + +proc isAssignable*(owner: PSym, n: PNode): TAssignableResult = + ## 'owner' can be nil! + result = arNone + case n.kind + of nkSym: + # don't list 'skLet' here: + if n.sym.kind in {skVar, skResult, skTemp}: + if owner != nil and owner.id == n.sym.owner.id and + sfGlobal notin n.sym.flags: + result = arLocalLValue + else: + result = arLValue + of nkDotExpr: + if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: + result = arLValue + else: + result = isAssignable(owner, n.sons[0]) + if result != arNone and sfDiscriminant in n.sons[1].sym.flags: + result = arDiscriminant + of nkBracketExpr: + if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: + result = arLValue + else: + result = isAssignable(owner, n.sons[0]) + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + # Object and tuple conversions are still addressable, so we skip them + # XXX why is 'tyOpenArray' allowed here? + if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: + result = isAssignable(owner, n.sons[1]) + elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct): + # types that are equal modulo distinction preserve l-value: + result = isAssignable(owner, n.sons[1]) + of nkHiddenDeref, nkDerefExpr: + result = arLValue + of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: + result = isAssignable(owner, n.sons[0]) + else: + nil + proc matchNodeKinds*(p, n: PNode): bool = # matches the parameter constraint 'p' against the concrete AST 'n'. # Efficiency matters here. @@ -199,6 +250,8 @@ proc matchNodeKinds*(p, n: PNode): bool = let kind = TNodeKind(code[pc+1]) push n.kind == kind inc pc + of ppLValue: push isAssignable(nil, n) in {arLValue, arLocalLValue} + of ppLocal: push isAssignable(nil, n) == arLocalLValue of ppSideEffect: push checkForSideEffects(n) == seSideEffect of ppNoSideEffect: push checkForSideEffects(n) != seSideEffect inc pc diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 402283b76..1a2f9b761 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -86,24 +86,38 @@ proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool = IdNodeTablePutLazy(c.mapping, param, n) result = true -proc matchNested(c: PPatternContext, p, n: PNode): bool = - # match ``op*param`` +proc gather(c: PPatternContext, param: PSym, n: PNode) = + var pp = IdNodeTableGetLazy(c.mapping, param) + if pp != nil and pp.kind == nkArgList: + pp.add(n) + else: + pp = newNodeI(nkArgList, n.info, 1) + pp.sons[0] = n + IdNodeTablePutLazy(c.mapping, param, pp) - proc matchStarAux(c: PPatternContext, op, n, arglist: PNode) = - if n.kind in nkCallKinds and matches(c, op, n.sons[0]): +proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool = + # match ``op * param`` or ``op *| param`` + proc matchStarAux(c: PPatternContext, op, n, arglist: PNode, + rpn: bool): bool = + result = true + if n.kind in nkCallKinds and matches(c, op.sons[1], n.sons[0]): for i in 1..sonsLen(n)-1: - matchStarAux(c, op, n[i], arglist) + if not matchStarAux(c, op, n[i], arglist, rpn): return false + if rpn: arglist.add(n.sons[0]) elif n.kind == nkHiddenStdConv and n.sons[1].kind == nkBracket: let n = n.sons[1] - for i in 0.. <n.len: matchStarAux(c, op, n[i], arglist) - else: + for i in 0.. <n.len: + if not matchStarAux(c, op, n[i], arglist, rpn): return false + elif checkTypes(c, p.sons[2].sym, n): add(arglist, n) + else: + result = false if n.kind notin nkCallKinds: return false if matches(c, p.sons[1], n.sons[0]): var arglist = newNodeI(nkArgList, n.info) - matchStarAux(c, p.sons[1], n, arglist) - result = bindOrCheck(c, p.sons[2].sym, arglist) + if matchStarAux(c, p, n, arglist, rpn): + result = bindOrCheck(c, p.sons[2].sym, arglist) proc matches(c: PPatternContext, p, n: PNode): bool = # hidden conversions (?) @@ -122,15 +136,21 @@ proc matches(c: PPatternContext, p, n: PNode): bool = let opr = p.sons[0].ident.s case opr of "|": result = matchChoice(c, p, n) - of "*": result = matchNested(c, p, n) + of "*": result = matchNested(c, p, n, rpn=false) + of "*|": result = matchNested(c, p, n, rpn=true) of "~": result = not matches(c, p.sons[1], n) else: InternalError(p.info, "invalid pattern") # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) = # add(a, b) elif p.kind == nkCurlyExpr: - assert isPatternParam(c, p.sons[1]) - if matches(c, p.sons[0], n): - result = bindOrCheck(c, p.sons[1].sym, n) + if p.sons[1].kind == nkPrefix: + if matches(c, p.sons[0], n): + gather(c, p.sons[1].sons[1].sym, n) + result = true + else: + assert isPatternParam(c, p.sons[1]) + if matches(c, p.sons[0], n): + result = bindOrCheck(c, p.sons[1].sym, n) elif sameKinds(p, n): case p.kind of nkSym: result = p.sym == n.sym @@ -196,7 +216,17 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode = elif matches(c, p, n): result = n -# writeln(X, a); writeln(X, b); --> writeln(X, a, b) +proc aliasAnalysisRequested(params: PNode): bool = + if params.len >= 2: + for i in 1 .. < params.len: + let param = params.sons[i].sym + if whichAlias(param) != aqNone: return true + +proc addToArgList(result, n: PNode) = + if n.typ != nil and n.typ.kind != tyStmt: + if n.kind != nkArgList: result.add(n) + else: + for i in 0 .. <n.len: result.add(n.sons[i]) proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = ## returns a tree to semcheck if the rule triggered; nil otherwise @@ -211,36 +241,40 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(s, n.info)) let params = s.typ.n + let requiresAA = aliasAnalysisRequested(params) + var args: PNode + if requiresAA: + args = newNodeI(nkArgList, n.info) for i in 1 .. < params.len: let param = params.sons[i].sym let x = IdNodeTableGetLazy(ctx.mapping, param) # couldn't bind parameter: if isNil(x): return nil result.add(x) + if requiresAA: addToArgList(args, n) # perform alias analysis here: - if params.len >= 2: + if requiresAA: for i in 1 .. < params.len: + var rs = result.sons[i] let param = params.sons[i].sym case whichAlias(param) of aqNone: nil of aqShouldAlias: # it suffices that it aliases for sure with *some* other param: var ok = false - for j in 1 .. < result.len: - if j != i and result.sons[j].typ != nil: - if aliases.isPartOf(result[i], result[j]) == arYes: - ok = true - break + for arg in items(args): + if arg != rs and aliases.isPartOf(rs, arg) == arYes: + ok = true + break # constraint not fullfilled: if not ok: return nil of aqNoAlias: # it MUST not alias with any other param: var ok = true - for j in 1 .. < result.len: - if j != i and result.sons[j].typ != nil: - if aliases.isPartOf(result[i], result[j]) != arNo: - ok = false - break + for arg in items(args): + if arg != rs and aliases.isPartOf(rs, arg) != arNo: + ok = false + break # constraint not fullfilled: if not ok: return nil diff --git a/compiler/sem.nim b/compiler/sem.nim index 24bee4a22..0f2627998 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -103,55 +103,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = return n result = evalTypedExpr(c, e) -proc evalPattern(c: PContext, n: PNode, info: TLineInfo): PNode = - InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym - # we need to ensure that the resulting AST is semchecked. However, it's - # aweful to semcheck before macro invocation, so we don't and treat - # templates and macros as immediate in this context. - var rule: string - if optHints in gOptions and hintPattern in gNotes: - rule = renderTree(n, {renderNoComments}) - let s = n.sons[0].sym - case s.kind - of skMacro: - result = semMacroExpr(c, n, n, s) - of skTemplate: - result = semTemplateExpr(c, n, s) - else: - result = semDirectOp(c, n, {}) - if optHints in gOptions and hintPattern in gNotes: - Message(info, hintPattern, rule & " --> '" & - renderTree(result, {renderNoComments}) & "'") - -proc applyPatterns(c: PContext, n: PNode): PNode = - # fast exit: - if c.patterns.len == 0 or optPatterns notin gOptions: return n - result = n - # we apply the last pattern first, so that pattern overriding is possible; - # however the resulting AST would better not trigger the old rule then - # anymore ;-) - for i in countdown(<c.patterns.len, 0): - let pattern = c.patterns[i] - if not isNil(pattern): - let x = applyRule(c, pattern, result) - if not isNil(x): - assert x.kind in {nkStmtList, nkCall} - inc(evalTemplateCounter) - if evalTemplateCounter > 100: - GlobalError(n.info, errTemplateInstantiationTooNested) - # deactivate this pattern: - c.patterns[i] = nil - if x.kind == nkStmtList: - assert x.len == 3 - x.sons[1] = evalPattern(c, x.sons[1], n.info) - result = flattenStmts(x) - else: - result = evalPattern(c, x, n.info) - dec(evalTemplateCounter) - # activate this pattern again: - c.patterns[i] = pattern - -include seminst, semcall +include hlo, seminst, semcall proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = inc(evalTemplateCounter) @@ -251,6 +203,7 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = # a generic has been added to `a`: if result.kind != nkEmpty: addSon(a, result) result = a + result = hloStmt(c, result) result = transformStmt(c.module, result) proc RecoverContext(c: PContext) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fe698bffb..fc3ea1820 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -438,51 +438,9 @@ proc skipObjConv(n: PNode): PNode = result = n of nkObjUpConv, nkObjDownConv: result = n.sons[0] else: result = n - -type - TAssignableResult = enum - arNone, # no l-value and no discriminant - arLValue, # is an l-value - arLocalLValue, # is an l-value, but local var; must not escape - # its stack frame! - arDiscriminant # is a discriminant proc isAssignable(c: PContext, n: PNode): TAssignableResult = - result = arNone - case n.kind - of nkSym: - # don't list 'skLet' here: - if n.sym.kind in {skVar, skResult, skTemp}: - if c.p.owner.id == n.sym.owner.id and sfGlobal notin n.sym.flags: - result = arLocalLValue - else: - result = arLValue - of nkDotExpr: - if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: - result = arLValue - else: - result = isAssignable(c, n.sons[0]) - if result != arNone and sfDiscriminant in n.sons[1].sym.flags: - result = arDiscriminant - of nkBracketExpr: - if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: - result = arLValue - else: - result = isAssignable(c, n.sons[0]) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - # Object and tuple conversions are still addressable, so we skip them - # XXX why is 'tyOpenArray' allowed here? - if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: - result = isAssignable(c, n.sons[1]) - elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct): - # types that are equal modulo distinction preserve l-value: - result = isAssignable(c, n.sons[1]) - of nkHiddenDeref, nkDerefExpr: - result = arLValue - of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = isAssignable(c, n.sons[0]) - else: - nil + result = parampatterns.isAssignable(c.p.owner, n) proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = if n.kind == nkHiddenDeref: @@ -1598,4 +1556,3 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = LocalError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) incl(result.flags, nfSem) - result = applyPatterns(c, result) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 2d1f68d5d..a03f62075 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -78,6 +78,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) = addResult(c, result.typ.sons[0], n.info, result.kind) addResultNode(c, n) var b = semStmtScope(c, n.sons[bodyPos]) + b = hloBody(c, b) n.sons[bodyPos] = transformBody(c.module, b, result) #echo "code instantiated ", result.name.s excl(result.flags, sfForward) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 04766ae58..4b79291e6 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -714,7 +714,7 @@ proc semLambda(c: PContext, n: PNode): PNode = LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) pushProcCon(c, s) addResult(c, s.typ.sons[0], n.info, skProc) - let semBody = semStmtScope(c, n.sons[bodyPos]) + let semBody = hloBody(c, semStmtScope(c, n.sons[bodyPos])) n.sons[bodyPos] = transformBody(c.module, semBody, s) addResultNode(c, n) popProcCon(c) @@ -772,7 +772,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, rawAddSon(s.typ, nil) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) - c.patterns.add(s) var proto = SearchForProc(c, s, c.tab.tos-2) # -2 because we have a scope # open for parameters @@ -821,7 +820,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, addResult(c, s.typ.sons[0], n.info, kind) if sfImportc notin s.flags: # no semantic checking for importc: - let semBody = semStmtScope(c, n.sons[bodyPos]) + let semBody = hloBody(c, semStmtScope(c, n.sons[bodyPos])) # unfortunately we cannot skip this step when in 'system.compiles' # context as it may even be evaluated in 'system.compiles': n.sons[bodyPos] = transformBody(c.module, semBody, s) @@ -844,6 +843,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, sideEffectsCheck(c, s) closeScope(c.tab) # close scope for parameters popOwner() + if n.sons[patternPos].kind != nkEmpty: + c.patterns.add(s) proc semIterator(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skIterator, iteratorPragmas) @@ -1222,7 +1223,6 @@ proc SemStmt(c: PContext, n: PNode): PNode = result = emptyNode else: incl(result.flags, nfSem) - result = applyPatterns(c, result) proc semStmtScope(c: PContext, n: PNode): PNode = openScope(c.tab) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 0887e1789..fa15f8ede 100755 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -392,8 +392,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0])) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) - c.patterns.add(s) - var ctx: TemplCtx ctx.toBind = initIntSet() ctx.c = c @@ -417,6 +415,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = addInterfaceOverloadableSymAt(c, s, curScope) else: SymTabReplace(c.tab.stack[curScope], proto, s) + if n.sons[patternPos].kind != nkEmpty: + c.patterns.add(s) proc semPatternBody(c: var TemplCtx, n: PNode): PNode = template templToExpand(s: expr): expr = @@ -455,12 +455,22 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = result = semBindStmt(c.c, n, c.toBind) of nkEmpty, nkSym..nkNilLit: nil of nkCurlyExpr: - # we support '(pattern){x}' to bind a subpattern to a parameter 'x': - if n.len != 2 or n.sons[1].kind != nkIdent: + # we support '(pattern){x}' to bind a subpattern to a parameter 'x'; + # '(pattern){|x}' does the same but the matches will be gathered in 'x' + if n.len != 2: localError(n.info, errInvalidExpression) - else: + elif n.sons[1].kind == nkIdent: n.sons[0] = semPatternBody(c, n.sons[0]) n.sons[1] = expectParam(c, n.sons[1]) + elif n.sons[1].kind == nkPrefix and n.sons[1].sons[0].kind == nkIdent: + let opr = n.sons[1].sons[0] + if opr.ident.s == "|": + n.sons[0] = semPatternBody(c, n.sons[0]) + n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1]) + else: + localError(n.info, errInvalidExpression) + else: + localError(n.info, errInvalidExpression) of nkCallKinds: let s = QualifiedLookUp(c.c, n.sons[0], {}) if s != nil: @@ -473,7 +483,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = # we interpret `*` and `|` only as pattern operators if they occur in # infix notation, so that '`*`(a, b)' can be used for verbatim matching: let opr = n.sons[0] - if opr.ident.s == "*": + if opr.ident.s == "*" or opr.ident.s == "*|": result = newNodeI(nkPattern, n.info, n.len) result.sons[0] = opr result.sons[1] = semPatternBody(c, n.sons[1]) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7c1318ada..ff745dc36 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -554,12 +554,15 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = if kind == skMacro: # within a macro, every param has the type PNimrodNode! # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: + # We used to copySym(param) here, but this is not possible for term + # rewriting macros; so we simply overwrite param.typ here and hope for + # the best ... let nn = getSysSym"PNimrodNode" - var a = copySym(param) - a.typ = nn.typ - if sfGenSym notin a.flags: addDecl(c, a) - else: - if sfGenSym notin param.flags: addDecl(c, param) + #var a = copySym(param) + #a.typ = nn.typ + param.typ = nn.typ + #if sfGenSym notin a.flags: addDecl(c, a) + if sfGenSym notin param.flags: addDecl(c, param) proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): tuple[typ: PType, id: PIdent] = |