gobstones 0.0.1.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 (135) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.simplecov +3 -0
  6. data/.travis.yml +4 -0
  7. data/CHANGELOG +4 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +47 -0
  10. data/LICENSE +675 -0
  11. data/README.md +17 -0
  12. data/Rakefile +4 -0
  13. data/bin/gobstones +12 -0
  14. data/gobstones.gemspec +24 -0
  15. data/lib/gobstones/cli/board_template +39 -0
  16. data/lib/gobstones/cli/printer.rb +106 -0
  17. data/lib/gobstones/cli/runner.rb +52 -0
  18. data/lib/gobstones/extensions/all.rb +2 -0
  19. data/lib/gobstones/extensions/boolean.rb +17 -0
  20. data/lib/gobstones/extensions/fixnum.rb +9 -0
  21. data/lib/gobstones/lang/all.rb +5 -0
  22. data/lib/gobstones/lang/commands/all.rb +13 -0
  23. data/lib/gobstones/lang/commands/assignments.rb +29 -0
  24. data/lib/gobstones/lang/commands/boom_cmd.rb +28 -0
  25. data/lib/gobstones/lang/commands/command_block.rb +37 -0
  26. data/lib/gobstones/lang/commands/conditional_cmd.rb +27 -0
  27. data/lib/gobstones/lang/commands/if_cmd.rb +38 -0
  28. data/lib/gobstones/lang/commands/ir_al_origen_cmd.rb +19 -0
  29. data/lib/gobstones/lang/commands/mover_cmd.rb +25 -0
  30. data/lib/gobstones/lang/commands/poner_cmd.rb +31 -0
  31. data/lib/gobstones/lang/commands/procedure_call.rb +23 -0
  32. data/lib/gobstones/lang/commands/repeat_with_cmd.rb +73 -0
  33. data/lib/gobstones/lang/commands/sacar_cmd.rb +31 -0
  34. data/lib/gobstones/lang/commands/skip_cmd.rb +19 -0
  35. data/lib/gobstones/lang/commands/vaciar_tablero_cmd.rb +19 -0
  36. data/lib/gobstones/lang/commands/while_cmd.rb +25 -0
  37. data/lib/gobstones/lang/definitions/all.rb +4 -0
  38. data/lib/gobstones/lang/definitions/definition.rb +32 -0
  39. data/lib/gobstones/lang/definitions/definition_call.rb +24 -0
  40. data/lib/gobstones/lang/definitions/function.rb +14 -0
  41. data/lib/gobstones/lang/definitions/main.rb +26 -0
  42. data/lib/gobstones/lang/definitions/no_return_statement.rb +15 -0
  43. data/lib/gobstones/lang/definitions/procedure.rb +44 -0
  44. data/lib/gobstones/lang/definitions/return_from_function.rb +22 -0
  45. data/lib/gobstones/lang/definitions/return_from_main.rb +22 -0
  46. data/lib/gobstones/lang/definitions/var_tuple.rb +26 -0
  47. data/lib/gobstones/lang/expressions/all.rb +8 -0
  48. data/lib/gobstones/lang/expressions/arithmetic_expressions.rb +52 -0
  49. data/lib/gobstones/lang/expressions/boolean_expressions.rb +29 -0
  50. data/lib/gobstones/lang/expressions/comparison_expressions.rb +45 -0
  51. data/lib/gobstones/lang/expressions/function_call.rb +15 -0
  52. data/lib/gobstones/lang/expressions/one_arg_expression.rb +21 -0
  53. data/lib/gobstones/lang/expressions/parentheses_expression.rb +13 -0
  54. data/lib/gobstones/lang/expressions/primitive_functions.rb +68 -0
  55. data/lib/gobstones/lang/expressions/two_arg_expression.rb +34 -0
  56. data/lib/gobstones/lang/expressions/type_bound_functions.rb +66 -0
  57. data/lib/gobstones/lang/expressions/var_name.rb +31 -0
  58. data/lib/gobstones/lang/literals/all.rb +4 -0
  59. data/lib/gobstones/lang/literals/booleans.rb +109 -0
  60. data/lib/gobstones/lang/literals/colors.rb +94 -0
  61. data/lib/gobstones/lang/literals/directions.rb +137 -0
  62. data/lib/gobstones/lang/literals/literal.rb +63 -0
  63. data/lib/gobstones/lang/literals/number.rb +49 -0
  64. data/lib/gobstones/lang/program.rb +32 -0
  65. data/lib/gobstones/modules/equal_by_class.rb +13 -0
  66. data/lib/gobstones/parser/ast/ast.rb +210 -0
  67. data/lib/gobstones/parser/grammar/gobstones.treetop +316 -0
  68. data/lib/gobstones/parser/parse_error.rb +17 -0
  69. data/lib/gobstones/parser/treetop_parser.rb +73 -0
  70. data/lib/gobstones/runner/all.rb +6 -0
  71. data/lib/gobstones/runner/board.rb +57 -0
  72. data/lib/gobstones/runner/cell.rb +60 -0
  73. data/lib/gobstones/runner/errors/all.rb +8 -0
  74. data/lib/gobstones/runner/errors/boom_error.rb +11 -0
  75. data/lib/gobstones/runner/errors/definition_not_found_error.rb +19 -0
  76. data/lib/gobstones/runner/errors/empty_cell_error.rb +11 -0
  77. data/lib/gobstones/runner/errors/gobstones_runtime_error.rb +11 -0
  78. data/lib/gobstones/runner/errors/gobstones_type_error.rb +11 -0
  79. data/lib/gobstones/runner/errors/out_of_board_error.rb +11 -0
  80. data/lib/gobstones/runner/errors/undefined_variable_error.rb +11 -0
  81. data/lib/gobstones/runner/errors/wrong_arguments_error.rb +11 -0
  82. data/lib/gobstones/runner/execution_context.rb +89 -0
  83. data/lib/gobstones/runner/head.rb +101 -0
  84. data/lib/gobstones/type_check_result.rb +16 -0
  85. data/spec/lang/commands/assignments_spec.rb +13 -0
  86. data/spec/lang/commands/boom_cmd_spec.rb +8 -0
  87. data/spec/lang/commands/cmd_block_spec.rb +21 -0
  88. data/spec/lang/commands/if_cmd_spec.rb +49 -0
  89. data/spec/lang/commands/ir_al_origen_cmd_spec.rb +16 -0
  90. data/spec/lang/commands/mover_cmd_spec.rb +38 -0
  91. data/spec/lang/commands/poner_cmd_spec.rb +29 -0
  92. data/spec/lang/commands/procedure_call_spec.rb +44 -0
  93. data/spec/lang/commands/procedure_spec.rb +67 -0
  94. data/spec/lang/commands/repeat_with_cmd_spec.rb +41 -0
  95. data/spec/lang/commands/sacar_cmd_spec.rb +34 -0
  96. data/spec/lang/commands/skip_cmd_spec.rb +12 -0
  97. data/spec/lang/commands/vaciar_tablero_cmd_spec.rb +13 -0
  98. data/spec/lang/commands/while_cmd_spec.rb +37 -0
  99. data/spec/lang/expressions/arithmetic_expressions_spec.rb +108 -0
  100. data/spec/lang/expressions/boolean_expressions_spec.rb +56 -0
  101. data/spec/lang/expressions/comparison_expressions_spec.rb +285 -0
  102. data/spec/lang/expressions/primitive_functions_spec.rb +126 -0
  103. data/spec/lang/expressions/type_bound_functions_spec.rb +39 -0
  104. data/spec/lang/expressions/var_name_spec.rb +16 -0
  105. data/spec/lang/literals/booleans_spec.rb +13 -0
  106. data/spec/lang/literals/colors_spec.rb +13 -0
  107. data/spec/lang/literals/directions_spec.rb +45 -0
  108. data/spec/lang/literals/numbers_spec.rb +8 -0
  109. data/spec/matchers/parse_matcher.rb +84 -0
  110. data/spec/parser/arithmetic_expressions_spec.rb +129 -0
  111. data/spec/parser/assignments_spec.rb +39 -0
  112. data/spec/parser/boolean_expressions_spec.rb +111 -0
  113. data/spec/parser/command_block_spec.rb +50 -0
  114. data/spec/parser/data_types_spec.rb +67 -0
  115. data/spec/parser/function_calls_spec.rb +37 -0
  116. data/spec/parser/function_definitions_spec.rb +50 -0
  117. data/spec/parser/gobstones_program_spec.rb +55 -0
  118. data/spec/parser/if_command_spec.rb +46 -0
  119. data/spec/parser/main_definition_spec.rb +42 -0
  120. data/spec/parser/nested_expressions_spec.rb +39 -0
  121. data/spec/parser/primitive_expressions_spec.rb +105 -0
  122. data/spec/parser/procedure_calls_spec.rb +36 -0
  123. data/spec/parser/procedure_definitions_spec.rb +39 -0
  124. data/spec/parser/repeat_with_command_spec.rb +23 -0
  125. data/spec/parser/simple_commands_spec.rb +62 -0
  126. data/spec/parser/treetop_parser_spec.rb +109 -0
  127. data/spec/parser/var_tuple_spec.rb +30 -0
  128. data/spec/parser/while_command_spec.rb +30 -0
  129. data/spec/runner/board_spec.rb +85 -0
  130. data/spec/runner/cell_spec.rb +72 -0
  131. data/spec/runner/execution_context_spec.rb +64 -0
  132. data/spec/runner/head_spec.rb +139 -0
  133. data/spec/spec_helper.rb +15 -0
  134. data/spec/type_checker_spec.rb +37 -0
  135. metadata +242 -0
