yard 0.2.2 → 0.2.3
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.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/LICENSE +1 -1
- data/README.markdown +200 -0
- data/Rakefile +6 -1
- data/benchmarks/format_args.rb +46 -0
- data/benchmarks/parsing.rb +13 -1
- data/benchmarks/rdoc_vs_yardoc.rb +10 -0
- data/benchmarks/ripper_parser.rb +12 -0
- data/docs/CODE_OBJECTS.markdown +121 -0
- data/docs/FAQ.markdown +34 -0
- data/docs/GENERATORS.markdown +211 -0
- data/docs/GETTING_STARTED.markdown +263 -0
- data/docs/GLOSSARY.markdown +13 -0
- data/docs/HANDLERS.markdown +158 -0
- data/docs/OVERVIEW.markdown +64 -0
- data/docs/PARSER.markdown +180 -0
- data/docs/TAGS.markdown +181 -0
- data/docs/WHATSNEW.markdown +96 -0
- data/docs/images/code-objects-class-diagram.png +0 -0
- data/docs/images/handlers-class-diagram.png +0 -0
- data/docs/images/overview-class-diagram.png +0 -0
- data/docs/images/parser-class-diagram.png +0 -0
- data/docs/images/tags-class-diagram.png +0 -0
- data/lib/yard.rb +4 -1
- data/lib/yard/autoload.rb +79 -31
- data/lib/yard/cli/yard_graph.rb +8 -2
- data/lib/yard/cli/yardoc.rb +61 -8
- data/lib/yard/code_objects/base.rb +78 -135
- data/lib/yard/code_objects/class_object.rb +9 -8
- data/lib/yard/code_objects/constant_object.rb +1 -0
- data/lib/yard/code_objects/extended_method_object.rb +9 -0
- data/lib/yard/code_objects/method_object.rb +18 -5
- data/lib/yard/code_objects/module_object.rb +8 -1
- data/lib/yard/code_objects/namespace_object.rb +25 -16
- data/lib/yard/code_objects/proxy.rb +22 -22
- data/lib/yard/core_ext/file.rb +1 -1
- data/lib/yard/core_ext/string.rb +0 -4
- data/lib/yard/core_ext/symbol_hash.rb +3 -2
- data/lib/yard/docstring.rb +180 -0
- data/lib/yard/generators/base.rb +33 -13
- data/lib/yard/generators/class_generator.rb +4 -2
- data/lib/yard/generators/constants_generator.rb +3 -2
- data/lib/yard/generators/full_doc_generator.rb +76 -9
- data/lib/yard/generators/helpers/base_helper.rb +18 -1
- data/lib/yard/generators/helpers/filter_helper.rb +2 -2
- data/lib/yard/generators/helpers/html_helper.rb +94 -39
- data/lib/yard/generators/helpers/html_syntax_highlight_helper.rb +49 -0
- data/lib/yard/generators/helpers/markup_helper.rb +86 -0
- data/lib/yard/generators/helpers/method_helper.rb +23 -7
- data/lib/yard/generators/method_generator.rb +15 -3
- data/lib/yard/generators/method_listing_generator.rb +3 -3
- data/lib/yard/generators/mixins_generator.rb +8 -2
- data/lib/yard/generators/module_generator.rb +3 -2
- data/lib/yard/generators/overloads_generator.rb +20 -0
- data/lib/yard/generators/quick_doc_generator.rb +3 -9
- data/lib/yard/generators/root_generator.rb +32 -0
- data/lib/yard/generators/source_generator.rb +2 -17
- data/lib/yard/generators/tags_generator.rb +34 -6
- data/lib/yard/generators/uml_generator.rb +16 -6
- data/lib/yard/handlers/base.rb +88 -253
- data/lib/yard/handlers/processor.rb +72 -0
- data/lib/yard/handlers/ruby/alias_handler.rb +38 -0
- data/lib/yard/handlers/ruby/attribute_handler.rb +69 -0
- data/lib/yard/handlers/ruby/base.rb +72 -0
- data/lib/yard/handlers/ruby/class_condition_handler.rb +70 -0
- data/lib/yard/handlers/ruby/class_handler.rb +74 -0
- data/lib/yard/handlers/ruby/class_variable_handler.rb +11 -0
- data/lib/yard/handlers/ruby/constant_handler.rb +12 -0
- data/lib/yard/handlers/ruby/exception_handler.rb +22 -0
- data/lib/yard/handlers/ruby/extend_handler.rb +19 -0
- data/lib/yard/handlers/{alias_handler.rb → ruby/legacy/alias_handler.rb} +3 -4
- data/lib/yard/handlers/{attribute_handler.rb → ruby/legacy/attribute_handler.rb} +2 -2
- data/lib/yard/handlers/ruby/legacy/base.rb +198 -0
- data/lib/yard/handlers/{class_handler.rb → ruby/legacy/class_handler.rb} +18 -6
- data/lib/yard/handlers/{class_variable_handler.rb → ruby/legacy/class_variable_handler.rb} +1 -1
- data/lib/yard/handlers/{constant_handler.rb → ruby/legacy/constant_handler.rb} +2 -2
- data/lib/yard/handlers/{exception_handler.rb → ruby/legacy/exception_handler.rb} +3 -3
- data/lib/yard/handlers/ruby/legacy/extend_handler.rb +18 -0
- data/lib/yard/handlers/ruby/legacy/method_handler.rb +31 -0
- data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +28 -0
- data/lib/yard/handlers/{module_handler.rb → ruby/legacy/module_handler.rb} +1 -1
- data/lib/yard/handlers/{visibility_handler.rb → ruby/legacy/visibility_handler.rb} +1 -1
- data/lib/yard/handlers/{yield_handler.rb → ruby/legacy/yield_handler.rb} +4 -4
- data/lib/yard/handlers/ruby/method_condition_handler.rb +7 -0
- data/lib/yard/handlers/ruby/method_handler.rb +48 -0
- data/lib/yard/handlers/ruby/mixin_handler.rb +25 -0
- data/lib/yard/handlers/ruby/module_handler.rb +9 -0
- data/lib/yard/handlers/ruby/visibility_handler.rb +18 -0
- data/lib/yard/handlers/ruby/yield_handler.rb +28 -0
- data/lib/yard/parser/ruby/ast_node.rb +263 -0
- data/lib/yard/parser/{ruby_lex.rb → ruby/legacy/ruby_lex.rb} +258 -259
- data/lib/yard/parser/{statement.rb → ruby/legacy/statement.rb} +8 -4
- data/lib/yard/parser/ruby/legacy/statement_list.rb +262 -0
- data/lib/yard/parser/{token_list.rb → ruby/legacy/token_list.rb} +1 -1
- data/lib/yard/parser/ruby/ruby_parser.rb +307 -0
- data/lib/yard/parser/source_parser.rb +76 -45
- data/lib/yard/rake/yardoc_task.rb +6 -1
- data/lib/yard/registry.rb +45 -19
- data/lib/yard/serializers/file_system_serializer.rb +8 -3
- data/lib/yard/tags/default_factory.rb +70 -10
- data/lib/yard/tags/default_tag.rb +12 -0
- data/lib/yard/tags/library.rb +65 -26
- data/lib/yard/tags/option_tag.rb +12 -0
- data/lib/yard/tags/overload_tag.rb +62 -0
- data/lib/yard/tags/ref_tag.rb +7 -0
- data/lib/yard/tags/ref_tag_list.rb +27 -0
- data/lib/yard/tags/tag.rb +1 -0
- data/lib/yard/tags/tag_format_error.rb +6 -0
- data/spec/cli/yardoc_spec.rb +43 -0
- data/spec/code_objects/base_spec.rb +56 -68
- data/spec/code_objects/class_object_spec.rb +18 -6
- data/spec/code_objects/constants_spec.rb +2 -0
- data/spec/code_objects/method_object_spec.rb +33 -5
- data/spec/code_objects/module_object_spec.rb +66 -8
- data/spec/code_objects/namespace_object_spec.rb +37 -17
- data/spec/code_objects/proxy_spec.rb +13 -2
- data/spec/core_ext/string_spec.rb +14 -2
- data/spec/core_ext/symbol_hash_spec.rb +9 -3
- data/spec/docstring_spec.rb +139 -0
- data/spec/generators/full_doc_generator_spec.rb +29 -0
- data/spec/generators/helpers/html_helper_spec.rb +74 -0
- data/spec/generators/helpers/markup_helper_spec.rb +95 -0
- data/spec/handlers/alias_handler_spec.rb +16 -3
- data/spec/handlers/attribute_handler_spec.rb +1 -1
- data/spec/handlers/base_spec.rb +15 -141
- data/spec/handlers/class_condition_handler_spec.rb +49 -0
- data/spec/handlers/class_handler_spec.rb +44 -3
- data/spec/handlers/class_variable_handler_spec.rb +1 -1
- data/spec/handlers/constant_handler_spec.rb +1 -1
- data/spec/handlers/examples/alias_handler_001.rb.txt +7 -3
- data/spec/handlers/examples/class_condition_handler_001.rb.txt +61 -0
- data/spec/handlers/examples/class_handler_001.rb.txt +33 -0
- data/spec/handlers/examples/exception_handler_001.rb.txt +1 -1
- data/spec/handlers/examples/extend_handler_001.rb.txt +8 -0
- data/spec/handlers/examples/method_condition_handler_001.rb.txt +10 -0
- data/spec/handlers/examples/method_handler_001.rb.txt +16 -4
- data/spec/handlers/examples/mixin_handler_001.rb.txt +10 -2
- data/spec/handlers/examples/module_handler_001.rb.txt +4 -0
- data/spec/handlers/examples/visibility_handler_001.rb.txt +1 -1
- data/spec/handlers/exception_handler_spec.rb +2 -2
- data/spec/handlers/extend_handler_spec.rb +15 -0
- data/spec/handlers/legacy_base_spec.rb +128 -0
- data/spec/handlers/method_condition_handler_spec.rb +14 -0
- data/spec/handlers/method_handler_spec.rb +38 -5
- data/spec/handlers/mixin_handler_spec.rb +15 -7
- data/spec/handlers/module_handler_spec.rb +5 -1
- data/spec/handlers/processor_spec.rb +19 -0
- data/spec/handlers/ruby/base_spec.rb +90 -0
- data/spec/handlers/ruby/legacy/base_spec.rb +53 -0
- data/spec/handlers/spec_helper.rb +22 -16
- data/spec/handlers/visibility_handler_spec.rb +4 -4
- data/spec/handlers/yield_handler_spec.rb +1 -1
- data/spec/parser/ruby/ast_node_spec.rb +15 -0
- data/spec/parser/ruby/legacy/statement_list_spec.rb +145 -0
- data/spec/parser/{token_list_spec.rb → ruby/legacy/token_list_spec.rb} +4 -4
- data/spec/parser/source_parser_spec.rb +0 -15
- data/spec/rake/yardoc_task_spec.rb +48 -0
- data/spec/registry_spec.rb +28 -2
- data/spec/serializers/file_system_serializer_spec.rb +7 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/tags/default_factory_spec.rb +135 -0
- data/spec/tags/default_tag_spec.rb +11 -0
- data/spec/tags/overload_tag_spec.rb +35 -0
- data/spec/tags/ref_tag_list_spec.rb +53 -0
- data/templates/default/attributes/html/header.erb +17 -5
- data/templates/default/attributes/text/header.erb +1 -1
- data/templates/default/fulldoc/html/all_files.erb +19 -0
- data/templates/default/fulldoc/html/all_methods.erb +8 -7
- data/templates/default/fulldoc/html/all_namespaces.erb +4 -1
- data/templates/default/fulldoc/html/app.js +1 -1
- data/templates/default/fulldoc/html/{readme.erb → file.erb} +2 -2
- data/templates/default/fulldoc/html/header.erb +1 -1
- data/templates/default/fulldoc/html/index.erb +4 -3
- data/templates/default/fulldoc/html/style.css +13 -3
- data/templates/default/fulldoc/html/syntax_highlight.css +8 -5
- data/templates/default/method/text/header.erb +1 -0
- data/templates/default/method/text/title.erb +1 -0
- data/templates/default/methodsignature/html/main.erb +10 -8
- data/templates/default/methodsignature/text/main.erb +4 -1
- data/templates/default/methodsummary/html/summary.erb +8 -4
- data/templates/default/methodsummary/text/summary.erb +4 -1
- data/templates/default/mixins/html/header.erb +3 -3
- data/templates/default/overloads/html/header.erb +8 -0
- data/templates/default/overloads/text/header.erb +8 -0
- data/templates/default/root/html/header.erb +4 -0
- data/templates/default/tags/html/example.erb +20 -0
- data/templates/default/tags/html/option.erb +27 -0
- data/templates/default/tags/html/param.erb +21 -0
- data/templates/default/tags/html/tags.erb +4 -1
- data/templates/default/tags/html/todo.erb +8 -0
- data/templates/default/tags/text/example.erb +14 -0
- data/templates/default/tags/text/header.erb +3 -3
- data/templates/default/tags/text/option.erb +5 -0
- data/templates/default/tags/text/param.erb +9 -0
- data/templates/default/uml/dot/dependencies.erb +1 -1
- data/templates/default/uml/dot/info.erb +1 -1
- data/templates/default/uml/dot/superclasses.erb +2 -2
- data/templates/javadoc/methodsummary/html/summary.erb +2 -2
- data/templates/javadoc/mixins/html/header.erb +3 -3
- metadata +108 -139
- data/README +0 -211
- data/lib/yard/handlers/method_handler.rb +0 -27
- data/lib/yard/handlers/mixin_handler.rb +0 -16
- data/lib/yard/parser/statement_list.rb +0 -167
- data/lib/yard/tags/merbdoc_factory.rb +0 -47
@@ -1,5 +1,5 @@
|
|
1
1
|
module YARD
|
2
|
-
module Parser
|
2
|
+
module Parser::Ruby::Legacy
|
3
3
|
class Statement
|
4
4
|
attr_reader :tokens, :comments, :block
|
5
5
|
|
@@ -9,8 +9,7 @@ module YARD
|
|
9
9
|
@comments = comments
|
10
10
|
end
|
11
11
|
|
12
|
-
def inspect
|
13
|
-
flineno = tokens.first.line_no
|
12
|
+
def inspect
|
14
13
|
buf = [""]
|
15
14
|
tokens.each do |tk|
|
16
15
|
if tk.is_a?(RubyToken::TkNL)
|
@@ -19,7 +18,12 @@ module YARD
|
|
19
18
|
buf.last << tk.text
|
20
19
|
end
|
21
20
|
end
|
22
|
-
buf.map {|
|
21
|
+
buf.map {|text| "\t#{line}: #{text}" }.join("\n")
|
22
|
+
end
|
23
|
+
alias show inspect
|
24
|
+
|
25
|
+
def line
|
26
|
+
tokens.first.line_no
|
23
27
|
end
|
24
28
|
|
25
29
|
private
|
@@ -0,0 +1,262 @@
|
|
1
|
+
module YARD
|
2
|
+
module Parser::Ruby::Legacy
|
3
|
+
class StatementList < Array
|
4
|
+
include RubyToken
|
5
|
+
|
6
|
+
# The following list of tokens will require a block to be opened
|
7
|
+
# if used at the beginning of a statement.
|
8
|
+
OPEN_BLOCK_TOKENS = [TkCLASS, TkDEF, TkMODULE, TkUNTIL,
|
9
|
+
TkIF, TkUNLESS, TkWHILE, TkFOR, TkCASE]
|
10
|
+
|
11
|
+
##
|
12
|
+
# Creates a new statement list
|
13
|
+
#
|
14
|
+
# @param [TokenList, String] content the tokens to create the list from
|
15
|
+
def initialize(content)
|
16
|
+
if content.is_a? TokenList
|
17
|
+
@tokens = content.dup
|
18
|
+
elsif content.is_a? String
|
19
|
+
@tokens = TokenList.new(content)
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Invalid content for StatementList: #{content.inspect}:#{content.class}"
|
22
|
+
end
|
23
|
+
|
24
|
+
parse_statements
|
25
|
+
end
|
26
|
+
|
27
|
+
def enumerator
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parse_statements
|
34
|
+
while stmt = next_statement do self << stmt end
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Returns the next statement in the token stream
|
39
|
+
#
|
40
|
+
# @return [Statement] the next statement
|
41
|
+
def next_statement
|
42
|
+
@state = :first_statement
|
43
|
+
@statement_stack = []
|
44
|
+
@level = 0
|
45
|
+
@done = false
|
46
|
+
@current_block = nil
|
47
|
+
@statement, @block, @comments = TokenList.new, nil, nil
|
48
|
+
@last_tk, @last_ns_tk, @before_last_tk = nil, nil, nil
|
49
|
+
|
50
|
+
while !@done && tk = @tokens.shift
|
51
|
+
process_token(tk)
|
52
|
+
|
53
|
+
@before_last_tk = @last_tk
|
54
|
+
@last_tk = tk # Save last token
|
55
|
+
@last_ns_tk = tk unless [TkSPACE, TkNL, TkEND_OF_SCRIPT].include? tk.class
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the code block with starting token and initial comments
|
59
|
+
# If there is no code in the block, return nil
|
60
|
+
@comments = @comments.compact if @comments
|
61
|
+
if @block || !@statement.empty?
|
62
|
+
Statement.new(@statement, @block, @comments)
|
63
|
+
else
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Processes a single token
|
70
|
+
#
|
71
|
+
# @param [RubyToken::Token] tk the token to process
|
72
|
+
def process_token(tk)
|
73
|
+
case @state
|
74
|
+
when :first_statement
|
75
|
+
return if process_initial_comment(tk)
|
76
|
+
return if @statement.empty? && [TkSPACE, TkNL, TkCOMMENT].include?(tk.class)
|
77
|
+
return if process_simple_block_opener(tk)
|
78
|
+
push_token(tk)
|
79
|
+
return if process_complex_block_opener(tk)
|
80
|
+
|
81
|
+
if balances?(tk)
|
82
|
+
process_statement_end(tk)
|
83
|
+
else
|
84
|
+
@state = :balance
|
85
|
+
end
|
86
|
+
when :balance
|
87
|
+
@statement << tk
|
88
|
+
return unless balances?(tk)
|
89
|
+
@state = :first_statement
|
90
|
+
process_statement_end(tk)
|
91
|
+
when :block_statement
|
92
|
+
push_token(tk)
|
93
|
+
return unless balances?(tk)
|
94
|
+
process_statement_end(tk)
|
95
|
+
when :pre_block
|
96
|
+
@current_block = nil
|
97
|
+
process_block_token(tk) unless tk.class == TkSEMICOLON
|
98
|
+
@state = :block
|
99
|
+
when :block; process_block_token(tk)
|
100
|
+
when :post_block
|
101
|
+
if tk.class == TkSPACE
|
102
|
+
@statement << tk
|
103
|
+
return
|
104
|
+
end
|
105
|
+
|
106
|
+
process_statement_end(tk)
|
107
|
+
@state = :block
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Processes a token in a block
|
113
|
+
#
|
114
|
+
# @param [RubyToken::Token] tk the token to process
|
115
|
+
def process_block_token(tk)
|
116
|
+
@block << tk
|
117
|
+
return unless balances?(tk)
|
118
|
+
process_statement_end(tk)
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Processes a comment token that comes before a statement
|
123
|
+
#
|
124
|
+
# @param [RubyToken::Token] tk the token to process
|
125
|
+
# @return [Boolean] whether or not +tk+ was processed as an initial comment
|
126
|
+
def process_initial_comment(tk)
|
127
|
+
return unless tk.class == TkCOMMENT
|
128
|
+
|
129
|
+
# Two new-lines in a row will destroy any comment blocks
|
130
|
+
if @last_tk.class == TkNL && @before_last_tk &&
|
131
|
+
(@before_last_tk.class == TkNL || @before_last_tk.class == TkSPACE)
|
132
|
+
@comments = nil
|
133
|
+
return
|
134
|
+
end
|
135
|
+
|
136
|
+
# Remove the "#" and up to 1 space before the text
|
137
|
+
# Since, of course, the convention is to have "# text"
|
138
|
+
# and not "#text", which I deem ugly (you heard it here first)
|
139
|
+
@comments ||= []
|
140
|
+
@comments << tk.text.gsub(/^#+\s{0,1}/, '')
|
141
|
+
@comments.pop if @comments.size == 1 && @comments.first =~ /^\s*$/
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Processes a simple block-opening token;
|
147
|
+
# that is, a block opener such as +begin+ or +do+
|
148
|
+
# that isn't followed by an expression
|
149
|
+
#
|
150
|
+
# @param [RubyToken::Token] tk the token to process
|
151
|
+
def process_simple_block_opener(tk)
|
152
|
+
return unless [TkLBRACE, TkDO, TkBEGIN].include?(tk.class) &&
|
153
|
+
# Make sure hashes are parsed as hashes, not as blocks
|
154
|
+
(@last_ns_tk.nil? || @last_ns_tk.lex_state != EXPR_BEG)
|
155
|
+
|
156
|
+
@block = TokenList.new
|
157
|
+
@block << tk
|
158
|
+
@level += 1
|
159
|
+
@state = :block
|
160
|
+
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Processes a complex block-opening token;
|
166
|
+
# that is, a block opener such as +while+ or +for+
|
167
|
+
# that is followed by an expression
|
168
|
+
#
|
169
|
+
# @param [RubyToken::Token] tk the token to process
|
170
|
+
def process_complex_block_opener(tk)
|
171
|
+
return unless OPEN_BLOCK_TOKENS.include?(tk.class)
|
172
|
+
return if @last_ns_tk.class == TkALIAS
|
173
|
+
|
174
|
+
@current_block = tk.class
|
175
|
+
@state = :block_statement
|
176
|
+
|
177
|
+
true
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Processes a token that closes a statement
|
182
|
+
#
|
183
|
+
# @param [RubyToken::Token] tk the token to process
|
184
|
+
def process_statement_end(tk)
|
185
|
+
# Whitespace means that we keep the same value of @new_statement as last token
|
186
|
+
return if tk.class == TkSPACE
|
187
|
+
|
188
|
+
return unless
|
189
|
+
# We might be coming after a statement-ending token...
|
190
|
+
((@last_tk && [TkSEMICOLON, TkNL, TkEND_OF_SCRIPT].include?(tk.class)) ||
|
191
|
+
# Or we might be at the beginning of an argument list
|
192
|
+
(@current_block == TkDEF && tk.class == TkRPAREN))
|
193
|
+
|
194
|
+
# Continue a possible existing new statement unless we just finished an expression...
|
195
|
+
return unless (@last_tk && [EXPR_END, EXPR_ARG].include?(@last_tk.lex_state)) ||
|
196
|
+
# Or we've opened a block and are ready to move into the body
|
197
|
+
(@current_block && [TkNL, TkSEMICOLON].include?(tk.class) &&
|
198
|
+
# Handle the case where the block statement's expression is on the next line
|
199
|
+
#
|
200
|
+
# while
|
201
|
+
# foo
|
202
|
+
# end
|
203
|
+
@last_ns_tk.class != @current_block &&
|
204
|
+
# And the case where part of the expression is on the next line
|
205
|
+
#
|
206
|
+
# while foo ||
|
207
|
+
# bar
|
208
|
+
# end
|
209
|
+
@last_tk.lex_state != EXPR_BEG)
|
210
|
+
|
211
|
+
# Continue with the statement if we've hit a comma in a def
|
212
|
+
return if @current_block == TkDEF && peek_no_space.class == TkCOMMA
|
213
|
+
|
214
|
+
unless @current_block
|
215
|
+
@done = true
|
216
|
+
return
|
217
|
+
end
|
218
|
+
|
219
|
+
@level += 1
|
220
|
+
@state = :pre_block unless @stat == :block_statement
|
221
|
+
@block = TokenList.new
|
222
|
+
@block << tk if @current_block && tk.class == TkNL
|
223
|
+
end
|
224
|
+
|
225
|
+
##
|
226
|
+
# Handles the balancing of parentheses and blocks
|
227
|
+
#
|
228
|
+
# @param [RubyToken::Token] tk the token to process
|
229
|
+
# @return [Boolean] whether or not the current statement's parentheses and blocks
|
230
|
+
# are balanced after +tk+
|
231
|
+
def balances?(tk)
|
232
|
+
if [TkLPAREN, TkLBRACK, TkLBRACE, TkDO, TkBEGIN].include?(tk.class)
|
233
|
+
@level += 1
|
234
|
+
elsif OPEN_BLOCK_TOKENS.include?(tk.class)
|
235
|
+
@level += 1 unless @last_ns_tk.class == TkALIAS
|
236
|
+
elsif [TkRPAREN, TkRBRACK, TkRBRACE, TkEND].include?(tk.class) && @level > 0
|
237
|
+
@level -= 1
|
238
|
+
end
|
239
|
+
|
240
|
+
@level == 0
|
241
|
+
end
|
242
|
+
|
243
|
+
##
|
244
|
+
# Adds a token to the current statement,
|
245
|
+
# unless it's a newline, semicolon, or comment
|
246
|
+
#
|
247
|
+
# @param [RubyToken::Token] tk the token to process
|
248
|
+
def push_token(tk)
|
249
|
+
@statement << tk unless @level == 0 && [TkNL, TkSEMICOLON, TkCOMMENT].include?(tk.class)
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# Returns the next token in the stream that's not a space
|
254
|
+
#
|
255
|
+
# @return [RubyToken::Token] the next non-space token
|
256
|
+
def peek_no_space
|
257
|
+
return @tokens.first unless @tokens.first.class == TkSPACE
|
258
|
+
return @tokens[1]
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
|
3
|
+
module YARD
|
4
|
+
module Parser
|
5
|
+
module Ruby
|
6
|
+
class ParserSyntaxError < UndocumentableError; end
|
7
|
+
|
8
|
+
class RubyParser < Ripper
|
9
|
+
attr_reader :ast, :charno, :comments, :file, :tokens
|
10
|
+
alias root ast
|
11
|
+
|
12
|
+
def initialize(source, filename, *args)
|
13
|
+
super
|
14
|
+
@file = filename
|
15
|
+
@source = source
|
16
|
+
@tokens = []
|
17
|
+
@comments = {}
|
18
|
+
@map = {}
|
19
|
+
@ns_charno = 0
|
20
|
+
@list = []
|
21
|
+
@charno = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse
|
25
|
+
@ast = super
|
26
|
+
@ast.full_source = @source
|
27
|
+
@ast.file = @file
|
28
|
+
freeze_tree
|
29
|
+
insert_comments
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def enumerator
|
34
|
+
ast.children
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
MAPPINGS = {
|
40
|
+
:BEGIN => "BEGIN",
|
41
|
+
:END => "END",
|
42
|
+
:alias => "alias",
|
43
|
+
:array => :lbracket,
|
44
|
+
:aref => :lbracket,
|
45
|
+
:arg_paren => :lparen,
|
46
|
+
:begin => "begin",
|
47
|
+
:blockarg => "&",
|
48
|
+
:brace_block => :lbrace,
|
49
|
+
:break => "break",
|
50
|
+
:case => "case",
|
51
|
+
:class => "class",
|
52
|
+
:def => "def",
|
53
|
+
:defined => "defined?",
|
54
|
+
:defs => "def",
|
55
|
+
:do_block => "do",
|
56
|
+
:else => "else",
|
57
|
+
:elsif => "elsif",
|
58
|
+
:ensure => "ensure",
|
59
|
+
:for => "for",
|
60
|
+
:hash => :lbrace,
|
61
|
+
:if => "if",
|
62
|
+
:lambda => "lambda",
|
63
|
+
:module => "module",
|
64
|
+
:next => "next",
|
65
|
+
:paren => :lparen,
|
66
|
+
:qwords_literal => :qwords_beg,
|
67
|
+
:redo => "redo",
|
68
|
+
:regexp_literal => :regexp_beg,
|
69
|
+
:rescue => "rescue",
|
70
|
+
:rest_param => "*",
|
71
|
+
:retry => "retry",
|
72
|
+
:return => "return",
|
73
|
+
:return0 => "return",
|
74
|
+
:sclass => "class",
|
75
|
+
:string_embexpr => :embexpr_beg,
|
76
|
+
:string_literal => [:tstring_beg, :heredoc_beg],
|
77
|
+
:super => "super",
|
78
|
+
:symbol => :symbeg,
|
79
|
+
:undef => "undef",
|
80
|
+
:unless => "unless",
|
81
|
+
:until => "until",
|
82
|
+
:when => "when",
|
83
|
+
:while => "while",
|
84
|
+
:xstring_literal => :backtick,
|
85
|
+
:yield => "yield",
|
86
|
+
:yield0 => "yield",
|
87
|
+
:zsuper => "super"
|
88
|
+
}
|
89
|
+
REV_MAPPINGS = {}
|
90
|
+
|
91
|
+
AST_TOKENS = [:CHAR, :backref, :const, :cvar, :gvar, :heredoc_end, :ident,
|
92
|
+
:int, :float, :ivar, :period, :regexp_end, :tstring_content, :backtick]
|
93
|
+
|
94
|
+
MAPPINGS.each do |k, v|
|
95
|
+
if Array === v
|
96
|
+
v.each {|_v| (REV_MAPPINGS[_v] ||= []) << k }
|
97
|
+
else
|
98
|
+
(REV_MAPPINGS[v] ||= []) << k
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
PARSER_EVENT_TABLE.each do |event, arity|
|
103
|
+
node_class = AstNode.node_class_for(event)
|
104
|
+
|
105
|
+
if /_new\z/ =~ event and arity == 0
|
106
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
107
|
+
def on_#{event}(*args)
|
108
|
+
#{node_class}.new(:list, args, listchar: charno...charno, listline: lineno..lineno)
|
109
|
+
end
|
110
|
+
eof
|
111
|
+
elsif /_add(_.+)?\z/ =~ event
|
112
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
113
|
+
def on_#{event}(list, item)
|
114
|
+
list.push(item)
|
115
|
+
list
|
116
|
+
end
|
117
|
+
eof
|
118
|
+
elsif MAPPINGS.has_key?(event)
|
119
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
120
|
+
def on_#{event}(*args)
|
121
|
+
visit_event #{node_class}.new(:#{event}, args)
|
122
|
+
end
|
123
|
+
eof
|
124
|
+
else
|
125
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
126
|
+
def on_#{event}(*args)
|
127
|
+
#{node_class}.new(:#{event}, args, listline: lineno..lineno, listchar: charno...charno)
|
128
|
+
end
|
129
|
+
eof
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
SCANNER_EVENTS.each do |event|
|
134
|
+
ast_token = AST_TOKENS.include?(event)
|
135
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
136
|
+
def on_#{event}(tok)
|
137
|
+
visit_ns_token(:#{event}, tok, #{ast_token.inspect})
|
138
|
+
end
|
139
|
+
eof
|
140
|
+
end
|
141
|
+
|
142
|
+
REV_MAPPINGS.select {|k| k.is_a?(Symbol) }.each do |event, value|
|
143
|
+
ast_token = AST_TOKENS.include?(event)
|
144
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
145
|
+
def on_#{event}(tok)
|
146
|
+
(@map[:#{event}] ||= []) << [lineno, charno]
|
147
|
+
visit_ns_token(:#{event}, tok, #{ast_token.inspect})
|
148
|
+
end
|
149
|
+
eof
|
150
|
+
end
|
151
|
+
|
152
|
+
[:kw, :op].each do |event|
|
153
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
154
|
+
def on_#{event}(tok)
|
155
|
+
unless @tokens.last && @tokens.last[0] == :symbeg
|
156
|
+
(@map[tok] ||= []) << [lineno, charno]
|
157
|
+
end
|
158
|
+
visit_ns_token(:#{event}, tok, true)
|
159
|
+
end
|
160
|
+
eof
|
161
|
+
end
|
162
|
+
|
163
|
+
[:sp, :nl, :ignored_nl].each do |event|
|
164
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
165
|
+
def on_#{event}(tok)
|
166
|
+
add_token(:#{event}, tok)
|
167
|
+
@charno += tok.length
|
168
|
+
end
|
169
|
+
eof
|
170
|
+
end
|
171
|
+
|
172
|
+
def visit_event(node)
|
173
|
+
lstart, sstart = *@map[MAPPINGS[node.type]].pop
|
174
|
+
node.source_range = Range.new(sstart, @ns_charno - 1)
|
175
|
+
node.line_range = Range.new(lstart, lineno)
|
176
|
+
node
|
177
|
+
end
|
178
|
+
|
179
|
+
def visit_event_arr(node)
|
180
|
+
mapping = MAPPINGS[node.type].find {|k| @map[k] && !@map[k].empty? }
|
181
|
+
lstart, sstart = *@map[mapping].pop
|
182
|
+
node.source_range = Range.new(sstart, @ns_charno - 1)
|
183
|
+
node.line_range = Range.new(lstart, lineno)
|
184
|
+
node
|
185
|
+
end
|
186
|
+
|
187
|
+
def visit_ns_token(token, data, ast_token = false)
|
188
|
+
add_token(token, data)
|
189
|
+
ch = charno
|
190
|
+
@charno += data.length
|
191
|
+
@ns_charno = charno
|
192
|
+
if ast_token
|
193
|
+
AstNode.new(token, [data], line: lineno..lineno, char: ch..charno-1, token: true)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def add_token(token, data)
|
198
|
+
if @tokens.last && @tokens.last[0] == :symbeg
|
199
|
+
@tokens[-1] = [:symbol, ":" + data]
|
200
|
+
else
|
201
|
+
@tokens << [token, data]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def on_program(*args)
|
206
|
+
args.first
|
207
|
+
end
|
208
|
+
|
209
|
+
def on_body_stmt(*args)
|
210
|
+
args.first
|
211
|
+
end
|
212
|
+
|
213
|
+
def on_hash(*args)
|
214
|
+
visit_event AstNode.new(:hash, [args.first], listline: lineno..lineno, listchar: charno...charno)
|
215
|
+
end
|
216
|
+
|
217
|
+
def on_assoc_new(*args)
|
218
|
+
AstNode.new(:assoc, args)
|
219
|
+
end
|
220
|
+
|
221
|
+
def on_bare_assoc_hash(*args)
|
222
|
+
args.first
|
223
|
+
end
|
224
|
+
|
225
|
+
def on_assoclist_from_args(*args)
|
226
|
+
args.first
|
227
|
+
end
|
228
|
+
|
229
|
+
def on_qwords_new
|
230
|
+
visit_event AstNode.new(:qwords_literal, [])
|
231
|
+
end
|
232
|
+
|
233
|
+
def on_string_literal(*args)
|
234
|
+
visit_event_arr AstNode.new(:string_literal, args)
|
235
|
+
end
|
236
|
+
|
237
|
+
def on_string_content(*args)
|
238
|
+
AstNode.new(:string_content, args, listline: lineno..lineno, listchar: charno..charno)
|
239
|
+
end
|
240
|
+
|
241
|
+
def on_void_stmt
|
242
|
+
AstNode.new(:void_stmt, [], line: lineno..lineno, char: charno...charno)
|
243
|
+
end
|
244
|
+
|
245
|
+
def on_params(*args)
|
246
|
+
args.map! do |arg|
|
247
|
+
if arg.class == Array
|
248
|
+
if arg.first.class == Array
|
249
|
+
arg.map! do |sub_arg|
|
250
|
+
if sub_arg.class == Array
|
251
|
+
AstNode.new(:default_arg, sub_arg, listline: lineno..lineno, listchar: charno..charno)
|
252
|
+
else
|
253
|
+
sub_arg
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
AstNode.new(:list, arg, listline: lineno..lineno, listchar: charno..charno)
|
258
|
+
else
|
259
|
+
arg
|
260
|
+
end
|
261
|
+
end
|
262
|
+
ParameterNode.new(:params, args, listline: lineno..lineno, listchar: charno..charno)
|
263
|
+
end
|
264
|
+
|
265
|
+
def on_comment(comment)
|
266
|
+
visit_ns_token(:comment, comment)
|
267
|
+
|
268
|
+
comment = comment.gsub(/^\#{1,2}\s{0,1}/, '').chomp
|
269
|
+
append_comment = @comments[lineno - 1]
|
270
|
+
|
271
|
+
if append_comment
|
272
|
+
@comments.delete(lineno - 1)
|
273
|
+
comment = append_comment + "\n" + comment
|
274
|
+
end
|
275
|
+
|
276
|
+
@comments[lineno] = comment
|
277
|
+
end
|
278
|
+
|
279
|
+
def on_parse_error(msg)
|
280
|
+
raise ParserSyntaxError, "syntax error in `#{file}`:(#{lineno},#{column}): #{msg}"
|
281
|
+
end
|
282
|
+
|
283
|
+
def insert_comments
|
284
|
+
root.traverse do |node|
|
285
|
+
next if node.type == :list || node.parent.type != :list
|
286
|
+
node.line.downto(node.line - 2) do |line|
|
287
|
+
comment = @comments[line]
|
288
|
+
if comment && !comment.empty?
|
289
|
+
node.docstring = comment
|
290
|
+
comments.delete(line)
|
291
|
+
break
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def freeze_tree(node = nil)
|
298
|
+
node ||= root
|
299
|
+
node.children.each do |child|
|
300
|
+
child.parent = node
|
301
|
+
freeze_tree(child)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|