Loading src/template.cpp +357 −167 Original line number Original line Diff line number Diff line Loading @@ -504,6 +504,8 @@ class Operator not not in in ==, !=, <, >, <=, >= ==, !=, <, >, <=, >= +, - *, /, % | | : : , , Loading @@ -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) Loading @@ -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 "?"; Loading Loading @@ -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) Loading Loading @@ -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 { { Loading @@ -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) Loading Loading @@ -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(); } } Loading Loading @@ -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: Loading @@ -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)); Loading Loading @@ -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; Loading @@ -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)); Loading @@ -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; } } Loading Loading @@ -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') { { Loading @@ -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; Loading Loading @@ -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); Loading @@ -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]; Loading Loading @@ -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() { { Loading @@ -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) { { Loading @@ -1784,6 +1973,7 @@ class TemplateNodeVariable : public TemplateNode ts << v.toString(); ts << v.toString(); } } } } } private: private: QCString m_templateName; QCString m_templateName; Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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())); Loading Loading @@ -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() { { Loading Loading @@ -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() Loading Loading @@ -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); Loading Loading @@ -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)); Loading Loading @@ -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); Loading Loading @@ -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)); Loading Loading @@ -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"); Loading Loading
src/template.cpp +357 −167 Original line number Original line Diff line number Diff line Loading @@ -504,6 +504,8 @@ class Operator not not in in ==, !=, <, >, <=, >= ==, !=, <, >, <=, >= +, - *, /, % | | : : , , Loading @@ -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) Loading @@ -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 "?"; Loading Loading @@ -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) Loading Loading @@ -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 { { Loading @@ -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) Loading Loading @@ -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(); } } Loading Loading @@ -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: Loading @@ -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)); Loading Loading @@ -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; Loading @@ -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)); Loading @@ -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; } } Loading Loading @@ -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') { { Loading @@ -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; Loading Loading @@ -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); Loading @@ -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]; Loading Loading @@ -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() { { Loading @@ -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) { { Loading @@ -1784,6 +1973,7 @@ class TemplateNodeVariable : public TemplateNode ts << v.toString(); ts << v.toString(); } } } } } private: private: QCString m_templateName; QCString m_templateName; Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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())); Loading Loading @@ -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() { { Loading Loading @@ -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() Loading Loading @@ -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); Loading Loading @@ -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)); Loading Loading @@ -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); Loading Loading @@ -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)); Loading Loading @@ -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"); Loading