| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Perl::LanguageServer::Parser ; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 900 | use Moose::Role ; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 7 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 1 |  |  | 1 |  | 5858 | use Coro ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 110 |  | 
| 6 | 1 |  |  | 1 |  | 8 | use Coro::AIO ; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 360 |  | 
| 7 | 1 |  |  | 1 |  | 8 | use JSON ; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 9 |  | 
| 8 | 1 |  |  | 1 |  | 164 | use File::Basename ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 89 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 1 |  |  | 1 |  | 22 | use v5.16; | 
|  | 1 |  |  |  |  | 4 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 1 |  |  | 1 |  | 7 | no if $] >= 5.018, warnings => 'experimental'; # given, when, Smartmatch | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 20 |  | 
| 13 | 1 |  |  | 1 |  | 93 | no warnings 'uninitialized' ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 31 |  | 
| 14 | 1 |  |  | 1 |  | 6 | use feature 'switch'; # perl 5.16 | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 141 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 1 |  |  | 1 |  | 564 | use Compiler::Lexer; | 
|  | 1 |  |  |  |  | 7104 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 17 | 1 |  |  | 1 |  | 9 | use Data::Dump qw{dump} ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 1 |  |  | 1 |  | 5 | use constant SymbolKindFile => 1; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 65 |  | 
| 20 | 1 |  |  | 1 |  | 6 | use constant SymbolKindModule => 2; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 42 |  | 
| 21 | 1 |  |  | 1 |  | 5 | use constant SymbolKindNamespace => 3; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 58 |  | 
| 22 | 1 |  |  | 1 |  | 6 | use constant SymbolKindPackage => 4; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 52 |  | 
| 23 | 1 |  |  | 1 |  | 9 | use constant SymbolKindClass => 5; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 44 |  | 
| 24 | 1 |  |  | 1 |  | 5 | use constant SymbolKindMethod => 6; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 50 |  | 
| 25 | 1 |  |  | 1 |  | 9 | use constant SymbolKindProperty => 7; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 71 |  | 
| 26 | 1 |  |  | 1 |  | 8 | use constant SymbolKindField => 8; | 
|  | 1 |  |  |  |  | 10 |  | 
|  | 1 |  |  |  |  | 47 |  | 
| 27 | 1 |  |  | 1 |  | 6 | use constant SymbolKindConstructor => 9; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 59 |  | 
| 28 | 1 |  |  | 1 |  | 9 | use constant SymbolKindEnum => 10; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 57 |  | 
| 29 | 1 |  |  | 1 |  | 7 | use constant SymbolKindInterface => 11; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 106 |  | 
| 30 | 1 |  |  | 1 |  | 13 | use constant SymbolKindFunction => 12; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 51 |  | 
| 31 | 1 |  |  | 1 |  | 6 | use constant SymbolKindVariable => 13; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 55 |  | 
| 32 | 1 |  |  | 1 |  | 38 | use constant SymbolKindConstant => 14; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 47 |  | 
| 33 | 1 |  |  | 1 |  | 6 | use constant SymbolKindString => 15; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 73 |  | 
| 34 | 1 |  |  | 1 |  | 8 | use constant SymbolKindNumber => 16; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 58 |  | 
| 35 | 1 |  |  | 1 |  | 7 | use constant SymbolKindBoolean => 17; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 68 |  | 
| 36 | 1 |  |  | 1 |  | 7 | use constant SymbolKindArray => 18; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 43 |  | 
| 37 | 1 |  |  | 1 |  | 5 | use constant SymbolKindObject => 19; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 50 |  | 
| 38 | 1 |  |  | 1 |  | 11 | use constant SymbolKindKey => 20; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 65 |  | 
| 39 | 1 |  |  | 1 |  | 7 | use constant SymbolKindNull => 21; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 42 |  | 
| 40 | 1 |  |  | 1 |  | 5 | use constant SymbolKindEnumMember => 22; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 61 |  | 
| 41 | 1 |  |  | 1 |  | 6 | use constant SymbolKindStruct => 23; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 41 |  | 
| 42 | 1 |  |  | 1 |  | 5 | use constant SymbolKindEvent => 24; | 
|  | 1 |  |  |  |  | 13 |  | 
|  | 1 |  |  |  |  | 52 |  | 
| 43 | 1 |  |  | 1 |  | 6 | use constant SymbolKindOperator => 25; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 51 |  | 
| 44 | 1 |  |  | 1 |  | 7 | use constant SymbolKindTypeParameter => 26; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 42 |  | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 1 |  |  | 1 |  | 5 | use constant CacheVersion => 5 ; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 4482 |  | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # --------------------------------------------------------------------------- | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | sub _get_docu | 
| 52 |  |  |  |  |  |  | { | 
| 53 | 0 |  |  | 0 |  |  | my ($self, $source, $line) = @_ ; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 0 |  |  |  |  |  | my @docu ; | 
| 56 |  |  |  |  |  |  | my $in_pod ; | 
| 57 | 0 |  |  |  |  |  | while ($line-- >= 0) | 
| 58 |  |  |  |  |  |  | { | 
| 59 | 0 |  |  |  |  |  | my $src = $source -> [$line] ; | 
| 60 | 0 | 0 |  |  |  |  | if ($src =~ /^=cut/) | 
| 61 |  |  |  |  |  |  | { | 
| 62 | 0 |  |  |  |  |  | $in_pod = 1 ; | 
| 63 | 0 |  |  |  |  |  | next ; | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 0 | 0 |  |  |  |  | if ($in_pod) | 
| 67 |  |  |  |  |  |  | { | 
| 68 | 0 | 0 |  |  |  |  | last if ($src =~ /^=pod/) ; | 
| 69 | 0 | 0 |  |  |  |  | next if ($src =~ /^=\w+\s*$/) ; | 
| 70 | 0 |  |  |  |  |  | $src =~ s/^=item /* / ; | 
| 71 | 0 |  |  |  |  |  | unshift @docu, $src ; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | else | 
| 74 |  |  |  |  |  |  | { | 
| 75 | 0 | 0 |  |  |  |  | next if ($src =~ /^\s*$/) ; | 
| 76 | 0 | 0 |  |  |  |  | next if ($src =~ /^\s*#[-#+~= \t]+$/) ; | 
| 77 | 0 | 0 |  |  |  |  | last if ($src !~ /^\s*#(.*?)\s*$/) ; | 
| 78 | 0 |  |  |  |  |  | unshift @docu, $1 ; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 0 |  | 0 |  |  |  | shift @docu while (@docu && ($docu[0] =~ /^\s*$/)) ; | 
| 83 | 0 |  | 0 |  |  |  | pop   @docu while (@docu && ($docu[-1] =~ /^\s*$/)) ; | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | return join ("\n", @docu) ; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | # --------------------------------------------------------------------------- | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | sub parse_perl_source | 
| 93 |  |  |  |  |  |  | { | 
| 94 | 0 |  |  | 0 | 0 |  | my ($self, $uri, $source, $server) = @_ ; | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 0 |  |  |  |  |  | $source =~ s/\r//g ; #  Compiler::Lexer computes wrong line numbers with \r | 
| 97 | 0 |  |  |  |  |  | my @source = split /\n/, $source ; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  |  |  |  | my $lexer  = Compiler::Lexer->new(); | 
| 100 | 0 |  |  |  |  |  | my $tokens = $lexer->tokenize($source); | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 0 |  |  |  |  |  | cede () ; | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | #$server -> logger (dump ($tokens) . "\n") ; | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | #my $modules = $lexer->get_used_modules($script); | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 0 |  |  |  |  |  | my @vars ; | 
| 109 | 0 |  |  |  |  |  | my $package = 'main::' ; | 
| 110 | 0 |  |  |  |  |  | my %state ; | 
| 111 |  |  |  |  |  |  | my $decl ; | 
| 112 | 0 |  |  |  |  |  | my $declline ; | 
| 113 | 0 |  |  |  |  |  | my $func ; | 
| 114 | 0 |  |  |  |  |  | my $parent ; | 
| 115 | 0 |  |  |  |  |  | my $top ; | 
| 116 | 0 |  |  |  |  |  | my $add ; | 
| 117 | 0 |  |  |  |  |  | my $func_param ; | 
| 118 | 0 |  |  |  |  |  | my $token_ndx = -1 ; | 
| 119 | 0 |  |  |  |  |  | my $brace_level = 0 ; | 
| 120 | 0 |  |  |  |  |  | my @stack ; | 
| 121 | 0 |  |  |  |  |  | my $beginchar = 0 ; | 
| 122 | 0 |  |  |  |  |  | my $endchar = 0 ; | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 0 |  |  |  |  |  | foreach my $token (@$tokens) | 
| 125 |  |  |  |  |  |  | { | 
| 126 | 0 |  |  |  |  |  | $token_ndx++ ; | 
| 127 | 0 |  |  |  |  |  | $token -> {data} =~ s/\r$// ; | 
| 128 | 0 | 0 |  |  |  |  | $server -> logger ("token=", dump ($token), "\n") if ($Perl::LanguageServer::debug3) ; | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 0 | 0 | 0 |  |  |  | if (exists $state{method_mod} && $token -> {name} eq 'RawString') | 
| 131 |  |  |  |  |  |  | { | 
| 132 | 0 |  |  |  |  |  | $token -> {name} = 'Function' ; | 
| 133 | 0 |  |  |  |  |  | delete $state{method_mod} ; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 | 0 |  |  |  |  |  | given ($token -> {name}) | 
| 137 |  |  |  |  |  |  | { | 
| 138 |  |  |  |  |  |  | when (['VarDecl', 'OurDecl', 'FunctionDecl']) | 
| 139 | 0 |  |  |  |  |  | { | 
| 140 |  |  |  |  |  |  | $decl = $token -> {data}, | 
| 141 | 0 |  |  |  |  |  | $declline = $token -> {line} ; | 
| 142 |  |  |  |  |  |  | } | 
| 143 |  |  |  |  |  |  | when (/Var$/) | 
| 144 | 0 |  |  |  |  |  | { | 
| 145 | 0 | 0 | 0 |  |  |  | $top = $decl eq 'our' || !$parent?\@vars:$parent ; | 
| 146 |  |  |  |  |  |  | push @$top, | 
| 147 |  |  |  |  |  |  | { | 
| 148 |  |  |  |  |  |  | name        => $token -> {data}, | 
| 149 | 0 | 0 |  |  |  |  | kind        => SymbolKindVariable, | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | containerName => $decl eq 'our'?$package:$func, | 
| 151 |  |  |  |  |  |  | ($decl?(definition   => $decl):()), | 
| 152 |  |  |  |  |  |  | ($decl eq 'my'?(localvar => $decl):()), | 
| 153 |  |  |  |  |  |  | } ; | 
| 154 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 155 | 0 | 0 |  |  |  |  | $token -> {line} = $declline if ($decl) ; | 
| 156 | 0 |  |  |  |  |  | $decl = undef ; | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  | when ('LeftBrace') | 
| 159 | 0 |  |  |  |  |  | { | 
| 160 | 0 |  |  |  |  |  | $brace_level++ ; | 
| 161 | 0 |  |  |  |  |  | $decl = undef ; | 
| 162 | 0 | 0 | 0 |  |  |  | if (@vars && $vars[-1]{kind} == SymbolKindVariable) | 
| 163 |  |  |  |  |  |  | { | 
| 164 | 0 |  |  |  |  |  | $vars[-1]{name} =~ s/^\$/%/ ; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  | when (['RightBrace', 'SemiColon']) | 
| 168 | 0 |  |  |  |  |  | { | 
| 169 | 0 | 0 |  |  |  |  | $brace_level-- if ($token -> {name} eq 'RightBrace') ; | 
| 170 | 0 | 0 | 0 |  |  |  | if (@stack > 0 && $brace_level == $stack[-1]{brace_level}) | 
| 171 |  |  |  |  |  |  | { | 
| 172 | 0 |  |  |  |  |  | my $stacktop = pop @stack ; | 
| 173 | 0 |  |  |  |  |  | $parent = $stacktop -> {parent} ; | 
| 174 | 0 |  |  |  |  |  | $func   = $stacktop -> {func} ; | 
| 175 | 0 |  |  |  |  |  | my $symbol = $stacktop -> {symbol} ; | 
| 176 | 0 |  | 0 |  |  |  | my $start_line = $symbol -> {range}{start}{line} // $symbol -> {line} ; | 
| 177 | 0 | 0 |  |  |  |  | $symbol ->  {range} = { start => { line => $start_line, character => 0 }, end => { line => $token -> {line}-1, character => 9999 }} | 
| 178 |  |  |  |  |  |  | if (defined ($start_line)) ; | 
| 179 |  |  |  |  |  |  | } | 
| 180 | 0 | 0 |  |  |  |  | if ($token -> {name} eq 'SemiColon') | 
| 181 |  |  |  |  |  |  | { | 
| 182 | 0 |  |  |  |  |  | $decl = undef ; | 
| 183 | 0 |  |  |  |  |  | continue ; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | when ('LeftBracket') | 
| 187 | 0 |  |  |  |  |  | { | 
| 188 | 0 | 0 | 0 |  |  |  | if (@vars && $vars[-1]{kind} == SymbolKindVariable) | 
| 189 |  |  |  |  |  |  | { | 
| 190 | 0 |  |  |  |  |  | $vars[-1]{name} =~ s/^\$/@/ ; | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  | when (['Function', 'Method']) | 
| 194 | 0 |  |  |  |  |  | { | 
| 195 | 0 | 0 |  |  |  |  | if ($token -> {data} =~ /^\w/) | 
| 196 |  |  |  |  |  |  | { | 
| 197 | 0 | 0 |  |  |  |  | $top = !$parent?\@vars:$parent ; | 
| 198 |  |  |  |  |  |  | push @$top, | 
| 199 |  |  |  |  |  |  | { | 
| 200 |  |  |  |  |  |  | name        => $token -> {data}, | 
| 201 | 0 | 0 |  |  |  |  | kind        => SymbolKindFunction, | 
|  |  | 0 |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | containerName => @stack?$func:$package, | 
| 203 |  |  |  |  |  |  | ($decl?(definition   => $decl):()), | 
| 204 |  |  |  |  |  |  | }  ; | 
| 205 | 0 |  |  |  |  |  | $func_param = $add = $top -> [-1] ; | 
| 206 | 0 | 0 |  |  |  |  | if ($decl) | 
| 207 |  |  |  |  |  |  | { | 
| 208 | 0 |  |  |  |  |  | push @stack, | 
| 209 |  |  |  |  |  |  | { | 
| 210 |  |  |  |  |  |  | brace_level => $brace_level, | 
| 211 |  |  |  |  |  |  | parent      => $parent, | 
| 212 |  |  |  |  |  |  | func        => $func, | 
| 213 |  |  |  |  |  |  | 'package'   => $package, | 
| 214 |  |  |  |  |  |  | symbol      => $add, | 
| 215 |  |  |  |  |  |  | } ; | 
| 216 | 0 |  |  |  |  |  | $token -> {line} = $declline ; | 
| 217 | 0 |  |  |  |  |  | $func = $token -> {data} ; | 
| 218 | 0 |  | 0 |  |  |  | $parent = $top -> [-1]{children} ||= [] ; | 
| 219 |  |  |  |  |  |  | } | 
| 220 | 0 |  |  |  |  |  | my $src = $source[$token -> {line}-1] ; | 
| 221 | 0 |  |  |  |  |  | my $i ; | 
| 222 | 0 | 0 | 0 |  |  |  | if ($src && ($i = index($src, $func) >= 0)) | 
| 223 |  |  |  |  |  |  | { | 
| 224 | 0 |  |  |  |  |  | $beginchar = $i + 1 ; | 
| 225 | 0 |  |  |  |  |  | $endchar   = $i + 1 + length ($func) ; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  | } | 
| 228 | 0 |  |  |  |  |  | $decl = undef ; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  | when ('ArgumentArray') | 
| 231 | 0 |  |  |  |  |  | { | 
| 232 | 0 | 0 |  |  |  |  | if ($func_param) | 
| 233 |  |  |  |  |  |  | { | 
| 234 | 0 |  |  |  |  |  | my @params ; | 
| 235 | 0 | 0 | 0 |  |  |  | if ($tokens -> [$token_ndx - 1]{name} eq 'Assign' && | 
| 236 |  |  |  |  |  |  | $tokens -> [$token_ndx - 2]{name} eq 'RightParenthesis') | 
| 237 |  |  |  |  |  |  | { | 
| 238 | 0 |  |  |  |  |  | for (my $i = $token_ndx - 3; $i >= 0; $i--) | 
| 239 |  |  |  |  |  |  | { | 
| 240 | 0 | 0 |  |  |  |  | next if ($tokens -> [$i]{name} eq 'Comma') ; | 
| 241 | 0 | 0 |  |  |  |  | last if ($tokens -> [$i]{name} !~ /Var$/) ; | 
| 242 | 0 |  |  |  |  |  | push @params, $tokens -> [$i]{data} ; | 
| 243 |  |  |  |  |  |  | } | 
| 244 | 0 |  | 0 |  |  |  | my $func_doc = $self -> _get_docu (\@source, $func_param -> {range}{start}{line} // $func_param -> {line}) ; | 
| 245 | 0 |  |  |  |  |  | my @parameters ; | 
| 246 | 0 |  |  |  |  |  | foreach my $p (reverse @params) | 
| 247 |  |  |  |  |  |  | { | 
| 248 | 0 |  |  |  |  |  | push @parameters, | 
| 249 |  |  |  |  |  |  | { | 
| 250 |  |  |  |  |  |  | label => $p, | 
| 251 |  |  |  |  |  |  | } ; | 
| 252 |  |  |  |  |  |  | } | 
| 253 | 0 |  |  |  |  |  | $func_param -> {detail} = '(' . join (',', reverse @params) . ')' ; | 
| 254 |  |  |  |  |  |  | $func_param -> {signature} = | 
| 255 |  |  |  |  |  |  | { | 
| 256 |  |  |  |  |  |  | label => $func_param -> {name} . $func_param -> {detail}, | 
| 257 | 0 |  |  |  |  |  | documentation => $func_doc, | 
| 258 |  |  |  |  |  |  | parameters => \@parameters | 
| 259 |  |  |  |  |  |  | } ; | 
| 260 |  |  |  |  |  |  | } | 
| 261 | 0 |  |  |  |  |  | $func_param = undef ; | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  | } | 
| 264 |  |  |  |  |  |  | when ('Prototype') | 
| 265 | 0 |  |  |  |  |  | { | 
| 266 | 0 | 0 |  |  |  |  | if ($func_param) | 
| 267 |  |  |  |  |  |  | { | 
| 268 | 0 |  |  |  |  |  | my @params = split /\s*,\s*/, $token -> {data} ; | 
| 269 | 0 |  | 0 |  |  |  | my $func_doc = $self -> _get_docu (\@source, $func_param -> {range}{start}{line} // $func_param -> {line}) ; | 
| 270 | 0 |  |  |  |  |  | my @parameters ; | 
| 271 | 0 |  |  |  |  |  | foreach my $p (@params) | 
| 272 |  |  |  |  |  |  | { | 
| 273 | 0 |  |  |  |  |  | push @parameters, | 
| 274 |  |  |  |  |  |  | { | 
| 275 |  |  |  |  |  |  | label => $p, | 
| 276 |  |  |  |  |  |  | } ; | 
| 277 |  |  |  |  |  |  | } | 
| 278 | 0 |  |  |  |  |  | $func_param -> {detail} = '(' . join (',', @params) . ')' ; | 
| 279 |  |  |  |  |  |  | $func_param -> {signature} = | 
| 280 |  |  |  |  |  |  | { | 
| 281 |  |  |  |  |  |  | label => $func_param -> {name} . $func_param -> {detail}, | 
| 282 | 0 |  |  |  |  |  | documentation => $func_doc, | 
| 283 |  |  |  |  |  |  | parameters => \@parameters | 
| 284 |  |  |  |  |  |  | } ; | 
| 285 | 0 |  |  |  |  |  | $func_param = undef ; | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  | when (['Package', 'UseDecl'] ) | 
| 289 | 0 |  |  |  |  |  | { | 
| 290 | 0 |  |  |  |  |  | $state{is} = $token -> {data} ; | 
| 291 | 0 |  |  |  |  |  | $state{module} = 1 ; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  | when (['ShortHashDereference', 'ShortArrayDereference']) | 
| 294 | 0 |  |  |  |  |  | { | 
| 295 | 0 |  |  |  |  |  | $state{scalar} = '$' ; | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  | when ('Key') | 
| 298 | 0 |  |  |  |  |  | { | 
| 299 | 0 | 0 |  |  |  |  | if (exists ($state{constant})) | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | { | 
| 301 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 302 |  |  |  |  |  |  | push @$top, | 
| 303 |  |  |  |  |  |  | { | 
| 304 |  |  |  |  |  |  | name        => $token -> {data}, | 
| 305 | 0 |  |  |  |  |  | kind        => SymbolKindConstant, | 
| 306 |  |  |  |  |  |  | containerName => $package, | 
| 307 |  |  |  |  |  |  | definition   => 1, | 
| 308 |  |  |  |  |  |  | } ; | 
| 309 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  | elsif (exists ($state{scalar})) | 
| 312 |  |  |  |  |  |  | { | 
| 313 | 0 | 0 | 0 |  |  |  | $top = $decl eq 'our' || !$parent?\@vars:$parent ; | 
| 314 |  |  |  |  |  |  | push @$top, | 
| 315 |  |  |  |  |  |  | { | 
| 316 |  |  |  |  |  |  | name        => $state{scalar} . $token -> {data}, | 
| 317 | 0 | 0 |  |  |  |  | kind        => SymbolKindVariable, | 
| 318 |  |  |  |  |  |  | containerName => $decl eq 'our'?$package:$func, | 
| 319 |  |  |  |  |  |  | } ; | 
| 320 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  | elsif ($token -> {data} ~~ ['has', 'class_has']) | 
| 323 |  |  |  |  |  |  | { | 
| 324 | 0 |  |  |  |  |  | $state{has} = 1 ; | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  | elsif ($token -> {data} ~~ ['around', 'before', 'after']) | 
| 327 |  |  |  |  |  |  | { | 
| 328 | 0 |  |  |  |  |  | $state{method_mod} = 1 ; | 
| 329 |  |  |  |  |  |  | $decl = $token -> {data}, | 
| 330 | 0 |  |  |  |  |  | $declline = $token -> {line} ; | 
| 331 |  |  |  |  |  |  | } | 
| 332 |  |  |  |  |  |  | elsif ($token -> {data} =~ /^[a-z_][a-z0-9_]+$/i) | 
| 333 |  |  |  |  |  |  | { | 
| 334 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 335 |  |  |  |  |  |  | push @$top, | 
| 336 |  |  |  |  |  |  | { | 
| 337 |  |  |  |  |  |  | name        => $token -> {data}, | 
| 338 | 0 |  |  |  |  |  | kind        => SymbolKindFunction, | 
| 339 |  |  |  |  |  |  | }  ; | 
| 340 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  | when ('RawString') | 
| 344 | 0 |  |  |  |  |  | { | 
| 345 | 0 | 0 |  |  |  |  | if (exists ($state{has})) | 
| 346 |  |  |  |  |  |  | { | 
| 347 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 348 |  |  |  |  |  |  | push @$top, | 
| 349 |  |  |  |  |  |  | { | 
| 350 |  |  |  |  |  |  | name        => $token -> {data}, | 
| 351 | 0 |  |  |  |  |  | kind        => SymbolKindProperty, | 
| 352 |  |  |  |  |  |  | containerName => $package, | 
| 353 |  |  |  |  |  |  | definition   => 1, | 
| 354 |  |  |  |  |  |  | } ; | 
| 355 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | when ('UsedName') | 
| 359 | 0 |  |  |  |  |  | { | 
| 360 | 0 | 0 |  |  |  |  | if ($token -> {data} eq 'constant') | 
| 361 |  |  |  |  |  |  | { | 
| 362 | 0 |  |  |  |  |  | delete $state{module} ; | 
| 363 | 0 |  |  |  |  |  | $state{constant} = 1 ; | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  | else | 
| 366 |  |  |  |  |  |  | { | 
| 367 | 0 |  |  |  |  |  | $state{ns} = [$token->{data}] ; | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  | when ('Namespace') | 
| 371 | 0 |  |  |  |  |  | { | 
| 372 | 0 |  | 0 |  |  |  | $state{ns} ||= [] ; | 
| 373 | 0 |  |  |  |  |  | push @{$state{ns}}, $token -> {data} ; | 
|  | 0 |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | when ('NamespaceResolver') | 
| 376 | 0 |  |  |  |  |  | { | 
| 377 |  |  |  |  |  |  | # make sure it is not matched below | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  | when ('Assign') | 
| 380 | 0 |  |  |  |  |  | { | 
| 381 | 0 |  |  |  |  |  | $decl = undef ; | 
| 382 | 0 |  |  |  |  |  | continue ; | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  | when ($token -> {data} =~ /^\W/) | 
| 385 | 0 |  |  |  |  |  | { | 
| 386 | 0 | 0 |  |  |  |  | if (exists ($state{ns})) | 
| 387 |  |  |  |  |  |  | { | 
| 388 | 0 | 0 |  |  |  |  | if ($state{module}) | 
| 389 |  |  |  |  |  |  | { | 
| 390 | 0 |  |  |  |  |  | my $def ; | 
| 391 | 0 | 0 |  |  |  |  | if ($state{is} eq 'package') | 
| 392 |  |  |  |  |  |  | { | 
| 393 | 0 |  |  |  |  |  | $def = 1 ; | 
| 394 | 0 |  |  |  |  |  | $package = join ('::', @{$state{ns}}) ; | 
|  | 0 |  |  |  |  |  |  | 
| 395 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 396 | 0 |  |  |  |  |  | push @$top, | 
| 397 |  |  |  |  |  |  | { | 
| 398 |  |  |  |  |  |  | name        => $package, | 
| 399 |  |  |  |  |  |  | kind        => SymbolKindModule, | 
| 400 |  |  |  |  |  |  | #containerName => join ('::', @{$state{ns}}), | 
| 401 |  |  |  |  |  |  | #($def?(definition   => $def):()), | 
| 402 |  |  |  |  |  |  | definition => 1, | 
| 403 |  |  |  |  |  |  | } ; | 
| 404 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  | else | 
| 407 |  |  |  |  |  |  | { | 
| 408 | 0 |  |  |  |  |  | my $name = pop @{$state{ns}} ; | 
|  | 0 |  |  |  |  |  |  | 
| 409 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 410 |  |  |  |  |  |  | push @$top, | 
| 411 |  |  |  |  |  |  | { | 
| 412 |  |  |  |  |  |  | name        => $name, | 
| 413 |  |  |  |  |  |  | kind        => SymbolKindModule, | 
| 414 | 0 | 0 |  |  |  |  | containerName => join ('::', @{$state{ns}}), | 
|  | 0 |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | ($def?(definition   => $def):()), | 
| 416 |  |  |  |  |  |  | } ; | 
| 417 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 418 |  |  |  |  |  |  | } | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  | else | 
| 421 |  |  |  |  |  |  | { | 
| 422 | 0 |  |  |  |  |  | my $name = shift @{$state{ns}} ; | 
|  | 0 |  |  |  |  |  |  | 
| 423 | 0 |  |  |  |  |  | $top = \@vars ; | 
| 424 |  |  |  |  |  |  | push @$top, | 
| 425 |  |  |  |  |  |  | { | 
| 426 |  |  |  |  |  |  | name        => $name, | 
| 427 |  |  |  |  |  |  | kind        => SymbolKindFunction, | 
| 428 | 0 |  |  |  |  |  | containerName => join ('::', @{$state{ns}}), | 
|  | 0 |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | } ; | 
| 430 | 0 |  |  |  |  |  | $add = $top -> [-1] ; | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  |  | 
| 434 | 0 |  |  |  |  |  | %state = () ; | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  | } | 
| 437 | 0 | 0 |  |  |  |  | if ($add) | 
| 438 |  |  |  |  |  |  | { | 
| 439 | 0 | 0 |  |  |  |  | if (!$uri) | 
| 440 |  |  |  |  |  |  | { | 
| 441 | 0 |  |  |  |  |  | $add ->  {line} = $token -> {line}-1 ; | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  | else | 
| 444 |  |  |  |  |  |  | { | 
| 445 |  |  |  |  |  |  | #$add ->  {location} = { uri => $uri, range => { start => { line => $token -> {line}-1, character => 0 }, end => { line => $token -> {line}-1, character => 0 }}} ; | 
| 446 |  |  |  |  |  |  | $add ->  {range} =         { start => { line => $token -> {line}-1, character => 0 }, | 
| 447 | 0 | 0 |  |  |  |  | end   => { line => $token -> {line}-1, character => ($endchar?9999:0) }} ; | 
| 448 |  |  |  |  |  |  | $add -> {selectionRange} = { start => { line => $token -> {line}-1, character => $beginchar }, | 
| 449 | 0 |  |  |  |  |  | end   => { line => $token -> {line}-1, character => $endchar }} ; | 
| 450 | 0 |  |  |  |  |  | $beginchar = $endchar = 0 ; | 
| 451 |  |  |  |  |  |  | } | 
| 452 | 0 | 0 |  |  |  |  | $server -> logger ("var=", dump ($add), "\n") if ($Perl::LanguageServer::debug3) ; | 
| 453 | 0 |  |  |  |  |  | $add = undef ; | 
| 454 |  |  |  |  |  |  | } | 
| 455 |  |  |  |  |  |  | } | 
| 456 |  |  |  |  |  |  |  | 
| 457 | 0 | 0 |  |  |  |  | $server -> logger (dump (\@vars), "\n") if ($Perl::LanguageServer::debug3) ; | 
| 458 |  |  |  |  |  |  |  | 
| 459 | 0 | 0 |  |  |  |  | return wantarray?(\@vars, $tokens):\@vars ; | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | # ---------------------------------------------------------------------------- | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | sub _parse_perl_source_cached | 
| 466 |  |  |  |  |  |  | { | 
| 467 | 0 |  |  | 0 |  |  | my ($self, $uri, $source, $path, $stats, $server) = @_ ; | 
| 468 |  |  |  |  |  |  |  | 
| 469 | 0 |  |  |  |  |  | my $cachepath ; | 
| 470 | 0 | 0 |  |  |  |  | if (!$self -> disable_cache) | 
| 471 |  |  |  |  |  |  | { | 
| 472 | 0 |  |  |  |  |  | my $escpath = $path ; | 
| 473 | 0 |  |  |  |  |  | $escpath =~ s/:/%3A/ ; | 
| 474 | 0 |  |  |  |  |  | $cachepath = $self -> state_dir .'/' . $escpath ; | 
| 475 | 0 |  |  |  |  |  | $self -> mkpath (dirname ($cachepath)) ; | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | #$server -> logger ("$path -> cachepath=$cachepath\n") ; | 
| 478 | 0 |  |  |  |  |  | aio_stat ($cachepath) ; | 
| 479 | 0 | 0 |  |  |  |  | if (-e _) | 
| 480 |  |  |  |  |  |  | { | 
| 481 | 0 |  |  |  |  |  | my $mtime_cache = -M _ ; | 
| 482 | 0 |  |  |  |  |  | aio_stat ($path) ; | 
| 483 | 0 |  |  |  |  |  | my $mtime_src = -M _ ; | 
| 484 |  |  |  |  |  |  | #$server -> logger ("cache = $mtime_cache src = $mtime_src\n") ; | 
| 485 | 0 | 0 |  |  |  |  | if ($mtime_src > $mtime_cache) | 
| 486 |  |  |  |  |  |  | { | 
| 487 |  |  |  |  |  |  | #$server -> logger ("load from cache\n") ; | 
| 488 | 0 |  |  |  |  |  | my $cache ; | 
| 489 | 0 |  |  |  |  |  | aio_load ($cachepath, $cache) ; | 
| 490 | 0 |  |  |  |  |  | my $cache_data = eval { $Perl::LanguageServer::json -> decode ($cache) ; } ; | 
|  | 0 |  |  |  |  |  |  | 
| 491 | 0 | 0 |  |  |  |  | if ($@) | 
|  |  | 0 |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | { | 
| 493 | 0 |  |  |  |  |  | $self -> logger ("Loading of $cachepath failed, reparse file ($@)\n") ; | 
| 494 |  |  |  |  |  |  | } | 
| 495 |  |  |  |  |  |  | elsif (ref ($cache_data) eq 'HASH') | 
| 496 |  |  |  |  |  |  | { | 
| 497 | 0 | 0 |  |  |  |  | if ($cache_data -> {version} == CacheVersion) | 
| 498 |  |  |  |  |  |  | { | 
| 499 | 0 |  |  |  |  |  | $stats -> {loaded}++ ; | 
| 500 | 0 |  |  |  |  |  | return $cache_data -> {vars} ; | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  | } | 
| 503 |  |  |  |  |  |  | } | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  | } | 
| 506 |  |  |  |  |  |  |  | 
| 507 | 0 |  |  |  |  |  | my $vars = $self -> parse_perl_source ($uri, $source, $server) ; | 
| 508 |  |  |  |  |  |  |  | 
| 509 | 0 | 0 |  |  |  |  | if ($cachepath) | 
| 510 |  |  |  |  |  |  | { | 
| 511 | 0 | 0 |  |  |  |  | my $ifh = aio_open ($cachepath, IO::AIO::O_WRONLY | IO::AIO::O_TRUNC | IO::AIO::O_CREAT, 0664) or die "open $cachepath failed ($!)" ; | 
| 512 | 0 |  |  |  |  |  | aio_write ($ifh, undef, undef, $Perl::LanguageServer::json -> encode ({ version => CacheVersion, vars => $vars}), 0) ; | 
| 513 | 0 |  |  |  |  |  | aio_close ($ifh) ; | 
| 514 |  |  |  |  |  |  | } | 
| 515 |  |  |  |  |  |  |  | 
| 516 | 0 |  |  |  |  |  | $stats -> {parsed}++ ; | 
| 517 |  |  |  |  |  |  |  | 
| 518 | 0 |  |  |  |  |  | return $vars ; | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | # ---------------------------------------------------------------------------- | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  | sub _parse_dir | 
| 526 |  |  |  |  |  |  | { | 
| 527 | 0 |  |  | 0 |  |  | my ($self, $server, $dir, $vars, $stats) = @_ ; | 
| 528 |  |  |  |  |  |  |  | 
| 529 | 0 |  |  |  |  |  | my $text ; | 
| 530 |  |  |  |  |  |  | my $fn ; | 
| 531 | 0 |  |  |  |  |  | my $uri ; | 
| 532 | 0 |  |  |  |  |  | my $file_vars ; | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 0 |  |  |  |  |  | my $filefilter = $self -> file_filter_regex ; | 
| 535 | 0 |  |  |  |  |  | my $ignore_dir = $self -> ignore_dir ; | 
| 536 |  |  |  |  |  |  |  | 
| 537 | 0 |  |  |  |  |  | my ($dirs, $files) = aio_scandir ($dir, 4) ; | 
| 538 |  |  |  |  |  |  |  | 
| 539 | 0 | 0 |  |  |  |  | if ($dirs) | 
| 540 |  |  |  |  |  |  | { | 
| 541 | 0 |  |  |  |  |  | foreach my $d (sort @$dirs) | 
| 542 |  |  |  |  |  |  | { | 
| 543 | 0 | 0 |  |  |  |  | next if (exists $ignore_dir -> {$d}) ; | 
| 544 | 0 |  |  |  |  |  | $self -> _parse_dir ($server, $dir . '/' . $d, $vars, $stats) ; | 
| 545 |  |  |  |  |  |  | } | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 0 | 0 |  |  |  |  | if ($files) | 
| 549 |  |  |  |  |  |  | { | 
| 550 | 0 |  |  |  |  |  | foreach my $f (sort @$files) | 
| 551 |  |  |  |  |  |  | { | 
| 552 | 0 | 0 |  |  |  |  | next if ($f !~ /$filefilter/) ; | 
| 553 |  |  |  |  |  |  |  | 
| 554 | 0 |  |  |  |  |  | $fn = $dir . '/' . $f ; | 
| 555 | 0 |  |  |  |  |  | aio_load ($fn, $text) ; | 
| 556 |  |  |  |  |  |  |  | 
| 557 | 0 |  |  |  |  |  | $uri = $self -> uri_server2client ('file://' . $fn) ; | 
| 558 |  |  |  |  |  |  | #$server -> logger ("parse $fn -> $uri\n") ; | 
| 559 | 0 |  |  |  |  |  | $file_vars = $self -> _parse_perl_source_cached (undef, $text, $fn, $stats, $server) ; | 
| 560 | 0 |  |  |  |  |  | $vars -> {$uri} =  $file_vars ; | 
| 561 |  |  |  |  |  |  | #$server -> logger ("done $fn\n") ; | 
| 562 | 0 |  |  |  |  |  | my $cnt = keys %$vars ; | 
| 563 | 0 | 0 |  |  |  |  | $server -> logger ("loaded $stats->{loaded} files, parsed $stats->{parsed} files, $cnt files\n") if ($cnt % 100 == 0) ; | 
| 564 |  |  |  |  |  |  | } | 
| 565 |  |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | } | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | # ---------------------------------------------------------------------------- | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | sub background_parser | 
| 573 |  |  |  |  |  |  | { | 
| 574 | 0 |  |  | 0 | 0 |  | my ($self, $server) = @_ ; | 
| 575 |  |  |  |  |  |  |  | 
| 576 | 0 |  |  |  |  |  | my $channel = $self -> parser_channel ; | 
| 577 | 0 |  |  |  |  |  | $channel -> shutdown ; # end other parser | 
| 578 | 0 |  |  |  |  |  | cede ; | 
| 579 |  |  |  |  |  |  |  | 
| 580 | 0 |  |  |  |  |  | $channel = $self -> parser_channel (Coro::Channel -> new) ; | 
| 581 | 0 |  |  |  |  |  | my $folders = $self -> folders ; | 
| 582 | 0 |  |  |  |  |  | $server -> logger ("background_parser folders = ", dump ($folders), "\n") ; | 
| 583 | 0 |  |  |  |  |  | %{$self -> symbols} = () ; | 
|  | 0 |  |  |  |  |  |  | 
| 584 |  |  |  |  |  |  |  | 
| 585 | 0 |  |  |  |  |  | my $stats = {} ; | 
| 586 | 0 |  |  |  |  |  | foreach my $dir (values %$folders) | 
| 587 |  |  |  |  |  |  | { | 
| 588 | 0 |  |  |  |  |  | $self -> _parse_dir ($server, $dir, $self -> symbols, $stats) ; | 
| 589 | 0 |  |  |  |  |  | cede ; | 
| 590 |  |  |  |  |  |  | } | 
| 591 |  |  |  |  |  |  |  | 
| 592 | 0 |  |  |  |  |  | my $cnt = keys %{$self -> symbols} ; | 
|  | 0 |  |  |  |  |  |  | 
| 593 | 0 |  |  |  |  |  | $server -> logger ("initial parsing done, loaded $stats->{loaded} files, parsed $stats->{parsed} files, $cnt files\n") ; | 
| 594 |  |  |  |  |  |  |  | 
| 595 | 0 |  |  |  |  |  | my $filefilter = $self -> file_filter_regex ; | 
| 596 |  |  |  |  |  |  |  | 
| 597 | 0 |  |  |  |  |  | while (my $item = $channel -> get) | 
| 598 |  |  |  |  |  |  | { | 
| 599 | 0 |  |  |  |  |  | my ($cmd, $uri) = @$item ; | 
| 600 |  |  |  |  |  |  |  | 
| 601 | 0 |  |  |  |  |  | my $fn = substr ($self -> uri_client2server ($uri), 7) ; | 
| 602 | 0 | 0 |  |  |  |  | next if (basename ($fn) !~ /$filefilter/) ; | 
| 603 |  |  |  |  |  |  |  | 
| 604 | 0 |  |  |  |  |  | my $text ; | 
| 605 | 0 |  |  |  |  |  | aio_load ($fn, $text) ; | 
| 606 |  |  |  |  |  |  |  | 
| 607 | 0 |  |  |  |  |  | $server -> logger ("parse $fn -> $uri\n") ; | 
| 608 | 0 |  |  |  |  |  | my $file_vars = $self -> _parse_perl_source_cached (undef, $text, $fn, {}, $server) ; | 
| 609 | 0 |  |  |  |  |  | $self -> symbols -> {$uri} =  $file_vars ; | 
| 610 |  |  |  |  |  |  | } | 
| 611 |  |  |  |  |  |  |  | 
| 612 | 0 |  |  |  |  |  | $server -> logger ("background_parser quit\n") ; | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | 1 ; | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  |  |