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,19 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'test/unit'
3
- require 'grammar_test'
4
- require 'malformed_grammar_test'
5
- require 'parser_test'
6
- require 'evaluator_test'
7
- require 'compiled_parser_test'
8
- require 'arithmetic_evaluator_test'
9
- require 'arithmetic_grammar_test'
10
- require 'arithmetic_tokenizer_test'
11
- require 'arithmetic_precedence_grammar_test'
12
- require 'arithmetic_precedence_parser_test'
13
- require 'brackets_test'
14
- require 'precedence_grammar_test'
15
- require 'chittagong_parser_test'
16
- require 'chittagong_evaluator_test'
17
- require 'chittagong_tokenizer_test'
18
- require 'chittagong_test'
19
- require 'chittagong_driver_test'
2
+ Dir['**/*test.rb'].each do |test_file|
3
+ puts test_file
4
+ require File.join(File.dirname(__FILE__), test_file)
5
+ end
@@ -1,16 +1,20 @@
1
1
  require File.dirname(__FILE__)+'/../lib/dhaka'
2
2
 
3
3
  class AnotherLALRButNotSLRGrammar < Dhaka::Grammar
4
+
4
5
  for_symbol(Dhaka::START_SYMBOL_NAME) do
5
- assignment ['L', '=', 'R']
6
- rhs ['R']
6
+ assignment %w| L = R |
7
+ rhs %w| R |
7
8
  end
9
+
8
10
  for_symbol('L') do
9
- contents ['*', 'R']
10
- identifier ['id']
11
+ contents %w| * R |
12
+ identifier %w| id |
11
13
  end
14
+
12
15
  for_symbol('R') do
13
- l_value ['L']
16
+ l_value %w| L |
14
17
  end
18
+
15
19
  end
16
20
 
@@ -1,5 +1,4 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'arithmetic_grammar'
1
+ require File.dirname(__FILE__) + '/arithmetic_grammar'
3
2
 
4
3
  class ArithmeticEvaluator < Dhaka::Evaluator
5
4
 
@@ -1,7 +1,8 @@
1
- require 'test/unit'
2
- require 'arithmetic_evaluator'
3
- require 'arithmetic_test_methods'
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + '/arithmetic_evaluator'
3
+ require File.dirname(__FILE__) + '/arithmetic_test_methods'
4
4
  eval(Dhaka::Parser.new(ArithmeticGrammar).compile_to_ruby_source_as(:CompiledArithmeticParser))
5
+
5
6
  class TestArithmeticEvaluator < Test::Unit::TestCase
6
7
  include ArithmeticTestMethods
7
8
 
@@ -10,45 +11,33 @@ class TestArithmeticEvaluator < Test::Unit::TestCase
10
11
  @max_func = Proc.new {|args| args.inject {|max, elem| max = (elem > max ? elem : max)}}
11
12
  end
12
13
 
13
-
14
14
  def test_results_simple_arithmetic_given_tokens_and_parse_tree_1
15
-
16
15
  token_stream = [token('n', 2), token('-', nil), token('n', 4), token(Dhaka::END_SYMBOL_NAME, nil)]
17
- parse_tree = parse(token_stream)
16
+ parse_tree = parse(token_stream)
18
17
  assert_equal -2, ArithmeticEvaluator.new(@min_func, @max_func).evaluate(parse_tree)
19
-
20
18
  end
21
19
 
22
20
  def test_results_simple_arithmetic_given_tokens_and_parse_tree_2
23
-
24
21
  token_stream = [token('n', 2), token('-', nil), token('(', nil), token('n', 3), token('/', nil), token('n', 4), token(')', nil), token(Dhaka::END_SYMBOL_NAME, nil)]
25
- parse_tree = parse(token_stream)
22
+ parse_tree = parse(token_stream)
26
23
  assert_equal 1.25, ArithmeticEvaluator.new(@min_func, @max_func).evaluate(parse_tree)
27
-
28
24
  end
29
25
 
30
26
  def test_results_simple_arithmetic_given_tokens_and_parse_tree_3
31
-
32
27
  token_stream = [token('n', 2), token('+', nil), token('(', nil), token('n', 3), token('/', nil), token('(', nil), token('n', 7), token('-', nil), token('n', 5), token(')', nil) , token(')', nil), token(Dhaka::END_SYMBOL_NAME, nil)]
33
- parse_tree = parse(token_stream)
28
+ parse_tree = parse(token_stream)
34
29
  assert_equal 3.5, ArithmeticEvaluator.new(@min_func, @max_func).evaluate(parse_tree)
35
-
36
30
  end
37
31
 
38
32
  def test_results_simple_arithmetic_given_tokens_and_parse_tree_4
