fish.rb 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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MjA2MGU2ZDJlODdkMmMyMjY4NzUxMTQ0ZGU2YzIwYTY1ODNiNzdmNg==
5
+ data.tar.gz: !binary |-
6
+ M2M3MTYyYWY0MDkyZjA4YzU1MWYwNzM3NzJiY2NmYjRlZTk2ZmQ4Nw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjFiMjE3ZGNlMGViMzRiNGZmNGY1ZWIwYmI0M2ViNjg2NGZmZjE1OWI2N2Zm
10
+ Y2Q3NjA2N2UxYmU1YTdmMmIwZDEyYzQyMTFhZGM0NjY5YTk3ZjVlYjg2MTk4
11
+ OTMzZjA0NmExY2ZjYTY4YTNlNjRiNjljZTY0OTkwMzlhNDM0Nzg=
12
+ data.tar.gz: !binary |-
13
+ YWI3NzgxYzI1Mzk4ZDhiOTBhZTI5ODFkMjNmY2Y4MThlYWQ3NDlhMGQ5NDIw
14
+ NTIzZDk2MmU1NmU4NTJlY2I5OGE1NDk1M2NlMjU3Zjc3MTdlYWM2MjQxMWI4
15
+ YzI3NDcyODNkNjcwY2VjNmMzOTA3N2M2ODg0ZGU5OGMwMjA2YmY=
@@ -0,0 +1 @@
1
+ /pkg
@@ -0,0 +1,23 @@
1
+ fish.rb
2
+ =======
3
+
4
+ A [fish](http://esolangs.org/wiki/Fish) interpreter in ruby.
5
+
6
+ There is a slew of examples in the examples directory.
7
+
8
+ Todo
9
+ ----
10
+
11
+ Things are mostly done, it needs some thorough testing
12
+
13
+
14
+ Thoughts
15
+ --------
16
+
17
+ Something that would be fun to implment is jit. While a straight
18
+ compiler would be very dificult due to reflection I don't think
19
+ jit would be to hard if implemented the way rubinius does thiers.
20
+ It would take a lot of time though, so it is doubtful it will happen.
21
+
22
+ If you have trouble with fish.rb for whatever reason just open an issue.
23
+ I love it when poeple use my software so give it a go.
@@ -0,0 +1,24 @@
1
+ # Created by GitVers - Fill the commented stuff out yourself
2
+
3
+ require 'rubygems'
4
+ require 'rubygems/package_task'
5
+
6
+ spec = Gem::Specification.new do |gem|
7
+ gem.name = File.basename(`git rev-parse --show-toplevel`).chop
8
+ gem.version = `gitver version`
9
+
10
+ gem.author = `git config --get user.name`
11
+ gem.email = `git config --get user.email`
12
+ gem.homepage = "https://github.com/zerocool/fish.rb"
13
+ gem.summary = "A fish interpreter"
14
+ gem.description = "Ruby fish interpreter for the newer multi-stack version of fish"
15
+
16
+ gem.files = `git ls-files`.split($\)
17
+
18
+ gem.bindir = "./"
19
+ gem.executables = ["fish.rb"]
20
+ end
21
+
22
+ Gem::PackageTask.new(spec) do |pkg|
23
+ pkg.gem_spec = spec
24
+ end
@@ -0,0 +1,2 @@
1
+ 0:n84*o1:nv
2
+ n:+@:o*48<
@@ -0,0 +1,2 @@
1
+ !v"hello, world"r!
2
+ >l?!;o
@@ -0,0 +1 @@
1
+ "ar00g!;oooooooooo|
data/fish.rb ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'optparse'
5
+
6
+ class CodeBox
7
+ def initialize lines
8
+ @data = {}
9
+ lines.each_with_index do |line, y_idx|
10
+ x_idx = 0
11
+ line.each_char do |c|
12
+ @data[[x_idx, y_idx]] = c
13
+ x_idx += 1
14
+ end
15
+ end
16
+
17
+ def self.[] x, y; @data[[x, y]] end
18
+ def self.at pt; self[pt[0], pt[1]] end
19
+ def self.set pt, what; @data[[pt[0], pt[1]]] = what end
20
+
21
+ def self.r pt
22
+ a = @data.select { |k, v| k[1] == pt[1] }
23
+ xs = (a.keys.collect { |k| k[0] }).sort
24
+ tmp = xs.select { |v| v > pt[0] }
25
+ pt.replace [(tmp == [] ? xs.min : tmp.min), pt[1]]
26
+ at pt
27
+ end
28
+ def self.l pt
29
+ a = @data.select { |k, v| k[1] == pt[1] }
30
+ xs = (a.keys.collect { |k| k[0] }).sort
31
+ tmp = xs.select { |v| v < pt[0] }
32
+ pt.replace [(tmp == [] ? xs.max : tmp.max), pt[1]]
33
+ at pt
34
+ end
35
+ def self.d pt
36
+ a = @data.select { |k, v| k[0] == pt[0] }
37
+ ys = (a.keys.collect { |k| k[1] }).sort
38
+ tmp = ys.select { |v| v > pt[1] }
39
+ pt.replace [pt[0], (tmp == [] ? ys.min : tmp.min)]
40
+ at pt
41
+ end
42
+ def self.u pt
43
+ a = @data.select { |k, v| k[0] == pt[0] }
44
+ ys = (a.keys.collect { |k| k[1] }).sort
45
+ tmp = ys.select { |v| v < pt[1] }
46
+ pt.replace [pt[0], (tmp == [] ? ys.max : tmp.max)]
47
+ at pt
48
+ end
49
+ end
50
+ end # class CodeBox
51
+
52
+ class Stack
53
+ attr_accessor :data
54
+ def initialize data
55
+ @data = data
56
+
57
+ def self.pop cnt
58
+ if cnt > @data.length; abort 'something smells fishy... (stack error)' end
59
+ @data.pop cnt
60
+ end
61
+
62
+ def self.safe_single_pop; @data.pop end
63
+ def self.push value; @data << value end
64
+
65
+ @reg = nil
66
+ def self.reg
67
+ if @reg.is_nil?
68
+ @reg = self.pop 1
69
+ else
70
+ self.push @reg
71
+ @reg = nil
72
+ ret
73
+ end
74
+ end
75
+ end
76
+ end # class Stack
77
+
78
+ class Interpreter
79
+ @@prng = Random.new
80
+ @@stdout = $stdout
81
+
82
+ @@mirrors = {
83
+ '_' => { 'r' => 'r', 'l' => 'l', 'u' => 'd', 'd' => 'u' },
84
+ '|' => { 'r' => 'l', 'l' => 'r', 'u' => 'u', 'd' => 'd' },
85
+ '/' => { 'r' => 'u', 'l' => 'd', 'u' => 'r', 'd' => 'l' },
86
+ '\\' => { 'r' => 'd', 'l' => 'u', 'u' => 'l', 'd' => 'r' },
87
+ '#' => { 'r' => 'l', 'l' => 'r', 'u' => 'd', 'd' => 'u' },
88
+ }
89
+
90
+ @@div_chk = lambda do |d|
91
+ abort 'something smells fishy... (division by zero)' unless d != 0
92
+ end
93
+
94
+ @@ops = {
95
+ # control flow
96
+ '>' => lambda { |pt, dir, stks, box, cntl| dir.replace 'r' },
97
+ '<' => lambda { |pt, dir, stks, box, cntl| dir.replace 'l' },
98
+ 'v' => lambda { |pt, dir, stks, box, cntl| dir.replace 'd' },
99
+ '^' => lambda { |pt, dir, stks, box, cntl| dir.replace 'u' },
100
+ 'x' => lambda { |pt, dir, stks, box, cntl| dir.replace 'rlud'[@@prng.rand 4] },
101
+ '!' => lambda { |pt, dir, stks, box, cntl| box.send dir, pt },
102
+ '?' => lambda { |pt, dir, stks, box, cntl| v = stks[-1].safe_single_pop; box.send dir, pt unless !v.nil? and v != 0 },
103
+ '.' => lambda { |pt, dir, stks, box, cntl| pt.replace stks[-1].pop 2 },
104
+ # operators
105
+ '+' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x + y },
106
+ '-' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x - y },
107
+ '*' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x * y },
108
+ ',' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; @@div_chk.call y; stks[-1].push x.to_f / y.to_f },
109
+ '%' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; @@div_chk.call y; stks[-1].push x % y },
110
+ '=' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x == y ? 1 : 0) },
111
+ ')' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x > y ? 1 : 0) },
112
+ '(' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x < y ? 1 : 0) },
113
+ # strings
114
+ '\'' => lambda { |pt, dir, stks, box, cntl| while ((a = box.send dir, pt) != '\'') do; stks[-1].push a.ord end },
115
+ '"' => lambda { |pt, dir, stks, box, cntl| while ((a = box.send dir, pt) != '"') do; stks[-1].push a.ord end },
116
+ # stack manipulation
117
+ ':' => lambda { |pt, dir, stks, box, cntl| stks[-1].push stks[-1].data[-1] },
118
+ '~' => lambda { |pt, dir, stks, box, cntl| stks[-1].pop 1 },
119
+ '$' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push y; stks[-1].push x },
120
+ '@' => lambda { |pt, dir, stks, box, cntl| x, y, z = stks[-1].pop 3; stks[-1].push z; stks[-1].push x; stks[-1].push y },
121
+ '}' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.rotate! 1 },
122
+ '{' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.rotate! -1 },
123
+ 'r' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.reverse! },
124
+ 'l' => lambda { |pt, dir, stks, box, cntl| stks[-1].push stks[-1].data.length },
125
+ '[' => lambda { |pt, dir, stks, box, cntl| stks << (Stack.new stks[-1].pop stks[-1].pop 1) },
126
+ ']' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.concat stks.pop.data },
127
+ # io
128
+ 'o' => lambda { |pt, dir, stks, box, cntl| @@stdout.write (stks[-1].pop 1)[0].round.chr },
129
+ 'n' => lambda { |pt, dir, stks, box, cntl| @@stdout.write (stks[-1].pop 1)[0].to_s },
130
+ 'i' => lambda { |pt, dir, stks, box, cntl| stks[-1].push (cntl[:ibuf].empty? ? -1 : cntl[:ibuf][0].ord); cntl[:ibuf] = cntl[:ibuf][1..-1] unless cntl[:ibuf].length < 2 },
131
+ # reflection
132
+ 'g' => lambda { |pt, dir, stks, box, cntl| stks[-1].push (box.at stks[-1].pop 2).ord },
133
+ 'p' => lambda { |pt, dir, stks, box, cntl| box.set (stks[-1].pop 2), (stks[-1].pop 1) },
134
+ # miscellaneous
135
+ '&' => lambda { |pt, dir, stks, box, cntl| stks[-1].reg },
136
+ ';' => lambda { |pt, dir, stks, box, cntl| cntl[:done] = true },
137
+ ' ' => lambda { |pt, dir, stks, box, cntl| }
138
+ }
139
+
140
+ @@mirrors.each do |k, v|
141
+ @@ops.merge! k => lambda { |pt, dir, stks, box, cntl| dir.replace v[dir] }
142
+ end
143
+
144
+ (0..9).to_a.each do |v|
145
+ @@ops.merge! v.to_s => lambda { |pt, dir, stks, box, cntl| stks[-1].push v }
146
+ end
147
+
148
+ ('a'..'f').to_a.each do |v|
149
+ @@ops.merge! v => lambda { |pt, dir, stks, box, cntl| stks[-1].push (v.ord - 0x57) }
150
+ end
151
+
152
+ def initialize lines, options
153
+ @box = CodeBox.new lines.collect { |line| line.chomp.chomp }
154
+
155
+ @pt = [0, 0]
156
+ @dir = 'r'
157
+ @stks = []
158
+ @stks << (Stack.new [])
159
+ @cntl = {
160
+ :ibuf => options[:stdin],
161
+ :done => false,
162
+ }
163
+
164
+
165
+ op = @box.at @pt
166
+ while !@cntl[:done] do
167
+ op = ' ' if op.nil?
168
+ if options[:debug] >= 3; puts op end
169
+ func = @@ops[op]
170
+ abort 'something smells fishy... (invalid instruction)' if func.nil?
171
+ func.call @pt, @dir, @stks, @box, @cntl
172
+ op = @box.send @dir, @pt
173
+ end
174
+ end
175
+ end # class Interpreter
176
+
177
+
178
+ options = {}
179
+ optparse = OptionParser.new do |opts|
180
+ opts.banner = "fish.rb <options> <files>"
181
+
182
+ opts.on '-h', '--help', 'Display help' do; puts opts; exit end
183
+ options[:debug] = 0
184
+ opts.on '-d [level]', '--debug [level]', 'Print debug messages (max of 3, defaults to 1)' do |opt|
185
+ options[:debug] = opt.to_i || options[:debug] = 1
186
+ end
187
+ options[:stdin] = ""
188
+ opts.on '-s str', '--stdin str', 'Stdin for fish script' do |opt|; options[:stdin] = opt end
189
+ opts.on '-r file', '--redir-stdout file', 'Redirect fish stdout to file' do |opt|
190
+ options[:stdout] = File.open opt, 'w'
191
+ end
192
+ end.parse!
193
+
194
+ Interpreter.new (IO.readlines ARGV.shift), options
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fish.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - ! 'floomby
8
+
9
+ '
10
+ autorequire:
11
+ bindir: ./
12
+ cert_chain: []
13
+ date: 2014-07-09 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: Ruby fish interpreter for the newer multi-stack version of fish
16
+ email: ! 'floomby@nmt.edu
17
+
18
+ '
19
+ executables:
20
+ - fish.rb
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - ./fish.rb
25
+ - .gitignore
26
+ - README.md
27
+ - Rakefile
28
+ - examples/fibonacci.fsh
29
+ - examples/hello.fsh
30
+ - examples/quine.fsh
31
+ - fish.rb
32
+ homepage: https://github.com/zerocool/fish.rb
33
+ licenses: []
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.2.2
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: A fish interpreter
55
+ test_files: []