File indexing completed on 2024-04-28 05:49:16
0001 /*************************************************************************** 0002 julia_parser.cpp - 0003 Kate parser for Julia files to use with Kate's Symbol viewer plugin. 0004 ------------------- 0005 begin : Feb 25 2023 0006 author : 2023 Cezar Tigaret 0007 email : cezar.tigaret@gmail.com 0008 ***************************************************************************/ 0009 /*************************************************************************** 0010 * * 0011 * SPDX-FileCopyrightText: 2023 Cezar M. Tigaret <cezar.tigaret@gmail.com> 0012 * SPDX-License-Identifier: LGPL-2.0-or-later 0013 * * 0014 ***************************************************************************/ 0015 #include "plugin_katesymbolviewer.h" 0016 0017 #include <KTextEditor/Document> 0018 0019 enum class Type { Function, Structure, Macro, Method }; 0020 0021 void KatePluginSymbolViewerView::parseJuliaSymbols(void) 0022 { 0023 if (!m_mainWindow->activeView()) { 0024 return; 0025 } 0026 0027 m_macro->setText(i18n("Show Macros")); 0028 m_struct->setText(i18n("Show Structures")); 0029 m_func->setText(i18n("Show Functions")); 0030 0031 bool commentLine = false; 0032 bool terseFunctionExpresion = false; 0033 0034 Type type; 0035 QString name; 0036 QString module_name; 0037 QString params; 0038 QString paramsSubstr; 0039 QString terseFuncAssignment; 0040 QString whereStmt; 0041 QString current_class_name; 0042 QString mutable_kw; 0043 QString lastControl; 0044 0045 QTreeWidgetItem *node = nullptr; 0046 QTreeWidgetItem *functionNode = nullptr, *mtdNode = nullptr, *clsNode = nullptr; 0047 QTreeWidgetItem *lastMcrNode = nullptr, *lastMtdNode = nullptr, *lastClsNode = nullptr; 0048 QTreeWidgetItem *macroNode = nullptr; 0049 QTreeWidgetItem *lastMacroNode = nullptr; 0050 0051 KTextEditor::Document *kv = m_mainWindow->activeView()->document(); 0052 0053 if (m_treeOn->isChecked()) { 0054 clsNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Structures"))); 0055 functionNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Functions"))); 0056 macroNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Macros"))); 0057 0058 functionNode->setIcon(0, m_icon_function); 0059 clsNode->setIcon(0, m_icon_class); 0060 macroNode->setIcon(0, m_icon_context); 0061 0062 if (m_expandOn->isChecked()) { 0063 m_symbols->expandItem(functionNode); 0064 m_symbols->expandItem(clsNode); 0065 m_symbols->expandItem(macroNode); 0066 } 0067 lastClsNode = clsNode; 0068 lastMcrNode = functionNode; 0069 lastMacroNode = macroNode; 0070 mtdNode = clsNode; 0071 lastMtdNode = clsNode; 0072 m_symbols->setRootIsDecorated(1); 0073 } else { 0074 m_symbols->setRootIsDecorated(0); 0075 } 0076 0077 static const QString contStr(QChar(0x21b5)); 0078 // static const QString contStr(0x21b5); 0079 0080 static const QRegularExpression comment_regexp(QLatin1String("[#]"), QRegularExpression::UseUnicodePropertiesOption); 0081 static const QRegularExpression ml_docsctring_regexp(QLatin1String("\"\"\""), QRegularExpression::UseUnicodePropertiesOption); 0082 static const QRegularExpression sl_docstring_regexp(QLatin1String("\"\"\"(.*)?\"\"\""), QRegularExpression::UseUnicodePropertiesOption); 0083 0084 static const QRegularExpression class_regexp(QLatin1String("(@[a-zA-Z0-9_\\s]+)?(?:struct|mutable\\s+struct)\\s+([\\w!a-zA-Z0-9_.]+)"), 0085 QRegularExpression::UseUnicodePropertiesOption); 0086 0087 static const QRegularExpression function_regexp( 0088 QLatin1String("(@[a-zA-Z0-9_\\s]+)?function\\s+([\\w:!.]+)\\s*(\\(.*[,;:\\{\\}\\s]*\\)?\\s*)?$( where [\\w:<>=.\\{\\}]*\\s?$)?"), 0089 QRegularExpression::UseUnicodePropertiesOption); 0090 0091 static const QRegularExpression terse_function_regexp( 0092 QLatin1String( 0093 "^(@[a-zA-Z0-9_\\s]+ )?([\\w:.]+)?([\\w:\\{\\}!]+)(\\s?)(\\(.*[\\),;\\s]*\\))(\\s?)(where [\\w:<>.,\\s\\{\\}a-zA-Z0-9]*\\s?)?(\\s?)\\s*=\\s*(.*)$"), 0094 QRegularExpression::UseUnicodePropertiesOption); 0095 0096 static const QRegularExpression macro_regexp(QLatin1String("^macro ([\\w:\\{\\}!]+)(\\s*)(\\(.*\\))?"), QRegularExpression::UseUnicodePropertiesOption); 0097 0098 static const QRegularExpression assert_regexp(QLatin1String("@assert")); 0099 0100 QRegularExpressionMatch match; 0101 0102 for (int i = 0; i < kv->lines(); i++) { 0103 int line = i; 0104 int indexOfHash = -1; 0105 QString cl = kv->line(i); 0106 if (cl.isEmpty()) { 0107 continue; 0108 } 0109 0110 // concatenate continued lines and remove continuation marker (from python_parser.cpp) 0111 while (cl[cl.length() - 1] == QLatin1Char('\\')) { 0112 cl = cl.left(cl.length() - 1); 0113 i++; 0114 if (i < kv->lines()) { 0115 cl += kv->line(i); 0116 } else { 0117 break; 0118 } 0119 if (cl.isEmpty()) { 0120 break; 0121 } 0122 } 0123 0124 QString cl_sp = cl.simplified(); 0125 0126 // strip away comments 0127 indexOfHash = cl_sp.indexOf(QLatin1Char('#')); 0128 if (indexOfHash > 0) { 0129 cl_sp = cl_sp.left(indexOfHash - 1); 0130 } else if (indexOfHash == 0) { 0131 continue; 0132 } 0133 // skip asserts 0134 match = assert_regexp.match(cl_sp); 0135 0136 if (match.hasMatch()) { 0137 continue; 0138 } 0139 0140 // skip # comments 0141 match = comment_regexp.match(cl_sp); 0142 0143 if (match.hasMatch()) { 0144 continue; 0145 } 0146 0147 // BEGIN skip doc strings """ ... """ or """ 0148 // """ 0149 // 0150 match = ml_docsctring_regexp.match(cl_sp); // match """ anywhere 0151 0152 if (match.hasMatch()) { 0153 match = sl_docstring_regexp.match(cl_sp); 0154 if (match.hasMatch()) { 0155 commentLine = false; 0156 continue; 0157 0158 } else { 0159 commentLine = !commentLine; 0160 continue; 0161 } 0162 } else { 0163 match = sl_docstring_regexp.match(cl_sp); 0164 if (match.hasMatch()) { 0165 commentLine = false; 0166 continue; 0167 } 0168 } 0169 0170 if (commentLine) { 0171 continue; 0172 } 0173 // END skip doc strings (""" ... """) 0174 0175 terseFunctionExpresion = false; 0176 0177 whereStmt.clear(); 0178 0179 match = class_regexp.match(cl_sp); 0180 0181 if (match.hasMatch()) { 0182 type = Type::Structure; 0183 0184 } else { 0185 match = macro_regexp.match(cl_sp); 0186 if (match.hasMatch()) { 0187 type = Type::Macro; 0188 } else { 0189 match = function_regexp.match(cl_sp); 0190 if (match.hasMatch()) { 0191 type = Type::Function; 0192 } else { 0193 match = terse_function_regexp.match(cl_sp); 0194 if (match.hasMatch()) { 0195 type = Type::Function; 0196 terseFunctionExpresion = true; 0197 } else { 0198 continue; 0199 } 0200 } 0201 } 0202 } 0203 0204 if (match.hasMatch()) { 0205 // either Structure, Macro, or Function egexp have matched 0206 if (type == Type::Structure) { 0207 name = match.captured(2); 0208 current_class_name = name; 0209 params.clear(); 0210 } else { 0211 if (type == Type::Function) { 0212 if (terseFunctionExpresion) { 0213 terseFuncAssignment = match.captured(9); 0214 whereStmt = match.captured(7); 0215 if (!terseFuncAssignment.isEmpty()) { 0216 module_name = match.captured(2); // useful when overloading a function from other module (in Julia that's typically 'adding' a 0217 // method to the overloaded function <-> function dispatch mechanism) 0218 name = match.captured(3); 0219 if (!module_name.isEmpty()) { 0220 name = module_name + name; 0221 } 0222 params = match.captured(5); 0223 0224 if (!whereStmt.isEmpty()) { 0225 params += QLatin1String(" "); 0226 params += whereStmt; 0227 } 0228 0229 } else { 0230 continue; 0231 } 0232 0233 } else { 0234 name = match.captured(2); 0235 params = match.captured(3); 0236 whereStmt = match.captured(4); 0237 } 0238 0239 } else if (type == Type::Macro) { 0240 name = match.captured(1); 0241 params = match.captured(3); 0242 } else { 0243 continue; 0244 } 0245 0246 if (!params.isEmpty() && !params.endsWith(QLatin1String(")"))) { 0247 if (!terseFunctionExpresion) { 0248 if (whereStmt.isEmpty() && !params.contains(QLatin1String("where"))) { 0249 params += QLatin1Char(' '); 0250 params += contStr; 0251 0252 } else { 0253 params += QLatin1String(" "); 0254 params += whereStmt; 0255 whereStmt.clear(); 0256 } 0257 } 0258 } 0259 } 0260 0261 if (m_typesOn->isChecked()) { 0262 name += params; 0263 } 0264 0265 if (m_func->isChecked() && type == Type::Structure) { 0266 if (m_treeOn->isChecked()) { 0267 node = new QTreeWidgetItem(clsNode, lastClsNode); 0268 if (m_expandOn->isChecked()) { 0269 m_symbols->expandItem(node); 0270 } 0271 lastClsNode = node; 0272 mtdNode = lastClsNode; 0273 lastMtdNode = lastClsNode; 0274 } else { 0275 node = new QTreeWidgetItem(m_symbols); 0276 } 0277 0278 node->setText(0, name); 0279 node->setIcon(0, m_icon_class); 0280 node->setText(1, QString::number(line, 10)); 0281 } 0282 0283 if (m_struct->isChecked() && type == Type::Method) { 0284 if (m_treeOn->isChecked()) { 0285 node = new QTreeWidgetItem(mtdNode, lastMtdNode); 0286 lastMtdNode = node; 0287 } else { 0288 node = new QTreeWidgetItem(m_symbols); 0289 } 0290 0291 node->setText(0, name); 0292 node->setIcon(0, m_icon_function); 0293 node->setText(1, QString::number(line, 10)); 0294 } 0295 0296 if (m_macro->isChecked() && type == Type::Function) { 0297 if (m_treeOn->isChecked()) { 0298 node = new QTreeWidgetItem(functionNode, lastMcrNode); 0299 lastMcrNode = node; 0300 } else { 0301 node = new QTreeWidgetItem(m_symbols); 0302 } 0303 0304 node->setText(0, name); 0305 node->setIcon(0, m_icon_function); 0306 node->setText(1, QString::number(line, 10)); 0307 } 0308 0309 if (m_macro->isChecked() && type == Type::Macro) { 0310 if (m_treeOn->isChecked()) { 0311 node = new QTreeWidgetItem(macroNode, lastMacroNode); 0312 lastMacroNode = node; 0313 } else { 0314 node = new QTreeWidgetItem(m_symbols); 0315 } 0316 0317 node->setText(0, name); 0318 node->setIcon(0, m_icon_function); 0319 node->setText(1, QString::number(line, 10)); 0320 } 0321 0322 name.clear(); 0323 params.clear(); 0324 } 0325 } 0326 }