syntax compatibility between do blocks and stmt blocks

See the section `do notation` in the manual for more info.

* nkMacroStmt has been removed
   Macro statements are now mapped to regular nkCall nodes.
   The support for additional clauses (such as else, except, of, etc)
   have been restored - they will now appear as additional arguments
   for the nkCall node (as nkElse, nkExcept, etc nodes)

* fixed some regressions in the `is` operator and semCompiles
This commit is contained in:
Zahary Karadjov 2012-10-03 21:11:41 +03:00
commit d9d82fb0af
21 changed files with 142 additions and 168 deletions

View file

@ -145,7 +145,6 @@ type
nkElifBranch, # used in if statements nkElifBranch, # used in if statements
nkExceptBranch, # an except section nkExceptBranch, # an except section
nkElse, # an else part nkElse, # an else part
nkMacroStmt, # a macro statement
nkAsmStmt, # an assembler block nkAsmStmt, # an assembler block
nkPragma, # a pragma statement nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block nkPragmaBlock, # a pragma with a block
@ -911,6 +910,18 @@ proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
result = newNodeIT(nkMetaNode, info, typ) result = newNodeIT(nkMetaNode, info, typ)
result.add(tree) result.add(tree)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
params = emptyParams,
name, pattern, genericParams,
pragmas, exceptions = ast.emptyNode): PNode =
result = newNodeI(kind, info)
result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body]
proc NewType(kind: TTypeKind, owner: PSym): PType = proc NewType(kind: TTypeKind, owner: PSym): PType =
new(result) new(result)
result.kind = kind result.kind = kind

View file

@ -1382,7 +1382,7 @@ proc nestedStatement(p: var TParser): PNode =
# Nimrod requires complex statements to be nested in whitespace! # Nimrod requires complex statements to be nested in whitespace!
const const
complexStmt = {nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, complexStmt = {nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef,
nkTemplateDef, nkIteratorDef, nkMacroStmt, nkIfStmt, nkTemplateDef, nkIteratorDef, nkIfStmt,
nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection,
nkConstSection, nkTypeSection, nkTryStmt, nkBlockStmt, nkStmtList, nkConstSection, nkTypeSection, nkTryStmt, nkBlockStmt, nkStmtList,
nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType} nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType}

View file

@ -1296,7 +1296,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkEmpty: result = n of nkEmpty: result = n
of nkSym: result = evalSym(c, n, flags) of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: result = copyNode(n) # end of atoms of nkType..nkNilLit: result = copyNode(n) # end of atoms
of nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit, nkInfix, of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkInfix,
nkPrefix, nkPostfix: nkPrefix, nkPostfix:
result = evalMagicOrCall(c, n) result = evalMagicOrCall(c, n)
of nkCurly, nkBracket, nkRange: of nkCurly, nkBracket, nkRange:

View file

@ -101,4 +101,6 @@ proc getIdent*(identifier: string, h: THash): PIdent =
proc IdentEq*(id: PIdent, name: string): bool = proc IdentEq*(id: PIdent, name: string): bool =
result = id.id == getIdent(name).id result = id.id == getIdent(name).id
let idAnon* = getIdent":anonymous"

View file

@ -585,22 +585,25 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
type type
TErrorHandling = enum doNothing, doAbort, doRaise TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
if msg == errInternal: template maybeTrace =
assert(false) # we want a stack trace here if defined(debug) or gVerbosity >= 3:
writeStackTrace()
if msg == errInternal:
writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax: if msg >= fatalMin and msg <= fatalMax:
if gVerbosity >= 3: assert(false) maybeTrace()
quit(1) quit(1)
if msg >= errMin and msg <= errMax: if msg >= errMin and msg <= errMax:
if gVerbosity >= 3: assert(false) maybeTrace()
inc(gErrorCounter) inc(gErrorCounter)
options.gExitcode = 1'i8 options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax or eh == doAbort: if gErrorCounter >= gErrorMax or eh == doAbort:
if gVerbosity >= 3: assert(false) quit(1) # one error stops the compiler
quit(1) # one error stops the compiler
elif eh == doRaise: elif eh == doRaise:
raiseRecoverableError(s) raiseRecoverableError(s)
proc `==`*(a, b: TLineInfo): bool = proc `==`*(a, b: TLineInfo): bool =
result = a.line == b.line and a.fileIndex == b.fileIndex result = a.line == b.line and a.fileIndex == b.fileIndex

