00001
00002
00003
00004
00005
00006
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
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
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
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
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 }