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.
- data/.gitignore +1 -0
- data/HISTORY.txt +11 -0
- data/README.rdoc +52 -28
- data/VERSION +1 -1
- data/lib/sourcify.rb +13 -1
- data/lib/sourcify/proc.rb +7 -4
- data/lib/sourcify/proc/parser.rb +109 -40
- data/lib/sourcify/proc/scanner.rb +2140 -0
- data/lib/sourcify/proc/scanner.rl +285 -0
- data/lib/sourcify/proc/scanner/comment.rb +21 -0
- data/lib/sourcify/proc/scanner/counter.rb +44 -0
- data/lib/sourcify/proc/scanner/dstring.rb +58 -0
- data/lib/sourcify/proc/scanner/extensions.rb +135 -0
- data/lib/sourcify/proc/scanner/heredoc.rb +24 -0
- data/sourcify.gemspec +38 -9
- data/spec/dump_object_space_procs.rb +84 -0
- data/spec/proc/created_on_the_fly_proc_spec.rb +172 -0
- data/spec/proc/others_spec.rb +36 -0
- data/spec/proc/to_sexp_variables_spec.rb +6 -6
- data/spec/proc/to_source_from_do_end_block_w_nested_literal_keyword_spec.rb +2 -0
- data/spec/proc/to_source_from_multi_blocks_w_many_matches_spec.rb +105 -29
- data/spec/proc/to_source_from_multi_blocks_w_single_match_spec.rb +85 -17
- data/spec/proc_scanner/block_comment_spec.rb +59 -0
- data/spec/proc_scanner/double_colons_spec.rb +14 -0
- data/spec/proc_scanner/double_quote_str_w_interpolation_spec.rb +62 -0
- data/spec/proc_scanner/double_quote_str_wo_interpolation_spec.rb +75 -0
- data/spec/proc_scanner/heredoc_spec.rb +142 -0
- data/spec/proc_scanner/kw_do_alias1_spec.rb +87 -0
- data/spec/proc_scanner/kw_do_alias2_spec.rb +86 -0
- data/spec/proc_scanner/per_line_comment_spec.rb +34 -0
- data/spec/proc_scanner/single_quote_str_spec.rb +68 -0
- data/spec/proc_scanner/spec_helper.rb +33 -0
- data/spec/proc_scanner/to_proc_spec.rb +15 -0
- data/spec/spec_helper.rb +23 -0
- metadata +39 -10
- data/lib/sourcify/proc/counter.rb +0 -41
- data/lib/sourcify/proc/lexer.rb +0 -40
- data/lib/sourcify/proc/lexer18.rb +0 -237
- data/lib/sourcify/proc/lexer19.rb +0 -204
- 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
|