diff options
Diffstat (limited to 'kommander/widget/parser.cpp')
-rw-r--r-- | kommander/widget/parser.cpp | 1243 |
1 files changed, 1243 insertions, 0 deletions
diff --git a/kommander/widget/parser.cpp b/kommander/widget/parser.cpp new file mode 100644 index 00000000..9bc9637b --- /dev/null +++ b/kommander/widget/parser.cpp @@ -0,0 +1,1243 @@ +/*************************************************************************** + parser.cpp - Internal parser + ------------------- + copyright : (C) 2004-2006 Michal Rudolf <mrudolf@kdewebdwev.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. * + * * + ***************************************************************************/ + +#include <klocale.h> + +#include "parser.h" +#include "parserdata.h" +#include "kommanderwidget.h" + +using namespace Parse; + +QString unescape(QString s) +{ + return s.replace("\\\"", "\"").replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\"); +} + +Parser::Parser(ParserData* pData) : m_data(pData), m_start(0), m_error(QString::null), m_errorPosition(0), + m_widget(0) +{ +} + +Parser::Parser(ParserData* pData, const QString& expr) : m_data(pData), m_start(0), + m_error(QString::null), m_errorPosition(0), m_widget(0) +{ + setString(expr); +} + +bool Parser::setString(const QString& s) +{ + reset(); + m_parts.clear(); + uint lines = 0; + uint start = 0; + uint i = 0; + while (start < s.length()) + { + if (s[start].isSpace() && s[start] != '\n') + start++; + else if (s[start] == '\\' && start < s.length() - 1 && s[start+1] == '\n') + start += 2; + else if (s[start] == ';') + { + insertNode(Semicolon, lines); + start++; + } + else if (s[start] == '\n') + { + if (m_parts.count() && !m_parts.last().isKeyword(Semicolon)) + insertNode(Semicolon, lines); + lines++; + start++; + } + else if (s[start] == '\"') // quoted string: "abc" + { + bool escaped = false; + for (i = start + 1; i < s.length() && (s[i] != '\"' || s[i-1] == '\\'); i++) + if (!escaped) + escaped = s[i] == '\\'; + if (escaped) + insertNode(unescape(s.mid(start + 1, i - start - 1)), lines); + else + insertNode(s.mid(start + 1, i - start - 1), lines); + start = i+1; + } + else if (s[start].isDigit()) // number: 1000 or 2.45 + { + bool decimal = false; + for (i = start+1; s[i].isDigit() || (!decimal && s[i] == QChar('.')); i++) + if (s[i] == '.') + decimal = true; + if (decimal) + insertNode(s.mid(start, i - start).toDouble(), lines); + else + insertNode(s.mid(start, i - start).toInt(), lines); + start = i; + } + else if (s[start].isLetter() || s[start] == '_') // keyword + { + for (i = start+1; s[i].isLetterOrNumber() || s[i] == '_'; i++) + ; + QString name = s.mid(start, i - start); + insertNode(ParseNode(m_data->stringToKeyword(name), name), lines); + start = i; + } // comment + else if (s[start] == '#' || (s[start] == '/' && start < s.length() +1 && s[start+1] == '/')) + { + while (start < s.length() && s[start] != '\n') + start++; + } // enable /* */ block comments + else if (s[start] == '/' && start < s.length() +1 && s[start+1] == '*') + { + start += 2; + while (start < s.length() +1 && !(s[start] == '*' && s[start+1] == '/')) + { + start++; + } + start += 2; + } // special keyword: <> + else if (m_data->stringToKeyword(s.mid(start, 2)) <= LastRealKeyword) + { + insertNode(m_data->stringToKeyword(s.mid(start, 2)), lines); + start += 2; + } // special keyword: < + else if (m_data->stringToKeyword(s.mid(start, 1)) <= LastRealKeyword) + { + insertNode(m_data->stringToKeyword(s.mid(start, 1)), lines); + start++; + } + else // Bad character + { + insertNode(s.mid(start, 1), lines); + setError(i18n("Invalid character: '%1'").arg(s[start]), m_parts.count()-1); + return false; + } + } + return true; +} + +void Parser::setWidget(KommanderWidget* w) +{ + m_widget = w; +} + +void Parser::insertNode(ParseNode p, int line) +{ + p.setContext(line); + m_parts.append(p); +} + +QString Parser::errorMessage() const +{ + return m_error; +} + +QString Parser::function(ParserData* data, const QString& name, const QStringList& params) +{ + ParameterList par; + for (QStringList::ConstIterator Iter = params.begin(); Iter != params.end(); ++Iter) + par.append(*Iter); + Function f = data->function(name); + return f.execute(0, par).toString(); +} + +QString Parser::expression(Mode mode) +{ + reset(); + ParseNode p = parseExpression(mode); + if (!isError()) + return p.toString(); + else + return QString(); +} + +bool Parser::isError() const +{ + return !m_error.isNull(); +} + + +bool Parser::command(Mode mode) +{ + reset(); + parseCommand(mode); + return !isError(); +} + +bool Parser::parse(Mode mode) +{ + reset(); + parseBlock(mode); + return !isError(); +} + +int Parser::errorLine() const +{ + if (isError()) + return m_parts[m_errorPosition].context(); + else + return -1; +} + +ParseNode Parser::parseConstant(Parse::Mode) +{ + ParseNode p = next(); + m_start++; + if (!p.isValue()) + { + setError(i18n("Constant value expected")); + return ParseNode(); + } + return p; +} +//attempting to allow assign or copy of array, so far with no joy +ParseNode Parser::parseValue(Mode mode) +{ + ParseNode p = next(); + //QString p2 = QString(p.toString()); + //qDebug("parseValue p2 = "+p2); + if (isFunction()) + return parseFunction(mode); + else if (isWidget()) + return parseWidget(mode); + else if (tryVariable(CheckOnly)) + { + if (tryKeyword(LeftBracket, CheckOnly)) + { + QString index = parseValue(mode).toString(); + if (tryKeyword(DoubleBracket, CheckOnly)) + {//2D array "matrix" + QString index2 = parseValue(mode).toString(); + tryKeyword(RightBracket); + QString arr = p.variableName(); + return matrixValue(arr, index, index2); + } + tryKeyword(RightBracket); + QString arr = p.variableName(); + return arrayValue(arr, index); + } + else if (tryKeyword(Dot, CheckOnly)) + { + QString value = variable(p.variableName()).toString(); + if (m_widget && m_widget->isWidget(value)) + { + m_start--; + return parseWidget(mode, value); + }else if (mode == Execute) + { + setError(i18n("'%1' (%2) is not a widget").arg(p.variableName()).arg(variable(p.variableName()).toString())); + return ParseNode(); + } else + { + //this means it looks like a widget, but it is unknown. As we only check + //the syntax, we should ignore the error an parse as a widget. + m_start = m_start - 2; + return parseWidget(mode); + } + } + else if (tryKeyword(LeftParenthesis, CheckOnly)) + { + setError(i18n("'%1' is not a function").arg(p.variableName())); + return ParseNode(); + } + else + p = variable(p.variableName()); + } + else if (tryKeyword(False, CheckOnly)) + return ParseNode(0); + else if (tryKeyword(True, CheckOnly)) + return ParseNode(1); +/* else if (isArray(p2)) + { + qDebug("returning array fpr p2"); + return p2; + }*/ + else if (p.isKeyword()) + setError(i18n("Expected value")); + else // single value + m_start++; + return p; +} + +ParseNode Parser::parseMultiply(Mode mode) +{ + ParseNode p = parseParenthesis(mode); + while (m_data->keywordGroup(next().keyword()) == GroupMultiply) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseParenthesis(mode); + ValueType type = p.commonType(p2); + if (mode == Execute) + { + if (k == Multiply) + if (type == ValueInt) + p = p.toInt() * p2.toInt(); + else + p = p.toDouble() * p2.toDouble(); + else if (k == Divide) + { + if (p2.toDouble() == 0.0) + setError(i18n("Divide by zero")); + else + if (type == ValueInt) + p = p.toInt() / p2.toInt(); + else + p = p.toDouble() / p2.toDouble(); + } + else /* k == Mod */ + { + if (p2.toInt() == 0) + setError(i18n("Divide by zero")); + else + p = p.toInt() - p.toInt() / p2.toInt() * p2.toInt(); + } + } + } + return p; +} + +ParseNode Parser::parseAdd(Mode mode) +{ + ParseNode p = parseMultiply(mode); + while (m_data->keywordGroup(next().keyword()) == GroupAdd) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseMultiply(mode); + ValueType type = p.commonType(p2); + if (mode == Execute) + { + if (k == Plus) + if (type == ValueString) + p = QString(p.toString() + p2.toString()); + else if (type == ValueDouble) + p = p.toDouble() + p2.toDouble(); + else + p = p.toInt() + p2.toInt(); + else /* k == Minus */ + if (type == ValueDouble) + p = p.toDouble() - p2.toDouble(); + else + p = p.toInt() - p2.toInt(); + } + } + return p; +} + +ParseNode Parser::parseSignedNumber(Mode mode) +{ + if (tryKeyword(Minus, CheckOnly)) + { + ParseNode p = parseValue(mode); + if (p.type() == ValueDouble) + return ParseNode(-p.toDouble()); + else + return ParseNode(-p.toInt()); + } + else + return parseValue(mode); +} + +ParseNode Parser::parseComparison(Mode mode) +{ + ParseNode p1 = parseAdd(mode); + if (m_data->keywordGroup(next().keyword()) == GroupComparison) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseAdd(mode); + switch (k) { + case Less: return ParseNode(p1 < p2); + case LessEqual: return ParseNode(p1 <= p2); + case Equal: return ParseNode(p1 == p2); + case NotEqual: return ParseNode(p1 != p2); + case GreaterEqual: return ParseNode(p1 >= p2); + case Greater: return ParseNode(p1 > p2); + default: ; + } + } + return p1; +} + +ParseNode Parser::parseParenthesis(Mode mode) +{ + if (tryKeyword(LeftParenthesis, CheckOnly)) + { + ParseNode p = parseExpression(mode); + tryKeyword(RightParenthesis); + return p; + } + else + return parseSignedNumber(mode); +} + + +ParseNode Parser::parseNot(Mode mode) +{ + if (tryKeyword(Not, CheckOnly)) + return !parseComparison(mode).toBool(); + else + return parseComparison(mode); +} + +ParseNode Parser::parseAnd(Mode mode) +{ + ParseNode p = parseNot(mode); + while (tryKeyword(And, CheckOnly)) + { + if (p == false) + parseNot(CheckOnly); + else + p = parseNot(mode); + } + return p; +} + +ParseNode Parser::parseOr(Mode mode) +{ + ParseNode p = parseAnd(mode); + while (tryKeyword(Or, CheckOnly)) + { + if (p == true) + parseAnd(CheckOnly); + else + p = parseAnd(mode); + } + return p; +} + +ParseNode Parser::parseCondition(Mode mode) +{ + return parseOr(mode); +} + +ParseNode Parser::parseExpression(Mode mode) +{ + return parseOr(mode); +} + +ParseNode Parser::parseFunction(Mode mode) +{ + int pos = m_start; + QString name = next().variableName(); + //qDebug("Parsing function: "+name); + Function f = m_data->function(name); + m_start++; + ParameterList params; + + if (tryKeyword(LeftParenthesis, CheckOnly) && !tryKeyword(RightParenthesis, CheckOnly)) + { + do { + params.append(parseExpression(mode)); + } while (tryKeyword(Comma, CheckOnly)); + tryKeyword(RightParenthesis); + } + if (f.minArgs() > params.count()) + setError(i18n("in function '%1': %2").arg(name).arg(i18n("too few parameters")), pos); + else if (f.maxArgs() < params.count()) + setError(i18n("in function '%1': %2").arg(name).arg(i18n("too many parameters")), pos); + else if (mode == Execute) + { + ParseNode p = f.execute(this, params); + if (!p.isValid()) + { + setError(i18n("in function '%1': %2").arg(name).arg(p.errorMessage()), pos); + return ParseNode(); + } + else + return p; + } + return ParseNode(); +} + +ParseNode Parser::parseWidget(Mode mode, const QString &widgetName) +{ + int pos = m_start; + QString widget; + if (widgetName.isNull()) + widget = nextVariable(mode); + else + widget = widgetName; + Function f = m_data->function("internalDcop"); + + if (!tryKeyword(Dot)) + return ParseNode(); + QString var = nextVariable(); + if (var.isNull()) + return ParseNode(); + ParameterList params; + params.append(var); + params.append(widget); + + if (tryKeyword(LeftParenthesis, CheckOnly) && !tryKeyword(RightParenthesis, CheckOnly)) + { + do { + params.append(parseExpression(mode)); + } while (tryKeyword(Comma, CheckOnly)); + tryKeyword(RightParenthesis); + } + if (mode == Execute) + { + ParseNode p = f.execute(this, params); + if (!p.isValid()) + { + setError(i18n("in widget function '%1.%2': %3").arg(widget).arg(var).arg(p.errorMessage()), pos); + return ParseNode(); + } + else + return p; + } + return ParseNode(); +} + + +ParseNode Parser::parseAssignment(Mode mode) +{ + QString var = nextVariable(); + //qDebug("var = "+var+" Pos:"+QString::number(m_start)); + if (tryKeyword(LeftBracket, CheckOnly)) + { + QString index = parseValue(mode).toString(); + if (tryKeyword(DoubleBracket, CheckOnly)) + {//2D array "matrix" + ParseNode p1 = next(); //move along... + QString index2 = parseValue(mode).toString(); + tryKeyword(RightBracket); + p1 = next(); + ParseNode p2 = matrixValue(var, index, index2); + if (p1.isKeyword(PlusEqual)) + { + tryKeyword(PlusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setMatrix(var, index, index2, p); + } + } + else if (p1.isKeyword(MinusEqual)) + { + tryKeyword(MinusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setMatrix(var, index, index2, p); + } + } + else if (p1.isKeyword(Increment)) + { + tryKeyword(Increment); + if (mode == Execute) + { + p2 = p2.toInt() + 1; + setMatrix(var, index, index2, p2); + } + } + else if (p1.isKeyword(Decrement)) + { + tryKeyword(Decrement); + if (mode == Execute) + { + p2 = p2.toInt() - 1; + setMatrix(var, index, index2, p2); + } + } + else + { + tryKeyword(Assign); + ParseNode p = parseExpression(mode); + if (mode == Execute) + setMatrix(var, index, index2, p); + } + } + else + { + tryKeyword(RightBracket); + ParseNode p1 = next(); + // seems awkward and pedantic but array values are now handled like variables + // for special assign with oparator + ParseNode p2 = arrayValue(var, index); + if (p1.isKeyword(PlusEqual)) + { + tryKeyword(PlusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setArray(var, index, p); + } + } + else if (p1.isKeyword(MinusEqual)) + { + tryKeyword(MinusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setArray(var, index, p); + } + } + else if (p1.isKeyword(Increment)) + { + tryKeyword(Increment); + if (mode == Execute) + { + p2 = p2.toInt() + 1; + setArray(var, index, p2); + } + } + else if (p1.isKeyword(Decrement)) + { + tryKeyword(Decrement); + if (mode == Execute) + { + p2 = p2.toInt() - 1; + setArray(var, index, p2); + } + } + else + { + tryKeyword(Assign); + ParseNode p = parseExpression(mode); + if (mode == Execute) + setArray(var, index, p); + } + } + } + else if (tryKeyword(Assign, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + setVariable(var, p); + } + } + else if (tryKeyword(PlusEqual, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p2 = variable(var); + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setVariable(var, p); + } + } + else if (tryKeyword(MinusEqual, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p2 = variable(var); + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setVariable(var, p); + } + } + else if (tryKeyword(Increment, CheckOnly)) + { + //ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p = variable(var); + p = p.toInt() + 1; + setVariable(var, p); + } + } + else if (tryKeyword(Decrement, CheckOnly)) + { + //ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p = variable(var); + p = p.toInt() - 1; + setVariable(var, p); + } + } + else if (tryKeyword(Dot, CheckOnly)) + { + QString value = variable(var).toString(); + if (m_widget && m_widget->isWidget(value)) + { + m_start--; + return parseWidget(mode, value); + } else + if (mode == CheckOnly) + { + //this means it looks like a widget, but it is unknown. As we only check + //the syntax, we should ignore the error an parse as a widget. + m_start = m_start - 2; + return parseWidget(mode); + } else + setError(i18n("'%1' is not a widget").arg(var)); + } + else if (tryKeyword(LeftParenthesis, CheckOnly)) + setError(i18n("'%1' is not a function").arg(var)); + else + setError(i18n("Unexpected symbol after variable '%1'").arg(var)); + + return ParseNode(); +} + +Flow Parser::parseIf(Mode mode) +{ + ParseNode p = next(); + Flow flow = FlowStandard; + bool matched = false; + bool thenFound = false; + do { + m_start++; + Mode m = matched ? CheckOnly : mode; + p = parseCondition(m); + thenFound = tryKeyword(Then, CheckOnly); + if (!thenFound) + tryKeyword(LeftCurlyBrace); + bool condition = !matched && p.toBool(); + if (condition) + { + flow = parseBlock(mode); + if (flow == FlowExit) + return flow; + } + else + parseBlock(CheckOnly); + matched = matched || p.toBool(); + if (!thenFound) + tryKeyword(RightCurlyBrace); + } while (nextElseIf() == true); + bool braceFound = false; + if (tryKeyword(Else, CheckOnly)) + { + braceFound = tryKeyword(LeftCurlyBrace, CheckOnly); + if (!matched) + flow = parseBlock(mode); + else + parseBlock(CheckOnly); + } + if (braceFound) + tryKeyword(RightCurlyBrace); + if (thenFound) + tryKeyword(Endif); + return flow; +} + +bool Parser::nextElseIf() +{ + ParseNode p1 = next(); + if (p1.isKeyword(Elseif)) + return true; + else + { + ParseNode p2 = next(); + if (p1.isKeyword(Else) && p2.isKeyword(If) ) + return true; + } + return false; +} + +Parse::Flow Parser::parseWhile(Mode mode) +{ + m_start++; + int start = m_start; + bool running = true; + Parse::Flow flow = FlowStandard; + bool doFound = false; + while (running) + { + m_start = start; + ParseNode p = parseCondition(mode); + doFound = tryKeyword(Do, CheckOnly); + if (!doFound && !tryKeyword(LeftCurlyBrace)) + break; + running = p.toBool(); + flow = parseBlock(running ? mode : CheckOnly); + if ( flow == FlowBreak || flow == FlowExit) + break; + } + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +Parse::Flow Parser::parseFor(Mode mode) +{ + m_start++; + QString var = nextVariable(); + tryKeyword(Assign); + int start = parseExpression(mode).toInt(); + tryKeyword(To); + int end = parseExpression(mode).toInt(); + int step = 1; + if (tryKeyword(Step, CheckOnly)) + step = parseExpression(mode).toInt(); + + bool doFound = tryKeyword(Do, CheckOnly); + if (!doFound) + tryKeyword(LeftCurlyBrace); + int block = m_start; + Parse::Flow flow = FlowStandard; + if (end >= start && step > 0) + { + for (int i = start; i <= end; i+=step) + { + m_start = block; + setVariable(var, ParseNode(i)); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } else if (end <= start && step < 0) + { + for (int i = start; i >= end; i+=step) + { + m_start = block; + setVariable(var, ParseNode(i)); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } else + parseBlock(Parse::CheckOnly); + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +Parse::Flow Parser::parseForeach(Mode mode) +{ + m_start++; + QString var = nextVariable(); + QString var2 = ""; + bool matrixfound = tryKeyword(ArrKeyVal, CheckOnly); + if (matrixfound == true) + { + m_start--; + tryKeyword(ArrKeyVal); + var2 = nextVariable(); + } + tryKeyword(In); + QString arr = nextVariable(); + bool doFound = tryKeyword(Do, CheckOnly); + if (!doFound) + tryKeyword(LeftCurlyBrace); + int start = m_start; + Parse::Flow flow = FlowStandard; + if (isArray(arr) && array(arr).count() && !matrixfound) + { + const QMap<QString, ParseNode> A = array(arr); + for (QMapConstIterator<QString, ParseNode> It = A.begin(); It != A.end(); ++It) + { + m_start = start; + setVariable(var, It.key()); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + else if (isMatrix(arr) && matrix(arr).count() ) + { + const QMap<QString, QMap<QString, ParseNode> > A = matrix(arr); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It = A.begin(); It != A.end(); ++It) + { + m_start = start; + setVariable(var, It.key()); + if (matrixfound == true) + { + const QMap<QString, ParseNode> B = It.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + m_start = start; + setVariable(var2, It2.key()); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + else + { + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + } + else + parseBlock(CheckOnly); + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +void Parser::parseSwitch(Mode mode) +{ + m_start++; + QString var = nextVariable(); + ParseNode caseValue = variable(var); + bool executed = false; + bool braceFound = false; + braceFound = tryKeyword(LeftCurlyBrace, CheckOnly); + tryKeyword(Semicolon, CheckOnly); + while (tryKeyword(Case, CheckOnly)) + { + ParseNode p = parseConstant(); + bool matched = mode == Execute && p == caseValue; + parseBlock(matched ? Execute : CheckOnly); + if (matched) + executed = true; + } + if (tryKeyword(Else, CheckOnly)) + parseBlock(executed ? CheckOnly : mode); + if (!braceFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); +} + +Flow Parser::parseCommand(Mode mode) +{ + ParseNode p = next(); + QString p2 = p.toString(); + //qDebug("Parsing command: "+p2); + if (next().isKeyword(If)) + return parseIf(mode); + else if (next().isKeyword(While)) + return parseWhile(mode); + else if (next().isKeyword(For)) + return parseFor(mode); + else if (next().isKeyword(Foreach)) + return parseForeach(mode); + else if (next().isKeyword(Switch)) + parseSwitch(mode); + else if (tryKeyword(Continue, CheckOnly)) + return FlowContinue; + else if (tryKeyword(Break, CheckOnly)) + return FlowBreak; + else if (isFunction()) + { + QString name = next().variableName(); + parseFunction(mode); + if (name == "return" && mode == Execute) + return FlowExit; + } + else if (isWidget()) + parseWidget(mode); + else if (next().isVariable()) + parseAssignment(mode); + else if (tryKeyword(Exit, CheckOnly)) + { + if (mode == Execute) + return FlowExit; + } + return FlowStandard; +} + +Flow Parser::parseBlock(Mode mode) +{ + Flow flow = parseCommand(mode); + while (tryKeyword(Semicolon, CheckOnly) && flow != FlowExit) + { + if (flow == FlowStandard) + flow = parseCommand(mode); + else + parseCommand(CheckOnly); + } + return flow; +} + + + + +ParseNode Parser::next() const +{ + if (isError() || m_start >= m_parts.count()) + return ParseNode(); + return m_parts[m_start]; +} + +bool Parser::tryKeyword(Keyword k, Mode mode) +{ + if (next().isKeyword(k)) + { + m_start++; + return true; + } + if (mode == Execute) + { + if (k == Dot) + setError(i18n("Expected '%1'<br><br>Possible cause of the error is having a variable with the same name as a widget").arg(m_data->keywordToString(k))); + else + setError(i18n("Expected '%1' got '%2'.").arg(m_data->keywordToString(k)).arg(next().toString())); + } + return false; +} + +bool Parser::tryVariable(Mode mode) +{ + if (next().isVariable()) + { + QString name = next().variableName(); + m_start++; + return true; + } + if (mode == Execute) + setError(i18n("Expected variable")); + return false; +} + +QString Parser::nextVariable(Mode mode) +{ + if (next().isVariable()) + { + QString name = next().variableName(); + m_start++; + return name; + } + else if (mode == Execute) + setError(i18n("Expected variable")); + return QString(); +} + + +bool Parser::isFunction() const +{ + return next().isVariable() && m_data->isFunction(next().variableName()); +} + +bool Parser::isWidget() const +{ + return m_widget && next().isVariable() && m_widget->isWidget(next().variableName()); +} + +void Parser::reset() +{ + m_start = 0; + m_error = QString::null; + m_errorPosition = 0; +} + +void Parser::setError(const QString& msg) +{ + setError(msg, m_start); +} + +void Parser::setError(const QString& msg, int pos) +{ + if (m_error.isNull()) + { + m_errorPosition = pos; + m_error = msg; + } +} + +void Parser::setVariable(const QString& name, ParseNode value) +{ + if (isGlobal(name)) + m_globalVariables[name] = value; + else + m_variables[name] = value; +} + +ParseNode Parser::variable(const QString& name) const +{ + if (isGlobal(name)) + return m_globalVariables.contains(name) ? m_globalVariables[name] : ParseNode(); + else + return m_variables.contains(name) ? m_variables[name] : ParseNode(); +} + +bool Parser::isGlobal(const QString& name) const +{ + return !name.isEmpty() && name[0] == '_'; +} + +bool Parser::isVariable(const QString& name) const +{ + return m_variables.contains(name) || m_globalVariables.contains(name); +} + +void Parser::unsetVariable(const QString& key) +{ + if (isGlobal(key)) + m_globalVariables.remove(key); + else + m_variables.remove(key); +} + +const QMap<QString, ParseNode>& Parser::array(const QString& name) const +{ + if (isGlobal(name)) + return m_globalArrays[name]; + else + return m_arrays[name]; +} + +bool Parser::isArray(const QString& name) const +{ + return m_arrays.contains(name) || m_globalArrays.contains(name); +} + +void Parser::setArray(const QString& name, const QString& key, ParseNode value) +{ + if (isGlobal(name)) + m_globalArrays[name][key] = value; + else + m_arrays[name][key] = value; +} + +void Parser::unsetArray(const QString& name, const QString& key) +{ + if (isGlobal(name)) + { + if (key.isNull()) + m_globalArrays.remove(name); + else if (isArray(name)) + m_globalArrays[name].remove(key); + } + else + { + if (key.isNull()) + m_arrays.remove(name); + else if (isArray(name)) + m_arrays[name].remove(key); + } +} + +ParseNode Parser::arrayValue(const QString& name, const QString& key) const +{ + if (!isArray(name)) + return ParseNode(); + if (isGlobal(name)) + return m_globalArrays[name].contains(key) ? m_globalArrays[name][key] : ParseNode(); + else + return m_arrays[name].contains(key) ? m_arrays[name][key] : ParseNode(); +} + +// 2D arrays "Matrix" +const QMap<QString, QMap<QString, ParseNode> >& Parser::matrix(const QString& name) const +{ + if (isGlobal(name)) + return m_globalMatrices[name]; + else + return m_matrices[name]; +} + +bool Parser::isMatrix(const QString& name) const +{ + return m_matrices.contains(name) || m_globalMatrices.contains(name); +} + +void Parser::setMatrix(const QString& name, const QString& keyr, const QString& keyc, ParseNode value) +{ + if (isGlobal(name)) + m_globalMatrices[name][keyr][keyc] = value; + else + m_matrices[name][keyr][keyc] = value; +} + +void Parser::unsetMatrix(const QString& name, const QString& keyr, const QString& keyc) +{ + if (isGlobal(name)) + { + if (keyr.isNull()) + m_globalMatrices.remove(name); + else if (isMatrix(name)) + { + if (keyc.isNull()) + m_globalMatrices[name].remove(keyr); + else + m_globalMatrices[name][keyr].remove(keyc); + } + } + else + { + if (keyr.isNull()) + m_matrices.remove(name); + else if (isMatrix(name)) + { + if (keyc.isNull()) + m_matrices[name].remove(keyr); + else + m_matrices[name][keyr].remove(keyc); + } + } +} + +ParseNode Parser::matrixValue(const QString& name, const QString& keyr, const QString& keyc) const +{ + if (!isMatrix(name)) + return ParseNode(); + if (isGlobal(name)) + return m_globalMatrices[name].contains(keyr) && m_globalMatrices[name][keyr].contains(keyc) ? m_globalMatrices[name][keyr][keyc] : ParseNode(); + else + return m_matrices[name].contains(keyr) && m_matrices[name][keyr].contains(keyc) ? m_matrices[name][keyr][keyc] : ParseNode(); +} + + + +KommanderWidget* Parser::currentWidget() const +{ + return m_widget; +} + +QMap<QString, ParseNode> Parser::m_globalVariables; +QMap<QString, QMap<QString, ParseNode> > Parser::m_globalArrays; +QMap<QString, QMap<QString, QMap<QString, ParseNode> > > Parser::m_globalMatrices; + |