loiol-practice 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 01f46e5cbce39ef6097dff5c1c1717f0bea03b20
4
+ data.tar.gz: 1dd1aea379c9cf7b574729f3d75163a4852f4ee3
5
+ SHA512:
6
+ metadata.gz: dfae7be278d115a826a64c76b4ef007c600246b7c7439c9ebea9993e13c22e532e3d0f21890654a1a0b9e7a3fc20b12f157278112110112bfa7424d6db65509d
7
+ data.tar.gz: 92e2be9dcc132fa044a38e755952df79bddf59cb06a78cee8b8bf58472443a9f92c4b489ce7508491f5111d6e0c5c66282abc3e2bf89dfa242e4480168c38aae
@@ -0,0 +1,7 @@
1
+ # The Practice module.
2
+ module Practice
3
+ ROOT_PATH = File.expand_path(File.dirname(__FILE__)) + '/practice/'
4
+ %w(implementation/interpreter brainfuck).each do |file|
5
+ require ROOT_PATH + file
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # The practice module.
2
+ module Practice
3
+ # The brainfuck class.
4
+ class Brainfuck
5
+ # Initialize.
6
+ def initialize(source)
7
+ @interpreter = Implementation::Interpreter.new(source)
8
+ end
9
+
10
+ # To evaluate the source code.
11
+ def evaluate(context)
12
+ @interpreter.evaluate(context)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,130 @@
1
+ # The Practice module
2
+ module Practice
3
+ # The Implementation module
4
+ module Implementation
5
+ # Brainfuck interpreter written in Ruby.
6
+ class Interpreter
7
+ # The Brainfuck command.
8
+ Command = Struct.new(:symbol)
9
+
10
+ # Increment the data pointer (to point to the next cell to the right).
11
+ @lshift = Command.new('<')
12
+ def @lshift.process(cxt, _)
13
+ cxt.cursor -= 1
14
+ raise ArgumentError.new('Subscript out of range') if cxt.cursor < 0
15
+ end
16
+
17
+ # Decrement the data pointer (to point to the next cell to the left).
18
+ @rshift = Command.new('>')
19
+ def @rshift.process(cxt, _)
20
+ cxt.cursor += 1
21
+ cxt.memory << 0 if cxt.cursor == cxt.memory.length
22
+ end
23
+
24
+ # Increment (increase by one) the byte at the data pointer.
25
+ @plus = Command.new('+')
26
+ def @plus.process(cxt, _)
27
+ value = cxt.memory[cxt.cursor] + 1
28
+ cxt.memory[cxt.cursor] = value > 255 ? 0 : value
29
+ end
30
+
31
+ # Decrement (decrease by one) the byte at the data pointer.
32
+ @minus = Command.new('-')
33
+ def @minus.process(cxt, _)
34
+ value = cxt.memory[cxt.cursor] - 1
35
+ cxt.memory[cxt.cursor] = value < 0 ? 255 : value
36
+ end
37
+
38
+ # Output the byte at the data pointer.
39
+ @dot = Command.new('.')
40
+ def @dot.process(cxt, _)
41
+ value = cxt.memory[cxt.cursor]
42
+ cxt.output(value.chr)
43
+ end
44
+
45
+ # Accept one byte of input,
46
+ # storing its value in the byte at the data pointer.
47
+ @comma = Command.new(',')
48
+ def @comma.process(cxt, _)
49
+ value = cxt.input
50
+ cxt.memory[cxt.cursor] = value.ord
51
+ end
52
+
53
+ # If the byte at the data pointer is zero,
54
+ # then instead of moving the instruction pointer
55
+ # forward to the next command,
56
+ # jump it forward to the command after the matching ] command.
57
+ @lbracket = Command.new('[')
58
+ def @lbracket.process(cxt, bracemap)
59
+ cxt.counter = bracemap[cxt.counter] if cxt.memory[cxt.cursor] == 0
60
+ end
61
+
62
+ # If the byte at the data pointer is nonzero,
63
+ # then instead of moving the instruction pointer
64
+ # forward to the next command,
65
+ # jump it back to the command after the matching [ command.
66
+ @rbracket = Command.new(']')
67
+ def @rbracket.process(cxt, bracemap)
68
+ cxt.counter = bracemap[cxt.counter] if cxt.memory[cxt.cursor] != 0
69
+ end
70
+
71
+ @symbols = %i(
72
+ lshift rshift plus minus dot comma lbracket rbracket
73
+ ).reduce({}) do |symbols, name|
74
+ command = instance_variable_get("@#{name}")
75
+ symbols[command.symbol] = command
76
+ symbols
77
+ end
78
+
79
+ # Initialize.
80
+ def initialize(source)
81
+ syms = Interpreter.symbols
82
+ tokens = source.each_char.map { |c| c }.select { |c| syms.include?(c) }
83
+ @commands = tokens.map { |c| Interpreter.command(c) }
84
+ @bracemap = parse(@commands)
85
+ end
86
+
87
+ # To evaluate the source code.
88
+ def evaluate(cxt)
89
+ while cxt.counter < @commands.length
90
+ command = @commands[cxt.counter]
91
+ command.process(cxt, @bracemap)
92
+ cxt.counter += 1
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ # Parse to brainfuck code.
99
+ def parse(commands)
100
+ bracestack, bracemap = [], {}
101
+ commands.each_with_index do |command, index|
102
+ if command.symbol == '['
103
+ bracestack << index
104
+ elsif command.symbol == ']'
105
+ message = "syntax error, unexpected ']'"
106
+ raise ArgumentError.new message if bracestack.empty?
107
+ bracepos = bracestack.pop
108
+ bracemap[bracepos] = index
109
+ bracemap[index] = bracepos
110
+ end
111
+ end
112
+
113
+ message = "syntax error, unexpected '['"
114
+ raise ArgumentError.new message unless bracestack.empty?
115
+ bracemap
116
+ end
117
+
118
+ class << self
119
+ # Get brainfuck symbols
120
+ def symbols
121
+ @symbols.keys
122
+ end
123
+
124
+ def command(c)
125
+ @symbols[c]
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,6 @@
1
+ module Practice
2
+ MAJOR = 1
3
+ MINOR = 0
4
+ PATCH = 0
5
+ VERSION = [MAJOR, MINOR, PATCH].join('.').freeze
6
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loiol-practice
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - loiol
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Brainfuck interpreter writen in Ruby
56
+ email:
57
+ - develop.loiol@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - lib/ruby/practice.rb
63
+ - lib/ruby/practice/brainfuck.rb
64
+ - lib/ruby/practice/implementation/interpreter.rb
65
+ - lib/ruby/practice/version.rb
66
+ homepage: https://github.com/loiol/practice
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib/ruby
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.0.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.5.1
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Brainfuck interpreter writen in Ruby
90
+ test_files: []