sourcify 0.1.2 → 0.2.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 (40) hide show
  1. data/.gitignore +1 -0
  2. data/HISTORY.txt +11 -0
  3. data/README.rdoc +52 -28
  4. data/VERSION +1 -1
  5. data/lib/sourcify.rb +13 -1
  6. data/lib/sourcify/proc.rb +7 -4
  7. data/lib/sourcify/proc/parser.rb +109 -40
  8. data/lib/sourcify/proc/scanner.rb +2140 -0
  9. data/lib/sourcify/proc/scanner.rl +285 -0
  10. data/lib/sourcify/proc/scanner/comment.rb +21 -0
  11. data/lib/sourcify/proc/scanner/counter.rb +44 -0
  12. data/lib/sourcify/proc/scanner/dstring.rb +58 -0
  13. data/lib/sourcify/proc/scanner/extensions.rb +135 -0
  14. data/lib/sourcify/proc/scanner/heredoc.rb +24 -0
  15. data/sourcify.gemspec +38 -9
  16. data/spec/dump_object_space_procs.rb +84 -0
  17. data/spec/proc/created_on_the_fly_proc_spec.rb +172 -0
  18. data/spec/proc/others_spec.rb +36 -0
  19. data/spec/proc/to_sexp_variables_spec.rb +6 -6
  20. data/spec/proc/to_source_from_do_end_block_w_nested_literal_keyword_spec.rb +2 -0
  21. data/spec/proc/to_source_from_multi_blocks_w_many_matches_spec.rb +105 -29
  22. data/spec/proc/to_source_from_multi_blocks_w_single_match_spec.rb +85 -17
  23. data/spec/proc_scanner/block_comment_spec.rb +59 -0
  24. data/spec/proc_scanner/double_colons_spec.rb +14 -0
  25. data/spec/proc_scanner/double_quote_str_w_interpolation_spec.rb +62 -0
  26. data/spec/proc_scanner/double_quote_str_wo_interpolation_spec.rb +75 -0
  27. data/spec/proc_scanner/heredoc_spec.rb +142 -0
  28. data/spec/proc_scanner/kw_do_alias1_spec.rb +87 -0
  29. data/spec/proc_scanner/kw_do_alias2_spec.rb +86 -0
  30. data/spec/proc_scanner/per_line_comment_spec.rb +34 -0
  31. data/spec/proc_scanner/single_quote_str_spec.rb +68 -0
  32. data/spec/proc_scanner/spec_helper.rb +33 -0
  33. data/spec/proc_scanner/to_proc_spec.rb +15 -0
  34. data/spec/spec_helper.rb +23 -0
  35. metadata +39 -10
  36. data/lib/sourcify/proc/counter.rb +0 -41
  37. data/lib/sourcify/proc/lexer.rb +0 -40
  38. data/lib/sourcify/proc/lexer18.rb +0 -237
  39. data/lib/sourcify/proc/lexer19.rb +0 -204
  40. data/spec/proc/misc_spec.rb +0 -16
