File indexing completed on 2024-05-19 04:41:35
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 }