rprb 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Public Domain
2
+
3
+ No warranties
4
+
5
+ You know the drill
data/README ADDED
@@ -0,0 +1,53 @@
1
+ ##
2
+ ## Intro/sample script for rprb (aka Reverse Polish RuBy)
3
+ ##
4
+
5
+ { Kernel swap puts drop } :say sto
6
+ { "Enter to continue..." say gets drop } :pause sto
7
+
8
+ # basic RPN stuff
9
+ 1 1 + p
10
+ 2 * p
11
+ pause
12
+
13
+ # basic Ruby stuff
14
+ zero? p
15
+ 0 zero? p
16
+ Array.new 1 push p
17
+ clr
18
+ pause
19
+
20
+ # obviously, lines starting with # are ignored, but also..
21
+ <<proc { puts "hi!" }
22
+ call
23
+ pause
24
+
25
+ # like Lisp, we have a "read" function
26
+ "1 1 +" read p
27
+ # which is equivalent to
28
+ { 1 1 + } p
29
+ pause
30
+
31
+ # and an "eval" function to evaluate the results
32
+ eval p clr
33
+ pause
34
+
35
+ # and an "evaln" function to evaluate n times
36
+ { 1 1 + } 5 dupn 5 evaln p clr
37
+
38
+ # we have registers..
39
+ 1 :a sto p
40
+ :a rcl p
41
+
42
+ # registers store our functions
43
+ :drop rcl p
44
+ { dup2 + } :fib sto
45
+ 0 1 fib p
46
+
47
+ # exen executes multiple times
48
+ :fib 5 exen
49
+
50
+ # which is equivalent to
51
+ :fib rcl 5 evaln
52
+
53
+ # and a bunch of other stuff
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'rprb'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require_gem 'rprb'
6
+ end
7
+
8
+ dc = RpRb::DC.new
9
+ while gets
10
+ dc.eval dc.read($_.chomp)
11
+ end
12
+
13
+ # vim:ft=ruby
@@ -0,0 +1,64 @@
1
+ # This code is release by the authors into the Public Domain
2
+
3
+ # stream: expr+
4
+ # expr: block | atom | comment
5
+ # string_literal: duh
6
+ # block: { stream }
7
+ # atom: \S+ | string_literal
8
+ # comment: # anything endl
9
+ # endl: \n
10
+ #
11
+
12
+ require 'rubygems'
13
+ require 'packrat/grammar'
14
+
15
+ module RpRb
16
+ Grammar = Packrat::Grammar.new do
17
+ start_symbol :Stream
18
+
19
+ S = hidden(/\s*/)
20
+ FS = hidden(/\s\s*/)
21
+
22
+ prod :Stream, [mult(:Expression), ast(:Stream)]
23
+
24
+ prod :StringLiteral, [/"(?:[^"]|\\")*"/, lift(0)]
25
+
26
+ prod :Block, [hidden('{'), S, :Stream, S, hidden('}'), ast(:Block)]
27
+
28
+ prod :Atom, [any(:StringLiteral, /[^{} \t]+/), lift(0)]
29
+
30
+ rule :Expression, [S, any(:Block, :Atom), S, ast(:Expression)]
31
+ end
32
+
33
+ Parser = Grammar.interpreting_parser
34
+
35
+ class Reader
36
+ def read(string)
37
+ to_stream(Parser.parse_string(string))
38
+ end
39
+
40
+ include RpRb::Grammar::ASTs
41
+
42
+ def to_stream(ast)
43
+ case ast
44
+ when Stream
45
+ ast.children[0].collect { |child| to_stream(child) }
46
+ when Expression, Block
47
+ to_stream ast.children[0]
48
+ else
49
+ ast
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ if __FILE__ == $0
56
+ require 'pp'
57
+
58
+ while gets
59
+ puts "Parser output:"
60
+ pp RpRb::Parser.parse_string($_.chomp)
61
+ puts "Reader output:"
62
+ pp RpRb::Reader.new.read($_.chomp)
63
+ end
64
+ end
@@ -0,0 +1,189 @@
1
+ # This code is release by the authors into the Public Domain
2
+
3
+ module Enumerable
4
+ def collect_with_index
5
+ result = []
6
+ each_with_index { |elem, i|
7
+ result << yield(elem, i)
8
+ }
9
+ result
10
+ end
11
+ end
12
+
13
+ #class Rational
14
+ # def inspect
15
+ # to_s
16
+ # end
17
+ #end
18
+
19
+ def trythese(*procs)
20
+ if procs.length == 0
21
+ raise "Ahhg!"
22
+ else
23
+ begin
24
+ procs[0].call
25
+ rescue Exception => error
26
+ #puts "ERROR: " + error
27
+ trythese(*procs[1..-1])
28
+ end
29
+ end
30
+ end
31
+
32
+ require 'expr'
33
+
34
+ module RpRb
35
+ class DC
36
+ def initialize
37
+ @reader = Reader.new
38
+
39
+ @stack = []
40
+
41
+ @registers = {
42
+ :eval => proc { |x| eval x },
43
+ :read => proc { |x| read x },
44
+
45
+ :p => proc { ||
46
+ puts "___"
47
+ puts @stack.collect_with_index { |entry, i| "%3d: %s" % [i, entry.inspect] }.reverse.join("\n")
48
+ puts "---"
49
+ :noval
50
+ },
51
+
52
+ :pick => proc { |n| @stack[n] },
53
+ :del => proc { |n| @stack.slice!(n); :noval },
54
+ :sto => proc { |val, sym| @registers[sym] = val; :noval },
55
+ :rcl => proc { |sym| @registers[sym] },
56
+ :if => proc { |den, elz, test| if test; den; else; elz; end },
57
+ :len => proc { || @stack.length },
58
+
59
+ :push => proc { |array, elem| array.push elem; array },
60
+
61
+ :while => proc { |expr, cond| loop { eval(cond); break unless @stack.shift; eval(expr) }; :noval },
62
+ :evaln => proc { |expr, n| n.times { eval(expr) }; :noval },
63
+ :loop => proc { |expr, times| times.times { |i| @stack.unshift(i); eval(expr) }; :noval },
64
+ :each => proc { |enumerable, expr| enumerable.each { |elem| @stack.unshift(elem); eval(expr) }; :noval },
65
+
66
+ :array => proc { |length| @stack.slice!(0, length).reverse },
67
+
68
+ :regs => proc { || @registers.keys },
69
+ }
70
+
71
+
72
+ [
73
+ read('{ Array.new } :"[]" sto'),
74
+ read('0 array :control sto'),
75
+ read('{ false true 2 pick if 1 del } :not sto'),
76
+ read('{ :control rcl swap unshift :control sto } :save sto'),
77
+ read('{ :control rcl 0 slice! } :restore sto'),
78
+ read('{ 1 pick 2 del } :swap sto'),
79
+ read('{ 0 del } :drop sto'),
80
+ read('{ 0 pick } :dup sto'),
81
+ read('{ {drop} swap evaln } :dropn sto'),
82
+ read('{ 2 dropn } :drop2 sto'),
83
+ read('{ 2 dupn } :dup2 sto'),
84
+ read('{ len dropn } :clr sto'),
85
+ read('{ rcl eval } :exe sto'),
86
+ read('{ swap rcl swap evaln } :exen sto'),
87
+ read('{ 1 - } :dec sto'),
88
+ read('{ 1 + } :inc sto'),
89
+ read('{ -1 * } :neg sto'),
90
+ read('{ 1.0 swap / } :inv sto'),
91
+ read('{ restore dup save } :peek sto'),
92
+ read('{ restore drop save } :poke sto'),
93
+ read('{ save {peek 1 - pick} peek evaln restore drop } :dupn sto'),
94
+ read('0 array :nop sto'),
95
+ read('{ swap dup length save swap each restore array } :map sto'),
96
+ read('{ File swap open save peek readlines restore close drop } :slurp sto'),
97
+ read('{ slurp {chomp} map {read} map {eval} each } :load sto'),
98
+ read('{ inc dup pick swap del } :take sto'),
99
+ read('{ len {+} swap dec evaln } :sum sto'),
100
+ ].each { |stream| eval(stream) }
101
+ end
102
+
103
+ def stack
104
+ @stack.dup
105
+ end
106
+
107
+ def read(val)
108
+ @reader.read val
109
+ end
110
+
111
+ def eval(tokens)
112
+ #puts "Eval-ing #{tokens.inspect}"
113
+ tokens.each { |token|
114
+ #puts "processing token #{token.inspect}..."
115
+ result = trythese(
116
+ *[
117
+ proc { execute(token.intern) },
118
+ proc { parse_code(token) },
119
+ proc { Kernel.eval(token) },
120
+ proc { puts("Error, nothing left to do"); :noval },
121
+ ]
122
+ )
123
+
124
+ unless result == :noval
125
+ @stack.unshift result
126
+ end
127
+ }
128
+
129
+ :noval
130
+ end
131
+
132
+ def parse_code(stream)
133
+ if stream.is_a? Array
134
+ stream
135
+ else
136
+ raise "#{stream.inspect} isn't code!"
137
+ end
138
+ end
139
+
140
+ def execute(fn)
141
+ # check if /fn/ names a register
142
+ if @registers.include? fn
143
+ case @registers[fn]
144
+ when Proc, Method
145
+ values = @stack.slice!(0, @registers[fn].arity).reverse
146
+ return @registers[fn].call(*values)
147
+ else
148
+ return eval(@registers[fn])
149
+ end
150
+ end
151
+
152
+ # check if /fn/ is a valid function call for an item on the stack
153
+ @stack.each_with_index { |src, arity|
154
+ begin
155
+ if fn == :call and (src.is_a?(Proc) or src.is_a?(Method)) and (src.arity == arity or src.arity == -1)
156
+ values = @stack.slice!(0, arity + 1).reverse
157
+ return values[0].call(*values[1..-1])
158
+ elsif src.respond_to?(fn) and (src.method(fn).arity == arity or src.method(fn).arity == -1)
159
+ values = @stack.slice!(0, arity + 1).reverse
160
+ return values[0].send(fn, *values[1..-1])
161
+ end
162
+ rescue ArgumentsError
163
+ end
164
+ }
165
+
166
+ # check if /fn/ is a valid method of Kernel or Math
167
+ [Kernel, Math].each { |src|
168
+ begin
169
+ if src.respond_to? fn
170
+ values = @stack.slice!(0, src.method(fn).arity).reverse
171
+ return src.send(fn, *values)
172
+ end
173
+ rescue
174
+ end
175
+ }
176
+
177
+ raise "Couldn't execute function on stack item, DC, Kernel, or Math"
178
+ end
179
+ end
180
+ end
181
+
182
+ if __FILE__ == $0
183
+ dc = RpRb::DC.new
184
+ while gets
185
+ dc.eval dc.read($_.chomp)
186
+ end
187
+ end
188
+
189
+ # vim:ts=4:sw=4
@@ -0,0 +1,199 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ include RpRb
5
+
6
+ class DCTest < Test::Unit::TestCase
7
+ def setup
8
+ @dc = DC.new
9
+ end
10
+
11
+ def e(arg)
12
+ @dc.eval arg
13
+ end
14
+
15
+ def r(arg)
16
+ @dc.read arg
17
+ end
18
+
19
+ def re(arg)
20
+ e r(arg)
21
+ end
22
+
23
+ def s
24
+ @dc.stack
25
+ end
26
+
27
+ def test_basic_eval
28
+ re('nil nil')
29
+ assert_equal [nil, nil], s
30
+
31
+ re('clr 1 2 3')
32
+ assert_equal [3, 2, 1], s
33
+ end
34
+
35
+ def test_basic_method_calling
36
+ re('1 2 +')
37
+ assert_equal [3], s
38
+
39
+ re 'clr 1 2 3 4 4 array 5 push'
40
+ assert_equal [[1, 2, 3, 4, 5]], s
41
+ end
42
+
43
+ def test_basic_Math_method_calling
44
+ re('0 sin 0 cos')
45
+ assert_equal [1.0, 0.0], s
46
+ end
47
+
48
+ def test_proc_calling
49
+ re '"proc{|arg|1+arg}" eval 1 call'
50
+ assert_equal [2], s
51
+
52
+ re 'clr Math.method(:sin) 0 call'
53
+ assert_equal [0.0], s
54
+ end
55
+
56
+ def test_basic_dc_methods
57
+ re('0 dup')
58
+ assert_equal [0, 0], s
59
+
60
+ re('nil dup')
61
+ assert_equal [nil, nil, 0, 0], s
62
+
63
+ re('drop2 drop')
64
+ assert_equal [0], s
65
+
66
+ re('1 2')
67
+ assert_equal [2, 1, 0], s
68
+
69
+ re('drop dup2')
70
+ assert_equal [1, 0, 1, 0], s
71
+
72
+ re('drop2')
73
+ assert_equal [1, 0], s
74
+
75
+ re 'swap'
76
+ assert_equal [0, 1], s
77
+
78
+ re '1 pick'
79
+ assert_equal [1, 0, 1], s
80
+
81
+ re 'neg'
82
+ assert_equal [-1, 0, 1], s
83
+
84
+ re 'inc'
85
+ assert_equal [0, 0, 1], s
86
+
87
+ re 'dec'
88
+ assert_equal [-1, 0, 1], s
89
+
90
+ re 'len'
91
+ assert_equal [3, -1, 0, 1], s
92
+
93
+ re '[]'
94
+ assert_equal [[], 3, -1, 0, 1], s
95
+ end
96
+
97
+ def test_variables
98
+ re('0 1 :a sto')
99
+ assert_equal [0], s
100
+
101
+ re(':a rcl')
102
+ assert_equal [1, 0], s
103
+ end
104
+
105
+ def test_if
106
+ re('1 2 true if')
107
+ assert_equal [1], s
108
+
109
+ re('clr 1 2 false if')
110
+ assert_equal [2], s
111
+ end
112
+
113
+ def test_not
114
+ re 'false not'
115
+ assert_equal [true], s
116
+
117
+ re 'clr true not'
118
+ assert_equal [false], s
119
+
120
+ re 'clr nil not'
121
+ assert_equal [true], s
122
+
123
+ re 'clr 0 not'
124
+ assert_equal [false], s
125
+ end
126
+
127
+ def test_while
128
+ re '{ 1 } { len 5 == not } while'
129
+ assert_equal [1, 1, 1, 1, 1], s
130
+ end
131
+
132
+ def test_array
133
+ re '1 2 3 4 4 array'
134
+ assert_equal [[1, 2, 3, 4]], s
135
+ end
136
+
137
+ def test_evaln
138
+ re '{ 1 } 5 evaln'
139
+ assert_equal [1, 1, 1, 1, 1], s
140
+
141
+ re '3 dropn { dup2 + } 3 evaln'
142
+ assert_equal [5, 3, 2, 1, 1], s
143
+ end
144
+
145
+ def test_stored_procedures
146
+ re('{ dup2 + } :fib sto 1 1')
147
+ assert_equal [1, 1], s
148
+ re('fib fib')
149
+ assert_equal [3, 2, 1, 1], s
150
+ re(':fib rcl eval')
151
+ assert_equal [5, 3, 2, 1, 1], s
152
+ re(':fib rcl 2 evaln')
153
+ assert_equal [13, 8, 5, 3, 2, 1, 1], s
154
+ end
155
+
156
+ def test_save_restore
157
+ re '1 save 2 save restore save :control rcl'
158
+ assert_equal [[2, 1]], s
159
+
160
+ re('clr Array.new :control sto 1 save :control rcl')
161
+ assert_equal [[1]], s
162
+
163
+ re 'clr restore'
164
+ assert_equal [1], s
165
+
166
+ re 'clr :control rcl'
167
+ assert_equal [[]], s
168
+ end
169
+
170
+ def test_each
171
+ re '1 2 3 4 5 5 array { 2 * } each'
172
+ assert_equal [10, 8, 6, 4, 2], s
173
+ end
174
+
175
+ def test_map
176
+ re('1 2 3 4 5 5 array { 2 * } map')
177
+ assert_equal [[2, 4, 6, 8, 10]], s
178
+
179
+ re 'clr 1 2 3 4 5 5 array { neg } map'
180
+ assert_equal [[-1, -2, -3, -4, -5]], s
181
+ end
182
+
183
+ def test_load
184
+ require 'tempfile'
185
+ thefile = nil
186
+ Tempfile.open("tc_evaluator") { |file|
187
+ thefile = file
188
+ file.write <<-END
189
+ { dup2 + } :fib sto
190
+ { 1 1 } :blah sto
191
+ END
192
+ }
193
+
194
+ re %Q{"#{thefile.path}" load}
195
+ re 'blah :fib 3 exen'
196
+ assert_equal [5, 3, 2, 1, 1], s
197
+ thefile.delete
198
+ end
199
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ class MiscTest < Test::Unit::TestCase
5
+ def test_collect_with_index
6
+ assert_equal [0, 1, 2, 3], [1, 2, 3, 4].collect_with_index { |a, i| i }
7
+ end
8
+ end
@@ -0,0 +1,27 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ include RpRb
5
+
6
+ class ReaderTest < Test::Unit::TestCase
7
+ def setup
8
+ @reader = Reader.new
9
+ end
10
+
11
+ def r(arg)
12
+ @reader.read arg
13
+ end
14
+
15
+ def test_read
16
+ assert_equal ['1'], @reader.read("1")
17
+ assert_equal [['1']], @reader.read("{ 1 }")
18
+ assert_equal [['1']], @reader.read("{1}")
19
+
20
+ assert_equal ['1', ['1']], @reader.read('1 {1}')
21
+
22
+ assert_equal [[]], @reader.read('{ }')
23
+
24
+ assert_equal ['"1 2 3"'], r('"1 2 3"')
25
+ assert_equal ['"proc {}"'], r('"proc {}"')
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) << File.join(File.dirname(__FILE__), '../lib')
2
+
3
+ require 'tc_misc'
4
+ require 'tc_reader'
5
+ require 'tc_evaluator'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rprb
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Jimmy Thrasher and Justin Dubs
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2006-10-11 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rockit
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 0
31
+ - 7
32
+ - 2
33
+ version: 0.7.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description:
37
+ email:
38
+ executables:
39
+ - rprb
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/rprb.rb
46
+ - lib/expr.rb
47
+ - bin/rprb
48
+ - test/ts_all.rb
49
+ - test/tc_evaluator.rb
50
+ - test/tc_reader.rb
51
+ - test/tc_misc.rb
52
+ - README
53
+ - LICENSE
54
+ has_rdoc: true
55
+ homepage:
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Provides Ruby in RPN style, ostensibly for a dc replacement
88
+ test_files:
89
+ - test/ts_all.rb
90
+ - test/tc_evaluator.rb
91
+ - test/tc_reader.rb
92
+ - test/tc_misc.rb