See More

/*************************************************************************** * 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; } } } } }