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.
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;