39
-
40
33
  token_stream = [token('n', 2), token('+', nil), token('h', nil), token('(', nil), token('n', 3), token(',', nil), token('n', 4), token(')', nil), token(Dhaka::END_SYMBOL_NAME, nil)]
41
- parse_tree = parse(token_stream)
34
+ parse_tree = parse(token_stream)
42
35
  assert_equal 6, ArithmeticEvaluator.new(@min_func, @max_func).evaluate(parse_tree)
43
-
44
36
  end
45
37
 
46
38
  def test_results_simple_arithmetic_given_tokens_and_parse_tree_5
47
-
48
39
  token_stream = [token('n', 2), token('+', nil), token('l', nil), token('(', nil), token('n', 3), token(',', nil), token('n', 4), token(')', nil), token(Dhaka::END_SYMBOL_NAME, nil)]
49
- parse_tree = parse(token_stream)
40
+ parse_tree = parse(token_stream)
50
41
  assert_equal 5, ArithmeticEvaluator.new(@min_func, @max_func).evaluate(parse_tree)
51
-
52
42
  end
53
-
54
43
  end
@@ -0,0 +1,41 @@
1
+ class ArithmeticGrammar < Dhaka::Grammar
2
+
3
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
4
+ expression %w| E |
5
+ end
6
+
7
+ for_symbol('E') do
8
+ subtraction %w| E - T |
9
+ addition %w| E + T |
10
+ term %w| T |
11
+ end
12
+
13
+ for_symbol('T') do
14
+ factor %w| F |
15
+ division %w| T / F |
16
+ multiplication %w| T * F |
17
+ end
18
+
19
+ for_symbol('F') do
20
+ getting_literals %w| n |
21
+ unpacking_parenthetized_expression %w| ( E ) |
22
+ function %w| Function |
23
+ end
24
+
25
+ for_symbol('Function') do
26
+ evaluating_function %w| FunctionName ( Args ) |
27
+ end
28
+
29
+ for_symbol('FunctionName') do
30
+ max_function %w| h |
31
+ min_function %w| l |
32
+ end
33
+
34
+ for_symbol('Args') do
35
+ empty_args %w||
36
+ single_args %w| E |
37
+ concatenating_args %w| E , Args |
38
+ end
39
+
40
+ end
41
+
@@ -1,11 +1,9 @@
1
- require 'test/unit'
2
- require 'arithmetic_grammar'
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + '/arithmetic_grammar'
3
3
 
4
4
  class ArithmeticGrammarTest < Test::Unit::TestCase
5
-
6
5
  def test_first_with_nullable_non_terminals
7
6
  grammar = ArithmeticGrammar
8
7
  assert_equal(Set.new(['(', 'n', 'h', 'l']), Set.new(grammar.first(grammar.symbol_for_name('Args')).collect { |symbol| symbol.name }))
9
8
  end
10
-
11
9
  end
@@ -1,11 +1,9 @@
1
1
  module ArithmeticTestMethods
2
-
3
2
  def parse(token_stream)
4
- CompiledArithmeticParser.parse(token_stream).parse_tree
3
+ CompiledArithmeticParser.parse(token_stream)
5
4
  end
6
5
 
7
6
  def token(symbol_name, value)
8
7
  Dhaka::Token.new(symbol_name, value, nil)
9
8
  end
10
-
11
9
  end
@@ -1,15 +1,13 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'arithmetic_grammar'
3
-
1
+ require File.dirname(__FILE__) + '/arithmetic_grammar'
4
2
 
5
3
  class ArithmeticTokenizer < Dhaka::Tokenizer
6
4
 
7
- digits = ('0'..'9').to_a
8
- parenths = ['(', ')']
9
- operators = ['-', '+', '/', '*']
10
- functions = ['h', 'l']
11
- arg_separator = [',']
12
- whitespace = [' ']
5
+ digits = ('0'..'9').to_a
6
+ parenths = %w| ( ) |
7
+ operators = %w| - + / * |
8
+ functions = %w| h l |
9
+ arg_separator = %w| , |
10
+ whitespace = [' ']
13
11
 
14
12
  all_characters = digits + parenths + operators + functions + arg_separator + whitespace
15
13
 
@@ -32,7 +30,7 @@ class ArithmeticTokenizer < Dhaka::Tokenizer
32
30
  switch_to Dhaka::TOKENIZER_IDLE_STATE
33
31
  end
34
32
  for_characters digits do
35
- curr_token.value += curr_char
33
+ curr_token.value << curr_char
36
34
  advance
37
35
  end
38
36
  end
@@ -1,13 +1,15 @@
1
- require "test/unit"
2
- require "arithmetic_tokenizer"
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/arithmetic_tokenizer"
3
3
 
