bixbite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +49 -0
  3. data/VERSION +1 -0
  4. data/bin/bixbite +73 -0
  5. data/lib/bixbite.rb +13 -0
  6. data/lib/bixbite/command.rb +14 -0
  7. data/lib/bixbite/create.rb +76 -0
  8. data/template/Rakefile +25 -0
  9. data/template/assets/bixbite/Rakefile.rb +297 -0
  10. data/template/assets/naturaldocs/NaturalDocs/Config/Languages.txt +286 -0
  11. data/template/assets/naturaldocs/NaturalDocs/Config/Topics.txt +382 -0
  12. data/template/assets/naturaldocs/NaturalDocs/Help/customizinglanguages.html +52 -0
  13. data/template/assets/naturaldocs/NaturalDocs/Help/customizingtopics.html +74 -0
  14. data/template/assets/naturaldocs/NaturalDocs/Help/documenting.html +58 -0
  15. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/reference.html +146 -0
  16. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/walkthrough.html +180 -0
  17. data/template/assets/naturaldocs/NaturalDocs/Help/example/Default.css +528 -0
  18. data/template/assets/naturaldocs/NaturalDocs/Help/example/NaturalDocs.js +204 -0
  19. data/template/assets/naturaldocs/NaturalDocs/Help/examples.css +90 -0
  20. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/background.png +0 -0
  21. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/leftside.png +0 -0
  22. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/logo.png +0 -0
  23. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbody.png +0 -0
  24. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbodybg.png +0 -0
  25. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overleftmargin.png +0 -0
  26. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenu.png +0 -0
  27. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenubg.png +0 -0
  28. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/rightside.png +0 -0
  29. data/template/assets/naturaldocs/NaturalDocs/Help/images/logo.gif +0 -0
  30. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/about.png +0 -0
  31. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/background.png +0 -0
  32. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomleft.png +0 -0
  33. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomright.png +0 -0
  34. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/community.png +0 -0
  35. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/customizing.png +0 -0
  36. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/using.png +0 -0
  37. data/template/assets/naturaldocs/NaturalDocs/Help/index.html +9 -0
  38. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/BrowserStyles.js +77 -0
  39. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/PNGHandling.js +72 -0
  40. data/template/assets/naturaldocs/NaturalDocs/Help/keywords.html +38 -0
  41. data/template/assets/naturaldocs/NaturalDocs/Help/languages.html +32 -0
  42. data/template/assets/naturaldocs/NaturalDocs/Help/menu.html +79 -0
  43. data/template/assets/naturaldocs/NaturalDocs/Help/output.html +84 -0
  44. data/template/assets/naturaldocs/NaturalDocs/Help/running.html +40 -0
  45. data/template/assets/naturaldocs/NaturalDocs/Help/styles.css +290 -0
  46. data/template/assets/naturaldocs/NaturalDocs/Help/styles.html +52 -0
  47. data/template/assets/naturaldocs/NaturalDocs/Help/troubleshooting.html +18 -0
  48. data/template/assets/naturaldocs/NaturalDocs/Info/CSSGuide.txt +947 -0
  49. data/template/assets/naturaldocs/NaturalDocs/Info/File Parsing.txt +83 -0
  50. data/template/assets/naturaldocs/NaturalDocs/Info/HTMLTestCases.pm +269 -0
  51. data/template/assets/naturaldocs/NaturalDocs/Info/Languages.txt +107 -0
  52. data/template/assets/naturaldocs/NaturalDocs/Info/NDMarkup.txt +91 -0
  53. data/template/assets/naturaldocs/NaturalDocs/Info/Symbol Management.txt +59 -0
  54. data/template/assets/naturaldocs/NaturalDocs/Info/images/Logo.png +0 -0
  55. data/template/assets/naturaldocs/NaturalDocs/JavaScript/NaturalDocs.js +836 -0
  56. data/template/assets/naturaldocs/NaturalDocs/License-GPL.txt +341 -0
  57. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/BinaryFile.pm +294 -0
  58. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder.pm +280 -0
  59. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/Base.pm +348 -0
  60. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/FramedHTML.pm +345 -0
  61. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTML.pm +398 -0
  62. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTMLBase.pm +3693 -0
  63. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy.pm +860 -0
  64. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/Class.pm +412 -0
  65. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/File.pm +157 -0
  66. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ConfigFile.pm +497 -0
  67. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Constants.pm +165 -0
  68. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/DefineMembers.pm +100 -0
  69. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Error.pm +305 -0
  70. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/File.pm +540 -0
  71. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable.pm +383 -0
  72. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm +44 -0
  73. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/String.pm +110 -0
  74. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages.pm +1475 -0
  75. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/ActionScript.pm +1473 -0
  76. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Ada.pm +38 -0
  77. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced.pm +828 -0
  78. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm +95 -0
  79. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm +70 -0
  80. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Base.pm +832 -0
  81. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/CSharp.pm +1484 -0
  82. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/PLSQL.pm +319 -0
  83. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Pascal.pm +143 -0
  84. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Perl.pm +1370 -0
  85. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype.pm +92 -0
  86. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm +87 -0
  87. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Simple.pm +503 -0
  88. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Tcl.pm +219 -0
  89. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu.pm +3406 -0
  90. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu/Entry.pm +201 -0
  91. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/NDMarkup.pm +76 -0
  92. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser.pm +1331 -0
  93. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/JavaDoc.pm +464 -0
  94. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/Native.pm +1060 -0
  95. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/ParsedTopic.pm +253 -0
  96. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project.pm +1402 -0
  97. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/ImageFile.pm +160 -0
  98. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/SourceFile.pm +113 -0
  99. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ReferenceString.pm +334 -0
  100. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings.pm +1418 -0
  101. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings/BuildTarget.pm +66 -0
  102. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB.pm +678 -0
  103. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Extension.pm +84 -0
  104. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/File.pm +129 -0
  105. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Item.pm +201 -0
  106. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm +45 -0
  107. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm +159 -0
  108. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/StatusMessage.pm +102 -0
  109. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolString.pm +212 -0
  110. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable.pm +1984 -0
  111. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/File.pm +186 -0
  112. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm +522 -0
  113. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Reference.pm +273 -0
  114. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm +97 -0
  115. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Symbol.pm +428 -0
  116. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm +96 -0
  117. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics.pm +1319 -0
  118. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics/Type.pm +151 -0
  119. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Version.pm +384 -0
  120. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs +400 -0
  121. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs.bat +17 -0
  122. data/template/assets/naturaldocs/NaturalDocs/Styles/Default.css +767 -0
  123. data/template/assets/naturaldocs/NaturalDocs/Styles/Roman.css +765 -0
  124. data/template/assets/naturaldocs/NaturalDocs/Styles/Small.css +763 -0
  125. data/template/assets/utilities/pngout +0 -0
  126. data/template/deploy/public_html/.htaccess +0 -0
  127. data/template/documentation/js/.htaccess +0 -0
  128. data/template/src/html/.htaccess +76 -0
  129. data/template/src/html/css/cmn/global.css +96 -0
  130. data/template/src/html/css/cmn/ie.css +15 -0
  131. data/template/src/html/css/cmn/ie6.css +15 -0
  132. data/template/src/html/images/cmn/.htaccess +0 -0
  133. data/template/src/html/images/tmp/.htaccess +0 -0
  134. data/template/src/html/includes/debug.inc +5 -0
  135. data/template/src/html/includes/footer.inc +52 -0
  136. data/template/src/html/includes/header.inc +61 -0
  137. data/template/src/html/includes/html.inc +3 -0
  138. data/template/src/html/includes/namespace.inc +19 -0
  139. data/template/src/html/includes/page.inc +151 -0
  140. data/template/src/html/index.html +35 -0
  141. data/template/src/html/js/cmn/bootstrap.js +74 -0
  142. data/template/src/html/js/cmn/global.js +142 -0
  143. data/template/src/html/js/cmn/lib/LAB.js +348 -0
  144. data/template/src/html/min/.htaccess +4 -0
  145. data/template/src/html/min/MinifyCLI.php +19 -0
  146. data/template/src/html/min/README.txt +132 -0
  147. data/template/src/html/min/builder/_index.js +242 -0
  148. data/template/src/html/min/builder/bm.js +36 -0
  149. data/template/src/html/min/builder/index.php +182 -0
  150. data/template/src/html/min/builder/ocCheck.php +36 -0
  151. data/template/src/html/min/builder/rewriteTest.js +1 -0
  152. data/template/src/html/min/config.php +187 -0
  153. data/template/src/html/min/groupsConfig.php +34 -0
  154. data/template/src/html/min/index.php +66 -0
  155. data/template/src/html/min/lib/FirePHP.php +1370 -0
  156. data/template/src/html/min/lib/HTTP/ConditionalGet.php +348 -0
  157. data/template/src/html/min/lib/HTTP/Encoder.php +326 -0
  158. data/template/src/html/min/lib/JSMin.php +314 -0
  159. data/template/src/html/min/lib/JSMinPlus.php +1872 -0
  160. data/template/src/html/min/lib/Minify.php +532 -0
  161. data/template/src/html/min/lib/Minify/Build.php +103 -0
  162. data/template/src/html/min/lib/Minify/CSS.php +83 -0
  163. data/template/src/html/min/lib/Minify/CSS/Compressor.php +250 -0
  164. data/template/src/html/min/lib/Minify/CSS/UriRewriter.php +270 -0
  165. data/template/src/html/min/lib/Minify/Cache/APC.php +130 -0
  166. data/template/src/html/min/lib/Minify/Cache/File.php +125 -0
  167. data/template/src/html/min/lib/Minify/Cache/Memcache.php +137 -0
  168. data/template/src/html/min/lib/Minify/ClosureCompiler.php +85 -0
  169. data/template/src/html/min/lib/Minify/CommentPreserver.php +90 -0
  170. data/template/src/html/min/lib/Minify/Controller/Base.php +202 -0
  171. data/template/src/html/min/lib/Minify/Controller/Files.php +78 -0
  172. data/template/src/html/min/lib/Minify/Controller/Groups.php +94 -0
  173. data/template/src/html/min/lib/Minify/Controller/MinApp.php +132 -0
  174. data/template/src/html/min/lib/Minify/Controller/Page.php +82 -0
  175. data/template/src/html/min/lib/Minify/Controller/Version1.php +118 -0
  176. data/template/src/html/min/lib/Minify/HTML.php +245 -0
  177. data/template/src/html/min/lib/Minify/ImportProcessor.php +157 -0
  178. data/template/src/html/min/lib/Minify/Lines.php +131 -0
  179. data/template/src/html/min/lib/Minify/Logger.php +45 -0
  180. data/template/src/html/min/lib/Minify/Packer.php +37 -0
  181. data/template/src/html/min/lib/Minify/Source.php +187 -0
  182. data/template/src/html/min/lib/Minify/YUICompressor.php +139 -0
  183. data/template/src/html/min/lib/Solar/Dir.php +199 -0
  184. data/template/src/html/min/lib/closure-compiler.jar +0 -0
  185. data/template/src/html/min/lib/yuicompressor-2.4.2.jar +0 -0
  186. data/template/src/html/min/utils.php +90 -0
  187. data/template/src/templates/css/template.css +7 -0
  188. data/template/src/templates/js/template.js +72 -0
  189. data/template/src/templates/template.html +18 -0
  190. data/template/src/yaml/config.yml +46 -0
  191. data/template/src/yaml/deploy.yml +35 -0
  192. data/test/bixbite_test.rb +7 -0
  193. data/test/test_helper.rb +10 -0
  194. 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;