dhaka 2.0.0 → 2.0.1

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 (68) hide show
  1. data/lib/dhaka.rb +24 -22
  2. data/lib/evaluator/evaluator.rb +42 -44
  3. data/lib/grammar/closure_hash.rb +4 -3
  4. data/lib/grammar/grammar.rb +113 -110
  5. data/lib/grammar/grammar_symbol.rb +6 -3
  6. data/lib/grammar/precedence.rb +3 -2
  7. data/lib/grammar/production.rb +5 -6
  8. data/lib/parser/action.rb +16 -11
  9. data/lib/parser/channel.rb +22 -16
  10. data/lib/parser/compiled_parser.rb +28 -22
  11. data/lib/parser/conflict.rb +54 -0
  12. data/lib/parser/item.rb +19 -19
  13. data/lib/parser/parse_result.rb +16 -1
  14. data/lib/parser/parse_tree.rb +15 -9
  15. data/lib/parser/parser.rb +51 -80
  16. data/lib/parser/parser_run.rb +6 -6
  17. data/lib/parser/parser_state.rb +16 -18
  18. data/lib/parser/token.rb +6 -4
  19. data/lib/tokenizer/tokenizer.rb +34 -31
  20. data/test/all_tests.rb +4 -18
  21. data/test/another_lalr_but_not_slr_grammar.rb +9 -5
  22. data/test/{arithmetic_evaluator.rb → arithmetic/arithmetic_evaluator.rb} +1 -2
  23. data/test/{arithmetic_evaluator_test.rb → arithmetic/arithmetic_evaluator_test.rb} +9 -20
  24. data/test/arithmetic/arithmetic_grammar.rb +41 -0
  25. data/test/{arithmetic_grammar_test.rb → arithmetic/arithmetic_grammar_test.rb} +2 -4
  26. data/test/{arithmetic_test_methods.rb → arithmetic/arithmetic_test_methods.rb} +1 -3
  27. data/test/{arithmetic_tokenizer.rb → arithmetic/arithmetic_tokenizer.rb} +8 -10
  28. data/test/{arithmetic_tokenizer_test.rb → arithmetic/arithmetic_tokenizer_test.rb} +4 -2
  29. data/test/{arithmetic_precedence_evaluator.rb → arithmetic_precedence/arithmetic_precedence_evaluator.rb} +1 -2
  30. data/test/arithmetic_precedence/arithmetic_precedence_grammar.rb +24 -0
  31. data/test/{arithmetic_precedence_grammar_test.rb → arithmetic_precedence/arithmetic_precedence_grammar_test.rb} +2 -3
  32. data/test/arithmetic_precedence/arithmetic_precedence_parser_test.rb +31 -0
  33. data/test/{arithmetic_precedence_tokenizer.rb → arithmetic_precedence/arithmetic_precedence_tokenizer.rb} +8 -10
  34. data/test/brackets/bracket_grammar.rb +23 -0
  35. data/test/{bracket_tokenizer.rb → brackets/bracket_tokenizer.rb} +2 -4
  36. data/test/{brackets_test.rb → brackets/brackets_test.rb} +3 -4
  37. data/test/chittagong/chittagong_driver.rb +47 -0
  38. data/test/{chittagong_driver_test.rb → chittagong/chittagong_driver_test.rb} +66 -58
  39. data/test/{chittagong_evaluator.rb → chittagong/chittagong_evaluator.rb} +28 -13
  40. data/test/{chittagong_evaluator_test.rb → chittagong/chittagong_evaluator_test.rb} +6 -10
  41. data/test/chittagong/chittagong_grammar.rb +110 -0
  42. data/test/{chittagong_parser_test.rb → chittagong/chittagong_parser_test.rb} +5 -7
  43. data/test/{chittagong_test.rb → chittagong/chittagong_test.rb} +27 -36
  44. data/test/{chittagong_tokenizer.rb → chittagong/chittagong_tokenizer.rb} +17 -17
  45. data/test/{chittagong_tokenizer_test.rb → chittagong/chittagong_tokenizer_test.rb} +2 -3
  46. data/test/compiled_parser_test.rb +9 -42
  47. data/test/dhaka_test_helper.rb +17 -0
  48. data/test/evaluator_test.rb +18 -3
  49. data/test/grammar_test.rb +10 -15
  50. data/test/lalr_but_not_slr_grammar.rb +10 -8
  51. data/test/malformed_grammar.rb +2 -4
  52. data/test/malformed_grammar_test.rb +2 -3
  53. data/test/nullable_grammar.rb +11 -8
  54. data/test/parse_result_test.rb +44 -0
  55. data/test/parser_state_test.rb +36 -0
  56. data/test/parser_test.rb +53 -103
  57. data/test/precedence_grammar.rb +6 -6
  58. data/test/precedence_grammar_test.rb +2 -3
  59. data/test/rr_conflict_grammar.rb +5 -7
  60. data/test/simple_grammar.rb +6 -8
  61. data/test/sr_conflict_grammar.rb +6 -6
  62. metadata +30 -26
  63. data/test/arithmetic_grammar.rb +0 -35
  64. data/test/arithmetic_precedence_grammar.rb +0 -24
  65. data/test/arithmetic_precedence_parser_test.rb +0 -33
  66. data/test/bracket_grammar.rb +0 -25
  67. data/test/chittagong_grammar.rb +0 -104
  68. data/test/incomplete_arithmetic_evaluator.rb +0 -60
