Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

componentfile_preprocess.cpp

Go to the documentation of this file.
00001 /*
00002         ClanGUI, copyrights by various people. Have a look in the CREDITS file.
00003         
00004         This sourcecode is distributed using the Library GNU Public Licence,
00005         version 2 or (at your option) any later version. Please read LICENSE
00006         for details.
00007 */
00008 
00009 #include "precomp.h"
00010 #include <algorithm>
00011 
00012 #include "API/Core/System/error.h"
00013 #include "API/GUI/component_manager.h"
00014 
00015 #include "componentfile_preprocess.h"
00016 #include "component_tokenizer.h"
00017 
00018 CL_Componentfile_Preprocess::CL_Componentfile_Preprocess(
00019         const std::string &_data,
00020         const std::string &filename) : data(_data)
00021 {
00022         CL_ComponentTokenizer lexer(data, filename);
00023         EParseState state = PARSE_GLOBAL;
00024         EParseState instantiation_dest_state = PARSE_GLOBAL;
00025 
00026         typedef std::map<std::string, TemplateDefinition *> TMAP;
00027         TMAP template_map;
00028 
00029         int offset;
00030         int body_scoping_count = 0;
00031         int cur_template_arg = 0;
00032 //      bool copy_to_output = true;
00033         std::string template_name;
00034         std::string last_variable_name;
00035         int last_variable_offset = 0;
00036         std::string last_token;
00037         int last_offset = 0;
00038         TemplateDefinition *cur = NULL;
00039 
00040         TMAP::iterator cur_instantiation;
00041         std::vector<std::string> template_arg_vals;
00042         std::string cur_template_arg_val;
00043 
00044         std::vector<TemplateReplacement> replacements_local;
00045         std::vector<TemplateReplacement> replacements_global;
00046         std::vector<TemplateReplacement> *cur_replacement_list = NULL;
00047 
00048         while (true)
00049         {
00050                 bool pop_token = true;
00051                 const std::string &token = lexer.peek_next_token(&offset);
00052                 if (token == "") break;
00053 
00054                 if (token == "=")
00055                 {
00056                         last_variable_name = last_token;
00057                         last_variable_offset = last_offset;
00058                 }
00059                 last_token = token;
00060                 last_offset = offset;
00061                 
00062                 switch (state)
00063                 {
00064                 case PARSE_GLOBAL:
00065                         if (token == "template")
00066                         {
00067                                 state = PARSE_TEMPLATE;
00068                                 cur = new TemplateDefinition;
00069                                 cur->file_offset = offset;
00070                         }
00071                         else
00072                         {
00073                                 TMAP::iterator f_it = template_map.find(token);
00074                                 if (f_it != template_map.end())
00075                                 {
00076                                         state = PARSE_TEMPLATE_INSTANTIATION;
00077                                         instantiation_dest_state = PARSE_GLOBAL;
00078                                         cur_instantiation = f_it;
00079                                         cur_replacement_list = &replacements_global;
00080                                 }
00081                         }
00082                         break;
00083                 case PARSE_TEMPLATE:
00084                         if (token == "<")
00085                         {
00086                                 state = PARSE_TEMPLATE_ARG;
00087                                 cur_template_arg = 0;
00088                         }
00089                         else
00090                         {
00091                                 state = PARSE_TEMPLATE_NAMEDEF;
00092                                 pop_token = false;
00093                         }
00094                         break;
00095                 case PARSE_TEMPLATE_ARG:
00096                         {
00097                                 const std::string &peek = lexer.peek_next_token();
00098                                 if (peek == ",")
00099                                 {
00100                                         // nop!
00101                                 }
00102                                 else if (peek == ">")
00103                                 {
00104                                         state = PARSE_TEMPLATE_NAMEDEF;
00105                                 }
00106                                 else
00107                                 {
00108                                         throw CL_Error(lexer.write_error("Invalid template syntax"));
00109                                 }
00110                                 cur->conversions[token] = std::make_pair(cur_template_arg, std::list<int>());
00111                                 cur_template_arg++;
00112                         }
00113                         break;
00114                 case PARSE_TEMPLATE_NAMEDEF:
00115                         cur->definition_copy_offset = offset;
00116                         if (CL_ComponentManager::component_types.find(token) != CL_ComponentManager::component_types.end())
00117                         {
00118                                 const std::string &peek = lexer.peek_next_token(&offset);
00119                                 if (peek == "{") throw CL_Error(lexer.write_error("Missing name"));
00120                                 template_name = peek;
00121                                 cur->name_offset = offset - cur->file_offset;
00122                                 state = PARSE_TEMPLATE_BODY;
00123                                 body_scoping_count = 0;
00124                         }
00125                         else
00126                         {
00127                                 throw CL_Error(lexer.write_error("Missing component type"));
00128                         }
00129                         break;
00130                 case PARSE_TEMPLATE_BODY:
00131                         if (token == "{")
00132                         {
00133                                 body_scoping_count++;
00134                         }
00135                         else if (token == "}")
00136                         {
00137                                 body_scoping_count--;
00138                                 if (body_scoping_count == 0)
00139                                 {
00140                                         cur->definition = std::string(
00141                                                 &data.c_str()[cur->file_offset], 
00142                                                 offset+token.length() - cur->file_offset);
00143 
00144                                         TemplateReplacement s;
00145                                         s.erase_length = cur->definition.length();
00146                                         s.offset = cur->file_offset;
00147                                         replacements_global.push_back(s);
00148 
00149                                         perform_replacements(cur->definition, replacements_local, cur->file_offset);
00150                                         replacements_local.clear();
00151 
00152 //                                      std::cout << "Template: '" << cur->definition.c_str() << std::endl;
00153                                         state = PARSE_GLOBAL;
00154                                         template_map[template_name] = cur;
00155                                         cur = NULL;
00156                                 }
00157                         }
00158                         else if (cur->conversions.find(token) != cur->conversions.end())
00159                         {
00160                                 cur->conversions[token].second.push_back(offset - cur->file_offset);
00161                         }
00162                         else
00163                         {
00164                                 TMAP::iterator f_it = template_map.find(token);
00165                                 if (f_it != template_map.end())
00166                                 {
00167                                         state = PARSE_TEMPLATE_INSTANTIATION;
00168                                         instantiation_dest_state = PARSE_TEMPLATE_BODY;
00169                                         cur_instantiation = f_it;
00170                                         cur_replacement_list = &replacements_local;
00171                                 }
00172                         }
00173                         break;
00174                 case PARSE_TEMPLATE_INSTANTIATION:
00175                         if (token != "<")
00176                         {
00177                                 throw CL_Error(lexer.write_error("Missing '<' following use of template"));
00178                         }
00179                         state = PARSE_TEMPLATE_INSTANTIATION_ARG;
00180                         cur_template_arg = 0;
00181                         break;
00182                 case PARSE_TEMPLATE_INSTANTIATION_ARG:
00183                         {
00184                                 if (token != "," && token != ">")
00185                                 {
00186                                         cur_template_arg_val.append(token);
00187                                         cur_template_arg_val.append(1, ' ');
00188                                 }
00189                                 else
00190                                 {
00191                                         cur_template_arg_val.erase(cur_template_arg_val.length()-1, 1);
00192                                         template_arg_vals.push_back(cur_template_arg_val);
00193                                         cur_template_arg_val = "";
00194                                         cur_template_arg++;
00195 
00196                                         if (token == ">")
00197                                         {
00198                                                 if (lexer.peek_next_token(&offset) != ";")
00199                                                 {
00200                                                         throw CL_Error(lexer.write_error("Missing ';' following template instantiation"));
00201                                                 }
00202                                                 state = instantiation_dest_state;
00203                                                 int template_instantiation_length = offset - last_variable_offset + 1;
00204                                                 std::string expanded_template_instantiation = (*cur_instantiation).second->definition;
00205 
00206                                                 std::vector<TemplateReplacement> replacements;
00207 
00208                                                 TemplateDefinition *cur_definition = (*cur_instantiation).second;
00209                                                 std::string cur_definition_name = (*cur_instantiation).first;
00210                                                 for (int i=0;i<(int) template_arg_vals.size();i++)
00211                                                 {
00212                                                         TemplateDefinition::CONV_MAP::iterator it = cur_definition->conversions.begin();
00213                                                         for (;it!=cur_definition->conversions.end();it++)
00214                                                         {
00215                                                                 if ((*it).second.first == i)
00216                                                                 {
00217                                                                         int name_length = (*it).first.length();
00218                                                                         std::list<int> &clist = (*it).second.second;
00219                                                                         std::list<int>::iterator c_it = clist.begin();
00220                                                                         std::list<int>::iterator c_it_end = clist.end();
00221                                                                         for (;c_it!=c_it_end;c_it++)
00222                                                                         {
00223                                                                                 TemplateReplacement s;
00224                                                                                 s.offset = *c_it;
00225                                                                                 s.erase_length = name_length;
00226                                                                                 s.new_text = template_arg_vals[i];
00227                                                                                 replacements.push_back(s);
00228                                                                         }
00229                                                                 }
00230                                                         }
00231                                                 }
00232                                                 perform_replacements(expanded_template_instantiation, replacements, 0);
00233 
00234                                                 expanded_template_instantiation.erase(cur_definition->name_offset, cur_definition_name.length());
00235                                                 expanded_template_instantiation.insert(cur_definition->name_offset, last_variable_name);
00236                                                 expanded_template_instantiation.erase(0, cur_definition->definition_copy_offset - cur_definition->file_offset);
00237 
00238         //                                      std::cout << expanded_template_instantiation.c_str() << std::endl;
00239 
00240                                                 TemplateReplacement s;
00241                                                 s.erase_length = template_instantiation_length;
00242                                                 s.new_text = expanded_template_instantiation;
00243                                                 s.offset = last_variable_offset;
00244                                                 cur_replacement_list->push_back(s);
00245 
00246                                                 template_arg_vals.clear();
00247                                         }
00248                                 }
00249                         }
00250                         break;
00251                 default:
00252                         throw CL_Error(lexer.write_error("Internal component manager preprocessor error"));
00253                 }
00254 
00255                 if (pop_token) lexer.pop_to_peek();
00256         }
00257 
00258         perform_replacements(data, replacements_global, 0);
00259 }
00260         
00261 void CL_Componentfile_Preprocess::perform_replacements(
00262         std::string &string_data,
00263         std::vector<TemplateReplacement> &replacements,
00264         int global_offset)
00265 {
00266         std::sort(replacements.begin(), replacements.end(), SortTemplateReplacementByLocationDescending());
00267         std::vector<TemplateReplacement>::iterator it = replacements.begin();
00268         std::vector<TemplateReplacement>::iterator it_end = replacements.end();
00269         for (;it!=it_end;it++)
00270         {
00271                 TemplateReplacement &s = *it;
00272                 string_data.erase(s.offset-global_offset, s.erase_length);
00273                 string_data.insert(s.offset-global_offset, s.new_text);
00274         }
00275 }

Generated at Wed Apr 4 19:53:59 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001