4
4
  class TestArithmeticTokenizer < Test::Unit::TestCase
5
5
  def test_returns_end_of_input_token_for_empty_input
6
6
  assert_equal([token(Dhaka::END_SYMBOL_NAME, nil)], ArithmeticTokenizer.tokenize([]).to_a)
7
7
  end
8
+
8
9
  def test_tokenizes_given_a_string_input
9
10
  assert_equal([token('n', 2), token('-', nil), token('n', 4), token(Dhaka::END_SYMBOL_NAME, nil)], ArithmeticTokenizer.tokenize('2 - 4').to_a)
10
11
  end
12
+
11
13
  def test_a_longer_input
12
14
  actual = ArithmeticTokenizer.tokenize('2+(3 / (7 - 5))').to_a
13
15
  assert_equal([token('n', 2), token('+', nil), token('(', nil), token('n', 3), token('/', nil), token('(', nil), token('n', 7), token('-', nil), token('n', 5), token(')', nil) , token(')', nil), token(Dhaka::END_SYMBOL_NAME, nil)], actual)
@@ -1,5 +1,4 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'arithmetic_precedence_grammar'
1
+ require File.dirname(__FILE__) + '/arithmetic_precedence_grammar'
3
2
 
4
3
  class ArithmeticPrecedenceEvaluator < Dhaka::Evaluator
5
4
 
@@ -0,0 +1,24 @@
1
+ class ArithmeticPrecedenceGrammar < Dhaka::Grammar
2
+
3
+ precedences do
4
+ left %w| + - |
5
+ left %w| * / |
6
+ nonassoc %w| ^ |
7
+ end
8
+
9
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
10
+ expression %w| E |
11
+ end
12
+
13
+ for_symbol('E') do
14
+ addition %w| E + E |
15
+ subtraction %w| E - E |
16
+ multiplication %w| E * E |
17
+ division %w| E / E |
18
+ power %w| E ^ E |
19
+ literal %w| n |
20
+ parenthetized_expression %w| ( E ) |
21
+ negated_expression %w| - E |, :prec => '*'
22
+ end
23
+
24
+ end
@@ -1,8 +1,7 @@
1
- require "test/unit"
2
- require 'arithmetic_precedence_grammar'
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + '/arithmetic_precedence_grammar'
3
3
 
4
4
  class TestArithmeticPrecedenceGrammar < Test::Unit::TestCase
5
-
6
5
  def setup
7
6
  @addop = ArithmeticPrecedenceGrammar.symbol_for_name('+')
8
7
  @subop = ArithmeticPrecedenceGrammar.symbol_for_name('-')
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/arithmetic_precedence_grammar"
3
+ require File.dirname(__FILE__) + "/arithmetic_precedence_tokenizer"
4
+ require File.dirname(__FILE__) + "/arithmetic_precedence_evaluator"
5
+
6
+ class TestArithmeticPrecedenceParser < Test::Unit::TestCase
7
+ def test_parses_arithmetic_expressions
8
+ fake_logger = FakeLogger.new
9
+ parser = Dhaka::Parser.new(ArithmeticPrecedenceGrammar, fake_logger)
10
+ eval(parser.compile_to_ruby_source_as(:ArithmeticPrecedenceParser))
11
+
12
+ assert_equal(30, fake_logger.warnings.size)
13
+ assert_equal(0, fake_logger.errors.size)
14
+
15
+ assert_equal(-8, evaluate(parse("5 * -14/(2*7 - 7) + 2")))
16
+ assert_equal(-4, evaluate(parse("-2^2")))
17
+ assert_equal(10, evaluate(parse("2+2^3")))
18
+ assert_equal(64, evaluate(parse("(2+2)^3")))
19
+ assert_equal(128, evaluate(parse("(2+2)^3*2")))
20
+ assert(parse("(2+2)^3^2").has_error?)
21
+ end
22
+
23
+ def parse(input)
24
+ ArithmeticPrecedenceParser.parse(ArithmeticPrecedenceTokenizer.tokenize(input))
25
+ end
26
+
27
+ def evaluate(parse_tree)
28
+ ArithmeticPrecedenceEvaluator.new.evaluate(parse_tree)
29
+ end
30
+ end
31
+
@@ -1,15 +1,13 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'arithmetic_precedence_grammar'
3
-
1
+ require File.dirname(__FILE__) + '/arithmetic_precedence_grammar'
4
2
 
5
3
  class ArithmeticPrecedenceTokenizer < Dhaka::Tokenizer
6
4
 