@@ -0,0 +1,126 @@
1
+ describe "primitive functions" do
2
+
3
+ let(:context) { ProgramExecutionContext.for double('GobstonesProgram') }
4
+ let(:black) { Negro.new }
5
+ let(:west) { Oeste.new }
6
+
7
+ describe "nroBolitas() function" do
8
+
9
+ it "should evaluates correctly in a clean context" do
10
+ expect(NroBolitas.new(black).evaluate(context)).to eq(0.to_gbs_num)
11
+ end
12
+
13
+ it "should evaluate correctly in a context with some data" do
14
+ 5.times { context.head.put black }
15
+ expect(NroBolitas.new(black).evaluate(context)).to eq(5.to_gbs_num)
16
+ end
17
+
18
+ end
19
+
20
+ describe "hayBolitas() function" do
21
+
22
+ it "should evaluate correctly in a clean context" do
23
+ expect(HayBolitas.new(black).evaluate(context)).to eq(false.to_gbs_bool)
24
+ end
25
+
26
+ it "should evaluate correctly in a context with some data" do
27
+ context.head.put black
28
+ expect(HayBolitas.new(black).evaluate(context)).to eq(true.to_gbs_bool)
29
+ end
30
+
31
+ end
32
+
33
+ describe "puedeMover() function" do
34
+
35
+ it "should evaluate correctly in a clean context" do
36
+ expect(PuedeMover.new(west).evaluate(context)).to eq(false.to_gbs_bool)
37
+ end
38
+
39
+ it "should evaluate correctly in a modified context" do
40
+ context.head.move(Este.new)
41
+ expect(PuedeMover.new(west).evaluate(context)).to eq(true.to_gbs_bool)
42
+ end
43
+
44
+ end
45
+
46
+ describe "siguiente() function" do
47
+
48
+ it "should evaluate correctly for numbers" do
49
+ expect(Siguiente.new(15.to_gbs_num).evaluate).to eq(16.to_gbs_num)
50
+ end
51
+
52
+ it "should evaluate correctly for colors" do
53
+ expect(Siguiente.new(Azul.new).evaluate).to eq(Negro.new)
54
+ expect(Siguiente.new(Negro.new).evaluate).to eq(Rojo.new)
55
+ expect(Siguiente.new(Rojo.new).evaluate).to eq(Verde.new)
56
+ expect(Siguiente.new(Verde.new).evaluate).to eq(Azul.new)
57
+ end
58
+
59
+ it "should evaluate correctly for directions" do
60
+ expect(Siguiente.new(Norte.new).evaluate).to eq(Este.new)
61
+ expect(Siguiente.new(Este.new).evaluate).to eq(Sur.new)
62
+ expect(Siguiente.new(Sur.new).evaluate).to eq(Oeste.new)
63
+ expect(Siguiente.new(Oeste.new).evaluate).to eq(Norte.new)
64
+ end
65
+
66
+ it "should evaluate correctly for booleans" do
67
+ expect(Siguiente.new(True.new).evaluate).to eq(False.new)
68
+ expect(Siguiente.new(False.new).evaluate).to eq(True.new)
69
+ end
70
+
71
+ end
72
+
73
+ describe "previo() function" do
74
+
75
+ it "should evaluate correctly for numbers" do
76
+ expect(Previo.new(43.to_gbs_num).evaluate).to eq(42.to_gbs_num)
77
+ end
78
+
79
+ it "should evaluate correctly for colors" do
80
+ expect(Previo.new(Azul.new).evaluate).to eq(Verde.new)
81
+ expect(Previo.new(Negro.new).evaluate).to eq(Azul.new)
82
+ expect(Previo.new(Rojo.new).evaluate).to eq(Negro.new)
83
+ expect(Previo.new(Verde.new).evaluate).to eq(Rojo.new)
84
+ end
85
+
86
+ it "should evaluate correctly for directions" do
87
+ expect(Previo.new(Norte.new).evaluate).to eq(Oeste.new)
88
+ expect(Previo.new(Este.new).evaluate).to eq(Norte.new)
89
+ expect(Previo.new(Sur.new).evaluate).to eq(Este.new)
90
+ expect(Previo.new(Oeste.new).evaluate).to eq(Sur.new)
91
+ end
92
+
93
+ it "should evaluate correctly for booleans" do
94
+ expect(Previo.new(True.new).evaluate).to eq(False.new)
95
+ expect(Previo.new(False.new).evaluate).to eq(True.new)
96
+ end
97
+
98
+ end
99
+
100
+ describe "opuesto() function" do
101
+
102
+ it "should evaluate correctly for numbers" do
103
+ expect(Opuesto.new(23.to_gbs_num).evaluate).to eq(-23.to_gbs_num)
104
+ expect(Opuesto.new(-42.to_gbs_num).evaluate).to eq(42.to_gbs_num)
105
+ end
106
+
107
+ it "should evaluate correctly for directions" do
108
+ expect(Opuesto.new(Norte.new).evaluate).to eq(Sur.new)
109
+ expect(Opuesto.new(Este.new).evaluate).to eq(Oeste.new)
110
+ expect(Opuesto.new(Sur.new).evaluate).to eq(Norte.new)
111
+ expect(Opuesto.new(Oeste.new).evaluate).to eq(Este.new)
112
+ end
113
+
114
+ it "should evaluate correctly for booleans" do
115
+ expect(Opuesto.new(True.new).evaluate).to eq(False.new)
116
+ expect(Opuesto.new(False.new).evaluate).to eq(True.new)
117
+ end
118
+
119
+ it "should fail when evaluating for colors" do
120
+ expect { Opuesto.new(Verde.new).evaluate }.
121
+ to raise_error(GobstonesTypeError, "colors don't have opposite")
122
+ end
123
+
124
+ end
125
+
126
+ end
@@ -0,0 +1,39 @@
1
+ describe "type bound functions" do
2
+
3
+ describe "boolean" do
4
+
5
+ it "should evaluate minBool() to False" do
6
+ expect(MinBool.new.evaluate).to eq(False.new)
7
+ end
8
+
9
+ it "should evaluate maxBool() to True" do
10
+ expect(MaxBool.new.evaluate).to eq(True.new)
11
+ end
12
+
13
+ end
14
+
15
+ describe "colors" do
16
+
17
+ it "should evaluate minColor() to Azul" do
18
+ expect(MinColor.new.evaluate).to eq(Azul.new)
19
+ end
20
+
21
+ it "should evaluate maxColor() to Verde" do
22
+ expect(MaxColor.new.evaluate).to eq(Verde.new)
23
+ end
24
+
25
+ end
26
+
27
+ describe "directions" do
28
+
29
+ it "should evaluate minDir() to Norte" do
30
+ expect(MinDir.new.evaluate).to eq(Norte.new)
31
+ end
32
+
33
+ it "should evaluate maxDir() to Oeste" do
34
+ expect(MaxDir.new.evaluate).to eq(Oeste.new)
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,16 @@
1
+ describe VarName do
2
+
3
+ let(:context) { ExecutionContext.new }
4
+ let(:var_name) { VarName.new 'var' }
5
+
6
+ it "should return the associated value if it was defined in the context" do
7
+ context.set var_name, 42.to_gbs_num
8
+ expect(var_name.evaluate(context)).to eq(42.to_gbs_num)
9
+ end
10
+
11
+ it "should raise an error if there is no definition in context" do
12
+ expect { var_name.evaluate context }
13
+ .to raise_error(UndefinedVariableError)
14
+ end
15
+
16
+ end
@@ -0,0 +1,13 @@
1
+ describe Boolean do
2
+
3
+ it "should evaluate true to self" do
4
+ bool = True.new
5
+ expect(bool.evaluate).to eq(bool)
6
+ end
7
+
8
+ it "should evaluate false to self" do
9
+ bool = False.new
10
+ expect(bool.evaluate).to eq(bool)
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ describe "colors" do
2
+
3
+ let(:all) { [Azul.new, Negro.new, Rojo.new, Verde.new] }
4
+
5
+ it "should evaluate any color to self" do
6
+ all.each { |color| expect(color.evaluate).to eq(color) }
7
+ end
8
+
9
+ it "should give the string representation" do
10
+ expect(all.map(&:to_s)).to eq(['Azul', 'Negro', 'Rojo', 'Verde'])
11
+ end
12
+
13
+ end
@@ -0,0 +1,45 @@
1
+ describe "directions" do
2
+
3
+ let(:all) { [Norte.new, Sur.new, Este.new, Oeste.new] }
4
+
5
+ it "should evaluate any direction to self" do
6
+ all.each { |dir| expect(dir.evaluate).to eq(dir) }
7
+ end
8
+
9
+ it "should return the string representation" do
10
+ expect(all.map(&:to_s)).to eq(['Norte', 'Sur', 'Este', 'Oeste'])
11
+ end
12
+
13
+ describe Norte do
14
+
15
+ it "should return Sur as opposite direction" do
16
+ expect(Norte.new.opposite).to eq(Sur.new)
17
+ end
18
+
19
+ end
20
+
21
+ describe Este do
22
+
23
+ it "should return Oeste as opposite direction" do
24
+ expect(Este.new.opposite).to eq(Oeste.new)
25
+ end
26
+
27
+ end
28
+
29
+ describe Sur do
30
+
31
+ it "should return Norte as opposite direction" do
32
+ expect(Sur.new.opposite).to eq(Norte.new)
33
+ end
34
+
35
+ end
36
+
37
+ describe Oeste do
38
+
39
+ it "should return Este as opposite direction" do
40
+ expect(Oeste.new.opposite).to eq(Este.new)
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,8 @@
1
+ describe Number do
2
+
3
+ it "should evaluate to self" do
4
+ num = 42.to_gbs_num
5
+ expect(num.evaluate).to eq(num)
6
+ end
7
+
8
+ end
@@ -0,0 +1,84 @@
1
+ require 'gobstones/parser/treetop_parser'
2
+ require 'gobstones/lang/program'
3
+
4
+ PARSER = Gobstones::Parser::TreetopParser.new
5
+
6
+ RSpec::Matchers.define :be_parsed_as do |grammar_elem|
7
+
8
+ @valid_nodes = [:program, :definition, :main, :expression, :command, :var_tuple ]
9
+
10
+ chain :and_fail do
11
+ @expect_parser_results = false
12
+ end
13
+
14
+ chain :and_return do |expected|
15
+ @expect_parser_results = true
16
+ @expected = expected
17
+ end
18
+
19
+ match do |actual|
20
+ fail 'wrong expectation' if @expect_parser_results.nil?
21
+ fail 'grammar elem not supported' if !@valid_nodes.include?(grammar_elem)
22
+
23
+ begin
24
+ parse send("#{grammar_elem}_code_to_program", actual)
25
+ @value == send("#{grammar_elem}_node_to_program", @expected)
26
+ rescue Gobstones::Parser::ParseError => e
27
+ !@expect_parser_results
28
+ end
29
+ end
30
+
31
+ def program_code_to_program(code)
32
+ code
33
+ end
34
+
35
+ def program_node_to_program(node)
36
+ node
37
+ end
38
+
39
+ def main_code_to_program(code)
40
+ code
41
+ end
42
+
43
+ def main_node_to_program(node)
44
+ Program.new [], node
45
+ end
46
+
47
+ def definition_code_to_program(code)
48
+ "#{code}\nprocedure Main() {}"
49
+ end
50
+
51
+ def definition_node_to_program(node)
52
+ Program.new [node], Main.new(CmdBlock.new([]), NoReturnStatement.new)
53
+ end
54
+
55
+ def expression_code_to_program(code)
56
+ "procedure Main() { x := #{code} }"
57
+ end
58
+
59
+ def expression_node_to_program(node)
60
+ assign = SingleAssignment.new VarName.new('x'), node
61
+ main_node_to_program Main.new(CmdBlock.new([assign]), NoReturnStatement.new)
62
+ end
63
+
64
+ def command_code_to_program(code)
65
+ "procedure Main() { #{code} }"
66
+ end
67
+
68
+ def command_node_to_program(node)
69
+ main_node_to_program Main.new(CmdBlock.new([node]), NoReturnStatement.new)
70
+ end
71
+
72
+ def var_tuple_code_to_program(code)
73
+ "procedure Main() { return #{code} }"
74
+ end
75
+
76
+ def var_tuple_node_to_program(node)
77
+ Program.new [], Main.new(CmdBlock.new([]), ReturnFromMain.new(node))
78
+ end
79
+
80
+ def parse(code)
81
+ @value = PARSER.parse code
82
+ end
83
+
84
+ end
@@ -0,0 +1,129 @@
1
+ describe Gobstones::Parser, "arithmetic expressions" do
2
+
3
+ let(:a) { VarName.new 'a' }
4
+ let(:b) { VarName.new 'b' }
5
+ let(:c) { VarName.new 'c' }
6
+ let(:d) { VarName.new 'd' }
7
+
8
+ describe "addition and subtraction" do
9
+
10
+ it "should parse a + expression" do
11
+ sum = Add.new a, b
12
+
13
+ expect('a+b').to be_parsed_as(:expression).and_return(sum)
14
+ expect('a + b').to be_parsed_as(:expression).and_return(sum)
15
+ end
16
+
17
+ it "should parse a nested + expression, associating to left" do
18
+ sum_ab = Add.new a, b
19
+ total = Add.new sum_ab, c
20
+
21
+ expect('a + b + c').to be_parsed_as(:expression).and_return(total)
22
+ end
23
+
24
+ it "should parse a - expression" do
25
+ sub = Sub.new a, b
26
+
27
+ expect('a-b').to be_parsed_as(:expression).and_return(sub)
28
+ expect('a - b').to be_parsed_as(:expression).and_return(sub)
29
+ end
30
+
31
+ it "should parse a nested expression with + and -, associating to left" do
32
+ sum_ab = Add.new a, b
33
+ total = Sub.new sum_ab, c
34
+
35
+ expect('a + b - c').to be_parsed_as(:expression).and_return(total)
36
+ end
37
+
38
+ end
39
+
40
+ describe "multiplication, division, modulus and power" do
41
+
42
+ it "should parse a * expression" do
43
+ mul = Mul.new a, b
44
+
45
+ expect('a*b').to be_parsed_as(:expression).and_return(mul)
46
+ expect('a * b').to be_parsed_as(:expression).and_return(mul)
47
+ end
48
+
49
+ it "should parse a nested * expression" do
50
+ mul_ab = Mul.new a, b
51
+ total = Mul.new mul_ab, c
52
+
53
+ expect('a * b * c').to be_parsed_as(:expression).and_return(total)
54
+ end
55
+
56
+ it "should parse a div expression" do
57
+ div = Div.new a, b
58
+
59
+ expect('a div b').to be_parsed_as(:expression).and_return(div)
60
+ expect('a div b').to be_parsed_as(:expression).and_return(div)
61
+ end
62
+
63
+ it "should parse a mod expression" do
64
+ mod = Mod.new a, b
65
+
66
+ expect('a mod b').to be_parsed_as(:expression).and_return(mod)
67
+ expect('a mod b').to be_parsed_as(:expression).and_return(mod)
68
+ end
69
+
70
+ it "should parse a power expression" do
71
+ pow = Pow.new a, b
72
+
73
+ expect('a^b').to be_parsed_as(:expression).and_return(pow)
74
+ expect('a ^ b').to be_parsed_as(:expression).and_return(pow)
75
+ end
76
+
77
+ it "should parse a nested power expression, associating left" do
78
+ pow_ab = Pow.new a, b
79
+ pow_abc = Pow.new pow_ab, c
80
+ pow_abcd = Pow.new pow_abc, d
81
+
82
+ expect('a ^ b ^ c ^ d').to be_parsed_as(:expression).and_return(pow_abcd)
83
+ end
84
+
85
+ end
86
+
87
+ describe "complex arithmetic expressions (without parentheses)" do
88
+
89
+ it "should parse using precedence of + and - over *" do
90
+ mul = Mul.new b, c
91
+ sub = Sub.new a, mul
92
+ add = Add.new sub, d
93
+
94
+ expect('a - b * c + d').to be_parsed_as(:expression).and_return(add)
95
+ end
96
+
97
+ it "should parse using precedence of * over div and mod" do
98
+ div = Div.new a, b
99
+ mod = Mod.new a, c
100
+ inner_mul = Mul.new div, mod
101
+ outer_mul = Mul.new inner_mul, d
102
+
103
+ expect('a div b * a mod c * d').
104
+ to be_parsed_as(:expression).and_return(outer_mul)
105
+ end
106
+
107
+ it "should parse using precedence of div and mod over ^" do
108
+ pow_ab = Pow.new a, b
109
+ pow_cd = Pow.new c, d
110
+ div = Div.new pow_ab, pow_cd
111
+
112
+ expect('a^b div c^d').to be_parsed_as(:expression).and_return(div)
113
+ end
114
+
115
+ it "should parse an expression with all kind of operators" do
116
+ pow = Pow.new b, c
117
+ mod = Mod.new a, pow
118
+ div = Div.new d, b
119
+ mul = Mul.new a, div
120
+ add = Add.new mod, mul
121
+ sub = Sub.new add, c
122
+
123
+ expect('a mod b ^ c + a * d div b - c').
124
+ to be_parsed_as(:expression).and_return(sub)
125
+ end
126
+
127
+ end
128
+
129
+ end