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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.simplecov +3 -0
- data/.travis.yml +4 -0
- data/CHANGELOG +4 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +675 -0
- data/README.md +17 -0
- data/Rakefile +4 -0
- data/bin/gobstones +12 -0
- data/gobstones.gemspec +24 -0
- data/lib/gobstones/cli/board_template +39 -0
- data/lib/gobstones/cli/printer.rb +106 -0
- data/lib/gobstones/cli/runner.rb +52 -0
- data/lib/gobstones/extensions/all.rb +2 -0
- data/lib/gobstones/extensions/boolean.rb +17 -0
- data/lib/gobstones/extensions/fixnum.rb +9 -0
- data/lib/gobstones/lang/all.rb +5 -0
- data/lib/gobstones/lang/commands/all.rb +13 -0
- data/lib/gobstones/lang/commands/assignments.rb +29 -0
- data/lib/gobstones/lang/commands/boom_cmd.rb +28 -0
- data/lib/gobstones/lang/commands/command_block.rb +37 -0
- data/lib/gobstones/lang/commands/conditional_cmd.rb +27 -0
- data/lib/gobstones/lang/commands/if_cmd.rb +38 -0
- data/lib/gobstones/lang/commands/ir_al_origen_cmd.rb +19 -0
- data/lib/gobstones/lang/commands/mover_cmd.rb +25 -0
- data/lib/gobstones/lang/commands/poner_cmd.rb +31 -0
- data/lib/gobstones/lang/commands/procedure_call.rb +23 -0
- data/lib/gobstones/lang/commands/repeat_with_cmd.rb +73 -0
- data/lib/gobstones/lang/commands/sacar_cmd.rb +31 -0
- data/lib/gobstones/lang/commands/skip_cmd.rb +19 -0
- data/lib/gobstones/lang/commands/vaciar_tablero_cmd.rb +19 -0
- data/lib/gobstones/lang/commands/while_cmd.rb +25 -0
- data/lib/gobstones/lang/definitions/all.rb +4 -0
- data/lib/gobstones/lang/definitions/definition.rb +32 -0
- data/lib/gobstones/lang/definitions/definition_call.rb +24 -0
- data/lib/gobstones/lang/definitions/function.rb +14 -0
- data/lib/gobstones/lang/definitions/main.rb +26 -0
- data/lib/gobstones/lang/definitions/no_return_statement.rb +15 -0
- data/lib/gobstones/lang/definitions/procedure.rb +44 -0
- data/lib/gobstones/lang/definitions/return_from_function.rb +22 -0
- data/lib/gobstones/lang/definitions/return_from_main.rb +22 -0
- data/lib/gobstones/lang/definitions/var_tuple.rb +26 -0
- data/lib/gobstones/lang/expressions/all.rb +8 -0
- data/lib/gobstones/lang/expressions/arithmetic_expressions.rb +52 -0
- data/lib/gobstones/lang/expressions/boolean_expressions.rb +29 -0
- data/lib/gobstones/lang/expressions/comparison_expressions.rb +45 -0
- data/lib/gobstones/lang/expressions/function_call.rb +15 -0
- data/lib/gobstones/lang/expressions/one_arg_expression.rb +21 -0
- data/lib/gobstones/lang/expressions/parentheses_expression.rb +13 -0
- data/lib/gobstones/lang/expressions/primitive_functions.rb +68 -0
- data/lib/gobstones/lang/expressions/two_arg_expression.rb +34 -0
- data/lib/gobstones/lang/expressions/type_bound_functions.rb +66 -0
- data/lib/gobstones/lang/expressions/var_name.rb +31 -0
- data/lib/gobstones/lang/literals/all.rb +4 -0
- data/lib/gobstones/lang/literals/booleans.rb +109 -0
- data/lib/gobstones/lang/literals/colors.rb +94 -0
- data/lib/gobstones/lang/literals/directions.rb +137 -0
- data/lib/gobstones/lang/literals/literal.rb +63 -0
- data/lib/gobstones/lang/literals/number.rb +49 -0
- data/lib/gobstones/lang/program.rb +32 -0
- data/lib/gobstones/modules/equal_by_class.rb +13 -0
- data/lib/gobstones/parser/ast/ast.rb +210 -0
- data/lib/gobstones/parser/grammar/gobstones.treetop +316 -0
- data/lib/gobstones/parser/parse_error.rb +17 -0
- data/lib/gobstones/parser/treetop_parser.rb +73 -0
- data/lib/gobstones/runner/all.rb +6 -0
- data/lib/gobstones/runner/board.rb +57 -0
- data/lib/gobstones/runner/cell.rb +60 -0
- data/lib/gobstones/runner/errors/all.rb +8 -0
- data/lib/gobstones/runner/errors/boom_error.rb +11 -0
- data/lib/gobstones/runner/errors/definition_not_found_error.rb +19 -0
- data/lib/gobstones/runner/errors/empty_cell_error.rb +11 -0
- data/lib/gobstones/runner/errors/gobstones_runtime_error.rb +11 -0
- data/lib/gobstones/runner/errors/gobstones_type_error.rb +11 -0
- data/lib/gobstones/runner/errors/out_of_board_error.rb +11 -0
- data/lib/gobstones/runner/errors/undefined_variable_error.rb +11 -0
- data/lib/gobstones/runner/errors/wrong_arguments_error.rb +11 -0
- data/lib/gobstones/runner/execution_context.rb +89 -0
- data/lib/gobstones/runner/head.rb +101 -0
- data/lib/gobstones/type_check_result.rb +16 -0
- data/spec/lang/commands/assignments_spec.rb +13 -0
- data/spec/lang/commands/boom_cmd_spec.rb +8 -0
- data/spec/lang/commands/cmd_block_spec.rb +21 -0
- data/spec/lang/commands/if_cmd_spec.rb +49 -0
- data/spec/lang/commands/ir_al_origen_cmd_spec.rb +16 -0
- data/spec/lang/commands/mover_cmd_spec.rb +38 -0
- data/spec/lang/commands/poner_cmd_spec.rb +29 -0
- data/spec/lang/commands/procedure_call_spec.rb +44 -0
- data/spec/lang/commands/procedure_spec.rb +67 -0
- data/spec/lang/commands/repeat_with_cmd_spec.rb +41 -0
- data/spec/lang/commands/sacar_cmd_spec.rb +34 -0
- data/spec/lang/commands/skip_cmd_spec.rb +12 -0
- data/spec/lang/commands/vaciar_tablero_cmd_spec.rb +13 -0
- data/spec/lang/commands/while_cmd_spec.rb +37 -0
- data/spec/lang/expressions/arithmetic_expressions_spec.rb +108 -0
- data/spec/lang/expressions/boolean_expressions_spec.rb +56 -0
- data/spec/lang/expressions/comparison_expressions_spec.rb +285 -0
- data/spec/lang/expressions/primitive_functions_spec.rb +126 -0
- data/spec/lang/expressions/type_bound_functions_spec.rb +39 -0
- data/spec/lang/expressions/var_name_spec.rb +16 -0
- data/spec/lang/literals/booleans_spec.rb +13 -0
- data/spec/lang/literals/colors_spec.rb +13 -0
- data/spec/lang/literals/directions_spec.rb +45 -0
- data/spec/lang/literals/numbers_spec.rb +8 -0
- data/spec/matchers/parse_matcher.rb +84 -0
- data/spec/parser/arithmetic_expressions_spec.rb +129 -0
- data/spec/parser/assignments_spec.rb +39 -0
- data/spec/parser/boolean_expressions_spec.rb +111 -0
- data/spec/parser/command_block_spec.rb +50 -0
- data/spec/parser/data_types_spec.rb +67 -0
- data/spec/parser/function_calls_spec.rb +37 -0
- data/spec/parser/function_definitions_spec.rb +50 -0
- data/spec/parser/gobstones_program_spec.rb +55 -0
- data/spec/parser/if_command_spec.rb +46 -0
- data/spec/parser/main_definition_spec.rb +42 -0
- data/spec/parser/nested_expressions_spec.rb +39 -0
- data/spec/parser/primitive_expressions_spec.rb +105 -0
- data/spec/parser/procedure_calls_spec.rb +36 -0
- data/spec/parser/procedure_definitions_spec.rb +39 -0
- data/spec/parser/repeat_with_command_spec.rb +23 -0
- data/spec/parser/simple_commands_spec.rb +62 -0
- data/spec/parser/treetop_parser_spec.rb +109 -0
- data/spec/parser/var_tuple_spec.rb +30 -0
- data/spec/parser/while_command_spec.rb +30 -0
- data/spec/runner/board_spec.rb +85 -0
- data/spec/runner/cell_spec.rb +72 -0
- data/spec/runner/execution_context_spec.rb +64 -0
- data/spec/runner/head_spec.rb +139 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/type_checker_spec.rb +37 -0
- 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 "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,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
|