summaryrefslogtreecommitdiff
path: root/src/libs/qmljs/qmljscodeformatter.cpp
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2010-07-07 11:45:18 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2010-08-10 14:27:08 +0200
commit822de6c17ab52002ae59a94c3e231bf0d5e3e438 (patch)
treea683fcd312b3f5840cd326ae2106f377fcd36505 /src/libs/qmljs/qmljscodeformatter.cpp
parentf6232260c2c5ba93e85d725e05c2d2c9b86e293c (diff)
downloadqt-creator-822de6c17ab52002ae59a94c3e231bf0d5e3e438.tar.gz
QmlJS: Introduce a new indenter that works similarly to the new C++ one.
Done-with: Thomas Hartmann
Diffstat (limited to 'src/libs/qmljs/qmljscodeformatter.cpp')
-rw-r--r--src/libs/qmljs/qmljscodeformatter.cpp910
1 files changed, 910 insertions, 0 deletions
diff --git a/src/libs/qmljs/qmljscodeformatter.cpp b/src/libs/qmljs/qmljscodeformatter.cpp
new file mode 100644
index 0000000000..468d112cbc
--- /dev/null
+++ b/src/libs/qmljs/qmljscodeformatter.cpp
@@ -0,0 +1,910 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljscodeformatter.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMetaEnum>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+
+using namespace QmlJS;
+
+CodeFormatter::BlockData::BlockData()
+ : m_blockRevision(-1)
+{
+}
+
+CodeFormatter::CodeFormatter()
+ : m_indentDepth(0)
+ , m_tabSize(4)
+{
+}
+
+CodeFormatter::~CodeFormatter()
+{
+}
+
+void CodeFormatter::setTabSize(int tabSize)
+{
+ m_tabSize = tabSize;
+}
+
+void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
+{
+ restoreCurrentState(block.previous());
+
+ const int lexerState = tokenizeBlock(block);
+ m_tokenIndex = 0;
+ m_newStates.clear();
+
+ //qDebug() << "Starting to look at " << block.text() << block.blockNumber() + 1;
+
+ for (; m_tokenIndex < m_tokens.size(); ) {
+ m_currentToken = tokenAt(m_tokenIndex);
+ const int kind = extendedTokenKind(m_currentToken);
+ //dump();
+ //qDebug() << "Token" << m_currentLine.mid(m_currentToken.begin(), m_currentToken.length) << m_tokenIndex << "in line" << block.blockNumber() + 1;
+
+ if (kind == Comment
+ && state().type != multiline_comment_cont
+ && state().type != multiline_comment_start) {
+ m_tokenIndex += 1;
+ continue;
+ }
+
+ switch (m_currentState.top().type) {
+ case topmost_intro:
+ switch (kind) {
+ case Identifier: enter(objectdefinition_or_js); continue;
+ case Import: enter(top_qml); continue;
+ default: enter(top_js); continue;
+ } break;
+
+ case top_qml:
+ switch (kind) {
+ case Import: enter(import_start); break;
+ case Identifier: enter(binding_or_objectdefinition); break;
+ } break;
+
+ case top_js:
+ tryStatement();
+ break;
+
+ case objectdefinition_or_js:
+ switch (kind) {
+ case Dot: break;
+ case Identifier:
+ if (!m_currentLine.at(m_currentToken.begin()).isUpper()) {
+ turnInto(top_js);
+ continue;
+ }
+ break;
+ case LeftBrace: turnInto(binding_or_objectdefinition); continue;
+ default: turnInto(top_js); continue;
+ } break;
+
+ case import_start:
+ enter(import_maybe_dot_or_version_or_as);
+ break;
+
+ case import_maybe_dot_or_version_or_as:
+ switch (kind) {
+ case Dot: turnInto(import_dot); break;
+ case As: turnInto(import_as); break;
+ case Number: turnInto(import_maybe_as); break;
+ default: leave(); leave(); continue;
+ } break;
+
+ case import_maybe_as:
+ switch (kind) {
+ case As: turnInto(import_as); break;
+ default: leave(); leave(); continue;
+ } break;
+
+ case import_dot:
+ switch (kind) {
+ case Identifier: turnInto(import_maybe_dot_or_version_or_as); break;
+ default: leave(); leave(); continue;
+ } break;
+
+ case import_as:
+ switch (kind) {
+ case Identifier: leave(); leave(); break;
+ } break;
+
+ case binding_or_objectdefinition:
+ switch (kind) {
+ case Colon: enter(binding_assignment); break;
+ case LeftBrace: enter(objectdefinition_open); break;
+ } break;
+
+ case binding_assignment:
+ switch (kind) {
+ case Semicolon: leave(true); break;
+ case If: enter(if_statement); break;
+ case LeftBrace: enter(jsblock_open); break;
+ case On:
+ case As:
+ case List:
+ case Import:
+ case Signal:
+ case Property:
+ case Identifier: enter(expression_or_objectdefinition); break;
+ default: enter(expression); continue;
+ } break;
+
+ case objectdefinition_open:
+ switch (kind) {
+ case RightBrace: leave(true); break;
+ case Default: enter(default_property_start); break;
+ case Property: enter(property_start); break;
+ case Function: enter(function_start); break;
+ case Signal: enter(signal_start); break;
+ case On:
+ case As:
+ case List:
+ case Import:
+ case Identifier: enter(binding_or_objectdefinition); break;
+ } break;
+
+ case default_property_start:
+ if (kind != Property)
+ leave(true);
+ else
+ turnInto(property_start);
+ break;
+
+ case property_start:
+ switch (kind) {
+ case Colon: enter(binding_assignment); break; // oops, was a binding
+ case Var:
+ case Identifier: enter(property_type); break;
+ case List: enter(property_list_open); break;
+ default: leave(true); continue;
+ } break;
+
+ case property_type:
+ turnInto(property_maybe_initializer);
+ break;
+
+ case property_list_open:
+ if (m_currentLine.midRef(m_currentToken.begin(), m_currentToken.length) == QLatin1String(">"))
+ turnInto(property_maybe_initializer);
+ break;
+
+ case property_maybe_initializer:
+ switch (kind) {
+ case Colon: enter(binding_assignment); break;
+ default: leave(true); continue;
+ } break;
+
+ case signal_start:
+ switch (kind) {
+ case Colon: enter(binding_assignment); break; // oops, was a binding
+ default: enter(signal_maybe_arglist); break;
+ } break;
+
+ case signal_maybe_arglist:
+ switch (kind) {
+ case LeftParenthesis: turnInto(signal_arglist_open); break;
+ default: leave(true); continue;
+ } break;
+
+ case signal_arglist_open:
+ switch (kind) {
+ case RightParenthesis: leave(true); break;
+ } break;
+
+ case function_start:
+ switch (kind) {
+ case LeftParenthesis: enter(function_arglist_open); break;
+ } break;
+
+ case function_arglist_open:
+ switch (kind) {
+ case RightParenthesis: turnInto(function_arglist_closed); break;
+ } break;
+
+ case function_arglist_closed:
+ switch (kind) {
+ case LeftBrace: turnInto(jsblock_open); break;
+ default: leave(true); continue; // error recovery
+ } break;
+
+ case expression_or_objectdefinition:
+ switch (kind) {
+ case LeftBrace: turnInto(objectdefinition_open); break;
+ default: enter(expression); continue; // really? first token already gone!
+ } break;
+
+ case expression:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case Comma:
+ case Delimiter: enter(expression_continuation); break;
+ case RightBracket:
+ case RightParenthesis: leave(); continue;
+ case RightBrace: leave(true); continue;
+ case Semicolon: leave(true); break;
+ } break;
+
+ case expression_continuation:
+ leave();
+ continue;
+
+ case expression_maybe_continuation:
+ switch (kind) {
+ case Question:
+ case Delimiter:
+ case LeftBracket:
+ case LeftParenthesis: leave(); continue;
+ default: leave(true); continue;
+ } break;
+
+ case paren_open:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case RightParenthesis: leave(); break;
+ } break;
+
+ case bracket_open:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case Comma: enter(bracket_element_start); break;
+ case RightBracket: leave(); break;
+ } break;
+
+ case bracket_element_start:
+ switch (kind) {
+ case Identifier: turnInto(bracket_element_maybe_objectdefinition); break;
+ default: leave(); continue;
+ } break;
+
+ case bracket_element_maybe_objectdefinition:
+ switch (kind) {
+ case LeftBrace: turnInto(objectdefinition_open); break;
+ default: leave(); continue;
+ } break;
+
+ case ternary_op:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case RightParenthesis:
+ case RightBracket:
+ case RightBrace:
+ case Comma:
+ case Semicolon: leave(); continue;
+ case Colon: enter(expression); break; // entering expression makes maybe_continuation work
+ } break;
+
+ case jsblock_open:
+ case substatement_open:
+ if (tryStatement())
+ break;
+ switch (kind) {
+ case RightBrace: leave(true); break;
+ } break;
+
+ case substatement:
+ // prefer substatement_open over block_open
+ if (kind != LeftBrace) {
+ if (tryStatement())
+ break;
+ }
+ switch (kind) {
+ case LeftBrace: turnInto(substatement_open); break;
+ } break;
+
+ case if_statement:
+ switch (kind) {
+ case LeftParenthesis: enter(condition_open); break;
+ default: leave(true); break; // error recovery
+ } break;
+
+ case maybe_else:
+ if (kind == Else) {
+ turnInto(else_clause);
+ enter(substatement);
+ break;
+ } else {
+ leave(true);
+ continue;
+ }
+
+ case else_clause:
+ // ### shouldn't happen
+ dump();
+ Q_ASSERT(false);
+ leave(true);
+ break;
+
+ case condition_open:
+ switch (kind) {
+ case RightParenthesis: turnInto(substatement); break;
+ case LeftParenthesis: enter(condition_paren_open); break;
+ } break;
+
+ // paren nesting
+ case condition_paren_open:
+ switch (kind) {
+ case RightParenthesis: leave(); break;
+ case LeftParenthesis: enter(condition_paren_open); break;
+ } break;
+
+ case switch_statement:
+ case statement_with_condition:
+ switch (kind) {
+ case LeftParenthesis: enter(statement_with_condition_paren_open); break;
+ default: leave(true);
+ } break;
+
+ case statement_with_condition_paren_open:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case RightParenthesis: turnInto(substatement); break;
+ } break;
+
+ case statement_with_block:
+ switch (kind) {
+ case LeftBrace: enter(jsblock_open); break;
+ default: leave(true); break;
+ } break;
+
+ case do_statement:
+ switch (kind) {
+ case While: break;
+ case LeftParenthesis: enter(do_statement_while_paren_open); break;
+ default: leave(true); break;
+ } break;
+
+ case do_statement_while_paren_open:
+ if (tryInsideExpression())
+ break;
+ switch (kind) {
+ case RightParenthesis: leave(); leave(true); break;
+ } break;
+
+ break;
+
+ case case_start:
+ switch (kind) {
+ case Colon: turnInto(case_cont); break;
+ } break;
+
+ case case_cont:
+ if (kind != Case && kind != Default && tryStatement())
+ break;
+ switch (kind) {
+ case RightBrace: leave(); continue;
+ case Default:
+ case Case: leave(); continue;
+ } break;
+
+ case multiline_comment_start:
+ case multiline_comment_cont:
+ if (kind != Comment) {
+ leave();
+ continue;
+ } else if (m_tokenIndex == m_tokens.size() - 1
+ && lexerState == Scanner::Normal) {
+ leave();
+ } else if (m_tokenIndex == 0) {
+ // to allow enter/leave to update the indentDepth
+ turnInto(multiline_comment_cont);
+ }
+ break;
+
+ default:
+ qWarning() << "Unhandled state" << m_currentState.top().type;
+ break;
+ } // end of state switch
+
+ ++m_tokenIndex;
+ }
+
+ int topState = m_currentState.top().type;
+
+ if (topState == expression
+ || topState == expression_or_objectdefinition) {
+ enter(expression_maybe_continuation);
+ }
+ if (topState != multiline_comment_start
+ && topState != multiline_comment_cont
+ && lexerState == Scanner::MultiLineComment) {
+ enter(multiline_comment_start);
+ }
+
+ saveCurrentState(block);
+}
+
+int CodeFormatter::indentFor(const QTextBlock &block)
+{
+// qDebug() << "indenting for" << block.blockNumber() + 1;
+
+ restoreCurrentState(block.previous());
+ correctIndentation(block);
+ return m_indentDepth;
+}
+
+void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
+{
+ QStack<State> previousState = initialState();
+ QTextBlock it = endBlock.document()->firstBlock();
+
+ // find the first block that needs recalculation
+ for (; it.isValid() && it != endBlock; it = it.next()) {
+ BlockData blockData;
+ if (!loadBlockData(it, &blockData))
+ break;
+ if (blockData.m_blockRevision != it.revision())
+ break;
+ if (previousState != blockData.m_beginState)
+ break;
+ if (loadLexerState(it) == -1)
+ break;
+
+ previousState = blockData.m_endState;
+ }
+
+ if (it == endBlock)
+ return;
+
+ // update everthing until endBlock
+ for (; it.isValid() && it != endBlock; it = it.next()) {
+ recalculateStateAfter(it);
+ }
+
+ // invalidate everything below by marking the state in endBlock as invalid
+ if (it.isValid()) {
+ BlockData invalidBlockData;
+ saveBlockData(&it, invalidBlockData);
+ }
+}
+
+void CodeFormatter::updateLineStateChange(const QTextBlock &block)
+{
+ if (!block.isValid())
+ return;
+
+ BlockData blockData;
+ if (loadBlockData(block, &blockData) && blockData.m_blockRevision == block.revision())
+ return;
+
+ recalculateStateAfter(block);
+
+ // invalidate everything below by marking the next block's state as invalid
+ QTextBlock next = block.next();
+ if (!next.isValid())
+ return;
+
+ saveBlockData(&next, BlockData());
+}
+
+CodeFormatter::State CodeFormatter::state(int belowTop) const
+{
+ if (belowTop < m_currentState.size())
+ return m_currentState.at(m_currentState.size() - 1 - belowTop);
+ else
+ return State();
+}
+
+const QVector<CodeFormatter::State> &CodeFormatter::newStatesThisLine() const
+{
+ return m_newStates;
+}
+
+int CodeFormatter::tokenIndex() const
+{
+ return m_tokenIndex;
+}
+
+int CodeFormatter::tokenCount() const
+{
+ return m_tokens.size();
+}
+
+const Token &CodeFormatter::currentToken() const
+{
+ return m_currentToken;
+}
+
+void CodeFormatter::invalidateCache(QTextDocument *document)
+{
+ if (!document)
+ return;
+
+ BlockData invalidBlockData;
+ QTextBlock it = document->firstBlock();
+ for (; it.isValid(); it = it.next()) {
+ saveBlockData(&it, invalidBlockData);
+ }
+}
+
+void CodeFormatter::enter(int newState)
+{
+ int savedIndentDepth = m_indentDepth;
+ onEnter(newState, &m_indentDepth, &savedIndentDepth);
+ State s(newState, savedIndentDepth);
+ m_currentState.push(s);
+ m_newStates.push(s);
+
+ if (newState == bracket_open)
+ enter(bracket_element_start);
+}
+
+void CodeFormatter::leave(bool statementDone)
+{
+ Q_ASSERT(m_currentState.size() > 1);
+ if (m_currentState.top().type == topmost_intro)
+ return;
+
+ if (m_newStates.size() > 0)
+ m_newStates.pop();
+
+ // restore indent depth
+ State poppedState = m_currentState.pop();
+ m_indentDepth = poppedState.savedIndentDepth;
+
+ int topState = m_currentState.top().type;
+
+ // if statement is done, may need to leave recursively
+ if (statementDone) {
+ if (!isExpressionEndState(topState))
+ leave(true);
+ if (topState == if_statement) {
+ if (poppedState.type != maybe_else)
+ enter(maybe_else);
+ else
+ leave(true);
+ } else if (topState == else_clause) {
+ // leave the else *and* the surrounding if, to prevent another else
+ leave();
+ leave(true);
+ }
+ }
+}
+
+void CodeFormatter::correctIndentation(const QTextBlock &block)
+{
+ const int lexerState = tokenizeBlock(block);
+ Q_ASSERT(m_currentState.size() >= 1);
+
+ adjustIndent(m_tokens, lexerState, &m_indentDepth);
+}
+
+bool CodeFormatter::tryInsideExpression(bool alsoExpression)
+{
+ int newState = -1;
+ const int kind = extendedTokenKind(m_currentToken);
+ switch (kind) {
+ case LeftParenthesis: newState = paren_open; break;
+ case LeftBracket: newState = bracket_open; break;
+ case Function: newState = function_start; break;
+ case Question: newState = ternary_op; break;
+ }
+
+ if (newState != -1) {
+ if (alsoExpression)
+ enter(expression);
+ enter(newState);
+ return true;
+ }
+
+ return false;
+}
+
+bool CodeFormatter::tryStatement()
+{
+ const int kind = extendedTokenKind(m_currentToken);
+ switch (kind) {
+ case Semicolon:
+ enter(empty_statement);
+ leave(true);
+ return true;
+ case Return:
+ enter(return_statement);
+ enter(expression);
+ return true;
+ case While:
+ case For:
+ case Catch:
+ enter(statement_with_condition);
+ return true;
+ case Switch:
+ enter(switch_statement);
+ return true;
+ case If:
+ enter(if_statement);
+ return true;
+ case Do:
+ enter(do_statement);
+ enter(substatement);
+ return true;
+ case Case:
+ case Default:
+ enter(case_start);
+ return true;
+ case Try:
+ case Finally:
+ enter(statement_with_block);
+ return true;
+ case LeftBrace:
+ enter(jsblock_open);
+ return true;
+ case Identifier:
+ case Delimiter:
+ case PlusPlus:
+ case MinusMinus:
+ case Import:
+ case Signal:
+ case On:
+ case As:
+ case List:
+ case Property:
+ case Function:
+ enter(expression);
+ // look at the token again
+ m_tokenIndex -= 1;
+ return true;
+ }
+ return false;
+}
+
+bool CodeFormatter::isBracelessState(int type) const
+{
+ return
+ type == if_statement ||
+ type == else_clause ||
+ type == substatement ||
+ type == binding_assignment ||
+ type == binding_or_objectdefinition;
+}
+
+bool CodeFormatter::isExpressionEndState(int type) const
+{
+ return
+ type == topmost_intro ||
+ type == top_js ||
+ type == objectdefinition_open ||
+ type == if_statement ||
+ type == else_clause ||
+ type == do_statement ||
+ type == jsblock_open ||
+ type == substatement_open ||
+ type == bracket_open ||
+ type == paren_open ||
+ type == case_cont;
+}
+
+const Token &CodeFormatter::tokenAt(int idx) const
+{
+ static const Token empty;
+ if (idx < 0 || idx >= m_tokens.size())
+ return empty;
+ else
+ return m_tokens.at(idx);
+}
+
+int CodeFormatter::column(int index) const
+{
+ int col = 0;
+ if (index > m_currentLine.length())
+ index = m_currentLine.length();
+
+ const QChar tab = QLatin1Char('\t');
+
+ for (int i = 0; i < index; i++) {
+ if (m_currentLine[i] == tab) {
+ col = ((col / m_tabSize) + 1) * m_tabSize;
+ } else {
+ col++;
+ }
+ }
+ return col;
+}
+
+QStringRef CodeFormatter::currentTokenText() const
+{
+ return m_currentLine.midRef(m_currentToken.begin(), m_currentToken.length);
+}
+
+void CodeFormatter::turnInto(int newState)
+{
+ leave(false);
+ enter(newState);
+}
+
+void CodeFormatter::saveCurrentState(const QTextBlock &block)
+{
+ if (!block.isValid())
+ return;
+
+ BlockData blockData;
+ blockData.m_blockRevision = block.revision();
+ blockData.m_beginState = m_beginState;
+ blockData.m_endState = m_currentState;
+ blockData.m_indentDepth = m_indentDepth;
+
+ QTextBlock saveableBlock(block);
+ saveBlockData(&saveableBlock, blockData);
+}
+
+void CodeFormatter::restoreCurrentState(const QTextBlock &block)
+{
+ if (block.isValid()) {
+ BlockData blockData;
+ if (loadBlockData(block, &blockData)) {
+ m_indentDepth = blockData.m_indentDepth;
+ m_currentState = blockData.m_endState;
+ m_beginState = m_currentState;
+ return;
+ }
+ }
+
+ m_currentState = initialState();
+ m_beginState = m_currentState;
+ m_indentDepth = 0;
+}
+
+QStack<CodeFormatter::State> CodeFormatter::initialState()
+{
+ static QStack<CodeFormatter::State> initialState;
+ if (initialState.isEmpty())
+ initialState.push(State(topmost_intro, 0));
+ return initialState;
+}
+
+int CodeFormatter::tokenizeBlock(const QTextBlock &block)
+{
+ int startState = loadLexerState(block.previous());
+ if (block.blockNumber() == 0)
+ startState = 0;
+ Q_ASSERT(startState != -1);
+
+ Scanner tokenize;
+ tokenize.setScanComments(true);
+
+ m_currentLine = block.text();
+ // to determine whether a line was joined, Tokenizer needs a
+ // newline character at the end
+ m_currentLine.append(QLatin1Char('\n'));
+ m_tokens = tokenize(m_currentLine, startState);
+
+ const int lexerState = tokenize.state();
+ QTextBlock saveableBlock(block);
+ saveLexerState(&saveableBlock, lexerState);
+ return lexerState;
+}
+
+CodeFormatter::TokenKind CodeFormatter::extendedTokenKind(const QmlJS::Token &token) const
+{
+ const int kind = token.kind;
+ QStringRef text = m_currentLine.midRef(token.begin(), token.length);
+
+ if (kind == Identifier) {
+ if (text == "as")
+ return As;
+ if (text == "import")
+ return Import;
+ if (text == "signal")
+ return Signal;
+ if (text == "property")
+ return Property;
+ if (text == "on")
+ return On;
+ if (text == "list")
+ return On;
+ } else if (kind == Keyword) {
+ const QChar char1 = text.at(0);
+ const QChar char2 = text.at(1);
+ const QChar char3 = (text.size() > 2 ? text.at(2) : QChar());
+ switch (char1.toLatin1()) {
+ case 'v':
+ return Var;
+ case 'i':
+ if (char2 == 'f')
+ return If;
+ else if (char3 == 's')
+ return Instanceof;
+ else
+ return In;
+ case 'f':
+ if (char2 == 'o')
+ return For;
+ else if (char2 == 'u')
+ return Function;
+ else
+ return Finally;
+ case 'e':
+ return Else;
+ case 'n':
+ return New;
+ case 'r':
+ return Return;
+ case 's':
+ return Switch;
+ case 'w':
+ if (char2 == 'h')
+ return While;
+ return With;
+ case 'c':
+ if (char3 == 's')
+ return Case;
+ if (char3 == 't')
+ return Catch;
+ return Continue;
+ case 'd':
+ if (char3 == 'l')
+ return Delete;
+ if (char3 == 'f')
+ return Default;
+ if (char3 == 'b')
+ return Debugger;
+ return Do;
+ case 't':
+ if (char3 == 'i')
+ return This;
+ if (char3 == 'y')
+ return Try;
+ if (char3 == 'r')
+ return Throw;
+ return Typeof;
+ case 'b':
+ return Break;
+ }
+ } else if (kind == Delimiter) {
+ if (text == "?")
+ return Question;
+ else if (text == "++")
+ return PlusPlus;
+ else if (text == "--")
+ return MinusMinus;
+ }
+
+ return static_cast<TokenKind>(kind);
+}
+
+void CodeFormatter::dump() const
+{
+ QMetaEnum metaEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("StateType"));
+
+ qDebug() << "Current token index" << m_tokenIndex;
+ qDebug() << "Current state:";
+ foreach (State s, m_currentState) {
+ qDebug() << metaEnum.valueToKey(s.type) << s.savedIndentDepth;
+ }
+ qDebug() << "Current indent depth:" << m_indentDepth;
+}