Module: Operations

Included in:
BefungeInterpreter
Defined in:
lib/operations.rb

Overview

This module is responsible for performing operations. It keeps all logic based on opertaions encapsulated. It is meant to be included with the top-level BefungeInterpreter.

Constant Summary collapse

MATH_OPS =

Bunch of Constants here. Important thing: %i() defines array of symbols while %w() defines array of strings. The Hash pattern I’ve chosen to employ here simply maps the string/symbol single character representation of the operation to it’s actual method name here. For instance: OPERATORS_MAP => :logical_not We can just #send that symbol in our #operate! method.

%i(+ - * / %)
DIRECTION_OPS =
%i(^ < > v)
DIRECTIONS =
%i(n w e s)
DIRECTIONS_MAP =
Hash[DIRECTION_OPS.zip(DIRECTIONS)]
OPERATORS =
%w(! ` ? _ | : \\ $ . , # p g & ~ @)
OPERATORS_MAP =
Hash[OPERATORS.zip([
  :logical_not, :greater_than, :rand_direction, :left_right,
  :up_down, :duplicate_stack_top, :swap_stack_top,
  :pop_and_discard, :pop_and_display_int, :pop_and_display_char,
  :trampoline, :put_call, :get_call, :get_user_input_int,
  :get_user_input_char, :end_program
]

Instance Method Summary collapse

Instance Method Details

#change_dir(op) ⇒ Object

I call this method two different ways - one with directional operational arguments < > ^ v and one with actual directions :n :e :s :w. This is the reason for the unless statement here.



53
54
55
56
# File 'lib/operations.rb', line 53

def change_dir(op)
  op = DIRECTIONS_MAP[op] unless DIRECTIONS.include?(op)
  @code_map.pointer.direction = op
end

#duplicate_stack_topObject



85
86
87
88
# File 'lib/operations.rb', line 85

def duplicate_stack_top
  @stack.push(0) and return if @stack.empty?
  @stack.push(@stack.last)
end

#end_programObject



140
141
142
# File 'lib/operations.rb', line 140

def end_program
  @computing = false
end

#get_callObject



122
123
124
125
126
# File 'lib/operations.rb', line 122

def get_call
  y = @stack.pop
  x = @stack.pop
  @stack.push(@code_map.get_operation_at(y, x).ord)
end

#get_user_input_charObject



133
134
135
136
137
138
# File 'lib/operations.rb', line 133

def get_user_input_char
  puts 'Befunge needs your input for char!'
  input = $stdin.gets.chomp
  raise 'Must be a single character' unless input.length == 1
  @stack.push(input.ord)
end

#get_user_input_intObject



128
129
130
131
# File 'lib/operations.rb', line 128

def get_user_input_int
  puts 'Befunge needs your input for int!'
  @stack.push(Integer($stdin.gets.chomp))
end

#greater_thanObject



62
63
64
65
66
# File 'lib/operations.rb', line 62

def greater_than
  a = @stack.pop
  b = @stack.pop
  b > a ? @stack.push(1) : @stack.push(0)
end

#left_rightObject



72
73
74
# File 'lib/operations.rb', line 72

def left_right
  @stack.pop == 0 ? change_dir(:e) : change_dir(:w)
end

#logical_notObject



58
59
60
# File 'lib/operations.rb', line 58

def logical_not
  @stack.pop == 0 ? @stack.push(1) : @stack.push(0)
end

#operate!(op) ⇒ Object



26
27
28
29
30
31
32
33
34
# File 'lib/operations.rb', line 26

def operate!(op)
  string_mode and return if op == '"'
  push_ascii_value(op) and return if @string_mode
  return if op == ' '
  send(op) and return if MATH_OPS.include?(op.to_sym)
  push_num(op) and return if Integer(op) rescue false
  change_dir(op.to_sym) and return if DIRECTION_OPS.include?(op.to_sym)
  send(OPERATORS_MAP[op])
end

#pop_and_discardObject



95
96
97
# File 'lib/operations.rb', line 95

def pop_and_discard
  @stack.pop
end

#pop_and_display_charObject



105
106
107
108
109
# File 'lib/operations.rb', line 105

def pop_and_display_char
  display_char = @stack.pop.chr
  @return_string << display_char
  print display_char
end

#pop_and_display_intObject



99
100
101
102
103
# File 'lib/operations.rb', line 99

def pop_and_display_int
  display_int = @stack.pop
  @return_string << display_int.to_s
  print display_int
end

#push_ascii_value(op) ⇒ Object



144
145
146
# File 'lib/operations.rb', line 144

def push_ascii_value(op)
  @stack.push(op.ord)
end

#push_num(num) ⇒ Object



46
47
48
# File 'lib/operations.rb', line 46

def push_num(num)
  @stack.push(num.to_i)
end

#put_callObject



115
116
117
118
119
120
# File 'lib/operations.rb', line 115

def put_call
  y = @stack.pop
  x = @stack.pop
  v = @stack.pop
  @code_map.set_operation(y, x, v.chr)
end

#rand_directionObject



68
69
70
# File 'lib/operations.rb', line 68

def rand_direction
  @code_map.pointer.direction = DIRECTIONS.sample
end

#string_modeObject



80
81
82
83
# File 'lib/operations.rb', line 80

def string_mode
  @string_mode = !@string_mode
  true
end

#swap_stack_topObject



90
91
92
93
# File 'lib/operations.rb', line 90

def swap_stack_top
  return if @stack.length < 2
  @stack[-1], @stack[-2] = @stack[-2], @stack[-1]
end

#trampolineObject



111
112
113
# File 'lib/operations.rb', line 111

def trampoline
  @code_map.pointer.trampoline = true
end

#up_downObject



76
77
78
# File 'lib/operations.rb', line 76

def up_down
  @stack.pop == 0 ? change_dir(:s) : change_dir(:n)
end