Решение на Бонус задача: ArnoldC+- от Михаил Здравков

Обратно към всички решения

Към профила на Михаил Здравков

Резултати

  • 7 точки от тестове
  • 0 бонус точки
  • 7 точки общо
  • 0 успешни тест(а)
  • 0 неуспешни тест(а)

Код

class ArnoldCPM
@printer = nil
@scopes = []
@builtin_variables = {i_lied: 0, no_problemo: 1}
@suppress_execution = false
@in_true_branch = false
@func_start_end_balance = 0
class << self
attr_writer :printer
def totally_recall(&block)
instance_eval &block
end
private
def method_missing(method)
method
end
# main start
def its_showtime
@scopes.push Scope.new
end
# main end
def you_have_been_terminated
@scopes.pop
end
# print
def talk_to_the_hand(something)
return if handle_possible_func_def __method__, something
return if @suppress_execution
with_value(something) do |value|
@printer.print value
end
end
# def var
def get_to_the_chopper(variable_name)
return if handle_possible_func_def __method__, variable_name
return if @suppress_execution
@init_variable = variable_name
end
# init value in var def
def here_is_my_invitation(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
scope.variables[@init_variable] = value
end
end
# +
def get_up(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :+, value
end
# -
def get_down(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :-, value
end
# *
def youre_fired(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :*, value
end
# /
def he_had_to_split(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :/, value
end
# %
def i_let_him_go(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :%, value
end
# or
def consider_that_a_divorce(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
current = scope.variables[@init_variable]
return current if current != 0
value
end
end
# and
def knock_knock(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
current = scope.variables[@init_variable]
return current if current == 0
value
end
end
# ==
def you_are_not_you_you_are_me(other)
return if handle_possible_func_def __method__, other
return if @suppress_execution
with_value(other) do |value|
current = scope.variables[@init_variable]
current === value
end
end
# >
def let_off_some_steam_bennet(other)
return if handle_possible_func_def __method__, other
return if @suppress_execution
with_value(other) do |value|
current = scope.variables[@init_variable]
current > value
end
end
# end var definitian
def enough_talk
return if handle_possible_func_def __method__
return if @suppress_execution
@init_variable = nil
end
# if
def because_im_going_to_say_please(condition)
return if handle_possible_func_def __method__, condition
return if @suppress_execution
@scopes.push Scope.new
with_value(condition) do |value|
@in_true_branch = value != 0
@suppress_execution = !@in_true_branch
end
end
# else
def bull_shit
return if handle_possible_func_def __method__
@suppress_execution = @in_true_branch
end
# fi
def you_have_no_respect_for_logic
return if handle_possible_func_def __method__
@suppress_execution = false
@in_true_branch = false
@scopes.pop
end
# def func
def listen_to_me_very_carefully(function_name)
@func_start_end_balance += 1
return if @suppress_execution
return if handle_possible_func_def __method__, function_name
scope.defining_function = function_name
scope.functions[function_name] = {args: [], body: []}
end
# parameter
def i_need_your_clothes_your_boots_and_your_motorcycle(argument_name)
return if @suppress_execution
function = scope.functions[scope.defining_function]
res = function[:body].any? do |f|
f[:method] != :i_need_your_clothes_your_boots_and_your_motorcycle
end
if res
function[:body] << {method: __method__, args: [argument_name]}
else
function[:args] << argument_name
end
end
# return
def ill_be_back(value = 0)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) { |value| value }
end
# end function definition
def hasta_la_vista_baby
@func_start_end_balance -= 1
return if @suppress_execution
scope.defining_function = nil if @func_start_end_balance == 0
return if handle_possible_func_def __method__
end
def do_it_now(function_name, *arguments)
return if handle_possible_func_def __method__, function_name, *arguments
return if @suppress_execution
function = get_function(function_name)
args_to_values = Hash[function[:args].zip(arguments)]
@scopes.push Scope.new
result = execute_function function, args_to_values
get_result = @scopes[-2].put_result_in_var && function[:produces_result]
@scopes[-2].variables[@scopes[-2].put_result_in_var] = result if get_result
@scopes[-2].put_result_in_var = nil
@scopes.pop
end
# marks a function that returns a result
def give_these_people_air
if scope.defining_function && @func_start_end_balance == 1
scope.functions[scope.defining_function][:produces_result] = true
end
handle_possible_func_def __method__
end
def get_your_ass_to_mars(variable_name)
return if handle_possible_func_def __method__, variable_name
scope.put_result_in_var = variable_name
end
# non-api internal functions
def execute_function(function, parameters)
function[:body].each do |function_call|
arguments = function_call[:args].map do |a|
!a.is_a?(Symbol) ? a : parameters[a] || get_var(a) || a
end
result = send function_call[:method], *arguments
return result if function_call[:method] == :ill_be_back && !result.nil?
end
0
end
def get_var(name)
@scopes.reverse.each do |scope|
return scope.variables[name] if scope.variables.key? name
end
@builtin_variables.fetch name, nil
end
def get_function(name)
@scopes.reverse.each do |scope|
return scope.functions[name] if scope.functions.key? name
end
nil
end
def apply_operator(operator, value)
with_value(value) do |value|
new_value = scope.variables[@init_variable].send(operator, value)
scope.variables[@init_variable] = new_value
end
end
def with_value(value)
if value.is_a? Symbol
yield get_var(value)
else
yield value
end
end
def scope
@scopes.last
end
def handle_possible_func_def(method, *arguments)
if scope.defining_function
scope.functions[scope.defining_function][:body] << {method: method, args: arguments}
end
scope.defining_function
end
end
class Scope
attr_accessor :functions, :variables, :defining_function, :put_result_in_var
def initialize
@functions = {}
@variables = {}
end
end
# put one general scope at the beginning
@scopes << Scope.new
end

Лог от изпълнението

Finished in 0.00096 seconds
2 examples, 1 failure
/data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:200:in `flatten': can't convert Class to Array (Class#to_ary gives Symbol) (TypeError)
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:200:in `full_description'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:76:in `store_computed'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:49:in `[]'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:123:in `full_description'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:76:in `store_computed'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/metadata.rb:49:in `[]'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example.rb:41:in `block (2 levels) in delegate_to_metadata'
	from /data/rails/evans-2016/releases/20161119130633/lib/language/ruby/json_formatter.rb:22:in `example_failed'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/reporter.rb:130:in `block in notify'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/reporter.rb:129:in `each'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/reporter.rb:129:in `notify'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/reporter.rb:92:in `example_failed'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example.rb:264:in `finish'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example.rb:231:in `fail_with_exception'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example_group.rb:523:in `block in fail_filtered_examples'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example_group.rb:523:in `each'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example_group.rb:523:in `fail_filtered_examples'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example_group.rb:501:in `rescue in run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/example_group.rb:506:in `run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/command_line.rb:24:in `block (2 levels) in run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/command_line.rb:24:in `map'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/command_line.rb:24:in `block in run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/reporter.rb:58:in `report'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/command_line.rb:21:in `run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/runner.rb:103:in `run'
	from /data/rails/evans-2016/shared/bundle/ruby/2.3.0/gems/rspec-core-2.99.2/lib/rspec/core/runner.rb:17:in `block in autorun'

История (2 версии и 3 коментара)

Михаил обнови решението на 28.12.2016 20:44 (преди около 7 години)

+class ArnoldCPM
+ @printer = nil
+ @scopes = []
+ @builtin_variables = {i_lied: 0, no_problemo: 1}
+ @suppress_execution = false
+ @in_true_branch = false
+ @just_defined_parameter = false
+
+ class << self
+ attr_writer :printer
+
+ def totally_recall(&block)
+ instance_eval &block
+ end
+
+ private
+
+ def method_missing(method)
+ method
+ end
+
+ # main start
+ def its_showtime
+ @scopes.push Scope.new
+ end
+
+ # main end
+ def you_have_been_terminated
+ @scopes.pop
+ end
+
+ # print
+ def talk_to_the_hand(something)
+ return if handle_possible_func_def __method__, something
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ # unless @scopes.empty?
+ with_value(something) do |value|
+ @printer.print value
+ end
+ # end
+ end
+
+ # def var
+ def get_to_the_chopper(variable_name)
+ return if handle_possible_func_def __method__, variable_name
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ @init_variable = variable_name
+ end
+
+ # init value in var def
+ def here_is_my_invitation(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ with_value(value) do |value|
+ scope.variables[@init_variable] = value
+ end
+ end
+
+ # +
+ def get_up(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ apply_operator :+, value
+ end
+
+ # -
+ def get_down(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ apply_operator :-, value
+ end
+
+ # *
+ def youre_fired(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ apply_operator :*, value
+ end
+
+ # /
+ def he_had_to_split(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ apply_operator :/, value
+ end
+
+ # %
+ def i_let_him_go(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ apply_operator :%, value
+ end
+
+ # or
+ def consider_that_a_divorce(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ with_value(value) do |value|
+ current = scope.variables[@init_variable]
+ return current if current != 0
+ value
+ end
+ end
+
+ # and
+ def knock_knock(value)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ with_value(value) do |value|
+ current = scope.variables[@init_variable]
+ return current if current == 0
+ value
+ end
+ end
+
+ # end var definitian
+ def enough_talk
+ return if handle_possible_func_def __method__
+ return if @suppress_execution
+ @init_variable = nil
+ end
+
+ # if
+ def because_im_going_to_say_please(condition)
+ return if handle_possible_func_def __method__, condition
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ @scopes.push Scope.new
+ with_value(condition) do |value|
+ @in_true_branch = value != 0
+ @suppress_execution = !@in_true_branch
+ end
+ end
+
+ # else
+ def bull_shit
+ return if handle_possible_func_def __method__
+ @suppress_execution = @in_true_branch
+ end
+
+ # fi
+ def you_have_no_respect_for_logic
+ return if handle_possible_func_def __method__
+ @suppress_execution = false
+ @in_true_branch = false
+ @scopes.pop
+ end
+
+ # def func
+ def listen_to_me_very_carefully(function_name)
+ return if handle_possible_func_def __method__, function_name
+ return if @suppress_execution
+ scope.functions[function_name] = {args: [], body: []}
+ scope.defining_function = function_name
+ end
+
+ # parameter
+ def i_need_your_clothes_your_boots_and_your_motorcycle(argument_name)
+ # return if handle_possible_func_def __method__, argument_name
+ return if @suppress_execution
+ scope.functions[scope.defining_function][:args] << argument_name
+ scope.after_parameter_def = true
+ end
+
+ # return
+ def ill_be_back(value = 0)
+ return if handle_possible_func_def __method__, value
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ with_value(value) do |value|
+ value
+ end
+ end
+
+ # end function definition
+ def hasta_la_vista_baby
+ # return if handle_possible_func_def __method__
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ scope.defining_function = nil
+ end
+
+ def do_it_now(function_name, *arguments)
+ return if handle_possible_func_def __method__
+ return if @suppress_execution
+ scope.after_parameter_def = false
+ function = get_function(function_name)
+ args_to_values = Hash[function[:args].zip(arguments)]
+ @scopes.push Scope.new
+ result = execute_function function, args_to_values
+ @scopes.pop
+ scope.variables[scope.put_result_in_var] = result if scope.put_result_in_var
+ end
+
+ # marks a function that returns a result
+ def give_these_people_air
+ scope.functions[scope.defining_function][:produces_result] = true
+ end
+
+ def get_your_ass_to_mars(variable_name)
+ scope.put_result_in_var = variable_name
+ end
+
+ # non-api internal functions
+
+ def execute_function(function, parameters)
+ function[:body].each do |function_call|
+ arguments = function_call[:args].map do |a|
+ a.is_a?(Symbol) ? parameters[a] : a
+ end
+ result = send function_call[:method], *arguments
+ return result if function_call[:method] == :ill_be_back && !result.nil?
+ end
+ end
+
+ def get_var(name)
+ @scopes.reverse.each do |scope|
+ return scope.variables[name] if scope.variables.key? name
+ end
+ @builtin_variables.fetch name, nil
+ end
+
+ def get_function(name)
+ @scopes.reverse.each do |scope|
+ return scope.functions[name] if scope.functions.key? name
+ end
+ nil
+ end
+
+ def apply_operator(operator, value)
+ with_value(value) do |value|
+ new_value = scope.variables[@init_variable].send(operator, value)
+ scope.variables[@init_variable] = new_value
+ end
+ end
+
+ def with_value(value)
+ if value.is_a? Symbol
+ yield get_var(value)
+ else
+ yield value
+ end
+ end
+
+ def scope
+ @scopes.last
+ end
+
+ def handle_possible_func_def(method, *arguments)
+ if scope&.defining_function
+ scope.functions[scope.defining_function][:body] << {method: method, args: arguments}
+ end
+ scope&.defining_function
+ end
+ end
+
+ class Scope
+ attr_accessor :functions, :variables, :defining_function, :after_parameter_def,
+ :put_result_in_var
+
+ def initialize
+ @functions = {}
+ @variables = {}
+ @after_parameter_def = false
+ end
+ end
+
+ # put one general scope at the beginning
+ @scopes << Scope.new
+end

Михаил обнови решението на 29.12.2016 02:33 (преди около 7 години)

class ArnoldCPM
@printer = nil
@scopes = []
@builtin_variables = {i_lied: 0, no_problemo: 1}
@suppress_execution = false
@in_true_branch = false
- @just_defined_parameter = false
+ @func_start_end_balance = 0
class << self
attr_writer :printer
def totally_recall(&block)
instance_eval &block
end
private
def method_missing(method)
method
end
# main start
def its_showtime
@scopes.push Scope.new
end
# main end
def you_have_been_terminated
@scopes.pop
end
# print
def talk_to_the_hand(something)
return if handle_possible_func_def __method__, something
return if @suppress_execution
- scope.after_parameter_def = false
- # unless @scopes.empty?
with_value(something) do |value|
@printer.print value
end
- # end
end
# def var
def get_to_the_chopper(variable_name)
return if handle_possible_func_def __method__, variable_name
return if @suppress_execution
- scope.after_parameter_def = false
@init_variable = variable_name
end
# init value in var def
def here_is_my_invitation(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
scope.variables[@init_variable] = value
end
end
# +
def get_up(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :+, value
end
# -
def get_down(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :-, value
end
# *
def youre_fired(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :*, value
end
# /
def he_had_to_split(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :/, value
end
# %
def i_let_him_go(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
apply_operator :%, value
end
# or
def consider_that_a_divorce(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
current = scope.variables[@init_variable]
return current if current != 0
value
end
end
# and
def knock_knock(value)
return if handle_possible_func_def __method__, value
return if @suppress_execution
with_value(value) do |value|
current = scope.variables[@init_variable]
return current if current == 0
value
end
end
+ # ==
+ def you_are_not_you_you_are_me(other)
+ return if handle_possible_func_def __method__, other
+ return if @suppress_execution
+ with_value(other) do |value|
+ current = scope.variables[@init_variable]
+ current === value
+ end
+ end
+
+ # >
+ def let_off_some_steam_bennet(other)
+ return if handle_possible_func_def __method__, other
+ return if @suppress_execution
+ with_value(other) do |value|
+ current = scope.variables[@init_variable]
+ current > value
+ end
+ end
+
# end var definitian
def enough_talk
return if handle_possible_func_def __method__
return if @suppress_execution
@init_variable = nil
end
# if
def because_im_going_to_say_please(condition)
return if handle_possible_func_def __method__, condition
return if @suppress_execution
- scope.after_parameter_def = false
@scopes.push Scope.new
with_value(condition) do |value|
@in_true_branch = value != 0
@suppress_execution = !@in_true_branch
end
end
# else
def bull_shit
return if handle_possible_func_def __method__
@suppress_execution = @in_true_branch
end
# fi
def you_have_no_respect_for_logic
return if handle_possible_func_def __method__
@suppress_execution = false
@in_true_branch = false
@scopes.pop
end
# def func
def listen_to_me_very_carefully(function_name)
- return if handle_possible_func_def __method__, function_name
+ @func_start_end_balance += 1
return if @suppress_execution
- scope.functions[function_name] = {args: [], body: []}
+ return if handle_possible_func_def __method__, function_name
scope.defining_function = function_name
+ scope.functions[function_name] = {args: [], body: []}
end
# parameter
def i_need_your_clothes_your_boots_and_your_motorcycle(argument_name)
- # return if handle_possible_func_def __method__, argument_name
return if @suppress_execution
- scope.functions[scope.defining_function][:args] << argument_name
- scope.after_parameter_def = true
+ function = scope.functions[scope.defining_function]
+ res = function[:body].any? do |f|
+ f[:method] != :i_need_your_clothes_your_boots_and_your_motorcycle
+ end
+
+ if res
+ function[:body] << {method: __method__, args: [argument_name]}
+ else
+ function[:args] << argument_name
+ end
end
# return
def ill_be_back(value = 0)
return if handle_possible_func_def __method__, value
return if @suppress_execution
- scope.after_parameter_def = false
- with_value(value) do |value|
- value
- end
+ with_value(value) { |value| value }
end
# end function definition
def hasta_la_vista_baby
- # return if handle_possible_func_def __method__
+ @func_start_end_balance -= 1
return if @suppress_execution
- scope.after_parameter_def = false
- scope.defining_function = nil
+ scope.defining_function = nil if @func_start_end_balance == 0
+ return if handle_possible_func_def __method__
end
def do_it_now(function_name, *arguments)
- return if handle_possible_func_def __method__
+ return if handle_possible_func_def __method__, function_name, *arguments
return if @suppress_execution
- scope.after_parameter_def = false
function = get_function(function_name)
args_to_values = Hash[function[:args].zip(arguments)]
@scopes.push Scope.new
result = execute_function function, args_to_values
+ get_result = @scopes[-2].put_result_in_var && function[:produces_result]
+ @scopes[-2].variables[@scopes[-2].put_result_in_var] = result if get_result
+ @scopes[-2].put_result_in_var = nil
@scopes.pop
- scope.variables[scope.put_result_in_var] = result if scope.put_result_in_var
end
# marks a function that returns a result
def give_these_people_air
- scope.functions[scope.defining_function][:produces_result] = true
+ if scope.defining_function && @func_start_end_balance == 1
+ scope.functions[scope.defining_function][:produces_result] = true
+ end
+ handle_possible_func_def __method__
end
def get_your_ass_to_mars(variable_name)
+ return if handle_possible_func_def __method__, variable_name
scope.put_result_in_var = variable_name
end
# non-api internal functions
def execute_function(function, parameters)
function[:body].each do |function_call|
arguments = function_call[:args].map do |a|
- a.is_a?(Symbol) ? parameters[a] : a
+ !a.is_a?(Symbol) ? a : parameters[a] || get_var(a) || a
end
result = send function_call[:method], *arguments
return result if function_call[:method] == :ill_be_back && !result.nil?
end
+ 0
end
def get_var(name)
@scopes.reverse.each do |scope|
return scope.variables[name] if scope.variables.key? name
end
@builtin_variables.fetch name, nil
end
def get_function(name)
@scopes.reverse.each do |scope|
return scope.functions[name] if scope.functions.key? name
end
nil
end
def apply_operator(operator, value)
with_value(value) do |value|
new_value = scope.variables[@init_variable].send(operator, value)
scope.variables[@init_variable] = new_value
end
end
def with_value(value)
if value.is_a? Symbol
yield get_var(value)
else
yield value
end
end
def scope
@scopes.last
end
def handle_possible_func_def(method, *arguments)
- if scope&.defining_function
+ if scope.defining_function
scope.functions[scope.defining_function][:body] << {method: method, args: arguments}
end
- scope&.defining_function
+ scope.defining_function
end
end
class Scope
- attr_accessor :functions, :variables, :defining_function, :after_parameter_def,
- :put_result_in_var
+ attr_accessor :functions, :variables, :defining_function, :put_result_in_var
def initialize
@functions = {}
@variables = {}
- @after_parameter_def = false
end
end
# put one general scope at the beginning
@scopes << Scope.new
end

Лог от изпълнението при ръчна проверка:


.........FFF.......F..FFF..F.

Failures:

  1) ArnoldCPM supports basic recursion
     Failure/Error: expect(printer).to receive(:print).with(value_to_be_printed).ordered

       (Double "printer").print(2)
           expected: 1 time with arguments: (2)
           received: 0 times
     # ./spec.rb:878:in `block in expect_execution'

  2) ArnoldCPM can calculate fibonacci(20) recursively
     Failure/Error: talk_to_the_hand _fibonacci_20

       #<Double "printer"> received :print with unexpected arguments
         expected: (6765)
              got: (nil)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:231:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:755:in `block (3 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:714:in `block (2 levels) in <top (required)>'

  3) ArnoldCPM can use closures in very convoluted ways
     Failure/Error: expect(printer).to receive(:print).with(value_to_be_printed).ordered

       (Double "printer").print(9)
           expected: 1 time with arguments: (9)
           received: 0 times
     # ./spec.rb:878:in `block in expect_execution'

  4) ArnoldCPM has boolean arithmetic that given *or* returns truthy values if one of the operands is truthy
     Failure/Error: talk_to_the_hand _result

       (Double "printer").print(0)
           expected: 0 times with arguments: (0)
           received: 1 time with arguments: (0)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:231:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:206:in `block (4 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:192:in `block (3 levels) in <top (required)>'

  5) ArnoldCPM has boolean arithmetic that given *and* returns falsy values if either operand is falsy
     Failure/Error: talk_to_the_hand _result

       (Double "printer").print(1)
           expected: 0 times with arguments: (1)
           received: 1 time with arguments: (1)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:231:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:268:in `block (4 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:261:in `block (3 levels) in <top (required)>'

  6) ArnoldCPM has boolean arithmetic that given *and* between two truthy values returns the second one
     Failure/Error: talk_to_the_hand _result

       (Double "printer").print(11)
           expected: 0 times with arguments: (11)
           received: 1 time with arguments: (11)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:231:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:299:in `block (4 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:292:in `block (3 levels) in <top (required)>'

  7) ArnoldCPM has boolean arithmetic that has the same precedence of *or* and *and* operations
     Failure/Error: talk_to_the_hand _result

       (Double "printer").print(1)
           expected: 0 times with arguments: (1)
           received: 1 time with arguments: (1)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:231:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:317:in `block (4 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:309:in `block (3 levels) in <top (required)>'

  8) ArnoldCPM has branching mechanism that can nest if-else statements
     Failure/Error: talk_to_the_hand 44

       (Double "printer").print(44)
           expected: 0 times with arguments: (44)
           received: 1 time with arguments: (44)
     # ./solution.rb:30:in `block in talk_to_the_hand'
     # ./solution.rb:233:in `with_value'
     # ./solution.rb:29:in `talk_to_the_hand'
     # ./spec.rb:420:in `block (4 levels) in <top (required)>'
     # ./solution.rb:11:in `instance_eval'
     # ./solution.rb:11:in `totally_recall'
     # ./spec.rb:408:in `block (3 levels) in <top (required)>'

Finished in 0.02961 seconds (files took 0.11884 seconds to load)
29 examples, 8 failures

Failed examples:

rspec ./spec.rb:651 # ArnoldCPM supports basic recursion
rspec ./spec.rb:695 # ArnoldCPM can calculate fibonacci(20) recursively
rspec ./spec.rb:760 # ArnoldCPM can use closures in very convoluted ways
rspec ./spec.rb:183 # ArnoldCPM has boolean arithmetic that given *or* returns truthy values if one of the operands is truthy
rspec ./spec.rb:252 # ArnoldCPM has boolean arithmetic that given *and* returns falsy values if either operand is falsy
rspec ./spec.rb:287 # ArnoldCPM has boolean arithmetic that given *and* between two truthy values returns the second one
rspec ./spec.rb:304 # ArnoldCPM has boolean arithmetic that has the same precedence of *or* and *and* operations
rspec ./spec.rb:378 # ArnoldCPM has branching mechanism that can nest if-else statements

Като цяло си в добра насока. Няколко забележки:

  • ArnoldCPM държи контекст отвъд printer-a. Ако опитам да пусна две ArnoldC+- програми в отделни нишки например, нещата ще се омажат тотално.
  • Е ли отговорност на Scope да се грижи за defining_function и put_result_in_var?
  • Вероятно и сам си забелязал, че постоянно се повтаря
return if handle_possible_func_def __method__, something
return if @suppress_execution

Идеята на нашето решение е сравнително подобна, може да погледнеш как сме се справили с това.

Мерси за коментарите. Май въобще не ми е хрумнало за пускането на 2 програми едновременно, просто реших, че ще има само един "интерпретатор" в дадено време. За повтарящите се return-и навсякъде: опитвах да се справя с този проблем като ползвам прок, който да прави това и навсякъде да го викам, но проблема беше, че като е дефиниран извън функцията прока, return-а му не работи както очаквах. Целия код е страшно омазан. Уж почнах доста по-рано с домашното, но все не можех да го накарам да работи и накрая писах до среднощ преди крайния срок. Преработвах кода сто пъти и почти се бях отказал, когато успях да оправя сериозните проблеми, но вече нямах сили да рефакторирам. Та така...