# # # The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements the passes functionality. A pass must implement the ## `TPass` interface. import options, ast, llstream, msgs, idents, syntaxes, modulegraphs, reorder, lineinfos, pathutils, std/sha1, packages when defined(nimPreviewSlimSystem): import std/syncio type TPassData* = tuple[input: PNode, closeOutput: PNode] # a pass is a tuple of procedure vars ``TPass.close`` may produce additional # nodes. These are passed to the other close procedures. # This mechanism used to be used for the instantiation of generics. proc makePass*(open: TPassOpen = nil, process: TPassProcess = nil, close: TPassClose = nil, isFrontend = false): TPass = result.open = open result.close = close result.process = process result.isFrontend = isFrontend proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = # can be used by codegen passes to determine whether they should do # something with `n`. Currently, this ignores `n` and uses the global # error count instead. result = config.errorCounter > 0 const maxPasses = 10 type TPassContextArray = array[0..maxPasses - 1, PPassContext] proc clearPasses*(g: ModuleGraph) = g.passes.setLen(0) proc registerPass*(g: ModuleGraph; p: TPass) = internalAssert g.config, g.passes.len < maxPasses g.passes.add(p) proc openPasses(g: ModuleGraph; a: var TPassContextArray; module: PSym; idgen: IdGenerator) = for i in 0..= 0 or isDefined(graph.config, "nimBackendAssumesChange") proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator; stream: PLLStream): bool {.discardable.} = if graph.stopCompile(): return true var p: Parser a: TPassContextArray s: PLLStream fileIdx = module.fileIdx prepareConfigNotes(graph, module) openPasses(graph, a, module, idgen) if stream == nil: let filename = toFullPathConsiderDirty(graph.config, fileIdx) s = llStreamOpen(filename, fmRead) if s == nil: rawMessage(graph.config, errCannotOpenFile, filename.string) return false else: s = stream when defined(nimsuggest): let filename = toFullPathConsiderDirty(graph.config, fileIdx).string msgs.setHash(graph.config, fileIdx, $sha1.secureHashFile(filename)) while true: openParser(p, fileIdx, s, graph.cache, graph.config) if not belongsToStdlib(graph, module) or (belongsToStdlib(graph, module) and module.name.s == "distros"): # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only # for the interactive mode. if module.name.s != "nimscriptapi": processImplicits graph, graph.config.implicitImports, nkImportStmt, a, module processImplicits graph, graph.config.implicitIncludes, nkIncludeStmt, a, module checkFirstLineIndentation(p) while true: if graph.stopCompile(): break var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break if (sfSystemModule notin module.flags and ({sfNoForward, sfReorder} * module.flags != {} or codeReordering in graph.config.features)): # read everything, no streaming possible var sl = newNodeI(nkStmtList, n.info) sl.add n while true: var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break sl.add n if sfReorder in module.flags or codeReordering in graph.config.features: sl = reorder(graph, sl, module) discard processTopLevelStmt(graph, sl, a) break elif n.kind in imperativeCode: # read everything until the next proc declaration etc. var sl = newNodeI(nkStmtList, n.info) sl.add n var rest: PNode = nil while true: var n = parseTopLevelStmt(p) if n.kind == nkEmpty or n.kind notin imperativeCode: rest = n break sl.add n #echo "-----\n", sl if not processTopLevelStmt(graph, sl, a): break if rest != nil: #echo "-----\n", rest if not processTopLevelStmt(graph, rest, a): break else: #echo "----- single\n", n if not processTopLevelStmt(graph, n, a): break closeParser(p) if s.kind != llsStdIn: break closePasses(graph, a) if graph.config.backend notin {backendC, backendCpp, backendObjc}: # We only write rod files here if no C-like backend is active. # The C-like backends have been patched to support the IC mechanism. # They are responsible for closing the rod files. See `cbackend.nim`. closeRodFile(graph, module) result = true