summaryrefslogtreecommitdiff
path: root/src/bin/eolian_mono
diff options
context:
space:
mode:
authorXavi Artigas <xavierartigas@yahoo.es>2018-12-21 14:52:11 +0100
committerXavi Artigas <xavierartigas@yahoo.es>2018-12-21 14:52:49 +0100
commitc84580cc050a0cb7c1ee99f1348a224f2f9f49ed (patch)
treeea77e00cafe3130a77cccfda50126fb2e9aab422 /src/bin/eolian_mono
parent166d5e476794a5c17f4c5e38289a0c72318a4d4a (diff)
doc: Turn comments from EO to C# XML syntax
Summary: This allows them to be nicely rendered by IDEs and automatic documentation generators like DocFX. The conversion includes things like turning $name to <c>name</c> or solving references to objects, which in turn requires converting from EO object names to C# names. It uses the same helper methods used to generate the C# object names, so if these change in the future, the references in the comments will change too. Additionally, this patch fixes some minor bugs, like <para> tags outside <summary> tags, misspelled <returns> tags or missing <returns> documentation for getter methods. Fixes T7453 Reviewers: lauromoura, vitor.sousa Reviewed By: lauromoura Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T7453 Differential Revision: https://phab.enlightenment.org/D7467
Diffstat (limited to 'src/bin/eolian_mono')
-rw-r--r--src/bin/eolian_mono/eolian/mono/blacklist.hh9
-rw-r--r--src/bin/eolian_mono/eolian/mono/documentation.hh238
-rw-r--r--src/bin/eolian_mono/eolian/mono/generation_contexts.hh5
-rw-r--r--src/bin/eolian_mono/eolian/mono/name_helpers.hh24
-rw-r--r--src/bin/eolian_mono/eolian_mono.cc8
5 files changed, 216 insertions, 68 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/blacklist.hh b/src/bin/eolian_mono/eolian/mono/blacklist.hh
index 646452e..684b842 100644
--- a/src/bin/eolian_mono/eolian/mono/blacklist.hh
+++ b/src/bin/eolian_mono/eolian/mono/blacklist.hh
@@ -77,14 +77,19 @@ inline bool is_alias_blacklisted(attributes::alias_def const& alias)
77 return name_helpers::alias_full_eolian_name(alias) == "Eina.Error"; 77 return name_helpers::alias_full_eolian_name(alias) == "Eina.Error";
78} 78}
79 79
80inline bool is_property_blacklisted(attributes::property_def const& property) 80inline bool is_property_blacklisted(std::string const& name)
81{ 81{
82 auto name = name_helpers::klass_full_concrete_or_interface_name(property.klass) + "." + name_helpers::property_managed_name(property);
83 return name == "Efl.Input.Key.Key" 82 return name == "Efl.Input.Key.Key"
84 || name == "Efl.Input.Hold.Hold" 83 || name == "Efl.Input.Hold.Hold"
85 || name == "Efl.Text.Text"; 84 || name == "Efl.Text.Text";
86} 85}
87 86
87inline bool is_property_blacklisted(attributes::property_def const& property)
88{
89 auto name = name_helpers::klass_full_concrete_or_interface_name(property.klass) + "." + name_helpers::property_managed_name(property);
90 return is_property_blacklisted(name);
91}
92
88} 93}
89 94
90} 95}
diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh
index f78c58a..4e9fc5d 100644
--- a/src/bin/eolian_mono/eolian/mono/documentation.hh
+++ b/src/bin/eolian_mono/eolian/mono/documentation.hh
@@ -6,6 +6,8 @@
6#include "grammar/html_escaped_string.hpp" 6#include "grammar/html_escaped_string.hpp"
7#include "using_decl.hh" 7#include "using_decl.hh"
8#include "name_helpers.hh" 8#include "name_helpers.hh"
9#include "generation_contexts.hh"
10#include "blacklist.hh"
9 11
10#include <Eina.h> 12#include <Eina.h>
11 13
@@ -19,39 +21,203 @@ struct documentation_generator
19 documentation_generator(int scope_size) 21 documentation_generator(int scope_size)
20 : scope_size(scope_size) {} 22 : scope_size(scope_size) {}
21 23
22 /// Tag generator helpers 24
23 template<typename OutputIterator, typename Context> 25 // Returns the number of parameters (values + keys) that a property method requires
24 bool generate_tag(OutputIterator sink, std::string const& tag, std::string const &text, Context const& context) const 26 // Specify if you want the Setter or the Getter method.
27 static int property_num_parameters(const ::Eolian_Function *function, ::Eolian_Function_Type ftype)
25 { 28 {
26 if (text.empty()) 29 Eina_Iterator *itr = ::eolian_property_keys_get(function, ftype);
27 return true; 30 Eolian_Function_Parameter *pr;
31 int n = 0;
32 EINA_ITERATOR_FOREACH(itr, pr) { n++; }
33 eina_iterator_free(itr);
34 itr = ::eolian_property_values_get(function, ftype);
35 EINA_ITERATOR_FOREACH(itr, pr) { n++; }
36 eina_iterator_free(itr);
37 return n;
38 }
28 39
29 return as_generator( scope_tab(scope_size) << "///<" << tag << ">" << html_escaped_string << "</" << tag << ">\n").generate(sink, text, context); 40 // Turns a function name from EO convention to EFL# convention.
41 // The name_tail parameter is the last 4 chars of the original string, which
42 // could be ".set" or ".get" and in this case they are ignored by Eolian.
43 // We want them to know what the documentation intended to reference.
44 static std::string function_conversion(const ::Eolian_Object *klass, const ::Eolian_Function *function, std::string name_tail)
45 {
46 ::Eolian_Function_Type ftype = ::eolian_function_type_get(function);
47 const char* eo_name = ::eolian_function_name_get(function);
48 std::string name = name_helpers::managed_namespace(::eolian_object_name_get(klass));
49 switch(ftype)
50 {
51 case ::EOLIAN_METHOD:
52 if (blacklist::is_function_blacklisted(
53 ::eolian_function_full_c_name_get(function, ftype, EINA_FALSE))) return "";
54 name += ".";
55 name += name_helpers::managed_method_name(
56 ::eolian_object_short_name_get(klass), eo_name);
57 break;
58 case ::EOLIAN_PROP_SET:
59 name += ".Set";
60 name += name_helpers::property_managed_name(eo_name);
61 break;
62 case ::EOLIAN_PROP_GET:
63 name += ".Get";
64 name += name_helpers::property_managed_name(eo_name);
65 break;
66 case ::EOLIAN_PROPERTY:
67 {
68 int getter_params = property_num_parameters(function, ::EOLIAN_PROP_GET);
69 int setter_params = property_num_parameters(function, ::EOLIAN_PROP_SET);
70 std::string short_name = name_helpers::property_managed_name(eo_name);
71 bool blacklisted = blacklist::is_property_blacklisted(name + "." + short_name);
72 // EO properties with keys, with more than one value, or blacklisted, are not
73 // converted into C# properties.
74 // In these cases we refer to the getter method instead of the property.
75 if ((getter_params > 1) || (setter_params > 1) || (blacklisted)) name += ".Get" + short_name;
76 else if (name_tail == ".get") name += ".Get" + short_name;
77 else if (name_tail == ".set") name += ".Set" + short_name;
78 else name += "." + short_name;
79 }
80 break;
81 default:
82 break;
83 }
84 return name;
30 } 85 }
31 86
87 // Turns an Eolian reference like @Efl.Input.Pointer.tool into a <see> tag
88 static std::string ref_conversion(const ::Eolian_Doc_Token *token, const Eolian_State *state, std::string name_tail)
89 {
90 const Eolian_Object *data, *data2;
91 ::Eolian_Object_Type type =
92 ::eolian_doc_token_ref_resolve(token, state, &data, &data2);
93 std::string ref;
94 switch(type)
95 {
96 case ::EOLIAN_OBJECT_STRUCT_FIELD:
97 ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
98 ref += ".";
99 ref += ::eolian_object_name_get(data2);
100 if (blacklist::is_struct_blacklisted(ref)) return "";
101 break;
102 case ::EOLIAN_OBJECT_EVENT:
103 ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
104 ref += ".";
105 ref += name_helpers::managed_event_name(::eolian_object_name_get(data2));
106 break;
107 case ::EOLIAN_OBJECT_ENUM_FIELD:
108 ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
109 ref += ".";
110 ref += name_helpers::enum_field_managed_name(::eolian_object_name_get(data2));
111 break;
112 case ::EOLIAN_OBJECT_FUNCTION:
113 ref += function_conversion(data, (const ::Eolian_Function *)data2, name_tail);
114 break;
115 case ::EOLIAN_OBJECT_UNKNOWN:
116 // If the reference cannot be resolved, just return an empty string and
117 // it won't be converted into a <see> tag.
118 break;
119 default:
120 ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
121 break;
122 }
123 return ref;
124 }
125
126 // Turns EO documentation syntax into C# triple-slash XML comment syntax
127 static std::string syntax_conversion(std::string text, const Eolian_State *state)
128 {
129 std::string new_text, ref;
130 ::Eolian_Doc_Token token;
131 const char *text_ptr = text.c_str();
132 ::eolian_doc_token_init(&token);
133 while ((text_ptr = ::eolian_documentation_tokenize(text_ptr, &token)) != NULL)
134 {
135 std::string token_text, name_tail;
136 char *token_text_cstr = ::eolian_doc_token_text_get(&token);
137 if (token_text_cstr)
138 {
139 token_text = token_text_cstr;
140 free(token_text_cstr);
141 if (token_text.length() > 4)
142 name_tail = token_text.substr(token_text.size() - 4, 4);
143 }
144 switch(::eolian_doc_token_type_get(&token))
145 {
146 case ::EOLIAN_DOC_TOKEN_TEXT:
147 new_text += token_text;
148 break;
149 case ::EOLIAN_DOC_TOKEN_REF:
150 ref = ref_conversion(&token, state, name_tail);
151 if (ref != "")
152 new_text += "<see cref=\"" + ref + "\"/>";
153 else
154 // Unresolved references are passed through.
155 // They will appear in the docs as plain text, without link,
156 // but at least they won't be removed by DocFX.
157 new_text += token_text;
158 break;
159 case ::EOLIAN_DOC_TOKEN_MARK_NOTE:
160 new_text += "NOTE: " + token_text;
161 break;
162 case ::EOLIAN_DOC_TOKEN_MARK_WARNING:
163 new_text += "WARNING: " + token_text;
164 break;
165 case ::EOLIAN_DOC_TOKEN_MARK_REMARK:
166 new_text += "REMARK: " + token_text;
167 break;
168 case ::EOLIAN_DOC_TOKEN_MARK_TODO:
169 new_text += "TODO: " + token_text;
170 break;
171 case ::EOLIAN_DOC_TOKEN_MARKUP_MONOSPACE:
172 new_text += "<c>" + token_text + "</c>";
173 break;
174 default:
175 break;
176 }
177 }
178 return new_text;
179 }
180
181 /// Tag generator helpers
32 template<typename OutputIterator, typename Context> 182 template<typename OutputIterator, typename Context>
33 bool generate_tag_summary(OutputIterator sink, std::string const& text, Context const& context) const 183 bool generate_tag(OutputIterator sink, std::string const& tag, std::string const &text, Context const& context, std::string tag_params = "") const
34 { 184 {
35 return generate_tag(sink, "summary", text, context); 185 std::string new_text;
186 if (!as_generator(html_escaped_string).generate(std::back_inserter(new_text), text, context))
187 return false;
188 new_text = syntax_conversion( new_text, context_find_tag<eolian_state_context>(context).state );
189
190 std::string tabs;
191 as_generator(scope_tab(scope_size) << "/// ").generate (std::back_inserter(tabs), attributes::unused, context);
192
193 std::istringstream ss(new_text);
194 std::string para;
195 std::string final_text = "<" + tag + tag_params + ">";
196 bool first = true;
197 while (std::getline(ss, para)) {
198 if (first) final_text += para;
199 else final_text += "\n" + tabs + para;
200 first = false;
201 }
202 return as_generator(scope_tab(scope_size) << "/// " << final_text << "</" << tag << ">\n").generate(sink, attributes::unused, context);
36 } 203 }
37 204
38 template<typename OutputIterator, typename Context> 205 template<typename OutputIterator, typename Context>
39 bool generate_tag_para(OutputIterator sink, std::string const& text, Context const& context) const 206 bool generate_tag_summary(OutputIterator sink, std::string const& text, Context const& context) const
40 { 207 {
41 return generate_tag(sink, "para", text, context); 208 return generate_tag(sink, "summary", text, context);
42 } 209 }
43 210
44 template<typename OutputIterator, typename Context> 211 template<typename OutputIterator, typename Context>
45 bool generate_tag_param(OutputIterator sink, std::string const& name, std::string const& text, Context const& context) const 212 bool generate_tag_param(OutputIterator sink, std::string const& name, std::string const& text, Context const& context) const
46 { 213 {
47 return as_generator( scope_tab(scope_size) << "///<param name=\"" << name << "\">" 214 return generate_tag(sink, "param", text, context, " name=\"" + name + "\"");
48 << html_escaped_string << "</param>\n").generate(sink, text, context);
49 } 215 }
50 216
51 template<typename OutputIterator, typename Context> 217 template<typename OutputIterator, typename Context>
52 bool generate_tag_return(OutputIterator sink, std::string const& text, Context const& context) const 218 bool generate_tag_return(OutputIterator sink, std::string const& text, Context const& context) const
53 { 219 {
54 return generate_tag(sink, "return", text, context); 220 return generate_tag(sink, "returns", text, context);
55 } 221 }
56 222
57 // Actual exported generators 223 // Actual exported generators
@@ -91,7 +257,7 @@ struct documentation_generator
91 if (!generate_parameter(sink, param, context)) 257 if (!generate_parameter(sink, param, context))
92 return false; 258 return false;
93 259
94 if (!generate_tag_return(sink, func.return_documentation.summary, context)) 260 if (!generate_tag_return(sink, func.return_documentation.full_text, context))
95 return false; 261 return false;
96 262
97 return true; 263 return true;
@@ -107,7 +273,7 @@ struct documentation_generator
107 if (!generate_parameter(sink, param, context)) 273 if (!generate_parameter(sink, param, context))
108 return false; 274 return false;
109 275
110 if (!generate_tag_return(sink, func.return_documentation.summary, context)) 276 if (!generate_tag_return(sink, func.return_documentation.full_text, context))
111 return false; 277 return false;
112 278
113 return true; 279 return true;
@@ -116,51 +282,13 @@ struct documentation_generator
116 template<typename OutputIterator, typename Context> 282 template<typename OutputIterator, typename Context>
117 bool generate_parameter(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const 283 bool generate_parameter(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
118 { 284 {
119 return generate_tag_param(sink, name_helpers::escape_keyword(param.param_name), param.documentation.summary, context); 285 return generate_tag_param(sink, name_helpers::escape_keyword(param.param_name), param.documentation.full_text, context);
120 } 286 }
121 287
122 template<typename OutputIterator, typename Context> 288 template<typename OutputIterator, typename Context>
123 bool generate(OutputIterator sink, attributes::documentation_def const& doc, Context const& context) const 289 bool generate(OutputIterator sink, attributes::documentation_def const& doc, Context const& context) const
124 { 290 {
125 if (!generate_preamble(sink, doc, context)) 291 return generate_tag_summary(sink, doc.full_text, context);
126 return false;
127 if (!generate_body(sink, doc, context))
128 return false;
129 if (!generate_epilogue(sink, doc, context))
130 return false;
131
132 return true;
133 }
134
135 template<typename OutputIterator, typename Context>
136 bool generate_preamble(OutputIterator sink, attributes::documentation_def const& doc, Context const context) const
137 {
138 return generate_tag_summary(sink, doc.summary, context);
139 }
140
141
142 template<typename OutputIterator, typename Context>
143 bool generate_body(OutputIterator sink, attributes::documentation_def const& doc, Context const context) const
144 {
145 for (auto&& para : doc.desc_paragraphs)
146 {
147 if (!generate_tag_para(sink, para, context))
148 return false;
149 }
150
151 return true;
152 }
153
154 template<typename OutputIterator, typename Context>
155 bool generate_epilogue(OutputIterator sink, attributes::documentation_def const& doc, Context const context) const
156 {
157 if (doc.since.empty())
158 return true;
159
160 if (!generate_tag_para(sink, doc.since, context))
161 return false;
162
163 return true;
164 } 292 }
165}; 293};
166 294
diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
index 7f94de7..ca1ca9e 100644
--- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
+++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
@@ -11,6 +11,7 @@ struct class_context
11 inherit, 11 inherit,
12 inherit_native, 12 inherit_native,
13 structs, 13 structs,
14 enums,
14 function_ptr, 15 function_ptr,
15 alias, 16 alias,
16 }; 17 };
@@ -40,6 +41,10 @@ library_context::actual_library_name(const std::string& filename) const
40 return '"' + library_name + '"'; 41 return '"' + library_name + '"';
41} 42}
42 43
44struct eolian_state_context {
45 const Eolian_State *state;
46};
47
43} 48}
44 49
45#endif 50#endif
diff --git a/src/bin/eolian_mono/eolian/mono/name_helpers.hh b/src/bin/eolian_mono/eolian/mono/name_helpers.hh
index cfda722..d953a09 100644
--- a/src/bin/eolian_mono/eolian/mono/name_helpers.hh
+++ b/src/bin/eolian_mono/eolian/mono/name_helpers.hh
@@ -32,10 +32,6 @@ namespace name_helpers {
32namespace attributes = efl::eolian::grammar::attributes; 32namespace attributes = efl::eolian::grammar::attributes;
33 33
34namespace detail { 34namespace detail {
35inline bool is_iequal(std::string const& lhs, std::string const& rhs)
36{
37 return strcasecmp(lhs.c_str(), rhs.c_str()) == 0;
38}
39inline bool is_equal(std::string const& lhs, std::string const& rhs) 35inline bool is_equal(std::string const& lhs, std::string const& rhs)
40{ 36{
41 return lhs == rhs; 37 return lhs == rhs;
@@ -176,21 +172,26 @@ inline std::string managed_namespace(std::string const& ns)
176 return escape_keyword(utils::remove_all(ns, '_')); 172 return escape_keyword(utils::remove_all(ns, '_'));
177} 173}
178 174
179inline std::string managed_method_name(attributes::function_def const& f) 175inline std::string managed_method_name(std::string const& klass, std::string const& name)
180{ 176{
181 std::vector<std::string> names = utils::split(f.name, '_'); 177 std::vector<std::string> names = utils::split(name, '_');
182 178
183 name_helpers::reorder_verb(names); 179 name_helpers::reorder_verb(names);
184 180
185 std::string candidate = escape_keyword(utils::to_pascal_case(names)); 181 std::string candidate = escape_keyword(utils::to_pascal_case(names));
186 182
187 // Some eolian methods have the same name as their parent class 183 // Some eolian methods have the same name as their parent class
188 if (candidate == f.klass.eolian_name) 184 if (candidate == klass)
189 candidate = "Do" + candidate; 185 candidate = "Do" + candidate;
190 186
191 return candidate; 187 return candidate;
192} 188}
193 189
190inline std::string managed_method_name(attributes::function_def const& f)
191{
192 return managed_method_name(f.klass.eolian_name, f.name);
193}
194
194inline std::string alias_full_eolian_name(attributes::alias_def const& alias) 195inline std::string alias_full_eolian_name(attributes::alias_def const& alias)
195{ 196{
196 return join_namespaces(alias.namespaces, '.') + alias.eolian_name; 197 return join_namespaces(alias.namespaces, '.') + alias.eolian_name;
@@ -243,14 +244,19 @@ inline std::string to_field_name(std::string const& in)
243 return utils::capitalize(in); 244 return utils::capitalize(in);
244} 245}
245 246
246inline std::string property_managed_name(attributes::property_def const& property) 247inline std::string property_managed_name(const std::string name)
247{ 248{
248 auto names = utils::split(property.name, '_'); 249 auto names = utils::split(name, '_');
249 // No need to escape keyword here as it will be capitalized and already 250 // No need to escape keyword here as it will be capitalized and already
250 // namespaced inside the owner class. 251 // namespaced inside the owner class.
251 return utils::to_pascal_case(names); 252 return utils::to_pascal_case(names);
252} 253}
253 254
255inline std::string property_managed_name(attributes::property_def const& property)
256{
257 return property_managed_name(property.name);
258}
259
254inline std::string managed_part_name(attributes::part_def const& part) 260inline std::string managed_part_name(attributes::part_def const& part)
255{ 261{
256 std::vector<std::string> names = utils::split(part.name, '_'); 262 std::vector<std::string> names = utils::split(part.name, '_');
diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc
index 2e0e891..db88881 100644
--- a/src/bin/eolian_mono/eolian_mono.cc
+++ b/src/bin/eolian_mono/eolian_mono.cc
@@ -138,11 +138,14 @@ run(options_type const& opts)
138 throw std::runtime_error("Failed to generate file preamble"); 138 throw std::runtime_error("Failed to generate file preamble");
139 } 139 }
140 140
141 auto context = efl::eolian::grammar::context_add_tag(eolian_mono::library_context{opts.dllimport, 141 auto lib_context = efl::eolian::grammar::context_add_tag(eolian_mono::library_context{opts.dllimport,
142 opts.v_major, 142 opts.v_major,
143 opts.v_minor, 143 opts.v_minor,
144 opts.references_map}, 144 opts.references_map},
145 efl::eolian::grammar::context_null()); 145 efl::eolian::grammar::context_null());
146
147 auto context = efl::eolian::grammar::context_add_tag(eolian_mono::eolian_state_context{opts.state}, lib_context);
148
146 EINA_ITERATOR_FOREACH(aliases, tp) 149 EINA_ITERATOR_FOREACH(aliases, tp)
147 { 150 {
148 if (eolian_typedecl_type_get(tp) == EOLIAN_TYPEDECL_FUNCTION_POINTER) 151 if (eolian_typedecl_type_get(tp) == EOLIAN_TYPEDECL_FUNCTION_POINTER)
@@ -179,7 +182,8 @@ run(options_type const& opts)
179 , enum_last; enum_iterator != enum_last; ++enum_iterator) 182 , enum_last; enum_iterator != enum_last; ++enum_iterator)
180 { 183 {
181 efl::eolian::grammar::attributes::enum_def enum_(&*enum_iterator, opts.unit); 184 efl::eolian::grammar::attributes::enum_def enum_(&*enum_iterator, opts.unit);
182 if (!eolian_mono::enum_definition.generate(iterator, enum_, efl::eolian::grammar::context_null())) 185 auto enum_cxt = context_add_tag(class_context{class_context::enums}, context);
186 if (!eolian_mono::enum_definition.generate(iterator, enum_, enum_cxt))
183 { 187 {
184 throw std::runtime_error("Failed to generate enum"); 188 throw std::runtime_error("Failed to generate enum");
185 } 189 }