rdtool 0.6.23

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 (94) hide show
  1. data/COPYING.txt +674 -0
  2. data/Gemfile +9 -0
  3. data/HISTORY +284 -0
  4. data/LICENSE.txt +58 -0
  5. data/MANIFEST +89 -0
  6. data/README.html +44 -0
  7. data/README.ja.html +46 -0
  8. data/README.rd +52 -0
  9. data/README.rd.ja +54 -0
  10. data/Rakefile +29 -0
  11. data/TODO +15 -0
  12. data/VERSION +1 -0
  13. data/bin/rd2 +281 -0
  14. data/bin/rdswap.rb +207 -0
  15. data/doc/rd-draft.rd +479 -0
  16. data/doc/rd-draft.rd.ja +487 -0
  17. data/lib/rd/block-element.rb +114 -0
  18. data/lib/rd/complex-list-item.rb +65 -0
  19. data/lib/rd/desclist.rb +55 -0
  20. data/lib/rd/document-struct.rb +46 -0
  21. data/lib/rd/dot.rd2rc +18 -0
  22. data/lib/rd/element.rb +160 -0
  23. data/lib/rd/filter.rb +255 -0
  24. data/lib/rd/inline-element.rb +233 -0
  25. data/lib/rd/labeled-element.rb +14 -0
  26. data/lib/rd/list.rb +57 -0
  27. data/lib/rd/loose-struct.rb +11 -0
  28. data/lib/rd/methodlist.rb +57 -0
  29. data/lib/rd/output-format-visitor.rb +28 -0
  30. data/lib/rd/package.rb +4 -0
  31. data/lib/rd/parser-util.rb +14 -0
  32. data/lib/rd/post-install +1 -0
  33. data/lib/rd/rbl-file.rb +69 -0
  34. data/lib/rd/rbl-suite.rb +37 -0
  35. data/lib/rd/rd-struct.rb +86 -0
  36. data/lib/rd/rd2html-lib.rb +490 -0
  37. data/lib/rd/rd2html-opt.rb +67 -0
  38. data/lib/rd/rd2man-lib.rb +241 -0
  39. data/lib/rd/rd2rdo-lib.rb +19 -0
  40. data/lib/rd/rd2rmi-lib.rb +32 -0
  41. data/lib/rd/rdblockparser.ry +518 -0
  42. data/lib/rd/rdblockparser.tab.rb +1050 -0
  43. data/lib/rd/rdfmt.rb +15 -0
  44. data/lib/rd/rdinlineparser.ry +503 -0
  45. data/lib/rd/rdinlineparser.tab.rb +1243 -0
  46. data/lib/rd/rdvisitor.rb +214 -0
  47. data/lib/rd/reference-resolver.rb +114 -0
  48. data/lib/rd/search-file.rb +14 -0
  49. data/lib/rd/tree.rb +103 -0
  50. data/lib/rd/version.rb +39 -0
  51. data/lib/rd/visitor.rb +86 -0
  52. data/makerdtool.rb +75 -0
  53. data/setup.rb +1596 -0
  54. data/test.rb +33 -0
  55. data/test/data/includee1.html +1 -0
  56. data/test/data/includee2.html +1 -0
  57. data/test/data/includee3.nothtml +1 -0
  58. data/test/data/includee4.xhtml +0 -0
  59. data/test/data/label.rbl +2 -0
  60. data/test/data/label2.rbl +2 -0
  61. data/test/data/sub/includee2.html +1 -0
  62. data/test/data/sub/includee4.html +0 -0
  63. data/test/dummy-observer.rb +6 -0
  64. data/test/dummy.rb +33 -0
  65. data/test/temp-dir.rb +19 -0
  66. data/test/test-block-parser.rb +46 -0
  67. data/test/test-desclist-item.rb +219 -0
  68. data/test/test-document-element.rb +46 -0
  69. data/test/test-document-struct.rb +66 -0
  70. data/test/test-element.rb +46 -0
  71. data/test/test-headline.rb +80 -0
  72. data/test/test-inline-parser.rb +46 -0
  73. data/test/test-list-item.rb +54 -0
  74. data/test/test-list.rb +53 -0
  75. data/test/test-methodlist-item.rb +73 -0
  76. data/test/test-nonterminal-element.rb +170 -0
  77. data/test/test-nonterminal-inline.rb +33 -0
  78. data/test/test-output-format-visitor.rb +48 -0
  79. data/test/test-parser-util.rb +41 -0
  80. data/test/test-rbl-file.rb +156 -0
  81. data/test/test-rbl-suite.rb +43 -0
  82. data/test/test-rd2html-lib.rb +496 -0
  83. data/test/test-rdtree.rb +17 -0
  84. data/test/test-rdvisitor.rb +29 -0
  85. data/test/test-reference-resolver.rb +202 -0
  86. data/test/test-reference.rb +132 -0
  87. data/test/test-search-file.rb +22 -0
  88. data/test/test-terminal-inline.rb +41 -0
  89. data/test/test-textblock.rb +44 -0
  90. data/test/test-tree.rb +82 -0
  91. data/test/test-version.rb +57 -0
  92. data/test/test-visitor.rb +230 -0
  93. data/utils/rd-mode.el +425 -0
  94. metadata +203 -0
