summaryrefslogtreecommitdiff
path: root/shared/cplusplus/TranslationUnit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'shared/cplusplus/TranslationUnit.cpp')
-rw-r--r--shared/cplusplus/TranslationUnit.cpp434
1 files changed, 434 insertions, 0 deletions
diff --git a/shared/cplusplus/TranslationUnit.cpp b/shared/cplusplus/TranslationUnit.cpp
new file mode 100644
index 0000000000..06a7a3af4e
--- /dev/null
+++ b/shared/cplusplus/TranslationUnit.cpp
@@ -0,0 +1,434 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "TranslationUnit.h"
+#include "Control.h"
+#include "Parser.h"
+#include "Lexer.h"
+#include "MemoryPool.h"
+#include "AST.h"
+#include "Literals.h"
+#include "DiagnosticClient.h"
+#include <stack>
+#include <cstdlib>
+#include <cstdarg>
+#include <algorithm>
+
+CPLUSPLUS_BEGIN_NAMESPACE
+
+TranslationUnit::TranslationUnit(Control *control, StringLiteral *fileId)
+ : _control(control),
+ _fileId(fileId),
+ _firstSourceChar(0),
+ _lastSourceChar(0),
+ _pool(0),
+ _ast(0),
+ _flags(0)
+{
+ _tokens = new Array<Token, 8>();
+ _previousTranslationUnit = control->switchTranslationUnit(this);
+ _pool = new MemoryPool();
+}
+
+TranslationUnit::~TranslationUnit()
+{
+ (void) _control->switchTranslationUnit(_previousTranslationUnit);
+ delete _tokens;
+ delete _pool;
+}
+
+bool TranslationUnit::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void TranslationUnit::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+Control *TranslationUnit::control() const
+{ return _control; }
+
+StringLiteral *TranslationUnit::fileId() const
+{ return _fileId; }
+
+const char *TranslationUnit::fileName() const
+{ return _fileId->chars(); }
+
+unsigned TranslationUnit::fileNameLength() const
+{ return _fileId->size(); }
+
+const char *TranslationUnit::firstSourceChar() const
+{ return _firstSourceChar; }
+
+const char *TranslationUnit::lastSourceChar() const
+{ return _lastSourceChar; }
+
+unsigned TranslationUnit::sourceLength() const
+{ return _lastSourceChar - _firstSourceChar; }
+
+void TranslationUnit::setSource(const char *source, unsigned size)
+{
+ _firstSourceChar = source;
+ _lastSourceChar = source + size;
+}
+
+unsigned TranslationUnit::tokenCount() const
+{ return _tokens->size(); }
+
+const Token &TranslationUnit::tokenAt(unsigned index) const
+{ return _tokens->at(index); }
+
+int TranslationUnit::tokenKind(unsigned index) const
+{ return _tokens->at(index).kind; }
+
+Identifier *TranslationUnit::identifier(unsigned index) const
+{ return _tokens->at(index).identifier; }
+
+Literal *TranslationUnit::literal(unsigned index) const
+{ return _tokens->at(index).literal; }
+
+StringLiteral *TranslationUnit::stringLiteral(unsigned index) const
+{ return _tokens->at(index).string; }
+
+NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const
+{ return _tokens->at(index).number; }
+
+unsigned TranslationUnit::matchingBrace(unsigned index) const
+{ return _tokens->at(index).close_brace; }
+
+MemoryPool *TranslationUnit::memoryPool() const
+{ return _pool; }
+
+TranslationUnitAST *TranslationUnit::ast() const
+{ return _ast; }
+
+bool TranslationUnit::isTokenized() const
+{ return _tokenized; }
+
+bool TranslationUnit::isParsed() const
+{ return _parsed; }
+
+void TranslationUnit::tokenize()
+{
+ if (isTokenized())
+ return;
+
+ _tokenized = true;
+
+ Lexer lex(this);
+ lex.setQtMocRunEnabled(_qtMocRunEnabled);
+
+ std::stack<unsigned> braces;
+ _tokens->push_back(Token()); // the first token needs to be invalid!
+
+ pushLineOffset(0);
+ pushPreprocessorLine(0, 1, fileId());
+
+ Identifier *lineId = control()->findOrInsertIdentifier("line");
+
+ Token tk;
+ do {
+ lex(&tk);
+
+ _Lrecognize:
+ if (tk.is(T_POUND)) {
+ unsigned offset = tk.offset;
+ lex(&tk);
+ if (! tk.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
+ lex(&tk);
+ if (! tk.newline && tk.is(T_INT_LITERAL)) {
+ unsigned line = (unsigned) strtoul(tk.spell(), 0, 0);
+ lex(&tk);
+ if (! tk.newline && tk.is(T_STRING_LITERAL)) {
+ StringLiteral *fileName = control()->findOrInsertFileName(tk.string->chars(),
+ tk.string->size());
+ pushPreprocessorLine(offset, line, fileName);
+ lex(&tk);
+ }
+ }
+ while (tk.isNot(T_EOF_SYMBOL) && ! tk.newline)
+ lex(&tk);
+ goto _Lrecognize;
+ } else if (tk.kind == T_LBRACE) {
+ braces.push(_tokens->size());
+ } else if (tk.kind == T_RBRACE && ! braces.empty()) {
+ const unsigned open_brace_index = braces.top();
+ braces.pop();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+ _tokens->push_back(tk);
+ } while (tk.kind);
+
+ for (; ! braces.empty(); braces.pop()) {
+ unsigned open_brace_index = braces.top();
+ (*_tokens)[open_brace_index].close_brace = _tokens->size();
+ }
+}
+
+bool TranslationUnit::skipFunctionBody() const
+{ return _skipFunctionBody; }
+
+void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody)
+{ _skipFunctionBody = skipFunctionBody; }
+
+void TranslationUnit::parse()
+{
+ if (isParsed())
+ return;
+
+ if (! isTokenized())
+ tokenize();
+
+ Parser parser(this);
+ parser.setQtMocRunEnabled(_qtMocRunEnabled);
+ parser.parseTranslationUnit(_ast);
+}
+
+void TranslationUnit::pushLineOffset(unsigned offset)
+{ _lineOffsets.push_back(offset); }
+
+void TranslationUnit::pushPreprocessorLine(unsigned offset,
+ unsigned line,
+ StringLiteral *fileName)
+{ _ppLines.push_back(PPLine(offset, line, fileName)); }
+
+unsigned TranslationUnit::findLineNumber(unsigned offset) const
+{
+ std::vector<unsigned>::const_iterator it =
+ std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset);
+
+ if (it != _lineOffsets.begin())
+ --it;
+
+ return it - _lineOffsets.begin();
+}
+
+TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const
+{
+ std::vector<PPLine>::const_iterator it =
+ std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset));
+
+ if (it != _ppLines.begin())
+ --it;
+
+ return *it;
+}
+
+unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const
+{
+ if (! offset)
+ return 0;
+
+ return offset - _lineOffsets[lineNumber];
+}
+
+void TranslationUnit::getTokenPosition(unsigned index,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{ return getPosition(tokenAt(index).offset, line, column, fileName); }
+
+void TranslationUnit::getPosition(unsigned tokenOffset,
+ unsigned *line,
+ unsigned *column,
+ StringLiteral **fileName) const
+{
+ unsigned lineNumber = findLineNumber(tokenOffset);
+ unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
+ const PPLine ppLine = findPreprocessorLine(tokenOffset);
+
+ lineNumber -= findLineNumber(ppLine.offset) + 1;
+ lineNumber += ppLine.line;
+
+ if (line)
+ *line = lineNumber;
+
+ if (column)
+ *column = columnNumber;
+
+ if (fileName)
+ *fileName = ppLine.fileName;
+}
+
+bool TranslationUnit::blockErrors(bool block)
+{
+ bool previous = _blockErrors;
+ _blockErrors = block;
+ return previous;
+}
+
+void TranslationUnit::warning(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Warning, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "warning: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::error(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Error, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "error: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+}
+
+void TranslationUnit::fatal(unsigned index, const char *format, ...)
+{
+ if (_blockErrors)
+ return;
+
+ index = std::min(index, tokenCount() - 1);
+
+ unsigned line = 0, column = 0;
+ StringLiteral *fileName = 0;
+ getTokenPosition(index, &line, &column, &fileName);
+
+ if (DiagnosticClient *client = control()->diagnosticClient()) {
+ va_list args;
+ va_start(args, format);
+ client->report(DiagnosticClient::Fatal, fileName, line, column,
+ format, args);
+ va_end(args);
+ } else {
+ fprintf(stderr, "%s:%d: ", fileName->chars(), line);
+ fprintf(stderr, "fatal: ");
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+
+ showErrorLine(index, column, stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
+{
+ unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
+ for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) {
+ fputc(*cp, out);
+ }
+ fputc('\n', out);
+
+ const char *end = _firstSourceChar + lineOffset + 1 + column - 1;
+ for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) {
+ if (*cp != '\t')
+ fputc(' ', out);
+ else
+ fputc('\t', out);
+ }
+ fputc('^', out);
+ fputc('\n', out);
+}
+
+void TranslationUnit::resetAST()
+{
+ delete _pool;
+ _pool = 0;
+}
+
+void TranslationUnit::release()
+{
+ resetAST();
+ delete _tokens;
+ _tokens = 0;
+}
+
+CPLUSPLUS_END_NAMESPACE