<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Iter;

use strict;

=head1 Iterator Module

A set of iterator functions for traversing the various trees and indexes.
Each iterator expects closures that operate on the elements in the iterated
data structure.


=head2 Generic

	Params: $node, &amp;$loopsub, &amp;$skipsub, &amp;$applysub, &amp;$recursesub

Iterate over $node's children. For each iteration:
	
If loopsub( $node, $kid ) returns false, the loop is terminated. 
If skipsub( $node, $kid )  returns true, the element is skipped.

Applysub( $node, $kid ) is called
If recursesub( $node, $kid ) returns true, the function recurses into 
the current node.

=cut

sub Generic
{
	my ( $root, $loopcond, $skipcond, $applysub, $recursecond ) = @_;

	return sub {
		foreach my $node ( @{$root-&gt;{Kids}} ) {

			if ( defined  $loopcond ) {
				return 0 unless $loopcond-&gt;( $root, $node );
			}

			if ( defined $skipcond ) {
				next if $skipcond-&gt;( $root, $node );
			}

			my $ret = $applysub-&gt;( $root, $node );
			return $ret if defined $ret &amp;&amp; $ret;

			if ( defined $recursecond 
					&amp;&amp; $recursecond-&gt;( $root, $node ) ) {
				$ret = Generic( $node, $loopcond, $skipcond,
						$applysub, $recursecond)-&gt;();
				if ( $ret ) {
					return $ret;
				}
			}
		}

		return 0;
	};
}

sub Class
{
	my ( $root, $applysub, $recurse ) = @_;

	return Generic( $root, undef,
		sub {
			my ( $root, $node ) = @_;
			return !( $node-&gt;{NodeType} eq "class" 
				|| $node-&gt;{NodeType} eq "struct" );
		}, 
		$applysub, $recurse );
}

=head2 Tree

	Params: $root, $recurse?, $commonsub, $compoundsub, $membersub,
		$skipsub

Traverse the ast tree starting at $root, skipping if skipsub returns true.

Applying $commonsub( $node, $kid),
then $compoundsub( $node, $kid ) or $membersub( $node, $kid ) depending on
the Compound flag of the node.

=cut

sub Tree
{
	my ( $rootnode, $recurse, $commonsub, $compoundsub, $membersub, 
		 $skipsub ) = @_;

	my $recsub = ($recurse != 0) ? sub { return 1 if $_[1]-&gt;{Compound}; } 
				: undef;

	Generic( $rootnode, undef, $skipsub,
		sub { 					# apply
			my ( $root, $node ) = @_;
			my $ret;

			if ( defined $commonsub ) {
				$ret = $commonsub-&gt;( $root, $node );
				return $ret if defined $ret;
			}

			if ( $node-&gt;{Compound} &amp;&amp; defined $compoundsub ) {
				$ret = $compoundsub-&gt;( $root, $node );
				return $ret if defined $ret;
			}
			
			if( !$node-&gt;{Compound} &amp;&amp; defined $membersub ) {
				$ret = $membersub-&gt;( $root, $node );
				return $ret if defined $ret;
			}
			return;
		},
		$recsub 				# skip
	)-&gt;();
}

=head2 LocalCompounds

Apply $compoundsub( $node ) to all locally defined compound nodes
(ie nodes that are not external to the library being processed).

=cut

sub LocalCompounds
{
		my ( $rootnode, $compoundsub ) = @_;

		return unless defined $rootnode &amp;&amp; defined $rootnode-&gt;{Kids};

		foreach my $kid ( sort { $a-&gt;{astNodeName} cmp $b-&gt;{astNodeName} }
								 @{$rootnode-&gt;{Kids}} ) {
				next if !defined $kid-&gt;{Compound};

				$compoundsub-&gt;( $kid ) unless defined $kid-&gt;{ExtSource};
				LocalCompounds( $kid, $compoundsub );
		}
}

=head2 GlobalsBySourceFile

	p: rootnode, sS, sE, sFileS, sFileE, sGlobalP

=cut

sub GlobalsBySourceFile
{
	my( $node, $sS, $sE, $sFileS, $sFileE, $sGlobalP ) = @_;

	my $sources = $node-&gt;{Sources};
	return if !defined $sources || $#$sources &lt; 0;

	$sS-&gt;() if defined $sS;

	foreach my $source ( 
			sort { $a-&gt;{astNodeName} cmp $b-&gt;{astNodeName} } @$sources )
	{
		next if !defined $source-&gt;{Globals};
		
		$sFileS-&gt;( $source-&gt;{astNodeName}, $source ) if defined $sFileS;

		if ( defined $sGlobalP ) {
			foreach my $global ( @{ $source-&gt;{Globals} } ) {
				$sGlobalP-&gt;( $global );
			}
		}

		$sFileE-&gt;( $source-&gt;{astNodeName}, $source ) if defined $sFileE;
	}

	$sE-&gt;() if defined $sE;
}

=head2 Hierarchy

	Params: $node, $levelDownSub, $printSub, $levelUpSub

This allows easy hierarchy traversal and printing.