@@ -0,0 +1,67 @@
1
+ =begin
2
+ = rd2html-opt.rb
3
+ sub-OptionParser for rd2html-lib.rb.
4
+ =end
5
+ require "optparse"
6
+
7
+ q = ARGV.options
8
+
9
+ q.on_tail("rd2html-lib options:")
10
+
11
+
12
+ #q.on_tail("--use-numbering-anchor",
13
+ # "use number for anchor name (old style)") do
14
+ # $Visitor.use_old_anchor = true
15
+ #end
16
+
17
+ q.on_tail("--output-rbl",
18
+ "output external Label file") do
19
+ $Visitor.output_rbl = true
20
+ end
21
+
22
+ q.on_tail("--with-css=FILE",
23
+ String,
24
+ "use FILE as CSS of output HTML") do |i|
25
+ $Visitor.css = i
26
+ end
27
+
28
+ q.on_tail("--html-charset=CHARSET",
29
+ String,
30
+ "indicate CHARSET as charset(char encoding)") do |i|
31
+ $Visitor.charset = i
32
+ end
33
+
34
+ q.on_tail("--html-lang=LANG",
35
+ String,
36
+ "indicate LANG as lang attribute of html") do |i|
37
+ $Visitor.lang = i
38
+ end
39
+
40
+ q.on_tail("--html-title=TITLE",
41
+ String,
42
+ "content of TITLE element of HTML") do |i|
43
+ $Visitor.title = i
44
+ end
45
+
46
+ q.on_tail("--html-link-rel=REL",
47
+ String,
48
+ "add forward LINK element.(\"<rel>:<href>\")") do |i|
49
+ if /(\w+):(.+)/ =~ i
50
+ $Visitor.html_link_rel[$1] = $2
51
+ else
52
+ # warning
53
+ end
54
+ end
55
+
56
+ q.on_tail("--html-link-rev=REV",
57
+ String,
58
+ "add reverse LINK element.(\"<rev>:<href>\")") do |i|
59
+ if /(\w+):(.+)/ =~ i
60
+ $Visitor.html_link_rev[$1] = $2
61
+ else
62
+ # warning
63
+ end
64
+ end
65
+
66
+
67
+
@@ -0,0 +1,241 @@
1
+ =begin
2
+ = rd/rd2man-lib.rb
3
+ =end
4
+
5
+ require "rd/rdvisitor"
6
+
7
+ unless [].respond_to? :collect!
8
+ class Array
9
+ alias collect! filter
10
+ end
11
+ end
12
+
13
+ module RD
14
+ class RD2MANVisitor < RDVisitor
15
+ include AutoLabel
16
+ include MethodParse
17
+
18
+ SYSTEM_NAME = "RDtool -- RD2ManVisitor"
19
+ SYSTEM_VERSION = "$Version: 0.6.23$" #"
20
+ VERSION = Version.new_from_version_string(SYSTEM_NAME, SYSTEM_VERSION)
21
+
22
+ def self.version
23
+ VERSION
24
+ end
25
+
26
+ # must-have constants
27
+ OUTPUT_SUFFIX = "1"
28
+ INCLUDE_SUFFIX = ["1"]
29
+
30
+ def initialize
31
+ @enumcounter = 0
32
+ @index = {}
33
+ @filename = nil
34
+ end
35
+
36
+ def visit(tree)
37
+ prepare_labels(tree, "")
38
+ super(tree)
39
+ end
40
+
41
+ def apply_to_DocumentElement(element, content)
42
+ content = content.join
43
+ title = @filename || ARGF.filename || "Untitled"
44
+ title = File.basename title
45
+ title = title.sub(/\.rd$/i, '')
46
+ <<"EOT"
47
+ .\\" DO NOT MODIFY THIS FILE! it was generated by rd2
48
+ .TH #{title} 1 "#{Time.now.strftime '%B %Y'}"
49
+ #{content}
50
+ EOT
51
+ end # "
52
+
53
+ def apply_to_Headline(element, title)
54
+ element.level <= 1 ? ".SH #{title}\n" : ".SS #{title}\n"
55
+ end
56
+
57
+ # RDVisitor#apply_to_Include
58
+
59
+ def apply_to_TextBlock(element, content)
60
+ if RD::DescListItem === element.parent ||
61
+ RD::ItemListItem === element.parent ||
62
+ RD::EnumListItem === element.parent
63
+ return content.join
64
+ else
65
+ return ".PP\n" + content.join
66
+ end
67
+ end
68
+
69
+ def apply_to_Verbatim(element)
70
+ content = []
71
+ element.each_line do |i|
72
+ content.push(apply_to_String(i))
73
+ end
74
+ # Can we use BLOCKQUOTE such like?
75
+ %Q[.nf\n\\& #{content.join("\\& ")}.fi\n]
76
+ end
77
+
78
+ def apply_to_ItemList(element, items)
79
+ items.collect! do |x| x.sub(/\n\n/, "\n") end
80
+ items = items.join(".IP\n.B\n\\(bu\n") # "\\(bu" -> "" ?
81
+ ".IP\n.B\n\\(bu\n" + items
82
+ end
83
+
84
+ def apply_to_EnumList(element, items)
85
+ @enumcounter = 0
86
+ items.join
87
+ end
88
+
89
+ def apply_to_DescList(element, items)
90
+ items.map{ |i| i =~ /\n$/ ? i : i + "\n" }.join("")
91
+ end
92
+
93
+ def apply_to_MethodList(element, items)
94
+ items.map{ |i| i =~ /\n$/ ? i : i + "\n" }.join("")
95
+ end
96
+
97
+ def apply_to_ItemListItem(element, content)
98
+ content.map{ |c| c =~ /\n$/ ? c : c + "\n" }.join("")
99
+ end
100
+
101
+ def apply_to_EnumListItem(element, content)
102
+ @enumcounter += 1
103
+ %Q[.TP\n#{@enumcounter}.\n#{content.join("\n")}]
104
+ end
105
+
106
+ def apply_to_DescListItem(element, term, description)
107
+ anchor = refer(element)
108
+ if description.empty?
109
+ ".TP\n.fi\n.B\n#{term}"
110
+ else
111
+ %[.TP\n.fi\n.B\n#{term}\n#{description.join("\n")}].chomp
112
+ end
113
+ end
114
+
115
+ def apply_to_MethodListItem(element, term, description)
116
+ term = parse_method(term) # maybe: term -> element.term
117
+ anchor = refer(element)
118
+ if description.empty?
119
+ ".TP\n.fi\n.B\n#{term}"
120
+ else
121
+ %[.TP\n.fi\n.B\n#{term}\n#{description.join("\n")}]
122
+ end
123
+ end
124
+
125
+ def parse_method(method)
126
+ klass, kind, method, args = MethodParse.analize_method(method)
127
+
128
+ if kind == :function
129
+ klass = kind = nil
130
+ else
131
+ kind = MethodParse.kind2str(kind)
132
+ end
133
+
134
+ case method
135
+ when "[]"
136
+ args.strip!
137
+ args.sub!(/^\((.*)\)$/, '\\1')
138
+ "#{klass}#{kind}[#{args}]"
139
+ when "[]="
140
+ args.strip!
141
+ args.sub!(/^\((.*)\)$/, '\\1')
142
+ args, val = /^(.*),([^,]*)$/.match(args)[1,2]
143
+ args.strip!
144
+ val.strip!
145
+
146
+ "#{klass}#{kind}[#{args}] = #{val}"
147
+ else
148
+ "#{klass}#{kind}#{method}#{args}"
149
+ end
150
+ end
151
+ private :parse_method
152
+
153
+ def apply_to_StringElement(element)
154
+ apply_to_String(element.content)
155
+ end
156
+
157
+ def apply_to_Emphasis(element, content)
158
+ %Q[\\fI#{content.join}\\fP]
159
+ end
160
+
161
+ def apply_to_Code(element, content)
162
+ %{\\&\\fB#{content.join.sub(/\./, '\\.')}\\fP}
163
+ end
164
+
165
+ def apply_to_Var(element, content)
166
+ content.join
167
+ end
168
+
169
+ def apply_to_Keyboard(element, content)
170
+ content.join
171
+ end
172
+
173
+ def apply_to_Index(element, content)
174
+ tmp = []
175
+ element.each do |i|
176
+ tmp.push(i) if i.is_a?(String)
177
+ end
178
+ key = meta_char_escape(tmp.join)
179
+ if @index.has_key?(key)
180
+ # warning?
181
+ ""
182
+ else
183
+ num = @index[key] = @index.size
184
+ %{\\&\\fB#{content.join.sub(/\./, '\\.')}\\fP}
185
+ end
186
+ end
187
+
188
+ def apply_to_Reference(element, content)
189
+ case element.label
190
+ when Reference::URL
191
+ apply_to_RefToURL(element, content)
192
+ when Reference::RDLabel
193
+ if element.label.filename
194
+ apply_to_RefToOtherFile(element, content)
195
+ else
196
+ apply_to_RefToElement(element, content)
197
+ end
198
+ end
199
+ end
200
+
201
+ def apply_to_RefToElement(element, content)
202
+ content = content.join
203
+ content.sub(/^function#/, "")
204
+ end
205
+
206
+ def apply_to_RefToOtherFile(element, content)
207
+ content.join
208
+ end
209
+
210
+ def apply_to_RefToURL(element, content)
211
+ content.join
212
+ end
213
+
214
+ def apply_to_Footnote(element, content)
215
+ ""
216
+ end
217
+
218
+ def apply_to_Verb(element)
219
+ apply_to_String(element.content)
220
+ end
221
+
222
+ def apply_to_String(element)
223
+ meta_char_escape(element)
224
+ end
225
+
226
+ def meta_char_escape(str)
227
+ str.gsub(/[-\\]/, '\\\\\\&').gsub(/^[.']/, '\\&') # '
228
+ end
229
+ private :meta_char_escape
230
+
231
+ end # RD2MANVisitor
232
+ end # RD
233
+
234
+ $Visitor_Class = RD::RD2MANVisitor
235
+
236
+ =begin
237
+ == script info.
238
+ RD to MAN translate library for rdfmt.rb
239
+ $Id: rd2man-lib.rb,v 1.9 2003/08/02 15:45:49 tosh Exp $
240
+ copyright WATANABE Hirofumi <eban@os.rim.or.jp>, 2000
241
+ =end
@@ -0,0 +1,19 @@
1
+ =begin
2
+ = rd2rdo-lib.rb
3
+ Format lib to dump tree objects.
4
+ =end
5
+
6
+ require "rd/rdvisitor"
7
+
8
+ module RD
9
+ class RD2RDOVisitor < RDVisitor
10
+ OUTPUT_SUFFIX = "rdo"
11
+ INCLUDE_SUFFIX = []
12
+
13
+ def visit(tree)
14
+ Marshal.dump(tree)
15
+ end
16
+ end
17
+ end
18
+
19
+ $Visitor_Class = RD::RD2RDOVisitor
@@ -0,0 +1,32 @@
1
+ =begin
2
+ = rd2rmi-lib.rb
3
+ library to output RMI.
4
+ =end
5
+ require "rd/rdvisitor"
6
+
7
+ module RD
8
+ class RD2RMIVisitor < RDVisitor
9
+ include AutoLabel
10
+ include MethodParse
11
+
12
+ OUTPUT_SUFFIX = "rmi"
13
+ INCLUDE_SUFFIX = ["rmi"]
14
+
15
+ def visit(tree)
16
+ ret = ""
17
+
18
+ prepare_labels(tree)
19
+
20
+ index = make_method_index(tree)
21
+ index.each do |i|
22
+ i[1] = kind2str(i[1])
23
+ i[3] = @filename
24
+ i[4] = refer(i[0]+i[1]+i[2])
25
+ ret << "$method_index.push(#{i.inspect})\n"
26
+ end
27
+ ret
28
+ end
29
+ end # class RD2RMIVisitor
30
+ end # module RD
31
+
32
+ $Visitor_Class = RD::RD2RMIVisitor
@@ -0,0 +1,518 @@
1
+
2
+ class RDParser
3
+
4
+ preclow
5
+ nonassoc DUMMY
6
+ left ITEMLISTLINE ENUMLISTLINE DESCLISTLINE METHODLISTLINE STRINGLINE
7
+ prechigh
8
+
9
+ token STRINGLINE ITEMLISTLINE ENUMLISTLINE DESCLISTLINE METHODLISTLINE
10
+ WHITELINE SUBTREE HEADLINE INCLUDE INDENT DEDENT DUMMY
11
+
12
+ rule
13
+ document : blocks { result = DocumentElement.new
14
+ add_children_to_element(result, *val[0])
15
+ }
16
+ | {
17
+ raise ParseError,
18
+ "Error: file empty."
19
+ }
20
+ ;
21
+ blocks : blocks block { result.concat(val[1]) }
22
+ | block
23
+ ;
24
+ block : textblock { result = val }
25
+ | verbatim { result = val }
26
+ | lists
27
+ | headline { result = val }
28
+ | include { result = val }
29
+ | WHITELINE { result = [] }
30
+ | SUBTREE { result = val[0].blocks }
31
+ ;
32
+
33
+ headline : HEADLINE { # val[0] is like [level, title]
34
+ title = @inline_parser.parse(val[0][1])
35
+ result = Headline.new(val[0][0])
36
+ add_children_to_element(result, *title)
37
+ }
38
+ ;
39
+ include : INCLUDE { result = Include.new(val[0]) }
40
+ ;
41
+
42
+ textblock : textblockcontent = DUMMY
43
+ { # val[0] is Array of String
44
+ content = cut_off(val[0]).join("")
45
+ contents = @inline_parser.parse(content)
46
+ result = TextBlock.new()
47
+ add_children_to_element(result, *contents)
48
+ }
49
+ ;
50
+ textblockcontent : textblockcontent STRINGLINE
51
+ { result.push(val[1]) }
52
+ | STRINGLINE { result = val }
53
+ ;
54
+
55
+ verbatim : INDENT verbatimcontent DEDENT
56
+ { # val[1] is Array of String
57
+ content = cut_off(val[1])
58
+ result = Verbatim.new(content)
59
+ # imform to lexer.
60
+ @in_verbatim = false }
61
+ ;
62
+ verbatim_after_lists : verbatimcontent
63
+ { # val[0] is Array of String
64
+ content = cut_off(val[0])
65
+ result = Verbatim.new(content)
66
+ # imform to lexer.
67
+ @in_verbatim = false }
68
+ ;
69
+ verbatimcontent : verbatimcontent STRINGLINE
70
+ { result.push(val[1]) }
71
+ | verbatimcontent INDENT verbatimcontent DEDENT
72
+ { result.concat(val[2]) }
73
+ | verbatimcontent WHITELINE
74
+ { result.push("\n") }
75
+ | STRINGLINE { result = val
76
+ # imform to lexer.
77
+ @in_verbatim = true }
78
+ ;
79
+
80
+ list : itemlist
81
+ | enumlist
82
+ | desclist
83
+ | methodlist
84
+ ;
85
+ lists : lists2 = DUMMY
86
+ | INDENT lists2 DEDENT { result = val[1] }
87
+ | INDENT lists2 verbatim_after_lists DEDENT
88
+ { result = val[1].push(val[2]) }
89
+ ;
90
+
91
+ lists2 : lists2 list { result.push(val[1]) }
92
+ | list { result = val }
93
+ ;
94
+
95
+ itemlist : itemlistitems = DUMMY {
96
+ result = ItemList.new
97
+ add_children_to_element(result, *val[0])
98
+ }
99
+ ;
100
+ itemlistitems : itemlistitems itemlistitem
101
+ { result.push(val[1]) }
102
+ | itemlistitem { result = val }
103
+ ;
104
+ itemlistitem : first_textblock_in_itemlist other_blocks_in_list DEDENT
105
+ {
106
+ result = ItemListItem.new
107
+ add_children_to_element(result, val[0], *val[1])
108
+ }
109
+ ;
110
+
111
+ enumlist : enumlistitems = DUMMY {
112
+ result = EnumList.new
113
+ add_children_to_element(result, *val[0])
114
+ }
115
+ ;
116
+ enumlistitems : enumlistitems enumlistitem
117
+ { result.push(val[1]) }
118
+ | enumlistitem { result = val }
119
+ ;
120
+ enumlistitem : first_textblock_in_enumlist other_blocks_in_list DEDENT
121
+ {
122
+ result = EnumListItem.new
123
+ add_children_to_element(result, val[0], *val[1])
124
+ }
125
+ ;
126
+
127
+ desclist : desclistitems = DUMMY {
128
+ result = DescList.new
129
+ add_children_to_element(result, *val[0])
130
+ }
131
+ ;
132
+ desclistitems : desclistitems desclistitem {
133
+ result.push(val[1]) }
134
+ | desclistitem { result = val }
135
+ ;
136
+ desclistitem : DESCLISTLINE description_part DEDENT
137
+ {
138
+ term = DescListItem::Term.new
139
+ term_contents = @inline_parser.parse(val[0].strip)
140
+ add_children_to_element(term, *term_contents)
141
+
142
+ result = DescListItem.new
143
+ set_term_to_element(result, term)
144
+ add_children_to_element(result, *val[1])
145
+ }
146
+ ;
147
+
148
+ methodlist : methodlistitems = DUMMY {
149
+ result = MethodList.new
150
+ add_children_to_element(result, *val[0])
151
+ }
152
+ ;
153
+ methodlistitems : methodlistitems methodlistitem
154
+ { result.push(val[1]) }
155
+ | methodlistitem { result = val }
156
+ ;
157
+ methodlistitem : METHODLISTLINE description_part DEDENT
158
+ {
159
+ term = MethodListItem::Term.new(val[0].strip)
160
+ result = MethodListItem.new
161
+ set_term_to_element(result, term)
162
+ add_children_to_element(result, *val[1])
163
+ }
164
+ ;
165
+
166
+ description_part : whitelines textblock blocks_in_list
167
+ { result = [val[1]].concat(val[2]) }
168
+ | whitelines textblock { result = [val[1]] }
169
+ | whitelines INDENT blocks_in_list DEDENT
170
+ { result = val[2] }
171
+ | whitelines { result = [] }
172
+ ;
173
+
174
+ blocks_in_list : blocks_in_list block_in_list { result.concat(val[1]) }
175
+ | block_in_list
176
+ ;
177
+ block_in_list : textblock { result = val }
178
+ | verbatim { result = val }
179
+ | lists
180
+ | WHITELINE { result = [] }
181
+ ;
182
+ whitelines : whitelines2
183
+ |
184
+ ;
185
+ whitelines2 : WHITELINE whitelines2
186
+ | WHITELINE
187
+ ;
188
+
189
+ first_textblock_in_itemlist : ITEMLISTLINE textblockcontent
190
+
191
+ { content = cut_off([val[0]].concat(val[1])).join("")
192
+ contents = @inline_parser.parse(content)
193
+ result = TextBlock.new()
194
+ add_children_to_element(result, *contents)
195
+ }
196
+ | ITEMLISTLINE
197
+
198
+ { content = cut_off([val[0]]).join("")
199
+ contents = @inline_parser.parse(content)
200
+ result = TextBlock.new()
201
+ add_children_to_element(result, *contents)
202
+ }
203
+ ;
204
+ first_textblock_in_enumlist : ENUMLISTLINE textblockcontent
205
+
206
+ { content = cut_off([val[0]].concat(val[1])).join("")
207
+ contents = @inline_parser.parse(content)
208
+ result = TextBlock.new()
209
+ add_children_to_element(result, *contents)
210
+ }
211
+ | ENUMLISTLINE
212
+
213
+ { content = cut_off([val[0]]).join("")
214
+ contents = @inline_parser.parse(content)
215
+ result = TextBlock.new()
216
+ add_children_to_element(result, *contents)
217
+ }
218
+ ;
219
+ other_blocks_in_list : verbatim blocks_in_list
220
+ { result = [val[0]].concat(val[1]) }
221
+ | lists blocks_in_list { result.concat(val[1]) }
222
+ | WHITELINE blocks_in_list { result = val[1] }
223
+ | verbatim { result = val }
224
+ | lists
225
+ | WHITELINE { result = [] }
226
+ | { result = [] }
227
+ ;
228
+ end
229
+
230
+ ---- inner
231
+ include ParserUtility
232
+
233
+ TMPFILE = ["rdtmp", $$, 0]
234
+
235
+ attr_reader :tree
236
+
237
+ def initialize
238
+ @inline_parser = RDInlineParser.new(self)
239
+ end
240
+
241
+ def parse(src, tree)
242
+ @src = src
243
+ @src.push(false)
244
+ # RDtree
245
+ @tree = tree
246
+
247
+ # @i: index(line no.) of src
248
+ @i = 0
249
+ # stack for current indentation
250
+ @indent_stack = []
251
+ # how indented.
252
+ @current_indent = @indent_stack.join("")
253
+ # RDParser for tmp src
254
+ @subparser = nil
255
+ # which part is in now
256
+ @in_part = nil
257
+ @part_content = []
258
+
259
+ @in_verbatim = false
260
+
261
+ @yydebug = true
262
+ do_parse
263
+ end
264
+
265
+ def next_token
266
+ # preprocessing
267
+ # if it is not in RD part
268
+ # => method
269
+ while @in_part != "rd"
270
+ line = @src[@i]
271
+ @i += 1 # next line
272
+
273
+ case line
274
+ # src end
275
+ when false
276
+ return [false, false]
277
+ # RD part begin
278
+ when /^=begin\s*(?:\bRD\b.*)?\s*$/
279
+ if @in_part # if in non-RD part
280
+ @part_content.push(line)
281
+ else
282
+ @in_part = "rd"
283
+ return [:WHITELINE, "=begin\n"] # <= for textblockand
284
+ end
285
+ # non-RD part begin
286
+ when /^=begin\s+(\w+)/
287
+ part = $1
288
+ if @in_part # if in non-RD part
289
+ @part_content.push(line)
290
+ else
291
+ @in_part = part if @tree.filter[part] # if filter exists
292
+ # p "BEGIN_PART: #{@in_part}" # DEBUG
293
+ end
294
+ # non-RD part end
295
+ when /^=end/
296
+ if @in_part # if in non-RD part
297
+ # p "END_PART: #{@in_part}" # DEBUG
298
+ # make Part-in object
299
+ part = RD::Part.new(@part_content.join(""), @tree, "r")
300
+ @part_content.clear
301
+ # call filter, part_out is output(Part object)
302
+ part_out = @tree.filter[@in_part].call(part)
303
+
304
+ if @tree.filter[@in_part].mode == :rd # if output is RD formated
305
+ subtree = parse_subtree(part_out.to_a)
306
+ else # if output is target formated
307
+ basename = TMPFILE.join('.')
308
+ TMPFILE[-1] += 1
309
+ tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w")
310
+ tmpfile.print(part_out)
311
+ tmpfile.close
312
+ subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"])
313
+ end
314
+ @in_part = nil
315
+ return [:SUBTREE, subtree]
316
+ end
317
+ else
318
+ if @in_part # if in non-RD part
319
+ @part_content.push(line)
320
+ end
321
+ end
322
+ end
323
+
324
+ @current_indent = @indent_stack.join("")
325
+ line = @src[@i]
326
+ case line
327
+ when false
328
+ if_current_indent_equal("") do
329
+ [false, false]
330
+ end
331
+ when /^=end/
332
+ if_current_indent_equal("") do
333
+ @in_part = nil
334
+ [:WHITELINE, "=end"] # MUST CHANGE??
335
+ end
336
+ when /^\s*$/
337
+ @i += 1 # next line
338
+ return [:WHITELINE, ':WHITELINE']
339
+ when /^\#/ # comment line
340
+ @i += 1 # next line
341
+ self.next_token()
342
+ when /^(={1,4})(?!=)\s*(?=\S)/, /^(\+{1,2})(?!\+)\s*(?=\S)/
343
+ rest = $' # '
344
+ rest.strip!
345
+ mark = $1
346
+ if_current_indent_equal("") do
347
+ return [:HEADLINE, [Headline.mark_to_level(mark), rest]]
348
+ end
349
+ when /^<<<\s*(\S+)/
350
+ file = $1
351
+ if_current_indent_equal("") do
352
+ suffix = file[-3 .. -1]
353
+ if suffix == ".rd" or suffix == ".rb"
354
+ subtree = parse_subtree(get_included(file))
355
+ [:SUBTREE, subtree]
356
+ else
357
+ [:INCLUDE, file]
358
+ end
359
+ end
360
+ when /^(\s*)\*(\s*)/
361
+ rest = $' # '
362
+ newIndent = $2
363
+ if_current_indent_equal($1) do
364
+ if @in_verbatim
365
+ [:STRINGLINE, line]
366
+ else
367
+ @indent_stack.push("\s" << newIndent)
368
+ [:ITEMLISTLINE, rest]
369
+ end
370
+ end
371
+ when /^(\s*)(\(\d+\))(\s*)/
372
+ rest = $' # '
373
+ mark = $2
374
+ newIndent = $3
375
+ if_current_indent_equal($1) do
376
+ if @in_verbatim
377
+ [:STRINGLINE, line]
378
+ else
379
+ @indent_stack.push("\s" * mark.size << newIndent)
380
+ [:ENUMLISTLINE, rest]
381
+ end
382
+ end
383
+ when /^(\s*):(\s*)/
384
+ rest = $' # '
385
+ newIndent = $2
386
+ if_current_indent_equal($1) do
387
+ if @in_verbatim
388
+ [:STRINGLINE, line]
389
+ else
390
+ @indent_stack.push("\s" << $2)
391
+ [:DESCLISTLINE, rest]
392
+ end
393
+ end
394
+ when /^(\s*)---(?!-|\s*$)/
395
+ indent = $1
396
+ rest = $'
397
+ /\s*/ === rest
398
+ term = $'
399
+ new_indent = $&
400
+ if_current_indent_equal(indent) do
401
+ if @in_verbatim
402
+ [:STRINGLINE, line]
403
+ else
404
+ @indent_stack.push("\s\s\s" + new_indent)
405
+ [:METHODLISTLINE, term]
406
+ end
407
+ end
408
+ when /^(\s*)/
409
+ if_current_indent_equal($1) do
410
+ [:STRINGLINE, line]
411
+ end
412
+ else
413
+ raise "[BUG] parsing error may occured."
414
+ end
415
+ end
416
+
417
+ =begin private
418
+ --- RDParser#if_current_indent_equal(indent)
419
+ if (({@current_indent == ((|indent|))})) then yield block, otherwise
420
+ process indentation.
421
+ =end
422
+ # always @current_indent = @indent_stack.join("")
423
+ def if_current_indent_equal(indent)
424
+ indent = indent.sub(/\t/, "\s" * 8)
425
+ if @current_indent == indent
426
+ @i += 1 # next line
427
+ yield
428
+ elsif indent.index(@current_indent) == 0
429
+ @indent_stack.push(indent[@current_indent.size .. -1])
430
+ [:INDENT, ":INDENT"]
431
+ else
432
+ @indent_stack.pop
433
+ [:DEDENT, ":DEDENT"]
434
+ end
435
+ end
436
+ private :if_current_indent_equal
437
+
438
+ def cut_off(src)
439
+ ret = []
440
+ whiteline_buf = []
441
+ line = src.shift
442
+ /^\s*/ =~ line
443
+ indent = Regexp.quote($&)
444
+ ret.push($') # '
445
+ while line = src.shift
446
+ if /^(\s*)$/ =~ line
447
+ whiteline_buf.push(line)
448
+ elsif /^#{indent}/ =~ line
449
+ unless whiteline_buf.empty?
450
+ ret.concat(whiteline_buf)
451
+ whiteline_buf.clear
452
+ end
453
+ ret.push($') # '
454
+ else
455
+ raise "[BUG]: probably Parser Error while cutting off.\n"
456
+ end
457
+ end
458
+ ret
459
+ end
460
+ private :cut_off
461
+
462
+ def set_term_to_element(parent, term)
463
+ # parent.set_term_under_document_struct(term, @tree.document_struct)
464
+ parent.set_term_without_document_struct(term)
465
+ end
466
+ private :set_term_to_element
467
+
468
+ def on_error( et, ev, _values )
469
+ line = @src[@i]
470
+ prv, cur, nxt = format_line_num(@i, @i+1, @i+2)
471
+
472
+ raise ParseError, <<Msg
473
+
474
+ RD syntax error: line #{@i+1}:
475
+ #{prv} |#{@src[@i-1].chomp}
476
+ #{cur}=>|#{@src[@i].chomp}
477
+ #{nxt} |#{@src[@i+1].chomp}
478
+
479
+ Msg
480
+ end
481
+
482
+ def line_index
483
+ @i
484
+ end
485
+
486
+ def parse_subtree(src)
487
+ @subparser = RD::RDParser.new() unless @subparser
488
+
489
+ @subparser.parse(src, @tree)
490
+ end
491
+ private :parse_subtree
492
+
493
+ def get_included(file)
494
+ included = ""
495
+ @tree.include_path.each do |dir|
496
+ file_name = dir + "/" + file
497
+ if test(?e, file_name)
498
+ included = IO.readlines(file_name)
499
+ break
500
+ end
501
+ end
502
+ included
503
+ end
504
+ private :get_included
505
+
506
+ def format_line_num(*args)
507
+ width = args.collect{|i| i.to_s.length }.max
508
+ args.collect{|i| sprintf("%#{width}d", i) }
509
+ end
510
+ private :format_line_num
511
+
512
+ ---- header
513
+ require "rd/rdinlineparser.tab.rb"
514
+ require "rd/parser-util"
515
+
516
+ module RD
517
+ ---- footer
518
+ end # end of module RD