View file

@ -227,5 +227,7 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
result = - 1 result = - 1
# Can we keep this? I'm using it all the time # Can we keep this? I'm using it all the time
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim" template nimdbg*: expr = c.filename.endsWith"hallo.nim"
template cnimdbg*: expr = p.module.filename.endsWith"nimdbg.nim" template cnimdbg*: expr = p.module.filename.endsWith"hallo.nim"
template enimdbg*: expr = c.module.name.s == "hallo"
template pnimdbg*: expr = p.lex.fileIdx.ToFilename.endsWith"hallo.nim"

View file

@ -693,20 +693,15 @@ proc optPragmas(p: var TParser): PNode =
else: result = ast.emptyNode else: result = ast.emptyNode
proc parseDoBlock(p: var TParser): PNode = proc parseDoBlock(p: var TParser): PNode =
var info = parLineInfo(p) let info = parLineInfo(p)
getTok(p) getTok(p)
var params = parseParamList(p, retColon=false) let params = parseParamList(p, retColon=false)
var pragmas = optPragmas(p) let pragmas = optPragmas(p)
eat(p, tkColon) eat(p, tkColon)
result = newNodeI(nkDo, info)
addSon(result, ast.emptyNode) # no name part
addSon(result, ast.emptyNode) # no pattern part
addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params)
addSon(result, pragmas)
skipComment(p, result) skipComment(p, result)
addSon(result, ast.emptyNode) # no exception list result = newProcNode(nkDo, info, parseStmt(p),
addSon(result, parseStmt(p)) params = params,
pragmas = pragmas)
proc parseDoBlocks(p: var TParser, call: PNode) = proc parseDoBlocks(p: var TParser, call: PNode) =
while p.tok.tokType == tkDo: while p.tok.tokType == tkDo:
@ -723,16 +718,11 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
params = parseParamList(p) params = parseParamList(p)
pragmas = optPragmas(p) pragmas = optPragmas(p)
if p.tok.tokType == tkEquals and isExpr: if p.tok.tokType == tkEquals and isExpr:
result = newNodeI(nkLambda, info)
addSon(result, ast.emptyNode) # no name part
addSon(result, ast.emptyNode) # no pattern
addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params)
addSon(result, pragmas)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
addSon(result, ast.emptyNode) # no exception list result = newProcNode(nkLambda, info, parseStmt(p),
addSon(result, parseStmt(p)) params = params,
pragmas = pragmas)
else: else:
result = newNodeI(nkProcTy, info) result = newNodeI(nkProcTy, info)
if hasSignature: if hasSignature:
@ -822,7 +812,7 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
proc parseTypeDesc(p: var TParser): PNode = proc parseTypeDesc(p: var TParser): PNode =
if p.tok.toktype == tkProc: result = parseProcExpr(p, false) if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
else: result = parseExpr(p) else: result = parseExpr(p)
proc parseExprStmt(p: var TParser): PNode = proc parseExprStmt(p: var TParser): PNode =
var a = lowestExpr(p) var a = lowestExpr(p)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
@ -832,32 +822,29 @@ proc parseExprStmt(p: var TParser): PNode =
result = newNodeI(nkAsgn, a.info) result = newNodeI(nkAsgn, a.info)
addSon(result, a) addSon(result, a)
addSon(result, b) addSon(result, b)
else: else:
result = newNodeP(nkCommand, p) var call = if a.kind == nkCall: a
result.info = a.info else: newNode(nkCommand, a.info, @[a])
addSon(result, a) while true:
while true:
if not isExprStart(p): break if not isExprStart(p): break
var e = parseExpr(p) var e = parseExpr(p)
addSon(result, e) addSon(call, e)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
if p.tok.tokType == tkDo: if p.tok.tokType == tkDo:
parseDoBlocks(p, result) parseDoBlocks(p, call)
return return
if sonsLen(result) <= 1: result = a result = if call.sonsLen <= 1: a
else: a = result else: call
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:
# macro statement result = call
result = newNodeP(nkMacroStmt, p)
result.info = a.info
addSon(result, a)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}): if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}):
addSon(result, parseStmt(p)) let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
var b: PNode var b: PNode
@ -882,7 +869,7 @@ proc parseExprStmt(p: var TParser): PNode =
else: break else: break
addSon(b, parseStmt(p)) addSon(b, parseStmt(p))
addSon(result, b) addSon(result, b)
if b.kind == nkElse: break if b.kind == nkElse: break
proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode = proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode =
var a: PNode var a: PNode

