ParseTree 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,16 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.libs << ":../../sexp_processor/dev/lib"
7
+ at.extra_files << "test/pt_testcase.rb"
8
+
9
+ %w(TestRawParseTree).each do |klass|
10
+ at.extra_class_map[klass] = "test/test_parse_tree.rb"
11
+ end
12
+
13
+ at.add_mapping(/pt_testcase/) do |f, _|
14
+ at.files_matching(/test_.*rb$/)
15
+ end
16
+ end
data/History.txt CHANGED
@@ -1,3 +1,51 @@
1
+ === 3.0.0 / 2008-10-22
2
+
3
+ * 3 major enhancements:
4
+
5
+ * Split out sexp_processor project.
6
+ * ParseTree#process outputs a UnifiedRuby parse tree.
7
+ * Switched all ParseTree tests to RawParseTree tests.
8
+ * Added ParseTree tests.
9
+ * Added UnifiedRuby#process.
10
+
11
+ * 28 minor enhancements:
12
+
13
+ * PTTC: Added a comprehensive suite of tests for every combo of defn args.
14
+ * PTTC: Added a ton of new tests.
15
+ * PTTC: Added extra tests for mri verbose flag testing (horrid horrid bug imhfo)
16
+ * PTTC: Don't generate tests if class has "TestCase" in the class name.
17
+ * PTTC: Made self.previous more overridable.
18
+ * PTTC: Now all tests that have "mri_verbose_flag" activate $VERBOSE
19
+ * PTTC: Officially added clone_same phase to generate_tests
20
+ * PTTC: Refactored test generation to make subclasses more flexible.
21
+ * PTTC: Refactored to use new add_tests. Much much cleaner.
22
+ * PTTC: Removed Unique from PTTC... subclasses need to deal with this
23
+ * PTTC: Removed some stupid tests.
24
+ * PTTC: Renamed a bunch of tests to be more uniform.
25
+ * UR: Added rewrite_attrasgn to normalize arg array into arglist.
26
+ * UR: Added rewrite_op_asgn1 to ensure the arglist is an arglist.
27
+ * UR: Flattened resbodies in rescue node.
28
+ * UR: Flattened super and yield args yet, deal with array arg properly.
29
+ * UR: Handle yield(*ary) properly.
30
+ * UR: Nuked argspush.
31
+ * UR: Removed begin node from unified sexps.
32
+ * UR: Removed block from rewritten resbody if only 1 element.
33
+ * UR: Removed dasgn, dasgn_curr, and dvar nodes.
34
+ * UR: Removed s(:block_arg, :block) in favor of :"&block"
35
+ * UR: Rewrote argscat to be a splat inside an array.
36
+ * UR: Rewrote block_pass into arglist of inner call/super.
37
+ * UR: Rewrote call to ALWAYS have an argslist (no more splat as arglist).
38
+ * UR: Rewrote rewrite_resbody from scratch... MUUCH cleaner.
39
+ * UR: zarray -> array
40
+ * Used Hoe#add_include_dirs to clean up rakefile.
41
+ * Moved PT dependent code from ruby2ruby to here (eg Proc#to_sexp & friends).
42
+
43
+ * 2 bug fixes:
44
+
45
+ * UR: Fixed a bug with resbody that starts with an lasgn.
46
+ * UR: Fixed args for attrset
47
+ * Fixed export of symbols to work across platforms.
48
+
1
49
  === 2.2.0 / 2008-06-09
2
50
 
3
51
  * 18 minor enhancements:
data/Manifest.txt CHANGED
@@ -1,3 +1,4 @@
1
+ .autotest
1
2
  History.txt
2
3
  Manifest.txt
3
4
  README.txt
@@ -7,18 +8,14 @@ bin/parse_tree_audit
7
8
  bin/parse_tree_deps
8
9
  bin/parse_tree_show
9
10
  demo/printer.rb
10
- lib/composite_sexp_processor.rb
11
11
  lib/parse_tree.rb
12
- lib/sexp.rb
13
- lib/sexp_processor.rb
12
+ lib/parse_tree_extensions.rb
14
13
  lib/unified_ruby.rb
15
14
  lib/unique.rb
16
15
  test/pt_testcase.rb
17
16
  test/something.rb
18
17
  test/test_all.rb
19
- test/test_composite_sexp_processor.rb
20
18
  test/test_parse_tree.rb
21
- test/test_sexp.rb
22
- test/test_sexp_processor.rb
19
+ test/test_parse_tree_extensions.rb
23
20
  test/test_unified_ruby.rb
24
21
  validate.sh
data/Rakefile CHANGED
@@ -3,7 +3,11 @@
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
5
 
6
- $: << "../../RubyInline/dev/lib"
6
+ Hoe.add_include_dirs("../../RubyInline/dev/lib",
7
+ "../../sexp_processor/dev/lib",
8
+ "../../ZenTest/dev/lib",
9
+ "lib")
10
+
7
11
  require './lib/parse_tree.rb'
8
12
 
9
13
  Hoe.new("ParseTree", ParseTree::VERSION) do |pt|
@@ -12,14 +16,13 @@ Hoe.new("ParseTree", ParseTree::VERSION) do |pt|
12
16
  pt.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
13
17
 
14
18
  pt.clean_globs << File.expand_path("~/.ruby_inline")
15
- pt.extra_deps << ['RubyInline', '>= 3.6.0']
19
+ pt.extra_deps << ['RubyInline', '>= 3.7.0']
20
+ pt.extra_deps << ['SexpProcessor', '>= 3.0.0']
16
21
  pt.spec_extras[:require_paths] = proc { |paths| paths << 'test' }
17
22
 
18
- pt.multiruby_skip << "1.9" << "rubinius"
23
+ pt.multiruby_skip << "mri_rel_1_9" << "rubinius" << "mri_trunk"
19
24
  end
20
25
 
21
- Hoe::RUBY_FLAGS.sub! /-I/, '-I../../RubyInline/dev/lib:test:'
22
-
23
26
  desc 'Run in gdb'
24
27
  task :debug do
25
28
  puts "RUN: r -d #{Hoe::RUBY_FLAGS} test/test_all.rb #{Hoe::FILTER}"
data/lib/parse_tree.rb CHANGED
@@ -7,6 +7,7 @@ raise LoadError, "ParseTree isn't needed with rubinius" if
7
7
 
8
8
  require 'rubygems'
9
9
  require 'inline'
10
+ require 'unified_ruby'
10
11
 
11
12
  class Module
12
13
  def modules
@@ -40,9 +41,9 @@ end
40
41
  # [:args],
41
42
  # [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
42
43
 
43
- class ParseTree
44
+ class RawParseTree
44
45
 
45
- VERSION = '2.2.0'
46
+ VERSION = '3.0.0'
46
47
 
47
48
  ##
48
49
  # Front end translation method.
@@ -288,7 +289,7 @@ class ParseTree
288
289
  # 1) Get me a login on your box so I can repro this and get it fixed.
289
290
  # 2) Fix it and send me the patch
290
291
  # 3) (quick, but dirty and bad), comment out the following line:
291
- builder.add_compile_flags "-Werror"
292
+ builder.add_compile_flags "-Werror" unless RUBY_PLATFORM =~ /mswin/
292
293
 
293
294
  builder.prefix %{
294
295
  #define nd_3rd u3.node
@@ -350,7 +351,7 @@ void add_to_parse_tree(VALUE self, VALUE ary, NODE * n, ID * locals) {
350
351
  static int masgn_level = 0;
351
352
 
352
353
  if (NIL_P(node_names)) {
353
- node_names = rb_const_get_at(rb_path2class("ParseTree"),rb_intern("NODE_NAMES"));
354
+ node_names = rb_const_get_at(rb_path2class("RawParseTree"),rb_intern("NODE_NAMES"));
354
355
  }
355
356
 
356
357
  if (!node) return;
@@ -508,15 +509,27 @@ again:
508
509
 
509
510
  case NODE_BREAK:
510
511
  case NODE_NEXT:
512
+ if (node->nd_stts)
513
+ add_to_parse_tree(self, current, node->nd_stts, locals);
514
+
515
+ break;
516
+
511
517
  case NODE_YIELD:
512
518
  if (node->nd_stts)
513
519
  add_to_parse_tree(self, current, node->nd_stts, locals);
520
+
521
+ if (node->nd_stts
522
+ && (nd_type(node->nd_stts) == NODE_ARRAY
523
+ || nd_type(node->nd_stts) == NODE_ZARRAY)
524
+ && !node->nd_state)
525
+ rb_ary_push(current, Qtrue);
526
+
514
527
  break;
515
528
 
516
529
  case NODE_RESCUE:
517
- add_to_parse_tree(self, current, node->nd_1st, locals);
518
- add_to_parse_tree(self, current, node->nd_2nd, locals);
519
- add_to_parse_tree(self, current, node->nd_3rd, locals);
530
+ add_to_parse_tree(self, current, node->nd_1st, locals);
531
+ add_to_parse_tree(self, current, node->nd_2nd, locals);
532
+ add_to_parse_tree(self, current, node->nd_3rd, locals);
520
533
  break;
521
534
 
522
535
  /*
@@ -665,15 +678,25 @@ again:
665
678
 
666
679
  case NODE_MASGN:
667
680
  masgn_level++;
668
- add_to_parse_tree(self, current, node->nd_head, locals);
681
+ if (node->nd_head) {
682
+ add_to_parse_tree(self, current, node->nd_head, locals);
683
+ } else {
684
+ rb_ary_push(current, Qnil);
685
+ }
669
686
  if (node->nd_args) {
670
687
  if (node->nd_args != (NODE *)-1) {
671
688
  add_to_parse_tree(self, current, node->nd_args, locals);
672
689
  } else {
673
690
  rb_ary_push(current, wrap_into_node("splat", 0));
674
691
  }
692
+ } else {
693
+ rb_ary_push(current, Qnil);
694
+ }
695
+ if (node->nd_value) {
696
+ add_to_parse_tree(self, current, node->nd_value, locals);
697
+ } else {
698
+ rb_ary_push(current, Qnil);
675
699
  }
676
- add_to_parse_tree(self, current, node->nd_value, locals);
677
700
  masgn_level--;
678
701
  break;
679
702
 
@@ -1051,9 +1074,12 @@ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE is_cls_meth) {
1051
1074
  }
1052
1075
  }
1053
1076
 
1054
- builder.prefix " extern NODE *ruby_eval_tree_begin; " \
1077
+ extern_mode = RUBY_PLATFORM =~ /mswin/ ? 'RUBY_EXTERN' : 'extern'
1078
+ builder.prefix " #{extern_mode} NODE *ruby_eval_tree_begin; " \
1055
1079
  if RUBY_VERSION < '1.9.0'
1056
1080
 
1081
+ # FIXME: ruby_in_eval is not properly exported across platforms
1082
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/13558
1057
1083
  builder.c %Q{
1058
1084
  static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line) {
1059
1085
  VALUE tmp;
@@ -1094,4 +1120,34 @@ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line) {
1094
1120
  }
1095
1121
 
1096
1122
  end # inline call
1097
- end # ParseTree class
1123
+ end # RawParseTree class
1124
+
1125
+ class ParseTree < RawParseTree
1126
+ ##
1127
+ # Initializes a ParseTree instance. Includes newline nodes if
1128
+ # +include_newlines+ which defaults to +$DEBUG+.
1129
+
1130
+ def initialize(include_newlines=$DEBUG)
1131
+ super
1132
+ @unifier = Unifier.new
1133
+ end
1134
+
1135
+ ##
1136
+ # Main driver for ParseTree. Returns a Sexp instance containing the
1137
+ # AST representing the input given. This is a UnifiedRuby sexp, not
1138
+ # a raw sexp from ruby. If you want raw, use the old
1139
+ # parse_tree_for_xxx methods... Please tell me if/why you want raw,
1140
+ # I'd like to know so I can justify keeping the code around.
1141
+
1142
+ def process(input, verbose = nil, file = "(string)", line = -1)
1143
+ case input
1144
+ when Array then
1145
+ @unifier.process(input)
1146
+ when String then
1147
+ pt = self.parse_tree_for_string(input, file, line, verbose).first
1148
+ @unifier.process(pt)
1149
+ else
1150
+ raise ArgumentError, "Unknown input type #{input.inspect}"
1151
+ end
1152
+ end
1153
+ end
@@ -0,0 +1,69 @@
1
+ class Method
2
+ def with_class_and_method_name
3
+ if self.inspect =~ /<Method: (.*)\#(.*)>/ then
4
+ klass = eval $1
5
+ method = $2.intern
6
+ raise "Couldn't determine class from #{self.inspect}" if klass.nil?
7
+ return yield(klass, method)
8
+ else
9
+ raise "Can't parse signature: #{self.inspect}"
10
+ end
11
+ end
12
+
13
+ def to_sexp
14
+ require 'parse_tree'
15
+ require 'unified_ruby'
16
+ parser = ParseTree.new(false)
17
+ unifier = Unifier.new
18
+ with_class_and_method_name do |klass, method|
19
+ old_sexp = parser.parse_tree_for_method(klass, method)
20
+ unifier.process(old_sexp) # HACK
21
+ end
22
+ end
23
+
24
+ def to_ruby
25
+ sexp = self.to_sexp
26
+ Ruby2Ruby.new.process sexp
27
+ end
28
+ end
29
+
30
+ class ProcStoreTmp
31
+ @@n = 0
32
+ def self.new_name
33
+ @@n += 1
34
+ return :"myproc#{@@n}"
35
+ end
36
+ end
37
+
38
+ class UnboundMethod
39
+ def to_ruby
40
+ name = ProcStoreTmp.new_name
41
+ ProcStoreTmp.send(:define_method, name, self)
42
+ m = ProcStoreTmp.new.method(name)
43
+ result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
44
+ 'proc { |\1|').sub(/end\Z/, '}')
45
+ return result
46
+ end
47
+ end
48
+
49
+ class Proc
50
+ def to_method
51
+ name = ProcStoreTmp.new_name
52
+ ProcStoreTmp.send(:define_method, name, self)
53
+ ProcStoreTmp.new.method(name)
54
+ end
55
+
56
+ def to_sexp
57
+ sexp = self.to_method.to_sexp
58
+ body = sexp.scope.block
59
+ args = sexp.args
60
+ args = nil if args.size == 1
61
+ body = body[1] if body.size == 2
62
+
63
+ s(:iter, s(:call, nil, :proc, s(:arglist)), args, body)
64
+ end
65
+
66
+ def to_ruby
67
+ Ruby2Ruby.new.process(self.to_sexp).sub(/^\Aproc do/, 'proc {').sub(/end\Z/, '}')
68
+ end
69
+ end
data/lib/unified_ruby.rb CHANGED
@@ -1,17 +1,37 @@
1
+ require 'sexp_processor'
1
2
 
2
3
  $TESTING ||= false
3
4
 
4
5
  module UnifiedRuby
6
+ def process exp
7
+ exp = Sexp.from_array exp unless Sexp === exp or exp.nil?
8
+ super
9
+ end
10
+
11
+ def rewrite_attrasgn(exp)
12
+ last = exp.last
13
+
14
+ if Sexp === last then
15
+ last[0] = :arglist if last[0] == :array
16
+ else
17
+ exp << s(:arglist)
18
+ end
19
+
20
+ exp
21
+ end
22
+
5
23
  def rewrite_bmethod(exp)
6
24
  exp[0] = :scope
7
25
 
26
+ has_splat = exp.masgn.array.splat.lasgn rescue false
27
+
8
28
  args =
9
- if exp.masgn and exp.masgn.dasgn_curr then
10
- arg = exp.masgn(true).dasgn_curr(true).sexp_body
29
+ if has_splat then
30
+ arg = exp.masgn(true).array.splat.lasgn.sexp_body
11
31
  raise "nope: #{arg.size}" unless arg.size == 1
12
32
  s(:args, :"*#{arg.last}")
13
33
  else
14
- args = exp.dasgn_curr(true)
34
+ args = exp.lasgn(true)
15
35
  if args then
16
36
  s(:args, *args.sexp_body)
17
37
  else
@@ -27,6 +47,35 @@ module UnifiedRuby
27
47
  exp
28
48
  end
29
49
 
50
+ def rewrite_argscat exp
51
+ _, ary, val = exp
52
+ ary = s(:array, ary) unless ary.first == :array
53
+ ary << s(:splat, val)
54
+ end
55
+
56
+ def rewrite_argspush exp
57
+ exp[0] = :arglist
58
+ exp
59
+ end
60
+
61
+ def rewrite_block_pass exp
62
+ if exp.size == 3 then
63
+ _, block, recv = exp
64
+ case recv.first
65
+ when :super then
66
+ recv << s(:block_pass, block)
67
+ exp = recv
68
+ when :call then
69
+ recv.last << s(:block_pass, block)
70
+ exp = recv
71
+ else
72
+ raise "huh?: #{recv.inspect}"
73
+ end
74
+ end
75
+
76
+ exp
77
+ end
78
+
30
79
  def rewrite_call(exp)
31
80
  args = exp.last
32
81
  case args
@@ -37,7 +86,7 @@ module UnifiedRuby
37
86
  when :array, :arglist then
38
87
  args[0] = :arglist
39
88
  when :argscat, :splat then
40
- # do nothing
89
+ exp[-1] = s(:arglist, args)
41
90
  else
42
91
  raise "unknown type in call #{args.first.inspect} in #{exp.inspect}"
43
92
  end
@@ -49,6 +98,13 @@ module UnifiedRuby
49
98
  exp
50
99
  end
51
100
 
101
+ def rewrite_dasgn(exp)
102
+ exp[0] = :lasgn
103
+ exp
104
+ end
105
+
106
+ alias :rewrite_dasgn_curr :rewrite_dasgn
107
+
52
108
  ##
53
109
  # :defn is one of the most complex of all the ASTs in ruby. We do
54
110
  # one of 3 different translations:
@@ -91,10 +147,23 @@ module UnifiedRuby
91
147
 
92
148
  # move block_arg up and in
93
149
  block_arg = exp.scope.block.block_arg(true) rescue nil
94
- exp.args << block_arg if block_arg
150
+ if block_arg
151
+ block = args.block(true)
152
+ args << :"&#{block_arg.last}"
153
+ args << block if block
154
+ end
95
155
 
96
156
  # patch up attr_accessor methods
97
- exp.insert 2, s(:args) if weirdo
157
+ if weirdo then
158
+ case
159
+ when exp.ivar then
160
+ exp.insert 2, s(:args)
161
+ when exp.attrset then
162
+ exp.insert 2, s(:args, :arg)
163
+ else
164
+ raise "unknown wierdo: #{wierdo.inpsect}"
165
+ end
166
+ end
98
167
 
99
168
  exp
100
169
  end
@@ -119,6 +188,11 @@ module UnifiedRuby
119
188
  exp.shift # scope / block / body
120
189
  end
121
190
 
191
+ def rewrite_dvar(exp)
192
+ exp[0] = :lvar
193
+ exp
194
+ end
195
+
122
196
  def rewrite_fcall(exp)
123
197
  exp[0] = :call
124
198
  exp.insert 1, nil
@@ -127,55 +201,105 @@ module UnifiedRuby
127
201
  rewrite_call(exp)
128
202
  end
129
203
 
130
- def rewrite_resbody(exp) # TODO: clean up and move to unified
131
- result = s()
204
+ def rewrite_masgn(exp)
205
+ raise "wtf: #{exp}" unless exp.size == 4
132
206
 
133
- code = result
134
- while exp and exp.first == :resbody do
135
- code << exp.shift
136
- list = exp.shift || s(:array)
137
- body = exp.empty? ? nil : exp.shift
138
- exp = exp.empty? ? nil : exp.shift
207
+ t, lhs, lhs_splat, rhs = exp
139
208
 
140
- # code may be nil, :lasgn, or :block
141
- case body.first
142
- when nil then
143
- # do nothing
144
- when :lasgn then
145
- # TODO: check that it is assigning $!
146
- list << body
147
- body = nil
148
- when :block then
149
- # TODO: check that it is assigning $!
150
- list << body.delete_at(1) if body[1].first == :lasgn
151
- else
152
- # do nothing (expression form)
153
- end if body
209
+ lhs ||= s(:array)
210
+
211
+ if lhs_splat then
212
+ lhs_splat = s(:splat, lhs_splat) unless lhs_splat[0] == :splat
213
+ lhs << lhs_splat
214
+ end
154
215
 
155
- code << list << body
156
- if exp then
157
- code = s()
158
- result << code
216
+ s(t, lhs, rhs).compact
217
+ end
218
+
219
+ def rewrite_op_asgn1(exp)
220
+ exp[2][0] = :arglist # if exp[2][0] == :array
221
+ exp
222
+ end
223
+
224
+ def rewrite_rescue(exp)
225
+ # SKETCHY HACK return exp if exp.size > 4
226
+ ignored = exp.shift
227
+ body = exp.shift unless exp.first.first == :resbody
228
+ resbody = exp.shift
229
+ els = exp.shift unless exp.first.first == :resbody unless exp.empty?
230
+ rest = exp.empty? ? nil : exp # graceful re-rewriting (see rewrite_begin)
231
+
232
+ resbodies = []
233
+
234
+ unless rest then
235
+ while resbody do
236
+ resbodies << resbody
237
+ resbody = resbody.resbody(true)
238
+ end
239
+
240
+ resbodies.each do |resbody|
241
+ if resbody[2] && resbody[2][0] == :block && resbody[2].size == 2 then
242
+ resbody[2] = resbody[2][-1]
243
+ end
159
244
  end
245
+ else
246
+ resbodies = [resbody] + rest
160
247
  end
161
248
 
162
- if $DEBUG or $TESTING then
163
- structure = result.structure
164
- raise "result structure wrong: #{structure[0..1].inspect}" unless
165
- structure.flatten[0] == :resbody
166
- raise "result structure wrong: #{structure[0..1].inspect}" unless
167
- s(:array, :splat, :argscat).include? structure.flatten[1]
168
- raise "result body wrong: #{structure[2].inspect}" unless
169
- structure[2].nil? or not structure[2].empty?
249
+ resbodies << els if els
250
+
251
+ s(:rescue, body, *resbodies).compact
252
+ end
253
+
254
+ def rewrite_resbody(exp)
255
+ exp[1] ||= s(:array) # no args
256
+
257
+ body = exp[2]
258
+ if body then
259
+ case body.first
260
+ when :lasgn, :iasgn then
261
+ exp[1] << exp.delete_at(2) if body[-1] == s(:gvar, :$!)
262
+ when :block then
263
+ exp[1] << body.delete_at(1) if [:lasgn, :iasgn].include?(body[1][0]) &&
264
+ body[1][-1] == s(:gvar, :$!)
265
+ end
170
266
  end
171
267
 
172
- result
268
+ exp << nil if exp.size == 2 # no body
269
+
270
+ exp
271
+ end
272
+
273
+ def rewrite_begin(exp)
274
+ raise "wtf: #{exp.inspect}" if exp.size > 2
275
+ exp.last
173
276
  end
174
277
 
175
278
  def rewrite_vcall(exp)
176
279
  exp.push nil
177
280
  rewrite_fcall(exp)
178
281
  end
282
+
283
+ def rewrite_yield(exp)
284
+ # Literal array in yield, not args.
285
+ if exp.size == 3 and exp.pop == true then
286
+ # exp[1] = s(:arglist, exp[1])
287
+ elsif exp.size == 2 && exp.last.first == :array then
288
+ exp.push(*exp.pop[1..-1])
289
+ end
290
+
291
+ exp
292
+ end
293
+
294
+ def rewrite_super(exp)
295
+ exp.push(*exp.pop[1..-1]) if exp.size == 2 && exp.last.first == :array
296
+ exp
297
+ end
298
+
299
+ def rewrite_zarray(exp)
300
+ exp[0] = :array
301
+ exp
302
+ end
179
303
  end
180
304
 
181
305
  ##
@@ -183,5 +307,9 @@ end
183
307
 
184
308
  class Unifier < SexpProcessor
185
309
  include UnifiedRuby
186
- end
187
310
 
311
+ def initialize
312
+ super
313
+ @unsupported.delete :newline
314
+ end
315
+ end