mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-20 11:26:11 +00:00
641 lines
16 KiB
C++
641 lines
16 KiB
C++
#include "scriptsyntax.h"
|
|
#include <QFile>
|
|
|
|
SyntaxTreeNode::SyntaxTreeNode(const QVector<QVariant> &data, SyntaxTreeNode *parent)
|
|
{
|
|
parentItem = parent;
|
|
itemData = data;
|
|
}
|
|
|
|
SyntaxTreeNode::~SyntaxTreeNode()
|
|
{
|
|
qDeleteAll(childItems);
|
|
}
|
|
|
|
SyntaxTreeNode *SyntaxTreeNode::child(int number)
|
|
{
|
|
return childItems.value(number);
|
|
}
|
|
|
|
int SyntaxTreeNode::childCount() const
|
|
{
|
|
return childItems.count();
|
|
}
|
|
|
|
int SyntaxTreeNode::childNumber() const
|
|
{
|
|
if (parentItem)
|
|
return parentItem->childItems.indexOf(const_cast<SyntaxTreeNode*>(this));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SyntaxTreeNode::columnCount() const
|
|
{
|
|
return itemData.count();
|
|
}
|
|
|
|
QVariant SyntaxTreeNode::data(int column) const
|
|
{
|
|
return itemData.value(column);
|
|
}
|
|
|
|
bool SyntaxTreeNode::insertChildren(int position, int count, int columns)
|
|
{
|
|
if (position < 0 || position > childItems.size())
|
|
return false;
|
|
|
|
for (int row = 0; row < count; ++row)
|
|
{
|
|
QVector<QVariant> dt(columns);
|
|
for(int ii = 0;ii < columns;++ii)
|
|
dt[ii] = QVariant(this->data(ii).type());
|
|
SyntaxTreeNode *item = new SyntaxTreeNode(dt, this);
|
|
childItems.insert(position, item);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SyntaxTreeNode::insertColumns(int position, int columns)
|
|
{
|
|
if (position < 0 || position > itemData.size())
|
|
return false;
|
|
|
|
for (int column = 0; column < columns; ++column)
|
|
itemData.insert(position, QVariant());
|
|
|
|
foreach (SyntaxTreeNode *child, childItems)
|
|
child->insertColumns(position, columns);
|
|
|
|
return true;
|
|
}
|
|
|
|
SyntaxTreeNode *SyntaxTreeNode::parent()
|
|
{
|
|
return parentItem;
|
|
}
|
|
|
|
bool SyntaxTreeNode::removeChildren(int position, int count)
|
|
{
|
|
if (position < 0 || position + count > childItems.size())
|
|
return false;
|
|
|
|
for (int row = 0; row < count; ++row)
|
|
delete childItems.takeAt(position);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SyntaxTreeNode::removeColumns(int position, int columns)
|
|
{
|
|
if (position < 0 || position + columns > itemData.size())
|
|
return false;
|
|
|
|
for (int column = 0; column < columns; ++column)
|
|
itemData.remove(position);
|
|
|
|
foreach (SyntaxTreeNode *child, childItems)
|
|
child->removeColumns(position, columns);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SyntaxTreeNode::setData(int column, const QVariant &value)
|
|
{
|
|
if (column < 0 || column >= itemData.size())
|
|
return false;
|
|
|
|
itemData[column] = value;
|
|
return true;
|
|
}
|
|
|
|
SyntaxTreeNode* SyntaxTreeNode::findChild( const QVector<QVariant>& data )
|
|
{
|
|
SyntaxTreeNode* ch = NULL;
|
|
int ind = 0;
|
|
while ((ch == NULL) && (ind < childCount()))
|
|
{
|
|
SyntaxTreeNode* tmp = child(ind);
|
|
bool equal = true;
|
|
int ii = 0;
|
|
while(equal && (ii < tmp->columnCount()))
|
|
{
|
|
equal = (tmp->data(ii) == data[ii]);
|
|
++ii;
|
|
}
|
|
if (equal)
|
|
ch = tmp;
|
|
else
|
|
++ind;
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
SyntaxTreeModel::SyntaxTreeModel(SyntaxTreeNode* root,QObject *parent)
|
|
:QAbstractItemModel(parent),rootItem(root)
|
|
{
|
|
}
|
|
|
|
SyntaxTreeModel::~SyntaxTreeModel()
|
|
{
|
|
delete rootItem;
|
|
}
|
|
|
|
int SyntaxTreeModel::columnCount(const QModelIndex & /* parent */) const
|
|
{
|
|
return rootItem->columnCount();
|
|
}
|
|
|
|
QVariant SyntaxTreeModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
if (role != Qt::DisplayRole && role != Qt::EditRole)
|
|
return QVariant();
|
|
|
|
SyntaxTreeNode *item = getItem(index);
|
|
|
|
return item->data(index.column());
|
|
}
|
|
|
|
Qt::ItemFlags SyntaxTreeModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return 0;
|
|
|
|
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
}
|
|
|
|
SyntaxTreeNode *SyntaxTreeModel::getItem(const QModelIndex &index) const
|
|
{
|
|
if (index.isValid()) {
|
|
SyntaxTreeNode *item = static_cast<SyntaxTreeNode*>(index.internalPointer());
|
|
if (item) return item;
|
|
}
|
|
return rootItem;
|
|
}
|
|
|
|
QVariant SyntaxTreeModel::headerData(int section, Qt::Orientation orientation,
|
|
int role) const
|
|
{
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
|
return rootItem->data(section);
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QModelIndex SyntaxTreeModel::index(int row, int column, const QModelIndex &parent) const
|
|
{
|
|
if (parent.isValid() && parent.column() != 0)
|
|
return QModelIndex();
|
|
|
|
SyntaxTreeNode *parentItem = getItem(parent);
|
|
|
|
SyntaxTreeNode *childItem = parentItem->child(row);
|
|
if (childItem)
|
|
return createIndex(row, column, childItem);
|
|
else
|
|
return QModelIndex();
|
|
}
|
|
|
|
bool SyntaxTreeModel::insertColumns(int position, int columns, const QModelIndex &parent)
|
|
{
|
|
bool success;
|
|
|
|
beginInsertColumns(parent, position, position + columns - 1);
|
|
success = rootItem->insertColumns(position, columns);
|
|
endInsertColumns();
|
|
|
|
return success;
|
|
}
|
|
|
|
bool SyntaxTreeModel::insertRows(int position, int rows, const QModelIndex &parent)
|
|
{
|
|
SyntaxTreeNode *parentItem = getItem(parent);
|
|
bool success;
|
|
|
|
beginInsertRows(parent, position, position + rows - 1);
|
|
success = parentItem->insertChildren(position, rows, rootItem->columnCount());
|
|
endInsertRows();
|
|
|
|
return success;
|
|
}
|
|
|
|
QModelIndex SyntaxTreeModel::parent(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return QModelIndex();
|
|
|
|
SyntaxTreeNode *childItem = getItem(index);
|
|
SyntaxTreeNode *parentItem = childItem->parent();
|
|
|
|
if (parentItem == rootItem)
|
|
return QModelIndex();
|
|
|
|
return createIndex(parentItem->childNumber(), 0, parentItem);
|
|
}
|
|
|
|
bool SyntaxTreeModel::removeColumns(int position, int columns, const QModelIndex &parent)
|
|
{
|
|
bool success;
|
|
|
|
beginRemoveColumns(parent, position, position + columns - 1);
|
|
success = rootItem->removeColumns(position, columns);
|
|
endRemoveColumns();
|
|
|
|
if (rootItem->columnCount() == 0)
|
|
removeRows(0, rowCount());
|
|
|
|
return success;
|
|
}
|
|
|
|
bool SyntaxTreeModel::removeRows(int position, int rows, const QModelIndex &parent)
|
|
{
|
|
SyntaxTreeNode *parentItem = getItem(parent);
|
|
bool success = true;
|
|
|
|
beginRemoveRows(parent, position, position + rows - 1);
|
|
success = parentItem->removeChildren(position, rows);
|
|
endRemoveRows();
|
|
|
|
return success;
|
|
}
|
|
|
|
int SyntaxTreeModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
SyntaxTreeNode *parentItem = getItem(parent);
|
|
|
|
return parentItem->childCount();
|
|
}
|
|
|
|
bool SyntaxTreeModel::setData(const QModelIndex &index, const QVariant &value,
|
|
int role)
|
|
{
|
|
if (role != Qt::EditRole)
|
|
return false;
|
|
|
|
SyntaxTreeNode *item = getItem(index);
|
|
bool result = item->setData(index.column(), value);
|
|
|
|
if (result)
|
|
emit dataChanged(index, index);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool SyntaxTreeModel::setHeaderData(int section, Qt::Orientation orientation,
|
|
const QVariant &value, int role)
|
|
{
|
|
if (role != Qt::EditRole || orientation != Qt::Horizontal)
|
|
return false;
|
|
|
|
bool result = rootItem->setData(section, value);
|
|
|
|
if (result)
|
|
emit headerDataChanged(orientation, section, section);
|
|
|
|
return result;
|
|
}
|
|
|
|
//void SyntaxTreeModel::addCompleteSubTree(const QStringList &signatures)
|
|
//{
|
|
// QStringList signs = signatures;
|
|
// foreach(QString sg,signs)
|
|
// createAndAppendBranch(sg,rootItem);
|
|
//}
|
|
|
|
//void SyntaxTreeModel::createAndAppendBranch( QString& st,SyntaxTree* parent )
|
|
//{
|
|
// if (st.isEmpty() || (parent == NULL))
|
|
// return;
|
|
// QVector<QVariant> dt;
|
|
// int indexpoint = st.indexOf(".");
|
|
// if (indexpoint == -1)
|
|
// {
|
|
// int indexpar = st.indexOf("(");
|
|
// if (indexpar == -1)
|
|
// {
|
|
// //is a member
|
|
// dt << st;
|
|
// }
|
|
// else
|
|
// {
|
|
// //is a function. I will add the name of the function and the signature for the tooltip
|
|
// dt << st.left(indexpar)/* << st*/;
|
|
// }
|
|
// AutoCompleterItem* ch = parent->findChild(dt);
|
|
// //Search if the node is already in the tree
|
|
// if (ch == NULL)
|
|
// {
|
|
// ch = new AutoCompleterItem(dt,parent);
|
|
// parent->appendChild(ch);
|
|
// }
|
|
// return;
|
|
// }
|
|
// else
|
|
// {
|
|
// //+1 so I will take also the .
|
|
// QString tmp = st.left(indexpoint + 1);
|
|
// st.remove(tmp);
|
|
// tmp.remove(".");
|
|
// dt << tmp;
|
|
// int ind = 0;
|
|
//
|
|
// AutoCompleterItem* ch = parent->findChild(dt);
|
|
// //Search if the node is already in the tree
|
|
// if (ch == NULL)
|
|
// {
|
|
// ch = new AutoCompleterItem(dt,parent);
|
|
// parent->appendChild(ch);
|
|
// }
|
|
// createAndAppendBranch(st,ch);
|
|
// }
|
|
//}
|
|
|
|
MLScriptLanguage::MLScriptLanguage()
|
|
:reserved(),langfuncs(),worddelimiter(),wordsjoiner(),openpar(),closepar(),libraries()
|
|
{
|
|
initLibrary();
|
|
}
|
|
|
|
|
|
|
|
const SyntaxTreeModel* MLScriptLanguage::functionsLibrary() const
|
|
{
|
|
return libraries;
|
|
}
|
|
|
|
SyntaxTreeModel* MLScriptLanguage::functionsLibrary()
|
|
{
|
|
return libraries;
|
|
}
|
|
|
|
void MLScriptLanguage::addLibrary( const QList<LibraryElementInfo>& funsigns )
|
|
{
|
|
if (libraries != NULL)
|
|
{
|
|
SyntaxTreeNode* root = libraries->getItem(QModelIndex());
|
|
foreach(LibraryElementInfo st,funsigns)
|
|
addBranch(st,root);
|
|
}
|
|
}
|
|
|
|
void MLScriptLanguage::addBranch( const LibraryElementInfo& mi,SyntaxTreeNode* parent )
|
|
{
|
|
if (mi.completename.isEmpty() || (parent == NULL))
|
|
return;
|
|
QString st = mi.completename;
|
|
QVector<QVariant> dt(5,QVariant(QString()));
|
|
int indexpoint = st.indexOf(wordsjoiner);
|
|
if (indexpoint == -1)
|
|
{
|
|
int indexpar = st.indexOf(openpar);
|
|
if (indexpar == -1)
|
|
{
|
|
//is a member
|
|
dt[0] = st;
|
|
dt[1] = mi.help;
|
|
dt[4] = QString::number(MLScriptLanguage::MEMBERFIELD);
|
|
}
|
|
else
|
|
{
|
|
//is a function. I will add the name of the function and the signature for the tooltip
|
|
dt[0] = st.left(indexpar);
|
|
dt[1] = mi.help;
|
|
dt[3] = st;
|
|
dt[4] = QString::number(MLScriptLanguage::FUNCTION);
|
|
}
|
|
SyntaxTreeNode* ch = parent->findChild(dt);
|
|
|
|
//Search if the node is already in the tree
|
|
if (ch == NULL)
|
|
{
|
|
parent->insertChildren(parent->childCount(),1,parent->columnCount());
|
|
ch = parent->child(parent->childCount() - 1);
|
|
for(int ii = 0;ii < 5;++ii)
|
|
ch->setData(ii,dt[ii]);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//+1 so I will take also the sep
|
|
QString tmp = st.left(indexpoint + 1);
|
|
st.remove(tmp);
|
|
QString specificsep = wordsjoiner.cap();
|
|
tmp.remove(wordsjoiner);
|
|
dt[0] = tmp;
|
|
dt[2] = specificsep;
|
|
dt[4] = QString::number(MLScriptLanguage::NAMESPACE);
|
|
SyntaxTreeNode* ch = parent->findChild(dt);
|
|
//Search if the node is already in the tree
|
|
if (ch == NULL)
|
|
{
|
|
parent->insertChildren(parent->childCount(),1,parent->columnCount());
|
|
ch = parent->child(parent->childCount() - 1);
|
|
for(int ii = 0;ii < 5;++ii)
|
|
ch->setData(ii,dt[ii]);
|
|
}
|
|
LibraryElementInfo minext;
|
|
minext.completename = st;
|
|
minext.help = mi.help;
|
|
addBranch(minext,ch);
|
|
}
|
|
}
|
|
|
|
MLScriptLanguage::~MLScriptLanguage()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
QString MLScriptLanguage::getExternalLibrariesCode()
|
|
{
|
|
QString code;
|
|
QList<ExternalLib*> liblist = this->scriptLibraryFiles();
|
|
for(int ii = 0;ii <liblist.size();++ii)
|
|
code += liblist[ii]->libCode();
|
|
return code;
|
|
}
|
|
|
|
void MLScriptLanguage::initLibrary()
|
|
{
|
|
delete libraries;
|
|
QVector<QVariant> v;
|
|
v.push_back("partial function ID");
|
|
v.push_back("help");
|
|
v.push_back("separator");
|
|
v.push_back("signature");
|
|
v.push_back("token");
|
|
SyntaxTreeNode* root = new SyntaxTreeNode(v,NULL);
|
|
libraries = new SyntaxTreeModel(root,NULL);
|
|
}
|
|
|
|
QList<LibraryElementInfo> MLScriptLanguage::getExternalLibrariesMembersInfo() const
|
|
{
|
|
QList<LibraryElementInfo> res;
|
|
QList<ExternalLib*> liblist = this->scriptLibraryFiles();
|
|
for(int ii = 0;ii <liblist.size();++ii)
|
|
res.append(liblist[ii]->libraryMembersInfo());
|
|
return res;
|
|
}
|
|
|
|
QRegExp MLScriptLanguage::matchIdentifiersButNotReservedWords() const
|
|
{
|
|
QString res = reserved.join("|");
|
|
QRegExp name("([a-z]|[A-Z])+\\w*");
|
|
QRegExp nokey("\\b(?!(?:" + res + ")\\b)");
|
|
return QRegExp(nokey.pattern() + name.pattern() + "\\b(\\s*" + wordsjoiner.pattern() + "\\s*" + nokey.pattern() + name.pattern() + "\\b)*");
|
|
}
|
|
|
|
QRegExp MLScriptLanguage::matchOnlyReservedWords() const
|
|
{
|
|
QString res = reserved.join("|");
|
|
return QRegExp("\\b(" + res + ")\\b");
|
|
}
|
|
|
|
QRegExp MLScriptLanguage::joinedWordExpression() const
|
|
{
|
|
//*\\*/(\\(\\w*\\))?
|
|
QRegExp parameter("(\\w*|\\d*(\\.\\d+)*)");
|
|
QRegExp parameterlist(parameter.pattern() + "(\\s*,\\s*" + parameter.pattern() + ")*");
|
|
QRegExp name("([a-z]|[A-Z])+\\w*(\\(" + parameterlist.pattern() + "\\))?");
|
|
QString st(name.pattern() + "(\\s*" + wordsjoiner.pattern() +"\\s*|\\s*" + wordsjoiner.pattern() +"\\s*" + name.pattern() + ")*");
|
|
return QRegExp(st);
|
|
|
|
}
|
|
|
|
JavaScriptLanguage::JavaScriptLanguage()
|
|
:MLScriptLanguage()
|
|
{
|
|
//HighlightingRule res;
|
|
//res.format.setForeground(Qt::darkBlue);
|
|
//res.format.setFontWeight(QFont::Bold);
|
|
wordsjoiner.setPattern("\\.");
|
|
openpar.setPattern("\\(");
|
|
closepar.setPattern("\\)");
|
|
reserved << "break";
|
|
reserved << "case";
|
|
reserved << "catch";
|
|
reserved << "continue";
|
|
reserved << "default";
|
|
reserved << "delete";
|
|
reserved << "do";
|
|
reserved << "else";
|
|
reserved << "finally";
|
|
reserved << "for";
|
|
reserved << "function";
|
|
reserved << "if";
|
|
reserved << "in";
|
|
reserved << "instanceof";
|
|
reserved << "new";
|
|
reserved << "return";
|
|
reserved << "switch";
|
|
reserved << "this";
|
|
reserved << "throw";
|
|
reserved << "try";
|
|
reserved << "typeof";
|
|
reserved << "var";
|
|
reserved << "void";
|
|
reserved << "while";
|
|
reserved << "with";
|
|
reserved << "true";
|
|
reserved << "false";
|
|
reserved << "null";
|
|
|
|
worddelimiter.setPattern("[\\s|\\t|\\n|\\r|=|;|,|\\(|\\)|{|}|\\[|\\]|\\||\\&|\\?|\\!|\\+|\\*|\\\\|\\-|%|\"|<|>]");
|
|
|
|
//foreach(QString st,reserved)
|
|
//{
|
|
// res.pattern = QRegExp(st);
|
|
// highlightingRules << res;
|
|
//}
|
|
|
|
//autoCompleteModel(mod);
|
|
////comp.setModel(&ls);
|
|
//comp.setCaseSensitivity(Qt::CaseSensitive);
|
|
//comp.setWidget(parent);
|
|
//comp.setCompletionMode(QCompleter::PopupCompletion);
|
|
//comp.setModel(&mod);
|
|
}
|
|
|
|
const QList<ExternalLib*> JavaScriptLanguage::scriptLibraryFiles() const
|
|
{
|
|
QList<ExternalLib*> res;
|
|
SGLMathLib* lib = new SGLMathLib();
|
|
res << lib;
|
|
return res;
|
|
}
|
|
|
|
//QStringList JavaScriptLanguage::splitLineInWords( const QStringList& line )
|
|
//{
|
|
// //Regular expression matching all the identifiers but not keywords
|
|
// QRegExp exp = matchIdentifiersButNotReservedWords();
|
|
// int index = 0;
|
|
// while (index >= 0)
|
|
// {
|
|
// line
|
|
// }
|
|
//}
|
|
|
|
QString ExternalLib::libCode() const
|
|
{
|
|
QFile lib(name);
|
|
if (!lib.open(QFile::ReadOnly))
|
|
qDebug("Warning: Library %s has not been loaded.",qPrintable(name));
|
|
QByteArray libcode = lib.readAll();
|
|
/*QScriptValue res = env.evaluate(QString(libcode));
|
|
if (res.isError())
|
|
throw JavaScriptException("Library " + liblist[ii] + " generated a JavaScript Error: " + res.toString() + "\n");*/
|
|
return QString(libcode);
|
|
}
|
|
|
|
ExternalLib::ExternalLib( const QString& filename )
|
|
:name(filename)
|
|
{
|
|
}
|
|
|
|
SGLMathLib::SGLMathLib()
|
|
:ExternalLib(":/script_system/math.js")
|
|
{
|
|
|
|
}
|
|
|
|
QList<LibraryElementInfo> SGLMathLib::libraryMembersInfo() const
|
|
{
|
|
QString code = libCode();
|
|
QList<LibraryElementInfo> res;
|
|
int index = 0;
|
|
QRegExp parameter("\\w*");
|
|
QRegExp parameterlist(parameter.pattern() + "(\\s*,\\s*" + parameter.pattern() + ")*");
|
|
QRegExp namespacelist(parameter.pattern() + "(\\s*\\.\\s*" + parameter.pattern() + ")*\\$?");
|
|
QRegExp help("/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/");
|
|
QRegExp exp("(" + help.pattern() + ")?" + "\\s*" + namespacelist.pattern() + "\\s*=\\s*function\\s*\\(" + parameterlist.pattern() + "\\)");
|
|
int ii = 0;
|
|
do
|
|
{
|
|
index = code.indexOf(exp,index) + exp.matchedLength();
|
|
if (index >= 0)
|
|
{
|
|
QString fun = exp.cap();
|
|
LibraryElementInfo mi;
|
|
int helpind = fun.indexOf(help);
|
|
if (helpind >= 0)
|
|
{
|
|
mi.help = help.cap();
|
|
mi.help.remove(QRegExp("\\*\\s+\\n"));
|
|
fun.remove(help.cap());
|
|
}
|
|
fun.remove(QRegExp("\\s*")).remove("=").remove("function");
|
|
mi.completename = fun;
|
|
res << mi;
|
|
++ii;
|
|
}
|
|
}while(index >= 0);
|
|
return res;
|
|
}
|
|
|
|
|