@@ -1,65 +1,11 @@
1
- require "test/unit"
2
- require "yaml"
3
- require "chittagong_grammar"
4
- require "chittagong_tokenizer"
5
- require "chittagong_evaluator"
6
- require "fake_logger"
7
-
1
+ require File.dirname(__FILE__)+'/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/chittagong_grammar"
8
3
  unless Object.const_defined? :ChittagongParser
9
4
  eval(Dhaka::Parser.new(ChittagongGrammar, FakeLogger.new).compile_to_ruby_source_as(:ChittagongParser))
10
5
  end
11
-
12
- class ChittagongDriver
13
- def marked_program(program, error_position)
14
- if error_position > 0
15
- program[0..(error_position-1)] + ">>>" + program[error_position..-1]
16
- else
17
- ">>>"+program
18
- end
19
- end
20
-
21
- def parse_error_message unexpected_token, program
22
- if unexpected_token.symbol_name == Dhaka::END_SYMBOL_NAME
23
- "Unexpected end of file."
24
- else
25
- "Unexpected token #{unexpected_token.symbol_name}:\n#{marked_program(program, unexpected_token.input_position)}"
26
- end
27
- end
28
-
29
- def tokenize_error_message unexpected_char_index, program
30
- "Unexpected character #{program[unexpected_char_index].chr}:\n#{marked_program(program, unexpected_char_index)}"
31
- end
32
-
33
- def evaluation_error_message evaluation_result, program
34
- "#{evaluation_result.exception}:\n#{marked_program(program, evaluation_result.node.tokens[0].input_position)}"
35
- end
36
-
37
- def run(program)
38
- tokenize_result = ChittagongTokenizer.tokenize(program)
39
- if tokenize_result.has_error?
40
- return tokenize_error_message(tokenize_result.unexpected_char_index, program)
41
- end
42
-
43
- parse_result = ChittagongParser.parse(tokenize_result)
44
- if parse_result.has_error?
45
- return parse_error_message(parse_result.unexpected_token, program)
46
- end
47
-
48
- evaluation_result = ChittagongEvaluator.new([{}], output_stream = []).
49
- evaluate(parse_result.parse_tree)
50
- if evaluation_result.exception
51
- return (output_stream << evaluation_error_message(evaluation_result, program)).
52
- join("\n")
53
- end
54
-
55
- return output_stream.join("\n")
56
- end
57
-
58
- end
59
-
6
+ require File.dirname(__FILE__) + "/chittagong_driver"
60
7
 
61
8
  class TestChittagongDriver < Test::Unit::TestCase
62
-
63
9
  def setup
64
10
  @driver = ChittagongDriver.new
65
11
  end
@@ -178,7 +124,7 @@ Undefined variable c:
178
124
 
179
125
  ", @driver.run(program))
180
126
  end
181
-
127
+ # lipi:variable_scoping
182
128
  def test_variable_scope
183
129
  program = "
184
130
  x = 1
