Commit 5af2b7c0 authored by Dimitri van Heesch's avatar Dimitri van Heesch

Added basic arithmetic operations to the template expressions, and made the expression lexer faster

parent 92d53a47
...@@ -504,6 +504,8 @@ class Operator ...@@ -504,6 +504,8 @@ class Operator
not not
in in
==, !=, <, >, <=, >= ==, !=, <, >, <=, >=
+, -
*, /, %
| |
: :
, ,
...@@ -511,7 +513,9 @@ class Operator ...@@ -511,7 +513,9 @@ class Operator
enum Type enum Type
{ {
Or, And, Not, In, Equal, NotEqual, Less, Greater, LessEqual, Or, And, Not, In, Equal, NotEqual, Less, Greater, LessEqual,
GreaterEqual, Filter, Colon, Comma, Last GreaterEqual, Plus, Minus, Multiply, Divide, Modulo, Filter, Colon, Comma,
LeftParen, RightParen,
Last
}; };
static const char *toString(Type op) static const char *toString(Type op)
...@@ -528,9 +532,16 @@ class Operator ...@@ -528,9 +532,16 @@ class Operator
case Greater: return ">"; case Greater: return ">";
case LessEqual: return "<="; case LessEqual: return "<=";
case GreaterEqual: return ">="; case GreaterEqual: return ">=";
case Plus: return "+";
case Minus: return "-";
case Multiply: return "*";
case Divide: return "/";
case Modulo: return "%";
case Filter: return "|"; case Filter: return "|";
case Colon: return ":"; case Colon: return ":";
case Comma: return ","; case Comma: return ",";
case LeftParen: return "(";
case RightParen: return ")";
case Last: return "?"; case Last: return "?";
} }
return "?"; return "?";
...@@ -890,7 +901,7 @@ class ExprAstFunctionVariable : public ExprAst ...@@ -890,7 +901,7 @@ class ExprAstFunctionVariable : public ExprAst
public: public:
ExprAstFunctionVariable(ExprAst *var,const QList<ExprAst> &args) ExprAstFunctionVariable(ExprAst *var,const QList<ExprAst> &args)
: m_var(var), m_args(args) : m_var(var), m_args(args)
{ TRACE(("ExprAstFunctionVariable(%s)\n",var->name().data())); { TRACE(("ExprAstFunctionVariable()\n"));
m_args.setAutoDelete(TRUE); m_args.setAutoDelete(TRUE);
} }
virtual TemplateVariant resolve(TemplateContext *c) virtual TemplateVariant resolve(TemplateContext *c)
...@@ -982,6 +993,28 @@ class ExprAstNegate : public ExprAst ...@@ -982,6 +993,28 @@ class ExprAstNegate : public ExprAst
ExprAst *m_expr; ExprAst *m_expr;
}; };
class ExprAstUnary : public ExprAst
{
public:
ExprAstUnary(Operator::Type op,ExprAst *exp) : m_operator(op), m_exp(exp)
{ TRACE(("ExprAstUnary %s\n",Operator::toString(op))); }
~ExprAstUnary() { delete m_exp; }
virtual TemplateVariant resolve(TemplateContext *c)
{
TemplateVariant exp = m_exp->resolve(c);
switch (m_operator)
{
case Operator::Minus:
return -exp.toInt();
default:
return TemplateVariant();
}
}
private:
Operator::Type m_operator;
ExprAst *m_exp;
};
/** @brief Class representing a binary operator in the AST */ /** @brief Class representing a binary operator in the AST */
class ExprAstBinary : public ExprAst class ExprAstBinary : public ExprAst
{ {
...@@ -992,6 +1025,7 @@ class ExprAstBinary : public ExprAst ...@@ -992,6 +1025,7 @@ class ExprAstBinary : public ExprAst
~ExprAstBinary() { delete m_lhs; delete m_rhs; } ~ExprAstBinary() { delete m_lhs; delete m_rhs; }
virtual TemplateVariant resolve(TemplateContext *c) virtual TemplateVariant resolve(TemplateContext *c)
{ {
TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
TemplateVariant lhs = m_lhs->resolve(c); TemplateVariant lhs = m_lhs->resolve(c);
TemplateVariant rhs = m_rhs ? m_rhs->resolve(c) : TemplateVariant(); TemplateVariant rhs = m_rhs ? m_rhs->resolve(c) : TemplateVariant();
switch(m_operator) switch(m_operator)
...@@ -1040,6 +1074,44 @@ class ExprAstBinary : public ExprAst ...@@ -1040,6 +1074,44 @@ class ExprAstBinary : public ExprAst
{ {
return lhs.toInt()>=rhs.toInt(); return lhs.toInt()>=rhs.toInt();
} }
case Operator::Plus:
{
return TemplateVariant(lhs.toInt() + rhs.toInt());
}
case Operator::Minus:
{
return TemplateVariant(lhs.toInt() - rhs.toInt());
}
case Operator::Multiply:
{
return TemplateVariant(lhs.toInt() * rhs.toInt());
}
case Operator::Divide:
{
int denom = rhs.toInt();
if (denom!=0)
{
return TemplateVariant(lhs.toInt() / denom);
}
else // divide by zero
{
ci->warn(ci->templateName(),ci->line(),"division by zero while evaluating expression is undefined");
return 0;
}
}
case Operator::Modulo:
{
int denom = rhs.toInt();
if (denom!=0)
{
return TemplateVariant(lhs.toInt() % denom);
}
else // module zero
{
ci->warn(ci->templateName(),ci->line(),"modulo zero while evaluating expression is undefined");
return 0;
}
}
default: default:
return TemplateVariant(); return TemplateVariant();
} }
...@@ -1110,23 +1182,7 @@ class ExpressionParser ...@@ -1110,23 +1182,7 @@ class ExpressionParser
if (expr==0) return 0; if (expr==0) return 0;
m_tokenStream = expr; m_tokenStream = expr;
getNextToken(); getNextToken();
return parseOrExpression(); return parseExpression();
}
ExprAst *parsePrimary(const char *expr)
{
if (expr==0) return 0;
m_tokenStream = expr;
getNextToken();
return parsePrimaryExpression();
}
ExprAst *parseVariable(const char *varExpr)
{
if (varExpr==0) return 0;
m_tokenStream = varExpr;
getNextToken();
return parseFilteredVariable();
} }
private: private:
...@@ -1149,6 +1205,14 @@ class ExpressionParser ...@@ -1149,6 +1205,14 @@ class ExpressionParser
Operator::Type op; Operator::Type op;
}; };
ExprAst *parseExpression()
{
TRACE(("{parseExpression(%s)\n",m_tokenStream));
ExprAst *result = parseOrExpression();
TRACE(("}parseExpression(%s)\n",m_tokenStream));
return result;
}
ExprAst *parseOrExpression() ExprAst *parseOrExpression()
{ {
TRACE(("{parseOrExpression(%s)\n",m_tokenStream)); TRACE(("{parseOrExpression(%s)\n",m_tokenStream));
...@@ -1212,7 +1276,7 @@ class ExpressionParser ...@@ -1212,7 +1276,7 @@ class ExpressionParser
ExprAst *parseCompareExpression() ExprAst *parseCompareExpression()
{ {
TRACE(("{parseCompareExpression(%s)\n",m_tokenStream)); TRACE(("{parseCompareExpression(%s)\n",m_tokenStream));
ExprAst *lhs = parsePrimaryExpression(); ExprAst *lhs = parseAdditiveExpression();
if (lhs) if (lhs)
{ {
Operator::Type op = m_curToken.op; Operator::Type op = m_curToken.op;
...@@ -1235,6 +1299,74 @@ class ExpressionParser ...@@ -1235,6 +1299,74 @@ class ExpressionParser
return lhs; return lhs;
} }
ExprAst *parseAdditiveExpression()
{
TRACE(("{parseAdditiveExpression(%s)\n",m_tokenStream));
ExprAst *lhs = parseMultiplicativeExpression();
if (lhs)
{
while (m_curToken.type==ExprToken::Operator &&
(m_curToken.op==Operator::Plus || m_curToken.op==Operator::Minus))
{
Operator::Type op = m_curToken.op;
getNextToken();
ExprAst *rhs = parseMultiplicativeExpression();
lhs = new ExprAstBinary(op,lhs,rhs);
}
}
TRACE(("}parseAdditiveExpression(%s)\n",m_tokenStream));
return lhs;
}
ExprAst *parseMultiplicativeExpression()
{
TRACE(("{parseMultiplicativeExpression(%s)\n",m_tokenStream));
ExprAst *lhs = parseUnaryExpression();
if (lhs)
{
while (m_curToken.type==ExprToken::Operator &&
(m_curToken.op==Operator::Multiply || m_curToken.op==Operator::Divide || m_curToken.op==Operator::Modulo))
{
Operator::Type op = m_curToken.op;
getNextToken();
ExprAst *rhs = parseUnaryExpression();
lhs = new ExprAstBinary(op,lhs,rhs);
}
}
TRACE(("}parseMultiplicativeExpression(%s)\n",m_tokenStream));
return lhs;
}
ExprAst *parseUnaryExpression()
{
TRACE(("{parseUnaryExpression(%s)\n",m_tokenStream));
ExprAst *result=0;
if (m_curToken.type==ExprToken::Operator)
{
if (m_curToken.op==Operator::Plus)
{
getNextToken();
result = parsePrimaryExpression();
}
else if (m_curToken.op==Operator::Minus)
{
getNextToken();
ExprAst *rhs = parsePrimaryExpression();
result = new ExprAstUnary(m_curToken.op,rhs);
}
else
{
result = parsePrimaryExpression();
}
}
else
{
result = parsePrimaryExpression();
}
TRACE(("}parseUnaryExpression(%s)\n",m_tokenStream));
return result;
}
ExprAst *parsePrimaryExpression() ExprAst *parsePrimaryExpression()
{ {
TRACE(("{parsePrimary(%s)\n",m_tokenStream)); TRACE(("{parsePrimary(%s)\n",m_tokenStream));
...@@ -1250,17 +1382,30 @@ class ExpressionParser ...@@ -1250,17 +1382,30 @@ class ExpressionParser
case ExprToken::Literal: case ExprToken::Literal:
result = parseLiteral(); result = parseLiteral();
break; break;
default: case ExprToken::Operator:
if (m_curToken.type==ExprToken::Operator) if (m_curToken.op==Operator::LeftParen)
{ {
warn(m_parser->templateName(),m_line,"unexpected operator '%s' in expression", getNextToken(); // skip over opening bracket
Operator::toString(m_curToken.op)); result = parseExpression();
if (m_curToken.type!=ExprToken::Operator ||
m_curToken.op!=Operator::RightParen)
{
warn(m_parser->templateName(),m_line,"missing closing parenthesis");
} }
else else
{ {
warn(m_parser->templateName(),m_line,"unexpected token in expression"); getNextToken(); // skip over closing bracket
} }
} }
else
{
warn(m_parser->templateName(),m_line,"unexpected operator '%s' in expression",
Operator::toString(m_curToken.op));
}
break;
default:
warn(m_parser->templateName(),m_line,"unexpected token in expression");
}
TRACE(("}parsePrimary(%s)\n",m_tokenStream)); TRACE(("}parsePrimary(%s)\n",m_tokenStream));
return result; return result;
} }
...@@ -1364,83 +1509,121 @@ class ExpressionParser ...@@ -1364,83 +1509,121 @@ class ExpressionParser
if (p==0 || *p=='\0') return FALSE; if (p==0 || *p=='\0') return FALSE;
while (*p==' ') p++; // skip over spaces while (*p==' ') p++; // skip over spaces
char c=*p; char c=*p;
if (strncmp(p,"not ",4)==0) const char *q = p;
{ switch (c)
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Not;
p+=4;
}
else if (strncmp(p,"and ",4)==0)
{ {
m_curToken.type = ExprToken::Operator; case '=':
m_curToken.op = Operator::And; if (c=='=' && *(p+1)=='=') // equal
p+=4;
}
else if (strncmp(p,"or ",3)==0)
{ {
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Or;
p+=3;
}
else if (c=='=' && *(p+1)=='=')
{
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Equal; m_curToken.op = Operator::Equal;
p+=2; p+=2;
} }
else if (c=='!' && *(p+1)=='=') break;
case '!':
if (c=='!' && *(p+1)=='=') // not equal
{ {
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::NotEqual; m_curToken.op = Operator::NotEqual;
p+=2; p+=2;
} }
else if (c=='<' && *(p+1)=='=') break;
case '<':
if (c=='<' && *(p+1)=='=') // less or equal
{ {
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::LessEqual; m_curToken.op = Operator::LessEqual;
p+=2; p+=2;
} }
else if (c=='>' && *(p+1)=='=') else // less
{
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::GreaterEqual;
p+=2;
}
else if (c=='<')
{ {
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Less; m_curToken.op = Operator::Less;
p++; p++;
} }
else if (c=='>') break;
case '>':
if (c=='>' && *(p+1)=='=') // greater or equal
{
m_curToken.op = Operator::GreaterEqual;
p+=2;
}
else // greater
{ {
m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Greater; m_curToken.op = Operator::Greater;
p++; p++;
} }
else if (c=='|') break;
{ case '(':
m_curToken.type = ExprToken::Operator; m_curToken.op = Operator::LeftParen;
p++;
break;
case ')':
m_curToken.op = Operator::RightParen;
p++;
break;
case '|':
m_curToken.op = Operator::Filter; m_curToken.op = Operator::Filter;
p++; p++;
} break;
else if (c==':') case '+':
{ m_curToken.op = Operator::Plus;
m_curToken.type = ExprToken::Operator; p++;
break;
case '-':
m_curToken.op = Operator::Minus;
p++;
break;
case '*':
m_curToken.op = Operator::Multiply;
p++;
break;
case '/':
m_curToken.op = Operator::Divide;
p++;
break;
case '%':
m_curToken.op = Operator::Modulo;
p++;
break;
case ':':
m_curToken.op = Operator::Colon; m_curToken.op = Operator::Colon;
p++; p++;
break;
case ',':
m_curToken.op = Operator::Comma;
p++;
break;
case 'n':
if (strncmp(p,"not ",4)==0)
{
m_curToken.op = Operator::Not;
p+=4;
}
break;
case 'a':
if (strncmp(p,"and ",4)==0)
{
m_curToken.op = Operator::And;
p+=4;
}
break;
case 'o':
if (strncmp(p,"or ",3)==0)
{
m_curToken.op = Operator::Or;
p+=3;
}
break;
default:
break;
} }
else if (c==',') if (p!=q) // found an operator
{ {
m_curToken.type = ExprToken::Operator; m_curToken.type = ExprToken::Operator;
m_curToken.op = Operator::Comma;
p++;
} }
else if ((c=='-' && *(p+1)>='0' && *(p+1)<='9') || (c>='0' && c<='9')) else // no token found yet
{
if (c>='0' && c<='9') // number?
{ {
m_curToken.type = ExprToken::Number; m_curToken.type = ExprToken::Number;
const char *np = p; const char *np = p;
if (c=='-') np++;
m_curToken.num = 0; m_curToken.num = 0;
while (*np>='0' && *np<='9') while (*np>='0' && *np<='9')
{ {
...@@ -1448,10 +1631,9 @@ class ExpressionParser ...@@ -1448,10 +1631,9 @@ class ExpressionParser
m_curToken.num+=*np-'0'; m_curToken.num+=*np-'0';
np++; np++;
} }
if (c=='-') m_curToken.num=-m_curToken.num;
p=np; p=np;
} }
else if (c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z')) else if (c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z')) // identifier?
{ {
m_curToken.type = ExprToken::Identifier; m_curToken.type = ExprToken::Identifier;
s[0]=c; s[0]=c;
...@@ -1479,7 +1661,7 @@ class ExpressionParser ...@@ -1479,7 +1661,7 @@ class ExpressionParser
m_curToken.num = 0; m_curToken.num = 0;
} }
} }
else if (c=='"' || c=='\'') else if (c=='"' || c=='\'') // string literal
{ {
m_curToken.type = ExprToken::Literal; m_curToken.type = ExprToken::Literal;
m_curToken.id.resize(0); m_curToken.id.resize(0);
...@@ -1498,7 +1680,8 @@ class ExpressionParser ...@@ -1498,7 +1680,8 @@ class ExpressionParser
} }
if (*p==tokenChar) p++; if (*p==tokenChar) p++;
} }
else }
if (p==q) // still no valid token found -> error
{ {
m_curToken.type = ExprToken::Unknown; m_curToken.type = ExprToken::Unknown;
char s[2]; char s[2];
...@@ -1758,7 +1941,11 @@ class TemplateNodeVariable : public TemplateNode ...@@ -1758,7 +1941,11 @@ class TemplateNodeVariable : public TemplateNode
{ {
TRACE(("TemplateNodeVariable(%s)\n",var.data())); TRACE(("TemplateNodeVariable(%s)\n",var.data()));
ExpressionParser expParser(parser,line); ExpressionParser expParser(parser,line);
m_var = expParser.parseVariable(var); m_var = expParser.parse(var);
if (m_var==0)
{
parser->warn(m_templateName,line,"invalid expression '%s' for variable",var.data());
}
} }
~TemplateNodeVariable() ~TemplateNodeVariable()
{ {
...@@ -1769,6 +1956,8 @@ class TemplateNodeVariable : public TemplateNode ...@@ -1769,6 +1956,8 @@ class TemplateNodeVariable : public TemplateNode
{ {
TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c); TemplateContextImpl* ci = dynamic_cast<TemplateContextImpl*>(c);
ci->setLocation(m_templateName,m_line); ci->setLocation(m_templateName,m_line);
if (m_var)
{
TemplateVariant v = m_var->resolve(c); TemplateVariant v = m_var->resolve(c);
if (v.type()==TemplateVariant::Function) if (v.type()==TemplateVariant::Function)
{ {
...@@ -1784,6 +1973,7 @@ class TemplateNodeVariable : public TemplateNode ...@@ -1784,6 +1973,7 @@ class TemplateNodeVariable : public TemplateNode
ts << v.toString(); ts << v.toString();
} }
} }
}
private: private:
QCString m_templateName; QCString m_templateName;
...@@ -1893,7 +2083,7 @@ class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat> ...@@ -1893,7 +2083,7 @@ class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat>
{ {
TRACE(("{TemplateNodeRepeat(%s)\n",data.data())); TRACE(("{TemplateNodeRepeat(%s)\n",data.data()));
ExpressionParser expParser(parser,line); ExpressionParser expParser(parser,line);
m_expr = expParser.parseVariable(data); m_expr = expParser.parse(data);
QStrList stopAt; QStrList stopAt;
stopAt.append("endrepeat"); stopAt.append("endrepeat");
parser->parse(this,line,stopAt,m_repeatNodes); parser->parse(this,line,stopAt,m_repeatNodes);
...@@ -1985,7 +2175,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor> ...@@ -1985,7 +2175,7 @@ class TemplateNodeFor : public TemplateNodeCreator<TemplateNodeFor>
} }
} }
ExpressionParser expParser(parser,line); ExpressionParser expParser(parser,line);
m_expr = expParser.parseVariable(exprStr); m_expr = expParser.parse(exprStr);
QStrList stopAt; QStrList stopAt;
stopAt.append("endfor"); stopAt.append("endfor");
...@@ -2215,7 +2405,7 @@ class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend> ...@@ -2215,7 +2405,7 @@ class TemplateNodeExtend : public TemplateNodeCreator<TemplateNodeExtend>
{ {
parser->warn(m_templateName,line,"extend tag is missing template file argument"); parser->warn(m_templateName,line,"extend tag is missing template file argument");
} }
m_extendExpr = ep.parsePrimary(data); m_extendExpr = ep.parse(data);
QStrList stopAt; QStrList stopAt;
parser->parse(this,line,stopAt,m_nodes); parser->parse(this,line,stopAt,m_nodes);
TRACE(("}TemplateNodeExtend(%s)\n",data.data())); TRACE(("}TemplateNodeExtend(%s)\n",data.data()));
...@@ -2298,7 +2488,7 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude> ...@@ -2298,7 +2488,7 @@ class TemplateNodeInclude : public TemplateNodeCreator<TemplateNodeInclude>
{ {
parser->warn(m_templateName,line,"include tag is missing template file argument"); parser->warn(m_templateName,line,"include tag is missing template file argument");
} }
m_includeExpr = ep.parsePrimary(data); m_includeExpr = ep.parse(data);
} }
~TemplateNodeInclude() ~TemplateNodeInclude()
{ {
...@@ -2374,8 +2564,8 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate> ...@@ -2374,8 +2564,8 @@ class TemplateNodeCreate : public TemplateNodeCreator<TemplateNodeCreate>
else else
{ {
ExpressionParser ep(parser,line); ExpressionParser ep(parser,line);
m_fileExpr = ep.parsePrimary(data.left(i).stripWhiteSpace()); m_fileExpr = ep.parse(data.left(i).stripWhiteSpace());
m_templateExpr = ep.parsePrimary(data.mid(i+6).stripWhiteSpace()); m_templateExpr = ep.parse(data.mid(i+6).stripWhiteSpace());
} }
} }
~TemplateNodeCreate() ~TemplateNodeCreate()
...@@ -2461,7 +2651,7 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> ...@@ -2461,7 +2651,7 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
{ {
parser->warn(m_templateName,line,"recursetree tag is missing data argument"); parser->warn(m_templateName,line,"recursetree tag is missing data argument");
} }
m_treeExpr = ep.parsePrimary(data); m_treeExpr = ep.parse(data);
QStrList stopAt; QStrList stopAt;
stopAt.append("endrecursetree"); stopAt.append("endrecursetree");
parser->parse(this,line,stopAt,m_treeNodes); parser->parse(this,line,stopAt,m_treeNodes);
...@@ -2569,7 +2759,7 @@ class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith> ...@@ -2569,7 +2759,7 @@ class TemplateNodeWith : public TemplateNodeCreator<TemplateNodeWith>
int j=arg.find('='); int j=arg.find('=');
if (j>0) if (j>0)
{ {
ExprAst *expr = expParser.parsePrimary(arg.mid(j+1)); ExprAst *expr = expParser.parse(arg.mid(j+1));
if (expr) if (expr)
{ {
m_args.append(new Mapping(arg.left(j),expr)); m_args.append(new Mapping(arg.left(j),expr));
...@@ -2627,7 +2817,7 @@ class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle> ...@@ -2627,7 +2817,7 @@ class TemplateNodeCycle : public TemplateNodeCreator<TemplateNodeCycle>
QValueListIterator<QCString> it = args.begin(); QValueListIterator<QCString> it = args.begin();
while (it!=args.end()) while (it!=args.end())
{ {
ExprAst *expr = expParser.parsePrimary(*it); ExprAst *expr = expParser.parse(*it);
if (expr) if (expr)
{ {
m_args.append(expr); m_args.append(expr);
...@@ -2697,7 +2887,7 @@ class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet> ...@@ -2697,7 +2887,7 @@ class TemplateNodeSet : public TemplateNodeCreator<TemplateNodeSet>
int j=arg.find('='); int j=arg.find('=');
if (j>0) if (j>0)
{ {
ExprAst *expr = expParser.parsePrimary(arg.mid(j+1)); ExprAst *expr = expParser.parse(arg.mid(j+1));
if (expr) if (expr)
{ {
m_args.append(new Mapping(arg.left(j),expr)); m_args.append(new Mapping(arg.left(j),expr));
...@@ -2776,8 +2966,8 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers> ...@@ -2776,8 +2966,8 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
{ {
ExpressionParser expParser(parser,line); ExpressionParser expParser(parser,line);
m_var = data.left(i); m_var = data.left(i);
m_listExpr = expParser.parseVariable(data.mid(i+4,w-i-4)); m_listExpr = expParser.parse(data.mid(i+4,w-i-4));
m_patternExpr = expParser.parseVariable(data.right(data.length()-w-6)); m_patternExpr = expParser.parse(data.right(data.length()-w-6));
} }
QStrList stopAt; QStrList stopAt;
stopAt.append("endmarkers"); stopAt.append("endmarkers");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment