* Add require 'khtml' statements
[kdebindings.git] / kalyptus / Iter.pm
blobbad7d70391fafe1a8bec38a1fa98c3886188bbdb
1 package Iter;
3 =head1 Iterator Module
5 A set of iterator functions for traversing the various trees and indexes.
6 Each iterator expects closures that operate on the elements in the iterated
7 data structure.
10 =head2 Generic
12 Params: $node, &$loopsub, &$skipsub, &$applysub, &$recursesub
14 Iterate over $node\'s children. For each iteration:
16 If loopsub( $node, $kid ) returns false, the loop is terminated.
17 If skipsub( $node, $kid ) returns true, the element is skipped.
19 Applysub( $node, $kid ) is called
20 If recursesub( $node, $kid ) returns true, the function recurses into
21 the current node.
23 =cut
25 sub Generic
27 my ( $root, $loopcond, $skipcond, $applysub, $recursecond ) = @_;
29 return sub {
30 foreach my $node ( @{$root->{Kids}} ) {
32 if ( defined $loopcond ) {
33 return 0 unless $loopcond->( $root, $node );
36 if ( defined $skipcond ) {
37 next if $skipcond->( $root, $node );
40 my $ret = $applysub->( $root, $node );
41 return $ret if defined $ret && $ret;
43 if ( defined $recursecond
44 && $recursecond->( $root, $node ) ) {
45 $ret = Generic( $node, $loopcond, $skipcond,
46 $applysub, $recursecond)->();
47 if ( $ret ) {
48 return $ret;
53 return 0;
57 sub Class
59 my ( $root, $applysub, $recurse ) = @_;
61 return Generic( $root, undef,
62 sub {
63 return !( $node->{NodeType} eq "class"
64 || $node->{NodeType} eq "struct" );
65 },
66 $applysub, $recurse );
69 =head2 Tree
71 Params: $root, $recurse?, $commonsub, $compoundsub, $membersub,
72 $skipsub
74 Traverse the ast tree starting at $root, skipping if skipsub returns true.
76 Applying $commonsub( $node, $kid),
77 then $compoundsub( $node, $kid ) or $membersub( $node, $kid ) depending on
78 the Compound flag of the node.
80 =cut
82 sub Tree
84 my ( $rootnode, $recurse, $commonsub, $compoundsub, $membersub,
85 $skipsub ) = @_;
87 my $recsub = $recurse ? sub { return 1 if $_[1]->{Compound}; }
88 : undef;
90 Generic( $rootnode, undef, $skipsub,
91 sub { # apply
92 my ( $root, $node ) = @_;
93 my $ret;
95 if ( defined $commonsub ) {
96 $ret = $commonsub->( $root, $node );
97 return $ret if defined $ret;
100 if ( $node->{Compound} && defined $compoundsub ) {
101 $ret = $compoundsub->( $root, $node );
102 return $ret if defined $ret;
105 if( !$node->{Compound} && defined $membersub ) {
106 $ret = $membersub->( $root, $node );
107 return $ret if defined $ret;
109 return;
111 $recsub # skip
112 )->();
115 =head2 LocalCompounds
117 Apply $compoundsub( $node ) to all locally defined compound nodes
118 (ie nodes that are not external to the library being processed).
120 =cut
122 sub LocalCompounds
124 my ( $rootnode, $compoundsub ) = @_;
126 return unless defined $rootnode && defined $rootnode->{Kids};
128 foreach my $kid ( sort { $a->{astNodeName} cmp $b->{astNodeName} }
129 @{$rootnode->{Kids}} ) {
130 next if !defined $kid->{Compound};
132 $compoundsub->( $kid ) unless defined $kid->{ExtSource};
133 LocalCompounds( $kid, $compoundsub );
137 =head2 Hierarchy
139 Params: $node, $levelDownSub, $printSub, $levelUpSub
141 This allows easy hierarchy traversal and printing.
143 Traverses the inheritance hierarchy starting at $node, calling printsub
144 for each node. When recursing downward into the tree, $levelDownSub($node) is
145 called, the recursion takes place, and $levelUpSub is called when the
146 recursion call is completed.
148 =cut
150 sub Hierarchy
152 my ( $node, $ldownsub, $printsub, $lupsub, $nokidssub ) = @_;
154 return if defined $node->{ExtSource}
155 && (!defined $node->{InBy}
156 || !kdocAstUtil::hasLocalInheritor( $node ));
158 $printsub->( $node );
160 if ( defined $node->{InBy} ) {
161 $ldownsub->( $node );
163 foreach my $kid (
164 sort {$a->{astNodeName} cmp $b->{astNodeName}}
165 @{ $node->{InBy} } ) {
166 Hierarchy( $kid, $ldownsub, $printsub, $lupsub );
169 $lupsub->( $node );
171 elsif ( defined $nokidssub ) {
172 $nokidssub->( $node );
175 return;
178 =head2
180 Call $printsub for each outer scope of $node.
182 =cut
183 sub Heritage
185 my ( $node, $printsub ) = @_;
186 my @anlist = ();
187 my @heritage = kdocAstUtil::refHeritage($node);
189 foreach my $innode ( @heritage ) {
190 next if $innode == $node;
191 $printsub->( $innode, $innode->{astNodeName},
192 $innode->{Type}, $innode->{TmplType} )
193 unless !defined $printsub;
196 return;
200 =head2
202 Call $printsub for each *direct* ancestor of $node.
203 Only multiple inheritance can lead to $printsub being called more than once.
205 =cut
206 sub Ancestors
208 my ( $node, $rootnode, $noancessub, $startsub, $printsub,
209 $endsub ) = @_;
210 my @anlist = ();
212 return if $node eq $rootnode;
214 if ( !exists $node->{InList} ) {
215 $noancessub->( $node ) unless !defined $noancessub;
216 return;
219 foreach my $innode ( @{ $node->{InList} } ) {
220 my $nref = $innode->{Node}; # real ancestor
221 next if defined $nref && $nref == $rootnode;
223 push @anlist, $innode;
226 if ( $#anlist < 0 ) {
227 $noancessub->( $node ) unless !defined $noancessub;
228 return;
231 $startsub->( $node ) unless !defined $startsub;
233 foreach my $innode ( sort { $a->{astNodeName} cmp $b->{astNodeName} }
234 @anlist ) {
236 # print
237 $printsub->( $innode->{Node}, $innode->{astNodeName},
238 $innode->{Type}, $innode->{TmplType} )
239 unless !defined $printsub;
242 $endsub->( $node ) unless !defined $endsub;
244 return;
248 sub Descendants
250 my ( $node, $nodescsub, $startsub, $printsub, $endsub ) = @_;
252 if ( !exists $node->{InBy} ) {
253 $nodescsub->( $node ) unless !defined $nodescsub;
254 return;
258 my @desclist = ();
259 DescendantList( \@desclist, $node );
261 if ( $#desclist < 0 ) {
262 $nodescsub->( $node ) unless !defined $nodescsub;
263 return;
266 $startsub->( $node ) unless !defined $startsub;
268 foreach my $innode ( sort { $a->{astNodeName} cmp $b->{astNodeName} }
269 @desclist ) {
271 $printsub->( $innode)
272 unless !defined $printsub;
275 $endsub->( $node ) unless !defined $endsub;
277 return;
281 sub DescendantList
283 my ( $list, $node ) = @_;
285 return unless exists $node->{InBy};
287 foreach my $kid ( @{ $node->{InBy} } ) {
288 push @$list, $kid;
289 DescendantList( $list, $kid );
293 =head2 DocTree
295 =cut
297 sub DocTree
299 my ( $rootnode, $allowforward, $recurse,
300 $commonsub, $compoundsub, $membersub ) = @_;
302 Generic( $rootnode, undef,
303 sub { # skip
304 my( $node, $kid ) = @_;
306 unless (!(defined $kid->{ExtSource})
307 && ($allowforward || $kid->{NodeType} ne "Forward")
308 && ($main::doPrivate || !($kid->{Access} =~ /private/))
309 && exists $kid->{DocNode} ) {
311 return 1;
314 return;
316 sub { # apply
317 my ( $root, $node ) = @_;
319 my $ret;
321 if ( defined $commonsub ) {
322 $ret = $commonsub->( $root, $node );
323 return $ret if defined $ret;
326 if ( $node->{Compound} && defined $compoundsub ) {
327 $ret = $compoundsub->( $root, $node );
328 return $ret if defined $ret;
330 elsif( defined $membersub ) {
331 $ret = $membersub->( $root, $node );
332 return $ret if defined $ret;
335 return;
337 sub { return 1 if $recurse; return; } # recurse
338 )->();
342 sub MembersByType
344 my ( $node, $startgrpsub, $methodsub, $endgrpsub, $nokidssub ) = @_;
346 # public
347 # types
348 # data
349 # methods
350 # signals
351 # slots
352 # static
353 # protected
354 # private (if enabled)
356 if ( !defined $node->{Kids} ) {
357 $nokidssub->( $node ) if defined $nokidssub;
358 return;
361 foreach my $acc ( qw/public protected private/ ) {
362 next if $acc eq "private" && !$main::doPrivate;
363 $access = $acc;
365 my @types = ();
366 my @data = ();
367 my @signals = ();
368 my @k_dcops = ();
369 my @k_dcop_signals = ();
370 my @k_dcop_hiddens = ();
371 my @slots =();
372 my @methods = ();
373 my @static = ();
374 my @modules = ();
375 my @interfaces = ();
377 # Build lists
378 foreach my $kid ( @{$node->{Kids}} ) {
379 next unless ( $kid->{Access} =~ /$access/
380 && !$kid->{ExtSource})
381 || ( $access eq "public"
382 && ( $kid->{Access} eq "signals"
383 || $kid->{Access} =~ "k_dcop" # note the =~
384 || $kid->{Access} eq "K_DCOP"));
386 my $type = $kid->{NodeType};
388 if ( $type eq "method" ) {
389 if ( $kid->{Flags} =~ "s" ) {
390 push @static, $kid;
392 elsif ( $kid->{Flags} =~ "l" ) {
393 push @slots, $kid;
395 elsif ( $kid->{Flags} =~ "n" ) {
396 push @signals, $kid;
398 elsif ( $kid->{Flags} =~ "d" ) {
399 push @k_dcops, $kid;
401 elsif ( $kid->{Flags} =~ "z" ) {
402 push @k_dcop_signals, $kid;
404 elsif ( $kid->{Flags} =~ "y" ) {
405 push @k_dcop_hiddens, $kid;
407 else {
408 push @methods, $kid; }
410 elsif ( $kid->{Compound} ) {
411 if ( $type eq "module" ) {
412 push @modules, $kid;
414 elsif ( $type eq "interface" ) {
415 push @interfaces, $kid;
417 else {
418 push @types, $kid;
421 elsif ( $type eq "typedef" || $type eq "enum" ) {
422 push @types, $kid;
424 else {
425 push @data, $kid;
429 # apply
430 $uc_access = ucfirst( $access );
432 doGroup( "$uc_access Types", $node, \@types, $startgrpsub,
433 $methodsub, $endgrpsub);
434 doGroup( "Modules", $node, \@modules, $startgrpsub,
435 $methodsub, $endgrpsub);
436 doGroup( "Interfaces", $node, \@interfaces, $startgrpsub,
437 $methodsub, $endgrpsub);
438 doGroup( "$uc_access Methods", $node, \@methods, $startgrpsub,
439 $methodsub, $endgrpsub);
440 doGroup( "$uc_access Slots", $node, \@slots, $startgrpsub,
441 $methodsub, $endgrpsub);
442 doGroup( "Signals", $node, \@signals, $startgrpsub,
443 $methodsub, $endgrpsub);
444 doGroup( "k_dcop", $node, \@k_dcops, $startgrpsub,
445 $methodsub, $endgrpsub);
446 doGroup( "k_dcop_signals", $node, \@k_dcop_signals, $startgrpsub,
447 $methodsub, $endgrpsub);
448 doGroup( "k_dcop_hiddens", $node, \@k_dcop_hiddens, $startgrpsub,
449 $methodsub, $endgrpsub);
450 doGroup( "$uc_access Static Methods", $node, \@static,
451 $startgrpsub, $methodsub, $endgrpsub);
452 doGroup( "$uc_access Members", $node, \@data, $startgrpsub,
453 $methodsub, $endgrpsub);
457 sub doGroup
459 my ( $name, $node, $list, $startgrpsub, $methodsub, $endgrpsub ) = @_;
461 my ( $hasMembers ) = 0;
462 foreach my $kid ( @$list ) {
463 if ( !exists $kid->{DocNode}->{Reimplemented} ) {
464 $hasMembers = 1;
465 break;
468 return if !$hasMembers;
470 if ( defined $methodsub ) {
471 foreach my $kid ( @$list ) {
472 if ( !exists $kid->{DocNode}->{Reimplemented} ) {
473 $methodsub->( $node, $kid );
478 $endgrpsub->( $name ) if defined $endgrpsub;
481 sub ByGroupLogical
483 my ( $root, $startgrpsub, $itemsub, $endgrpsub ) = @_;
485 return 0 unless defined $root->{Groups};
487 foreach my $groupname ( sort keys %{$root->{Groups}} ) {
488 next if $groupname eq "astNodeName"||$groupname eq "NodeType";
490 my $group = $root->{Groups}->{ $group };
491 next unless $group->{Kids};
493 $startgrpsub->( $group->{astNodeName}, $group->{Desc} );
495 foreach my $kid (sort {$a->{astNodeName} cmp $b->{astNodeName}}
496 @group->{Kids} ) {
497 $itemsub->( $root, $kid );
499 $endgrpsub->( $group->{Desc} );
502 return 1;
505 sub SeeAlso
507 my ( $node, $nonesub, $startsub, $printsub, $endsub ) = @_;
509 if( !defined $node ) {
510 $nonesub->();
511 return;
514 my $doc = $node;
516 if ( $node->{NodeType} ne "DocNode" ) {
517 $doc = $node->{DocNode};
518 if ( !defined $doc ) {
519 $nonesub->() if defined $nonesub;
520 return;
524 if ( !defined $doc->{See} ) {
525 $nonesub->() if defined $nonesub;
526 return;
529 my $see = $doc->{See};
530 my $ref = $doc->{SeeRef};
532 if ( $#$see < 1 ) {
533 $nonesub->() if defined $nonesub;
534 return;
537 $startsub->( $node ) if defined $startsub;
539 for my $i ( 0..$#$see ) {
540 my $seelabel = $see->[ $i ];
541 my $seenode = undef;
542 if ( defined $ref ) {
543 $seenode = $ref->[ $i ];
546 $printsub->( $seelabel, $seenode ) if defined $printsub;
549 $endsub->( $node ) if defined $endsub;
551 return;