/src/tools/wrappers-generator/name_converter.e
Specman e | 297 lines | 203 code | 24 blank | 70 comment | 8 complexity | 9290cd4d821f192adf1bc5b1669d0dbd MD5 | raw file
1deferred class NAME_CONVERTER 2 -- Query features to dcover if a symbol name does comply to SmartEiffel's 3 -- naming rules and to convert arbitrary C symbols into valid Eiffel names 4 -- of classes or features. 5 6insert 7 PLATFORM 8 EXCEPTIONS 9 10feature {ANY} -- Auxiliary features 11 eiffel_feature (a_name: ABSTRACT_STRING): STRING 12 -- Translate `a_name' content into a proper feature name for the 13 -- Gnu-Eiffel language. "CamelCase" is translated into "camel_case", 14 -- "ENOO" is translated into "enoo". Eventual underscores in front of 15 -- `a_name' are removed: "__foo" becomes "foo"; symbols starting with 16 -- underscores folloed by a number are prefixed with "a_"; reserved 17 -- language names and names of features of class ANY are escaped. 18 -- TODO: handle in a fairly 19 require 20 name_not_void: a_name /= Void 21 name_not_empty: not a_name.is_empty 22 do 23 create Result.make_from_string(a_name) 24 -- Remove header underscores. 25 from 26 until 27 Result.first /= '_' 28 loop 29 Result.remove_first 30 end 31 -- If first character is a number prepend an `a_' 32 if Result.first.is_digit then 33 Result.prepend(once "a_") 34 end 35 36 insert_underscores(Result) 37 -- Remove spurious underscores and the end 38 from 39 until 40 Result.last /= '_' 41 loop 42 Result.remove_last 43 end 44 45 multiple_underscores_remover.substitute_all_in(Result) 46 -- Deal with C++ names: turn lt<foo> into lt_of_foo 47 -- TODO: queue<dock,deepspace::station> into queue_of_dock_and_deepspace_station 48 49 lt_translator.substitute_all_in(Result) 50 gt_translator.substitute_all_in(Result) 51 namespace_separator_translator.substitute_all_in(Result) 52 Result.to_lower 53 Result := adapt(Result, once "_external") 54 end 55 56 eiffel_argument (a_name: ABSTRACT_STRING): STRING 57 -- `a_name' content translated into a proper argument placeholder for 58 -- the Gnu-Eiffel language. "CamelCase" is translated into 59 -- "a_camel_case", "ENOO" is translated into "an_enoo". Eventual 60 -- underscores in front of `a_name' are removed: "__foo" becomes 61 -- "a_foo". See also `eiffel_feature'. 62 require 63 name_not_void: a_name /= Void 64 local 65 e_feature, e_prefix: ABSTRACT_STRING 66 do 67 e_feature := eiffel_feature(a_name) 68 inspect 69 e_feature.first 70 when 'a', 'e', 'o', 'i', 'u' then 71 e_prefix := once "an_" 72 else 73 e_prefix := once "a_" 74 end 75 Result := e_prefix + e_feature 76 end 77 78 insert_underscores (a_string: STRING) 79 -- Insert an underscore ('_') before each uppercase letter following a lowercase one. 80 require 81 a_string /= Void 82 not a_string.is_empty 83 local 84 i: INTEGER 85 do 86 from 87 i := a_string.lower + 1 88 until 89 i > a_string.upper 90 loop 91 if a_string.item(i - 1).is_lower and a_string.item(i).is_upper then 92 a_string.insert_character('_', i) 93 i := i + 2 94 else 95 i := i + 1 96 end 97 end 98 end 99 100 camelcase_translator: REGULAR_EXPRESSION 101 -- Insert an underscore ('_') between any lowercase letter followed by an uppercase one 102 local 103 builder: REGULAR_EXPRESSION_BUILDER 104 once 105 Result := builder.convert_perl_pattern("([a-z])([A-Z])") 106 Result.prepare_substitution("\1_\2") 107 end 108 109 multiple_underscores_remover: REGULAR_EXPRESSION 110 -- Replace all multiple occurences of underscore "_" with a single one 111 local 112 builder: REGULAR_EXPRESSION_BUILDER 113 once 114 Result := builder.convert_perl_pattern("(\_\_+)") 115 Result.prepare_substitution("_") 116 end 117 118 lt_translator: REGULAR_EXPRESSION 119 -- Replace all occurences of "<" (shown as "<") with "_of_" 120 local 121 builder: REGULAR_EXPRESSION_BUILDER 122 once 123 Result := builder.convert_perl_pattern("(<)") 124 Result.prepare_substitution("_of_") 125 end 126 127 gt_translator: REGULAR_EXPRESSION 128 -- Remove all occurences of ">" (shown as ">") 129 local 130 builder: REGULAR_EXPRESSION_BUILDER 131 once 132 Result := builder.convert_perl_pattern("(>)") 133 Result.prepare_substitution("") 134 end 135 136 namespace_separator_translator: REGULAR_EXPRESSION 137 -- Replace all occurences of "::" (C++ namespace separator) with "_" 138 local 139 builder: REGULAR_EXPRESSION_BUILDER 140 once 141 Result := builder.convert_perl_pattern("(>)") 142 Result.prepare_substitution("i") 143 end 144 145 is_public_name (a_name: ABSTRACT_STRING): BOOLEAN 146 -- Does `a_name' start with an alphabetical character? Names 147 -- starting with underscores or other strange characters are 148 -- usually considered private in C/C++ languages. 149 require 150 not_void: a_name /= Void 151 meaningful_length: a_name.count > 1 152 do 153 Result := a_name.first.is_letter 154 end 155 156 eiffel_class_name (a_string, a_suffix: ABSTRACT_STRING): STRING 157 -- An Eiffel class name derived from `a_string'. Trailing and tail 158 -- underscores are removed, dashes are turned into underscores, 159 -- `a_suffix' is added at the end if not void, all is made uppercase. 160 require 161 a_string /= Void 162 do 163 create Result.make_from_string(a_string) 164 -- Remove trailing underscores 165 from 166 until 167 Result.first /= '_' 168 loop 169 Result.remove_first 170 end 171 172 check 173 Result.last.code /= 0 174 end 175 -- Remove spurious underscores at the end 176 from 177 until 178 Result.last /= '_' 179 loop 180 Result.remove_last 181 end 182 183 check 184 Result.last.code /= 0 185 end 186 insert_underscores(Result) 187 if a_suffix /= Void then 188 Result.append(a_suffix) 189 end 190 191 check 192 Result.last.code /= 0 193 -- The reason of this check is not easy understandable here. 194 -- It's actually a poor's man test of a strange, old bug of STRING 195 -- shown by xml library that don't update capacity and actual 196 -- length with an off-by-one length error 197 end 198 Result.replace_all('-', '_') 199 Result.to_upper 200 -- print("'"+Result+"' last charcter code is: "+Result.last.code.to_string+"%N") 201 check 202 Result.last.code /= 0 203 end 204 ensure 205 Result /= Void 206 is_valid_class_name(Result) 207 end 208 209 is_valid_class_name (a_name: ABSTRACT_STRING): BOOLEAN 210 -- Does `a_name' represents a valid Eiffel class name? i.e. does it 211 -- start with an upper-case letter and contain only upper-case 212 -- letters, underscores and numbers? 213 require 214 a_name /= Void 215 local 216 iter: ITERATOR[CHARACTER]; c: CHARACTER 217 do 218 iter := a_name.new_iterator 219 from 220 iter.start 221 Result := iter.item.is_upper 222 iter.next 223 until 224 Result = False or else not iter.is_off 225 loop 226 c := iter.item 227 Result := c.is_upper or else c.is_digit and c /= '.' or else c = '_' 228 iter.next 229 end 230 end 231 232 adapt (a_name, a_suffix: ABSTRACT_STRING): STRING 233 -- A valid, adapted identifier for an Eiffel feature labelled 234 -- `a_name'. Can be either `a_name' itself or a new string 235 -- containing an adapatation. Reserved words and those of 236 -- features belonging to ANY are "escaped", appending `a_suffix'. 237 require 238 name_not_void: a_name /= Void 239 valid_name: a_name.first /= '_' 240 suffix_not_void: a_suffix /= Void 241 suffix_not_empty: not a_suffix.is_empty 242 do 243 if keywords.has(a_name) or else any_features.has(a_name) then 244 Result := a_name + a_suffix 245 elseif Result ?:= a_name then 246 Result ::= a_name 247 else 248 create Result.make_from_string(a_name) 249 end 250 ensure 251 Result /= Void 252 end 253 254feature {} -- Constants 255 keywords: HASHED_SET[ABSTRACT_STRING] 256 once 257 Result := {HASHED_SET[ABSTRACT_STRING] << "indexing" 258 -- Keywords: 259 -- related to classes 260 , "class", "deferred", "expanded", "separate", "end", "obsolete", "inherit" -- related to inheritance 261 , "insert", "creation", "feature", "rename", "redefine", "undefine", "select", "export", "require" -- design by contract 262 , "ensure", "check", "debug", "invariant", "variant", "rescue", "local" -- features body 263 , "do", "once", "alias", "external", "attribute", "if" -- control flow 264 , "then", "else", "elseif", "when", "from", "until", "loop", "and" -- boolean operators 265 , "or", "xor", "not", "implies" >> } 266 end 267 268 any_features: HASHED_SET[ABSTRACT_STRING] 269 -- The names of the features contained in class ANY. 270 -- The following "static" definition of the features of ANY 271 -- somehow unacceptable in a perfect world. Yet computing it each 272 -- and every time would enlarge the memory usage of the program 273 -- quite a lot, not counting the runtime requirements. We will do 274 -- it when we will cache compilation results. 275 once 276 -- The following "static" definition of the features of ANY 277 -- somehow unacceptable in a perfect world. Yet computing it each 278 -- and every time would enlarge the memory usage of the program 279 -- quite a lot, not counting the runtime requirements. We will do 280 -- it when we will cache compilation results. 281 Result := {HASHED_SET[ABSTRACT_STRING] << "generating", "generator", "same_dynamic_type", "_equal", "standard__equal", "_deep_equal", "twin", "copy", "standard_twin", "standard_copy", "deep_twin", "default", "_default", "print_on", "tagged_out", "out", "out_in_tagged_out_memory", "tagged_out_memory", "fill_tagged_out_memory", "to_pointer", "_basic_expanded_type", "object_size" >> } 282 end 283 284end -- class NAME_CONVERTER 285 286-- Copyright (C) 2008-2017: Paolo Redaelli 287 288-- wrappers-generator is free software: you can redistribute it and/or modify it 289-- under the terms of the GNU General Public License as publhed by the Free 290-- Software Foundation, either version 2 of the License, or (at your option) 291-- any later version. 292-- wrappers-generator is distributed in the hope that it will be useful, but 293-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 294-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 295-- more details. 296-- You should have received a copy of the GNU General Public License along with 297-- th program. If not, see <http://www.gnu.org/licenses/>.