7
- digits = ('0'..'9').to_a
8
- parenths = ['(', ')']
9
- operators = ['-', '+', '/', '*', '^']
10
- functions = ['h', 'l']
11
- arg_separator = [',']
12
- whitespace = [' ']
5
+ digits = ('0'..'9').to_a
6
+ parenths = %w| ( ) |
7
+ operators = %w| - + / * ^ |
8
+ functions = %w| h l |
9
+ arg_separator = %w| , |
10
+ whitespace = [' ']
13
11
 
14
12
  all_characters = digits + parenths + operators + functions + arg_separator + whitespace
15
13
 
@@ -32,7 +30,7 @@ class ArithmeticPrecedenceTokenizer < Dhaka::Tokenizer
32
30
  switch_to Dhaka::TOKENIZER_IDLE_STATE
33
31
  end
34
32
  for_characters digits do
35
- curr_token.value += curr_char
33
+ curr_token.value << curr_char
36
34
  advance
37
35
  end
38
36
  end
@@ -0,0 +1,23 @@
1
+ class BracketGrammar < Dhaka::Grammar
2
+
3
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
4
+ start %w| Package |
5
+ end
6
+
7
+ for_symbol('Package') do
8
+ soft_wrapped_package %w| ( Contents ) |
9
+ cardboard_package %w| [ Contents ] |
10
+ wooden_package %w| { Contents } |
11
+ end
12
+
13
+ for_symbol('Contents') do
14
+ bracket %w| B |
15
+ set_of_packages %w| SetOfPackages |
16
+ end
17
+
18
+ for_symbol('SetOfPackages') do
19
+ one_package %w| Package |
20
+ multiple_packages %w| SetOfPackages Package |
21
+ end
22
+
23
+ end
@@ -1,10 +1,8 @@
1
- require File.dirname(__FILE__)+'/../lib/dhaka'
2
- require 'bracket_grammar'
3
-
1
+ require File.dirname(__FILE__) + '/bracket_grammar'
4
2
 
5
3
  class BracketTokenizer < Dhaka::Tokenizer
6
4
 
7
- all_characters = ['(', '[', '{', 'B', '}', ']', ')']
5
+ all_characters = %w| ( [ { B } ] ) |
8
6
 
9
7
  for_state Dhaka::TOKENIZER_IDLE_STATE do
10
8
  for_characters(all_characters) do
@@ -1,7 +1,6 @@
1
- require "test/unit"
2
-
3
- require "bracket_grammar"
4
- require 'bracket_tokenizer'
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/bracket_grammar"
3
+ require File.dirname(__FILE__) + '/bracket_tokenizer'
5
4
 
6
5
  class TestBracketGrammar < Test::Unit::TestCase
7
6
  def test_recognizes_faulty_bracket_configuration_correctly
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + "/chittagong_tokenizer"
2
+ require File.dirname(__FILE__) + "/chittagong_evaluator"
3
+
4
+ class ChittagongDriver
5
+
6
+ ERROR_MARKER = ">>>"
7
+
8
+ def parse_error_message unexpected_token, program
9
+ if unexpected_token.symbol_name == Dhaka::END_SYMBOL_NAME
10
+ "Unexpected end of file."
11
+ else
12
+ "Unexpected token #{unexpected_token.symbol_name}:\n#{program.insert(unexpected_token.input_position, ERROR_MARKER)}"
13
+ end
14
+ end
15
+
16
+ def tokenize_error_message unexpected_char_index, program
17
+ "Unexpected character #{program[unexpected_char_index].chr}:\n#{program.insert(unexpected_char_index, ERROR_MARKER)}"
18
+ end
19
+
20
+ def evaluation_error_message evaluation_result, program
21
+ "#{evaluation_result.exception}:\n#{program.insert(evaluation_result.node.tokens[0].input_position, ERROR_MARKER)}"
22
+ end
23
+
24
+ # lipi:run_method
25
+ def run(program)
26
+ tokenize_result = ChittagongTokenizer.tokenize(program)
27
+ if tokenize_result.has_error?
28
+ return tokenize_error_message(tokenize_result.unexpected_char_index, program)
29
+ end
30
+
31
+ parse_result = ChittagongParser.parse(tokenize_result)
32
+ if parse_result.has_error?
33
+ return parse_error_message(parse_result.unexpected_token, program)
34
+ end
35
+
36
+ evaluation_result = ChittagongEvaluator.new([{}], output_stream = []).
37
+ evaluate(parse_result)
38
+ if evaluation_result.exception
39
+ return (output_stream << evaluation_error_message(evaluation_result, program)).
40
+ join("\n")
41
+ end
42
+
43
+ return output_stream.join("\n")
44
+ end
45
+ # lipi:run_method
46
+
47
+ end