1/* node.vala 2 * 3 * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois 4 * Copyright (C) 2011 Florian Brosch 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Author: 21 * Didier 'Ptitjes Villevalois <ptitjes@free.fr> 22 */ 23 24 25/** 26 * Represents a node in the api tree. 27 */ 28public abstract class Valadoc.Api.Node : Item, Documentation { 29 protected bool do_document = false; 30 private SourceFile file; 31 32 /** 33 * The name of the node 34 */ 35 public string? name { 36 private set; 37 get; 38 } 39 40 public SourceFile get_source_file () { 41 return file; 42 } 43 44 /** 45 * Returns the type of this node 46 */ 47 public abstract NodeType node_type { get; } 48 49 private Vala.Map<string, Node> per_name_children; 50 private Vala.Map<NodeType, Vala.List<Node>> per_type_children; 51 52 53 protected Node (Node? parent, SourceFile? file, string? name, Vala.CodeNode? data) { 54 base (data); 55 56 per_name_children = new Vala.HashMap<string, Node> (str_hash, str_equal); 57 per_type_children = new Vala.HashMap<NodeType, Vala.List<Node>> (); 58 59 if (name != null && (Vala.Scanner.get_identifier_or_keyword (name, name.length) != Vala.TokenType.IDENTIFIER || name[0].isdigit ())) { 60 this.name = "@" + name; 61 } else { 62 this.name = name; 63 } 64 65 this.parent = parent; 66 this.file = file; 67 } 68 69 /** 70 * Visits this node with the specified Visitor. 71 * 72 * @param visitor the visitor to be called while traversing 73 */ 74 public abstract void accept (Visitor visitor); 75 76 /** 77 * {@inheritDoc} 78 */ 79 // TODO: rename to is_visible 80 public abstract bool is_browsable (Settings settings); 81 82 /** 83 * {@inheritDoc} 84 */ 85 public string? get_filename () { 86 if (file == null) { 87 return null; 88 } 89 90 return file.relative_path; 91 } 92 93 public void add_child (Symbol child) { 94 if (child.name != null) { 95 if (child.name[0] == '@') { 96 per_name_children.set (child.name.next_char (), child); 97 } else { 98 per_name_children.set (child.name, child); 99 } 100 } else { 101 // Special case for the root namespace 102 per_name_children.set ("", child); 103 } 104 105 Vala.List<Node> children = per_type_children.get (child.node_type); 106 if (children == null) { 107 children = new Vala.ArrayList<Node> (); 108 per_type_children.set (child.node_type, children); 109 } 110 111 children.add (child); 112 } 113 114 /** 115 * {@inheritDoc} 116 */ 117 internal override void parse_comments (Settings settings, DocumentationParser parser) { 118 do_document = true; 119 120 foreach (Node node in per_name_children.get_values ()) { 121 if (this.parent == node) { 122 continue; 123 } 124 if (node.is_browsable (settings)) { 125 node.parse_comments (settings, parser); 126 } 127 } 128 } 129 130 /** 131 * {@inheritDoc} 132 */ 133 internal override void check_comments (Settings settings, DocumentationParser parser) { 134 135 foreach (Node node in per_name_children.get_values ()) { 136 if (this.parent == node) { 137 continue; 138 } 139 if (node.is_browsable (settings)) { 140 node.check_comments (settings, parser); 141 } 142 } 143 } 144 145 146 /** 147 * Specifies whether this node has at least one visible child with the given type 148 * 149 * @param type a node type 150 */ 151 public bool has_visible_children_by_type (NodeType type, Settings settings) { 152 Vala.List<Node>? all_children = per_type_children.get (type); 153 if (all_children != null) { 154 foreach (Node node in all_children) { 155 if (node.is_browsable (settings)) { 156 return true; 157 } 158 } 159 } 160 161 return false; 162 } 163 164 /** 165 * Specifies whether this node has at least one visible child with the given types 166 * 167 * @param types a list of node types 168 */ 169 public bool has_visible_children_by_types (NodeType[] types, Settings settings) { 170 foreach (NodeType type in types) { 171 if (has_visible_children_by_type (type, settings)) { 172 return true; 173 } 174 } 175 176 return false; 177 } 178 179 /** 180 * Specifies whether this node has at least one visible child 181 */ 182 public bool has_visible_children (Settings settings) { 183 return has_visible_children_by_types (per_type_children.get_keys ().to_array (), settings); 184 } 185 186 /** 187 * Specifies whether this node has at least one child with the given type 188 * 189 * @param type a node type 190 */ 191 public bool has_children_by_type (NodeType type) { 192 Vala.List<Node>? all_children = per_type_children.get (type); 193 return all_children != null && !all_children.is_empty; 194 } 195 196 /** 197 * Specifies whether this node has at least one child with the given types 198 * 199 * @param types a list of node types 200 */ 201 public bool has_children (NodeType[] types) { 202 foreach (NodeType type in types) { 203 if (has_children_by_type (type)) { 204 return true; 205 } 206 } 207 return false; 208 } 209 210 /** 211 * Returns a list of all children with the given type. 212 * 213 * @param type a node type 214 * @param filtered specifies whether nodes which are not browsable should appear in the list 215 */ 216 public Vala.List<Node> get_children_by_type (NodeType type, bool filtered = true) { 217 var children = new Vala.ArrayList<Node> (); 218 219 Vala.List<Node> all_children = per_type_children.get (type); 220 if (all_children != null) { 221 foreach (Node node in all_children) { 222 if (node.do_document || !filtered) { 223 children.add (node); 224 } 225 } 226 } 227 228 return children; 229 } 230 231 /** 232 * Returns a list of all children with the given types. 233 * 234 * @param types a list of node types 235 * @param filtered specifies whether nodes which are not browsable should appear in the list 236 */ 237 public Vala.List<Node> get_children_by_types (NodeType[] types, bool filtered = true) { 238 var children = new Vala.ArrayList<Node> (); 239 240 foreach (NodeType type in types) { 241 children.add_all (get_children_by_type (type, filtered)); 242 } 243 244 return children; 245 } 246 247 /** 248 * Visits all children of this node with the given type with the specified Visitor. 249 * 250 * @param type a node type 251 * @param visitor the visitor to be called while traversing 252 * @param filtered specifies whether nodes which are not browsable should appear in the list 253 */ 254 public void accept_children_by_type (NodeType type, Visitor visitor, bool filtered = true) { 255 Vala.List<Node> all_children = per_type_children.get (type); 256 if (all_children != null) { 257 foreach (Node node in all_children) { 258 if (node.do_document || !filtered) { 259 node.accept (visitor); 260 } 261 } 262 } 263 } 264 265 /** 266 * Visits all children of this node with the given types with the specified Visitor. 267 * 268 * @param types a list of node types 269 * @param visitor the visitor to be called while traversing 270 * @param filtered specifies whether nodes which are not browsable should appear in the list 271 */ 272 public void accept_children (NodeType[] types, Visitor visitor, bool filtered = true) { 273 foreach (NodeType type in types) { 274 accept_children_by_type (type, visitor, filtered); 275 } 276 } 277 278 /** 279 * Visits all children of this node with the specified Visitor. 280 * 281 * @param visitor the visitor to be called while traversing 282 * @param filtered specifies whether nodes which are not browsable should appear in the list 283 */ 284 public void accept_all_children (Visitor visitor, bool filtered = true) { 285 foreach (Vala.List<Node> children in per_type_children.get_values ()) { 286 if (this.parent == children[0]) { 287 continue; 288 } 289 foreach (Node node in children) { 290 if (node.do_document || !filtered) { 291 node.accept (visitor); 292 } 293 } 294 } 295 } 296 297 public Node? find_by_name (string name) { 298 if (name[0] == '@') { 299 return per_name_children.get (name.next_char ()); 300 } else { 301 return per_name_children.get (name); 302 } 303 } 304 305 private Namespace? _nspace = null; 306 private Package? _package = null; 307 private string _full_name = null; 308 309 /** 310 * The corresponding namespace 311 */ 312 public Namespace? nspace { 313 get { 314 if (this._nspace == null) { 315 Api.Item ast = this; 316 while (ast is Valadoc.Api.Namespace == false) { 317 ast = ast.parent; 318 if (ast == null) { 319 return null; 320 } 321 } 322 this._nspace = (Valadoc.Api.Namespace)ast; 323 } 324 return this._nspace; 325 } 326 } 327 328 /** 329 * The corresponding package such as a vapi or gir file 330 */ 331 public Package? package { 332 get { 333 if (this._package == null) { 334 Api.Item ast = this; 335 while (ast is Valadoc.Api.Package == false) { 336 ast = ast.parent; 337 if (ast == null) { 338 return null; 339 } 340 } 341 this._package = (Valadoc.Api.Package)ast; 342 } 343 return this._package; 344 } 345 } 346 347 public Content.Comment? documentation { 348 internal set; 349 get; 350 } 351 352 /** 353 * Returns canonicalized absolute name (GLib.FileStream for instance) 354 */ 355 public string? get_full_name () { 356 if (this._full_name == null) { 357 if (this.name == null) { 358 return null; 359 } 360 361 GLib.StringBuilder full_name = new GLib.StringBuilder (this.name); 362 363 if (this.parent != null) { 364 for (Item pos = this.parent; pos is Package == false ; pos = pos.parent) { 365 string name = ((Node)pos).name; 366 if (name != null) { 367 full_name.prepend_unichar ('.'); 368 full_name.prepend (name); 369 } 370 } 371 } 372 this._full_name = full_name.str; 373 } 374 return this._full_name; 375 } 376 377 /** 378 * A comparison function used to sort nodes in alphabetical order 379 */ 380 public int compare_to (Node node) { 381 return strcmp (name, node.name); 382 } 383} 384 385