You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdewebdev/quanta/parsers/sagroupparser.cpp

312 lines
12 KiB

/***************************************************************************
sagroupparser.cpp - description
-------------------
begin : Wed Feb 11 2004
copyright : (C) 2004 Andras Mantia <amantia@kde.org>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
//qt includes
#include <tqtimer.h>
#include <tqvaluelist.h>
//kde includes
#include <kdebug.h>
#include <kdirwatch.h>
#include <kurl.h>
//own includes
#include "sagroupparser.h"
#include "saparser.h"
#include "document.h"
#include "node.h"
#include "parsercommon.h"
#include "qextfileinfo.h"
#include "quantacommon.h"
#include "resource.h"
#include "tag.h"
extern GroupElementMapList globalGroupMap;
SAGroupParser::SAGroupParser(SAParser *parent, Document *write, Node *startNode, Node *endNode, bool synchronous, bool parsingLastNode, bool paringLastGroup)
{
g_node = startNode;
g_endNode = endNode;
m_synchronous = synchronous;
m_lastGroupParsed = paringLastGroup;
m_parsingLastNode = parsingLastNode;
m_parent = parent;
m_write = write;
m_count = 0;
m_parseForGroupTimer = new TQTimer(this);
connect(m_parseForGroupTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotParseForScriptGroup()));
}
void SAGroupParser::slotParseForScriptGroup()
{
#ifdef DEBUG_PARSER
//kdDebug(24001) << "slotParseForScriptGroup. Synch: " << m_synchronous << endl;
#endif
if ((m_parent && !m_parent->parsingEnabled()) || (!baseNode && !m_synchronous))
{
#ifdef DEBUG_PARSER
kdDebug(24001) << "slotParseForScriptGroup aborted. Synch: " << m_synchronous << endl;
#endif
return;
}
if (g_node && g_node != g_endNode )
{
if (g_node->tag && (g_node->tag->type == Tag::Text || g_node->tag->type == Tag::ScriptStructureBegin))
parseForScriptGroup(g_node);
g_node = g_node->nextSibling();
if (m_synchronous)
{
slotParseForScriptGroup();
return;
}
else
{
#ifdef DEBUG_PARSER
//kdDebug(24001) << "Calling slotParseForScriptGroup from slotParseForScriptGroup." << endl;
#endif
m_parseForGroupTimer->start(0, true);
}
} else
{
#ifdef DEBUG_PARSER
kdDebug(24001) << "slotParseForScriptGroup done." << endl;
#endif
if (m_lastGroupParsed && m_parsingLastNode && !m_synchronous)
{
if (m_lastGroupParsed)
{
#ifdef DEBUG_PARSER
// kdDebug(24000) << "Calling cleanGroups from SAGroupParser::slotParseForScriptGroup" << endl;
kdDebug(24001) << m_count << " GroupElement created." << endl;
#endif
emit cleanGroups();
m_lastGroupParsed = false;
}
#ifdef DEBUG_PARSER
kdDebug(24001) << "Emitting rebuildStructureTree from slotParseForScriptGroup." << endl;
#endif
emit rebuildStructureTree(true);
}
}
}
void SAGroupParser::parseForScriptGroup(Node *node)
{
#ifdef DEBUG_PARSER
TQTime t;
t.start();
#endif
int bl, bc, el, ec;
int pos;
TQString title;
TQString tmpStr;
StructTreeGroup group;
GroupElement *groupElement;
GroupElementList* groupElementList;
KURL baseURL = QExtFileInfo::path(m_write->url());
TQString str = node->tag->cleanStr;
TQString tagStr = node->tag->tagStr();
const DTDStruct* dtd = node->tag->dtd();
node->tag->beginPos(bl, bc);
TQValueList<StructTreeGroup>::ConstIterator it;
for (it = dtd->structTreeGroups.begin(); it != dtd->structTreeGroups.end(); ++it)
{
group = *it;
if (!group.hasDefinitionRx ||
node->tag->type == Tag::XmlTag ||
node->tag->type == Tag::XmlTagEnd ||
node->tag->type == Tag::Comment ||
node->tag->type == Tag::Empty ||
( group.tagType != Tag::Text && node->tag->type != group.tagType)
)
continue;
pos = 0;
group.definitionRx.setMinimal(group.isMinimalDefinitionRx);
while (pos != -1)
{
pos = group.definitionRx.search(str, pos);
if (pos != -1) //the Node is part of this group
{
title = tagStr.mid(pos, group.definitionRx.matchedLength());
node->tag->beginPos(bl, bc);
tmpStr = tagStr.left(pos);
int newLines = tmpStr.contains('\n');
bl += newLines;
int l = tmpStr.findRev('\n'); //the last EOL
bc = (l == -1) ? bc + pos : pos - l - 1;
newLines = title.contains('\n');
l = title.length();
el = bl + newLines;
ec = (newLines > 0) ? l - title.findRev('\n') : bc + l - 1;
pos += l;
AreaStruct area(bl, bc, el, ec);
//get the list of elements which are present in this group and
//have the same title. For example get the list of all group
//element which are variable and the matched string was "$i"
int cap1Pos = str.find(group.definitionRx.cap(1));
TQString s = tagStr.mid(cap1Pos, group.definitionRx.cap(1).length());
groupElementList = & (globalGroupMap[group.name + "|" + s]);
//Create a new tag which point to the exact location of the matched string.
//For example when the group defined PHP variables it
//points to "$i" in a node which originally contained "print $i + 1"
Tag *newTag = new Tag(*node->tag);
newTag->setTagPosition(area);
newTag->setStr(title);
newTag->name = s;
groupElement = new GroupElement;
groupElement->deleted = false;
groupElement->tag = newTag;
groupElement->node = node;
groupElement->group = const_cast<StructTreeGroup*>(&(*it));
//Find out if the current node is inside a script structure or not.
//This is used to define local/global scope of the group elements.
Node *tmpNode = node;
while (tmpNode && tmpNode->tag->dtd() == dtd && tmpNode->tag->type != Tag::ScriptStructureBegin)
{
tmpNode = tmpNode->parent;
}
if (tmpNode && tmpNode->tag->type == Tag::ScriptStructureBegin)
{
groupElement->parentNode = tmpNode;
} else
{
groupElement->parentNode = 0L;
}
groupElement->global = true;
tmpNode = node->parent;
while (tmpNode && tmpNode->tag->dtd() == dtd)
{
if ( tmpNode->tag->type == Tag::ScriptStructureBegin && tmpNode->tag->dtd()->localScopeKeywordsRx.search(tmpNode->tag->cleanStr) != -1)
{
groupElement->global = false;
groupElement->parentNode = tmpNode;
break;
}
tmpNode = tmpNode->parent;
}
if (group.appendToTags)
{
TQTag *qTag = new TQTag();
// The location of the first open bracket '(', also the end of the tag name
int nameEnd = s.find('(');
qTag->setName(s.left(nameEnd));
qTag->className = "";
if (groupElement->parentNode)
{
for (GroupElementList::ConstIterator it2 = groupElement->parentNode->m_groupElements.constBegin(); it2 != groupElement->parentNode->m_groupElements.constEnd(); ++it2)
{
if ((*it2)->group->name == group.parentGroup)
{
qTag->className = (*it2)->tag->name;
break;
}
}
}
// Test for variable or function Type by checking for an opening bracket "(" used by functions
// and store the type in the TQTag type variable.
bool isArgument=false;
if (nameEnd == -1)
{
qTag->type="variable";
// If this tag is a class function argument, it should not belong to the class, so we need to remove it
if(qTag->className.length() != 0 && tagStr.contains('(') && tagStr.contains(')'))
{
// First we want to determine the whole line the tag is on
TQString tagWholeLineStr = tagStr;
// Remove lines before target line
while(tagWholeLineStr.length() > 0) // this stops infinit looping in case something goes wrong!
{
int firstNewline = tagWholeLineStr.find('\n');
if(firstNewline == -1) //no new lines so we must be on the last
break;
TQString checkLineStr = tagWholeLineStr.mid(firstNewline+1,tagWholeLineStr.length());
if(checkLineStr.contains(s))
tagWholeLineStr = checkLineStr;
else
break;
}
// Remove lines after target line - essentially same as above
while(tagWholeLineStr.length() > 0)
{
int lastNewLine = tagWholeLineStr.findRev('\n');
if(lastNewLine == -1)
break;
TQString checkLineStr = tagWholeLineStr.mid(0,lastNewLine);
if(checkLineStr.contains(s))
tagWholeLineStr = checkLineStr;
else
break;
}
// Now we are left with the current line, lets check if the variable is inside parentheses
int lineOpenParenth=tagWholeLineStr.find('(');
if(lineOpenParenth != -1)
{
int lineCloseParenth=tagWholeLineStr.find(')');
if(lineCloseParenth != -1)
{
int lineNameLocation=tagWholeLineStr.find(s);
if(lineNameLocation > lineOpenParenth || lineNameLocation < lineCloseParenth) // Write the current tag to the list
isArgument=true;
}
}
}
}
else
{
qTag->type="function";
}
if(!isArgument)
m_write->userTagList.replace(s.lower(), qTag);
}
if (!group.typeRx.pattern().isEmpty() && group.typeRx.search(title) != -1)
groupElement->type = group.typeRx.cap(1);
#ifdef DEBUG_PARSER
kdDebug(24001) << "GroupElement created: " <<groupElement << " "<< groupElement->tag->area().bLine << " " << groupElement->tag->area().bCol << " "<< groupElement->tag->area().eLine << " "<< groupElement->tag->area().eCol << " " << groupElement->tag->tagStr() << " " << groupElement->type << endl;
#endif
//store the pointer to the group element list where this node was put
//used to clear the corresponding entry from the group element lists
//when the node is deleted (eg. $i was deleted, so it should be deleted
//from the "variables | $i" group element list as well)
node->m_groupElements.append(groupElement);
groupElementList->append(groupElement);
m_count++;
//if a filename may be present in the title, extract it
if (group.hasFileName && group.parseFile)
{
s.remove(group.fileNameRx);
KURL url;
QuantaCommon::setUrl(url, s.stripWhiteSpace());
url = QExtFileInfo::toAbsolute(url, baseURL);
ParserCommon::includedFiles += url.path();
ParserCommon::includedFilesDTD.append(dtd);
ParserCommon::includeWatch->addFile(url.path());
}
}
}
}
#ifdef DEBUG_PARSER
if (t.elapsed() > 10)
kdDebug(24001) << "Done: " << t.elapsed() << endl;
#endif
}
#include "sagroupparser.moc"