summaryrefslogtreecommitdiff
path: root/src/bin/eolian_mono/eolian_mono.cc
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2017-11-23 21:50:16 -0300
committerLauro Moura <lauromoura@expertisesolutions.com.br>2017-12-04 15:47:50 -0300
commitd93e9ff286ce1961f530d56b5536881f47104ebd (patch)
treed9fd8cd25a64b9ab6b23ae34b92c342dc8e6b543 /src/bin/eolian_mono/eolian_mono.cc
parent9391407319424c503a78479b407737ccead945b7 (diff)
eolian_mono: Added code for eolian_mono generator
Based on the eolian_cxx library generators. Buildsystem files will come in a future commmit.
Diffstat (limited to 'src/bin/eolian_mono/eolian_mono.cc')
-rw-r--r--src/bin/eolian_mono/eolian_mono.cc367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc
new file mode 100644
index 0000000000..220f1e43c4
--- /dev/null
+++ b/src/bin/eolian_mono/eolian_mono.cc
@@ -0,0 +1,367 @@
1
2#include <iostream>
3#include <fstream>
4
5#include <stdlib.h>
6#include <unistd.h>
7#include <getopt.h>
8#include <libgen.h>
9
10#include <string>
11#include <map>
12#include <algorithm>
13#include <stdexcept>
14#include <iosfwd>
15#include <type_traits>
16#include <cassert>
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <Eolian.h>
22
23#include <Eina.hh>
24#include <Eolian_Cxx.hh>
25
26#include <eolian/mono/klass.hh>
27#include <eolian/mono/enum_definition.hh>
28#include <eolian/mono/struct_definition.hh>
29#include <eolian/mono/type_impl.hh>
30#include <eolian/mono/marshall_type_impl.hh>
31#include <eolian/mono/marshall_annotation.hh>
32#include <eolian/mono/function_pointer.hh>
33
34namespace eolian_mono {
35
36/// Program options.
37struct options_type
38{
39 std::vector<std::string> include_dirs;
40 std::string in_file;
41 std::string out_file;
42 std::string dllimport;
43 int v_major;
44 int v_minor;
45 std::map<const std::string, std::string> references_map;
46};
47
48efl::eina::log_domain domain("eolian_mono");
49
50// Parses a CSV file in the format 'filename,library' (without trimming spaces around ',')
51static std::vector<std::pair<std::string, std::string> >
52parse_reference(std::string filename)
53{
54 std::vector<std::pair<std::string, std::string> > ret;
55 std::string delimiter = ",";
56 std::ifstream infile(filename);
57 std::string line;
58
59 while (std::getline(infile, line))
60 {
61 size_t pos = line.find(delimiter);
62
63 if (pos == std::string::npos)
64 throw std::invalid_argument("Malformed mapping. Must be 'filename,library'");
65
66 std::string eo_filename = line.substr(0, pos);
67 std::string library = line.substr(pos + 1);
68 library[0] = std::toupper(library[0]);
69 ret.push_back(std::pair<std::string, std::string>(eo_filename, library));
70 }
71 return ret;
72}
73
74static bool
75opts_check(eolian_mono::options_type const& opts)
76{
77 if (opts.in_file.empty())
78 {
79 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
80 << "Nothing to generate?" << std::endl;
81 }
82 else if (opts.out_file.empty())
83 {
84 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
85 << "Nowhere to generate?" << std::endl;
86 }
87 else
88 return true; // valid.
89 return false;
90}
91
92static void
93run(options_type const& opts)
94{
95 const Eolian_Class *klass = NULL;
96 Eina_Iterator *aliases = NULL;
97 const Eolian_Typedecl *tp = NULL;
98 char* dup = strdup(opts.in_file.c_str());
99 std::string basename_input = basename(dup);
100 klass = ::eolian_class_get_by_file(NULL, basename_input.c_str());
101 aliases= ::eolian_typedecl_aliases_get_by_file(NULL, basename_input.c_str());
102 free(dup);
103
104 std::string class_file_name = opts.out_file;
105
106 std::ofstream output_file;
107 std::ostream_iterator<char> iterator
108 {[&]
109 {
110 if(opts.out_file == "-")
111 return std::ostream_iterator<char>(std::cout);
112 else
113 {
114 output_file.open(class_file_name);
115 if (!output_file.good())
116 {
117 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
118 << "Can't open output file: " << class_file_name << std::endl;
119 throw std::runtime_error("");
120 }
121 return std::ostream_iterator<char>(output_file);
122 }
123 }()};
124
125 if (!as_generator("using System;\nusing System.Runtime.InteropServices;\nusing System.Collections.Generic;\n")
126 .generate(iterator, efl::eolian::grammar::attributes::unused, efl::eolian::grammar::context_null()))
127 {
128 throw std::runtime_error("Failed to generate file preamble");
129 }
130
131 auto context = efl::eolian::grammar::context_add_tag(eolian_mono::library_context{opts.dllimport,
132 opts.v_major,
133 opts.v_minor,
134 opts.references_map},
135 efl::eolian::grammar::context_null());
136 EINA_ITERATOR_FOREACH(aliases, tp)
137 {
138 if (eolian_typedecl_type_get(tp) != EOLIAN_TYPEDECL_FUNCTION_POINTER)
139 continue;
140
141 const Eolian_Function *fp = eolian_typedecl_function_pointer_get(tp);
142 efl::eolian::grammar::attributes::function_def function_def(fp, EOLIAN_FUNCTION_POINTER, NULL);
143 std::vector<std::string> namespaces;
144
145 for (efl::eina::iterator<const char> namespace_iterator(::eolian_typedecl_namespaces_get(tp)), namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
146 {
147 namespaces.push_back(&*namespace_iterator);
148 }
149
150 if (!eolian_mono::function_pointer
151 .generate(iterator, function_def, escape_namespace(namespaces), context))
152 {
153 throw std::runtime_error("Failed to generate function pointer wrapper");
154 }
155 }
156
157 if (klass)
158 {
159 efl::eolian::grammar::attributes::klass_def klass_def(klass, NULL);
160 std::vector<efl::eolian::grammar::attributes::klass_def> klasses{klass_def};
161
162 if (!eolian_mono::klass
163 .generate(iterator, klass_def, context))
164 {
165 throw std::runtime_error("Failed to generate class");
166 }
167 }
168 //else
169 {
170 for (efl::eina::iterator<const Eolian_Typedecl> enum_iterator( ::eolian_typedecl_enums_get_by_file(NULL, basename_input.c_str()))
171 , enum_last; enum_iterator != enum_last; ++enum_iterator)
172 {
173 efl::eolian::grammar::attributes::enum_def enum_(&*enum_iterator);
174 if (!eolian_mono::enum_definition.generate(iterator, enum_, efl::eolian::grammar::context_null()))
175 {
176 throw std::runtime_error("Failed to generate enum");
177 }
178 }
179
180 for (efl::eina::iterator<const Eolian_Typedecl> struct_iterator( ::eolian_typedecl_structs_get_by_file(NULL, basename_input.c_str()))
181 , struct_last; struct_iterator != struct_last; ++struct_iterator)
182 {
183 efl::eolian::grammar::attributes::struct_def struct_(&*struct_iterator);
184 if (!eolian_mono::struct_definition.generate(iterator, struct_, efl::eolian::grammar::context_null()))
185 {
186 throw std::runtime_error("Failed to generate struct");
187 }
188 }
189
190 }
191}
192
193static void
194database_load(options_type const& opts)
195{
196 for (auto src : opts.include_dirs)
197 {
198 if (!::eolian_directory_scan(src.c_str()))
199 {
200 EINA_CXX_DOM_LOG_WARN(eolian_mono::domain)
201 << "Couldn't load eolian from '" << src << "'.";
202 }
203 }
204 if (!::eolian_all_eot_files_parse())
205 {
206 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
207 << "Eolian failed parsing eot files";
208 assert(false && "Error parsing eot files");
209 }
210 if (opts.in_file.empty())
211 {
212 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
213 << "No input file.";
214 assert(false && "Error parsing input file");
215 }
216 if (!::eolian_file_parse(opts.in_file.c_str()))
217 {
218 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain)
219 << "Failed parsing: " << opts.in_file << ".";
220 assert(false && "Error parsing input file");
221 }
222}
223
224} // namespace eolian_mono {
225
226static void
227_print_version()
228{
229 std::cerr
230 << "Eolian C++ Binding Generator (EFL "
231 << PACKAGE_VERSION << ")" << std::endl;
232}
233
234static void
235_usage(const char *progname)
236{
237 std::cerr
238 << progname
239 << " [options] [file.eo]" << std::endl
240 << " A single input file must be provided (unless -a is specified)." << std::endl
241 << "Options:" << std::endl
242 << " -a, --all Generate bindings for all Eo classes." << std::endl
243 << " -c, --class <name> The Eo class name to generate code for." << std::endl
244 << " -D, --out-dir <dir> Output directory where generated code will be written." << std::endl
245 << " -I, --in <file/dir> The source containing the .eo descriptions." << std::endl
246 << " -o, --out-file <file> The output file name. [default: <classname>.eo.hh]" << std::endl
247 << " -n, --namespace <ns> Wrap generated code in a namespace. [Eg: efl::ecore::file]" << std::endl
248 << " -r, --recurse Recurse input directories loading .eo files." << std::endl
249 << " -v, --version Print the version." << std::endl
250 << " -h, --help Print this help." << std::endl;
251 exit(EXIT_FAILURE);
252}
253
254static void
255_assert_not_dup(std::string option, std::string value)
256{
257 if (value != "")
258 {
259 EINA_CXX_DOM_LOG_ERR(eolian_mono::domain) <<
260 "Option -" + option + " already set (" + value + ")";
261 }
262}
263
264static eolian_mono::options_type
265opts_get(int argc, char **argv)
266{
267 eolian_mono::options_type opts;
268
269 const struct option long_options[] =
270 {
271 { "in", required_argument, 0, 'I' },
272 { "out-file", required_argument, 0, 'o' },
273 { "version", no_argument, 0, 'v' },
274 { "help", no_argument, 0, 'h' },
275 { "dllimport", required_argument, 0, 'l' },
276 { "vmaj", required_argument, 0, 'M' },
277 { "vmin", required_argument, 0, 'm' },
278 { "references", required_argument, 0, 'r'},
279 { 0, 0, 0, 0 }
280 };
281 const char* options = "I:D:o:c:M:m:ar:vh";
282
283 int c, idx;
284 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1)
285 {
286 if (c == 'I')
287 {
288 opts.include_dirs.push_back(optarg);
289 }
290 else if (c == 'o')
291 {
292 _assert_not_dup("o", opts.out_file);
293 opts.out_file = optarg;
294 }
295 else if (c == 'h')
296 {
297 _usage(argv[0]);
298 }
299 else if (c == 'l')
300 {
301 opts.dllimport = optarg;
302 }
303 else if (c == 'M')
304 {
305 opts.v_major = std::stoi(optarg);
306 }
307 else if (c == 'm')
308 {
309 opts.v_minor = std::stoi(optarg);
310 }
311 else if (c == 'r')
312 {
313 try
314 {
315 std::vector<std::pair<std::string, std::string> > names = eolian_mono::parse_reference(optarg);
316 for (auto&& p : names)
317 {
318 opts.references_map[p.first] = p.second;
319 }
320 }
321 catch (const std::invalid_argument &e)
322 {
323 std::cerr << "Invalid argument processing argument " << optarg << std::endl;
324 _usage(argv[0]);
325 assert(false && e.what());
326 }
327 }
328 else if (c == 'v')
329 {
330 _print_version();
331 if (argc == 2) exit(EXIT_SUCCESS);
332 }
333 }
334 if (optind == argc-1)
335 {
336 opts.in_file = argv[optind];
337 }
338
339 if (!eolian_mono::opts_check(opts))
340 {
341 _usage(argv[0]);
342 assert(false && "Wrong options passed in command-line");
343 }
344
345 return opts;
346}
347
348int main(int argc, char **argv)
349{
350 try
351 {
352 efl::eina::eina_init eina_init;
353 efl::eolian::eolian_init eolian_init;
354 eolian_mono::options_type opts = opts_get(argc, argv);
355 eolian_mono::database_load(opts);
356 eolian_mono::run(opts);
357 }
358 catch(std::exception const& e)
359 {
360 std::cerr << "EOLCXX: Eolian C++ failed generation for the following reason: " << e.what() << std::endl;
361 std::cout << "EOLCXX: Eolian C++ failed generation for the following reason: " << e.what() << std::endl;
362 return -1;
363 }
364 return 0;
365}
366
367