# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # import ast, types, msgs, os, osproc, streams, options, idents, securehash proc readOutput(p: Process): (string, int) = result[0] = "" var output = p.outputStream while not output.atEnd: result[0].add(output.readLine) result[0].add("\n") if result[0].len > 0: result[0].setLen(result[0].len - "\n".len) result[1] = p.waitForExit proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) = let workingDir = parentDir(info.toFullPath) if cache.len > 0:# and optForceFullMake notin gGlobalOptions: let h = secureHash(cmd & "\t" & input & "\t" & cache) let filename = options.toGeneratedFile("gorge_" & $h, "txt") var f: File if open(f, filename): result = (f.readAll, 0) f.close return var readSuccessful = false try: var p = startProcess(cmd, workingDir, options={poEvalCommand, poStderrToStdout}) if input.len != 0: p.inputStream.write(input) p.inputStream.close() result = p.readOutput readSuccessful = true writeFile(filename, result[0]) except IOError, OSError: if not readSuccessful: result = ("", -1) else: try: var p = startProcess(cmd, workingDir, options={poEvalCommand, poStderrToStdout}) if input.len != 0: p.inputStream.write(input) p.inputStream.close() result = p.readOutput except IOError, OSError: result = ("", -1) proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = try: var filename = parentDir(info.toFullPath) / file if not fileExists(filename): filename = file.findFile result = readFile(filename) # we produce a fake include statement for every slurped filename, so that # the module dependencies are accurate: appendToModule(module, newNode(nkIncludeStmt, info, @[ newStrNode(nkStrLit, filename)])) except IOError: localError(info, errCannotOpenFile, file) result = "" proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode = let sym = newSym(skType, getIdent(name), t.owner, info) sym.magic = m sym.typ = t result = newSymNode(sym) result.typ = t proc atomicTypeX(s: PSym; info: TLineInfo): PNode = result = newSymNode(s) result.info = info proc mapTypeToAstX(t: PType; info: TLineInfo; inst=false; allowRecursionX=false): PNode proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo; inst=false): PNode = result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result.add atomicTypeX(name, m, t, info) for i in 0 .. < t.len: if t.sons[i] == nil: let void = atomicTypeX("void", mVoid, t, info) void.typ = newType(tyVoid, t.owner) result.add void else: result.add mapTypeToAstX(t.sons[i], info, inst) proc objectNode(n: PNode): PNode = if n.kind == nkSym: result = newNodeI(nkIdentDefs, n.info) result.add n # name result.add mapTypeToAstX(n.sym.typ, n.info, true, false) # type result.add ast.emptyNode # no assigned value else: result = copyNode(n) for i in 0 ..< n.safeLen: result.add objectNode(n[i]) proc mapTypeToAstX(t: PType; info: TLineInfo; inst=false; allowRecursionX=false): PNode = var allowRecursion = allowRecursionX template atomicType(name, m): untyped = atomicTypeX(name, m, t, info) template atomicType(s): untyped = atomicTypeX(s, info) template mapTypeToAst(t,info): untyped = mapTypeToAstX(t, info, inst) template mapTypeToAstR(t,info): untyped = mapTypeToAstX(t, info, inst, true) template mapTypeToAst(t,i,info): untyped = if i 0: result.add objectNode(t.n) else: result.add ast.emptyNode else: if allowRecursion or t.sym == nil: result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t) result.add ast.emptyNode if t.sons[0] == nil: result.add ast.emptyNode else: result.add mapTypeToAst(t.sons[0], info) result.add copyTree(t.n) else: result = atomicType(t.sym) of tyEnum: result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t) result.add ast.emptyNode # pragma node, currently always empty for enum for c in t.n.sons: result.add copyTree(c) of tyTuple: if inst: result = newNodeX(nkTupleTy) # only named tuples have a node, unnamed tuples don't if t.n.isNil: for subType in t.sons: result.add mapTypeToAst(subType, info) else: for s in t.n.sons: result.add newIdentDefs(s) else: result = mapTypeToBracket("tuple", mTuple, t, info) of tySet: result = mapTypeToBracket("set", mSet, t, info) of tyPtr: if inst: result = newNodeX(nkPtrTy) result.add mapTypeToAst(t.sons[0], info) else: result = mapTypeToBracket("ptr", mPtr, t, info) of tyRef: if inst: result = newNodeX(nkRefTy) result.add mapTypeToAst(t.sons[0], info) else: result = mapTypeToBracket("ref", mRef, t, info) of tyVar: result = mapTypeToBracket("var", mVar, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) of tyProc: if inst: result = newNodeX(nkProcTy) var fp = newNodeX(nkFormalParams) if t.sons[0] == nil: fp.add ast.emptyNode else: fp.add mapTypeToAst(t.sons[0], t.n[0].info) for i in 1..