View file

@ -1051,7 +1051,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkWhileStmt: gwhile(g, n) of nkWhileStmt: gwhile(g, n)
of nkPragmaBlock: gpragmaBlock(g, n) of nkPragmaBlock: gpragmaBlock(g, n)
of nkCaseStmt, nkRecCase: gcase(g, n) of nkCaseStmt, nkRecCase: gcase(g, n)
of nkMacroStmt: gmacro(g, n)
of nkTryStmt: gtry(g, n) of nkTryStmt: gtry(g, n)
of nkForStmt, nkParForStmt: gfor(g, n) of nkForStmt, nkParForStmt: gfor(g, n)
of nkBlockStmt, nkBlockExpr: gblock(g, n) of nkBlockStmt, nkBlockExpr: gblock(g, n)

View file

@ -22,8 +22,7 @@ proc semPass*(): TPass
type type
TExprFlag = enum TExprFlag = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
efMacroStmt # expr to semcheck is a macro statement
TExprFlags = set[TExprFlag] TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@ -35,7 +34,7 @@ proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
proc changeType(n: PNode, newType: PType) proc changeType(n: PNode, newType: PType)
proc semLambda(c: PContext, n: PNode): PNode proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
proc semStmt(c: PContext, n: PNode): PNode proc semStmt(c: PContext, n: PNode): PNode
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
@ -44,6 +43,8 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
proc addResultNode(c: PContext, n: PNode) proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode)
proc typeMismatch(n: PNode, formal, actual: PType) = proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError: if formal.kind != tyError and actual.kind != tyError:
@ -91,8 +92,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode semCheck: bool = true): PNode
proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
semCheck = true): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode

View file

