gobstones 0.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,32 @@
|
|
1
|
+
require 'gobstones/runner/execution_context'
|
2
|
+
|
3
|
+
module Gobstones
|
4
|
+
|
5
|
+
module Lang
|
6
|
+
|
7
|
+
class Program
|
8
|
+
|
9
|
+
attr_reader :definitions, :main_definition
|
10
|
+
|
11
|
+
def initialize(definitions, main_definition)
|
12
|
+
@definitions = definitions
|
13
|
+
@main_definition = main_definition
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
self.class == other.class &&
|
18
|
+
self.definitions == other.definitions &&
|
19
|
+
self.main_definition == other.main_definition
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate
|
23
|
+
context = Gobstones::Runner::ProgramExecutionContext.for self
|
24
|
+
main_definition.evaluate context
|
25
|
+
context
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'gobstones/lang/all'
|
2
|
+
|
3
|
+
module Gobstones
|
4
|
+
|
5
|
+
# TODO divide into smaller modules
|
6
|
+
module Parser
|
7
|
+
|
8
|
+
include Gobstones::Lang
|
9
|
+
|
10
|
+
RESERVED_IDS = %w(
|
11
|
+
if else not True False case of while Skip repeatWith in procedure function
|
12
|
+
return Mover Sacar Poner BOOM IrAlOrigen VaciarTablero div mod hayBolitas
|
13
|
+
nroBolitas puedeMover Norte Sur Este Oeste minBool maxBool minDir maxDir
|
14
|
+
minColor maxColor siguiente previo opuesto Verde Rojo Azul Negro Main
|
15
|
+
)
|
16
|
+
|
17
|
+
def self.ast_node(name, &value_block)
|
18
|
+
# TODO check if it is better to have classes
|
19
|
+
mod = Module.new do
|
20
|
+
define_method :value do
|
21
|
+
instance_eval(&value_block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
const_set name, mod
|
25
|
+
end
|
26
|
+
|
27
|
+
ast_node(:IntegerLiteral) { Number.new text_value.to_i }
|
28
|
+
ast_node(:BooleanLiteral) { Kernel.const_get(text_value).new }
|
29
|
+
ast_node(:ColorLiteral) { Kernel.const_get(text_value).new }
|
30
|
+
ast_node(:DirectionLiteral) { Kernel.const_get(text_value).new }
|
31
|
+
|
32
|
+
ast_node(:MinBoolFuncNode) { MinBool.new }
|
33
|
+
ast_node(:MaxBoolFuncNode) { MaxBool.new }
|
34
|
+
ast_node(:MinColorFuncNode) { MinColor.new }
|
35
|
+
ast_node(:MaxColorFuncNode) { MaxColor.new }
|
36
|
+
ast_node(:MinDirFuncNode) { MinDir.new }
|
37
|
+
ast_node(:MaxDirFuncNode) { MaxDir.new }
|
38
|
+
|
39
|
+
ast_node(:VarNameNode) { VarName.new text_value }
|
40
|
+
|
41
|
+
ast_node(:NroBolitasFuncNode) { NroBolitas.new gexp.value }
|
42
|
+
ast_node(:HayBolitasFuncNode) { HayBolitas.new gexp.value }
|
43
|
+
ast_node(:PuedeMoverFuncNode) { PuedeMover.new gexp.value }
|
44
|
+
ast_node(:SiguienteFuncNode) { Siguiente.new gexp.value }
|
45
|
+
ast_node(:PrevioFuncNode) { Previo.new gexp.value }
|
46
|
+
ast_node(:OpuestoFuncNode) { Opuesto.new gexp.value }
|
47
|
+
|
48
|
+
ast_node :NopExprNode do
|
49
|
+
if sub_exps.empty?
|
50
|
+
left.value
|
51
|
+
else
|
52
|
+
# it is a nested exp
|
53
|
+
sub_exps.elements.inject(left.value) do |memo, node|
|
54
|
+
case node.op.text_value
|
55
|
+
when '+'
|
56
|
+
memo = Add.new memo, node.right.value
|
57
|
+
when '-'
|
58
|
+
memo = Sub.new memo, node.right.value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
ast_node :MulExprNode do
|
65
|
+
if sub_exps.empty?
|
66
|
+
left.value
|
67
|
+
else
|
68
|
+
# it is a nested exp
|
69
|
+
sub_exps.elements.inject(left.value) do |memo, node|
|
70
|
+
memo = Mul.new memo, node.right.value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
ast_node :DivModExprNode do
|
76
|
+
case op.text_value
|
77
|
+
when 'div'
|
78
|
+
Div.new left.value, right.value
|
79
|
+
when 'mod'
|
80
|
+
Mod.new left.value, right.value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ast_node :PowExprNode do
|
85
|
+
if sub_exps.empty?
|
86
|
+
left.value
|
87
|
+
else
|
88
|
+
# it is a nested exp
|
89
|
+
sub_exps.elements.inject(left.value) do |memo, node|
|
90
|
+
memo = Pow.new memo, node.right.value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
ast_node :RopExprNode do
|
96
|
+
classes = {
|
97
|
+
'==' => Equal, '/=' => NotEqual,
|
98
|
+
'<' => LessThan, '>' => GreaterThan,
|
99
|
+
'<=' => LessEqual, '>=' => GreaterEqual
|
100
|
+
}
|
101
|
+
classes[rop.text_value].new left.value, right.value
|
102
|
+
end
|
103
|
+
|
104
|
+
ast_node(:NotExprNode) { Not.new exp.value }
|
105
|
+
ast_node(:AndExprNode) { And.new left.value, right.value }
|
106
|
+
ast_node(:OrExprNode) { Or.new left.value, right.value }
|
107
|
+
|
108
|
+
ast_node(:ParenthesesExprNode) { ParenthesesExpr.new gexp.value }
|
109
|
+
ast_node(:FuncCallNode) do
|
110
|
+
FunctionCall.new func_name.text_value, gexp_tuple.value
|
111
|
+
end
|
112
|
+
ast_node(:TupleExprNode) { exps.empty? ? [] : exps.value }
|
113
|
+
|
114
|
+
ast_node :GexpsNode do
|
115
|
+
if elements.length == 2
|
116
|
+
[elements[0].value]
|
117
|
+
else
|
118
|
+
[exp.value] + exps.value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
ast_node(:SkipCmdNode) { Skip.new }
|
123
|
+
ast_node(:BoomCmdNode) { Boom.new string.text_value[1..-2] }
|
124
|
+
|
125
|
+
ast_node(:PonerCmdNode) { Poner.new gexp.value }
|
126
|
+
ast_node(:SacarCmdNode) { Sacar.new gexp.value }
|
127
|
+
ast_node(:MoverCmdNode) { Mover.new gexp.value }
|
128
|
+
|
129
|
+
ast_node(:IrAlOrigenCmdNode) { IrAlOrigen.new }
|
130
|
+
ast_node(:VaciarTableroCmdNode) { VaciarTablero.new }
|
131
|
+
|
132
|
+
ast_node :ProcCallNode do
|
133
|
+
ProcedureCall.new proc_name.text_value, gexp_tuple.value
|
134
|
+
end
|
135
|
+
|
136
|
+
ast_node :SingleAssignmentNode do
|
137
|
+
SingleAssignment.new var_name.value, gexp.value
|
138
|
+
end
|
139
|
+
|
140
|
+
ast_node :CmdBlockNode do
|
141
|
+
CmdBlock.new create_commands(commands)
|
142
|
+
end
|
143
|
+
|
144
|
+
ast_node :IfCmdNode do
|
145
|
+
if else_clause.empty?
|
146
|
+
IfCmd.new gexp.value, then_block.value
|
147
|
+
else
|
148
|
+
IfElseCmd.new gexp.value, then_block.value, else_clause.else_block.value
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
ast_node(:WhileCmdNode) { WhileCmd.new gexp.value, cmd_block.value }
|
153
|
+
|
154
|
+
ast_node :RepeatWithCmdNode do
|
155
|
+
RepeatWithCmd.new var_name.value, range_min.value,
|
156
|
+
range_max.value, cmd_block.value
|
157
|
+
end
|
158
|
+
|
159
|
+
# TODO abstract duplication, very similar to GexpsNode
|
160
|
+
ast_node(:VarNamesNode) do
|
161
|
+
if elements.length == 2
|
162
|
+
# TODO check why it is needed to create a VarName
|
163
|
+
# instead of having already a VarName in elements[0]
|
164
|
+
[VarName.new(elements[0].text_value)]
|
165
|
+
else
|
166
|
+
[vn.value] + vns.value
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
ast_node(:VarTupleNode) do
|
171
|
+
variables = vns.empty? ? [] : vns.value
|
172
|
+
VarTuple.new variables
|
173
|
+
end
|
174
|
+
|
175
|
+
ast_node(:ProcedureNode) do
|
176
|
+
Procedure.new proc_name.text_value, var_tuple.value, cmd_block.value
|
177
|
+
end
|
178
|
+
|
179
|
+
ast_node(:FunctionNode) do
|
180
|
+
cmd_block = CmdBlock.new create_commands(commands)
|
181
|
+
Function.new func_name.text_value, var_tuple.value,
|
182
|
+
cmd_block, func_return.value
|
183
|
+
end
|
184
|
+
|
185
|
+
ast_node(:FuncReturnNode) do
|
186
|
+
ReturnFromFunction.new gexp_tuple_1.value
|
187
|
+
end
|
188
|
+
|
189
|
+
ast_node(:MainReturnNode) do
|
190
|
+
ReturnFromMain.new var_tuple.value
|
191
|
+
end
|
192
|
+
|
193
|
+
ast_node(:MainDefNode) do
|
194
|
+
cmd_block = CmdBlock.new create_commands(commands)
|
195
|
+
return_st = ret.empty? ? NoReturnStatement.new : ret.value
|
196
|
+
Main.new cmd_block, return_st
|
197
|
+
end
|
198
|
+
|
199
|
+
ast_node(:ProgramNode) do
|
200
|
+
defs = definitions.elements.map { |node| node.definition.value }
|
201
|
+
Program.new defs, main_def.value
|
202
|
+
end
|
203
|
+
|
204
|
+
def create_commands(commands)
|
205
|
+
commands.elements.map { |node| node.command.value }
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# TODO modularize when possible
|
2
|
+
grammar Gobstones
|
3
|
+
|
4
|
+
# TOP RULE: program
|
5
|
+
|
6
|
+
rule program
|
7
|
+
definitions main_def space* <ProgramNode>
|
8
|
+
end
|
9
|
+
|
10
|
+
# DEFINITIONS: main, procedures, functions
|
11
|
+
|
12
|
+
rule definitions
|
13
|
+
(space* definition space*)*
|
14
|
+
end
|
15
|
+
|
16
|
+
rule definition
|
17
|
+
procedure_def / function_def
|
18
|
+
end
|
19
|
+
|
20
|
+
rule main_def
|
21
|
+
'procedure' space+ 'Main' space* '(' space* ')' space*
|
22
|
+
'{' space* commands ret:main_return? space* '}' <MainDefNode>
|
23
|
+
end
|
24
|
+
|
25
|
+
rule main_return
|
26
|
+
'return' space* var_tuple space* ';'? <MainReturnNode>
|
27
|
+
end
|
28
|
+
|
29
|
+
rule procedure_def
|
30
|
+
'procedure' space+ proc_name space*
|
31
|
+
var_tuple space* cmd_block <ProcedureNode>
|
32
|
+
end
|
33
|
+
|
34
|
+
rule function_def
|
35
|
+
'function' space+ func_name space* var_tuple space*
|
36
|
+
'{' space* commands func_return space* '}' <FunctionNode>
|
37
|
+
end
|
38
|
+
|
39
|
+
rule func_return
|
40
|
+
'return' space* gexp_tuple_1 space* ';'? <FuncReturnNode>
|
41
|
+
end
|
42
|
+
|
43
|
+
# COMMANDS
|
44
|
+
|
45
|
+
rule commands
|
46
|
+
(command space* ';'? space*)*
|
47
|
+
end
|
48
|
+
|
49
|
+
rule command
|
50
|
+
simple_cmd / complex_cmd
|
51
|
+
end
|
52
|
+
|
53
|
+
rule simple_cmd
|
54
|
+
skip_cmd / boom_cmd / poner_cmd / sacar_cmd / mover_cmd /
|
55
|
+
ir_al_origen_cmd / vaciar_tablero_cmd / proc_call /
|
56
|
+
cmd_block / single_assignment # / multiple_assignment
|
57
|
+
end
|
58
|
+
|
59
|
+
rule skip_cmd
|
60
|
+
'Skip' <SkipCmdNode>
|
61
|
+
end
|
62
|
+
|
63
|
+
rule boom_cmd
|
64
|
+
'BOOM' space* '(' space* string space* ')' <BoomCmdNode>
|
65
|
+
end
|
66
|
+
|
67
|
+
rule poner_cmd
|
68
|
+
'Poner' space* '(' space* gexp space* ')' <PonerCmdNode>
|
69
|
+
end
|
70
|
+
|
71
|
+
rule sacar_cmd
|
72
|
+
'Sacar' space* '(' space* gexp space* ')' <SacarCmdNode>
|
73
|
+
end
|
74
|
+
|
75
|
+
rule mover_cmd
|
76
|
+
'Mover' space* '(' space* gexp space* ')' <MoverCmdNode>
|
77
|
+
end
|
78
|
+
|
79
|
+
rule ir_al_origen_cmd
|
80
|
+
'IrAlOrigen' space* '(' space* ')' <IrAlOrigenCmdNode>
|
81
|
+
end
|
82
|
+
|
83
|
+
rule vaciar_tablero_cmd
|
84
|
+
'VaciarTablero' space* '(' space* ')' <VaciarTableroCmdNode>
|
85
|
+
end
|
86
|
+
|
87
|
+
rule proc_call
|
88
|
+
proc_name space* gexp_tuple <ProcCallNode>
|
89
|
+
end
|
90
|
+
|
91
|
+
rule cmd_block
|
92
|
+
'{' space* commands space* '}' <CmdBlockNode>
|
93
|
+
end
|
94
|
+
|
95
|
+
rule single_assignment
|
96
|
+
var_name space* ':=' space* gexp <SingleAssignmentNode>
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO implement
|
100
|
+
# rule multiple_assignment
|
101
|
+
# end
|
102
|
+
|
103
|
+
rule complex_cmd
|
104
|
+
if_cmd / while_cmd / repeat_with_cmd # / case_cmd
|
105
|
+
end
|
106
|
+
|
107
|
+
rule if_cmd
|
108
|
+
'if' space* '(' space* gexp space* ')'
|
109
|
+
space* then_block:cmd_block
|
110
|
+
else_clause:(space* 'else' space* else_block:cmd_block)?
|
111
|
+
<IfCmdNode>
|
112
|
+
end
|
113
|
+
|
114
|
+
rule while_cmd
|
115
|
+
'while' space* '(' space* gexp space* ')' space* cmd_block <WhileCmdNode>
|
116
|
+
end
|
117
|
+
|
118
|
+
rule repeat_with_cmd
|
119
|
+
'repeatWith' space+ var_name space+ 'in' space+
|
120
|
+
range_min:gexp space* '..' space* range_max:gexp space*
|
121
|
+
cmd_block <RepeatWithCmdNode>
|
122
|
+
end
|
123
|
+
|
124
|
+
# TODO implement
|
125
|
+
# rule case_cmd
|
126
|
+
# end
|
127
|
+
|
128
|
+
# EXPRESSIONS
|
129
|
+
|
130
|
+
rule gexp
|
131
|
+
bexp
|
132
|
+
end
|
133
|
+
|
134
|
+
rule bexp
|
135
|
+
left:bterm space* '||' space* right:bexp <OrExprNode> / bterm
|
136
|
+
end
|
137
|
+
|
138
|
+
rule bterm
|
139
|
+
left:bfact space* '&&' space* right:bterm <AndExprNode> / bfact
|
140
|
+
end
|
141
|
+
|
142
|
+
rule bfact
|
143
|
+
'not' space+ exp:batom <NotExprNode> / batom
|
144
|
+
end
|
145
|
+
|
146
|
+
rule batom
|
147
|
+
left:nexp space* rop space* right:nexp <RopExprNode> / nexp
|
148
|
+
end
|
149
|
+
|
150
|
+
rule rop
|
151
|
+
'==' / '/=' / '<=' / '>=' / '<' / '>'
|
152
|
+
end
|
153
|
+
|
154
|
+
rule nexp
|
155
|
+
left:nterm sub_exps:(space* op:[+-] space* right:nterm)* <NopExprNode>
|
156
|
+
end
|
157
|
+
|
158
|
+
rule nterm
|
159
|
+
left:nfactH sub_exps:(space* '*' space* right:nfactH)* <MulExprNode>
|
160
|
+
end
|
161
|
+
|
162
|
+
rule nfactH
|
163
|
+
left:nfactL space+ op:mop space+ right:nfactL <DivModExprNode> / nfactL
|
164
|
+
end
|
165
|
+
|
166
|
+
rule mop
|
167
|
+
'div' / 'mod'
|
168
|
+
end
|
169
|
+
|
170
|
+
rule nfactL
|
171
|
+
left:natom sub_exps:(space* '^' space* right:natom)* <PowExprNode>
|
172
|
+
end
|
173
|
+
|
174
|
+
rule natom
|
175
|
+
literal / type_bound_func / primitive_func /
|
176
|
+
paren_expr / func_call / var_name
|
177
|
+
end
|
178
|
+
|
179
|
+
rule type_bound_func
|
180
|
+
bool_type_bound_func / color_type_bound_func / direction_type_bound_func
|
181
|
+
end
|
182
|
+
|
183
|
+
rule bool_type_bound_func
|
184
|
+
'minBool()' <MinBoolFuncNode> / 'maxBool()' <MaxBoolFuncNode>
|
185
|
+
end
|
186
|
+
|
187
|
+
rule color_type_bound_func
|
188
|
+
'minColor()' <MinColorFuncNode> / 'maxColor()' <MaxColorFuncNode>
|
189
|
+
end
|
190
|
+
|
191
|
+
rule direction_type_bound_func
|
192
|
+
'minDir()' <MinDirFuncNode> / 'maxDir()' <MaxDirFuncNode>
|
193
|
+
end
|
194
|
+
|
195
|
+
rule primitive_func
|
196
|
+
nro_bolitas_func / hay_bolitas_func / puede_mover_func /
|
197
|
+
siguiente_func / previo_func / opuesto_func
|
198
|
+
end
|
199
|
+
|
200
|
+
rule nro_bolitas_func
|
201
|
+
'nroBolitas' space* '(' space* gexp space* ')' <NroBolitasFuncNode>
|
202
|
+
end
|
203
|
+
|
204
|
+
rule hay_bolitas_func
|
205
|
+
'hayBolitas' space* '(' space* gexp space* ')' <HayBolitasFuncNode>
|
206
|
+
end
|
207
|
+
|
208
|
+
rule puede_mover_func
|
209
|
+
'puedeMover' space* '(' space* gexp space* ')' <PuedeMoverFuncNode>
|
210
|
+
end
|
211
|
+
|
212
|
+
rule siguiente_func
|
213
|
+
'siguiente' space* '(' space* gexp space* ')' <SiguienteFuncNode>
|
214
|
+
end
|
215
|
+
|
216
|
+
rule previo_func
|
217
|
+
'previo' space* '(' space* gexp space* ')' <PrevioFuncNode>
|
218
|
+
end
|
219
|
+
|
220
|
+
rule opuesto_func
|
221
|
+
'opuesto' space* '(' space* gexp space* ')' <OpuestoFuncNode>
|
222
|
+
end
|
223
|
+
|
224
|
+
rule paren_expr
|
225
|
+
'(' space* gexp space* ')' <ParenthesesExprNode>
|
226
|
+
end
|
227
|
+
|
228
|
+
rule func_call
|
229
|
+
func_name space* gexp_tuple <FuncCallNode>
|
230
|
+
end
|
231
|
+
|
232
|
+
rule var_name
|
233
|
+
lower_id &{ |id| id[0].is_not_reserved } <VarNameNode>
|
234
|
+
end
|
235
|
+
|
236
|
+
# LITERALS
|
237
|
+
|
238
|
+
rule literal
|
239
|
+
number / boolean / color / direction
|
240
|
+
end
|
241
|
+
|
242
|
+
rule number
|
243
|
+
'-'? [0-9] [0-9]* <IntegerLiteral>
|
244
|
+
end
|
245
|
+
|
246
|
+
rule boolean
|
247
|
+
('True' / 'False') <BooleanLiteral>
|
248
|
+
end
|
249
|
+
|
250
|
+
rule color
|
251
|
+
('Azul' / 'Negro' / 'Rojo' / 'Verde') <ColorLiteral>
|
252
|
+
end
|
253
|
+
|
254
|
+
rule direction
|
255
|
+
('Norte' / 'Este' / 'Sur' / 'Oeste') <DirectionLiteral>
|
256
|
+
end
|
257
|
+
|
258
|
+
# AUX DEFINITIONS: identifiers, tuples
|
259
|
+
|
260
|
+
rule proc_name
|
261
|
+
upper_id &{ |id| id[0].is_not_reserved }
|
262
|
+
end
|
263
|
+
|
264
|
+
rule func_name
|
265
|
+
lower_id &{ |id| id[0].is_not_reserved }
|
266
|
+
end
|
267
|
+
|
268
|
+
rule var_tuple
|
269
|
+
'(' space* vns:var_names? space* ')' <VarTupleNode>
|
270
|
+
end
|
271
|
+
|
272
|
+
rule var_names
|
273
|
+
((vn:var_name space* ',' space* vns:var_names) / var_name) <VarNamesNode>
|
274
|
+
end
|
275
|
+
|
276
|
+
rule gexp_tuple
|
277
|
+
'(' space* exps:gexps? space* ')' <TupleExprNode>
|
278
|
+
end
|
279
|
+
|
280
|
+
rule gexp_tuple_1
|
281
|
+
'(' space* exps:gexps space* ')' <TupleExprNode>
|
282
|
+
end
|
283
|
+
|
284
|
+
rule gexps
|
285
|
+
((exp:gexp space* ',' space* exps:gexps) / gexp) <GexpsNode>
|
286
|
+
end
|
287
|
+
|
288
|
+
rule lower_id
|
289
|
+
[a-z] char* {
|
290
|
+
def is_not_reserved
|
291
|
+
!Gobstones::Parser::RESERVED_IDS.include? text_value
|
292
|
+
end
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
296
|
+
rule upper_id
|
297
|
+
[A-Z] char* {
|
298
|
+
def is_not_reserved
|
299
|
+
!Gobstones::Parser::RESERVED_IDS.include? text_value
|
300
|
+
end
|
301
|
+
}
|
302
|
+
end
|
303
|
+
|
304
|
+
rule char
|
305
|
+
[a-zA-Z0-9'_]
|
306
|
+
end
|
307
|
+
|
308
|
+
rule string
|
309
|
+
'"' ('\"' / !'"' .)* '"'
|
310
|
+
end
|
311
|
+
|
312
|
+
rule space
|
313
|
+
[\s]
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|