/***************************************************************************
* This file is part of KDevelop *
* Copyright 2007 Andreas Pakulat *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "astbuilder.h"
#include
#include "ast.h"
#include
#include
#include
#include "kurl.h"
#include
#include
#include
#include
#include
#include
#include "parserConfig.h"
#include
using namespace KDevelop;
namespace Python
{
CodeAst* AstBuilder::parse(KUrl filename, const QString& contents)
{
CodeAst* ast = parseXmlAst(getXmlForFile(filename, contents));
return ast;
}
QString AstBuilder::getXmlForFile(KUrl filename, const QString& contents)
{
QProcess* parser = new QProcess();
// we call a python script to parse the code for us. It returns an XML string with the AST
// kDebug() << QDir::current();
kDebug() << "+++ Starting parser for file " << filename.path();
parser->start("/usr/bin/env", QStringList() << "python" << QString(INSTALL_PATH) + QString("/pythonpythonparser.py"));
qint64 length = contents.length();
qint64 written = parser->write(contents.toAscii().data(), length);
kDebug() << "Content length: " << length << ", Bytes written: " << written;
parser->closeWriteChannel();
if ( written != length ) {
Q_ASSERT(false);
}
parser->waitForFinished();
kDebug() << " ** Reading results...";
// TODO this is not clean
if ( parser->exitStatus() != QProcess::NormalExit ) {
kError() << "Error parsing file: " << parser->errorString();
return "0";
}
QString result = parser->readAllStandardOutput();
kDebug() << " ** XML for " << filename << ": length" << result.length();
if ( ! result.length() ) {
result = parser->readAllStandardError();
QStringList position = result.split(":::");
QString additionalExplanation = "";
if ( position.length() < 4 ) {
kError() << "Could not parse error message! This should not happen.";
kError() << "Raw data was: " << result;
return "0";
}
qint64 lineno = position.at(0).toInt() - 1;
qint64 colno = position.at(1).toInt() - 1;
kDebug() << lineno << colno;
if ( position.at(2) == "SyntaxError" ) {
additionalExplanation = "Something's wrong with your syntax. Check for missing brackets, commas, and colons.";
}
else if ( position.at(2) == "IndentationError" ) {
additionalExplanation = "You indented your code incorrectly. Also check that you didn't mix tabs and spaces in an incorrect way!";
}
KDevelop::ProblemPointer p(new KDevelop::Problem());
p->setFinalLocation(KDevelop::DocumentRange(KDevelop::IndexedString(filename), KDevelop::SimpleRange(lineno, colno - 5 < 0 ? 0 : colno - 5, lineno, colno + 5)));
p->setSource(KDevelop::ProblemData::Parser);
p->setDescription(position.at(2));
p->setExplanation(position.at(3) + "
" + additionalExplanation);
p->setSeverity(KDevelop::ProblemData::Error);
{
DUChainWriteLocker lock(DUChain::lock());
m_problems.clear();
m_problems.append(p);
}
kWarning() << "Parse Error: " << result;
return "0";
}
delete parser;
return result;
}
CodeAst* AstBuilder::parseXmlAst(QString xml)
{
Q_ASSERT(xml.length());
if ( xml == "0" ) {
return 0;
}
QXmlStreamReader* xmlast = new QXmlStreamReader();
xmlast->addData(xml);
m_nodeMap.clear();
parseXmlAstNode(xmlast, QXmlStreamReader::Invalid);
populateAst();
CodeAst* codeAst = dynamic_cast(m_currentNode);
Q_ASSERT(codeAst);
return codeAst;
}
void AstBuilder::parseXmlAstNode(QXmlStreamReader* xmlast, QXmlStreamReader::TokenType token = QXmlStreamReader::Invalid) {
bool nodeAdded = false;
while ( ! xmlast->atEnd() && ! xmlast->hasError() ) {
// Advance to the next (first) token
QXmlStreamReader::TokenType token = xmlast->readNext();
// Store everything we need later into local variables
QString currentElementName = xmlast->name().toString();
QString currentElementText = xmlast->text().toString();
QList currentElementAttributes = xmlast->attributes().toList();
// We ignore startDocument and EndDocument
if ( token == QXmlStreamReader::StartDocument || token == QXmlStreamReader::EndDocument ) {
continue;
}
// We recursively continue parsing if we find another element
else if ( token == QXmlStreamReader::StartElement ) {
// Here we can now assemble an actual node with the attributes extracted above
// Skip the document root element
if ( currentElementName == "pythonast" ) {
parseXmlAstNode(xmlast, token);
continue;
}
// this will push a parent onto the stack
nodeAdded = parseAstNode(currentElementName, currentElementText, currentElementAttributes);
if ( ! nodeAdded ) {
m_isRealNodeMap.append(false);
continue;
}
m_isRealNodeMap.append(true);
m_currentNode = m_nodeStack.last();
parseXmlAstNode(xmlast, token);
}
else if ( token == QXmlStreamReader::EndElement ) {
if ( currentElementName == "pythonast" ) continue;
// now we pop the parent off
bool isreal = m_isRealNodeMap.last();
m_isRealNodeMap.removeLast();
if ( isreal ) {
m_currentNode = m_nodeStack.last();
m_nodeStack.removeLast();
}
}
// Everything else (stuff between tags, comments...) is ignored
else continue;
}
if ( xmlast->hasError() ) {
kWarning() << "Invalid XML file: " << xmlast->errorString();
kWarning() << "Aborting!";
Q_ASSERT(false);
}
}
bool AstBuilder::parseAstNode(QString name, QString text, const QList< QXmlStreamAttribute >& attributes)
{
Ast* ast;
QMap attributeDict;
for ( int i=0; istartLine = -5;
m_nodeMap.insert(node_id, ast);
m_attributeStore.insert(node_id, attributeDict);
m_nodeStack.append(ast);
// kDebug() << "Stack size: " << m_nodeStack.length();
return true;
}
template T* AstBuilder::resolveNode(const QString& identifier)
{
if ( ! identifier.length() ) return 0;
int id = identifier.toInt();
Ast* found = m_nodeMap.value(id);
T* ret = dynamic_cast(found);
Q_ASSERT(found || ! ret);
return found ? ret : 0;
}
template QList AstBuilder::resolveNodeList(const QString& commaSeperatedIdentifiers)
{
QList items;
items.clear();
QStringList identifiers = commaSeperatedIdentifiers.split(",");
T* found;
for ( int i=0; i(identifiers.at(i));
if ( found ) items << found;
}
return items;
}
Identifier* AstBuilder::createIdentifier(const QString& name, Ast* range)
{
Identifier* ident = new Identifier(name);
ident->startCol = range->startCol;
ident->endCol = range->startCol + name.length() - 1;
ident->startLine = range->startLine;
ident->endLine = range->endLine;
ident->parent = range;
return ident;
}
ExpressionAst::Context AstBuilder::resolveContext(const QString& identifier)
{
int id = identifier.toInt();
if ( ! id ) return ExpressionAst::Invalid;
return m_contextNodeMap.value(id);
}
Ast::BooleanOperationTypes AstBuilder::resolveBooleanOperator(const QString& identifier)
{
int id = identifier.toInt();
if ( ! id ) return Ast::BooleanInvalidOperation;
return m_boolOpNodeMap.value(id);
}
Ast::OperatorTypes AstBuilder::resolveOperator(const QString& identifier)
{
int id = identifier.toInt();
if ( ! id ) return Ast::OperatorInvalid;
return m_opNodeMap.value(id);
}
Ast::UnaryOperatorTypes AstBuilder::resolveUnaryOperator(const QString& identifier)
{
int id = identifier.toInt();
if ( ! id ) return Ast::UnaryOperatorInvalid;
return m_unaryOpNodeMap.value(id);
}
Ast::ComparisonOperatorTypes AstBuilder::resolveComparisonOperator(const QString& identifier)
{
int id = identifier.toInt();
if ( ! id ) return Ast::ComparisonOperatorInvalid;
return m_compOpNodeMap.value(id);
}
QList< Ast::ComparisonOperatorTypes > AstBuilder::resolveComparisonOperatorList(const QString& identifiers)
{
QList<:comparisonoperatortypes> items;
QList ids = identifiers.split(",");
for ( int i=0; i < ids.length(); i++ ) {
items << resolveComparisonOperator(ids.at(i));
}
return items;
}
ExecAst* AstBuilder::populateExecAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ExecAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNode(currentAttributes.value("NR_body"));
currentNode->locals = resolveNode(currentAttributes.value("NR_locals"));
currentNode->globals = resolveNode(currentAttributes.value("NR_globals"));
return currentNode;
}
NameAst* AstBuilder::populateNameAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
NameAst* currentNode = dynamic_cast(ast);
currentNode->context = resolveContext(currentAttributes.value("NR_ctx"));
currentNode->identifier = createIdentifier(currentAttributes.value("id"), currentNode);
// kDebug() << "Processing NameAst" << currentNode->identifier->value;
return currentNode;
}
ClassDefinitionAst* AstBuilder::populateClassDefinitonAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ClassDefinitionAst* currentNode = dynamic_cast(ast);
currentNode->baseClasses = resolveNodeList(currentAttributes.value("NRLST_bases"));
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list"));
currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode);
currentNode->name->startCol += 6; // TODO fix this! ;D
currentNode->name->endCol += 6;
return currentNode;
}
FunctionDefinitionAst* AstBuilder::populateFunctionDefinitionAst(Ast* ast, const stringDictionary& currentAttributes)
{
FunctionDefinitionAst* currentNode = dynamic_cast(ast);
currentNode->arguments = resolveNode(currentAttributes.value("NR_args"));
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->decorators = resolveNodeList(currentAttributes.value("NRLST_decorator_list"));
currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode);
currentNode->name->startCol += 4; // TODO fix this! ;D
currentNode->name->endCol += 4;
return currentNode;
}
AssignmentAst* AstBuilder::populateAssignmentAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
AssignmentAst* currentNode = dynamic_cast(ast);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
currentNode->targets = resolveNodeList(currentAttributes.value("NRLST_targets"));
return currentNode;
}
CodeAst* AstBuilder::populateCodeAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
CodeAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
return currentNode;
}
DeleteAst* AstBuilder::populateDeleteAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
DeleteAst* currentNode = dynamic_cast(ast);
currentNode->targets = resolveNodeList(currentAttributes.value("NRLST_targets"));
return currentNode;
}
ForAst* AstBuilder::populateForAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ForAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse"));
currentNode->iterator = resolveNode(currentAttributes.value("NR_iter"));
currentNode->target = resolveNode(currentAttributes.value("NR_target"));
return currentNode;
}
PrintAst* AstBuilder::populatePrintAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
PrintAst* currentNode = dynamic_cast(ast);
currentNode->destination = resolveNode(currentAttributes.value("NR_dest"));
currentNode->newline = currentAttributes.value("nl") == "True" ? true : false;
currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values"));
return currentNode;
}
ReturnAst* AstBuilder::populateReturnAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ReturnAst* currentNode = dynamic_cast(ast);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
IfAst* AstBuilder::populateIfAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
IfAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->condition = resolveNode(currentAttributes.value("NR_test"));
currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse"));
return currentNode;
}
BooleanOperationAst* AstBuilder::populateBooleanOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
BooleanOperationAst* currentNode = dynamic_cast(ast);
currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values"));
currentNode->type = resolveBooleanOperator(currentAttributes.value("NR_op"));
return currentNode;
}
CallAst* AstBuilder::populateCallAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
CallAst* currentNode = dynamic_cast(ast);
currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args"));
currentNode->function = resolveNode(currentAttributes.value("NR_func"));
currentNode->keywordArguments = resolveNode(currentAttributes.value("NR_kwargs"));
currentNode->keywords = resolveNodeList(currentAttributes.value("NRLST_keywords"));
currentNode->starArguments = resolveNode(currentAttributes.value("NR_starargs"));
return currentNode;
}
LambdaAst* AstBuilder::populateLambdaAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
LambdaAst* currentNode = dynamic_cast(ast);
currentNode->arguments = resolveNode(currentAttributes.value("NR_args"));
currentNode->body = resolveNode(currentAttributes.value("NR_body"));
return currentNode;
}
WhileAst* AstBuilder::populateWhileAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
WhileAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse"));
currentNode->condition = resolveNode(currentAttributes.value("NR_test"));
return currentNode;
}
DictAst* AstBuilder::populateDictAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
DictAst* currentNode = dynamic_cast(ast);
currentNode->keys = resolveNodeList(currentAttributes.value("NRLST_keys"));
currentNode->values = resolveNodeList(currentAttributes.value("NRLST_values"));
return currentNode;
}
ListAst* AstBuilder::populateListAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ListAst* currentNode = dynamic_cast(ast);
currentNode->elements = resolveNodeList(currentAttributes.value("NRLST_elts"));
currentNode->context = resolveContext(currentAttributes.value("NR_ctx"));
return currentNode;
}
TupleAst* AstBuilder::populateTupleAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
TupleAst* currentNode = dynamic_cast(ast);
currentNode->context = resolveContext(currentAttributes.value("NR_ctx"));
currentNode->elements = resolveNodeList(currentAttributes.value("NRLST_elts"));
return currentNode;
}
AugmentedAssignmentAst* AstBuilder::populateAugmentedAssignmentAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
AugmentedAssignmentAst* currentNode = dynamic_cast(ast);
currentNode->op = resolveOperator(currentAttributes.value("NR_op"));
currentNode->target = resolveNode(currentAttributes.value("NR_target"));
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
RaiseAst* AstBuilder::populateRaiseAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
RaiseAst* currentNode = dynamic_cast(ast);
currentNode->type = resolveNode(currentAttributes.value("NR_type"));
return currentNode;
}
TryExceptAst* AstBuilder::populateTryExceptAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
TryExceptAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->handlers = resolveNodeList(currentAttributes.value("NRLST_handlers"));
currentNode->orelse = resolveNodeList(currentAttributes.value("NRLST_orelse"));
return currentNode;
}
TryFinallyAst* AstBuilder::populateTryFinallyAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
TryFinallyAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->finalbody = resolveNodeList(currentAttributes.value("NRLST_finalbody"));
return currentNode;
}
AssertionAst* AstBuilder::populateAssertionAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
AssertionAst* currentNode = dynamic_cast(ast);
currentNode->condition = resolveNode(currentAttributes.value("NR_test"));
currentNode->message = resolveNode(currentAttributes.value("NR_msg"));
return currentNode;
}
BinaryOperationAst* AstBuilder::populateBinaryOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
BinaryOperationAst* currentNode = dynamic_cast(ast);
currentNode->rhs = resolveNode(currentAttributes.value("NR_right"));
currentNode->lhs = resolveNode(currentAttributes.value("NR_left"));
currentNode->type = resolveOperator(currentAttributes.value("NR_op"));
return currentNode;
}
ImportAst* AstBuilder::populateImportAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ImportAst* currentNode = dynamic_cast(ast);
currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names"));
return currentNode;
}
ImportFromAst* AstBuilder::populateImportFromAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ImportFromAst* currentNode = dynamic_cast(ast);
currentNode->level = currentAttributes.value("level").toInt();
currentNode->module = createIdentifier(currentAttributes.value("module"), currentNode);
currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names"));
return currentNode;
}
AliasAst* AstBuilder::populateAliasAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
AliasAst* currentNode = dynamic_cast(ast);
currentNode->asName = resolveNode(currentAttributes.value("NR_asname"));
currentNode->name = createIdentifier(currentAttributes.value("name"), currentNode);
return currentNode;
}
GlobalAst* AstBuilder::populateGlobalAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
GlobalAst* currentNode = dynamic_cast(ast);
// currentNode->names = resolveNodeList(currentAttributes.value("NRLST_names")); // TODO the parser does not write this correctly! also, need to fix resolve
return currentNode;
}
UnaryOperationAst* AstBuilder::populateUnaryOperationAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
UnaryOperationAst* currentNode = dynamic_cast(ast);
currentNode->operand = resolveNode(currentAttributes.value("NR_operand"));
currentNode->type = resolveUnaryOperator(currentAttributes.value("NR_op"));
return currentNode;
}
IfExpressionAst* AstBuilder::populateIfExpressionAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
IfExpressionAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNode(currentAttributes.value("NR_body"));
currentNode->orelse = resolveNode(currentAttributes.value("NR_orelse"));
currentNode->condition = resolveNode(currentAttributes.value("NR_test"));
return currentNode;
}
ListComprehensionAst* AstBuilder::populateListComprehensionAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ListComprehensionAst* currentNode = dynamic_cast(ast);
currentNode->generators = resolveNodeList(currentAttributes.value("NRLST_generators"));
currentNode->element = resolveNode(currentAttributes.value("NR_elt"));
return currentNode;
}
WithAst* AstBuilder::populateWithAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
WithAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->contextExpression = resolveNode(currentAttributes.value("NR_context_expr"));
currentNode->optionalVars = resolveNode(currentAttributes.value("NR_optional_vars"));
return currentNode;
}
ComprehensionAst* AstBuilder::populateComprehensionAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ComprehensionAst* currentNode = dynamic_cast(ast);
currentNode->conditions = resolveNodeList(currentAttributes.value("NRLST_ifs"));
currentNode->iterator = resolveNode(currentAttributes.value("NR_iter"));
currentNode->target = resolveNode(currentAttributes.value("NR_target"));
return currentNode;
}
CompareAst* AstBuilder::populateCompareAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
CompareAst* currentNode = dynamic_cast(ast);
currentNode->comparands = resolveNodeList(currentAttributes.value("NRLST_comparators"));
currentNode->operators = resolveComparisonOperatorList(currentAttributes.value("NRLST_ops"));
currentNode->leftmostElement = resolveNode(currentAttributes.value("NR_left"));
return currentNode;
}
NumberAst* AstBuilder::populateNumberAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
NumberAst* currentNode = dynamic_cast(ast);
currentNode->value = currentAttributes.value("n"); // save this as a QString to aviod problems with python number formats like 3j+2 (complex), 3L, 3.35, etc.
return currentNode;
}
StringAst* AstBuilder::populateStringAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
StringAst* currentNode = dynamic_cast(ast);
currentNode->value = currentAttributes.value("s");
return currentNode;
}
AttributeAst* AstBuilder::populateAttributeAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
AttributeAst* currentNode = dynamic_cast(ast);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
currentNode->attribute = createIdentifier(currentAttributes.value("attr"), currentNode);
currentNode->context = resolveContext(currentAttributes.value("NR_ctx"));
return currentNode;
}
SubscriptAst* AstBuilder::populateSubscriptAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
SubscriptAst* currentNode = dynamic_cast(ast);
currentNode->context = resolveContext("NR_ctx");
currentNode->slice = resolveNode(currentAttributes.value("NR_slice"));
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
SliceAst* AstBuilder::populateSliceAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
SliceAst* currentNode = dynamic_cast(ast);
currentNode->lower = resolveNode(currentAttributes.value("NR_lower"));
currentNode->upper = resolveNode(currentAttributes.value("NR_upper"));
currentNode->step = resolveNode(currentAttributes.value("NR_step"));
return currentNode;
}
ArgumentsAst* AstBuilder::populateArgumentsAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ArgumentsAst* currentNode = dynamic_cast(ast);
currentNode->arguments = resolveNodeList(currentAttributes.value("NRLST_args"));
currentNode->defaultValues = resolveNodeList(currentAttributes.value("NRLST_defaults"));
currentNode->kwarg = createIdentifier(currentAttributes.value("kwarg"), currentNode);
currentNode->vararg = createIdentifier(currentAttributes.value("paramstar"), currentNode);
return currentNode;
}
ExceptionHandlerAst* AstBuilder::populateExceptionHandlerAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
ExceptionHandlerAst* currentNode = dynamic_cast(ast);
currentNode->body = resolveNodeList(currentAttributes.value("NRLST_body"));
currentNode->name = resolveNode(currentAttributes.value("NR_name"));
currentNode->type = resolveNode(currentAttributes.value("NR_type"));
return currentNode;
}
IndexAst* AstBuilder::populateIndexAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
IndexAst* currentNode = dynamic_cast(ast);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
KeywordAst* AstBuilder::populateKeywordAst(Ast* ast, const Python::stringDictionary& currentAttributes)
{
KeywordAst* currentNode = dynamic_cast(ast);
currentNode->argumentName = createIdentifier(currentAttributes.value("arg"), currentNode);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
ExpressionAst* AstBuilder::populateExpressionAst(Ast* ast, const stringDictionary& currentAttributes)
{
ExpressionAst* currentNode = dynamic_cast(ast);
currentNode->value = resolveNode(currentAttributes.value("NR_value"));
return currentNode;
}
void AstBuilder::populateAst()
{
Ast* currentAbstractNode;
stringDictionary currentAttributes;
QMapIterator i(m_nodeMap);
while ( i.hasNext() ) {
i.next();
currentAbstractNode = i.value();
currentAttributes = m_attributeStore.value(i.key());
// kDebug() << "Processing AST node ID " << i.key();
// kDebug() << "Amount of attributes: " << currentAttributes.size();
stringDictionary::const_iterator i = currentAttributes.begin();
// while ( i != currentAttributes.end() ) {
// kDebug() << i.key() << i.value();
// ++i;
// }
if ( currentAttributes.value("lineno").length() > 0 && currentAttributes.value("col_offset").length() > 0 )
currentAbstractNode->hasUsefulRangeInformation = true;
else currentAbstractNode->hasUsefulRangeInformation = false;
int startLine = currentAttributes.value("lineno").toInt() - 1; // start = 0 <> start = 1
currentAbstractNode->startLine = startLine;
currentAbstractNode->endLine = startLine;
int startCol = currentAttributes.value("col_offset").toInt();
currentAbstractNode->startCol = startCol;
currentAbstractNode->endCol = startCol; // this is justified if necessary (only an AST with an actual value or identifier will know the true range)
switch ( currentAbstractNode->astType ) {
case Ast::CodeAstType: currentAbstractNode = populateCodeAst(currentAbstractNode, currentAttributes); break;
case Ast::FunctionDefinitionAstType: currentAbstractNode = populateFunctionDefinitionAst(currentAbstractNode, currentAttributes); break;
case Ast::ClassDefinitionAstType: currentAbstractNode = populateClassDefinitonAst(currentAbstractNode, currentAttributes); break;
case Ast::ReturnAstType: currentAbstractNode = populateReturnAst(currentAbstractNode, currentAttributes); break;
case Ast::DeleteAstType: currentAbstractNode = populateDeleteAst(currentAbstractNode, currentAttributes); break;
case Ast::AssignmentAstType: currentAbstractNode = populateAssignmentAst(currentAbstractNode, currentAttributes); break;
case Ast::AugmentedAssignmentAstType: currentAbstractNode = populateAugmentedAssignmentAst(currentAbstractNode, currentAttributes); break;
case Ast::ForAstType: currentAbstractNode = populateForAst(currentAbstractNode, currentAttributes); break;
case Ast::WhileAstType: currentAbstractNode = populateWhileAst(currentAbstractNode, currentAttributes); break;
case Ast::IfAstType: currentAbstractNode = populateIfAst(currentAbstractNode, currentAttributes); break;
case Ast::WithAstType: currentAbstractNode = populateWithAst(currentAbstractNode, currentAttributes); break;
case Ast::RaiseAstType: currentAbstractNode = populateRaiseAst(currentAbstractNode, currentAttributes); break;
case Ast::TryExceptAstType: currentAbstractNode = populateTryExceptAst(currentAbstractNode, currentAttributes); break;
case Ast::TryFinallyAstType: currentAbstractNode = populateTryFinallyAst(currentAbstractNode, currentAttributes); break;
case Ast::AssertionAstType: currentAbstractNode = populateAssertionAst(currentAbstractNode, currentAttributes); break;
case Ast::ImportAstType: currentAbstractNode = populateImportAst(currentAbstractNode, currentAttributes); break;
case Ast::ImportFromAstType: currentAbstractNode = populateImportFromAst(currentAbstractNode, currentAttributes); break;
// case Ast::ExecAstType: break; // TODO support this? or better not? :]
case Ast::GlobalAstType: currentAbstractNode = populateGlobalAst(currentAbstractNode, currentAttributes); break;
case Ast::BreakAstType: break; // ok
case Ast::ContinueAstType: break; // ok
case Ast::PrintAstType: currentAbstractNode = populatePrintAst(currentAbstractNode, currentAttributes); break;
case Ast::PassAstType: break; // ok
case Ast::BooleanOperationAstType: currentAbstractNode = populateBooleanOperationAst(currentAbstractNode, currentAttributes); break;
case Ast::BinaryOperationAstType: currentAbstractNode = populateBinaryOperationAst(currentAbstractNode, currentAttributes); break;
case Ast::UnaryOperationAstType: currentAbstractNode = populateUnaryOperationAst(currentAbstractNode, currentAttributes); break;
case Ast::LambdaAstType: currentAbstractNode = populateLambdaAst(currentAbstractNode, currentAttributes); break;
case Ast::IfExpressionAstType: currentAbstractNode = populateIfExpressionAst(currentAbstractNode, currentAttributes); break;
case Ast::DictAstType: currentAbstractNode = populateDictAst(currentAbstractNode, currentAttributes); break;
// case Ast::SetAstType: break; // TODO support this (read about sets)
case Ast::ListComprehensionAstType: currentAbstractNode = populateListComprehensionAst(currentAbstractNode, currentAttributes); break;
// case Ast::SetComprehensionAstType: break; // TODO support this
// case Ast::DictionaryComprehensionAstType: break; // TODO fix this for python 2.7+
// case Ast::GeneratorExpressionAstType: break; // TODO read about this
case Ast::CompareAstType: currentAbstractNode = populateCompareAst(currentAbstractNode, currentAttributes); break;
// case Ast::ReprAstType: break; // TODO support this
case Ast::NumberAstType: currentAbstractNode = populateNumberAst(currentAbstractNode, currentAttributes); break;
case Ast::StringAstType: currentAbstractNode = populateStringAst(currentAbstractNode, currentAttributes); break;
// case Ast::YieldAstType: break; // TODO TODO
case Ast::NameAstType: currentAbstractNode = populateNameAst(currentAbstractNode, currentAttributes); break;
case Ast::CallAstType: currentAbstractNode = populateCallAst(currentAbstractNode, currentAttributes); break;
case Ast::AttributeAstType: currentAbstractNode = populateAttributeAst(currentAbstractNode, currentAttributes); break;
case Ast::SubscriptAstType: currentAbstractNode = populateSubscriptAst(currentAbstractNode, currentAttributes); break;
case Ast::ListAstType: currentAbstractNode = populateListAst(currentAbstractNode, currentAttributes); break;
case Ast::TupleAstType: currentAbstractNode = populateTupleAst(currentAbstractNode, currentAttributes); break;
// case Ast::EllipsisAstType: break; // TODO TODO
case Ast::SliceAstType: currentAbstractNode = populateSliceAst(currentAbstractNode, currentAttributes); break;
// case Ast::ExtendedSliceAstType: break; // TODO TODO
case Ast::IndexAstType: currentAbstractNode = populateIndexAst(currentAbstractNode, currentAttributes); break;
case Ast::ArgumentsAstType: currentAbstractNode = populateArgumentsAst(currentAbstractNode, currentAttributes); break;
case Ast::KeywordAstType: currentAbstractNode = populateKeywordAst(currentAbstractNode, currentAttributes); break;
case Ast::ComprehensionAstType: currentAbstractNode = populateComprehensionAst(currentAbstractNode, currentAttributes); break;
case Ast::ExceptionHandlerAstType: currentAbstractNode = populateExceptionHandlerAst(currentAbstractNode, currentAttributes); break;
case Ast::AliasAstType: currentAbstractNode = populateAliasAst(currentAbstractNode, currentAttributes); break;
case Ast::ExpressionAstType: currentAbstractNode = populateExpressionAst(currentAbstractNode, currentAttributes); break;
case Ast::StatementAstType: break; // ok
default: kWarning() << "Unsupported AST type: " << currentAbstractNode->astType; break;
}
// Walk through the tree and set proper end columns and lines, as the python parser sadly does not do this for us
if ( currentAbstractNode->hasUsefulRangeInformation ) {
Ast* parent = currentAbstractNode->parent;
while ( parent ) {
if ( parent->endLine < currentAbstractNode->endLine ) {
parent->endLine = currentAbstractNode->endLine;
parent->endCol = currentAbstractNode->endCol;
}
if ( ! parent->hasUsefulRangeInformation && parent->startLine == -5 ) {
parent->startLine = currentAbstractNode->startLine;
parent->startCol = currentAbstractNode->startCol;
}
parent = parent->parent;
}
}
}
}
}