Traverses the inheritance hierarchy starting at $node, calling printsub
for each node. When recursing downward into the tree, $levelDownSub($node) is
called, the recursion takes place, and $levelUpSub is called when the
recursion call is completed. 

=cut

sub Hierarchy
{
	my ( $node, $ldownsub, $printsub, $lupsub, $nokidssub ) = @_;

	return if defined $node-&gt;{ExtSource}
		&amp;&amp; (!defined $node-&gt;{InBy} 
			|| !kdocAstUtil::hasLocalInheritor( $node ));

        return if exists $node-&gt;{DocNode}-&gt;{Internal} &amp;&amp; $main::skipInternal;

	$printsub-&gt;( $node );

	if ( defined $node-&gt;{InBy} ) {
		$ldownsub-&gt;( $node );

		foreach my $kid ( 
				sort {$a-&gt;{astNodeName} cmp $b-&gt;{astNodeName}}
				@{ $node-&gt;{InBy} } ) {
			Hierarchy( $kid, $ldownsub, $printsub, $lupsub );
		}

		$lupsub-&gt;( $node );
	}
	elsif ( defined $nokidssub ) {
		$nokidssub-&gt;( $node );
	}

	return;
}


sub Ancestors
{
	my ( $node, $rootnode, $noancessub, $startsub, $printsub,
		$endsub ) = @_;
	my @anlist = ();

	return if $node eq $rootnode;

	if ( !exists $node-&gt;{InList} ) {
		$noancessub-&gt;( $node ) unless !defined $noancessub;
		return;
	}
	
	foreach my $innode ( @{ $node-&gt;{InList} } ) {
		my $nref = $innode-&gt;{Node};	# real ancestor
		next if defined $nref &amp;&amp; $nref == $rootnode;

		push @anlist, $innode;
	}

	if ( $#anlist &lt; 0 ) {
		$noancessub-&gt;( $node ) unless !defined $noancessub;
		return;
	}

	$startsub-&gt;( $node ) unless !defined $startsub;

	foreach my $innode ( sort { $a-&gt;{astNodeName} cmp $b-&gt;{astNodeName} }
				@anlist ) {

		# print
		$printsub-&gt;( $innode-&gt;{Node}, $innode-&gt;{astNodeName},
			$innode-&gt;{Type}, $innode-&gt;{TmplType} ) 
			unless !defined $printsub;
	}

	$endsub-&gt;( $node ) unless !defined $endsub;

	return;

}

sub Descendants
{
	my ( $node, $nodescsub, $startsub, $printsub, $endsub ) = @_;

	if ( !exists $node-&gt;{InBy} ) {
		$nodescsub-&gt;( $node ) unless !defined $nodescsub;
		return;
	}

	
	my @desclist = ();
	DescendantList( \@desclist, $node );
	
	if ( $#desclist &lt; 0 ) {
		$nodescsub-&gt;( $node ) unless !defined $nodescsub;
		return;
	}

	$startsub-&gt;( $node ) unless !defined $startsub;

	foreach my $innode ( sort { $a-&gt;{astNodeName} cmp $b-&gt;{astNodeName} }
				@desclist ) {

		$printsub-&gt;( $innode) 
			unless !defined $printsub;
	}

	$endsub-&gt;( $node ) unless !defined $endsub;

	return;

}

sub DescendantList
{
	my ( $list, $node ) = @_;

	return unless exists $node-&gt;{InBy};

	foreach my $kid ( @{ $node-&gt;{InBy} } ) {
		push @$list, $kid;
		DescendantList( $list, $kid );
	}
}

=head2 DocTree

=cut

sub DocTree
{
	my ( $rootnode, $allowforward, $recurse, 
		$commonsub, $compoundsub, $membersub ) = @_;
		
	Generic( $rootnode, undef,
		sub {				# skip
			my( $node, $kid ) = @_;

			unless (!(defined $kid-&gt;{ExtSource}) 
					&amp;&amp; ($allowforward || $kid-&gt;{NodeType} ne "Forward")
					&amp;&amp; ($main::doPrivate || !($kid-&gt;{Access} =~ /private/))
					&amp;&amp; exists $kid-&gt;{DocNode} ) {

				return 1;
			}

			return;
		},
		sub { 				# apply
			my ( $root, $node ) = @_;

			my $ret;

			if ( defined $commonsub ) {
				$ret = $commonsub-&gt;( $root, $node );
				return $ret if defined $ret;
			}

			if ( $node-&gt;{Compound} &amp;&amp; defined $compoundsub ) {
				$ret = $compoundsub-&gt;( $root, $node );
				return $ret if defined $ret;
			}
			elsif( defined $membersub ) {
				$ret = $membersub-&gt;( $root, $node );
				return $ret if defined $ret;
			}

			return;
		},
		sub { return 1 if $recurse; return; }	# recurse
		)-&gt;();

}

=head2 MembersByType

	p: node, $sGroupS, $sItemP, $sGroupE, $sOnNone

Iterates over node's members sorted by type.

What we have to cover, in order

public (types/data/methods/slots/statics)
signals
k_dcop stuff
protected (types/data/methods/slots/statics)
private (types/data/methods/slots/statics) (depending on doPrivate)

