#!/usr/bin/env perl use strict; exit main( @ARGV ); #--------------------------------------------------------------------- sub main { my $lines = ReadLines(); my ( $xref, $numbers_to_names ) = CrossReferenceCodeChunks( $lines ); LangifyCodeChunks( $xref, $numbers_to_names ); EmitLangifiedLines( $lines, $xref, $numbers_to_names ); return 0; } #--------------------------------------------------------------------- sub ReadLines { my @lines = (); while ( my $line = <> ) { chomp $line; push @lines, $line; } return \@lines; } #--------------------------------------------------------------------- sub CrossReferenceCodeChunks { my ( $lines ) = @_; my $current_chunk = ''; my %chunks = (); my @numbers_to_names = (); my $name; foreach my $line ( @$lines ) { if ( $line =~ m/\A@[b]egin code (\d+)\z/ ) { $current_chunk = $1; } elsif ( $current_chunk ne '' && $line =~ m/\A@[d]efn (.*)\z/ ) { $name = $1; push @{ $chunks{$name}{'definition'} }, $current_chunk; $numbers_to_names[$current_chunk] = $name; } elsif ( $current_chunk ne '' && $line =~ m/\A@[u]se (.*)\z/ ) { $name = $1; push @{ $chunks{$name}{'used_by'} }, $current_chunk; } elsif ( $line =~ m/\A@[e]nd code (\d+)\z/ ) { $current_chunk = ''; } } while ( (my $key, my $chunk) = each(%chunks) ) { foreach my $used_by ( @{ $chunk->{'used_by'} || [] } ) { my $other_name = $numbers_to_names[ $used_by ]; my $other = $chunks{ $other_name }; $other->{'uses'}{$key} = 1; } } return \%chunks, \@numbers_to_names; } #--------------------------------------------------------------------- sub SetLanguage { my ( $xref, $lang, $numbers_to_names, $chunk ) = @_; unless ( $chunk->{'lang'} ) { $chunk->{'lang'} = $lang; foreach my $used_key ( keys %{ $chunk->{'uses'} || {} } ) { my $used = $xref->{ $used_key }; SetLanguage( $xref, $lang, $numbers_to_names, $used ) if $used; } } } #--------------------------------------------------------------------- sub LangifyCodeChunks { my ( $xref, $numbers_to_names ) = @_; foreach my $key ( keys %{ $xref } ) { if ( ! $xref->{$key}{'used_by'} ) { my $lang = ''; if ( $key =~ m/\.(lisp|scm|lsp|clj)\z/ ) { $lang = "lisp"; } elsif ( $key =~ m/\.(c|h)\z/ ) { $lang = "c"; } elsif ( $key =~ m/\.(cc|cxx|hh|hxx)\z/ ) { $lang = "c++"; } elsif ( $key =~ m/\.(sh|bash)\z/ ) { $lang = "bash"; } elsif ( $key =~ m/\.([^.]*)\z/ ) { $lang = $1; } if ( $lang ) { SetLanguage( $xref, $lang, $numbers_to_names, $xref->{$key} ); } } } } #--------------------------------------------------------------------- sub EmitLangifiedLines { my ( $lines, $xref, $numbers_to_names ) = @_; foreach my $line ( @$lines ) { print STDOUT "$line\n"; if ( $line =~ m/\A@[b]egin code (\d+)\z/ ) { my $number = $1; my $chunk = $xref->{ $numbers_to_names->[$number] }; my $lang = $chunk->{'lang'}; if ( $lang ) { print STDOUT "\@language $lang\n"; } } } }