/*************************************************************************** saparser.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> //kde includes #include <kdebug.h> #include <tdetexteditor/editinterface.h> //own includes #include "saparser.h" #include "sagroupparser.h" #include "document.h" #include "dtds.h" #include "node.h" #include "parsercommon.h" #include "qtag.h" #include "quantacommon.h" #include "resource.h" //#define DEBUG_PARSER SAParser::SAParser() { m_write = 0L; m_baseNode = 0L; m_currentNode = 0L; m_quotesRx = TQRegExp("\"|'"); m_specialInsideXml = false; m_parsingEnabled = true; m_synchronous = true; m_parseOneLineTimer = new TQTimer(this); connect(m_parseOneLineTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotParseOneLine())); m_parseInDetailTimer = new TQTimer(this); connect(m_parseInDetailTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotParseNodeInDetail())); } SAParser::~SAParser() { } void SAParser::init(Node *node, Document* write) { m_baseNode = node; m_write = write; m_dtd = write->defaultDTD(); } bool SAParser::slotParseOneLine() { if ((!m_parsingEnabled || !baseNode) && !m_synchronous) { #ifdef DEBUG_PARSER kdDebug(24001) << "slotParseOneLine - interrupted" << endl; #endif return false; } if (s_line <= s_endLine) { s_contextFound = false; switch (s_currentContext.type) { case Group: case Text: { int areaEndPos = -1; int quotedStringPos = -1; int commentPos = -1; int groupKeywordPos = -1; if (s_searchContent || (s_parentNode && s_parentNode->tag->dtd()->family == Xml)) { //search for different s_contexts if (s_searchContent) //search for quoted strings, comments, groups only in non-comment special areas { quotedStringPos = s_textLine.find(m_quotesRx, s_col); //quoted strings s_searchedString = s_textLine.left(quotedStringPos); commentPos = s_searchedString.find(s_dtd->commentsStartRx, s_col); //comments s_searchedString = s_textLine.left(commentPos); if (s_fullParse) groupKeywordPos = s_searchedString.find(s_dtd->structRx, s_col); //groups, like { } } else s_searchedString = s_textLine; int specialAreaPos = -1; if (s_searchForSpecialAreas) //special area inside special area { s_searchedString = s_textLine.left(groupKeywordPos); specialAreaPos = s_searchedString.find(s_dtd->specialAreaStartRx, s_col); } if (s_searchForAreaEnd) //the end of the special area { s_searchedString = s_textLine.left(specialAreaPos); areaEndPos = s_searchedString.find(s_areaEndString, s_col); } else if (s_searchForForcedAreaEnd) //the end of the special area if a forcing string was specified { s_searchedString = s_textLine.left(specialAreaPos); areaEndPos = s_searchedString.find(s_forcedAreaRx, s_col); if (areaEndPos != -1) s_areaEndString = s_forcedAreaRx.cap(); } //check which s_context was found first if (quotedStringPos != -1) //is it a quoted string? { if ( (quotedStringPos < commentPos || commentPos == -1) && (quotedStringPos < groupKeywordPos || groupKeywordPos == -1) && (quotedStringPos < specialAreaPos || specialAreaPos == -1) && (quotedStringPos < areaEndPos || areaEndPos == -1) ) { s_context.type = QuotedString; s_context.area.bCol = quotedStringPos; s_context.startString = s_textLine.mid(quotedStringPos, 1); s_contextFound = true; } } if (!s_contextFound && commentPos != -1) //is it a comment? { if ( (commentPos < groupKeywordPos || groupKeywordPos == -1) && (commentPos < specialAreaPos || specialAreaPos == -1) && (commentPos < areaEndPos || areaEndPos == -1) ) { s_context.type = Comment; s_context.area.bCol = commentPos; s_context.startString = s_dtd->commentsStartRx.cap(); s_contextFound = true; } } if (!s_contextFound && groupKeywordPos != -1) //is it a group structure? { if ( (groupKeywordPos < specialAreaPos || specialAreaPos == -1) && (groupKeywordPos < areaEndPos || areaEndPos == -1) ) { TQString foundText = s_dtd->structRx.cap(); if (foundText == s_dtd->structBeginStr) { s_context.type = Group; s_context.area.bCol = groupKeywordPos; s_context.startString = foundText; //create a text node until the struct. beginning s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = groupKeywordPos + foundText.length() - 1; if (s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); else s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, s_currentContext.area.eCol + 1, s_currentContext.parentNode); s_currentNode->tag->type = Tag::ScriptStructureBegin; s_currentNode->tag->single = false; s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; s_currentContext.lastNode = s_currentNode; s_contextStack.push(s_currentContext); s_currentContext.parentNode = s_currentNode; s_col = s_context.area.bCol + s_context.startString.length(); s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = s_col; s_currentContext.type = Group; if (m_synchronous) //slotParseOneLine(); return true; else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from parseArea (opening group struct)." << endl; #endif m_parseOneLineTimer->start(0, true); } return true; } else //it's a closing group structure element (like "}") { if (s_currentContext.type != Group) { s_col = groupKeywordPos + foundText.length(); if (m_synchronous) //slotParseOneLine(); return true; else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from parseArea (closing group struct)." << endl; #endif m_parseOneLineTimer->start(0, true); } return true; } s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = groupKeywordPos - 1; //kdDebug(24000) << TQString("Group Struct s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl; if (s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); else s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, groupKeywordPos, s_currentContext.parentNode); if (s_currentNode) { s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } s_previousContext = s_contextStack.pop(); s_currentContext.parentNode = s_previousContext.parentNode; s_currentContext.lastNode = s_previousContext.lastNode; s_currentContext.type = s_previousContext.type; s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = groupKeywordPos + foundText.length(); s_currentContext.area.eLine = s_currentContext.area.eCol = -1; s_currentContext.startString = s_previousContext.startString; s_col = s_currentContext.area.bCol; Tag *tag = new Tag(); tag->name = foundText; tag->setStr(foundText); tag->setWrite(m_write); tag->setTagPosition(s_line, groupKeywordPos, s_line, s_col - 1); tag->setDtd(s_dtd); tag->type = Tag::ScriptStructureEnd; tag->single = true; Node *node = new Node(s_currentContext.parentNode); nodeNum++; node->tag = tag; node->insideSpecial = true; node->specialInsideXml = m_specialInsideXml; if (s_currentContext.parentNode && !s_currentContext.parentNode->child) { s_currentContext.parentNode->child = node; } else if (s_currentContext.lastNode) { node->prev = s_currentContext.lastNode; s_currentContext.lastNode->next = node; } s_currentNode = node; if (m_synchronous) return true; else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from parseArea (group structure)." << endl; #endif m_parseOneLineTimer->start(0, true); } return true; } } } if (!s_contextFound && specialAreaPos != -1) //is it a special area? { if (specialAreaPos < areaEndPos || areaEndPos == -1) { TQString foundText = s_dtd->specialAreaStartRx.cap(); s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = specialAreaPos - 1; if (s_fullParse) { if ( s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); else s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, specialAreaPos, s_currentContext.parentNode); if (s_currentNode) { s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } } //create a toplevel node for the included special area AreaStruct area(s_line, specialAreaPos, s_line, specialAreaPos + foundText.length() - 1); Node *node = ParserCommon::createScriptTagNode(m_write, area, foundText, s_dtd, s_currentContext.parentNode, s_currentNode); #ifdef DEBUG_PARSER kdDebug(24001) << "Parsing a nested area." << endl; #endif AreaStruct area2(s_line, specialAreaPos, s_endLine, s_endCol); SAParser *p = new SAParser(); p->init(m_baseNode, m_write); s_currentNode = p->parseArea(area2, foundText, "", node, s_fullParse, true); s_line = p->lastParsedLine(); s_col = p->lastParsedColumn(); delete p; s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = s_col + 1; s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol); s_col++; if (m_synchronous) { return true; } else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from slotParseOneLine (nested area)." << endl; #endif m_parseOneLineTimer->start(0, true); return true; } } } } else //when we look only for the area end string if (s_searchForAreaEnd) { areaEndPos = s_textLine.find(s_areaEndString, s_col); } else if (s_searchForForcedAreaEnd) { areaEndPos = s_textLine.find(s_forcedAreaRx, s_col); if (areaEndPos != -1) s_areaEndString = s_forcedAreaRx.cap(); } if (!s_contextFound && areaEndPos != -1) //did we find the end of the special area? { m_lastParsedLine = s_line; m_lastParsedCol = areaEndPos + s_areaEndString.length() - 1; s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = areaEndPos - 1; //Always create a node between the opening and closing special area nodes. //This fixes the "commnet loss" bug when editing in VPL and autocompletion //for simple special areas like <? a ?> if (s_fullParse || !s_parentNode->child) { if ( s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); else { s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_line, areaEndPos, s_parentNode); } if (s_currentNode) { s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } } //kdDebug(24000) << TQString("Special area %1 ends at %2, %3").arg(s_dtd->name).arg(s_line).arg(lastCol) << endl; //create a closing node for the special area Tag *tag = new Tag(); tag->setTagPosition(s_line, areaEndPos, s_line, m_lastParsedCol); tag->parse(s_areaEndString, m_write); tag->setDtd(s_dtd); tag->type = Tag::XmlTagEnd; tag->validXMLTag = false; //FIXME: this is more or less a workaround. We should introduce and handle Tag::ScriptTagEnd tag->single = true; //at this point s_parentNode = the opening node of the special area (eg. <?) //and it should always exist Node *node = new Node(s_parentNode->parent); nodeNum++; s_parentNode->next = node; node->prev = s_parentNode; node->tag = tag; node->closesPrevious = true; if (s_fullParse) { Node *g_node, *g_endNode; g_node = s_parentNode->child; /* g_endNode = s_currentNode; if (g_node && g_node == g_endNode) g_endNode = s_parentNode->next;*/ g_endNode = node; #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseForScriptGroup from slotParseOneLine." << endl; #endif // slotParseForScriptGroup(); if (!m_synchronous) { bool parsingLastNode = true; Node *n = g_endNode; while (n) { n = n->nextSibling(); if (n && n->insideSpecial) { parsingLastNode = false; break; } } SAGroupParser *groupParser = new SAGroupParser(this, write(), g_node, g_endNode, m_synchronous, parsingLastNode, true); connect(groupParser, TQT_SIGNAL(rebuildStructureTree(bool)), TQT_SIGNAL(rebuildStructureTree(bool))); connect(groupParser, TQT_SIGNAL(cleanGroups()), TQT_SIGNAL(cleanGroups())); connect(groupParser, TQT_SIGNAL(parsingDone(SAGroupParser*)), TQT_SLOT(slotGroupParsingDone(SAGroupParser*))); groupParser->slotParseForScriptGroup(); m_groupParsers.append(groupParser); } } m_lastParsedNode = node; s_useReturnVars = true; if (!m_synchronous) { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling parsingDone from slotParseOneLine (area end found)." << endl; #endif m_lastParsedNode = parsingDone(); } return false; //parsing finished } if (s_contextFound) { s_context.area.bLine = s_line; s_context.area.eLine = s_context.area.eCol = -1; s_context.parentNode = s_currentContext.parentNode; s_currentContext.area.eLine = s_context.area.bLine; s_currentContext.area.eCol = s_context.area.bCol - 1; // s_currentContext.parentNode = s_parentNode; s_contextStack.push(s_currentContext); if (s_fullParse) { if (s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) { ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } else if (s_currentContext.area.bLine < s_currentContext.area.eLine || (s_currentContext.area.bLine == s_currentContext.area.eLine && s_currentContext.area.bCol < s_currentContext.area.eCol)) { //create a tag from the s_currentContext Tag *tag = new Tag(s_currentContext.area, m_write, s_dtd); TQString tagStr = tag->tagStr(); tag->cleanStr = tagStr; QuantaCommon::removeCommentsAndQuotes(tag->cleanStr, s_dtd); if (tagStr.simplifyWhiteSpace().isEmpty()) { tag->type = Tag::Empty; } else { tag->type = Tag::Text; } tag->single = true; //create a node with the above tag Node *node = new Node(s_currentContext.parentNode); nodeNum++; node->tag = tag; node->insideSpecial = true; node->specialInsideXml = m_specialInsideXml; if (s_currentContext.parentNode && !s_currentContext.parentNode->child) { s_currentContext.parentNode->child = node; } else if (s_currentNode) { node->prev = s_currentNode; s_currentNode->next = node; } s_currentNode = node; } } //kdDebug(24000) << TQString("%1 s_context: %2, %3, %4, %5").arg(s_currentContext.type).arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl; s_currentContext = s_context; s_col = s_context.area.bCol + s_context.startString.length(); } else { s_line++; s_col = 0; s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol); } break; } case QuotedString: { int pos = -1; int p = s_col; int l = s_textLine.length(); while (p < l) { p = s_textLine.find(s_currentContext.startString, p); if (p != -1) { if (p >= 0) { int i = p - 1; int slahNum = 0; while (i > 0 && s_textLine[i] == '\\') { slahNum++; i--; } if (p == 0 || (slahNum % 2 == 0)) { pos = p; break; } } } else break; p++; } if (pos != -1) { // if (pos != 0) pos++; s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = pos; //kdDebug(24000) << TQString("Quoted String s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl; if (s_fullParse) { if ( s_currentNode && (s_currentNode->tag->type == Tag::Text || s_currentNode->tag->type == Tag::Empty) ) ParserCommon::appendAreaToTextNode(m_write, s_currentContext.area, s_currentNode); else s_currentNode = ParserCommon::createTextNode(m_write, 0L, s_line, pos, s_currentContext.parentNode); s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } s_previousContext = s_contextStack.pop(); s_currentContext.parentNode = s_previousContext.parentNode; s_currentContext.type = s_previousContext.type; s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = pos + 1; s_currentContext.area.eLine = s_currentContext.area.eCol = -1; s_currentContext.startString = s_previousContext.startString; s_col = pos + 1; } else { s_line++; s_col = 0; s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol); } break; } case Comment: { int pos = s_textLine.find(s_dtd->comments[s_currentContext.startString], s_col); if (pos == -1 && s_dtd->comments[s_currentContext.startString] == "\n") { int pos2 = s_textLine.find(s_areaEndString, s_col); if (pos2 != -1) { pos = pos2 - 1; } else { pos = s_textLine.length(); } } if (pos != -1) { s_currentContext.area.eLine = s_line; s_currentContext.area.eCol = pos + s_dtd->comments[s_currentContext.startString].length() - 1; s_currentContext.type = s_previousContext.type; //kdDebug(24000) << TQString("Comment s_context: %1, %2, %3, %4").arg( s_currentContext.bLine).arg(s_currentContext.bCol).arg(s_currentContext.eLine).arg(s_currentContext.eCol) << endl; if (s_fullParse) { //create a tag with the comment Tag *tag = new Tag(s_currentContext.area, m_write, s_dtd); tag->type = Tag::Comment; tag->single = true; //create a node with the above tag Node *node = new Node(s_currentContext.parentNode); nodeNum++; node->tag = tag; node->insideSpecial = true; node->specialInsideXml = m_specialInsideXml; if (s_currentNode && s_currentNode != node->parent) { s_currentNode->next = node; node->prev = s_currentNode; } else if (node->parent && !node->parent->child) node->parent->child = node; s_currentNode = node; } s_previousContext = s_contextStack.pop(); s_currentContext.parentNode = s_previousContext.parentNode; s_currentContext.type = s_previousContext.type; s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = s_currentContext.area.eCol + 1; s_currentContext.area.eLine = s_currentContext.area.eCol = -1; s_currentContext.startString = s_previousContext.startString; s_col = s_currentContext.area.bCol; } else { s_line++; s_col = 0; s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol); } break; } default: { s_line++; s_col = 0; s_textLine = ParserCommon::getLine(m_write, s_line, s_endLine, s_endCol); } } if (m_synchronous) { //slotParseOneLine(); } else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from slotParseOneLine." << endl; #endif m_parseOneLineTimer->start(0, true); } } else { if (!m_synchronous) { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling parsingDone from slotParseOneLine." << endl; #endif parsingDone(); } return false; //parsing finished } return true; } Node* SAParser::parseArea(const AreaStruct &specialArea, const TQString &areaStartString, const TQString &forcedAreaEndString, Node *parentNode, bool fullParse, bool synchronous) { m_synchronous = synchronous; s_parentNode = parentNode; s_fullParse = fullParse; #ifdef DEBUG_PARSER kdDebug(24001) << "parseArea full: " << s_fullParse << " synch: " << m_synchronous <<endl; #endif int s_startLine = specialArea.bLine; int s_startCol = specialArea.bCol; s_endLine = specialArea.eLine; s_endCol = specialArea.eCol; //kdDebug(24000) << TQString("Starting to parse at %1, %2 for %3").arg(s_startLine).arg(s_startCol).arg(areaStartString) << endl; s_searchForAreaEnd = false; s_searchForForcedAreaEnd = false; s_dtd = 0L; if (s_parentNode && !areaStartString.isEmpty()) { const DTDStruct *parentDTD = m_dtd; if (s_parentNode->parent) parentDTD = s_parentNode->parent->tag->dtd(); s_dtd = DTDs::ref()->find(parentDTD->specialAreaNames[areaStartString]); s_areaEndString = parentDTD->specialAreas[areaStartString]; s_searchForAreaEnd = true; } if (!forcedAreaEndString.isEmpty()) { s_forcedAreaRx.setPattern(forcedAreaEndString); s_forcedAreaRx.setCaseSensitive(m_dtd->caseSensitive); s_searchForForcedAreaEnd = true; s_searchForAreaEnd = false; if (s_parentNode) s_dtd = s_parentNode->tag->dtd(); } s_searchContent = true; if (s_parentNode && s_parentNode->tag->type == Tag::Comment) s_searchContent = false; if (!s_dtd) { if (s_parentNode) s_dtd = s_parentNode->tag->dtd(); //fallback, usually when the special area is a comment else s_dtd = m_dtd; //fallback when there is no s_parentNode } m_write->addDTEP(s_dtd->name); s_searchForSpecialAreas = (s_dtd->specialAreas.count() > 0); if (s_parentNode && s_parentNode->tag->type == Tag::Comment) s_searchForSpecialAreas = false; s_col = s_startCol + areaStartString.length(); s_line = s_startLine; s_textLine = m_write->text(s_startLine, 0, s_startLine, m_write->editIf->lineLength(s_startLine)); if (s_line == s_endLine) { if (s_endCol > 0) s_textLine.truncate(s_endCol + 1); else s_textLine = ""; } s_previousContext.type = Unknown; s_currentContext.type = Text; s_currentContext.area.bLine = s_line; s_currentContext.area.bCol = s_col; s_currentContext.area.eLine = s_currentContext.area.eCol = -1; s_currentContext.parentNode = s_parentNode; s_currentNode = s_parentNode; m_lastParsedNode = 0L; s_useReturnVars = false; if (s_line <= s_endLine) { if (m_synchronous) { while (slotParseOneLine()); //actually this parses the whole area, as synchronous == true if (s_useReturnVars) //this is true if the special area end was found { return m_lastParsedNode; } } else { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseOneLine from parseArea." << endl; #endif m_parseOneLineTimer->start(0, true); return 0L; } } if (m_synchronous) //if the special area end was not found and we are in synchronous mode { s_next = 0L; #ifdef DEBUG_PARSER kdDebug(24001) << "Calling parsingDone from parseArea." << endl; #endif s_currentNode = parsingDone(); return s_currentNode; } return 0L; } Node *SAParser::parsingDone() { #ifdef DEBUG_PARSER kdDebug(24001) << "parsingDone. Use return values:" << s_useReturnVars << endl; #endif if (s_useReturnVars) { if (s_fullParse) { Node *n = m_lastParsedNode; if (m_useNext) { // kdDebug(24000) << "m_lastParsedNode: " << m_lastParsedNode << " " << m_lastParsedNode->tag->tagStr() << endl; n->next = s_next; if (s_next) { s_next->prev = n; } n->prev = s_parentNode; } m_currentNode = n->nextSibling(); if (m_currentNode) { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseNodeInDetail from parsingDone (use return values)" << endl; #endif m_parseInDetailTimer->start(0, true); return m_lastParsedNode; } else { m_parsingEnabled = true; #ifdef DEBUG_PARSER kdDebug(24001) << "Emitting rebuildStructureTree from parsingDone (use return values). Enable parsing." << endl; #endif emit rebuildStructureTree(false); #ifdef DEBUG_PARSER // kdDebug(24000) << "Calling cleanGroups from SAParser::parsingDone" << endl; #endif emit cleanGroups(); } } m_currentNode = 0L; return m_lastParsedNode; } if (!s_currentNode) { s_currentNode = ParserCommon::createTextNode(m_write, s_parentNode, s_endLine, s_endCol, s_parentNode); if (s_currentNode) { s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } } else if (s_parentNode && !s_parentNode->next) { s_currentNode = ParserCommon::createTextNode(m_write, s_currentNode, s_endLine, s_endCol, s_parentNode); s_currentNode->insideSpecial = true; s_currentNode->specialInsideXml = m_specialInsideXml; } if (s_fullParse) { Node *n; if (s_parentNode) { n = s_parentNode;//->child; } else { n = s_currentNode; while (n && n->prev) n = n->prev; s_currentNode = n; } Node *g_node = n; #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseForScriptGroup from parsingDone. Synch:" << m_synchronous << endl; #endif //parse for groups only when doing aynchronous detailed parsing if (!m_synchronous) { SAGroupParser *groupParser = new SAGroupParser(this, write(), g_node, 0L, m_synchronous, true /*last node*/, true); connect(groupParser, TQT_SIGNAL(rebuildStructureTree(bool)), TQT_SIGNAL(rebuildStructureTree(bool))); connect(groupParser, TQT_SIGNAL(cleanGroups()), TQT_SIGNAL(cleanGroups())); connect(groupParser, TQT_SIGNAL(parsingDone(SAGroupParser*)), TQT_SLOT(slotGroupParsingDone(SAGroupParser*))); groupParser->slotParseForScriptGroup(); m_groupParsers.append(groupParser); } } m_lastParsedLine = s_endLine; m_lastParsedCol = s_endCol + 1; if (s_fullParse && m_currentNode) { if (m_useNext && s_currentNode) { // kdDebug(24000) << "s_currentNode: " << s_currentNode << endl; Node *n = s_currentNode; n->next = s_next; if (s_next) s_next->prev = n; } m_currentNode = m_currentNode->nextSibling(); if (m_currentNode) { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseNodeInDetail from parsingDone." << endl; #endif m_parseInDetailTimer->start(0, true); emit rebuildStructureTree(false); } else { m_parsingEnabled = true; #ifdef DEBUG_PARSER kdDebug(24001) << "Emitting detailedParsingDone from parsingDone. Enable parsing." << endl; #endif emit rebuildStructureTree(false); } } m_currentNode = 0L; return s_currentNode; } void SAParser::parseInDetail(bool synchronous) { // synchronous = true; //for testing. Uncomment to test the parser in synchronous mode // return; //for testing. Uncomment to disable the detailed parser #ifdef DEBUG_PARSER kdDebug(24001) << "parseInDetail. Enabled: " << m_parsingEnabled << endl; #endif if (!m_parsingEnabled) { m_currentNode = m_baseNode; m_parsingEnabled = true; m_synchronous = synchronous; if (m_currentNode) { #ifdef DEBUG_PARSER kdDebug(24001) << "Calling slotParseNodeInDetail from parseInDetail." << endl; #endif slotParseNodeInDetail(); } } } void SAParser::slotParseNodeInDetail() { #ifdef DEBUG_PARSER kdDebug(24001) << "slotParseNodeInDetail. Enabled: " << m_parsingEnabled << " Synch: " << m_synchronous << endl; //this is really heavy debug information, enable only when really needed #endif if (m_currentNode && m_parsingEnabled && baseNode) { if (m_currentNode->insideSpecial && m_currentNode->tag->type != Tag::Comment && m_currentNode->tag->type != Tag::Text && m_currentNode->tag->type != Tag::Empty) { Node::deleteNode(m_currentNode->child); m_currentNode->child = 0L; AreaStruct area(m_currentNode->tag->area()); s_next = 0L; m_useNext = false; //FIXME: Find out why can the tag become 0L if (m_currentNode->next && m_currentNode->next->tag) { AreaStruct area2(m_currentNode->next->tag->area()); area.eLine = area2.eLine; area.eCol = area2.eCol + 1; s_next = m_currentNode->next->next; if (m_currentNode->next->closesPrevious) { m_currentNode->next->removeAll = false; Node *secondNext = m_currentNode->next->next; if (secondNext) secondNext->prev = m_currentNode; Node::deleteNode(m_currentNode->next); m_currentNode->next = secondNext; m_useNext = true; } } else { area.eLine = m_write->editIf->numLines() - 1; area.eCol = m_write->editIf->lineLength(area.eLine); } #ifdef DEBUG_PARSER kdDebug(24001) << "Calling parseArea from slotParseNodeInDetail." << endl; #endif TQString areaStartString = m_currentNode->tag->tagStr(); if (m_currentNode->tag->dtd()->specialAreaNames[areaStartString].isEmpty()) { AreaStruct area2(m_currentNode->tag->area()); area.bLine = area2.eLine; area.bCol = area2.eCol + 1; parseArea(area, "", "</"+m_currentNode->tag->name+"\\s*>", m_currentNode, true, m_synchronous); } else parseArea(area, m_currentNode->tag->tagStr(), "", m_currentNode, true, m_synchronous); } else { // Node *node = m_currentNode; m_currentNode = m_currentNode->nextSibling(); if (m_currentNode) { #ifdef DEBUG_PARSER // kdDebug(24001) << "Calling slotParseNodeInDetail from slotParseNodeInDetail." << endl; //this is really heavy debug information, enable only when really needed #endif m_parseInDetailTimer->start(0, true); } else { #ifdef DEBUG_PARSER kdDebug(24001) << "Emitting rebuildStructureTree from slotParseNodeInDetail." << endl; #endif emit rebuildStructureTree(false); } } } } void SAParser::setParsingEnabled(bool enabled) { #ifdef DEBUG_PARSER kdDebug(24001) << "Parsing enabled: " << enabled << endl; #endif m_parsingEnabled = enabled; if (!enabled) { m_parseOneLineTimer->stop(); m_parseInDetailTimer->stop(); for (TQValueList<SAGroupParser*>::Iterator it = m_groupParsers.begin(); it != m_groupParsers.end(); ++it) { (*it)->m_parseForGroupTimer->stop(); delete (*it); } m_groupParsers.clear(); } } void SAParser::slotGroupParsingDone(SAGroupParser *groupParser) { m_groupParsers.remove(groupParser); delete groupParser; } #include "saparser.moc"