Collection criteria:

Access contains word (public, private, protected)
Access is word (signals, interface, module)

=cut

sub MembersByType
{
	
	my ( $node, $startgrpsub, $methodsub, $endgrpsub, $nokidssub ) = @_;

	# per vis
	my @types = ();
	my @data = ();
	my @methods = ();
	my @slots = ();
	my @static = ();

	my @interfaces = ();
	my @modules = ();
	my @signals = ();

	# build list for public, protected types, data members and methods

	if ( !defined $node-&gt;{Kids} ) {
			$nokidssub-&gt;( $node ) if defined $nokidssub;
			return;
	}

	my $kids = $node-&gt;{Kids};

	foreach my $kid ( @$kids ) {
		my $type = $kid-&gt;{NodeType};

		if ( $type eq "method" ) {
			if ( $kid-&gt;{Flags} =~ /s/ ) {
				push @static, $kid;
			}
			elsif ( $kid-&gt;{Flags} =~ /l/ ) {
				push @slots, $kid;
			}
			elsif ( $kid-&gt;{Flags} =~ /n/ ) {
				push @signals, $kid;
			}
			else {
				push @methods, $kid;
			}
		}
		elsif ( $kid-&gt;{Compound} ) {
			if ( $type eq "module" ) {
				push @modules, $kid;
			}
			elsif ( $type eq "interface" ) {
				push @interfaces, $kid;
			}
			else {
				push @types, $kid;
			}
		}
		elsif ( $type eq "typedef" || $type eq "enum" ) {
			push @types, $kid;
		}
		else {
			push @data, $kid;
		}
	}

	doGroup( "Modules", $node, \@modules, $startgrpsub,
			$methodsub, $endgrpsub);
	doGroup( "Interfaces", $node, \@interfaces, $startgrpsub,
			$methodsub, $endgrpsub);

	# select into visibility lists
	my @vislist = qw/public protected/;
	push @vislist, "private" if $main::doPrivate;

	foreach my $access ( @vislist ) {
		my $uc_access = ucfirst( $access );

		doGroup( "$uc_access Types", $node, \@types, $startgrpsub,
				$methodsub, $endgrpsub, $access );

#		if ( $access eq "public" ) {
#			doGroup( "Modules", $node, \@modules, $startgrpsub,
#					$methodsub, $endgrpsub);
#			doGroup( "Interfaces", $node, \@interfaces, $startgrpsub,
#					$methodsub, $endgrpsub);
#		}

		doGroup( "$uc_access Methods", $node, \@methods, $startgrpsub,
				$methodsub, $endgrpsub, $access );
		doGroup( "$uc_access Slots", $node, \@slots, $startgrpsub,
				$methodsub, $endgrpsub, $access );

		if ( $access eq "public" ) {
			doGroup( "Signals", $node, \@signals, $startgrpsub,
					$methodsub, $endgrpsub);
		}

		doGroup( "$uc_access Static Methods", $node, \@static, 
				$startgrpsub, $methodsub, $endgrpsub, $access);
		doGroup( "$uc_access Members", $node, \@data, $startgrpsub,
				$methodsub, $endgrpsub, $access );
	}
}

sub doGroup
{
	my ($name, $node, $list, $startgrpsub, $methodsub, $endgrpsub, $vis)=@_;

	my ( $hasMembers ) = 0;
	foreach my $kid ( @$list ) {
		next if defined $vis &amp;&amp; !($kid-&gt;{Access} =~ /$vis/);

		if ( !exists $kid-&gt;{DocNode}-&gt;{Reimplemented} ) {
			$hasMembers = 1;
			last;
		}
	}
	return if !$hasMembers;

	$startgrpsub-&gt;( $name ) if defined $startgrpsub;

	if ( defined $methodsub ) {
		foreach my $kid ( @$list ) {
			next if defined $vis &amp;&amp; !($kid-&gt;{Access} =~ /$vis/)
					|| exists $kid-&gt;{DocNode}-&gt;{Reimplemented};
			$methodsub-&gt;( $node, $kid );
		}
	}

	$endgrpsub-&gt;( $name ) if defined $endgrpsub;
}

sub ByGroupLogical
{
	my ( $root, $startgrpsub, $itemsub, $endgrpsub ) = @_;

	return 0 unless defined $root-&gt;{Groups};

	foreach my $groupname ( sort keys %{$root-&gt;{Groups}} ) {
		next if $groupname eq "astNodeName"||$groupname eq "NodeType";

		my $group = $root-&gt;{Groups}-&gt;{ $groupname };
		next unless $group-&gt;{Kids};
		
		$startgrpsub-&gt;( $group-&gt;{astNodeName}, $group-&gt;{Desc} );

		foreach my $kid (sort {$a-&gt;{astNodeName} cmp $b-&gt;{astNodeName}}
					$group-&gt;{Kids} ) {
			$itemsub-&gt;( $root, $kid );
		}
		$endgrpsub-&gt;( $group-&gt;{Desc} );	
	}

	return 1;
}


1;
</pre></body></html>