gobstones 0.0.2 → 0.0.3
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 +5 -5
- data/.rubocop.yml +133 -0
- data/.rubocop_todo.yml +75 -0
- data/.simplecov +1 -3
- data/.tool-versions +1 -0
- data/.travis.yml +9 -2
- data/Gemfile +11 -5
- data/Gemfile.lock +65 -39
- data/README.md +8 -1
- data/Rakefile +1 -1
- data/bin/gobstones +1 -1
- data/gobstones.gemspec +12 -11
- data/lib/gobstones/cli/printer.rb +41 -28
- data/lib/gobstones/cli/runner.rb +50 -15
- data/lib/gobstones/extensions/all.rb +1 -1
- data/lib/gobstones/extensions/boolean.rb +1 -5
- data/lib/gobstones/extensions/{fixnum.rb → integer.rb} +2 -4
- data/lib/gobstones/extensions/string.rb +1 -3
- data/lib/gobstones/lang/all.rb +3 -3
- data/lib/gobstones/lang/commands/all.rb +11 -10
- data/lib/gobstones/lang/commands/boom.rb +26 -0
- data/lib/gobstones/lang/commands/command_block.rb +23 -23
- data/lib/gobstones/lang/commands/conditional.rb +26 -0
- data/lib/gobstones/lang/commands/if.rb +13 -0
- data/lib/gobstones/lang/commands/if_then_else.rb +26 -0
- data/lib/gobstones/lang/commands/ir_al_origen.rb +15 -0
- data/lib/gobstones/lang/commands/mover.rb +23 -0
- data/lib/gobstones/lang/commands/multiple_assignment.rb +34 -21
- data/lib/gobstones/lang/commands/poner.rb +31 -0
- data/lib/gobstones/lang/commands/procedure_call.rb +8 -8
- data/lib/gobstones/lang/commands/repeat_with.rb +69 -0
- data/lib/gobstones/lang/commands/sacar.rb +29 -0
- data/lib/gobstones/lang/commands/single_assignment.rb +15 -20
- data/lib/gobstones/lang/commands/skip.rb +15 -0
- data/lib/gobstones/lang/commands/vaciar_tablero.rb +15 -0
- data/lib/gobstones/lang/commands/while.rb +20 -0
- data/lib/gobstones/lang/definitions/definition.rb +16 -23
- data/lib/gobstones/lang/definitions/definition_call.rb +7 -15
- data/lib/gobstones/lang/definitions/function.rb +1 -7
- data/lib/gobstones/lang/definitions/main.rb +1 -8
- data/lib/gobstones/lang/definitions/no_return_statement.rb +2 -8
- data/lib/gobstones/lang/definitions/procedure.rb +1 -7
- data/lib/gobstones/lang/definitions/return_from_function.rb +6 -13
- data/lib/gobstones/lang/definitions/return_from_main.rb +15 -10
- data/lib/gobstones/lang/definitions/var_tuple.rb +10 -12
- data/lib/gobstones/lang/expressions/arithmetic_expressions.rb +17 -27
- data/lib/gobstones/lang/expressions/boolean_expressions.rb +4 -10
- data/lib/gobstones/lang/expressions/comparison_expressions.rb +0 -16
- data/lib/gobstones/lang/expressions/enclosed_by_parens_expression.rb +3 -5
- data/lib/gobstones/lang/expressions/expression.rb +18 -0
- data/lib/gobstones/lang/expressions/function_call.rb +9 -6
- data/lib/gobstones/lang/expressions/one_arg_expression.rb +8 -16
- data/lib/gobstones/lang/expressions/primitive_functions.rb +24 -16
- data/lib/gobstones/lang/expressions/two_arg_expression.rb +9 -16
- data/lib/gobstones/lang/expressions/type_bound_functions.rb +30 -25
- data/lib/gobstones/lang/expressions/var_name.rb +9 -13
- data/lib/gobstones/lang/literals/all.rb +3 -3
- data/lib/gobstones/lang/literals/{booleans.rb → boolean.rb} +24 -22
- data/lib/gobstones/lang/literals/{colors.rb → color.rb} +4 -14
- data/lib/gobstones/lang/literals/{directions.rb → direction.rb} +3 -13
- data/lib/gobstones/lang/literals/literal.rb +35 -27
- data/lib/gobstones/lang/literals/number.rb +6 -8
- data/lib/gobstones/lang/program.rb +9 -16
- data/lib/gobstones/modules/equality_definition.rb +23 -0
- data/lib/gobstones/parser/ast/ast.rb +48 -70
- data/lib/gobstones/parser/parse_error.rb +2 -7
- data/lib/gobstones/parser/treetop_parser.rb +9 -14
- data/lib/gobstones/runner/board.rb +12 -15
- data/lib/gobstones/runner/cell.rb +14 -20
- data/lib/gobstones/runner/errors/all.rb +1 -1
- data/lib/gobstones/runner/errors/boom_error.rb +0 -5
- data/lib/gobstones/runner/errors/definition_not_found_error.rb +7 -7
- data/lib/gobstones/runner/errors/empty_cell_error.rb +0 -5
- data/lib/gobstones/runner/errors/gobstones_runtime_error.rb +0 -5
- data/lib/gobstones/runner/errors/gobstones_type_error.rb +2 -7
- data/lib/gobstones/runner/errors/out_of_board_error.rb +0 -5
- data/lib/gobstones/runner/errors/undefined_variable_error.rb +6 -4
- data/lib/gobstones/runner/errors/wrong_arguments_error.rb +0 -5
- data/lib/gobstones/runner/execution_context.rb +16 -33
- data/lib/gobstones/runner/head.rb +17 -20
- data/lib/gobstones/runner/program_result.rb +12 -0
- data/lib/gobstones/type_check_result.rb +0 -4
- data/spec/lang/commands/boom_spec.rb +7 -0
- data/spec/lang/commands/command_block_spec.rb +15 -0
- data/spec/lang/commands/if_spec.rb +32 -0
- data/spec/lang/commands/if_then_else_spec.rb +19 -0
- data/spec/lang/commands/ir_al_origen_spec.rb +11 -0
- data/spec/lang/commands/mover_spec.rb +30 -0
- data/spec/lang/commands/multiple_assignment_spec.rb +39 -22
- data/spec/lang/commands/poner_spec.rb +27 -0
- data/spec/lang/commands/procedure_call_spec.rb +26 -28
- data/spec/lang/commands/procedure_spec.rb +32 -32
- data/spec/lang/commands/repeat_with_spec.rb +64 -0
- data/spec/lang/commands/sacar_spec.rb +32 -0
- data/spec/lang/commands/single_assignment_spec.rb +5 -6
- data/spec/lang/commands/skip_spec.rb +10 -0
- data/spec/lang/commands/vaciar_tablero_spec.rb +10 -0
- data/spec/lang/commands/while_spec.rb +39 -0
- data/spec/lang/definitions/main_spec.rb +34 -0
- data/spec/lang/definitions/no_return_statement_spec.rb +4 -5
- data/spec/lang/definitions/var_tuple_spec.rb +4 -7
- data/spec/lang/expressions/arithmetic_expressions_spec.rb +37 -64
- data/spec/lang/expressions/boolean_expressions_spec.rb +25 -34
- data/spec/lang/expressions/comparison_expressions_spec.rb +109 -155
- data/spec/lang/expressions/enclosed_by_parens_expression_spec.rb +3 -7
- data/spec/lang/expressions/function_call_spec.rb +24 -20
- data/spec/lang/expressions/primitive_functions_spec.rb +28 -39
- data/spec/lang/expressions/type_bound_functions_spec.rb +10 -18
- data/spec/lang/expressions/var_name_spec.rb +8 -12
- data/spec/lang/literals/{booleans_spec.rb → boolean_spec.rb} +3 -5
- data/spec/lang/literals/color_spec.rb +19 -0
- data/spec/lang/literals/direction_spec.rb +46 -0
- data/spec/lang/literals/{numbers_spec.rb → number_spec.rb} +3 -4
- data/spec/matchers/parse_matcher.rb +9 -11
- data/spec/parser/arithmetic_expressions_spec.rb +51 -61
- data/spec/parser/assignments_spec.rb +21 -31
- data/spec/parser/boolean_expressions_spec.rb +35 -43
- data/spec/parser/command_block_spec.rb +18 -20
- data/spec/parser/data_types_spec.rb +9 -19
- data/spec/parser/function_calls_spec.rb +19 -19
- data/spec/parser/function_definitions_spec.rb +17 -22
- data/spec/parser/gobstones_program_spec.rb +30 -30
- data/spec/parser/if_command_spec.rb +19 -28
- data/spec/parser/main_definition_spec.rb +13 -16
- data/spec/parser/nested_expressions_spec.rb +20 -24
- data/spec/parser/primitive_expressions_spec.rb +33 -38
- data/spec/parser/procedure_calls_spec.rb +17 -18
- data/spec/parser/procedure_definitions_spec.rb +12 -15
- data/spec/parser/repeat_with_command_spec.rb +10 -10
- data/spec/parser/simple_commands_spec.rb +23 -37
- data/spec/parser/treetop_parser_spec.rb +87 -83
- data/spec/parser/var_tuple_spec.rb +8 -12
- data/spec/parser/while_command_spec.rb +11 -14
- data/spec/runner/board_spec.rb +28 -33
- data/spec/runner/cell_spec.rb +21 -28
- data/spec/runner/execution_context_spec.rb +18 -35
- data/spec/runner/head_spec.rb +54 -60
- data/spec/spec_helper.rb +10 -1
- data/spec/support/board_assertions.rb +18 -0
- data/spec/{gobstones_lang_test_objects.rb → support/gobstones_lang_test_objects.rb} +6 -4
- data/spec/type_checker_spec.rb +19 -25
- metadata +80 -56
- data/.ruby-version +0 -1
- data/lib/gobstones/lang/commands/boom_cmd.rb +0 -31
- data/lib/gobstones/lang/commands/conditional_cmd.rb +0 -31
- data/lib/gobstones/lang/commands/if_cmd.rb +0 -38
- data/lib/gobstones/lang/commands/ir_al_origen_cmd.rb +0 -19
- data/lib/gobstones/lang/commands/mover_cmd.rb +0 -27
- data/lib/gobstones/lang/commands/poner_cmd.rb +0 -35
- data/lib/gobstones/lang/commands/repeat_with_cmd.rb +0 -77
- data/lib/gobstones/lang/commands/sacar_cmd.rb +0 -33
- data/lib/gobstones/lang/commands/skip_cmd.rb +0 -19
- data/lib/gobstones/lang/commands/vaciar_tablero_cmd.rb +0 -19
- data/lib/gobstones/lang/commands/while_cmd.rb +0 -25
- data/lib/gobstones/modules/equal_by_class.rb +0 -13
- data/spec/lang/commands/boom_cmd_spec.rb +0 -8
- data/spec/lang/commands/cmd_block_spec.rb +0 -21
- data/spec/lang/commands/if_cmd_spec.rb +0 -50
- data/spec/lang/commands/ir_al_origen_cmd_spec.rb +0 -16
- data/spec/lang/commands/mover_cmd_spec.rb +0 -36
- data/spec/lang/commands/poner_cmd_spec.rb +0 -28
- data/spec/lang/commands/repeat_with_cmd_spec.rb +0 -60
- data/spec/lang/commands/sacar_cmd_spec.rb +0 -35
- data/spec/lang/commands/skip_cmd_spec.rb +0 -12
- data/spec/lang/commands/vaciar_tablero_cmd_spec.rb +0 -14
- data/spec/lang/commands/while_cmd_spec.rb +0 -43
- data/spec/lang/literals/colors_spec.rb +0 -13
- data/spec/lang/literals/directions_spec.rb +0 -45
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'gobstones/runner/board'
|
2
|
+
require 'gobstones/runner/errors/out_of_board_error'
|
2
3
|
|
3
4
|
module Gobstones
|
4
|
-
|
5
5
|
module Runner
|
6
|
-
|
7
6
|
class Head
|
8
|
-
|
9
7
|
MAX_ROWS = 9
|
10
8
|
MAX_COLS = 9
|
11
9
|
|
@@ -16,15 +14,16 @@ module Gobstones
|
|
16
14
|
end
|
17
15
|
|
18
16
|
def self.with_position_and_board(x_pos, y_pos, board)
|
19
|
-
new.with_position_and_board
|
17
|
+
new.with_position_and_board(x_pos, y_pos, board)
|
20
18
|
end
|
21
19
|
|
22
20
|
def initialize
|
23
|
-
with_position_and_board
|
21
|
+
with_position_and_board(0, 0, Board.new(MAX_ROWS, MAX_COLS))
|
24
22
|
end
|
25
23
|
|
26
24
|
def at_random
|
27
|
-
@x_pos
|
25
|
+
@x_pos = rand(MAX_ROWS)
|
26
|
+
@y_pos = rand(MAX_COLS)
|
28
27
|
self
|
29
28
|
end
|
30
29
|
|
@@ -37,27 +36,28 @@ module Gobstones
|
|
37
36
|
|
38
37
|
def can_move?(dir)
|
39
38
|
check dir
|
40
|
-
dir.can_move?
|
39
|
+
dir.can_move?(self)
|
41
40
|
end
|
42
41
|
|
43
42
|
def can_move_north?
|
44
|
-
@y_pos < MAX_COLS-1
|
43
|
+
@y_pos < MAX_COLS - 1
|
45
44
|
end
|
46
45
|
|
47
46
|
def can_move_south?
|
48
|
-
@y_pos
|
47
|
+
@y_pos.positive?
|
49
48
|
end
|
50
49
|
|
51
50
|
def can_move_east?
|
52
|
-
@x_pos < MAX_ROWS-1
|
51
|
+
@x_pos < MAX_ROWS - 1
|
53
52
|
end
|
54
53
|
|
55
54
|
def can_move_west?
|
56
|
-
@x_pos
|
55
|
+
@x_pos.positive?
|
57
56
|
end
|
58
57
|
|
59
58
|
def move(dir)
|
60
59
|
raise OutOfBoardError unless can_move?(dir)
|
60
|
+
|
61
61
|
dir.move self
|
62
62
|
end
|
63
63
|
|
@@ -78,7 +78,8 @@ module Gobstones
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def go_to_origin
|
81
|
-
@x_pos
|
81
|
+
@x_pos = 0
|
82
|
+
@y_pos = 0
|
82
83
|
end
|
83
84
|
|
84
85
|
def put(color)
|
@@ -90,26 +91,22 @@ module Gobstones
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def number_of_balls(color)
|
93
|
-
@board.number_of_balls
|
94
|
+
@board.number_of_balls(x_pos, y_pos, color)
|
94
95
|
end
|
95
96
|
|
96
97
|
def are_there_balls?(color)
|
97
|
-
@board.are_there_balls?
|
98
|
+
@board.are_there_balls?(x_pos, y_pos, color)
|
98
99
|
end
|
99
100
|
|
100
101
|
def clone
|
101
|
-
self.class.with_position_and_board
|
102
|
+
self.class.with_position_and_board(x_pos, y_pos, board.clone)
|
102
103
|
end
|
103
104
|
|
104
105
|
private
|
105
106
|
|
106
107
|
def check(dir)
|
107
|
-
raise GobstonesTypeError, "#{dir} is not a direction"
|
108
|
-
unless [Norte, Sur, Este, Oeste].include? dir.class
|
108
|
+
raise GobstonesTypeError, "#{dir} is not a direction" unless [Norte, Sur, Este, Oeste].include?(dir.class)
|
109
109
|
end
|
110
|
-
|
111
110
|
end
|
112
|
-
|
113
111
|
end
|
114
|
-
|
115
112
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe CommandBlock do
|
2
|
+
let(:context) { clean_context }
|
3
|
+
|
4
|
+
it 'evaluates all inner commands' do
|
5
|
+
command_block = described_class.new([Poner.new(rojo), Poner.new(verde), Poner.new(negro), Poner.new(azul)])
|
6
|
+
command_block.evaluate context
|
7
|
+
|
8
|
+
expect_balls(azul, negro, rojo, verde)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'builds an empty command block' do
|
12
|
+
expect(described_class.new([])).to be_empty
|
13
|
+
expect(described_class.empty).to be_empty
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
RSpec.describe If do
|
2
|
+
subject(:evaluate_if_command) { described_class.new(condition, then_block).evaluate(context) }
|
3
|
+
|
4
|
+
let(:context) { clean_context }
|
5
|
+
let(:then_block) { CommandBlock.with_just(Poner.new(verde)) }
|
6
|
+
|
7
|
+
context 'when condition is true' do
|
8
|
+
let(:condition) { true_value }
|
9
|
+
|
10
|
+
it "evaluates the 'then' block" do
|
11
|
+
evaluate_if_command and expect_balls(verde)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when condition is false' do
|
16
|
+
let(:condition) { false_value }
|
17
|
+
|
18
|
+
it "does not evaluate the 'then' block" do
|
19
|
+
evaluate_if_command and expect_no_balls(verde)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
[42.to_gbs_num, norte, verde].each do |value|
|
24
|
+
context "when condition has a wrong type (#{value.class})" do
|
25
|
+
let(:condition) { value }
|
26
|
+
|
27
|
+
it 'raises a type error' do
|
28
|
+
expect { evaluate_if_command }.to raise_error(GobstonesTypeError, /is not a boolean/)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
RSpec.describe IfThenElse do
|
2
|
+
let(:context) { clean_context }
|
3
|
+
let(:then_block) { CommandBlock.with_just(Poner.new(verde)) }
|
4
|
+
let(:else_block) { CommandBlock.with_just(Poner.new(rojo)) }
|
5
|
+
|
6
|
+
it "evaluates the 'then' block and it does not evaluate the 'else' block" do
|
7
|
+
described_class.new(true_value, then_block, else_block).evaluate context
|
8
|
+
|
9
|
+
expect_balls(verde)
|
10
|
+
expect_no_balls(rojo)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not evaluate the 'then' block and it evaluates the 'else' block" do
|
14
|
+
described_class.new(false_value, then_block, else_block).evaluate context
|
15
|
+
|
16
|
+
expect_no_balls(verde)
|
17
|
+
expect_balls(rojo)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe Mover do
|
2
|
+
let(:context) { clean_context }
|
3
|
+
|
4
|
+
it 'moves the head to the specified direction when evaluating' do
|
5
|
+
described_class.new(norte).evaluate(context)
|
6
|
+
|
7
|
+
expect_positioned_at(0, 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'undoes the given movement' do
|
11
|
+
cmd = described_class.new(norte)
|
12
|
+
|
13
|
+
cmd.evaluate context
|
14
|
+
cmd.undo context
|
15
|
+
|
16
|
+
expect_positioned_at(0, 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns the opposite command' do
|
20
|
+
expect(described_class.new(norte).opposite).to eq(described_class.new(sur))
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'fails if the argument is not a direction' do
|
24
|
+
expect { described_class.new(verde).evaluate(context) }.to raise_error(GobstonesTypeError, /is not a direction/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'fails when the resulting position is out of board' do
|
28
|
+
expect { described_class.new(sur).evaluate(context) }.to raise_error(OutOfBoardError)
|
29
|
+
end
|
30
|
+
end
|
@@ -1,37 +1,54 @@
|
|
1
|
-
describe MultipleAssignment do
|
2
|
-
|
3
|
-
let(:
|
4
|
-
let(:
|
5
|
-
let(:program) { Program.new
|
6
|
-
let(:context) { program_context_for
|
1
|
+
RSpec.describe MultipleAssignment do
|
2
|
+
let(:my_function_return) { ReturnFromFunction.new([42.to_gbs_num, verde, MinDir.new]) }
|
3
|
+
let(:my_function_def) { Function.new('myFunction', no_arguments, empty_body, my_function_return) }
|
4
|
+
let(:call_to_my_function) { FunctionCall.new('myFunction', []) }
|
5
|
+
let(:program) { Program.new([my_function_def], no_return_statement) }
|
6
|
+
let(:context) { program_context_for(program) }
|
7
7
|
let(:a) { 'a'.to_var_name }
|
8
8
|
let(:b) { 'b'.to_var_name }
|
9
9
|
let(:c) { 'c'.to_var_name }
|
10
|
+
let(:d) { 'd'.to_var_name }
|
10
11
|
|
11
|
-
|
12
|
+
def expect_assignment(variable, value)
|
13
|
+
expect(context.has_variable_named?(variable.name)).to be(true)
|
14
|
+
expect(context.get(variable)).to eq(value)
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
assign =
|
17
|
+
context 'when assignment can be made' do
|
18
|
+
it 'evaluates and set all the variables with the return values of a function call' do
|
19
|
+
var_tuple = VarTuple.new([a, b, c])
|
20
|
+
assign = described_class.new(var_tuple, call_to_my_function)
|
17
21
|
assign.evaluate context
|
18
|
-
expect(context.has_variable_named?('a')).to be true
|
19
|
-
expect(context.get(a)).to eq(42.to_gbs_num)
|
20
|
-
expect(context.has_variable_named?('b')).to be true
|
21
|
-
expect(context.get(b)).to eq(verde)
|
22
|
-
expect(context.has_variable_named?('c')).to be true
|
23
|
-
expect(context.get(c)).to eq(norte)
|
24
|
-
end
|
25
22
|
|
23
|
+
expect_assignment(a, 42.to_gbs_num)
|
24
|
+
expect_assignment(b, verde)
|
25
|
+
expect_assignment(c, norte)
|
26
|
+
end
|
26
27
|
end
|
27
28
|
|
28
|
-
context
|
29
|
+
context 'when assignment cannot be made' do
|
30
|
+
it 'fails if there are more variables to be assigned on the left' do
|
31
|
+
var_tuple = VarTuple.new([a, b, c, d])
|
32
|
+
assign = described_class.new(var_tuple, call_to_my_function)
|
29
33
|
|
30
|
-
|
34
|
+
error_message = 'Wrong number of arguments in assignment: expected 4, got 3'
|
35
|
+
expect { assign.evaluate context }.to raise_error(Gobstones::Runner::WrongArgumentsError, error_message)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'fails if there are more things to assign on the right' do
|
39
|
+
var_tuple = VarTuple.new([a, b])
|
40
|
+
assign = described_class.new(var_tuple, call_to_my_function)
|
31
41
|
|
32
|
-
|
42
|
+
error_message = 'Wrong number of arguments in assignment: expected 2, got 3'
|
43
|
+
expect { assign.evaluate context }.to raise_error(Gobstones::Runner::WrongArgumentsError, error_message)
|
44
|
+
end
|
33
45
|
|
34
|
-
it
|
46
|
+
it 'fails if the expression on the right is not a function call' do
|
47
|
+
var_tuple = VarTuple.new([a, b])
|
48
|
+
assign = described_class.new(var_tuple, Add.new(12.to_gbs_num, 23.to_gbs_num))
|
35
49
|
|
50
|
+
error_message = 'expected a function call in multiple assignment'
|
51
|
+
expect { assign.evaluate context }.to raise_error(Gobstones::Runner::GobstonesTypeError, error_message)
|
52
|
+
end
|
36
53
|
end
|
37
54
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
RSpec.describe Poner do
|
2
|
+
subject(:poner_cmd) { described_class.new(verde) }
|
3
|
+
|
4
|
+
let(:context) { clean_context }
|
5
|
+
|
6
|
+
it 'puts a ball of the given color in the current cell when evaluating' do
|
7
|
+
poner_cmd.evaluate(context)
|
8
|
+
|
9
|
+
expect(context.head.number_of_balls(verde)).to eq(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'undoes the command' do
|
13
|
+
context.head.put verde
|
14
|
+
|
15
|
+
poner_cmd.undo(context)
|
16
|
+
|
17
|
+
expect(context.head.number_of_balls(verde)).to eq(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns the opposite command' do
|
21
|
+
expect(poner_cmd.opposite).to eq(Sacar.new(verde))
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'fails if the argument is not a color' do
|
25
|
+
expect { described_class.new(norte).evaluate(context) }.to raise_error(GobstonesTypeError, /is not a color/)
|
26
|
+
end
|
27
|
+
end
|
@@ -1,39 +1,37 @@
|
|
1
|
-
describe
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
proc_call = ProcedureCall.new 'MyProcedure', []
|
1
|
+
RSpec.describe ProcedureCall do
|
2
|
+
it 'evaluates an existing procedure when calling it' do
|
3
|
+
poner_cmd = Poner.new(verde)
|
4
|
+
body = CommandBlock.with_just(poner_cmd)
|
5
|
+
my_procedure = Procedure.new('MyProcedure', no_arguments, body)
|
6
|
+
program = Program.new([my_procedure], no_return_statement)
|
7
|
+
context = program_context_for(program)
|
8
|
+
|
9
|
+
proc_call = described_class.new('MyProcedure', [])
|
11
10
|
proc_call.evaluate context
|
12
11
|
|
13
|
-
expect(context.head.are_there_balls?(verde)).to be
|
12
|
+
expect(context.head.are_there_balls?(verde)).to be(true)
|
14
13
|
end
|
15
14
|
|
16
|
-
it
|
17
|
-
poner_cmd = Poner.new
|
18
|
-
inner_procedure_body = CommandBlock.
|
19
|
-
inner_procedure = Procedure.new
|
20
|
-
call_to_inner_procedure =
|
21
|
-
outer_procedure_body = CommandBlock.
|
22
|
-
outer_procedure = Procedure.new
|
23
|
-
program = Program.new
|
24
|
-
program_context = program_context_for
|
25
|
-
|
26
|
-
call_to_outer_procedure =
|
15
|
+
it 'allows to call a procedure from another procedure' do
|
16
|
+
poner_cmd = Poner.new(azul)
|
17
|
+
inner_procedure_body = CommandBlock.with_just(poner_cmd)
|
18
|
+
inner_procedure = Procedure.new('Inner', no_arguments, inner_procedure_body)
|
19
|
+
call_to_inner_procedure = described_class.new('Inner', [])
|
20
|
+
outer_procedure_body = CommandBlock.with_just(call_to_inner_procedure)
|
21
|
+
outer_procedure = Procedure.new('Outer', no_arguments, outer_procedure_body)
|
22
|
+
program = Program.new([outer_procedure, inner_procedure], no_return_statement)
|
23
|
+
program_context = program_context_for(program)
|
24
|
+
|
25
|
+
call_to_outer_procedure = described_class.new('Outer', [])
|
27
26
|
call_to_outer_procedure.evaluate program_context
|
28
27
|
|
29
|
-
expect(program_context.head.are_there_balls?(azul)).to be
|
28
|
+
expect(program_context.head.are_there_balls?(azul)).to be(true)
|
30
29
|
end
|
31
30
|
|
32
|
-
it
|
33
|
-
proc_call =
|
31
|
+
it 'fails to execute an undefined procedure' do
|
32
|
+
proc_call = described_class.new('UndefinedProcedure', [])
|
34
33
|
|
35
|
-
expect { proc_call.evaluate clean_context }
|
36
|
-
|
34
|
+
expect { proc_call.evaluate clean_context }.
|
35
|
+
to raise_error(DefinitionNotFound, DefinitionNotFound.message_for('UndefinedProcedure'))
|
37
36
|
end
|
38
|
-
|
39
37
|
end
|
@@ -1,63 +1,63 @@
|
|
1
|
-
describe Procedure do
|
2
|
-
|
1
|
+
RSpec.describe Procedure do
|
3
2
|
let(:context) { clean_context }
|
4
3
|
|
5
|
-
it
|
6
|
-
poner_cmd = Poner.new
|
7
|
-
body = CommandBlock.
|
8
|
-
procedure =
|
4
|
+
it 'executes its body and leaves state in the program context' do
|
5
|
+
poner_cmd = Poner.new(rojo)
|
6
|
+
body = CommandBlock.with_just(poner_cmd)
|
7
|
+
procedure = described_class.new('MyProcedure', no_arguments, body)
|
9
8
|
procedure.evaluate context
|
10
|
-
|
9
|
+
|
10
|
+
expect_balls(rojo)
|
11
11
|
end
|
12
12
|
|
13
|
-
it
|
13
|
+
it 'fails getting a variable which is in the outer context' do
|
14
14
|
var_name = 'var'.to_var_name
|
15
15
|
context.set var_name, verde
|
16
16
|
|
17
|
-
poner_cmd = Poner.new
|
18
|
-
body = CommandBlock.
|
19
|
-
procedure =
|
17
|
+
poner_cmd = Poner.new(var_name)
|
18
|
+
body = CommandBlock.with_just(poner_cmd)
|
19
|
+
procedure = described_class.new('MyProcedure', no_arguments, body)
|
20
|
+
|
20
21
|
expect { procedure.evaluate context }.to raise_error(UndefinedVariableError)
|
21
22
|
end
|
22
23
|
|
23
|
-
it
|
24
|
+
it 'sets arguments in the new context so they can be used' do
|
24
25
|
a_color = 'a_color'.to_var_name
|
25
26
|
a_direction = 'a_direction'.to_var_name
|
26
|
-
args = VarTuple.new
|
27
|
-
mover_cmd = Mover.new
|
28
|
-
poner_cmd = Poner.new
|
29
|
-
body = CommandBlock.new
|
30
|
-
procedure =
|
27
|
+
args = VarTuple.new([a_color, a_direction])
|
28
|
+
mover_cmd = Mover.new(a_direction)
|
29
|
+
poner_cmd = Poner.new(a_color)
|
30
|
+
body = CommandBlock.new([mover_cmd, poner_cmd])
|
31
|
+
procedure = described_class.new('MyProc', args, body)
|
31
32
|
|
32
33
|
procedure.evaluate context, [negro, norte]
|
33
34
|
|
34
|
-
|
35
|
+
expect_balls(negro)
|
35
36
|
expect(context.head.y_pos).to eq(1)
|
36
37
|
end
|
37
38
|
|
38
|
-
it
|
39
|
+
it 'does not set arguments as var names in outer context' do
|
39
40
|
a_direction = 'a_direction'.to_var_name
|
40
|
-
args = VarTuple.new
|
41
|
-
procedure =
|
41
|
+
args = VarTuple.new([a_direction])
|
42
|
+
procedure = described_class.new('MyProc', args, empty_body)
|
42
43
|
|
43
44
|
procedure.evaluate context, [oeste]
|
44
45
|
|
45
|
-
expect(context.has_variable_named?('a_direction')).to be
|
46
|
+
expect(context.has_variable_named?('a_direction')).to be(false)
|
46
47
|
end
|
47
48
|
|
48
|
-
it
|
49
|
-
procedure =
|
49
|
+
it 'fails if it is executed with more arguments than expected' do
|
50
|
+
procedure = described_class.new('MyProcedure', no_arguments, empty_body)
|
51
|
+
|
50
52
|
error_message = "Wrong number of arguments in procedure 'MyProcedure': expected 0, got 1"
|
51
|
-
expect { procedure.evaluate context, [norte] }
|
52
|
-
.to raise_error(WrongArgumentsError, error_message)
|
53
|
+
expect { procedure.evaluate context, [norte] }.to raise_error(WrongArgumentsError, error_message)
|
53
54
|
end
|
54
55
|
|
55
|
-
it
|
56
|
-
args = VarTuple.
|
57
|
-
procedure =
|
56
|
+
it 'fails if it is executed with less arguments than expected' do
|
57
|
+
args = VarTuple.with_names(%w[arg1 arg2])
|
58
|
+
procedure = described_class.new('MyProcedure2', args, empty_body)
|
59
|
+
|
58
60
|
error_message = "Wrong number of arguments in procedure 'MyProcedure2': expected 2, got 1"
|
59
|
-
expect { procedure.evaluate context, [verde] }
|
60
|
-
.to raise_error(WrongArgumentsError, error_message)
|
61
|
+
expect { procedure.evaluate context, [verde] }.to raise_error(WrongArgumentsError, error_message)
|
61
62
|
end
|
62
|
-
|
63
63
|
end
|