@@ -0,0 +1,285 @@
1
+ Sourcify.require_rb('proc', 'scanner', 'extensions')
2
+
3
+ module Sourcify
4
+ module Proc
5
+ module Scanner #:nodoc:all
6
+
7
+ %%{
8
+ machine proc_scanner;
9
+
10
+ kw_class = 'class';
11
+ kw_module = 'module';
12
+ kw_def = 'def';
13
+ kw_begin = 'begin';
14
+ kw_case = 'case';
15
+ kw_if = 'if';
16
+ kw_unless = 'unless';
17
+ kw_do = 'do';
18
+ kw_then = 'then';
19
+ kw_for = 'for';
20
+ kw_while = 'while';
21
+ kw_until = 'until';
22
+ kw_end = 'end';
23
+
24
+ vchar = alnum | '_';
25
+ const = upper . vchar* . ('::' . alpha . vchar*)*;
26
+ var = (lower | '_') . vchar*;
27
+ meth = (alpha | '_') . vchar*;
28
+ symbol = ':' . (var | const);
29
+ assoc = '=>';
30
+ assgn = '=';
31
+ comma = ',';
32
+ label = (var | const) . ':';
33
+
34
+ lparen = '(';
35
+ rparen = ')';
36
+ lbrace = '{';
37
+ rbrace = '}';
38
+ smcolon = ';';
39
+ newline = '\n';
40
+ ospaces = space* -- newline;
41
+ mspaces = space+ -- newline;
42
+
43
+ ## MACHINE >> New statement
44
+ new_statement := |*
45
+
46
+ (kw_for | kw_while | kw_until) . ^vchar => {
47
+ push(:kw_do_alias2, ts, te)
48
+ increment_counter(:do_end, 0..1)
49
+ fgoto main;
50
+ };
51
+
52
+ (
53
+ ((kw_class | kw_module | kw_def | kw_begin | kw_case | kw_if | kw_unless) . ^vchar) |
54
+ (kw_class . ospaces . '<<' . ospaces . ^newline+)
55
+ ) => {
56
+ push(:kw_do_alias1, ts, te)
57
+ increment_counter(:do_end, 1)
58
+ fgoto main;
59
+ };
60
+
61
+ ospaces => { push(:space, ts, te) };
62
+ any => { fhold; fgoto main; };
63
+
64
+ *|;
65
+
66
+ ## MACHINE >> One-liner comment
67
+ per_line_comment := |*
68
+ ^newline* => {
69
+ push(:comment, ts.pred, te)
70
+ fgoto main;
71
+ };
72
+ *|;
73
+
74
+ ## MACHINE >> Block comment
75
+ block_comment := |*
76
+ any* . newline . '=end' . ospaces . ^newline* => {
77
+ unless push_comment(ts, te)
78
+ fgoto main;
79
+ end
80
+ };
81
+ *|;
82
+
83
+ ## MACHINE >> Heredoc
84
+ heredoc := |*
85
+ ^newline* . newline . ospaces . ^newline+ => {
86
+ unless push_heredoc(ts, te)
87
+ fgoto main;
88
+ end
89
+ };
90
+ *|;
91
+
92
+ ## MACHINE >> Double quote string
93
+ double_quote_str := |*
94
+ delimiter = [\~\`\!\@\#\$\%\^\&\*\)\-\_\+\=\}\]\:\;\'\"\>\,\.\?\/\|\\];
95
+ (^delimiter* . delimiter) -- ('\\' . delimiter) => {
96
+ unless push_dstring(ts, te)
97
+ fgoto main;
98
+ end
99
+ };
100
+ *|;
101
+
102
+ ## MACHINE >> Main
103
+ main := |*
104
+
105
+ ## == Start/end of do..end block
106
+
107
+ kw_do => {
108
+ push(:kw_do, ts, te)
109
+ increment_counter(:do_end)
110
+ fgoto new_statement;
111
+ };
112
+
113
+ kw_end => {
114
+ push(:kw_end, ts, te)
115
+ decrement_counter(:do_end)
116
+ };
117
+
118
+ ## == Start/end of {...} block
119
+
120
+ lbrace => {
121
+ push(:lbrace, ts, te)
122
+ increment_counter(:brace)
123
+ };
124
+
125
+ rbrace => {
126
+ push(:rbrace, ts, te)
127
+ decrement_counter(:brace)
128
+ };
129
+
130
+ assoc => {
131
+ push(:assoc, ts, te)
132
+ fix_counter_false_start(:brace)
133
+ };
134
+
135
+ label => {
136
+ push_label(ts, te)
137
+ fix_counter_false_start(:brace)
138
+ };
139
+
140
+ ## == New statement
141
+
142
+ newline => {
143
+ push(:newline, ts, te)
144
+ increment_lineno
145
+ fgoto new_statement;
146
+ };
147
+
148
+ smcolon | lparen | assgn | kw_then | comma => {
149
+ push(:newline_alias, ts, te)
150
+ fgoto new_statement;
151
+ };
152
+
153
+ ## == Comment
154
+
155
+ '#' => {
156
+ fgoto per_line_comment;
157
+ };
158
+
159
+ newline . '=begin' . ospaces . (ospaces . ^newline+)* . newline => {
160
+ push_comment(ts, te)
161
+ increment_lineno
162
+ fgoto block_comment;
163
+ };
164
+
165
+ ## == Misc
166
+
167
+ var => { push(:var, ts, te) };
168
+ const => { push(:const, ts, te) };
169
+ symbol => { push(:symbol, ts, te) };
170
+ mspaces => { push(:space, ts, te) };
171
+ any => { push(:any, ts, te) };
172
+ '&:' . meth => { push(:to_proc, ts, te) };
173
+
174
+ ## == Heredoc
175
+
176
+ ('<<' | '<<-') . ["']? . (const | var) . ["']? . newline => {
177
+ push_heredoc(ts, te)
178
+ increment_lineno
179
+ fgoto heredoc;
180
+ };
181
+
182
+ ## == Single quote strings
183
+
184
+ sqs1 = "'" . ([^\']* | ([^\'\\]*[\\][\'][^\']*)*) . '\\\\'* . "'";
185
+ sqs2 = '~' . ([^\~]* | ([^\~\\]*[\\][\~][^\~]*)*) . '\\\\'* . '~';
186
+ sqs3 = '`' . ([^\`]* | ([^\`\\]*[\\][\`][^\`]*)*) . '\\\\'* . '`';
187
+ sqs4 = '!' . ([^\!]* | ([^\!\\]*[\\][\!][^\!]*)*) . '\\\\'* . '!';
188
+ sqs5 = '@' . ([^\@]* | ([^\@\\]*[\\][\@][^\@]*)*) . '\\\\'* . '@';
189
+ sqs6 = '#' . ([^\#]* | ([^\#\\]*[\\][\#][^\#]*)*) . '\\\\'* . '#';
190
+ sqs7 = '$' . ([^\$]* | ([^\$\\]*[\\][\$][^\$]*)*) . '\\\\'* . '$';
191
+ sqs8 = '%' . ([^\%]* | ([^\%\\]*[\\][\%][^\%]*)*) . '\\\\'* . '%';
192
+ sqs9 = '^' . ([^\^]* | ([^\^\\]*[\\][\^][^\^]*)*) . '\\\\'* . '^';
193
+ sqs10 = '&' . ([^\&]* | ([^\&\\]*[\\][\&][^\&]*)*) . '\\\\'* . '&';
194
+ sqs11 = '*' . ([^\*]* | ([^\*\\]*[\\][\*][^\*]*)*) . '\\\\'* . '*';
195
+ sqs12 = '-' . ([^\-]* | ([^\-\\]*[\\][\-][^\-]*)*) . '\\\\'* . '-';
196
+ sqs13 = '_' . ([^\_]* | ([^\_\\]*[\\][\_][^\_]*)*) . '\\\\'* . '_';
197
+ sqs14 = '+' . ([^\+]* | ([^\+\\]*[\\][\+][^\+]*)*) . '\\\\'* . '+';
198
+ sqs15 = '=' . ([^\=]* | ([^\=\\]*[\\][\=][^\=]*)*) . '\\\\'* . '=';
199
+ sqs16 = '<' . ([^\>]* | ([^\>\\]*[\\][\>][^\>]*)*) . '\\\\'* . '>';
200
+ sqs17 = '|' . ([^\|]* | ([^\|\\]*[\\][\|][^\|]*)*) . '\\\\'* . '|';
201
+ sqs18 = ':' . ([^\:]* | ([^\:\\]*[\\][\:][^\:]*)*) . '\\\\'* . ':';
202
+ sqs19 = ';' . ([^\;]* | ([^\;\\]*[\\][\;][^\;]*)*) . '\\\\'* . ';';
203
+ sqs20 = '"' . ([^\"]* | ([^\"\\]*[\\][\"][^\"]*)*) . '\\\\'* . '"';
204
+ sqs21 = ',' . ([^\,]* | ([^\,\\]*[\\][\,][^\,]*)*) . '\\\\'* . ',';
205
+ sqs22 = '.' . ([^\.]* | ([^\.\\]*[\\][\.][^\.]*)*) . '\\\\'* . '.';
206
+ sqs23 = '?' . ([^\?]* | ([^\?\\]*[\\][\?][^\?]*)*) . '\\\\'* . '?';
207
+ sqs24 = '/' . ([^\/]* | ([^\/\\]*[\\][\/][^\/]*)*) . '\\\\'* . '/';
208
+ sqs25 = '{' . ([^\}]* | ([^\}\\]*[\\][\}][^\}]*)*) . '\\\\'* . '}';
209
+ sqs26 = '[' . ([^\]]* | ([^\]\\]*[\\][\]][^\]]*)*) . '\\\\'* . ']';
210
+ sqs27 = '(' . ([^\)]* | ([^\)\\]*[\\][\)][^\)]*)*) . '\\\\'* . ')';
211
+ sqs28 = '\\' . ([^\\]* | ([^\)]*[\\][\\][^\\]*)*) . '\\';
212
+
213
+ sqm = ('%q' | '%w'); (
214
+ sqs1 | sqm . sqs1 | sqm . sqs2 | sqm . sqs3 | sqm . sqs4 |
215
+ sqm . sqs5 | sqm . sqs6 | sqm . sqs7 | sqm . sqs8 | sqm . sqs9 |
216
+ sqm . sqs10 | sqm . sqs11 | sqm . sqs12 | sqm . sqs13 | sqm . sqs14 |
217
+ sqm . sqs15 | sqm . sqs16 | sqm . sqs17 | sqm . sqs18 | sqm . sqs19 |
218
+ sqm . sqs20 | sqm . sqs21 | sqm . sqs22 | sqm . sqs23 | sqm . sqs24 |
219
+ sqm . sqs25 | sqm . sqs26 | sqm . sqs27 | sqm . sqs28
220
+ ) => {
221
+ push(:sstring, ts, te)
222
+ };
223
+
224
+ ## == Double quote strings
225
+
226
+ dqs1 = '"' . (([^\"]* | ([^\"\\]*[\\][\"][^\"]*)*) -- '#{') . '\\\\'* . ('"' | '#{');
227
+ dqs2 = '`' . (([^\`]* | ([^\`\\]*[\\][\`][^\`]*)*) -- '#{') . '\\\\'* . ('`' | '#{');
228
+ dqs3 = '/' . (([^\/]* | ([^\/\\]*[\\][\/][^\/]*)*) -- '#{') . '\\\\'* . ('/' | '#{');
229
+ dqs4 = "'" . (([^\']* | ([^\'\\]*[\\][\'][^\']*)*) -- '#{') . '\\\\'* . ("'" | '#{');
230
+ dqs5 = '~' . (([^\~]* | ([^\~\\]*[\\][\~][^\~]*)*) -- '#{') . '\\\\'* . ('~' | '#{');
231
+ dqs6 = '!' . (([^\!]* | ([^\!\\]*[\\][\!][^\!]*)*) -- '#{') . '\\\\'* . ('!' | '#{');
232
+ dqs7 = '@' . (([^\@]* | ([^\@\\]*[\\][\@][^\@]*)*) -- '#{') . '\\\\'* . ('@' | '#{');
233
+ dqs8 = '#' . (([^\#]* | ([^\#\\]*[\\][\#][^\#]*)*) -- '#{') . '\\\\'* . ('#' | '#{');
234
+ dqs9 = '$' . (([^\$]* | ([^\$\\]*[\\][\$][^\$]*)*) -- '#{') . '\\\\'* . ('$' | '#{');
235
+ dqs10 = '%' . (([^\%]* | ([^\%\\]*[\\][\%][^\%]*)*) -- '#{') . '\\\\'* . ('%' | '#{');
236
+ dqs11 = '^' . (([^\^]* | ([^\^\\]*[\\][\^][^\^]*)*) -- '#{') . '\\\\'* . ('^' | '#{');
237
+ dqs12 = '&' . (([^\&]* | ([^\&\\]*[\\][\&][^\&]*)*) -- '#{') . '\\\\'* . ('&' | '#{');
238
+ dqs13 = '*' . (([^\*]* | ([^\*\\]*[\\][\*][^\*]*)*) -- '#{') . '\\\\'* . ('*' | '#{');
239
+ dqs14 = '-' . (([^\-]* | ([^\-\\]*[\\][\-][^\-]*)*) -- '#{') . '\\\\'* . ('-' | '#{');
240
+ dqs15 = '_' . (([^\_]* | ([^\_\\]*[\\][\_][^\_]*)*) -- '#{') . '\\\\'* . ('_' | '#{');
241
+ dqs16 = '+' . (([^\+]* | ([^\+\\]*[\\][\+][^\+]*)*) -- '#{') . '\\\\'* . ('+' | '#{');
242
+ dqs17 = '=' . (([^\=]* | ([^\=\\]*[\\][\=][^\=]*)*) -- '#{') . '\\\\'* . ('=' | '#{');
243
+ dqs18 = '<' . (([^\>]* | ([^\>\\]*[\\][\>][^\>]*)*) -- '#{') . '\\\\'* . ('>' | '#{');
244
+ dqs19 = '|' . (([^\|]* | ([^\|\\]*[\\][\|][^\|]*)*) -- '#{') . '\\\\'* . ('|' | '#{');
245
+ dqs20 = ':' . (([^\:]* | ([^\:\\]*[\\][\:][^\:]*)*) -- '#{') . '\\\\'* . (':' | '#{');
246
+ dqs21 = ';' . (([^\;]* | ([^\;\\]*[\\][\;][^\;]*)*) -- '#{') . '\\\\'* . (';' | '#{');
247
+ dqs22 = ',' . (([^\,]* | ([^\,\\]*[\\][\,][^\,]*)*) -- '#{') . '\\\\'* . (',' | '#{');
248
+ dqs23 = '.' . (([^\.]* | ([^\.\\]*[\\][\.][^\.]*)*) -- '#{') . '\\\\'* . ('.' | '#{');
249
+ dqs24 = '?' . (([^\?]* | ([^\?\\]*[\\][\?][^\?]*)*) -- '#{') . '\\\\'* . ('?' | '#{');
250
+ dqs25 = '{' . (([^\}]* | ([^\}\\]*[\\][\}][^\}]*)*) -- '#{') . '\\\\'* . ('}' | '#{');
251
+ dqs26 = '[' . (([^\]]* | ([^\]\\]*[\\][\]][^\]]*)*) -- '#{') . '\\\\'* . (']' | '#{');
252
+ dqs27 = '(' . (([^\)]* | ([^\)\\]*[\\][\)][^\)]*)*) -- '#{') . '\\\\'* . (')' | '#{');
253
+ dqs28 = '\\' . (([^\\]* | ([^\\]*[\\][\\][^\\]*)*) -- '#{') . ('\\' | '#{');
254
+
255
+ dqm = ('%Q' | '%W' | '%x' | '%r' | '%'); (
256
+ dqs1 | dqs2 | dqs3 | dqm . dqs1 | dqm . dqs2 |
257
+ dqm . dqs3 | dqm . dqs4 | dqm . dqs5 | dqm . dqs6 | dqm . dqs7 |
258
+ dqm . dqs8 | dqm . dqs9 | dqm . dqs10 | dqm . dqs11 | dqm . dqs12 |
259
+ dqm . dqs13 | dqm . dqs14 | dqm . dqs15 | dqm . dqs16 | dqm . dqs17 |
260
+ dqm . dqs18 | dqm . dqs19 | dqm . dqs20 | dqm . dqs21 | dqm . dqs22 |
261
+ dqm . dqs23 | dqm . dqs24 | dqm . dqs25 | dqm . dqs26 | dqm . dqs27 |
262
+ dqm . dqs28
263
+ ) => {
264
+ if push_dstring(ts, te)
265
+ fgoto double_quote_str;
266
+ end
267
+ };
268
+
269
+ *|;
270
+
271
+ }%%
272
+ %% write data;
273
+
274
+ extend Scanner::Extensions
275
+
276
+ def self.execute!
277
+ data = @data
278
+ eof = data.length
279
+ %% write init;
280
+ %% write exec;
281
+ end
282
+
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,21 @@
1
+ module Sourcify
2
+ module Proc
3
+ module Scanner #:nodoc:all
4
+ class Comment
5
+
6
+ def <<(content)
7
+ (@contents ||= []) << content
8
+ end
9
+
10
+ def to_s
11
+ @contents.join
12
+ end
13
+
14
+ def closed?
15
+ @contents[-1].split("\n")[-1].strip == '=end'
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ module Sourcify
2
+ module Proc
3
+ module Scanner #:nodoc:all
4
+ class Counter
5
+
6
+ attr_reader :counts
7
+
8
+ def initialize
9
+ @counts = [0,0]
10
+ end
11
+
12
+ def started?
13
+ @counts.any?(&:nonzero?)
14
+ end
15
+
16
+ def just_started?
17
+ @counts.any?{|count| count == 1 }
18
+ end
19
+
20
+ def balanced?
21
+ @counts.any?(&:zero?)
22
+ end
23
+
24
+ def decrement
25
+ (0..1).each{|i| @counts[i] -= 1 unless @counts[i].zero? }
26
+ end
27
+
28
+ def increment(val = 1)
29
+ if val.is_a?(Range)
30
+ @counts[0] += val.first
31
+ @counts[1] += val.last
32
+ else
33
+ (0..1).each{|i| @counts[i] += 1 }
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class DoEndBlockCounter < Counter; end
40
+ class BraceBlockCounter < Counter; end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ module Sourcify
2
+ module Proc
3
+ module Scanner #:nodoc:all
4
+ class DString < Struct.new(:tag)
5
+
6
+ # To suppress 'warning: Object#type is deprecated; use Object#class' when
7
+ # evaluating string
8
+ attr_reader :type
9
+
10
+ def <<(content)
11
+ (@contents ||= []) << content
12
+ end
13
+
14
+ def to_s
15
+ @contents.join
16
+ end
17
+
18
+ def closed?
19
+ # NOTE: The only real error is SyntaxError, other errors are due
20
+ # to undefined variable or watever, which are perfectly ok when
21
+ # testing for validity of the string.
22
+ begin
23
+ instance_eval(safe_contents) if evaluable?
24
+ rescue SyntaxError
25
+ false
26
+ rescue Exception
27
+ true
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ CLOSING_TAGS = {'(' => ')', '[' => ']', '<' => '>', '{' => '}'}
34
+
35
+ def evaluable?
36
+ @contents[-1][-1].chr == end_tag
37
+ end
38
+
39
+ def safe_contents
40
+ # NOTE: %x & ` strings are dangerous to eval cos they execute shell commands,
41
+ # thus we convert them to normal strings 1st
42
+ @contents.join.gsub(/(%x)(\W|\_)/, '%Q\2').gsub(/.{0,2}(`)/) do |s|
43
+ s =~ /^(%Q|%W|%r|%x|.?%|.?\\)/ ? s : s.sub(/`$/,'%Q`')
44
+ end
45
+ end
46
+
47
+ def start_tag
48
+ @start_tag ||= tag[-1].chr
49
+ end
50
+
51
+ def end_tag
52
+ @end_tag ||= (CLOSING_TAGS[start_tag] || start_tag)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,135 @@
1
+ %w{heredoc comment dstring counter}.each do |f|
2
+ Sourcify.require_rb('proc', 'scanner', f)
3
+ end
4
+
5
+ module Sourcify
6
+ module Proc
7
+ module Scanner #:nodoc:all
8
+ module Extensions
9
+
10
+ class Escape < Exception; end
11
+
12
+ def process(data, stop_on_newline = false)
13
+ begin
14
+ @stop_on_newline = stop_on_newline
15
+ @results, @data = [], data.unpack("c*")
16
+ reset_attributes
17
+ execute!
18
+ rescue Escape
19
+ @results
20
+ end
21
+ end
22
+
23
+ def data_frag(range)
24
+ @data[range].pack('c*')
25
+ end
26
+
27
+ def push(key, ts, te)
28
+ @results << :symbol_to_proc if key == :to_proc && @lineno == 1
29
+ @tokens << [key, data_frag(ts .. te.pred)]
30
+ end
31
+
32
+ def push_dstring(ts, te)
33
+ data = data_frag(ts .. te.pred)
34
+ unless @dstring
35
+ @dstring = DString.new(data[%r{^("|`|/|%(?:Q|W|r|x|)(?:\W|_))},1])
36
+ end
37
+ @dstring << data
38
+ return true unless @dstring.closed?
39
+ @tokens << [:dstring, @dstring.to_s]
40
+ @dstring = nil
41
+ end
42
+
43
+ def push_comment(ts, te)
44
+ data = data_frag(ts .. te.pred)
45
+ @comment ||= Comment.new
46
+ @comment << data
47
+ return true unless @comment.closed?
48
+ @tokens << [:comment, @comment.to_s]
49
+ @comment = nil
50
+ end
51
+
52
+ def push_heredoc(ts, te)
53
+ data = data_frag(ts .. te.pred)
54
+ unless @heredoc
55
+ indented, tag = data.match(/\<\<(\-?)['"]?(\w+)['"]?$/)[1..3]
56
+ @heredoc = Heredoc.new(tag, !indented.empty?)
57
+ end
58
+ @heredoc << data
59
+ return true unless @heredoc.closed?(data_frag(te .. te))
60
+ @tokens << [:heredoc, @heredoc.to_s]
61
+ @heredoc = nil
62
+ end
63
+
64
+ def push_label(ts, te)
65
+ # NOTE: 1.9.* supports label key, which RubyParser cannot handle, thus
66
+ # conversion is needed.
67
+ data = data_frag(ts .. te.pred)
68
+ @tokens << [:symbol, data.sub(/^(.*)\:$/, ':\1')]
69
+ @tokens << [:space, ' ']
70
+ @tokens << [:assoc, '=>']
71
+ end
72
+
73
+ def increment_lineno
74
+ @lineno += 1
75
+ raise Escape if @stop_on_newline || !@results.empty?
76
+ end
77
+
78
+ def increment_counter(key, count = 1)
79
+ return if other_counter(key).started?
80
+ counter = this_counter(key)
81
+ offset_attributes unless counter.started?
82
+ counter.increment(count)
83
+ end
84
+
85
+ def decrement_counter(key)
86
+ return unless (counter = this_counter(key)).started?
87
+ counter.decrement
88
+ construct_result_code if counter.balanced?
89
+ end
90
+
91
+ def fix_counter_false_start(key)
92
+ reset_attributes if this_counter(key).just_started?
93
+ end
94
+
95
+ def other_counter(type)
96
+ {:do_end => @brace_counter, :brace => @do_end_counter}[type]
97
+ end
98
+
99
+ def this_counter(type)
100
+ {:brace => @brace_counter, :do_end => @do_end_counter}[type]
101
+ end
102
+
103
+ def construct_result_code
104
+ begin
105
+ code = 'proc ' + @tokens.map(&:last).join
106
+ eval(code) # TODO: any better way to check for completeness of proc code ??
107
+ @results << code
108
+ raise Escape if @stop_on_newline or @lineno != 1
109
+ reset_attributes
110
+ rescue Exception
111
+ raise if $!.is_a?(Escape)
112
+ end
113
+ end
114
+
115
+ def reset_attributes
116
+ @tokens = []
117
+ @lineno = 1
118
+ @heredoc, @dstring, @comment = nil
119
+ @do_end_counter = DoEndBlockCounter.new
120
+ @brace_counter = BraceBlockCounter.new
121
+ end
122
+
123
+ def offset_attributes
124
+ @lineno = 1 # Fixing JRuby's lineno bug (see http://jira.codehaus.org/browse/JRUBY-5014)
125
+ unless @tokens.empty?
126
+ last = @tokens[-1]
127
+ @tokens.clear
128
+ @tokens << last
129
+ end
130
+ end
131
+
132
+ end
133
+ end
134
+ end
135
+ end