sourcify 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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