File Coverage

blib/lib/Go/Tokenize.pm
Criterion Covered Total %
statement 27 42 64.2
branch 1 4 25.0
condition n/a
subroutine 8 9 88.8
pod 1 2 50.0
total 37 57 64.9


line stmt bran cond sub pod time code
1             package Go::Tokenize;
2 1     1   764 use warnings;
  1         2  
  1         32  
3 1     1   6 use strict;
  1         1  
  1         19  
4 1     1   4 use Carp;
  1         1  
  1         52  
5 1     1   5 use utf8;
  1         1  
  1         5  
6             require Exporter;
7             our @ISA = qw(Exporter);
8             our @EXPORT_OK = qw/tokenize/;
9             our %EXPORT_TAGS = (
10             all => \@EXPORT_OK,
11             );
12             our $VERSION = '0.01';
13              
14 1     1   649 use Text::LineNumber;
  1         369  
  1         32  
15 1     1   487 use C::Tokenize qw!$comment_re!;
  1         4423  
  1         280  
16              
17             our $bt_string_re = qr!`[^`]*`!;
18             our $q_string_re = qr!"(\\"|[^"])*"!;
19             our $string_re = qr!(?:$bt_string_re|$q_string_re)!;
20              
21             # https://golang.org/ref/spec#Keywords
22              
23             our @keywords = qw!
24             break default func interface select
25             case defer go map struct
26             chan else goto package switch
27             const fallthrough if range type
28             continue for import return var
29             !;
30              
31             # https://golang.org/ref/spec#Operators_and_punctuation
32              
33             our $operator_re;
34             {
35             # Perl makes an error message "Possible attempt to separate words with
36             # commas at lib/Go/Tokenize.pm line 40." See
37             # https://stackoverflow.com/questions/19573977/
38 1     1   9 no warnings 'qw';
  1         1  
  1         430  
39             my @operators = (qw@
40             + & += &= && == != ( )
41             - | -= |= || < <= [ ]
42             * ^ *= ^= <- > >= { }
43             / << /= <<= ++ = := , ;
44             % >> %= >>= -- ! ... . :
45             &^ &^=
46             @);
47             $operator_re = make_re (@operators);
48             }
49              
50             our $keyword_re = make_re (@keywords);
51              
52             our $go_re = qr!
53             # Comment must go before everything else.
54             (?$comment_re)
55             |
56             # String must go before everything except comments.
57             (?$string_re)
58             |
59             (?$keyword_re)
60             |
61             (?$operator_re)
62             !x;
63              
64             my @types = (qw!comment string keyword operator!);
65              
66             sub tokenize
67             {
68 0     0 1 0 my ($go) = @_;
69 0         0 my $tln = Text::LineNumber->new ($go);
70 0         0 my @tokens;
71 0         0 while ($go =~ /($go_re)/g) {
72 0         0 my %token;
73 0         0 $token{contents} = $1;
74 0         0 $token{end} = pos ($go);
75 0         0 $token{start} = $token{end} - length ($token{contents}) + 1;
76 0         0 for my $type (@types) {
77 0 0       0 if ($+{$type}) {
78 0         0 $token{type} = $type;
79 0         0 last;
80             }
81             }
82 0         0 $token{line} = $tln->off2lnr ($token{start});
83 0         0 push @tokens, \%token;
84             }
85 0         0 return \@tokens;
86             }
87              
88             sub make_re
89             {
90 2 50   2 0 7 my @sorted = sort {length ($b) <=> length ($a) || $a cmp $b} @_;
  296         445  
91 2         4 my @quoted = map {quotemeta ($_)} @sorted;
  72         101  
92 2         47 my $re = join '|', @quoted;
93 2         13 return $re;
94             }
95              
96             1;