gobstones 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|