BOAST 0.9995 → 0.9996

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.
@@ -1,8 +1,9 @@
1
1
  module BOAST
2
2
 
3
3
  class Procedure
4
- include BOAST::Inspectable
5
- extend BOAST::Functor
4
+ include PrivateStateAccessor
5
+ include Inspectable
6
+ extend Functor
6
7
 
7
8
  attr_reader :name
8
9
  attr_reader :parameters
@@ -25,7 +26,7 @@ module BOAST
25
26
  headers.each { |h|
26
27
  s += "#include <#{h}>\n"
27
28
  }
28
- if BOAST::get_lang == CL then
29
+ if lang == CL then
29
30
  s += "__kernel "
30
31
  wgs = @properties[:reqd_work_group_size]
31
32
  if wgs then
@@ -61,34 +62,34 @@ module BOAST
61
62
  def boast_header(lang=C)
62
63
  s = boast_header_s(lang)
63
64
  s += ";\n"
64
- BOAST::get_output.print s
65
+ output.print s
65
66
  return self
66
67
  end
67
68
 
68
69
  def call(*parameters)
69
70
  prefix = ""
70
- prefix += "call " if BOAST::get_lang==FORTRAN
71
+ prefix += "call " if lang==FORTRAN
71
72
  f = FuncCall::new(@name, *parameters)
72
73
  f.prefix = prefix
73
74
  return f
74
75
  end
75
76
 
76
77
  def close
77
- return self.close_fortran if BOAST::get_lang==FORTRAN
78
- return self.close_c if [C, CL, CUDA].include?( BOAST::get_lang )
78
+ return close_fortran if lang==FORTRAN
79
+ return close_c if [C, CL, CUDA].include?( lang )
79
80
  end
80
81
 
81
82
  def close_c
82
- BOAST::decrement_indent_level
83
+ decrement_indent_level
83
84
  s = ""
84
85
  s += " return #{@properties[:return]};\n" if @properties[:return]
85
86
  s += "}"
86
- BOAST::get_output.puts s
87
+ output.puts s
87
88
  return self
88
89
  end
89
90
 
90
91
  def close_fortran
91
- BOAST::decrement_indent_level
92
+ decrement_indent_level
92
93
  s = ""
93
94
  if @properties[:return] then
94
95
  s += " #{@name} = #{@properties[:return]}\n"
@@ -96,22 +97,22 @@ module BOAST
96
97
  else
97
98
  s += "END SUBROUTINE #{@name}"
98
99
  end
99
- BOAST::get_output.puts s
100
+ output.puts s
100
101
  return self
101
102
  end
102
103
 
103
- def print
104
- self.open
104
+ def pr
105
+ open
105
106
  if @block then
106
107
  @block.call
107
- self.close
108
+ close
108
109
  end
109
110
  return self
110
111
  end
111
112
 
112
113
  def decl
113
- return self.decl_fortran if BOAST::get_lang==FORTRAN
114
- return self.decl_c if [C, CL, CUDA].include?( BOAST::get_lang )
114
+ return decl_fortran if lang==FORTRAN
115
+ return decl_c if [C, CL, CUDA].include?( lang )
115
116
  end
116
117
 
117
118
  def decl_fortran
@@ -120,7 +121,7 @@ module BOAST
120
121
 
121
122
  def decl_c_s
122
123
  s = ""
123
- if BOAST::get_lang == CL then
124
+ if lang == CL then
124
125
  if @properties[:local] then
125
126
  s += "static "
126
127
  else
@@ -130,7 +131,7 @@ module BOAST
130
131
  s += "__attribute__((reqd_work_group_size(#{wgs[0]},#{wgs[1]},#{wgs[2]}))) "
131
132
  end
132
133
  end
133
- elsif BOAST::get_lang == CUDA then
134
+ elsif lang == CUDA then
134
135
  if @properties[:local] then
135
136
  s += "static __device__ "
136
137
  else
@@ -162,26 +163,21 @@ module BOAST
162
163
 
163
164
  def decl_c
164
165
  s = decl_c_s + ";"
165
- BOAST::get_output.puts s
166
+ output.puts s
166
167
  return self
