File indexing completed on 2024-05-19 15:46:17

0001 /*
0002     SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "buildastvisitor.h"
0008 
0009 #include "qmakeast.h"
0010 #include "qmakeparser.h"
0011 #include "ast.h"
0012 
0013 #include <QScopedValueRollback>
0014 
0015 #include <debug.h>
0016 
0017 namespace QMake {
0018 
0019 void setIdentifierForStatement(StatementAST* stmt, ValueAST* val)
0020 {
0021     if (auto* orop = dynamic_cast<OrAST*>(stmt)) {
0022         setIdentifierForStatement(orop->scopes.at(0), val);
0023     } else if (auto* assign = dynamic_cast<AssignmentAST*>(stmt)) {
0024         assign->identifier = val;
0025     } else if (auto* funcall = dynamic_cast<FunctionCallAST*>(stmt)) {
0026         funcall->identifier = val;
0027     } else if (auto* simple = dynamic_cast<SimpleScopeAST*>(stmt)) {
0028         simple->identifier = val;
0029     }
0030 }
0031 
0032 BuildASTVisitor::BuildASTVisitor(Parser* parser, ProjectAST* project)
0033     : m_parser(parser)
0034 {
0035     aststack.push(project);
0036 }
0037 
0038 BuildASTVisitor::~BuildASTVisitor()
0039 {
0040     aststack.clear();
0041     m_parser = nullptr;
0042 }
0043 
0044 void BuildASTVisitor::visitArgumentList(ArgumentListAst* node)
0045 {
0046     // Nothing to be done here as we just need to iterate through the items
0047     DefaultVisitor::visitArgumentList(node);
0048 }
0049 
0050 void BuildASTVisitor::visitFunctionArguments(FunctionArgumentsAst* node)
0051 {
0052     // Nothing to be done here as we just need to iterate through the items
0053     DefaultVisitor::visitFunctionArguments(node);
0054 }
0055 
0056 void BuildASTVisitor::visitOrOperator(OrOperatorAst* node)
0057 {
0058     // Nothing to be done here as we just need to iterate through the items
0059     DefaultVisitor::visitOrOperator(node);
0060 }
0061 
0062 void BuildASTVisitor::visitItem(ItemAst* node)
0063 {
0064     if (node->functionArguments) {
0065         auto* call = createAst<FunctionCallAST>(node, aststack.top());
0066         auto* val = createAst<ValueAST>(node, call);
0067         val->value = getTokenString(node->id);
0068         setPositionForToken(node->id, val);
0069         call->identifier = val;
0070         auto* orast = stackTop<OrAST>();
0071         orast->scopes.append(call);
0072         aststack.push(call);
0073         DefaultVisitor::visitItem(node);
0074         aststack.pop();
0075     } else {
0076         auto* simple = createAst<SimpleScopeAST>(node, aststack.top());
0077         auto* val = createAst<ValueAST>(node, simple);
0078         val->value = getTokenString(node->id);
0079         setPositionForToken(node->id, val);
0080         simple->identifier = val;
0081         auto* orast = stackTop<OrAST>();
0082         orast->scopes.append(simple);
0083         DefaultVisitor::visitItem(node);
0084     }
0085 }
0086 
0087 void BuildASTVisitor::visitScope(ScopeAst* node)
0088 {
0089     if (node->orOperator) {
0090         auto* orast = createAst<OrAST>(node, aststack.top());
0091         // qCDebug(KDEV_QMAKE) << "created orast:" << orast;
0092         if (node->functionArguments) {
0093             auto* ast = createAst<FunctionCallAST>(node, orast);
0094             aststack.push(ast);
0095             // qCDebug(KDEV_QMAKE) << "creating function call as first or-op" << ast;
0096             visitNode(node->functionArguments);
0097             // qCDebug(KDEV_QMAKE) << "function call done";
0098             aststack.pop();
0099             orast->scopes.append(ast);
0100         } else {
0101             auto* simple = createAst<SimpleScopeAST>(node, orast);
0102             // qCDebug(KDEV_QMAKE) << "creating simple scope as first or-op";
0103             orast->scopes.append(simple);
0104         }
0105         aststack.push(orast);
0106         visitNode(node->orOperator);
0107     } else {
0108         if (node->functionArguments) {
0109             auto* call = createAst<FunctionCallAST>(node, aststack.top());
0110             aststack.push(call);
0111             visitNode(node->functionArguments);
0112         } else {
0113             auto* simple = createAst<SimpleScopeAST>(node, aststack.top());
0114             aststack.push(simple);
0115         }
0116     }
0117     if (node->ifElse) {
0118         auto* scopebody = createAst<ScopeBodyAST>(node, aststack.top());
0119         auto* scope = stackTop<ScopeAST>();
0120         scope->body = scopebody;
0121         aststack.push(scopebody);
0122         visitNode(node->ifElse);
0123         aststack.pop();
0124     }
0125 }
0126 
0127 void BuildASTVisitor::visitIfElse(IfElseAst* node)
0128 {
0129     auto* scopeBody = stackTop<ScopeBodyAST>();
0130     {
0131         auto guard = QScopedValueRollback(m_currentStatements, &scopeBody->ifStatements);
0132         visitNode(node->ifBody);
0133     }
0134     {
0135         auto guard = QScopedValueRollback(m_currentStatements, &scopeBody->elseStatements);
0136         visitNode(node->elseBody);
0137     }
0138 }
0139 
0140 void BuildASTVisitor::visitOp(OpAst* node)
0141 {
0142     auto* assign = stackTop<AssignmentAST>();
0143     auto* val = createAst<ValueAST>(node, assign);
0144     val->value = getTokenString(node->optoken);
0145     setPositionForToken(node->optoken, val);
0146     assign->op = val;
0147     DefaultVisitor::visitOp(node);
0148 }
0149 
0150 void BuildASTVisitor::visitProject(ProjectAst* node)
0151 {
0152     auto* project = stackTop<ProjectAST>();
0153     auto guard = QScopedValueRollback(m_currentStatements, &project->statements);
0154     DefaultVisitor::visitProject(node);
0155 }
0156 
0157 void BuildASTVisitor::visitScopeBody(ScopeBodyAst* node)
0158 {
0159     DefaultVisitor::visitScopeBody(node);
0160 }
0161 
0162 void BuildASTVisitor::visitStatement(StatementAst* node)
0163 {
0164     DefaultVisitor::visitStatement(node);
0165     if (!node->isNewline) {
0166         auto* stmt = stackPop<StatementAST>();
0167         // qCDebug(KDEV_QMAKE) << "got statement ast, setting value" << stmt;
0168         auto* val = createAst<ValueAST>(node, stmt);
0169         // qCDebug(KDEV_QMAKE) << "created value ast:" << val;
0170         val->value = getTokenString(node->id);
0171         // qCDebug(KDEV_QMAKE) << "set value" << val << val->value;
0172         setPositionForToken(node->id, val);
0173         if (node->isExclam) {
0174             // qCDebug(KDEV_QMAKE) << "found exclam";
0175             val->value = QLatin1Char('!') + val->value;
0176         }
0177         setIdentifierForStatement(stmt, val);
0178 
0179         m_currentStatements->append(stmt);
0180     }
0181 }
0182 
0183 void BuildASTVisitor::visitValue(ValueAst* node)
0184 {
0185     auto* assign = dynamic_cast<AssignmentAST*>(aststack.top());
0186     if (assign) {
0187         auto* value = createAst<ValueAST>(node, assign);
0188         value->value = getTokenString(node->value);
0189         assign->values.append(value);
0190     } else {
0191         auto* call = stackTop<FunctionCallAST>();
0192         auto* value = createAst<ValueAST>(node, call);
0193         value->value = getTokenString(node->value);
0194         setPositionForToken(node->value, value);
0195         call->args.append(value);
0196     }
0197     DefaultVisitor::visitValue(node);
0198 }
0199 
0200 void BuildASTVisitor::visitValueList(ValueListAst* node)
0201 {
0202     DefaultVisitor::visitValueList(node);
0203 }
0204 
0205 void BuildASTVisitor::visitVariableAssignment(VariableAssignmentAst* node)
0206 {
0207     auto* assign = createAst<AssignmentAST>(node, aststack.top());
0208     aststack.push(assign);
0209     DefaultVisitor::visitVariableAssignment(node);
0210 }
0211 
0212 template <typename T>
0213 T* BuildASTVisitor::createAst(AstNode* node, AST* parent)
0214 {
0215     if (!node) {
0216         return nullptr;
0217     }
0218     auto ast = new T(parent);
0219     setPositionForAst(node, ast);
0220     return ast;
0221 }
0222 
0223 template <typename T>
0224 T* BuildASTVisitor::stackTop()
0225 {
0226     if (aststack.isEmpty()) {
0227         qCDebug(KDEV_QMAKE);
0228         qCCritical(KDEV_QMAKE) << "ERROR: AST stack is empty, this should never happen";
0229         exit(255);
0230     }
0231     T* ast = dynamic_cast<T*>(aststack.top());
0232     if (!ast) {
0233         qCDebug(KDEV_QMAKE);
0234         qCCritical(KDEV_QMAKE) << "ERROR: AST stack is screwed, doing a hard exit" << aststack.top()->type;
0235         exit(255);
0236     }
0237     return ast;
0238 }
0239 
0240 template <typename T>
0241 T* BuildASTVisitor::stackPop()
0242 {
0243     if (aststack.isEmpty()) {
0244         qCDebug(KDEV_QMAKE);
0245         qCCritical(KDEV_QMAKE) << "ERROR: AST stack is empty, this should never happen";
0246         exit(255);
0247     }
0248     AST* tmp = aststack.pop();
0249     T* ast = dynamic_cast<T*>(tmp);
0250     if (!ast) {
0251         qCDebug(KDEV_QMAKE);
0252         qCCritical(KDEV_QMAKE) << "ERROR: AST stack is screwed, doing a hard exit" << tmp->type;
0253         exit(255);
0254     }
0255     return ast;
0256 }
0257 
0258 QString BuildASTVisitor::getTokenString(qint64 idx)
0259 {
0260     QMake::Parser::Token token = m_parser->tokenStream->at(idx);
0261     return m_parser->tokenText(token.begin, token.end).replace(QLatin1Char('\n'), QLatin1String("\\n"));
0262 }
0263 
0264 void BuildASTVisitor::setPositionForAst(AstNode* node, AST* ast)
0265 {
0266     qint64 line, col;
0267     m_parser->tokenStream->startPosition(node->startToken, &line, &col);
0268     ast->startLine = line;
0269     ast->startColumn = col;
0270     QMake::Parser::Token tok = m_parser->tokenStream->at(node->startToken);
0271     ast->start = tok.begin;
0272     m_parser->tokenStream->endPosition(node->endToken, &line, &col);
0273     ast->endLine = line;
0274     ast->endColumn = col;
0275     tok = m_parser->tokenStream->at(node->endToken);
0276     ast->end = tok.end;
0277 }
0278 
0279 void BuildASTVisitor::setPositionForToken(qint64 idx, ValueAST* ast)
0280 {
0281     qint64 line, col;
0282     QMake::Parser::Token token = m_parser->tokenStream->at(idx);
0283     m_parser->tokenStream->startPosition(idx, &line, &col);
0284     ast->startLine = line;
0285     ast->startColumn = col;
0286     ast->start = token.begin;
0287     ast->end = token.end;
0288     m_parser->tokenStream->endPosition(idx, &line, &col);
0289     ast->endLine = line;
0290     ast->endColumn = col;
0291 }
0292 }