void updateCode(std::unique_ptr<llvm::MemoryBuffer> Buffer) { BufferID = SM.addNewSourceBuffer(std::move(Buffer)); Parser.reset(new ParserUnit(SM, BufferID, CompInv.getLangOptions(), CompInv.getModuleName())); Parser->getDiagnosticEngine().addConsumer(DiagConsumer); auto &P = Parser->getParser(); for (bool Done = false; !Done; Done = P.Tok.is(tok::eof)) { P.parseTopLevel(); } }
static StringRef getSourceToken(unsigned Offset, ImmutableTextSnapshotRef Snap) { auto MemBuf = Snap->getBuffer()->getInternalBuffer(); SourceManager SM; auto MemBufRef = llvm::MemoryBuffer::getMemBuffer(MemBuf->getBuffer(), MemBuf->getBufferIdentifier()); auto BufId = SM.addNewSourceBuffer(std::move(MemBufRef)); SourceLoc Loc = SM.getLocForOffset(BufId, Offset); // Use fake language options; language options only affect validity // and the exact token produced. LangOptions FakeLangOpts; Lexer L(FakeLangOpts, SM, BufId, nullptr, /*InSILMode=*/ false, CommentRetentionMode::ReturnAsTokens); return L.getTokenAt(Loc).getText(); }
int getTokensFromFile(const StringRef InputFilename, LangOptions &LangOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags, std::vector<std::pair<RC<syntax::TokenSyntax>, syntax::AbsolutePosition>> &Tokens) { auto Buffer = llvm::MemoryBuffer::getFile(InputFilename); if (!Buffer) { Diags.diagnose(SourceLoc(), diag::cannot_open_file, InputFilename, Buffer.getError().message()); return EXIT_FAILURE; } auto BufferID = SourceMgr.addNewSourceBuffer(std::move(Buffer.get())); return getTokensFromFile(BufferID, LangOpts, SourceMgr, Diags, Tokens); }
SourceCompleteResult ide::isSourceInputComplete(std::unique_ptr<llvm::MemoryBuffer> MemBuf) { SourceManager SM; auto BufferID = SM.addNewSourceBuffer(std::move(MemBuf)); ParserUnit Parse(SM, BufferID); Parser &P = Parse.getParser(); bool Done; do { P.parseTopLevel(); Done = P.Tok.is(tok::eof); } while (!Done); SourceCompleteResult SCR; SCR.IsComplete = !P.isInputIncomplete(); // Use the same code that was in the REPL code to track the indent level // for now. In the future we should get this from the Parser if possible. CharSourceRange entireRange = SM.getRangeForBuffer(BufferID); StringRef Buffer = SM.extractText(entireRange); const char *SourceStart = Buffer.data(); const char *SourceEnd = Buffer.data() + Buffer.size(); const char *LineStart = SourceStart; const char *LineSourceStart = nullptr; uint32_t LineIndent = 0; struct IndentInfo { StringRef Prefix; uint32_t Indent; IndentInfo(const char *s, size_t n, uint32_t i) : Prefix(s, n), Indent(i) {} }; SmallVector<IndentInfo, 4> IndentInfos; for (const char *p = SourceStart; p<SourceEnd; ++p) { switch (*p) { case '\r': case '\n': LineIndent = 0; LineSourceStart = nullptr; LineStart = p + 1; break; case '"': p = skipStringInCode (p, SourceEnd); break; case '{': case '(': case '[': ++LineIndent; if (LineSourceStart == nullptr) IndentInfos.push_back(IndentInfo(LineStart, p - LineStart, LineIndent)); else IndentInfos.push_back(IndentInfo(LineStart, LineSourceStart - LineStart, LineIndent)); break; case '}': case ')': case ']': if (LineIndent > 0) --LineIndent; if (!IndentInfos.empty()) IndentInfos.pop_back(); break; default: if (LineSourceStart == nullptr && !isspace(*p)) LineSourceStart = p; break; } if (*p == '\0') break; } if (!IndentInfos.empty()) { SCR.IndentPrefix = IndentInfos.back().Prefix.str(); // Trim off anything that follows a non-space character const size_t pos = SCR.IndentPrefix.find_first_not_of(" \t"); if (pos != std::string::npos) SCR.IndentPrefix.erase(pos); SCR.IndentLevel = IndentInfos.back().Indent; } return SCR; }