167
168
  end
168
169
 
169
170
  def open
170
- return self.open_fortran if BOAST::get_lang==FORTRAN
171
- return self.open_c if [C, CL, CUDA].include?( BOAST::get_lang )
171
+ return open_fortran if lang==FORTRAN
172
+ return open_c if [C, CL, CUDA].include?( lang )
172
173
  end
173
174
 
174
- def open_c
175
- s = decl_c_s + "{"
176
- BOAST::get_output.puts s
177
- BOAST::increment_indent_level
178
- constants.each { |c|
179
- c.decl
180
- }
181
- return self
175
+ def to_s
176
+ return decl_c_s if [C, CL, CUDA].include?( lang )
177
+ return to_s_fortran if lang==FORTRAN
182
178
  end
183
179
 
184
- def open_fortran
180
+ def to_s_fortran
185
181
  s = ""
186
182
  if @properties[:return] then
187
183
  s += "#{@properties[:return].type.decl} FUNCTION "
@@ -190,10 +186,25 @@ module BOAST
190
186
  end
191
187
  s += "#{@name}("
192
188
  s += parameters.join(", ")
193
- s += ")\n"
194
- BOAST::increment_indent_level
195
- s += BOAST::indent + "integer, parameter :: wp=kind(1.0d0)"
196
- BOAST::get_output.puts s
189
+ s += ")"
190
+ end
191
+
192
+ def open_c
193
+ s = decl_c_s + "{"
194
+ output.puts s
195
+ increment_indent_level
196
+ constants.each { |c|
197
+ c.decl
198
+ }
199
+ return self
200
+ end
201
+
202
+ def open_fortran
203
+ s = to_s_fortran
204
+ s += "\n"
205
+ increment_indent_level
206
+ s += indent + "integer, parameter :: wp=kind(1.0d0)"
207
+ output.puts s
197
208
  constants.each { |c|
198
209
  c.decl
199
210
  }
@@ -202,6 +213,7 @@ module BOAST
202
213
  }
203
214
  return self
204
215
  end
216
+
205
217
  end
206
218
 
207
219
  end
@@ -0,0 +1,79 @@
1
+ module BOAST
2
+
3
+ def self.state_accessor(*args)
4
+ args.each { |arg|
5
+ s = <<EOF
6
+ def #{arg}=(val)
7
+ @@#{arg} = val
8
+ end
9
+ module_function :#{arg}=
10
+ def #{arg}
11
+ @@#{arg}
12
+ end
13
+ module_function :#{arg}
14
+ def set_#{arg}(val)
15
+ @@#{arg} = val
16
+ end
17
+ module_function :set_#{arg}
18
+ def get_#{arg}
19
+ @@#{arg}
20
+ end
21
+ module_function :get_#{arg}
22
+ EOF
23
+ eval s
24
+ }
25
+ end
26
+
27
+ def self.boolean_state_accessor(*args)
28
+ self.state_accessor(*args)
29
+ args.each { |arg|
30
+ s = <<EOF
31
+ def #{arg}?
32
+ !!@@#{arg}
33
+ end
34
+ module_function :#{arg}?
35
+ EOF
36
+ eval s
37
+ }
38
+ end
39
+
40
+ module PrivateStateAccessor
41
+
42
+ def self.private_state_accessor(*args)
43
+ args.each { |arg|
44
+ s = <<EOF
45
+ private
46
+ def #{arg}=(val)
47
+ BOAST::#{arg}= val
48
+ end
49
+ def #{arg}
50
+ BOAST::#{arg}
51
+ end
52
+ def set_#{arg}(val)
53
+ BOAST::set_#{arg}(val)
54
+ end
55
+ def get_#{arg}
56
+ BOAST::get_#{arg}
57
+ end
58
+ EOF
59
+ eval s
60
+ }
61
+ end
62
+
63
+ def self.private_boolean_state_accessor(*args)
64
+ self.private_state_accessor(*args)
65
+ args.each { |arg|
66
+ s = <<EOF
67
+ private
68
+ def #{arg}?
69
+ BOAST::#{arg}?
70
+ end
71
+ EOF
72
+ eval s
73
+ }
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
@@ -1,9 +1,11 @@
1
1
  module BOAST
