fish.rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []