CPPSERV


Home Projects Jobs Clientele Contact
CPPSERV Documentation Download TODO Mailing lists Bug tracker News RSS Feed Browse source

ConditionalTags.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2011 by Ilya A. Volynets-Evenbakh                       *
00003  *   ilya@total-knowledge.com                                              *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include "StdTagBase.h"
00022 #include <ctype.h>
00023 #include <sstream>
00024 #include <list>
00025 
00026 using namespace servlet::taglib;
00027 using namespace std;
00028 
00029 namespace csp
00030 {
00031 namespace tags
00032 {
00033 
00034 
00038 class IfTag: public StdTagBase
00039 {
00040 private:
00041     string m_cond;
00042 public:
00043     IfTag(const string& name)
00044         : StdTagBase(name)
00045     {}
00046     virtual void doStartTag(const attribs_t& attribs);
00047     virtual void doEndTag();
00048 };
00049 
00050 void IfTag::doStartTag(const Generator::attribs_t& attribs)
00051 {
00052     get_attr(attribs, "test", m_cond, "csp:if");
00053     *body << "if(" << m_cond << ") {"<<endl;
00054     //TODO: indent generated code in output?
00055 }
00056 
00057 void IfTag::doEndTag()
00058 {
00059     *body<<endl<<"} /* end csp:foreach_attr: "<<m_cond<<" */"<<endl;
00060 }
00061 
00073 class ChoiceTag: public StdTagBase
00074 {
00075 private:
00076     stringstream m_my_body;
00077     struct condition
00078     {
00079         string name;
00080         string cond; // ignored by "otherwise"
00081         string body;
00082     };
00083     list<condition> m_conditions;
00084     condition* m_my_condition;
00085 public:
00086     ChoiceTag(const string& name)
00087         : StdTagBase(name)
00088         , m_my_condition(0)
00089     {}
00090     virtual void doStartTag(const attribs_t& attribs);
00091     virtual void doEndTag();
00092     virtual void initChildBuffers();
00093 private:
00094     void doWhenStartTag(const attribs_t& attribs);
00095     void doTopEndTag();
00096     void doChildEndTag();
00097 };
00098 
00099 void ChoiceTag::initChildBuffers()
00100 {
00101     StdTagBase::initChildBuffers();
00102     m_child_body = &m_my_body;
00103     if(getName()!="csp:choice") {
00104         ChoiceTag* parent = (ChoiceTag*)this->parent;
00105         condition c;
00106         parent->m_conditions.push_back(c);
00107         m_my_condition = &parent->m_conditions.back();
00108         m_my_condition->name = getName();
00109     }
00110 }
00111 
00112 void ChoiceTag::doWhenStartTag(const Generator::attribs_t& attribs)
00113 {
00114     ChoiceTag* parent = (ChoiceTag*)this->parent;
00115     get_attr(attribs, "test", m_my_condition->cond, "csp:when");
00116 }
00117 
00118 void ChoiceTag::doStartTag(const Generator::attribs_t& attribs)
00119 {
00120     if(getName() != "csp:choice") {
00121         if(this->parent->getName()!="csp:choice")
00122             throw runtime_error("<"+getName()+"> must be enclosed in <csp:choice> tag.");
00123     }
00124     if(getName() == "csp:when")
00125         doWhenStartTag(attribs);
00126 }
00127 
00128 void ChoiceTag::doEndTag()
00129 {
00130     if(getName() == "csp:choice")
00131         doTopEndTag();
00132     else
00133         doChildEndTag();
00134 }
00135 void ChoiceTag::doChildEndTag()
00136 {
00137     m_my_condition->body.assign(m_my_body.str());
00138 }
00139 void ChoiceTag::doTopEndTag()
00140 {
00142     /*string cb = m_my_body.str();
00143     if(cb.find_first_not_of(" \t\n") != string::npos)
00144     throw runtime_error("<csp:choice> body contains something other then <csp:when> or <csp:otherwise>: '"+cb+"'");*/
00145     bool otherwise = false;
00146     bool first = true;
00147     for(list<condition>::iterator it = m_conditions.begin(); it!=m_conditions.end(); it++) {
00148         if(otherwise) {
00149             throw runtime_error("<csp:otherwise> can only be the last child of <csp:choice>");
00150         }
00151         if(it->name == "csp:when") {
00152             *body<<((first)?"":"else ")<<"if("<<it->cond<<") {\n" << it->body << "\n}\n";
00153             first=false;
00154         } else if(it->name == "csp:otherwise") {
00155             otherwise = true;
00156             *body<<"else {\n" << it->body << "\n}\n";
00157         } else {
00158             throw runtime_error("Invalid child of <csp:choice>: "+it->name);
00159         }
00160     }
00161 }
00175 class SwitchTag: public StdTagBase
00176 {
00177 private:
00178     stringstream m_my_body;
00179     string m_test;
00180     struct condition
00181     {
00182         string name;
00183         string cond; // ignored by "default"
00184         string body;
00185         bool   fallthrough;
00186     };
00187     list<condition> m_conditions;
00188     condition* m_my_condition;
00189 public:
00190     SwitchTag(const string& name)
00191         : StdTagBase(name)
00192         , m_my_condition(0)
00193     {}
00194     virtual void doStartTag(const attribs_t& attribs);
00195     virtual void doEndTag();
00196     virtual void initChildBuffers();
00197 private:
00198     void doTopEndTag();
00199     void doChildEndTag();
00200 };
00201 
00202 void SwitchTag::initChildBuffers()
00203 {
00204     StdTagBase::initChildBuffers();
00205     m_child_body = &m_my_body;
00206     if(getName()!="csp:switch") {
00207         SwitchTag* parent = (SwitchTag*)this->parent;
00208         condition c;
00209         parent->m_conditions.push_back(c);
00210         m_my_condition = &parent->m_conditions.back();
00211         m_my_condition->name = getName();
00212         m_my_condition->fallthrough = false;
00213     }
00214 }
00215 
00216 void SwitchTag::doStartTag(const Generator::attribs_t& attribs)
00217 {
00218     if(getName() != "csp:switch") {
00219         if(this->parent->getName()!="csp:switch")
00220             throw runtime_error("<"+getName()+"> must be enclosed in <csp:switch> tag.");
00221         SwitchTag* parent = (SwitchTag*)this->parent;
00222         if(getName() == "csp:case")
00223             get_attr(attribs, "value", m_my_condition->cond, "csp:case");
00224         string ft;
00225         get_attr(attribs, "fallthrough", ft, getName(), "false");
00226         m_my_condition->fallthrough = (ft == "true");
00227     } else {
00228         get_attr(attribs, "test", m_test, "csp:switch");
00229     }
00230 }
00231 
00232 void SwitchTag::doEndTag()
00233 {
00234     if(getName() == "csp:switch")
00235         doTopEndTag();
00236     else
00237         doChildEndTag();
00238 }
00239 void SwitchTag::doChildEndTag()
00240 {
00241     m_my_condition->body.assign(m_my_body.str());
00242 }
00243 void SwitchTag::doTopEndTag()
00244 {
00246     /*string cb = m_my_body.str();
00247     if(cb.find_first_not_of(" \t\n") != string::npos)
00248     throw runtime_error("<csp:switch> body contains something other then <csp:case> or <csp:default>: '"+cb+"'");*/
00249     int otherwise = 0;
00250     *body<<"switch ("<<m_test<<") {\n";
00251     for(list<condition>::iterator it = m_conditions.begin(); it!=m_conditions.end(); it++) {
00252         if(it->name == "csp:case") {
00253             *body<<"\tcase "<<it->cond<<":\n\t{" << it->body << "\n\t}\n";
00254             if(!it->fallthrough)
00255                 *body<<"\tbreak;\n";
00256         } else if(it->name == "csp:default") {
00257             otherwise++;
00258             *body<<"default:\n\t{\n" << it->body << "\n\t}\n";
00259             if(!it->fallthrough)
00260                 *body<<"\tbreak;\n";
00261         } else {
00262             throw runtime_error("Invalid child of <csp:switch>: "+it->name);
00263         }
00264         if(otherwise>1) {
00265             throw runtime_error("<csp:default> can only appear once in <csp:switch>");
00266         }
00267     }
00268     *body<<"} /* end of switch("<<m_test<<") */\n";
00269 }
00270 
00271 } //namespace tags
00272 } //namespace csp
00273 DECLARE_COMPILE_TIME_TAGLIB(csp)
00274 EXPORT_COMPILE_TIME_TAG(csp, if, csp::tags::IfTag)
00275 EXPORT_COMPILE_TIME_TAG(csp, choice, csp::tags::ChoiceTag)
00276 EXPORT_COMPILE_TIME_TAG(csp, when, csp::tags::ChoiceTag)
00277 EXPORT_COMPILE_TIME_TAG(csp, otherwise, csp::tags::ChoiceTag)
00278 EXPORT_COMPILE_TIME_TAG(csp, switch, csp::tags::SwitchTag)
00279 EXPORT_COMPILE_TIME_TAG(csp, case, csp::tags::SwitchTag)
00280 EXPORT_COMPILE_TIME_TAG(csp, default, csp::tags::SwitchTag)

SourceForge.net Logo