2
+
2
3
  module TypeTransition
4
+
3
5
  @@transitions = Hash::new { |hash, key| hash[key] = Hash::new }
6
+
4
7
  def get_transition(type1, type2, operator)
5
8
  #STDERR.puts @@transitions.inspect
6
- #STDERR.puts @@transitions[t1][t2].inspec
7
9
  ops = @@transitions[[type1,type2]]
8
10
  raise "Types #{[type1,type2]} have no relation!" if not ops
9
11
  t = ops[operator]
@@ -21,19 +23,25 @@ module BOAST
21
23
  signed = false
22
24
  size = nil
23
25
  vector_length = 1
24
- return_type, operator = get_transition(var1.type.class, var2.type.class, operator)
26
+ t1 = var1.type.class
27
+ t2 = var2.type.class
28
+ t1 = var1.type.name if t1 == CustomType
29
+ t2 = var2.type.name if t2 == CustomType
30
+ return_type, operator = get_transition(t1, t2, operator)
25
31
  #STDERR.puts "#{return_type} : #{var1.type.class} #{operator} #{var2.type.class}"
26
- if var1.type.class == return_type and var2.type.class == return_type then
32
+ if t1 == return_type and t2 == return_type then
27
33
  signed = (signed or var1.type.signed)
28
34
  signed = (signed or var2.type.signed)
29
35
  size = [var1.type.size, var2.type.size].max
30
36
  vector_length = [var1.type.vector_length, var2.type.vector_length].max
31
- [BOAST::Variable::new("dummy", return_type, :size => size, :signed => signed, :vector_length => vector_length), operator]
37
+ [Variable::new("dummy", return_type, :size => size, :signed => signed, :vector_length => vector_length), operator]
32
38
  elsif var1.type.class == return_type then
33
39
  return [var1, operator]
34
- elsif var2.type.class == return_type then
40
+ else # var2.type.class == return_type then
35
41
  return [var2, operator]
36
42
  end
37
43
  end
44
+
38
45
  end
46
+
39
47
  end
@@ -1,8 +1,9 @@
1
1
  module BOAST
2
2
 
3
3
  class Dimension
4
- include BOAST::Inspectable
5
- extend BOAST::Functor
4
+ include PrivateStateAccessor
5
+ include Inspectable
6
+ extend Functor
6
7
 
7
8
  attr_reader :val1
8
9
  attr_reader :val2
@@ -13,8 +14,8 @@ module BOAST
13
14
  @val1 = nil
14
15
  @val2 = nil
15
16
  if v2.nil? and v1 then
16
- @val1 = BOAST::get_array_start
17
- @val2 = v1 + BOAST::get_array_start - 1
17
+ @val1 = get_array_start
18
+ @val2 = v1 + get_array_start - 1
18
19
  @size = v1
19
20
  else
20
21
  @val1 = v1
@@ -25,11 +26,11 @@ module BOAST
25
26
  def to_s
26
27
  s = ""
27
28
  if @val2 then
28
- if BOAST::get_lang == BOAST::FORTRAN then
29
+ if lang == FORTRAN then
29
30
  s += @val1.to_s
30
31
  s += ":"
31
32
  s += @val2.to_s
32
- elsif [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang ) then
33
+ elsif [C, CL, CUDA].include?( lang ) then
33
34
  s += (@val2 - @val1 + 1).to_s
34
35
  end
35
36
  elsif @val1.nil? then
@@ -42,7 +43,8 @@ module BOAST
42
43
  end
43
44
 
44
45
  class ConstArray < Array
45
- include BOAST::Inspectable
46
+ include PrivateStateAccessor
47
+ include Inspectable
46
48
 
47
49
  def initialize(array,type = nil)
48
50
  super(array)
@@ -50,15 +52,15 @@ module BOAST
50
52
  end
51
53
 
52
54
  def to_s