@@ -211,6 +157,7 @@ Undefined variable c:
211
157
 
212
158
  ", @driver.run(program))
213
159
  end
160
+ # lipi:variable_scoping
214
161
 
215
162
  def test_nested_function_calls
216
163
 
@@ -258,4 +205,65 @@ Undefined variable c:
258
205
  ", @driver.run(program))
259
206
 
260
207
  end
208
+
209
+ def test_an_empty_program
210
+ program = ""
211
+ assert_equal("Unexpected end of file.", @driver.run(program))
212
+ end
213
+
214
+ def test_associating_equality_tests_should_show_an_error
215
+ program = "
216
+ def foo()
217
+ print 999
218
+ end
219
+
220
+ foo()
221
+ print 1 == 1 == 1"
222
+
223
+ assert_equal("Unexpected token ==:
224
+
225
+ def foo()
226
+ print 999
227
+ end
228
+
229
+ foo()
230
+ print 1 == 1 >>>== 1", @driver.run(program))
231
+ end
232
+
233
+ def test_catches_bad_decimal_points
234
+ program = "
235
+ a = .234
236
+ b = 20.234.2
237
+ "
238
+
239
+ assert_equal("Unexpected token .:
240
+
241
+ a = .234
242
+ b = 20.234>>>.2
243
+ ", @driver.run(program))
244
+ end
245
+ # lipi:recursive_fib
246
+ def test_recursive_fibonacci
247
+ program = "
248
+
249
+ def fib(n)
250
+ if n == 0
251
+ return 1
252
+ end
253
+ if n == 1
254
+ return 1
255
+ end
256
+ return fib(n-1) + fib(n-2)
257
+ end
258
+
259
+ x = 0
260
+ while x < 9
261
+ print fib(x)
262
+ x = x + 1
263
+ end
264
+
265
+ "
266
+ assert_equal(["1", "1", "2", "3", "5", "8", "13", "21", "34"].join("\n"), @driver.run(program))
267
+ end
268
+ # lipi:recursive_fib
261
269
  end
@@ -1,5 +1,4 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'chittagong_grammar'
1
+ require File.dirname(__FILE__) + '/chittagong_grammar'
3
2
 
4
3
  class ChittagongEvaluator < Dhaka::Evaluator
5
4
 
@@ -25,14 +24,15 @@ class ChittagongEvaluator < Dhaka::Evaluator
25
24
  return first if (first.exception || first.result)
26
25
  evaluate(child_nodes[2])
27
26
  end
28
-
27
+ # lipi:function_defs
29
28
  for_function_definition do
30
- function_name = evaluate(child_nodes[1])
29
+ function_name = evaluate(child_nodes[1])
31
30
  arg_declarations = evaluate(child_nodes[3])
32
- body = child_nodes[6]
31
+ body = child_nodes[6]
33
32
  @function_table[function_name] = Function.new(arg_declarations, body)
34
33
  ChittagongSuccessResult.new(nil)
35
34
  end
35
+ # lipi:function_defs
36
36
 
37
37
  for_main_body_if_statement do
38
38
  checked_if_statement
@@ -76,7 +76,7 @@ class ChittagongEvaluator < Dhaka::Evaluator
76
76
  end
77
77
 
78
78
  def checked_while_statement
79
- while true
79
+ loop do
80
80
  condition_eval = evaluate(child_nodes[1])
81
81
  return condition_eval if condition_eval.exception
82
82
  break unless condition_eval.result
@@ -107,7 +107,7 @@ class ChittagongEvaluator < Dhaka::Evaluator
107
107
  for_function_call_expression do
108
108
  checked_function_call
109
109
  end
110
-
110
+ # lipi:checked_function_call
111
111
  def checked_function_call
112
112
  function_name = evaluate(child_nodes[0])
113
113
  return ChittagongExceptionResult.new("Undefined function #{function_name}",
@@ -121,6 +121,7 @@ class ChittagongEvaluator < Dhaka::Evaluator
121
121
  "Wrong number of arguments", child_nodes[1]
122
122
  ) unless function.args.size == arg_values.result.size
123
123
  new_frame = {}
124
+
124
125
  function.args.zip(arg_values.result).each do |arg_name, arg_value|
125
126
  new_frame[arg_name] = arg_value
126
127
  end
@@ -131,6 +132,7 @@ class ChittagongEvaluator < Dhaka::Evaluator
131
132
 
132
133
  result
133
134
  end
135
+ # lipi:checked_function_call
134
136
 
135
137
  for_return_statement do
136
138
  checked_unary_operation(child_nodes[1]){|x| x}
@@ -166,7 +168,16 @@ class ChittagongEvaluator < Dhaka::Evaluator
166
168
  ChittagongSuccessResult.new(@stack[-1][variable_name])
167
169
  end
168
170
 
169
- for_literal do
171
+
172
+ for_float_without_leading_digits do
173
+ ChittagongSuccessResult.new(('.' + child_nodes[1].token.value).to_f)
174
+ end
175
+
176
+ for_float_with_leading_digits do
177
+ ChittagongSuccessResult.new((child_nodes[0].token.value + '.' +child_nodes[2].token.value).to_f)
178
+ end
179
+
180
+ for_integer do
170
181
  ChittagongSuccessResult.new(child_nodes[0].token.value.to_i)
171
182
  end
172
183
 
@@ -229,23 +240,27 @@ class ChittagongEvaluator < Dhaka::Evaluator
229
240
  end
230
241
 
231
242
  for_function_name do
232
- child_nodes[0].token.value
243
+ token_value
233
244
  end
234
245
 
235
246
  for_variable_name do
236
- child_nodes[0].token.value
247
+ token_value
237
248
  end
238
249
 
239
250
  for_arg_declaration do
240
- child_nodes[0].token.value
251
+ token_value
241
252
  end
242
-
253
+
254
+ def token_value
255
+ child_nodes.first.token.value
256
+ end
257
+ # lipi:initialize
243
258
  def initialize(stack, output_stream)
244
259
  @stack = stack
245
260
  @function_table = {}
246
261
  @output_stream = output_stream
247
262
  end
248
-
263
+ # lipi:initialize
249
264
  end
250
265
 
251
266
  end
@@ -1,16 +1,12 @@
1
- require "test/unit"
2
-
3
- require "chittagong_evaluator"
4
- require "fake_logger"
5
-
6
- unless Object.const_defined? :ChittagongParser
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/chittagong_evaluator"
3
+ unless defined? ChittagongParser
7
4
  eval(Dhaka::Parser.new(ChittagongGrammar, FakeLogger.new).compile_to_ruby_source_as(:ChittagongParser))
8
5
  end
9
6
 
10
7
  class TestChittagongEvaluator < Test::Unit::TestCase
11
-
12
8
  def test_evaluates_a_simple_program
13
- token_stream = build_tokens(
9
+ token_stream = build_tokens(
14
10
  ['newline'],
15
11
  ['word_literal', 'x'], ['='], ['int_literal', 23], ['newline'],
16
12
  ['print'], ['word_literal', 'x'], ['newline'],
@@ -25,9 +21,9 @@ class TestChittagongEvaluator < Test::Unit::TestCase
25
21
  ['newline'],
26
22
  [Dhaka::END_SYMBOL_NAME]
27
23
  )
28
- stack = [{}]
24
+ stack = [{}]
29
25
  output_stream = []
30
- ChittagongEvaluator.new(stack, output_stream).evaluate(ChittagongParser.parse(token_stream).parse_tree)
26
+ ChittagongEvaluator.new(stack, output_stream).evaluate(ChittagongParser.parse(token_stream))
31
27
  assert_equal(23, stack[0]['x'])
32
28
  assert_equal(46, stack[0]['y'])
33
29
  assert_equal(['23', '1058', '46'], output_stream)
@@ -0,0 +1,110 @@
1
+ class ChittagongGrammar < Dhaka::Grammar
2
+
3
+ precedences do
4
+ nonassoc %w| == |
5
+ nonassoc %w| < > |
6
+ left %w| + - |
7
+ left %w| * / |
8
+ nonassoc %w| ^ |
9
+ nonassoc %w| ! |
10
+ end
11
+ # lipi:grammar_overview
12
+
13
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
14
+ program %w| opt_terms main_body opt_terms |
15
+ end
16
+
17
+ for_symbol('main_body') do
18
+ single_main_body_statement %w| main_body_statement |
19
+ multiple_main_body_statements %w| main_body terms main_body_statement |
20
+ end
21
+
22
+ for_symbol('main_body_statement') do
23
+ main_body_simple_statement %w| simple_statement |
24
+ function_definition %w| def function_name ( arg_declarations ) terms
25
+ function_body terms end |
26
+ main_body_if_statement %w| if expression terms main_body terms end |
27
+ main_body_if_else_statement %w| if expression terms main_body terms else terms main_body
28
+ terms end |
29
+ main_body_while_statement %w| while expression terms main_body terms end |
30
+ end
31
+ # lipi:grammar_overview
32
+
33
+ for_symbol('simple_statement') do
34
+ assignment_statement %w| var_name = expression |
35
+ print_statement %w| print expression |
36
+ function_call_statement %w| function_name ( arg_list ) |
37
+ end
38
+
39
+ for_symbol('function_body') do
40
+ single_function_body_statement %w| function_body_statement |
41
+ multiple_function_body_statements %w| function_body terms function_body_statement |
42
+ end
43
+
44
+ for_symbol('function_body_statement') do
45
+ function_body_simple_statement %w| simple_statement |
46
+ return_statement %w| return expression |
47
+ function_body_if_statement %w| if expression terms function_body terms end |
48
+ function_body_if_else_statement %w| if expression terms function_body terms else terms function_body terms end |
49
+ function_body_while_statement %w| while expression terms function_body terms end |
50
+ end
51
+
52
+ for_symbol('function_name') do
53
+ function_name %w| word_literal |
54
+ end
55
+
56
+ for_symbol('var_name') do
57
+ variable_name %w| word_literal |
58
+ end
59
+
60
+ for_symbol('arg_declarations') do
61
+ no_arg_decl %w| |
62
+ single_arg_declaration %w| arg_decl |
63
+ multiple_arg_declarations %w| arg_declarations , arg_decl |
64
+ end
65
+
66
+ for_symbol('arg_decl') do
67
+ arg_declaration %w| word_literal |
68
+ end
69
+
70
+ for_symbol('arg_list') do
71
+ no_args %w| |
72
+ single_arg %w| expression |
73
+ multiple_args %w| arg_list , expression |
74
+ end
75
+ # lipi:expressions
76
+ for_symbol('expression') do
77
+ negation %w| ! expression |
78
+ equality_comparison %w| expression == expression |
79
+ greater_than_comparison %w| expression > expression |
80
+ less_than_comparison %w| expression < expression |
81
+ addition %w| expression + expression |
82
+ subtraction %w| expression - expression |
83
+ multiplication %w| expression * expression |
84
+ division %w| expression / expression |
85
+ power %w| expression ^ expression |
86
+ literal %w| numeric_literal |
87
+ function_call_expression %w| function_name ( arg_list ) |
88
+ variable_reference %w| var_name |
89
+ parenthetized_expression %w| ( expression ) |
90
+ negated_expression %w| - expression |, :prec => '*'
91
+ end
92
+ # lipi:expressions
93
+
94
+ for_symbol('numeric_literal') do
95
+ integer %w| int_literal |
96
+ float_with_leading_digits %w| int_literal . int_literal |
97
+ float_without_leading_digits %w| . int_literal |
98
+ end
99
+
100
+ for_symbol('terms') do
101
+ single_term %w| newline |
102
+ multiple_terms %w| terms newline |
103
+ end
104
+
105
+ for_symbol('opt_terms') do
106
+ some_terms %w| terms |
107
+ no_terms %w| |
108
+ end
109
+
110
+ end
@@ -1,8 +1,5 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
-
3
- require 'chittagong_grammar'
4
- require "test/unit"
5
- require "fake_logger"
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + '/chittagong_grammar'
6
3
 
7
4
  class TestChittagongParser < Test::Unit::TestCase
8
5
  def setup
@@ -10,7 +7,7 @@ class TestChittagongParser < Test::Unit::TestCase
10
7
  @parser = Dhaka::Parser.new(ChittagongGrammar, fake_logger)
11
8
  assert_equal(80, fake_logger.warnings.size)
12
9
  assert_equal(0, fake_logger.errors.size)
13
- eval(@parser.compile_to_ruby_source_as(:ChittagongParser)) unless Module.const_defined? :ChittagongParser
10
+ eval(@parser.compile_to_ruby_source_as(:ChittagongParser)) unless defined? ChittagongParser
14
11
  end
15
12
 
16
13
  def test_parses_a_series_of_statements
@@ -28,6 +25,7 @@ class TestChittagongParser < Test::Unit::TestCase
28
25
  assert_equal(["single_term",
29
26
  "some_terms",
30
27
  "variable_name",
28
+ "integer",
31
29
  "literal",
32
30
  "assignment_statement",
33
31
  "main_body_simple_statement",
@@ -49,7 +47,7 @@ class TestChittagongParser < Test::Unit::TestCase
49
47
  "single_term",
50
48
  "multiple_terms",
51
49
  "some_terms",
52
- "program"], result.parse_tree.linearize.collect {|node| node.production.name})
50
+ "program"], result.linearize.collect {|node| node.production.name})
53
51
 
54
52
  end
55
53
 
@@ -1,15 +1,11 @@
1
- require "test/unit"
2
-
3
- require "chittagong_grammar"
4
- require "chittagong_tokenizer"
5
- require "chittagong_evaluator"
6
- require "fake_logger"
7
-
8
- unless Object.const_defined? :ChittagongParser
9
- eval(Dhaka::Parser.new(ChittagongGrammar, FakeLogger.new).compile_to_ruby_source_as(:ChittagongParser))
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/chittagong_grammar"
3
+ require File.dirname(__FILE__) + "/chittagong_tokenizer"
4
+ require File.dirname(__FILE__) + "/chittagong_evaluator"
5
+ unless defined? ChittagongParser
6
+ eval(Dhaka::Parser.new(ChittagongGrammar, FakeLogger.new).compile_to_ruby_source_as(:ChittagongParser))
10
7
  end
11
8
 
12
-
13
9
  class TestChittagong < Test::Unit::TestCase
14
10
 
15
11
  def fact(n)
@@ -20,7 +16,7 @@ class TestChittagong < Test::Unit::TestCase
20
16
  def program_output program
21
17
  output_stream = []
22
18
  parse_result = ChittagongParser.parse(ChittagongTokenizer.tokenize(program))
23
- result = ChittagongEvaluator.new([{}], output_stream).evaluate(parse_result.parse_tree)
19
+ result = ChittagongEvaluator.new([{}], output_stream).evaluate(parse_result)
24
20
  return result, output_stream
25
21
  end
26
22
 
@@ -71,30 +67,6 @@ class TestChittagong < Test::Unit::TestCase
71
67
  assert_equal(["1", "1", "2", "3", "5", "8", "13", "21", "34"], output_stream)
72
68
  end
73
69
 
74
- def test_recursive_fibonacci
75
- program = "
76
-
77
- def fib(n)
78
- if n == 0
79
- return 1
80
- end
81
- if n == -1
82
- return 0
83
- end
84
- return fib(n-1) + fib(n-2)
85
- end
86
-
87
- x = 0
88
- while x < 9
89
- print fib(x)
90
- x = x + 1
91
- end
92
-
93
- "
94
- result, output_stream = program_output(program)
95
- assert_equal(["1", "1", "2", "3", "5", "8", "13", "21", "34"], output_stream)
96
- end
97
-
98
70
  def test_recursive_factorial
99
71
  program = "
100
72
  def fact(n)
@@ -172,4 +144,23 @@ class TestChittagong < Test::Unit::TestCase
172
144
  assert_equal(["1", "2"], output_stream)
173
145
  end
174
146
 
175
- end
147
+ def test_decimal_numbers
148
+ program = "
149
+ print .2347 * 23.34
150
+ a = 1.012
151
+ b = 345.44
152
+ c = .234
153
+ print (a^b)/c
154
+ def foo(a)
155
+ print a
156
+ end
157
+ foo(3.4)
158
+ "
159
+
160
+ result, output_stream = program_output(program)
161
+ assert_equal(["5.477898", "263.233029427781", "3.4"], output_stream)
162
+ end
163
+
164
+
165
+
166
+ end