bixbite 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.markdown +49 -0
- data/VERSION +1 -0
- data/bin/bixbite +73 -0
- data/lib/bixbite.rb +13 -0
- data/lib/bixbite/command.rb +14 -0
- data/lib/bixbite/create.rb +76 -0
- data/template/Rakefile +25 -0
- data/template/assets/bixbite/Rakefile.rb +297 -0
- data/template/assets/naturaldocs/NaturalDocs/Config/Languages.txt +286 -0
- data/template/assets/naturaldocs/NaturalDocs/Config/Topics.txt +382 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/customizinglanguages.html +52 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/customizingtopics.html +74 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/documenting.html +58 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/documenting/reference.html +146 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/documenting/walkthrough.html +180 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/example/Default.css +528 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/example/NaturalDocs.js +204 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/examples.css +90 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/background.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/leftside.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/logo.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbody.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbodybg.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overleftmargin.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenu.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenubg.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/header/rightside.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/logo.gif +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/about.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/background.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomleft.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomright.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/community.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/customizing.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/using.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/index.html +9 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/javascript/BrowserStyles.js +77 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/javascript/PNGHandling.js +72 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/keywords.html +38 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/languages.html +32 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/menu.html +79 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/output.html +84 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/running.html +40 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/styles.css +290 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/styles.html +52 -0
- data/template/assets/naturaldocs/NaturalDocs/Help/troubleshooting.html +18 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/CSSGuide.txt +947 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/File Parsing.txt +83 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/HTMLTestCases.pm +269 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/Languages.txt +107 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/NDMarkup.txt +91 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/Symbol Management.txt +59 -0
- data/template/assets/naturaldocs/NaturalDocs/Info/images/Logo.png +0 -0
- data/template/assets/naturaldocs/NaturalDocs/JavaScript/NaturalDocs.js +836 -0
- data/template/assets/naturaldocs/NaturalDocs/License-GPL.txt +341 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/BinaryFile.pm +294 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder.pm +280 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/Base.pm +348 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/FramedHTML.pm +345 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTML.pm +398 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTMLBase.pm +3693 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy.pm +860 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/Class.pm +412 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/File.pm +157 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ConfigFile.pm +497 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Constants.pm +165 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/DefineMembers.pm +100 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Error.pm +305 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/File.pm +540 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable.pm +383 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm +44 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/String.pm +110 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages.pm +1475 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/ActionScript.pm +1473 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Ada.pm +38 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced.pm +828 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm +95 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm +70 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Base.pm +832 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/CSharp.pm +1484 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/PLSQL.pm +319 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Pascal.pm +143 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Perl.pm +1370 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype.pm +92 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm +87 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Simple.pm +503 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Tcl.pm +219 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu.pm +3406 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu/Entry.pm +201 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/NDMarkup.pm +76 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser.pm +1331 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/JavaDoc.pm +464 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/Native.pm +1060 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/ParsedTopic.pm +253 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project.pm +1402 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/ImageFile.pm +160 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/SourceFile.pm +113 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ReferenceString.pm +334 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings.pm +1418 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings/BuildTarget.pm +66 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB.pm +678 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Extension.pm +84 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/File.pm +129 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Item.pm +201 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm +45 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm +159 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/StatusMessage.pm +102 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolString.pm +212 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable.pm +1984 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/File.pm +186 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm +522 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Reference.pm +273 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm +97 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Symbol.pm +428 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm +96 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics.pm +1319 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics/Type.pm +151 -0
- data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Version.pm +384 -0
- data/template/assets/naturaldocs/NaturalDocs/NaturalDocs +400 -0
- data/template/assets/naturaldocs/NaturalDocs/NaturalDocs.bat +17 -0
- data/template/assets/naturaldocs/NaturalDocs/Styles/Default.css +767 -0
- data/template/assets/naturaldocs/NaturalDocs/Styles/Roman.css +765 -0
- data/template/assets/naturaldocs/NaturalDocs/Styles/Small.css +763 -0
- data/template/assets/utilities/pngout +0 -0
- data/template/deploy/public_html/.htaccess +0 -0
- data/template/documentation/js/.htaccess +0 -0
- data/template/src/html/.htaccess +76 -0
- data/template/src/html/css/cmn/global.css +96 -0
- data/template/src/html/css/cmn/ie.css +15 -0
- data/template/src/html/css/cmn/ie6.css +15 -0
- data/template/src/html/images/cmn/.htaccess +0 -0
- data/template/src/html/images/tmp/.htaccess +0 -0
- data/template/src/html/includes/debug.inc +5 -0
- data/template/src/html/includes/footer.inc +52 -0
- data/template/src/html/includes/header.inc +61 -0
- data/template/src/html/includes/html.inc +3 -0
- data/template/src/html/includes/namespace.inc +19 -0
- data/template/src/html/includes/page.inc +151 -0
- data/template/src/html/index.html +35 -0
- data/template/src/html/js/cmn/bootstrap.js +74 -0
- data/template/src/html/js/cmn/global.js +142 -0
- data/template/src/html/js/cmn/lib/LAB.js +348 -0
- data/template/src/html/min/.htaccess +4 -0
- data/template/src/html/min/MinifyCLI.php +19 -0
- data/template/src/html/min/README.txt +132 -0
- data/template/src/html/min/builder/_index.js +242 -0
- data/template/src/html/min/builder/bm.js +36 -0
- data/template/src/html/min/builder/index.php +182 -0
- data/template/src/html/min/builder/ocCheck.php +36 -0
- data/template/src/html/min/builder/rewriteTest.js +1 -0
- data/template/src/html/min/config.php +187 -0
- data/template/src/html/min/groupsConfig.php +34 -0
- data/template/src/html/min/index.php +66 -0
- data/template/src/html/min/lib/FirePHP.php +1370 -0
- data/template/src/html/min/lib/HTTP/ConditionalGet.php +348 -0
- data/template/src/html/min/lib/HTTP/Encoder.php +326 -0
- data/template/src/html/min/lib/JSMin.php +314 -0
- data/template/src/html/min/lib/JSMinPlus.php +1872 -0
- data/template/src/html/min/lib/Minify.php +532 -0
- data/template/src/html/min/lib/Minify/Build.php +103 -0
- data/template/src/html/min/lib/Minify/CSS.php +83 -0
- data/template/src/html/min/lib/Minify/CSS/Compressor.php +250 -0
- data/template/src/html/min/lib/Minify/CSS/UriRewriter.php +270 -0
- data/template/src/html/min/lib/Minify/Cache/APC.php +130 -0
- data/template/src/html/min/lib/Minify/Cache/File.php +125 -0
- data/template/src/html/min/lib/Minify/Cache/Memcache.php +137 -0
- data/template/src/html/min/lib/Minify/ClosureCompiler.php +85 -0
- data/template/src/html/min/lib/Minify/CommentPreserver.php +90 -0
- data/template/src/html/min/lib/Minify/Controller/Base.php +202 -0
- data/template/src/html/min/lib/Minify/Controller/Files.php +78 -0
- data/template/src/html/min/lib/Minify/Controller/Groups.php +94 -0
- data/template/src/html/min/lib/Minify/Controller/MinApp.php +132 -0
- data/template/src/html/min/lib/Minify/Controller/Page.php +82 -0
- data/template/src/html/min/lib/Minify/Controller/Version1.php +118 -0
- data/template/src/html/min/lib/Minify/HTML.php +245 -0
- data/template/src/html/min/lib/Minify/ImportProcessor.php +157 -0
- data/template/src/html/min/lib/Minify/Lines.php +131 -0
- data/template/src/html/min/lib/Minify/Logger.php +45 -0
- data/template/src/html/min/lib/Minify/Packer.php +37 -0
- data/template/src/html/min/lib/Minify/Source.php +187 -0
- data/template/src/html/min/lib/Minify/YUICompressor.php +139 -0
- data/template/src/html/min/lib/Solar/Dir.php +199 -0
- data/template/src/html/min/lib/closure-compiler.jar +0 -0
- data/template/src/html/min/lib/yuicompressor-2.4.2.jar +0 -0
- data/template/src/html/min/utils.php +90 -0
- data/template/src/templates/css/template.css +7 -0
- data/template/src/templates/js/template.js +72 -0
- data/template/src/templates/template.html +18 -0
- data/template/src/yaml/config.yml +46 -0
- data/template/src/yaml/deploy.yml +35 -0
- data/test/bixbite_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +278 -0
@@ -0,0 +1,1370 @@
|
|
1
|
+
###############################################################################
|
2
|
+
#
|
3
|
+
# Class: NaturalDocs::Languages::Perl
|
4
|
+
#
|
5
|
+
###############################################################################
|
6
|
+
#
|
7
|
+
# A subclass to handle the language variations of Perl.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Topic: Language Support
|
11
|
+
#
|
12
|
+
# Supported:
|
13
|
+
#
|
14
|
+
# - Packages
|
15
|
+
# - Inheritance via "use base" and "@ISA =".
|
16
|
+
# - Functions
|
17
|
+
# - Variables
|
18
|
+
#
|
19
|
+
# Not supported yet:
|
20
|
+
#
|
21
|
+
# - Constants
|
22
|
+
#
|
23
|
+
###############################################################################
|
24
|
+
|
25
|
+
# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
|
26
|
+
# Natural Docs is licensed under the GPL
|
27
|
+
|
28
|
+
use strict;
|
29
|
+
use integer;
|
30
|
+
|
31
|
+
package NaturalDocs::Languages::Perl;
|
32
|
+
|
33
|
+
use base 'NaturalDocs::Languages::Advanced';
|
34
|
+
|
35
|
+
|
36
|
+
#
|
37
|
+
# array: hereDocTerminators
|
38
|
+
# An array of active Here Doc terminators, or an empty array if not active. Each entry is an arrayref of tokens. The entries
|
39
|
+
# must appear in the order they must appear in the source.
|
40
|
+
#
|
41
|
+
my @hereDocTerminators;
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
###############################################################################
|
46
|
+
# Group: Interface Functions
|
47
|
+
|
48
|
+
|
49
|
+
#
|
50
|
+
# Function: PackageSeparator
|
51
|
+
# Returns the package separator symbol.
|
52
|
+
#
|
53
|
+
sub PackageSeparator
|
54
|
+
{ return '::'; };
|
55
|
+
|
56
|
+
#
|
57
|
+
# Function: EnumValues
|
58
|
+
# Returns the <EnumValuesType> that describes how the language handles enums.
|
59
|
+
#
|
60
|
+
sub EnumValues
|
61
|
+
{ return ::ENUM_GLOBAL(); };
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# Function: ParseFile
|
66
|
+
#
|
67
|
+
# Parses the passed source file, sending comments acceptable for documentation to <NaturalDocs::Parser->OnComment()>.
|
68
|
+
#
|
69
|
+
# Parameters:
|
70
|
+
#
|
71
|
+
# sourceFile - The name of the source file to parse.
|
72
|
+
# topicList - A reference to the list of <NaturalDocs::Parser::ParsedTopics> being built by the file.
|
73
|
+
#
|
74
|
+
# Returns:
|
75
|
+
#
|
76
|
+
# The array ( autoTopics, scopeRecord ).
|
77
|
+
#
|
78
|
+
# autoTopics - An arrayref of automatically generated topics from the file, or undef if none.
|
79
|
+
# scopeRecord - An arrayref of <NaturalDocs::Languages::Advanced::ScopeChanges>, or undef if none.
|
80
|
+
#
|
81
|
+
sub ParseFile #(sourceFile, topicsList)
|
82
|
+
{
|
83
|
+
my ($self, $sourceFile, $topicsList) = @_;
|
84
|
+
|
85
|
+
@hereDocTerminators = ( );
|
86
|
+
|
87
|
+
# The regular block comment symbols are undef because they're all potentially JavaDoc comments. PreprocessFile() will
|
88
|
+
# handle translating things like =begin naturaldocs and =begin javadoc to =begin nd.
|
89
|
+
$self->ParseForCommentsAndTokens($sourceFile, [ '#' ], undef, [ '##' ], [ '=begin nd', '=end nd' ]);
|
90
|
+
|
91
|
+
my $tokens = $self->Tokens();
|
92
|
+
my $index = 0;
|
93
|
+
my $lineNumber = 1;
|
94
|
+
|
95
|
+
while ($index < scalar @$tokens)
|
96
|
+
{
|
97
|
+
if ($self->TryToSkipWhitespace(\$index, \$lineNumber) ||
|
98
|
+
$self->TryToGetPackage(\$index, \$lineNumber) ||
|
99
|
+
$self->TryToGetBase(\$index, \$lineNumber) ||
|
100
|
+
$self->TryToGetFunction(\$index, \$lineNumber) ||
|
101
|
+
$self->TryToGetVariable(\$index, \$lineNumber) )
|
102
|
+
{
|
103
|
+
# The functions above will handle everything.
|
104
|
+
}
|
105
|
+
|
106
|
+
elsif ($tokens->[$index] eq '{')
|
107
|
+
{
|
108
|
+
$self->StartScope('}', $lineNumber, undef);
|
109
|
+
$index++;
|
110
|
+
}
|
111
|
+
|
112
|
+
elsif ($tokens->[$index] eq '}')
|
113
|
+
{
|
114
|
+
if ($self->ClosingScopeSymbol() eq '}')
|
115
|
+
{ $self->EndScope($lineNumber); };
|
116
|
+
|
117
|
+
$index++;
|
118
|
+
}
|
119
|
+
|
120
|
+
elsif (lc($tokens->[$index]) eq 'eval')
|
121
|
+
{
|
122
|
+
# We want to skip the token in this case instead of letting it fall to SkipRestOfStatement. This allows evals with braces
|
123
|
+
# to be treated like normal floating braces.
|
124
|
+
$index++;
|
125
|
+
}
|
126
|
+
|
127
|
+
else
|
128
|
+
{
|
129
|
+
$self->SkipRestOfStatement(\$index, \$lineNumber);
|
130
|
+
};
|
131
|
+
};
|
132
|
+
|
133
|
+
|
134
|
+
# Don't need to keep these around.
|
135
|
+
$self->ClearTokens();
|
136
|
+
|
137
|
+
return ( $self->AutoTopics(), $self->ScopeRecord() );
|
138
|
+
};
|
139
|
+
|
140
|
+
|
141
|
+
#
|
142
|
+
# Function: PreprocessFile
|
143
|
+
#
|
144
|
+
# Overridden to support "=begin nd" and similar.
|
145
|
+
#
|
146
|
+
# - "=begin [nd|naturaldocs|natural docs|jd|javadoc|java doc]" all translate to "=begin nd".
|
147
|
+
# - "=[nd|naturaldocs|natural docs]" also translate to "=begin nd".
|
148
|
+
# - "=end [nd|naturaldocs|natural docs|jd|javadoc]" all translate to "=end nd".
|
149
|
+
# - "=cut" from a ND block translates into "=end nd", but the next line will be altered to begin with "(NDPODBREAK)". This is
|
150
|
+
# so if there is POD leading into ND which ends with a cut, the parser can still end the original POD because the end ND line
|
151
|
+
# would have been removed. Remember, <NaturalDocs::Languages::Advanced->ParseForCommentsAndTokens()> removes
|
152
|
+
# Natural Docs-worthy comments to save parsing time.
|
153
|
+
# - "=pod begin nd" and "=pod end nd" are supported for compatibility with ND 1.32 and earlier, even though the syntax is a
|
154
|
+
# mistake.
|
155
|
+
# - It also supports the wrong plural forms, so naturaldoc/natural doc/javadocs/java docs will work.
|
156
|
+
#
|
157
|
+
sub PreprocessFile #(lines)
|
158
|
+
{
|
159
|
+
my ($self, $lines) = @_;
|
160
|
+
|
161
|
+
my $inNDPOD = 0;
|
162
|
+
my $mustBreakPOD = 0;
|
163
|
+
|
164
|
+
for (my $i = 0; $i < scalar @$lines; $i++)
|
165
|
+
{
|
166
|
+
if ($lines->[$i] =~ /^\=(?:(?:pod[ \t]+)?begin[ \t]+)?(?:nd|natural[ \t]*docs?|jd|java[ \t]*docs?)[ \t]*$/i)
|
167
|
+
{
|
168
|
+
$lines->[$i] = '=begin nd';
|
169
|
+
$inNDPOD = 1;
|
170
|
+
$mustBreakPOD = 0;
|
171
|
+
}
|
172
|
+
elsif ($lines->[$i] =~ /^\=(?:pod[ \t]+)end[ \t]+(?:nd|natural[ \t]*docs?|jd|javadocs?)[ \t]*$/i)
|
173
|
+
{
|
174
|
+
$lines->[$i] = '=end nd';
|
175
|
+
$inNDPOD = 0;
|
176
|
+
$mustBreakPOD = 0;
|
177
|
+
}
|
178
|
+
elsif ($lines->[$i] =~ /^\=cut[ \t]*$/i)
|
179
|
+
{
|
180
|
+
if ($inNDPOD)
|
181
|
+
{
|
182
|
+
$lines->[$i] = '=end nd';
|
183
|
+
$inNDPOD = 0;
|
184
|
+
$mustBreakPOD = 1;
|
185
|
+
};
|
186
|
+
}
|
187
|
+
elsif ($mustBreakPOD)
|
188
|
+
{
|
189
|
+
$lines->[$i] = '(NDPODBREAK)' . $lines->[$i];
|
190
|
+
$mustBreakPOD = 0;
|
191
|
+
};
|
192
|
+
};
|
193
|
+
};
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
###############################################################################
|
198
|
+
# Group: Statement Parsing Functions
|
199
|
+
# All functions here assume that the current position is at the beginning of a statement.
|
200
|
+
#
|
201
|
+
# Note for developers: I am well aware that the code in these functions do not check if we're past the end of the tokens as
|
202
|
+
# often as it should. We're making use of the fact that Perl will always return undef in these cases to keep the code simpler.
|
203
|
+
|
204
|
+
|
205
|
+
#
|
206
|
+
# Function: TryToGetPackage
|
207
|
+
#
|
208
|
+
# Determines whether the position is at a package declaration statement, and if so, generates a topic for it, skips it, and
|
209
|
+
# returns true.
|
210
|
+
#
|
211
|
+
sub TryToGetPackage #(indexRef, lineNumberRef)
|
212
|
+
{
|
213
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
214
|
+
my $tokens = $self->Tokens();
|
215
|
+
|
216
|
+
if (lc($tokens->[$$indexRef]) eq 'package')
|
217
|
+
{
|
218
|
+
my $index = $$indexRef + 1;
|
219
|
+
my $lineNumber = $$lineNumberRef;
|
220
|
+
|
221
|
+
if (!$self->TryToSkipWhitespace(\$index, \$lineNumber))
|
222
|
+
{ return undef; };
|
223
|
+
|
224
|
+
my $name;
|
225
|
+
|
226
|
+
while ($tokens->[$index] =~ /^[a-z_\:]/i)
|
227
|
+
{
|
228
|
+
$name .= $tokens->[$index];
|
229
|
+
$index++;
|
230
|
+
};
|
231
|
+
|
232
|
+
if (!defined $name)
|
233
|
+
{ return undef; };
|
234
|
+
|
235
|
+
my $autoTopic = NaturalDocs::Parser::ParsedTopic->New(::TOPIC_CLASS(), $name,
|
236
|
+
undef, undef,
|
237
|
+
undef,
|
238
|
+
undef, undef, $$lineNumberRef);
|
239
|
+
$self->AddAutoTopic($autoTopic);
|
240
|
+
|
241
|
+
NaturalDocs::Parser->OnClass($autoTopic->Symbol());
|
242
|
+
|
243
|
+
$self->SetPackage($autoTopic->Symbol(), $$lineNumberRef);
|
244
|
+
|
245
|
+
$$indexRef = $index;
|
246
|
+
$$lineNumberRef = $lineNumber;
|
247
|
+
$self->SkipRestOfStatement($indexRef, $lineNumberRef);
|
248
|
+
|
249
|
+
return 1;
|
250
|
+
};
|
251
|
+
|
252
|
+
return undef;
|
253
|
+
};
|
254
|
+
|
255
|
+
|
256
|
+
#
|
257
|
+
# Function: TryToGetBase
|
258
|
+
#
|
259
|
+
# Determines whether the position is at a package base declaration statement, and if so, calls
|
260
|
+
# <NaturalDocs::Parser->OnClassParent()>.
|
261
|
+
#
|
262
|
+
# Supported Syntaxes:
|
263
|
+
#
|
264
|
+
# > use base [list of strings]
|
265
|
+
# > @ISA = [list of strings]
|
266
|
+
# > @[package]::ISA = [list of strings]
|
267
|
+
# > our @ISA = [list of strings]
|
268
|
+
#
|
269
|
+
sub TryToGetBase #(indexRef, lineNumberRef)
|
270
|
+
{
|
271
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
272
|
+
my $tokens = $self->Tokens();
|
273
|
+
|
274
|
+
my ($index, $lineNumber, $class, $parents);
|
275
|
+
|
276
|
+
if (lc($tokens->[$$indexRef]) eq 'use')
|
277
|
+
{
|
278
|
+
$index = $$indexRef + 1;
|
279
|
+
$lineNumber = $$lineNumberRef;
|
280
|
+
|
281
|
+
if (!$self->TryToSkipWhitespace(\$index, \$lineNumber) ||
|
282
|
+
lc($tokens->[$index]) ne 'base')
|
283
|
+
{ return undef; }
|
284
|
+
|
285
|
+
$index++;
|
286
|
+
$self->TryToSkipWhitespace(\$index, \$lineNumber);
|
287
|
+
|
288
|
+
$parents = $self->TryToGetListOfStrings(\$index, \$lineNumber);
|
289
|
+
}
|
290
|
+
|
291
|
+
else
|
292
|
+
{
|
293
|
+
$index = $$indexRef;
|
294
|
+
$lineNumber = $$lineNumberRef;
|
295
|
+
|
296
|
+
if (lc($tokens->[$index]) eq 'our')
|
297
|
+
{
|
298
|
+
$index++;
|
299
|
+
$self->TryToSkipWhitespace(\$index, \$lineNumber);
|
300
|
+
};
|
301
|
+
|
302
|
+
if ($tokens->[$index] eq '@')
|
303
|
+
{
|
304
|
+
$index++;
|
305
|
+
|
306
|
+
while ($index < scalar @$tokens)
|
307
|
+
{
|
308
|
+
if ($tokens->[$index] eq 'ISA')
|
309
|
+
{
|
310
|
+
$index++;
|
311
|
+
$self->TryToSkipWhitespace(\$index, \$lineNumber);
|
312
|
+
|
313
|
+
if ($tokens->[$index] eq '=')
|
314
|
+
{
|
315
|
+
$index++;
|
316
|
+
$self->TryToSkipWhitespace(\$index, \$lineNumber);
|
317
|
+
|
318
|
+
$parents = $self->TryToGetListOfStrings(\$index, \$lineNumber);
|
319
|
+
}
|
320
|
+
else
|
321
|
+
{ last; };
|
322
|
+
}
|
323
|
+
|
324
|
+
# If token isn't ISA...
|
325
|
+
elsif ($tokens->[$index] =~ /^[a-z0-9_:]/i)
|
326
|
+
{
|
327
|
+
$class .= $tokens->[$index];
|
328
|
+
$index++;
|
329
|
+
}
|
330
|
+
else
|
331
|
+
{ last; };
|
332
|
+
};
|
333
|
+
};
|
334
|
+
};
|
335
|
+
|
336
|
+
if (defined $parents)
|
337
|
+
{
|
338
|
+
if (defined $class)
|
339
|
+
{
|
340
|
+
$class =~ s/::$//;
|
341
|
+
my @classIdentifiers = split(/::/, $class);
|
342
|
+
$class = NaturalDocs::SymbolString->Join(@classIdentifiers);
|
343
|
+
}
|
344
|
+
else
|
345
|
+
{ $class = $self->CurrentScope(); };
|
346
|
+
|
347
|
+
foreach my $parent (@$parents)
|
348
|
+
{
|
349
|
+
my @parentIdentifiers = split(/::/, $parent);
|
350
|
+
my $parentSymbol = NaturalDocs::SymbolString->Join(@parentIdentifiers);
|
351
|
+
|
352
|
+
NaturalDocs::Parser->OnClassParent($class, $parentSymbol, undef, undef, ::RESOLVE_ABSOLUTE());
|
353
|
+
};
|
354
|
+
|
355
|
+
$$indexRef = $index;
|
356
|
+
$$lineNumberRef = $lineNumber;
|
357
|
+
$self->SkipRestOfStatement($indexRef, $lineNumberRef);
|
358
|
+
|
359
|
+
return 1;
|
360
|
+
}
|
361
|
+
else
|
362
|
+
{ return undef; };
|
363
|
+
};
|
364
|
+
|
365
|
+
|
366
|
+
#
|
367
|
+
# Function: TryToGetFunction
|
368
|
+
#
|
369
|
+
# Determines whether the position is at a function declaration statement, and if so, generates a topic for it, skips it, and
|
370
|
+
# returns true.
|
371
|
+
#
|
372
|
+
sub TryToGetFunction #(indexRef, lineNumberRef)
|
373
|
+
{
|
374
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
375
|
+
my $tokens = $self->Tokens();
|
376
|
+
|
377
|
+
if ( lc($tokens->[$$indexRef]) eq 'sub')
|
378
|
+
{
|
379
|
+
my $prototypeStart = $$indexRef;
|
380
|
+
my $prototypeStartLine = $$lineNumberRef;
|
381
|
+
my $prototypeEnd = $$indexRef + 1;
|
382
|
+
my $prototypeEndLine = $$lineNumberRef;
|
383
|
+
|
384
|
+
if ( !$self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine) ||
|
385
|
+
$tokens->[$prototypeEnd] !~ /^[a-z_]/i )
|
386
|
+
{ return undef; };
|
387
|
+
|
388
|
+
my $name = $tokens->[$prototypeEnd];
|
389
|
+
$prototypeEnd++;
|
390
|
+
|
391
|
+
# We parsed 'sub [name]'. Now keep going until we find a semicolon or a brace.
|
392
|
+
|
393
|
+
for (;;)
|
394
|
+
{
|
395
|
+
if ($prototypeEnd >= scalar @$tokens)
|
396
|
+
{ return undef; }
|
397
|
+
|
398
|
+
# End if we find a semicolon, since it means we found a predeclaration rather than an actual function.
|
399
|
+
elsif ($tokens->[$prototypeEnd] eq ';')
|
400
|
+
{ return undef; }
|
401
|
+
|
402
|
+
elsif ($tokens->[$prototypeEnd] eq '{')
|
403
|
+
{
|
404
|
+
# Found it!
|
405
|
+
|
406
|
+
my $prototype = $self->NormalizePrototype( $self->CreateString($prototypeStart, $prototypeEnd) );
|
407
|
+
|
408
|
+
$self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_FUNCTION(), $name,
|
409
|
+
$self->CurrentScope(), undef,
|
410
|
+
$prototype,
|
411
|
+
undef, undef, $prototypeStartLine));
|
412
|
+
|
413
|
+
$$indexRef = $prototypeEnd;
|
414
|
+
$$lineNumberRef = $prototypeEndLine;
|
415
|
+
|
416
|
+
$self->SkipRestOfStatement($indexRef, $lineNumberRef);
|
417
|
+
|
418
|
+
return 1;
|
419
|
+
}
|
420
|
+
|
421
|
+
else
|
422
|
+
{ $self->GenericSkip(\$prototypeEnd, \$prototypeEndLine, 0, 1); };
|
423
|
+
};
|
424
|
+
}
|
425
|
+
else
|
426
|
+
{ return undef; };
|
427
|
+
};
|
428
|
+
|
429
|
+
|
430
|
+
#
|
431
|
+
# Function: TryToGetVariable
|
432
|
+
#
|
433
|
+
# Determines if the position is at a variable declaration statement, and if so, generates a topic for it, skips it, and returns
|
434
|
+
# true.
|
435
|
+
#
|
436
|
+
# Supported Syntaxes:
|
437
|
+
#
|
438
|
+
# - Supports variables declared with "my", "our", and "local".
|
439
|
+
# - Supports multiple declarations in one statement, such as "my ($x, $y);".
|
440
|
+
# - Supports types and attributes.
|
441
|
+
#
|
442
|
+
sub TryToGetVariable #(indexRef, lineNumberRef)
|
443
|
+
{
|
444
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
445
|
+
my $tokens = $self->Tokens();
|
446
|
+
|
447
|
+
my $firstToken = lc( $tokens->[$$indexRef] );
|
448
|
+
|
449
|
+
if ($firstToken eq 'my' || $firstToken eq 'our' || $firstToken eq 'local')
|
450
|
+
{
|
451
|
+
my $prototypeStart = $$indexRef;
|
452
|
+
my $prototypeStartLine = $$lineNumberRef;
|
453
|
+
my $prototypeEnd = $$indexRef + 1;
|
454
|
+
my $prototypeEndLine = $$lineNumberRef;
|
455
|
+
|
456
|
+
$self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine);
|
457
|
+
|
458
|
+
|
459
|
+
# Get the type if present.
|
460
|
+
|
461
|
+
my $type;
|
462
|
+
|
463
|
+
if ($tokens->[$prototypeEnd] =~ /^[a-z\:]/i)
|
464
|
+
{
|
465
|
+
do
|
466
|
+
{
|
467
|
+
$type .= $tokens->[$prototypeEnd];
|
468
|
+
$prototypeEnd++;
|
469
|
+
}
|
470
|
+
while ($tokens->[$prototypeEnd] =~ /^[a-z\:]/i);
|
471
|
+
|
472
|
+
if (!$self->TryToSkipWhitespace(\$prototypeEnd, \$prototypeEndLine))
|
473
|
+
{ return undef; };
|
474
|
+
};
|
475
|
+
|
476
|
+
|
477
|
+
# Get the name, or possibly names.
|
478
|
+
|
479
|
+
if ($tokens->[$prototypeEnd] eq '(')
|
480
|
+
{
|
481
|
+
# If there's multiple variables, we'll need to build a custom prototype for each one. $firstToken already has the
|
482
|
+
# declaring word. We're going to store each name in @names, and we're going to use $prototypeStart and
|
483
|
+
# $prototypeEnd to capture any properties appearing after the list.
|
484
|
+
|
485
|
+
my $name;
|
486
|
+
my @names;
|
487
|
+
my $hasComma = 0;
|
488
|
+
|
489
|
+
$prototypeStart = $prototypeEnd + 1;
|
490
|
+
$prototypeStartLine = $prototypeEndLine;
|
491
|
+
|
492
|
+
for (;;)
|
493
|
+
{
|
494
|
+
$self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
|
495
|
+
|
496
|
+
$name = $self->TryToGetVariableName(\$prototypeStart, \$prototypeStartLine);
|
497
|
+
|
498
|
+
if (!defined $name)
|
499
|
+
{ return undef; };
|
500
|
+
|
501
|
+
push @names, $name;
|
502
|
+
|
503
|
+
$self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
|
504
|
+
|
505
|
+
# We can have multiple commas in a row. We can also have trailing commas. However, the parenthesis must
|
506
|
+
# not start with a comma or be empty, hence this logic does not appear earlier.
|
507
|
+
while ($tokens->[$prototypeStart] eq ',')
|
508
|
+
{
|
509
|
+
$prototypeStart++;
|
510
|
+
$self->TryToSkipWhitespace(\$prototypeStart, \$prototypeStartLine);
|
511
|
+
|
512
|
+
$hasComma = 1;
|
513
|
+
}
|
514
|
+
|
515
|
+
if ($tokens->[$prototypeStart] eq ')')
|
516
|
+
{
|
517
|
+
$prototypeStart++;
|
518
|
+
last;
|
519
|
+
}
|
520
|
+
elsif (!$hasComma)
|
521
|
+
{ return undef; };
|
522
|
+
};
|
523
|
+
|
524
|
+
|
525
|
+
# Now find the end of the prototype.
|
526
|
+
|
527
|
+
$prototypeEnd = $prototypeStart;
|
528
|
+
$prototypeEndLine = $prototypeStartLine;
|
529
|
+
|
530
|
+
while ($prototypeEnd < scalar @$tokens &&
|
531
|
+
$tokens->[$prototypeEnd] !~ /^[\;\=]/)
|
532
|
+
{
|
533
|
+
$prototypeEnd++;
|
534
|
+
};
|
535
|
+
|
536
|
+
|
537
|
+
my $prototypePrefix = $firstToken . ' ';
|
538
|
+
if (defined $type)
|
539
|
+
{ $prototypePrefix .= $type . ' '; };
|
540
|
+
|
541
|
+
my $prototypeSuffix = ' ' . $self->CreateString($prototypeStart, $prototypeEnd);
|
542
|
+
|
543
|
+
foreach $name (@names)
|
544
|
+
{
|
545
|
+
my $prototype = $self->NormalizePrototype( $prototypePrefix . $name . $prototypeSuffix );
|
546
|
+
|
547
|
+
$self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_VARIABLE(), $name,
|
548
|
+
$self->CurrentScope(), undef,
|
549
|
+
$prototype,
|
550
|
+
undef, undef, $prototypeStartLine));
|
551
|
+
};
|
552
|
+
|
553
|
+
$self->SkipRestOfStatement(\$prototypeEnd, \$prototypeEndLine);
|
554
|
+
|
555
|
+
$$indexRef = $prototypeEnd;
|
556
|
+
$$lineNumberRef = $prototypeEndLine;
|
557
|
+
}
|
558
|
+
|
559
|
+
else # no parenthesis
|
560
|
+
{
|
561
|
+
my $name = $self->TryToGetVariableName(\$prototypeEnd, \$prototypeEndLine);
|
562
|
+
|
563
|
+
if (!defined $name)
|
564
|
+
{ return undef; };
|
565
|
+
|
566
|
+
while ($prototypeEnd < scalar @$tokens &&
|
567
|
+
$tokens->[$prototypeEnd] !~ /^[\;\=]/)
|
568
|
+
{
|
569
|
+
$prototypeEnd++;
|
570
|
+
};
|
571
|
+
|
572
|
+
my $prototype = $self->NormalizePrototype( $self->CreateString($prototypeStart, $prototypeEnd) );
|
573
|
+
|
574
|
+
$self->AddAutoTopic(NaturalDocs::Parser::ParsedTopic->New(::TOPIC_VARIABLE(), $name,
|
575
|
+
$self->CurrentScope(), undef,
|
576
|
+
$prototype,
|
577
|
+
undef, undef, $prototypeStartLine));
|
578
|
+
|
579
|
+
$self->SkipRestOfStatement(\$prototypeEnd, \$prototypeEndLine);
|
580
|
+
|
581
|
+
$$indexRef = $prototypeEnd;
|
582
|
+
$$lineNumberRef = $prototypeEndLine;
|
583
|
+
};
|
584
|
+
|
585
|
+
return 1;
|
586
|
+
}
|
587
|
+
else
|
588
|
+
{ return undef; };
|
589
|
+
};
|
590
|
+
|
591
|
+
|
592
|
+
#
|
593
|
+
# Function: TryToGetVariableName
|
594
|
+
#
|
595
|
+
# Determines if the position is at a variable name, and if so, skips it and returns the name.
|
596
|
+
#
|
597
|
+
sub TryToGetVariableName #(indexRef, lineNumberRef)
|
598
|
+
{
|
599
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
600
|
+
my $tokens = $self->Tokens();
|
601
|
+
|
602
|
+
my $name;
|
603
|
+
|
604
|
+
if ($tokens->[$$indexRef] =~ /^[\$\@\%\*]/)
|
605
|
+
{
|
606
|
+
$name .= $tokens->[$$indexRef];
|
607
|
+
$$indexRef++;
|
608
|
+
|
609
|
+
$self->TryToSkipWhitespace($indexRef, $lineNumberRef);
|
610
|
+
|
611
|
+
if ($tokens->[$$indexRef] =~ /^[a-z_]/i)
|
612
|
+
{
|
613
|
+
$name .= $tokens->[$$indexRef];
|
614
|
+
$$indexRef++;
|
615
|
+
}
|
616
|
+
else
|
617
|
+
{ return undef; };
|
618
|
+
};
|
619
|
+
|
620
|
+
return $name;
|
621
|
+
};
|
622
|
+
|
623
|
+
|
624
|
+
#
|
625
|
+
# Function: TryToGetListOfStrings
|
626
|
+
#
|
627
|
+
# Attempts to retrieve a list of strings from the current position. Returns an arrayref of them if any are found, or undef if none.
|
628
|
+
# It stops the moment it reaches a non-string, so "string1, variable, string2" will only return string1.
|
629
|
+
#
|
630
|
+
# Supported Syntaxes:
|
631
|
+
#
|
632
|
+
# - Supports parenthesis.
|
633
|
+
# - Supports all string forms supported by <TryToSkipString()>.
|
634
|
+
# - Supports qw() string arrays.
|
635
|
+
#
|
636
|
+
sub TryToGetListOfStrings #(indexRef, lineNumberRef)
|
637
|
+
{
|
638
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
639
|
+
my $tokens = $self->Tokens();
|
640
|
+
|
641
|
+
my $parenthesis = 0;
|
642
|
+
my $strings;
|
643
|
+
|
644
|
+
while ($$indexRef < scalar @$tokens)
|
645
|
+
{
|
646
|
+
# We'll tolerate parenthesis.
|
647
|
+
if ($tokens->[$$indexRef] eq '(')
|
648
|
+
{
|
649
|
+
$$indexRef++;
|
650
|
+
$parenthesis++;
|
651
|
+
}
|
652
|
+
elsif ($tokens->[$$indexRef] eq ')')
|
653
|
+
{
|
654
|
+
if ($parenthesis == 0)
|
655
|
+
{ last; };
|
656
|
+
|
657
|
+
$$indexRef++;
|
658
|
+
$parenthesis--;
|
659
|
+
}
|
660
|
+
elsif ($tokens->[$$indexRef] eq ',')
|
661
|
+
{
|
662
|
+
$$indexRef++;
|
663
|
+
}
|
664
|
+
else
|
665
|
+
{
|
666
|
+
my ($startContent, $endContent);
|
667
|
+
my $symbolIndex = $$indexRef;
|
668
|
+
|
669
|
+
if ($self->TryToSkipString($indexRef, $lineNumberRef, \$startContent, \$endContent))
|
670
|
+
{
|
671
|
+
my $content = $self->CreateString($startContent, $endContent);
|
672
|
+
|
673
|
+
if (!defined $strings)
|
674
|
+
{ $strings = [ ]; };
|
675
|
+
|
676
|
+
if (lc($tokens->[$symbolIndex]) eq 'qw')
|
677
|
+
{
|
678
|
+
$content =~ tr/ \t\n/ /s;
|
679
|
+
$content =~ s/^ //;
|
680
|
+
|
681
|
+
my @qwStrings = split(/ /, $content);
|
682
|
+
|
683
|
+
push @$strings, @qwStrings;
|
684
|
+
}
|
685
|
+
else
|
686
|
+
{
|
687
|
+
push @$strings, $content;
|
688
|
+
};
|
689
|
+
}
|
690
|
+
else
|
691
|
+
{ last; };
|
692
|
+
};
|
693
|
+
|
694
|
+
$self->TryToSkipWhitespace($indexRef, $lineNumberRef);
|
695
|
+
};
|
696
|
+
|
697
|
+
return $strings;
|
698
|
+
};
|
699
|
+
|
700
|
+
|
701
|
+
###############################################################################
|
702
|
+
# Group: Low Level Parsing Functions
|
703
|
+
|
704
|
+
|
705
|
+
#
|
706
|
+
# Function: GenericSkip
|
707
|
+
#
|
708
|
+
# Advances the position one place through general code.
|
709
|
+
#
|
710
|
+
# - If the position is on a comment or string, it will skip it completely.
|
711
|
+
# - If the position is on an opening symbol, it will skip until the past the closing symbol.
|
712
|
+
# - If the position is on a regexp or quote-like operator, it will skip it completely.
|
713
|
+
# - If the position is on a backslash, it will skip it and the following token.
|
714
|
+
# - If the position is on whitespace (including comments), it will skip it completely.
|
715
|
+
# - Otherwise it skips one token.
|
716
|
+
#
|
717
|
+
# Parameters:
|
718
|
+
#
|
719
|
+
# indexRef - A reference to the current index.
|
720
|
+
# lineNumberRef - A reference to the current line number.
|
721
|
+
# noRegExps - If set, does not test for regular expressions.
|
722
|
+
#
|
723
|
+
sub GenericSkip #(indexRef, lineNumberRef, noRegExps)
|
724
|
+
{
|
725
|
+
my ($self, $indexRef, $lineNumberRef, $noRegExps, $allowStringedClosingParens) = @_;
|
726
|
+
my $tokens = $self->Tokens();
|
727
|
+
|
728
|
+
if ($tokens->[$$indexRef] eq "\\" && $$indexRef + 1 < scalar @$tokens && $tokens->[$$indexRef+1] ne "\n")
|
729
|
+
{ $$indexRef += 2; }
|
730
|
+
|
731
|
+
# Note that we don't want to count backslashed ()[]{} since they could be in regexps. Also, ()[] are valid variable names
|
732
|
+
# when preceded by a string.
|
733
|
+
|
734
|
+
# We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
|
735
|
+
elsif ($tokens->[$$indexRef] eq '{' && !$self->IsBackslashed($$indexRef))
|
736
|
+
{
|
737
|
+
$$indexRef++;
|
738
|
+
$self->GenericSkipUntilAfter($indexRef, $lineNumberRef, '}', $noRegExps, $allowStringedClosingParens);
|
739
|
+
}
|
740
|
+
elsif ($tokens->[$$indexRef] eq '(' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
|
741
|
+
{
|
742
|
+
# Temporarily allow stringed closing parenthesis if it looks like we're in an anonymous function declaration with Perl's
|
743
|
+
# cheap version of prototypes, such as "my $_declare = sub($) {}".
|
744
|
+
my $tempAllowStringedClosingParens = $allowStringedClosingParens;
|
745
|
+
if (!$allowStringedClosingParens)
|
746
|
+
{
|
747
|
+
my $tempIndex = $$indexRef - 1;
|
748
|
+
if ($tempIndex >= 0 && $tokens->[$tempIndex] =~ /^[ \t]/)
|
749
|
+
{ $tempIndex--; }
|
750
|
+
if ($tempIndex >= 0 && $tokens->[$tempIndex] eq 'sub')
|
751
|
+
{ $tempAllowStringedClosingParens = 1; }
|
752
|
+
}
|
753
|
+
|
754
|
+
$$indexRef++;
|
755
|
+
|
756
|
+
do
|
757
|
+
{ $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ')', $noRegExps, $tempAllowStringedClosingParens); }
|
758
|
+
while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1) && !$tempAllowStringedClosingParens);
|
759
|
+
}
|
760
|
+
elsif ($tokens->[$$indexRef] eq '[' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
|
761
|
+
{
|
762
|
+
$$indexRef++;
|
763
|
+
|
764
|
+
do
|
765
|
+
{ $self->GenericSkipUntilAfter($indexRef, $lineNumberRef, ']', $noRegExps, $allowStringedClosingParens); }
|
766
|
+
while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1));
|
767
|
+
}
|
768
|
+
|
769
|
+
elsif ($self->TryToSkipWhitespace($indexRef, $lineNumberRef) ||
|
770
|
+
$self->TryToSkipString($indexRef, $lineNumberRef) ||
|
771
|
+
$self->TryToSkipHereDocDeclaration($indexRef, $lineNumberRef) ||
|
772
|
+
(!$noRegExps && $self->TryToSkipRegexp($indexRef, $lineNumberRef) ) )
|
773
|
+
{
|
774
|
+
}
|
775
|
+
|
776
|
+
else
|
777
|
+
{ $$indexRef++; };
|
778
|
+
};
|
779
|
+
|
780
|
+
|
781
|
+
#
|
782
|
+
# Function: GenericSkipUntilAfter
|
783
|
+
#
|
784
|
+
# Advances the position via <GenericSkip()> until a specific token is reached and passed.
|
785
|
+
#
|
786
|
+
sub GenericSkipUntilAfter #(indexRef, lineNumberRef, token, noRegExps, allowStringedClosingParens)
|
787
|
+
{
|
788
|
+
my ($self, $indexRef, $lineNumberRef, $token, $noRegExps, $allowStringedClosingParens) = @_;
|
789
|
+
my $tokens = $self->Tokens();
|
790
|
+
|
791
|
+
while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
|
792
|
+
{ $self->GenericSkip($indexRef, $lineNumberRef, $noRegExps, $allowStringedClosingParens); };
|
793
|
+
|
794
|
+
if ($tokens->[$$indexRef] eq "\n")
|
795
|
+
{ $$lineNumberRef++; };
|
796
|
+
$$indexRef++;
|
797
|
+
};
|
798
|
+
|
799
|
+
|
800
|
+
#
|
801
|
+
# Function: GenericRegexpSkip
|
802
|
+
#
|
803
|
+
# Advances the position one place through regexp code.
|
804
|
+
#
|
805
|
+
# - If the position is on an opening symbol, it will skip until the past the closing symbol.
|
806
|
+
# - If the position is on a backslash, it will skip it and the following token.
|
807
|
+
# - If the position is on whitespace (not including comments), it will skip it completely.
|
808
|
+
# - Otherwise it skips one token.
|
809
|
+
#
|
810
|
+
# Also differs from <GenericSkip()> in that the parenthesis in $( and $) do count against the scope, where they wouldn't
|
811
|
+
# normally.
|
812
|
+
#
|
813
|
+
# Parameters:
|
814
|
+
#
|
815
|
+
# indexRef - A reference to the current index.
|
816
|
+
# lineNumberRef - A reference to the current line number.
|
817
|
+
# inBrackets - Whether we're in brackets or not. If true, we don't care about matching braces and parenthesis.
|
818
|
+
#
|
819
|
+
sub GenericRegexpSkip #(indexRef, lineNumberRef, inBrackets)
|
820
|
+
{
|
821
|
+
my ($self, $indexRef, $lineNumberRef, $inBrackets) = @_;
|
822
|
+
my $tokens = $self->Tokens();
|
823
|
+
|
824
|
+
if ($tokens->[$$indexRef] eq "\\" && $$indexRef + 1 < scalar @$tokens && $tokens->[$$indexRef+1] ne "\n")
|
825
|
+
{ $$indexRef += 2; }
|
826
|
+
|
827
|
+
# We can ignore the scope stack because we're just skipping everything without parsing, and we need recursion anyway.
|
828
|
+
elsif ($tokens->[$$indexRef] eq '{' && !$self->IsBackslashed($$indexRef) && !$inBrackets)
|
829
|
+
{
|
830
|
+
$$indexRef++;
|
831
|
+
$self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, '}');
|
832
|
+
}
|
833
|
+
elsif ($tokens->[$$indexRef] eq '(' && !$self->IsBackslashed($$indexRef) && !$inBrackets)
|
834
|
+
{
|
835
|
+
$$indexRef++;
|
836
|
+
$self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, ')');
|
837
|
+
}
|
838
|
+
elsif ($tokens->[$$indexRef] eq '[' && !$self->IsBackslashed($$indexRef) && !$self->IsStringed($$indexRef))
|
839
|
+
{
|
840
|
+
$$indexRef++;
|
841
|
+
|
842
|
+
do
|
843
|
+
{ $self->GenericRegexpSkipUntilAfter($indexRef, $lineNumberRef, ']'); }
|
844
|
+
while ($$indexRef < scalar @$tokens && $self->IsStringed($$indexRef - 1));
|
845
|
+
}
|
846
|
+
|
847
|
+
elsif ($tokens->[$$indexRef] eq "\n")
|
848
|
+
{
|
849
|
+
$$lineNumberRef++;
|
850
|
+
$$indexRef++;
|
851
|
+
}
|
852
|
+
|
853
|
+
else
|
854
|
+
{ $$indexRef++; };
|
855
|
+
};
|
856
|
+
|
857
|
+
|
858
|
+
#
|
859
|
+
# Function: GenericRegexpSkipUntilAfter
|
860
|
+
#
|
861
|
+
# Advances the position via <GenericRegexpSkip()> until a specific token is reached and passed.
|
862
|
+
#
|
863
|
+
sub GenericRegexpSkipUntilAfter #(indexRef, lineNumberRef, token)
|
864
|
+
{
|
865
|
+
my ($self, $indexRef, $lineNumberRef, $token) = @_;
|
866
|
+
my $tokens = $self->Tokens();
|
867
|
+
|
868
|
+
my $inBrackets = ( $token eq ']' );
|
869
|
+
|
870
|
+
while ($$indexRef < scalar @$tokens && $tokens->[$$indexRef] ne $token)
|
871
|
+
{ $self->GenericRegexpSkip($indexRef, $lineNumberRef, $inBrackets); };
|
872
|
+
|
873
|
+
if ($tokens->[$$indexRef] eq "\n")
|
874
|
+
{ $$lineNumberRef++; };
|
875
|
+
$$indexRef++;
|
876
|
+
};
|
877
|
+
|
878
|
+
|
879
|
+
#
|
880
|
+
# Function: SkipRestOfStatement
|
881
|
+
#
|
882
|
+
# Advances the position via <GenericSkip()> until after the end of the current statement, which is defined as a semicolon or
|
883
|
+
# a brace group. Of course, either of those appearing inside parenthesis, a nested brace group, etc. don't count.
|
884
|
+
#
|
885
|
+
sub SkipRestOfStatement #(indexRef, lineNumberRef)
|
886
|
+
{
|
887
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
888
|
+
my $tokens = $self->Tokens();
|
889
|
+
|
890
|
+
while ($$indexRef < scalar @$tokens &&
|
891
|
+
$tokens->[$$indexRef] ne ';' &&
|
892
|
+
!($tokens->[$$indexRef] eq '{' && !$self->IsStringed($$indexRef)) )
|
893
|
+
{
|
894
|
+
$self->GenericSkip($indexRef, $lineNumberRef);
|
895
|
+
};
|
896
|
+
|
897
|
+
if ($tokens->[$$indexRef] eq ';')
|
898
|
+
{ $$indexRef++; }
|
899
|
+
elsif ($tokens->[$$indexRef] eq '{')
|
900
|
+
{ $self->GenericSkip($indexRef, $lineNumberRef); };
|
901
|
+
};
|
902
|
+
|
903
|
+
|
904
|
+
#
|
905
|
+
# Function: TryToSkipWhitespace
|
906
|
+
#
|
907
|
+
# If the current position is on whitespace it skips them and returns true. If there are a number of these in a row, it skips them
|
908
|
+
# all.
|
909
|
+
#
|
910
|
+
# Supported Syntax:
|
911
|
+
#
|
912
|
+
# - Whitespace
|
913
|
+
# - Line break
|
914
|
+
# - All comment forms supported by <TryToSkipComment()>
|
915
|
+
# - Here Doc content
|
916
|
+
#
|
917
|
+
sub TryToSkipWhitespace #(indexRef, lineNumberRef)
|
918
|
+
{
|
919
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
920
|
+
my $tokens = $self->Tokens();
|
921
|
+
|
922
|
+
my $result;
|
923
|
+
|
924
|
+
while ($$indexRef < scalar @$tokens)
|
925
|
+
{
|
926
|
+
if ($self->TryToSkipHereDocContent($indexRef, $lineNumberRef) ||
|
927
|
+
$self->TryToSkipComment($indexRef, $lineNumberRef))
|
928
|
+
{
|
929
|
+
$result = 1;
|
930
|
+
}
|
931
|
+
elsif ($tokens->[$$indexRef] =~ /^[ \t]/)
|
932
|
+
{
|
933
|
+
$$indexRef++;
|
934
|
+
$result = 1;
|
935
|
+
}
|
936
|
+
elsif ($tokens->[$$indexRef] eq "\n")
|
937
|
+
{
|
938
|
+
$$indexRef++;
|
939
|
+
$$lineNumberRef++;
|
940
|
+
$result = 1;
|
941
|
+
}
|
942
|
+
else
|
943
|
+
{ last; };
|
944
|
+
};
|
945
|
+
|
946
|
+
return $result;
|
947
|
+
};
|
948
|
+
|
949
|
+
|
950
|
+
#
|
951
|
+
# Function: TryToSkipComment
|
952
|
+
# If the current position is on a comment, skip past it and return true.
|
953
|
+
#
|
954
|
+
sub TryToSkipComment #(indexRef, lineNumberRef)
|
955
|
+
{
|
956
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
957
|
+
|
958
|
+
return ( $self->TryToSkipLineComment($indexRef, $lineNumberRef) ||
|
959
|
+
$self->TryToSkipPODComment($indexRef, $lineNumberRef) );
|
960
|
+
};
|
961
|
+
|
962
|
+
|
963
|
+
#
|
964
|
+
# Function: TryToSkipLineComment
|
965
|
+
# If the current position is on a line comment symbol, skip past it and return true.
|
966
|
+
#
|
967
|
+
sub TryToSkipLineComment #(indexRef, lineNumberRef)
|
968
|
+
{
|
969
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
970
|
+
my $tokens = $self->Tokens();
|
971
|
+
|
972
|
+
# Note that $#var is not a comment.
|
973
|
+
if ($tokens->[$$indexRef] eq '#' && !$self->IsStringed($$indexRef))
|
974
|
+
{
|
975
|
+
$self->SkipRestOfLine($indexRef, $lineNumberRef);
|
976
|
+
return 1;
|
977
|
+
}
|
978
|
+
else
|
979
|
+
{ return undef; };
|
980
|
+
};
|
981
|
+
|
982
|
+
|
983
|
+
#
|
984
|
+
# Function: TryToSkipPODComment
|
985
|
+
# If the current position is on a POD comment symbol, skip past it and return true.
|
986
|
+
#
|
987
|
+
sub TryToSkipPODComment #(indexRef, lineNumberRef)
|
988
|
+
{
|
989
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
990
|
+
my $tokens = $self->Tokens();
|
991
|
+
|
992
|
+
# Note that whitespace is not allowed before the equals sign. It must directly start a line.
|
993
|
+
if ($tokens->[$$indexRef] eq '=' &&
|
994
|
+
( $$indexRef == 0 || $tokens->[$$indexRef - 1] eq "\n" ) &&
|
995
|
+
$tokens->[$$indexRef + 1] =~ /^[a-z]/i )
|
996
|
+
{
|
997
|
+
# Skip until =cut or (NDPODBREAK). Note that it's theoretically possible for =cut to appear without a prior POD directive.
|
998
|
+
|
999
|
+
do
|
1000
|
+
{
|
1001
|
+
if ($tokens->[$$indexRef] eq '=' && lc( $tokens->[$$indexRef + 1] ) eq 'cut')
|
1002
|
+
{
|
1003
|
+
$self->SkipRestOfLine($indexRef, $lineNumberRef);
|
1004
|
+
last;
|
1005
|
+
}
|
1006
|
+
elsif ($tokens->[$$indexRef] eq '(' && $$indexRef + 2 < scalar @$tokens &&
|
1007
|
+
$tokens->[$$indexRef+1] eq 'NDPODBREAK' && $tokens->[$$indexRef+2] eq ')')
|
1008
|
+
{
|
1009
|
+
$$indexRef += 3;
|
1010
|
+
last;
|
1011
|
+
}
|
1012
|
+
else
|
1013
|
+
{
|
1014
|
+
$self->SkipRestOfLine($indexRef, $lineNumberRef);
|
1015
|
+
};
|
1016
|
+
}
|
1017
|
+
while ($$indexRef < scalar @$tokens);
|
1018
|
+
|
1019
|
+
return 1;
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
# It's also possible that (NDPODBREAK) will appear without any opening pod statement because "=begin nd" and "=cut" will
|
1023
|
+
# still result in one. We need to pick off the stray (NDPODBREAK).
|
1024
|
+
elsif ($tokens->[$$indexRef] eq '(' && $$indexRef + 2 < scalar @$tokens &&
|
1025
|
+
$tokens->[$$indexRef+1] eq 'NDPODBREAK' && $tokens->[$$indexRef+2] eq ')')
|
1026
|
+
{
|
1027
|
+
$$indexRef += 3;
|
1028
|
+
return 1;
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
else
|
1032
|
+
{ return undef; };
|
1033
|
+
};
|
1034
|
+
|
1035
|
+
|
1036
|
+
#
|
1037
|
+
# Function: TryToSkipString
|
1038
|
+
# If the current position is on a string delimiter, skip past the string and return true.
|
1039
|
+
#
|
1040
|
+
# Parameters:
|
1041
|
+
#
|
1042
|
+
# indexRef - A reference to the index of the position to start at.
|
1043
|
+
# lineNumberRef - A reference to the line number of the position.
|
1044
|
+
# startContentIndexRef - A reference to the variable in which to store the index of the first content token. May be undef.
|
1045
|
+
# endContentIndexRef - A reference to the variable in which to store the index of the end of the content, which is one past
|
1046
|
+
# the last content token. may be undef.
|
1047
|
+
#
|
1048
|
+
# Returns:
|
1049
|
+
#
|
1050
|
+
# Whether the position was at a string. The index, line number, and content index variabls will only be changed if true.
|
1051
|
+
#
|
1052
|
+
# Syntax Support:
|
1053
|
+
#
|
1054
|
+
# - Supports quotes, apostrophes, backticks, q(), qq(), qx(), and qw().
|
1055
|
+
# - All symbols are supported for the letter forms.
|
1056
|
+
#
|
1057
|
+
sub TryToSkipString #(indexRef, lineNumberRef, startContentIndexRef, endContentIndexRef)
|
1058
|
+
{
|
1059
|
+
my ($self, $indexRef, $lineNumberRef, $startContentIndexRef, $endContentIndexRef) = @_;
|
1060
|
+
my $tokens = $self->Tokens();
|
1061
|
+
|
1062
|
+
# The three string delimiters. All three are Perl variables when preceded by a dollar sign.
|
1063
|
+
if (!$self->IsStringed($$indexRef) &&
|
1064
|
+
( $self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '\'', '\'', $startContentIndexRef, $endContentIndexRef) ||
|
1065
|
+
$self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '"', '"', $startContentIndexRef, $endContentIndexRef) ||
|
1066
|
+
$self->SUPER::TryToSkipString($indexRef, $lineNumberRef, '`', '`', $startContentIndexRef, $endContentIndexRef) ) )
|
1067
|
+
{
|
1068
|
+
return 1;
|
1069
|
+
}
|
1070
|
+
elsif ($tokens->[$$indexRef] =~ /^(?:q|qq|qx|qw)$/i &&
|
1071
|
+
($$indexRef == 0 || $tokens->[$$indexRef - 1] !~ /^[\$\%\@\*]$/))
|
1072
|
+
{
|
1073
|
+
$$indexRef++;
|
1074
|
+
|
1075
|
+
$self->TryToSkipWhitespace($indexRef, $lineNumberRef);
|
1076
|
+
|
1077
|
+
my $openingSymbol = $tokens->[$$indexRef];
|
1078
|
+
my $closingSymbol;
|
1079
|
+
|
1080
|
+
if ($openingSymbol eq '{')
|
1081
|
+
{ $closingSymbol = '}'; }
|
1082
|
+
elsif ($openingSymbol eq '(')
|
1083
|
+
{ $closingSymbol = ')'; }
|
1084
|
+
elsif ($openingSymbol eq '[')
|
1085
|
+
{ $closingSymbol = ']'; }
|
1086
|
+
elsif ($openingSymbol eq '<')
|
1087
|
+
{ $closingSymbol = '>'; }
|
1088
|
+
else
|
1089
|
+
{ $closingSymbol = $openingSymbol; };
|
1090
|
+
|
1091
|
+
$self->SUPER::TryToSkipString($indexRef, $lineNumberRef, $openingSymbol, $closingSymbol,
|
1092
|
+
$startContentIndexRef, $endContentIndexRef);
|
1093
|
+
|
1094
|
+
return 1;
|
1095
|
+
}
|
1096
|
+
else
|
1097
|
+
{ return undef; };
|
1098
|
+
};
|
1099
|
+
|
1100
|
+
|
1101
|
+
#
|
1102
|
+
# Function: TryToSkipHereDocDeclaration
|
1103
|
+
#
|
1104
|
+
# If the current position is on a Here Doc declaration, add its terminators to <hereDocTerminators> and skip it.
|
1105
|
+
#
|
1106
|
+
# Syntax Support:
|
1107
|
+
#
|
1108
|
+
# - Supports <<EOF
|
1109
|
+
# - Supports << "String" with all string forms supported by <TryToSkipString()>.
|
1110
|
+
#
|
1111
|
+
sub TryToSkipHereDocDeclaration #(indexRef, lineNumberRef)
|
1112
|
+
{
|
1113
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
1114
|
+
my $tokens = $self->Tokens();
|
1115
|
+
|
1116
|
+
my $index = $$indexRef;
|
1117
|
+
my $lineNumber = $$lineNumberRef;
|
1118
|
+
|
1119
|
+
if ($tokens->[$index] eq '<' && $tokens->[$index + 1] eq '<')
|
1120
|
+
{
|
1121
|
+
$index += 2;
|
1122
|
+
my $success;
|
1123
|
+
|
1124
|
+
# No whitespace allowed with the bare word.
|
1125
|
+
if ($tokens->[$index] =~ /^[a-z0-9_]/i)
|
1126
|
+
{
|
1127
|
+
push @hereDocTerminators, [ $tokens->[$index] ];
|
1128
|
+
$index++;
|
1129
|
+
$success = 1;
|
1130
|
+
}
|
1131
|
+
else
|
1132
|
+
{
|
1133
|
+
$self->TryToSkipWhitespace(\$index, \$lineNumber);
|
1134
|
+
|
1135
|
+
my ($contentStart, $contentEnd);
|
1136
|
+
if ($self->TryToSkipString(\$index, \$lineNumber, \$contentStart, \$contentEnd))
|
1137
|
+
{
|
1138
|
+
push @hereDocTerminators, [ @{$tokens}[$contentStart..$contentEnd - 1] ];
|
1139
|
+
$success = 1;
|
1140
|
+
};
|
1141
|
+
};
|
1142
|
+
|
1143
|
+
if ($success)
|
1144
|
+
{
|
1145
|
+
$$indexRef = $index;
|
1146
|
+
$$lineNumberRef = $lineNumber;
|
1147
|
+
|
1148
|
+
return 1;
|
1149
|
+
};
|
1150
|
+
};
|
1151
|
+
|
1152
|
+
return 0;
|
1153
|
+
};
|
1154
|
+
|
1155
|
+
|
1156
|
+
#
|
1157
|
+
# Function: TryToSkipHereDocContent
|
1158
|
+
#
|
1159
|
+
# If the current position is at the beginning of a line and there are entries in <hereDocTerminators>, skips lines until all the
|
1160
|
+
# terminators are exhausted or we reach the end of the file.
|
1161
|
+
#
|
1162
|
+
# Returns:
|
1163
|
+
#
|
1164
|
+
# Whether the position was on Here Doc content.
|
1165
|
+
#
|
1166
|
+
sub TryToSkipHereDocContent #(indexRef, lineNumberRef)
|
1167
|
+
{
|
1168
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
1169
|
+
my $tokens = $self->Tokens();
|
1170
|
+
|
1171
|
+
# We don't use IsFirstLineToken() because it really needs to be the first line token. Whitespace is not allowed.
|
1172
|
+
if ($$indexRef > 0 && $tokens->[$$indexRef - 1] eq "\n")
|
1173
|
+
{
|
1174
|
+
my $success = (scalar @hereDocTerminators > 0);
|
1175
|
+
|
1176
|
+
while (scalar @hereDocTerminators && $$indexRef < scalar @$tokens)
|
1177
|
+
{
|
1178
|
+
my $terminatorIndex = 0;
|
1179
|
+
|
1180
|
+
while ($hereDocTerminators[0]->[$terminatorIndex] eq $tokens->[$$indexRef])
|
1181
|
+
{
|
1182
|
+
$terminatorIndex++;
|
1183
|
+
$$indexRef++;
|
1184
|
+
};
|
1185
|
+
|
1186
|
+
if ($terminatorIndex == scalar @{$hereDocTerminators[0]} &&
|
1187
|
+
($tokens->[$$indexRef] eq "\n" || ($tokens->[$$indexRef] =~ /^[ \t]/ && $tokens->[$$indexRef + 1] eq "\n")) )
|
1188
|
+
{
|
1189
|
+
shift @hereDocTerminators;
|
1190
|
+
$$indexRef++;
|
1191
|
+
$$lineNumberRef++;
|
1192
|
+
}
|
1193
|
+
else
|
1194
|
+
{ $self->SkipRestOfLine($indexRef, $lineNumberRef); };
|
1195
|
+
};
|
1196
|
+
|
1197
|
+
return $success;
|
1198
|
+
}
|
1199
|
+
|
1200
|
+
else
|
1201
|
+
{ return 0; };
|
1202
|
+
};
|
1203
|
+
|
1204
|
+
|
1205
|
+
#
|
1206
|
+
# Function: TryToSkipRegexp
|
1207
|
+
# If the current position is on a regular expression or a quote-like operator, skip past it and return true.
|
1208
|
+
#
|
1209
|
+
# Syntax Support:
|
1210
|
+
#
|
1211
|
+
# - Supports //, ??, m//, qr//, s///, tr///, and y///.
|
1212
|
+
# - All symbols are supported for the letter forms.
|
1213
|
+
# - ?? is *not* supported because it could cause problems with ?: statements. The generic parser has a good chance of
|
1214
|
+
# successfully stumbling through a regex, whereas the regex code will almost certainly see the rest of the file as part of it.
|
1215
|
+
#
|
1216
|
+
sub TryToSkipRegexp #(indexRef, lineNumberRef)
|
1217
|
+
{
|
1218
|
+
my ($self, $indexRef, $lineNumberRef) = @_;
|
1219
|
+
my $tokens = $self->Tokens();
|
1220
|
+
|
1221
|
+
my $isRegexp;
|
1222
|
+
|
1223
|
+
# If it's a supported character sequence that's not a variable (ex $qr)...
|
1224
|
+
if ($tokens->[$$indexRef] =~ /^(?:m|qr|s|tr|y)$/i &&
|
1225
|
+
($$indexRef == 0 || $tokens->[$$indexRef - 1] !~ /^[\$\%\@\*\-]$/) )
|
1226
|
+
{ $isRegexp = 1; }
|
1227
|
+
|
1228
|
+
elsif ($tokens->[$$indexRef] eq '/' && !$self->IsStringed($$indexRef))
|
1229
|
+
{
|
1230
|
+
# This is a bit of a hack. If we find a random slash, it could be a divide operator or a bare regexp. Find the first previous
|
1231
|
+
# non-whitespace token and if it's text, a closing brace, or a string, assume it's a divide operator. (Strings don't make
|
1232
|
+
# much pratical sense there but a regexp would be impossible.) Otherwise assume it's a regexp.
|
1233
|
+
|
1234
|
+
# We make a special consideration for split() appearing without parenthesis. If the previous token is split and it's not a
|
1235
|
+
# variable, assume it is a regexp even though it fails the above test.
|
1236
|
+
|
1237
|
+
my $index = $$indexRef - 1;
|
1238
|
+
|
1239
|
+
while ($index >= 0 && $tokens->[$index] =~ /^(?: |\t|\n)/)
|
1240
|
+
{ $index--; };
|
1241
|
+
|
1242
|
+
if ($index < 0 || $tokens->[$index] !~ /^[a-zA-Z0-9_\)\]\}\'\"\`]/ ||
|
1243
|
+
($tokens->[$index] =~ /^split|grep$/ && $index > 0 && $tokens->[$index-1] !~ /^[\$\%\@\*]$/) )
|
1244
|
+
{ $isRegexp = 1; };
|
1245
|
+
};
|
1246
|
+
|
1247
|
+
if ($isRegexp)
|
1248
|
+
{
|
1249
|
+
my $operator = lc($tokens->[$$indexRef]);
|
1250
|
+
my $index = $$indexRef;
|
1251
|
+
my $lineNumber = $$lineNumberRef;
|
1252
|
+
|
1253
|
+
if ($operator =~ /^[\?\/]/)
|
1254
|
+
{ $operator = 'm'; }
|
1255
|
+
else
|
1256
|
+
{
|
1257
|
+
$index++;
|
1258
|
+
|
1259
|
+
# Believe it or not, s#...# is allowed. We can't pass over number signs here.
|
1260
|
+
if ($tokens->[$index] ne '#')
|
1261
|
+
{ $self->TryToSkipWhitespace(\$index, \$lineNumber); };
|
1262
|
+
};
|
1263
|
+
|
1264
|
+
if ($tokens->[$index] =~ /^\w/)
|
1265
|
+
{ return undef; };
|
1266
|
+
if ($tokens->[$index] eq '=' && $tokens->[$index+1] eq '>')
|
1267
|
+
{ return undef; };
|
1268
|
+
|
1269
|
+
my $openingSymbol = $tokens->[$index];
|
1270
|
+
my $closingSymbol;
|
1271
|
+
|
1272
|
+
if ($openingSymbol eq '{')
|
1273
|
+
{ $closingSymbol = '}'; }
|
1274
|
+
elsif ($openingSymbol eq '(')
|
1275
|
+
{ $closingSymbol = ')'; }
|
1276
|
+
elsif ($openingSymbol eq '[')
|
1277
|
+
{ $closingSymbol = ']'; }
|
1278
|
+
elsif ($openingSymbol eq '<')
|
1279
|
+
{ $closingSymbol = '>'; }
|
1280
|
+
else
|
1281
|
+
{ $closingSymbol = $openingSymbol; };
|
1282
|
+
|
1283
|
+
$index++;
|
1284
|
+
|
1285
|
+
$self->GenericRegexpSkipUntilAfter(\$index, \$lineNumber, $closingSymbol);
|
1286
|
+
|
1287
|
+
$$indexRef = $index;
|
1288
|
+
$$lineNumberRef = $lineNumber;
|
1289
|
+
|
1290
|
+
if ($operator =~ /^(?:s|tr|y)$/)
|
1291
|
+
{
|
1292
|
+
if ($openingSymbol ne $closingSymbol)
|
1293
|
+
{
|
1294
|
+
$self->TryToSkipWhitespace($indexRef, $lineNumberRef);
|
1295
|
+
|
1296
|
+
$openingSymbol = $tokens->[$index];
|
1297
|
+
|
1298
|
+
if ($openingSymbol eq '{')
|
1299
|
+
{ $closingSymbol = '}'; }
|
1300
|
+
elsif ($openingSymbol eq '(')
|
1301
|
+
{ $closingSymbol = ')'; }
|
1302
|
+
elsif ($openingSymbol eq '[')
|
1303
|
+
{ $closingSymbol = ']'; }
|
1304
|
+
elsif ($openingSymbol eq '<')
|
1305
|
+
{ $closingSymbol = '>'; }
|
1306
|
+
else
|
1307
|
+
{ $closingSymbol = $openingSymbol; };
|
1308
|
+
|
1309
|
+
$$indexRef++;
|
1310
|
+
};
|
1311
|
+
|
1312
|
+
if ($operator eq 's')
|
1313
|
+
{
|
1314
|
+
$self->GenericSkipUntilAfter($indexRef, $lineNumberRef, $closingSymbol, 1);
|
1315
|
+
}
|
1316
|
+
else # ($operator eq 'tr' || $operator eq 'y')
|
1317
|
+
{
|
1318
|
+
while ($$indexRef < scalar @$tokens &&
|
1319
|
+
($tokens->[$$indexRef] ne $closingSymbol || $self->IsBackslashed($$indexRef)) )
|
1320
|
+
{
|
1321
|
+
if ($tokens->[$$indexRef] eq "\n")
|
1322
|
+
{ $$lineNumberRef++; };
|
1323
|
+
$$indexRef++;
|
1324
|
+
};
|
1325
|
+
|
1326
|
+
$$indexRef++;
|
1327
|
+
};
|
1328
|
+
};
|
1329
|
+
|
1330
|
+
# We want to skip any letters after the regexp. Otherwise something like tr/a/b/s; could have the trailing s; interpreted
|
1331
|
+
# as another regexp. Whitespace is not allowed between the closing symbol and the letters.
|
1332
|
+
|
1333
|
+
if ($tokens->[$$indexRef] =~ /^[a-z]/i)
|
1334
|
+
{ $$indexRef++; };
|
1335
|
+
|
1336
|
+
return 1;
|
1337
|
+
};
|
1338
|
+
|
1339
|
+
return undef;
|
1340
|
+
};
|
1341
|
+
|
1342
|
+
|
1343
|
+
|
1344
|
+
###############################################################################
|
1345
|
+
# Group: Support Functions
|
1346
|
+
|
1347
|
+
|
1348
|
+
#
|
1349
|
+
# Function: IsStringed
|
1350
|
+
#
|
1351
|
+
# Returns whether the position is after a string (dollar sign) character. Returns false if it's preceded by two dollar signs so
|
1352
|
+
# "if ($x == $$)" doesn't skip the closing parenthesis as stringed.
|
1353
|
+
#
|
1354
|
+
# Parameters:
|
1355
|
+
#
|
1356
|
+
# index - The index of the postition.
|
1357
|
+
#
|
1358
|
+
sub IsStringed #(index)
|
1359
|
+
{
|
1360
|
+
my ($self, $index) = @_;
|
1361
|
+
my $tokens = $self->Tokens();
|
1362
|
+
|
1363
|
+
if ($index > 0 && $tokens->[$index - 1] eq '$' && !($index > 1 && $tokens->[$index - 2] eq '$'))
|
1364
|
+
{ return 1; }
|
1365
|
+
else
|
1366
|
+
{ return undef; };
|
1367
|
+
};
|
1368
|
+
|
1369
|
+
|
1370
|
+
1;
|