53
- return self.to_s_fortran if BOAST::get_lang == BOAST::FORTRAN
54
- return self.to_s_c if [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
55
+ return to_s_fortran if lang == FORTRAN
56
+ return to_s_c if [C, CL, CUDA].include?( lang )
55
57
  end
56
58
 
57
59
  def to_s_fortran
58
60
  s = ""
59
- return s if self.first.nil?
61
+ return s if first.nil?
60
62
  s += "(/ &\n"
61
- s += self.first.to_s
63
+ s += first.to_s
62
64
  s += "_wp" if @type and @type.size == 8
63
65
  self[1..-1].each { |v|
64
66
  s += ", &\n"+v.to_s
@@ -69,9 +71,9 @@ module BOAST
69
71
 
70
72
  def to_s_c
71
73
  s = ""
72
- return s if self.first.nil?
74
+ return s if first.nil?
73
75
  s += "{\n"
74
- s += self.first.to_s
76
+ s += first.to_s
75
77
  self[1..-1].each { |v|
76
78
  s += ",\n"+v.to_s
77
79
  }
@@ -80,17 +82,19 @@ module BOAST
80
82
  end
81
83
 
82
84
  class Variable
83
- include BOAST::Arithmetic
84
- include BOAST::Inspectable
85
- extend BOAST::Functor
85
+ include PrivateStateAccessor
86
+ include Arithmetic
87
+ include Inspectable
88
+ extend Functor
86
89
 
87
90
  alias_method :orig_method_missing, :method_missing
88
91
 
89
92
  def method_missing(m, *a, &b)
90
- return self.struct_reference(type.members[m.to_s]) if type.members[m.to_s]
91
- # return self.get_element(m.to_s) if type.getters[m.to_s]
92
- # return self.set_element(m.to_s) if type.setters[m.to_s]
93
- return self.orig_method_missing(m, *a, &b)
93
+ if @type.methods.include?(:members) and @type.members[m.to_s] then
94
+ return struct_reference(type.members[m.to_s])
95
+ else
96
+ return orig_method_missing(m, *a, &b)
97
+ end
94
98
  end
95
99
 
96
100
  attr_reader :name
@@ -106,6 +110,38 @@ module BOAST
106
110
  attr_accessor :replace_constant
107
111
  attr_accessor :force_replace_constant
108
112
 
113
+ def constant?
114
+ !!@constant
115
+ end
116
+
117
+ def allocate?
118
+ !!@allocate
119
+ end
120
+
121
+ def texture?
122
+ !!@texture
123
+ end
124
+
125
+ def local?
126
+ !!@local
127
+ end
128
+
129
+ def restrict?
130
+ !!@restrict
131
+ end
132
+
133
+ def replace_constant?
134
+ !!@replace_constant
135
+ end
136
+
137
+ def force_replace_constant?
138
+ !!@force_replace_constant
139
+ end
140
+
141
+ def dimension?
142
+ !!@dimension
143
+ end
144
+
109
145
  def initialize(name,type,hash={})
110
146
  @name = name.to_s
111
147
  @direction = hash[:direction] ? hash[:direction] : hash[:dir]
@@ -121,19 +157,19 @@ module BOAST
121
157
  else
122
158
  @replace_constant = true
123
159
  end
124
- if @texture and BOAST::get_lang == BOAST::CL then
125
- @sampler = Variable::new("sampler_#{name}", BOAST::CustomType,:type_name => "sampler_t" ,:replace_constant => false, :constant => "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST")
160
+ if @texture and lang == CL then
161
+ @sampler = Variable::new("sampler_#{name}", CustomType,:type_name => "sampler_t" ,:replace_constant => false, :constant => "CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST")
126
162
  else
127
163
  @sampler = nil
128
164
  end
129
165
  @type = type::new(hash)
130
166
  @options = hash
131
- if (@direction == :out or @direction == :inout) and not @dimension then
167
+ if (@direction == :out or @direction == :inout) and not dimension? then
132
168
  @scalar_output = true
133
169
  else
134
170
  @scalar_output = false
135
171
  end
136
- @dimension = [@dimension].flatten if @dimension
172
+ @dimension = [@dimension].flatten if dimension?
137
173
  end
138
174
 
139
175
  def copy(name=nil,options={})
@@ -145,7 +181,7 @@ module BOAST
145
181
  return Variable::new(name, @type.class, h)
146
182
  end
147
183
 
148
- def Variable.from_type(name, type, options={})
184
+ def self.from_type(name, type, options={})
149
185
  hash = type.to_hash
150
186
  options.each { |k,v|
151
187
  hash[k] = v
@@ -156,13 +192,13 @@ module BOAST
156
192
  end
157
193
 
158
194
  def to_s
159
- if @force_replace_constant or ( @replace_constant and @constant and BOAST::get_replace_constants and not @dimension ) then
195
+ if force_replace_constant? or ( replace_constant? and constant? and replace_constants? and not dimension? ) then
160
196
  s = @constant.to_s
161
- s += "_wp" if BOAST::get_lang == BOAST::FORTRAN and @type and @type.size == 8
197
+ s += "_wp" if lang == FORTRAN and @type and @type.size == 8
162
198
  return s
163
199
  end
164
- if @scalar_output and [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang ) then
165
- return "(*#{self.name})"
200
+ if @scalar_output and [C, CL, CUDA].include?( lang ) then
201
+ return "(*#{name})"
166
202
  end
167
203
  return @name
168
204
  end
@@ -172,18 +208,18 @@ module BOAST
172
208
  end
173
209
 
174
210
  def set(x)
175
- return Expression::new(BOAST::Set, self, x)
211
+ return Expression::new(Set, self, x)
176
212
  end
177
213
 
178
214
  def dereference
179
- return self.copy("*(#{self.name})", :dimension => nil, :dim => nil, :direction => nil, :dir => nil) if [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
180
- return self if BOAST::get_lang == BOAST::FORTRAN
215
+ return copy("*(#{name})", :dimension => nil, :dim => nil, :direction => nil, :dir => nil) if [C, CL, CUDA].include?( lang )
216
+ return self if lang == FORTRAN
181
217
  #return Expression::new("*",nil,self)
182
218
  end
183
219
 
184
220
  def struct_reference(x)
185
- return x.copy(self.name+"."+x.name) if [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
186
- return x.copy(self.name+"%"+x.name) if BOAST::get_lang == BOAST::FORTRAN
221
+ return x.copy(name+"."+x.name) if [C, CL, CUDA].include?( lang )
222
+ return x.copy(name+"%"+x.name) if lang == FORTRAN
187
223
  end
188
224
 
189
225
  def inc
@@ -196,20 +232,20 @@ module BOAST
196
232
 
197
233
  def finalize
198
234
  s = ""
199
- s += ";" if [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
235
+ s += ";" if [C, CL, CUDA].include?( lang )
200
236
  s+="\n"
201
237
  return s
202
238
  end
203
239
 
204
240
  def boast_header(lang=C)
205
- return decl_texture_s if @texture
241
+ return decl_texture_s if texture?
206
242
  s = ""
207
- s += "const " if @constant or @direction == :in
243
+ s += "const " if constant? or @direction == :in
208
244
  s += @type.decl
209
- if @dimension then
245
+ if dimension? then
210
246
  s += " *"
211
247
  end
212
- if not @dimension and ( lang == BOAST::FORTRAN or @direction == :out or @direction == :inout ) then
248
+ if not dimension? and ( lang == FORTRAN or @direction == :out or @direction == :inout ) then
213
249
  s += " *"
214
250
  end
215
251
  s += " #{@name}"
@@ -217,54 +253,54 @@ module BOAST
217
253
  end
218
254
 
219
255
  def decl
220
- return self.decl_fortran if BOAST::get_lang == BOAST::FORTRAN
221
- return self.decl_c if [BOAST::C, BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
256
+ return decl_fortran if lang == FORTRAN
257
+ return decl_c if [C, CL, CUDA].include?( lang )
222
258
  end
223
259
 
224
260
  def decl_c_s(device = false)
225
- return decl_texture_s if @texture
261
+ return decl_texture_s if texture?
226
262
  s = ""
227
- s += "const " if @constant or @direction == :in
228
- s += "__global " if @direction and @dimension and not (@options[:register] or @options[:private] or @local) and BOAST::get_lang == BOAST::CL
229
- s += "__local " if @local and BOAST::get_lang == BOAST::CL
230
- s += "__shared__ " if @local and not device and BOAST::get_lang == BOAST::CUDA
263
+ s += "const " if constant? or @direction == :in
264
+ s += "__global " if @direction and dimension? and not (@options[:register] or @options[:private] or local?) and lang == CL
265
+ s += "__local " if local? and lang == CL
266
+ s += "__shared__ " if local? and not device and lang == CUDA
231
267
  s += @type.decl
232
- if(@dimension and not @constant and not @allocate and (not @local or (@local and device))) then
268
+ if dimension? and not constant? and not allocate? and (not local? or (local? and device)) then
233
269
  s += " *"
234
- if @restrict then
235
- if BOAST::get_lang == BOAST::CL
270
+ if restrict? then
271
+ if lang == CL
236
272
  s += " restrict"
237
273
  else
238
274
  s += " __restrict__"
239
275
  end
240
276
  end
241
277
  end
242
- if not @dimension and ( @direction == :out or @direction == :inout ) then
278
+ if not dimension? and ( @direction == :out or @direction == :inout ) then
243
279
  s += " *"
244
280
  end
245
281
  s += " #{@name}"
246
- if @dimension and @constant then
282
+ if dimension? and constant? then
247
283
  s += "[]"
248
284
  end
249
- if @dimension and ((@local and not device) or (@allocate and not @constant)) then
285
+ if dimension? and ((local? and not device) or (allocate? and not constant?)) then
250
286
  s +="["
251
287
  s += @dimension.reverse.join("*")
252
288
  s +="]"
253
289
  end
254
- s += " = #{@constant}" if @constant
290
+ s += " = #{@constant}" if constant?
255
291
  return s
256
292
  end
257
293
 
258
294
  def decl_texture_s
259
- raise "Unsupported language #{BOAST::get_lang} for texture!" if not [BOAST::CL, BOAST::CUDA].include?( BOAST::get_lang )
260
- raise "Write is unsupported for textures!" if not (@constant or @direction == :in)
295
+ raise "Unsupported language #{lang} for texture!" if not [CL, CUDA].include?( lang )
296
+ raise "Write is unsupported for textures!" if not (constant? or @direction == :in)
261
297
  dim_number = 1
262
- if @dimension then
298
+ if dimension? then
263
299
  dim_number == @dimension.size
264
300
  end
265
301
  raise "Unsupported number of dimension: #{dim_number}!" if dim_number > 3
266
302
  s = ""
267
- if BOAST::get_lang == BOAST::CL then
303
+ if lang == CL then
268
304
  s += "__read_only "
269
305
  if dim_number < 3 then
270
306
  s += "image2d_t " #from OCL 1.2+ image1d_t is defined
@@ -280,21 +316,21 @@ module BOAST
280
316
 
281
317
  def decl_c
282
318
  s = ""
283
- s += BOAST::indent
284
- s += self.decl_c_s
285
- s += self.finalize
286
- BOAST::get_output.print s
319
+ s += indent
320
+ s += decl_c_s
321
+ s += finalize
322
+ output.print s
287
323
  return self
288
324
  end
289
325
 
290
326
 
291
327
  def decl_fortran
292
328
  s = ""
293
- s += BOAST::indent
329
+ s += indent
294
330
  s += @type.decl
295
331
  s += ", intent(#{@direction})" if @direction
296
- s += ", parameter" if @constant
297
- if(@dimension) then
332
+ s += ", parameter" if constant?
333
+ if dimension? then
298
334
  s += ", dimension("
299
335
  dim = @dimension[0].to_s
300
336
  if dim then
@@ -308,12 +344,12 @@ module BOAST
308
344
  s += ")"
309
345
  end
310
346
  s += " :: #{@name}"
311
- if @constant then
347
+ if constant? then
312
348
  s += " = #{@constant}"
313
- s += "_wp" if not @dimension and @type and @type.size == 8
349
+ s += "_wp" if not dimension? and @type and @type.size == 8
314
350
  end
315
- s += self.finalize
316
- BOAST::get_output.print s
351
+ s += finalize
352
+ output.print s
317
353
  return self
318
354
  end
319
355