@ -304,16 +304,17 @@ proc semIs(c: PContext, n: PNode): PNode =
# BUGFIX: don't evaluate this too early: ``T is void`` # BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = evalIsOp(n) if not containsGenericType(t1): result = evalIsOp(n)
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) = proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - tailToExclude): let flags = {efDetermineType}
for i in countup(1, n.sonsLen- 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprWithType(c, a.sons[1]) a.sons[1] = semExprWithType(c, a.sons[1], flags)
a.typ = a.sons[1].typ a.typ = a.sons[1].typ
else: else:
n.sons[i] = semExprWithType(c, a) n.sons[i] = semExprWithType(c, a, flags)
proc overloadedCallOpr(c: PContext, n: PNode): PNode = proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded: # quick check if there is *any* () operator overloaded:
@ -668,8 +669,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler! # this seems to be a hotspot in the compiler!
let nOrig = n.copyTree let nOrig = n.copyTree
semOpAux(c, n, 1 + ord(efMacroStmt in flags)) semOpAux(c, n)
let flags = flags - {efMacroStmt}
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil: if result == nil:
result = overloadedCallOpr(c, n) result = overloadedCallOpr(c, n)
@ -679,8 +679,9 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let callee = result.sons[0].sym let callee = result.sons[0].sym
case callee.kind case callee.kind
of skMacro: result = semMacroExpr(c, result, nOrig, callee) of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee) of skTemplate: result = semTemplateExpr(c, result, callee)
else: else:
activate(c, n)
fixAbstractType(c, result) fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result) analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone: if callee.magic != mNone:
@ -1281,7 +1282,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we replace this node by a 'true' or 'false' node: # we replace this node by a 'true' or 'false' node:
if sonsLen(n) != 2: return semDirectOp(c, n, flags) if sonsLen(n) != 2: return semDirectOp(c, n, flags)
result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil)) result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
result.info = n.info result.info = n.info
result.typ = getSysType(tyBool) result.typ = getSysType(tyBool)
@ -1496,52 +1497,6 @@ proc buildCall(n: PNode): PNode =
else: else:
result = n result = n
proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
semCheck = true): PNode =
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
else: a = n.sons[0]
var s = qualifiedLookup(c, a, {checkUndeclared})
if s != nil:
# transform
# nkMacroStmt(nkCall(a...), stmt, b...)
# to
# nkCall(a..., stmt, b...)
result = newNodeI(nkCall, n.info)
addSon(result, a)
if isCallExpr(n.sons[0]):
for i in countup(1, sonsLen(n.sons[0]) - 1):
addSon(result, n.sons[0].sons[i])
# for sigmatch this need to have a type; we use 'void':
for i in countup(1, sonsLen(n) - 1):
n.sons[i].typ = newTypeS(tyEmpty, c)
addSon(result, n.sons[i])
case s.kind
of skMacro:
if sfImmediate notin s.flags:
result = semDirectOp(c, result, flags+{efMacroStmt})
else:
result = semMacroExpr(c, result, n, s, semCheck)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, result, flags+{efMacroStmt})
else:
result = semTemplateExpr(c, result, s, semCheck)
else:
LocalError(n.info, errXisNoMacroOrTemplate, s.name.s)
result = errorNode(c, n)
elif a.kind == nkDotExpr:
# 'x.m(y): stmt' == nkMacroStmt(nkCall(nkDotExpr(x, m), y), stmt)
# --> nkMacroStmt(nkCall(m, x, y), stmt)
n.sons[0] = buildCall(n.sons[0])
result = semMacroStmt(c, n, flags, semCheck)
else:
LocalError(n.info, errInvalidExpressionX,
renderTree(a, {renderNoComments}))
result = errorNode(c, n)
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode = proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# The case expression is simply rewritten to a StmtListExpr: # The case expression is simply rewritten to a StmtListExpr:
# var res {.noInit, genSym.}: type(values) # var res {.noInit, genSym.}: type(values)
@ -1553,7 +1508,7 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# res # res
var var
info = caseStmt.info info = caseStmt.info
resVar = newSym(skVar, getIdent":res", getCurrOwner(), info) resVar = newSym(skVar, idAnon, getCurrOwner(), info)
resNode = newSymNode(resVar, info) resNode = newSymNode(resVar, info)
resType: PType resType: PType
@ -1592,7 +1547,15 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
resNode]) resNode])
result = semStmtListExpr(c, result) result = semStmtListExpr(c, result)
proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out
# the planned overload resolution reforms
for i in 1 .. <n.len:
if n[i].kind == nkDo: n.sons[i] = n[i][bodyPos]
result = n
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -1670,12 +1633,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if sfImmediate notin s.flags: if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
result = semMacroExpr(c, n, n, s) var p = fixImmediateParams(n)
result = semMacroExpr(c, p, p, s)
of skTemplate: of skTemplate:
if sfImmediate notin s.flags: if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
result = semTemplateExpr(c, n, s) var p = fixImmediateParams(n)
result = semTemplateExpr(c, p, s)
of skType: of skType:
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: if n.len == 2:
@ -1695,8 +1660,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
result = semIndirectOp(c, n, flags) result = semIndirectOp(c, n, flags)
of nkMacroStmt:
result = semMacroStmt(c, n, flags)
of nkWhen: of nkWhen:
if efWantStmt in flags: if efWantStmt in flags:
result = semWhen(c, n, true) result = semWhen(c, n, true)
@ -1725,7 +1688,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of paSingle: result = semExpr(c, n.sons[0], flags) of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n) of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n) of nkBracket: result = semArrayConstr(c, n)
of nkLambdaKinds: result = semLambda(c, n) of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n) of nkDerefExpr: result = semDeref(c, n)
of nkAddr: of nkAddr:
result = n result = n

