1/* valanamespace.vala 2 * 3 * Copyright (C) 2006-2010 Jürg Billeter 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * Author: 20 * Jürg Billeter <j@bitron.ch> 21 */ 22 23using GLib; 24 25/** 26 * Represents a namespace declaration in the source code. 27 */ 28public class Vala.Namespace : Symbol { 29 private List<Class> classes = new ArrayList<Class> (); 30 private List<Interface> interfaces = new ArrayList<Interface> (); 31 private List<Struct> structs = new ArrayList<Struct> (); 32 private List<Enum> enums = new ArrayList<Enum> (); 33 private List<ErrorDomain> error_domains = new ArrayList<ErrorDomain> (); 34 private List<Delegate> delegates = new ArrayList<Delegate> (); 35 private List<Constant> constants = new ArrayList<Constant> (); 36 private List<Field> fields = new ArrayList<Field> (); 37 private List<Method> methods = new ArrayList<Method> (); 38 39 private List<Comment> comments = new ArrayList<Comment> (); 40 41 private List<Namespace> namespaces = new ArrayList<Namespace> (); 42 43 private List<UsingDirective> using_directives = new ArrayList<UsingDirective> (); 44 45 /** 46 * Creates a new namespace. 47 * 48 * @param name namespace name 49 * @param source_reference reference to source code 50 * @return newly created namespace 51 */ 52 public Namespace (string? name, SourceReference? source_reference = null) { 53 base (name, source_reference); 54 access = SymbolAccessibility.PUBLIC; 55 } 56 57 /** 58 * Adds a new using directive with the specified namespace. 59 * 60 * @param ns reference to namespace 61 */ 62 public void add_using_directive (UsingDirective ns) { 63 using_directives.add (ns); 64 } 65 66 public void add_comment (Comment comment) { 67 comments.add (comment); 68 } 69 70 /** 71 * Returns the list of namespaces. 72 * 73 * @return comment list 74 */ 75 public unowned List<Comment> get_comments () { 76 return comments; 77 } 78 79 /** 80 * Adds the specified namespace to this source file. 81 * 82 * @param ns a namespace 83 */ 84 public override void add_namespace (Namespace ns) { 85 if (ns.owner == null) { 86 ns.source_reference.file.add_node (ns); 87 } 88 89 if (scope.lookup (ns.name) is Namespace) { 90 // merge if namespace already exists 91 var old_ns = (Namespace) scope.lookup (ns.name); 92 if (old_ns.external_package && !ns.external_package) { 93 old_ns.source_reference = ns.source_reference; 94 } 95 96 foreach (var using_directive in ns.using_directives) { 97 old_ns.add_using_directive (using_directive); 98 } 99 foreach (Namespace sub_ns in ns.get_namespaces ()) { 100 old_ns.add_namespace (sub_ns); 101 } 102 foreach (Class cl in ns.get_classes ()) { 103 old_ns.add_class (cl); 104 } 105 foreach (Struct st in ns.get_structs ()) { 106 old_ns.add_struct (st); 107 } 108 foreach (Interface iface in ns.get_interfaces ()) { 109 old_ns.add_interface (iface); 110 } 111 foreach (Delegate d in ns.get_delegates ()) { 112 old_ns.add_delegate (d); 113 } 114 foreach (Enum en in ns.get_enums ()) { 115 old_ns.add_enum (en); 116 } 117 foreach (ErrorDomain ed in ns.get_error_domains ()) { 118 old_ns.add_error_domain (ed); 119 } 120 foreach (Constant c in ns.get_constants ()) { 121 old_ns.add_constant (c); 122 } 123 foreach (Field f in ns.get_fields ()) { 124 old_ns.add_field (f); 125 } 126 foreach (Method m in ns.get_methods ()) { 127 old_ns.add_method (m); 128 } 129 foreach (Comment c in ns.get_comments ()) { 130 old_ns.add_comment (c); 131 } 132 foreach (Attribute a in ns.attributes) { 133 if (old_ns.get_attribute (a.name) == null) { 134 old_ns.attributes.append(a); 135 } 136 } 137 } else { 138 namespaces.add (ns); 139 scope.add (ns.name, ns); 140 } 141 } 142 143 /** 144 * Returns the list of namespaces. 145 * 146 * @return namespace list 147 */ 148 public unowned List<Namespace> get_namespaces () { 149 return namespaces; 150 } 151 152 /** 153 * Adds the specified class to this namespace. 154 * 155 * @param cl a class 156 */ 157 public override void add_class (Class cl) { 158 // namespaces do not support private members 159 if (cl.access == SymbolAccessibility.PRIVATE) { 160 cl.access = SymbolAccessibility.INTERNAL; 161 } 162 163 if (cl.owner == null) { 164 cl.source_reference.file.add_node (cl); 165 } 166 167 classes.add (cl); 168 scope.add (cl.name, cl); 169 } 170 171 /** 172 * Adds the specified interface to this namespace. 173 * 174 * @param iface an interface 175 */ 176 public override void add_interface (Interface iface) { 177 // namespaces do not support private members 178 if (iface.access == SymbolAccessibility.PRIVATE) { 179 iface.access = SymbolAccessibility.INTERNAL; 180 } 181 182 if (iface.owner == null) { 183 iface.source_reference.file.add_node (iface); 184 } 185 186 interfaces.add (iface); 187 scope.add (iface.name, iface); 188 189 } 190 191 /** 192 * Adds the specified struct to this namespace. 193 * 194 * @param st a struct 195 */ 196 public override void add_struct (Struct st) { 197 // namespaces do not support private members 198 if (st.access == SymbolAccessibility.PRIVATE) { 199 st.access = SymbolAccessibility.INTERNAL; 200 } 201 202 if (st.owner == null) { 203 st.source_reference.file.add_node (st); 204 } 205 206 structs.add (st); 207 scope.add (st.name, st); 208 } 209 210 /** 211 * Adds the specified enum to this namespace. 212 * 213 * @param en an enum 214 */ 215 public override void add_enum (Enum en) { 216 // namespaces do not support private members 217 if (en.access == SymbolAccessibility.PRIVATE) { 218 en.access = SymbolAccessibility.INTERNAL; 219 } 220 221 if (en.owner == null) { 222 en.source_reference.file.add_node (en); 223 } 224 225 enums.add (en); 226 scope.add (en.name, en); 227 } 228 229 /** 230 * Adds the specified error domain to this namespace. 231 * 232 * @param edomain an error domain 233 */ 234 public override void add_error_domain (ErrorDomain edomain) { 235 // namespaces do not support private members 236 if (edomain.access == SymbolAccessibility.PRIVATE) { 237 edomain.access = SymbolAccessibility.INTERNAL; 238 } 239 240 if (edomain.owner == null) { 241 edomain.source_reference.file.add_node (edomain); 242 } 243 244 error_domains.add (edomain); 245 scope.add (edomain.name, edomain); 246 } 247 248 /** 249 * Adds the specified delegate to this namespace. 250 * 251 * @param d a delegate 252 */ 253 public override void add_delegate (Delegate d) { 254 // namespaces do not support private members 255 if (d.access == SymbolAccessibility.PRIVATE) { 256 d.access = SymbolAccessibility.INTERNAL; 257 } 258 259 if (d.owner == null) { 260 d.source_reference.file.add_node (d); 261 } 262 263 delegates.add (d); 264 scope.add (d.name, d); 265 } 266 267 /** 268 * Returns the list of structs. 269 * 270 * @return struct list 271 */ 272 public unowned List<Struct> get_structs () { 273 return structs; 274 } 275 276 /** 277 * Returns the list of classes. 278 * 279 * @return class list 280 */ 281 public unowned List<Class> get_classes () { 282 return classes; 283 } 284 285 /** 286 * Returns the list of interfaces. 287 * 288 * @return interface list 289 */ 290 public unowned List<Interface> get_interfaces () { 291 return interfaces; 292 } 293 294 /** 295 * Returns the list of enums. 296 * 297 * @return enum list 298 */ 299 public unowned List<Enum> get_enums () { 300 return enums; 301 } 302 303 /** 304 * Returns the list of error domains. 305 * 306 * @return error domain list 307 */ 308 public unowned List<ErrorDomain> get_error_domains () { 309 return error_domains; 310 } 311 312 /** 313 * Returns the list of fields. 314 * 315 * @return field list 316 */ 317 public unowned List<Field> get_fields () { 318 return fields; 319 } 320 321 /** 322 * Returns the list of constants. 323 * 324 * @return constant list 325 */ 326 public unowned List<Constant> get_constants () { 327 return constants; 328 } 329 330 /** 331 * Returns the list of delegates. 332 * 333 * @return delegate list 334 */ 335 public unowned List<Delegate> get_delegates () { 336 return delegates; 337 } 338 339 /** 340 * Returns the list of methods. 341 * 342 * @return method list 343 */ 344 public unowned List<Method> get_methods () { 345 return methods; 346 } 347 348 /** 349 * Adds the specified constant to this namespace. 350 * 351 * @param constant a constant 352 */ 353 public override void add_constant (Constant constant) { 354 // namespaces do not support private members 355 if (constant.access == SymbolAccessibility.PRIVATE) { 356 constant.access = SymbolAccessibility.INTERNAL; 357 } 358 359 if (constant.owner == null) { 360 constant.source_reference.file.add_node (constant); 361 } 362 363 constants.add (constant); 364 scope.add (constant.name, constant); 365 } 366 367 /** 368 * Adds the specified field to this namespace. 369 * 370 * @param f a field 371 */ 372 public override void add_field (Field f) { 373 // namespaces do not support private members 374 if (f.access == SymbolAccessibility.PRIVATE) { 375 f.access = SymbolAccessibility.INTERNAL; 376 } 377 378 if (f.owner == null) { 379 f.source_reference.file.add_node (f); 380 } 381 382 fields.add (f); 383 scope.add (f.name, f); 384 } 385 386 /** 387 * Adds the specified method to this namespace. 388 * 389 * @param m a method 390 */ 391 public override void add_method (Method m) { 392 // namespaces do not support private members 393 if (m.access == SymbolAccessibility.PRIVATE) { 394 m.access = SymbolAccessibility.INTERNAL; 395 } 396 397 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) { 398 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference); 399 m.result_var.is_result = true; 400 } 401 402 if (m.owner == null) { 403 m.source_reference.file.add_node (m); 404 } 405 406 methods.add (m); 407 scope.add (m.name, m); 408 } 409 410 public override void accept (CodeVisitor visitor) { 411 visitor.visit_namespace (this); 412 } 413 414 public override void accept_children (CodeVisitor visitor) { 415 foreach (UsingDirective ns_ref in using_directives) { 416 ns_ref.accept (visitor); 417 } 418 419 foreach (Namespace ns in namespaces) { 420 ns.accept (visitor); 421 } 422 423 /* process enums first to avoid order problems in C code */ 424 foreach (Enum en in enums) { 425 en.accept (visitor); 426 } 427 428 foreach (ErrorDomain edomain in error_domains) { 429 edomain.accept (visitor); 430 } 431 432 foreach (Class cl in classes) { 433 cl.accept (visitor); 434 } 435 436 foreach (Interface iface in interfaces) { 437 iface.accept (visitor); 438 } 439 440 foreach (Struct st in structs) { 441 st.accept (visitor); 442 } 443 444 foreach (Delegate d in delegates) { 445 d.accept (visitor); 446 } 447 448 foreach (Constant c in constants) { 449 c.accept (visitor); 450 } 451 452 foreach (Field f in fields) { 453 f.accept (visitor); 454 } 455 456 foreach (Method m in methods) { 457 m.accept (visitor); 458 } 459 } 460 461 public override bool check (CodeContext context) { 462 if (checked) { 463 return !error; 464 } 465 466 checked = true; 467 468 var a = get_attribute ("CCode"); 469 if (a != null && a.has_argument ("gir_namespace")) { 470 source_reference.file.gir_namespace = a.get_string ("gir_namespace"); 471 } 472 if (a != null && a.has_argument ("gir_version")) { 473 source_reference.file.gir_version = a.get_string ("gir_version"); 474 } 475 476 foreach (Field f in fields) { 477 if (f.binding == MemberBinding.INSTANCE) { 478 Report.error (f.source_reference, "instance fields are not allowed outside of data types"); 479 f.error = true; 480 error = true; 481 } else if (f.binding == MemberBinding.CLASS) { 482 Report.error (f.source_reference, "class fields are not allowed outside of classes"); 483 f.error = true; 484 error = true; 485 } 486 } 487 488 foreach (Method m in methods) { 489 if (m is CreationMethod) { 490 Report.error (m.source_reference, "construction methods may only be declared within classes and structs"); 491 m.error = true; 492 error = true; 493 } 494 if (m.binding == MemberBinding.INSTANCE) { 495 Report.error (m.source_reference, "instance methods are not allowed outside of data types"); 496 m.error = true; 497 error = true; 498 } else if (m.binding == MemberBinding.CLASS) { 499 Report.error (m.source_reference, "class methods are not allowed outside of classes"); 500 m.error = true; 501 error = true; 502 } 503 } 504 505 foreach (Namespace ns in namespaces) { 506 ns.check (context); 507 } 508 509 return !error; 510 } 511 512 public override string to_string () { 513 if (name == null) { 514 return "(root namespace)"; 515 } else { 516 return "namespace %s".printf (name); 517 } 518 } 519} 520