summaryrefslogtreecommitdiff
path: root/src/bin/eolian_cxx/eolian_cxx.cc
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@samsung.com>2014-06-30 19:32:52 +0100
committerDaniel Kolesa <d.kolesa@samsung.com>2014-06-30 19:35:06 +0100
commitc05493b480b23cf45d2b8de9fe50070939519abb (patch)
tree372dcb9175b63b6e87e09cb9c570ba58e52983cf /src/bin/eolian_cxx/eolian_cxx.cc
parentbd41cfe9ea1633a9dd8e2831f6b1ab37d7ddf41d (diff)
eolian-cxx: Added namespaces and more (see below)
Implemented namespaces Added eolian_wrappers.hh with C++ code wrapping Eolain API Changed eolian_cxx program options. Now they're eolian_gen's Added functions to safe_str.hh (safe_lower, safe_upper, normalize_spaces, path_base) Added a mocked version of type_lookup.hh in advance. The full version will come as soon as complex-types are added. Made apply again by Daniel Kolesa, original implementation by Savio Sena.
Diffstat (limited to 'src/bin/eolian_cxx/eolian_cxx.cc')
-rw-r--r--src/bin/eolian_cxx/eolian_cxx.cc322
1 files changed, 144 insertions, 178 deletions
diff --git a/src/bin/eolian_cxx/eolian_cxx.cc b/src/bin/eolian_cxx/eolian_cxx.cc
index 951397708c..40b226be94 100644
--- a/src/bin/eolian_cxx/eolian_cxx.cc
+++ b/src/bin/eolian_cxx/eolian_cxx.cc
@@ -13,42 +13,40 @@
13#include <type_traits> 13#include <type_traits>
14#include <cassert> 14#include <cassert>
15 15
16extern "C"
17{
18#ifdef HAVE_CONFIG_H 16#ifdef HAVE_CONFIG_H
19# include <config.h> 17# include <config.h>
20#endif 18#endif
21
22#include <Eina.h>
23#include <Eolian.h> 19#include <Eolian.h>
24}
25 20
26#include <Eina.hh> 21#include <Eina.hh>
27#include <Eolian_Cxx.hh> 22#include <Eolian_Cxx.hh>
28 23
29#include "eo_read.h"
30#include "convert.hh" 24#include "convert.hh"
25#include "type_lookup.hh"
26
27#include "convert.hh"
28#include "eolian_wrappers.hh"
31#include "safe_strings.hh" 29#include "safe_strings.hh"
32 30
33namespace { 31namespace eolian_cxx {
34 32
35// Program options. 33/// Program options.
36struct options_type 34struct options_type
37{ 35{
38 std::vector<std::string> in_srcs; 36 std::vector<std::string> include_dirs;
37 std::string in_file;
39 std::string out_file; 38 std::string out_file;
40 std::string out_dir; 39 std::string out_dir;
41 std::string classname; 40 std::string classname;
42 std::string name_space;
43 bool recurse; 41 bool recurse;
44 bool generate_all; 42 bool generate_all;
45 43
46 options_type() 44 options_type()
47 : in_srcs() 45 : include_dirs()
48 , out_file("") 46 , in_file()
49 , out_dir("") 47 , out_file()
50 , classname("") 48 , out_dir()
51 , name_space("") 49 , classname()
52 , recurse(false) 50 , recurse(false)
53 , generate_all(false) 51 , generate_all(false)
54 {} 52 {}
@@ -56,112 +54,80 @@ struct options_type
56 54
57efl::eina::log_domain domain("eolian_cxx"); 55efl::eina::log_domain domain("eolian_cxx");
58 56
59} 57static bool
60 58opts_check(eolian_cxx::options_type const& opts)
61static void
62_opt_error(std::string message)
63{
64 EINA_CXX_DOM_LOG_ERR(::domain) << message << std::endl;
65 exit(EXIT_FAILURE);
66}
67
68static void
69_assert_not_dup(std::string option, std::string value)
70{ 59{
71 if (value != "") 60 if (!opts.generate_all && opts.in_file.empty())
72 { 61 {
73 _opt_error("Option -" + option + " already set (" + value + ")"); 62 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
63 << "Nothing to generate?" << std::endl;
74 } 64 }
75} 65 else if (opts.generate_all && !opts.in_file.empty())
76
77// Try to guess classname from input filenames.
78// Precondition: Input sources must be loaded into Eolian Database
79// otherwise we can't infer the classname from the .eo files.
80// Precondition: Input options must have opts.classname == "".
81static std::string
82_guess_classname_from_sources(::options_type& opts)
83{
84 for (auto filename : opts.in_srcs)
85 { 66 {
86 if (Eolian_Class klass = eolian_class_find_by_file(filename.c_str())) 67 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
87 { 68 << "Didn't expect to receive input files (" << opts.in_file
88 return eolian_class_full_name_get(klass); 69 << ") with parameter -a."
89 } 70 << std::endl;
90 } 71 }
91 return ""; 72 else if (opts.generate_all && !opts.out_file.empty())
92} 73 {
93 74 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
94std::pair<std::string, std::string> get_filename_info(std::string path) 75 << "Can't use -a and -o together." << std::endl;
95{ 76 }
96 const size_t last = path.rfind("lib/"); 77 else if (opts.generate_all && opts.include_dirs.empty())
97 if (last != std::string::npos) 78 {
98 { 79 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
99 path.erase(0, last+4); 80 << "Option -a requires at least one include directory (-I)."
100 81 << std::endl;
101 std::string::iterator slash 82 }
102 = std::find(path.begin(), path.end(), '/'); 83 else
103 if(slash != path.end()) 84 {
104 { 85 return true; // valid.
105 std::string namespace_ (path.begin(), slash); 86 }
106 std::string filename (slash+1, path.end()); 87 return false;
107 return {filename, namespace_};
108 }
109 }
110 std::string::reverse_iterator slash
111 = std::find(path.rbegin(), path.rend(), '/');
112 return {std::string(slash.base(), path.end()), std::string()};
113} 88}
114 89
115efl::eolian::eo_generator_options 90efl::eolian::eo_generator_options
116_resolve_includes(std::string const& classname) 91generator_options(const Eolian_Class klass)
117{ 92{
118 efl::eolian::eo_generator_options gen_opts; 93 efl::eolian::eo_generator_options gen_opts;
119 94 gen_opts.c_headers.push_back(class_base_file(klass) + ".h");
120 std::string cls_name = classname;
121 Eolian_Class klass = eolian_class_find_by_name(classname.c_str());
122 std::transform(cls_name.begin(), cls_name.end(), cls_name.begin(), ::tolower);
123
124 std::string eo_file = safe_str(eolian_class_file_get(klass));
125 gen_opts.c_headers.push_back(get_filename_info(eo_file).first + ".h");
126 95
127 void *cur = NULL; 96 void *cur = NULL;
128 const Eina_List *itr, *inheritances = eolian_class_inherits_list_get(klass); 97 const Eina_List *itr, *inheritances = eolian_class_inherits_list_get(klass);
129 EINA_LIST_FOREACH(inheritances, itr, cur) 98 EINA_LIST_FOREACH(inheritances, itr, cur)
130 { 99 {
131 Eolian_Class ext = eolian_class_find_by_name(static_cast<const char*>(cur)); 100 Eolian_Class ext = eolian_class_find_by_name(static_cast<const char*>(cur));
132 std::string eo_parent_file = safe_str(eolian_class_file_get(ext)); 101 std::string eo_parent_file = class_base_file(ext);
133 if (!eo_parent_file.empty()) 102 if (!eo_parent_file.empty())
134 { 103 {
135 std::string filename, namespace_;
136 std::tie(filename, namespace_) = get_filename_info(eo_parent_file);
137 // we have our own eo_base.hh 104 // we have our own eo_base.hh
138 std::string eo_base_eo = "eo_base.eo"; 105 std::string eo_base_eo = "eo_base.eo";
139 if (filename.length() < eo_base_eo.length() || 106 if (eo_parent_file.length() < eo_base_eo.length() ||
140 !std::equal(eo_base_eo.begin(), eo_base_eo.end(), 107 !std::equal(eo_base_eo.begin(), eo_base_eo.end(),
141 filename.end() - eo_base_eo.length())) 108 eo_parent_file.end() - eo_base_eo.length()))
142 { 109 {
143 gen_opts.cxx_headers.push_back(filename + ".hh"); 110 gen_opts.cxx_headers.push_back(eo_parent_file + ".hh");
144 } 111 }
145 } 112 }
146 else 113 else
147 { 114 {
148 EINA_CXX_DOM_LOG_ERR(::domain) 115 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
149 << "Couldn't find source file for class '" << ext << "'"; 116 << "Couldn't find source file for class '" << ext << "'"
117 << std::endl;
150 } 118 }
151 } 119 }
152 return gen_opts; 120 return gen_opts;
153} 121}
154 122
155static void 123static bool
156_generate(const std::string classname, ::options_type const& opts) 124generate(const Eolian_Class klass, eolian_cxx::options_type const& opts)
157{ 125{
158 efl::eolian::eo_class cls = ::c_to_cxx(classname.c_str()); 126 assert(!!klass);
159 cls.name_space = opts.name_space; 127 efl::eolian::eo_class cls = eolian_cxx::convert_eolian_class(klass);
160 efl::eolian::eo_class_validate(cls); 128 efl::eolian::eo_generator_options gen_opts = generator_options(klass);
161 efl::eolian::eo_generator_options gen_opts = _resolve_includes(classname); 129 std::string outname = opts.out_file.empty() ? (class_base_file(klass) + ".hh") : opts.out_file;
162 std::string outname = (opts.out_file == "") ? (cls.name + ".eo.hh") : opts.out_file; 130 if (!opts.out_dir.empty())
163
164 if (opts.out_dir != "")
165 { 131 {
166 outname = opts.out_dir + "/" + outname; 132 outname = opts.out_dir + "/" + outname;
167 } 133 }
@@ -173,105 +139,96 @@ _generate(const std::string classname, ::options_type const& opts)
173 { 139 {
174 std::ofstream outfile; 140 std::ofstream outfile;
175 outfile.open(outname); 141 outfile.open(outname);
176 assert(outfile.good()); 142 if (outfile.good())
177 efl::eolian::generate(outfile, cls, gen_opts); 143 {
178 outfile.close(); 144 efl::eolian::generate(outfile, cls, gen_opts);
145 outfile.close();
146 }
147 else
148 {
149 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
150 << "Can't open output file: " << outname << std::endl;
151 return false;
152 }
179 } 153 }
154 return true;
180} 155}
181 156
182static void 157static void
183_run(options_type const& opts) 158run(options_type const& opts)
184{ 159{
185 if (opts.classname != "") 160 Eolian_Class klass = NULL;
161 if (!opts.classname.empty())
162 klass = class_from_name(opts.classname);
163 else if (!opts.in_file.empty())
164 klass = class_from_file(opts.in_file);
165 if (klass)
186 { 166 {
187 _generate(opts.classname.c_str(), opts); 167 if (!generate(klass, opts))
168 goto err;
188 } 169 }
189 else 170 else
190 { 171 {
191 efl::eina::range_ptr_list<const char* const> 172 auto classes = class_list_all();
192 classes(eolian_class_names_list_get()); 173 for (const Eolian_Class c : classes)
193 for (auto cls : classes)
194 { 174 {
195 if (opts.classname == "" || opts.classname == cls) 175 if (!generate(c, opts))
196 { 176 {
197 _generate(cls, opts); 177 klass = c;
178 goto err;
198 } 179 }
199 } 180 }
200 } 181 }
182 return;
183 err:
184 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
185 << "Error generating: " << class_name(klass)
186 << std::endl;
187 std::abort();
201} 188}
202 189
203static void 190static void
204_print_version() 191database_load(options_type const& opts)
205{ 192{
206 std::cerr 193 for (auto src : opts.include_dirs)
207 << "Eolian C++ Binding Generator (EFL "
208 << PACKAGE_VERSION << ")" << std::endl;
209}
210
211static void
212_validate_options(::options_type const& opts)
213{
214 if (opts.in_srcs.size() == 0)
215 {
216 _opt_error("You must provide at least one input source (-I). "
217 "Either an .eo file or a directory of .eo files.");
218 }
219 else if (opts.out_file != "" && opts.generate_all)
220 { 194 {
221 _opt_error("Options -a and -o can't be used together."); 195 if (!::eolian_directory_scan(src.c_str()))
196 {
197 EINA_CXX_DOM_LOG_WARN(eolian_cxx::domain)
198 << "Couldn't load eolian from '" << src << "'.";
199 }
222 } 200 }
223 else if (!opts.generate_all && opts.classname == "") 201 if (!::eolian_all_eot_files_parse())
224 { 202 {
225 _opt_error("Neither -a nor -c provided. " 203 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
226 "Don't know what to generate."); 204 << "Eolian failed parsing eot files";
205 std::abort();
227 } 206 }
228} 207 if (!opts.in_file.empty())
229
230static void
231_resolve_classname(options_type& opts)
232{
233 if (opts.classname == "")
234 { 208 {
235 std::string cls = _guess_classname_from_sources(opts); 209 if (!::eolian_eo_file_parse(opts.in_file.c_str()))
236 opts.classname = cls; 210 {
211 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
212 << "Failed parsing: " << opts.in_file << ".";
213 std::abort();
214 }
237 } 215 }
238 if (opts.classname == "" && opts.out_file != "") 216 if (!::eolian_all_eo_files_parse())
239 { 217 {
240 EINA_CXX_DOM_LOG_ERR(::domain) 218 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
241 << "Unknown output class for " << opts.out_file 219 << "Eolian failed parsing input files";
242 << " : Missing '-c' option?";
243 std::abort(); 220 std::abort();
244 } 221 }
245} 222}
246 223
247static void 224} // namespace eolian_cxx {
248_scan_directories(options_type const& opts)
249{
250 for (auto src : opts.in_srcs)
251 {
252 if (eina_str_has_suffix(src.c_str(), EO_SUFFIX)) continue;
253 eolian_read_from_fs(src.c_str());
254 }
255}
256
257static void
258_load_eot()
259{
260 eolian_all_eot_files_parse();
261}
262 225
263static void 226static void
264_load_classes(options_type const& opts) 227_print_version()
265{ 228{
266 for (auto src : opts.in_srcs) 229 std::cerr
267 { 230 << "Eolian C++ Binding Generator (EFL "
268 if (!eina_str_has_suffix(src.c_str(), EO_SUFFIX)) continue; 231 << PACKAGE_VERSION << ")" << std::endl;
269 if ( eolian_read_from_fs(src.c_str()) == NULL)
270 {
271 EINA_CXX_DOM_LOG_WARN(::domain)
272 << "Couldn't load eolian file: " << src;
273 }
274 }
275} 232}
276 233
277static void 234static void
@@ -279,7 +236,8 @@ _usage(const char *progname)
279{ 236{
280 std::cerr 237 std::cerr
281 << progname 238 << progname
282 << " [options]" << std::endl 239 << " [options] [file.eo]" << std::endl
240 << " A single input file must be provided (unless -a is specified)." << std::endl
283 << "Options:" << std::endl 241 << "Options:" << std::endl
284 << " -a, --all Generate bindings for all Eo classes." << std::endl 242 << " -a, --all Generate bindings for all Eo classes." << std::endl
285 << " -c, --class <name> The Eo class name to generate code for." << std::endl 243 << " -c, --class <name> The Eo class name to generate code for." << std::endl
@@ -293,10 +251,20 @@ _usage(const char *progname)
293 exit(EXIT_FAILURE); 251 exit(EXIT_FAILURE);
294} 252}
295 253
296static ::options_type 254static void
297_read_options(int argc, char **argv) 255_assert_not_dup(std::string option, std::string value)
298{ 256{
299 ::options_type opts; 257 if (value != "")
258 {
259 EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain) <<
260 "Option -" + option + " already set (" + value + ")";
261 }
262}
263
264static eolian_cxx::options_type
265opts_get(int argc, char **argv)
266{
267 eolian_cxx::options_type opts;
300 268
301 const struct option long_options[] = 269 const struct option long_options[] =
302 { 270 {
@@ -304,21 +272,20 @@ _read_options(int argc, char **argv)
304 { "out-dir", required_argument, 0, 'D' }, 272 { "out-dir", required_argument, 0, 'D' },
305 { "out-file", required_argument, 0, 'o' }, 273 { "out-file", required_argument, 0, 'o' },
306 { "class", required_argument, 0, 'c' }, 274 { "class", required_argument, 0, 'c' },
307 { "namespace", required_argument, 0, 'n' },
308 { "all", no_argument, 0, 'a' }, 275 { "all", no_argument, 0, 'a' },
309 { "recurse", no_argument, 0, 'r' }, 276 { "recurse", no_argument, 0, 'r' },
310 { "version", no_argument, 0, 'v' }, 277 { "version", no_argument, 0, 'v' },
311 { "help", no_argument, 0, 'h' }, 278 { "help", no_argument, 0, 'h' },
312 { 0, 0, 0, 0 } 279 { 0, 0, 0, 0 }
313 }; 280 };
314 const char* options = "I:D:o:c:n:arvh"; 281 const char* options = "I:D:o:c:arvh";
315 282
316 int c, idx; 283 int c, idx;
317 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1) 284 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1)
318 { 285 {
319 if (c == 'I') 286 if (c == 'I')
320 { 287 {
321 opts.in_srcs.push_back(optarg); 288 opts.include_dirs.push_back(optarg);
322 } 289 }
323 else if (c == 'D') 290 else if (c == 'D')
324 { 291 {
@@ -335,11 +302,6 @@ _read_options(int argc, char **argv)
335 _assert_not_dup("c", opts.classname); 302 _assert_not_dup("c", opts.classname);
336 opts.classname = optarg; 303 opts.classname = optarg;
337 } 304 }
338 else if (c == 'n')
339 {
340 _assert_not_dup("n", opts.name_space);
341 opts.name_space = optarg;
342 }
343 else if (c == 'a') 305 else if (c == 'a')
344 { 306 {
345 opts.generate_all = true; 307 opts.generate_all = true;
@@ -358,6 +320,17 @@ _read_options(int argc, char **argv)
358 if (argc == 2) exit(EXIT_SUCCESS); 320 if (argc == 2) exit(EXIT_SUCCESS);
359 } 321 }
360 } 322 }
323 if (optind == argc-1)
324 {
325 opts.in_file = argv[optind];
326 }
327
328 if (!eolian_cxx::opts_check(opts))
329 {
330 _usage(argv[0]);
331 std::abort();
332 }
333
361 return opts; 334 return opts;
362} 335}
363 336
@@ -365,15 +338,8 @@ int main(int argc, char **argv)
365{ 338{
366 efl::eina::eina_init eina_init; 339 efl::eina::eina_init eina_init;
367 efl::eolian::eolian_init eolian_init; 340 efl::eolian::eolian_init eolian_init;
368#if DEBUG 341 eolian_cxx::options_type opts = opts_get(argc, argv);
369 domain.set_level(efl::eina::log_level::debug); 342 eolian_cxx::database_load(opts);
370#endif 343 eolian_cxx::run(opts);
371 options_type opts = _read_options(argc, argv);
372 _scan_directories(opts);
373 _load_eot();
374 _load_classes(opts);
375 _resolve_classname(opts);
376 _validate_options(opts);
377 _run(opts);
378 return 0; 344 return 0;
379} 345}