View file

@ -53,6 +53,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skTemplate: of skTemplate:
if macroToExpand(s): if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false) result = semTemplateExpr(c, n, s, false)
else: else:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
@ -123,6 +124,7 @@ proc semGenericStmt(c: PContext, n: PNode,
result = n result = n
of skTemplate: of skTemplate:
if macroToExpand(s): if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false) result = semTemplateExpr(c, n, s, false)
else: else:
n.sons[0] = symChoice(c, n.sons[0], s, scOpen) n.sons[0] = symChoice(c, n.sons[0], s, scOpen)
@ -151,17 +153,6 @@ proc semGenericStmt(c: PContext, n: PNode,
let flags = if isDefinedMagic: flags+{withinMixin} else: flags let flags = if isDefinedMagic: flags+{withinMixin} else: flags
for i in countup(first, sonsLen(result) - 1): for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind) result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkMacroStmt:
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
else: a = n.sons[0]
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
var s = qualifiedLookup(c, a, luf)
if s != nil and macroToExpand(s):
result = semMacroStmt(c, n, {}, false)
for i in countup(0, sonsLen(result)-1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkIfStmt: of nkIfStmt:
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, toBind) n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, toBind)

View file

@ -623,9 +623,9 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
let m = lookupMacro(c, key) let m = lookupMacro(c, key)
if m == nil: continue if m == nil: continue
# we transform ``proc p {.m, rest.}`` into ``m: proc p {.rest.}`` and # we transform ``proc p {.m, rest.}`` into ``m(proc p {.rest.})`` and
# let the semantic checker deal with it: # let the semantic checker deal with it:
var x = newNodeI(nkMacroStmt, n.info) var x = newNodeI(nkCall, n.info)
x.add(newSymNode(m)) x.add(newSymNode(m))
prc.sons[pragmasPos] = copyExcept(n, i) prc.sons[pragmasPos] = copyExcept(n, i)
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
@ -634,15 +634,19 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
x.add(prc) x.add(prc)
# recursion assures that this works for multiple macro annotations too: # recursion assures that this works for multiple macro annotations too:
return semStmt(c, x) return semStmt(c, x)
proc semLambda(c: PContext, n: PNode): PNode = proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semProcAnnotation(c, n) result = semProcAnnotation(c, n)
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(), n.info) var s: PSym
s.ast = n if n[namePos].kind != nkSym:
n.sons[namePos] = newSymNode(s) s = newSym(skProc, idAnon, getCurrOwner(), n.info)
s.ast = n
n.sons[namePos] = newSymNode(s)
else:
s = n[namePos].sym
pushOwner(s) pushOwner(s)
openScope(c.tab) openScope(c.tab)
if n.sons[genericParamsPos].kind != nkEmpty: if n.sons[genericParamsPos].kind != nkEmpty:
@ -659,19 +663,31 @@ proc semLambda(c: PContext, n: PNode): PNode =
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
if sfImportc in s.flags: if sfImportc in s.flags:
LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
pushProcCon(c, s) if efDetermineType notin flags:
addResult(c, s.typ.sons[0], n.info, skProc) pushProcCon(c, s)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) addResult(c, s.typ.sons[0], n.info, skProc)
n.sons[bodyPos] = transformBody(c.module, semBody, s) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
addResultNode(c, n) n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c) addResultNode(c, n)
popProcCon(c)
sideEffectsCheck(c, s)
else: else:
LocalError(n.info, errImplOfXexpected, s.name.s) LocalError(n.info, errImplOfXexpected, s.name.s)
sideEffectsCheck(c, s)
closeScope(c.tab) # close scope for parameters closeScope(c.tab) # close scope for parameters
popOwner() popOwner()
result.typ = s.typ result.typ = s.typ
proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned.
case n.kind
of nkLambdaKinds:
discard semLambda(c, n, {})
of nkCallKinds:
for i in 1 .. <n.len: activate(c, n[i])
else:
nil
proc instantiateDestructor*(c: PContext, typ: PType): bool proc instantiateDestructor*(c: PContext, typ: PType): bool
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) = proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =

View file

@ -64,10 +64,11 @@ proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode = proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
result = copyNode(n) result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ) result.typ = ReplaceTypeVarsT(cl, n.typ)
if result.kind == nkSym: result.sym = ReplaceTypeVarsS(cl, n.sym)
for i in 0 .. safeLen(n)-1: for i in 0 .. safeLen(n)-1:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f` # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if i == 0: result.add(n[i]) if i == 0: result.add(n[i])
else: result.add(ReplaceTypeVarsN(cl, n[i])) else: result.add(prepareNode(cl, n[i]))
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n == nil: return if n == nil: return

View file

@ -637,8 +637,12 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
if f.kind == tyTypeDesc: result = arg if f.kind == tyStmt and argOrig.kind == nkDo:
else: result = argOrig result = argOrig[bodyPos]
elif f.kind == tyTypeDesc:
result = arg
else:
result = argOrig
else: else:
result = copyTree(arg) result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f) result.typ = getInstantiatedType(c, arg, m, f)

View file

@ -175,8 +175,7 @@ proc findClosestDot(n: PNode): PNode =
if result != nil: return if result != nil: return
const const
CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit, CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit}
nkMacroStmt}
proc findClosestCall(n: PNode): PNode = proc findClosestCall(n: PNode): PNode =
if n.kind in callNodes and msgs.inCheckpoint(n.info) == cpExact: if n.kind in callNodes and msgs.inCheckpoint(n.info) == cpExact:

View file

@ -38,7 +38,7 @@ type
nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef, nnkModule, nnkProcDef, nnkMethodDef, nnkConverterDef,
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt, nnkElifBranch, nnkExceptBranch, nnkElse,
nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt, nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt, nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,

View file

@ -22,7 +22,7 @@ type
PSurface* = ref TSurface ## a surface to draw onto PSurface* = ref TSurface ## a surface to draw onto
TSurface* {.pure, final.} = object TSurface* {.pure, final.} = object
w*, h*: int w*, h*: Natural
s*: sdl.PSurface s*: sdl.PSurface
EGraphics* = object of EIO EGraphics* = object of EIO

View file

@ -940,7 +940,7 @@ proc readIntoBuf(socket: TSocket, flags: int32): int =
socket.currPos = 0 socket.currPos = 0
template retRead(flags, readBytes: int) = template retRead(flags, readBytes: int) =
let res = socket.readIntoBuf(flags) let res = socket.readIntoBuf(flags.int32)
if res <= 0: if res <= 0:
if readBytes > 0: if readBytes > 0:
return readBytes return readBytes

View file

@ -151,7 +151,7 @@ template require*(conditions: stmt): stmt {.immediate, dirty.} =
const AbortOnError {.inject.} = true const AbortOnError {.inject.} = true
check conditions check conditions
macro expect*(exp: stmt): stmt {.immediate.} = macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
let exp = callsite() let exp = callsite()
template expectBody(errorTypes, lineInfoLit: expr, template expectBody(errorTypes, lineInfoLit: expr,
body: stmt): PNimrodNode {.dirty.} = body: stmt): PNimrodNode {.dirty.} =
@ -162,12 +162,11 @@ macro expect*(exp: stmt): stmt {.immediate.} =
except errorTypes: except errorTypes:
nil nil
var expectCall = exp[0] var body = exp[exp.len - 1]
var body = exp[1]
var errorTypes = newNimNode(nnkBracket) var errorTypes = newNimNode(nnkBracket)
for i in countup(1, expectCall.len - 1): for i in countup(1, exp.len - 2):
errorTypes.add(expectCall[i]) errorTypes.add(exp[i])
result = getAst(expectBody(errorTypes, exp.lineinfo, body)) result = getAst(expectBody(errorTypes, exp.lineinfo, body))

View file

@ -1,5 +1,5 @@
discard """ discard """
output: "Got: 'nnkMacroStmt' hi" output: "Got: 'nnkCall' hi"
""" """
import import
@ -11,17 +11,15 @@ macro outterMacro*(n: stmt): stmt {.immediate.} =
proc innerProc(i: int): string = proc innerProc(i: int): string =
echo "Using arg ! " & n.repr echo "Using arg ! " & n.repr
result = "Got: '" & $n.kind & "' " & $j result = "Got: '" & $n.kind & "' " & $j
if n.kind != TNimrodNodeKind.nnkMacroStmt:
error("Macro " & n[0].repr & " requires a block.")
var callNode = n[0] var callNode = n[0]
expectKind(callNode, TNimrodNodeKind.nnkCall) expectKind(n, TNimrodNodeKind.nnkCall)
if callNode.len != 2 or callNode[1].kind != TNimrodNodeKind.nnkIdent: if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent:
error("Macro " & callNode.repr & error("Macro " & callNode.repr &
" requires the ident passed as parameter (eg: " & callNode.repr & " requires the ident passed as parameter (eg: " & callNode.repr &
"(the_name_you_want)): statements.") "(the_name_you_want)): statements.")
result = newNimNode(TNimrodNodeKind.nnkStmtList) result = newNimNode(TNimrodNodeKind.nnkStmtList)
var ass : PNimrodNode = newNimNode(TNimrodNodeKind.nnkAsgn) var ass : PNimrodNode = newNimNode(nnkAsgn)
ass.add(newIdentNode(callNode[1].ident)) ass.add(newIdentNode(n[1].ident))
ass.add(newStrLitNode(innerProc(4))) ass.add(newStrLitNode(innerProc(4)))
result.add(ass) result.add(ass)

View file

@ -28,12 +28,12 @@ import
# `opened` is defined to `optional.hasValue` # `opened` is defined to `optional.hasValue`
macro using(e: expr): stmt {.immediate.} = macro using(e: expr): stmt {.immediate.} =
let e = callsite() let e = callsite()
if e.len != 2: if e.len != 3:
error "Using statement: unexpected number of arguments. Got " & error "Using statement: unexpected number of arguments. Got " &
$e.len & ", expected: 1 or more variable assignments and a block" $e.len & ", expected: 1 or more variable assignments and a block"
var args = e[0] var args = e
var body = e[1] var body = e[2]
var var
variables : seq[PNimrodNode] variables : seq[PNimrodNode]
@ -41,8 +41,8 @@ macro using(e: expr): stmt {.immediate.} =
newSeq(variables, 0) newSeq(variables, 0)
newSeq(closingCalls, 0) newSeq(closingCalls, 0)
for i in countup(1, args.len-1): for i in countup(1, args.len-2):
if args[i].kind == nnkExprEqExpr: if args[i].kind == nnkExprEqExpr:
var varName = args[i][0] var varName = args[i][0]
var varValue = args[i][1] var varValue = args[i][1]