waltz_rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/waltz.rb +211 -0
  3. metadata +48 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: da3fe36065329e7374616b0d3492f6ededc9f35b
4
+ data.tar.gz: 7a4efb5890246e5b2b494c1b5d07db43900e24b4
5
+ SHA512:
6
+ metadata.gz: df1b60bbea9fe24b09afa2106240917876234b3f7b9b300a1fe2b0b032e8648244da1c5fceb36da3a4ba2aa2ebf2a8945b16c2d9168b0b931d94e830c5512aee
7
+ data.tar.gz: 3fb5cf5b08ad6d08b7adbeb6fb504cc73c50a61a0db671c8e4a53c120bc5a12e6bbefa9392d538d7fc97285ec73dc765bd62b26a2c91ff57670a04660b32a624
data/lib/waltz.rb ADDED
@@ -0,0 +1,211 @@
1
+ require 'readline'
2
+
3
+ class String
4
+ def remove_backslash_comments
5
+ self.gsub(/\\.*/, '')
6
+ end
7
+ end
8
+
9
+ class Waltz
10
+ attr_accessor :runtime_stack, :runtime_words,
11
+ :control_stack, :control_words,
12
+ :compiled
13
+
14
+ def initialize
15
+ @runtime_stack = []
16
+ @control_stack = []
17
+ @compiled = []
18
+
19
+ @runtime_words = {
20
+ '+' => -> {
21
+ a, b = @runtime_stack.pop(2)
22
+ @runtime_stack.push (a + b)
23
+ },
24
+
25
+ '*' => -> {
26
+ a, b = @runtime_stack.pop(2)
27
+ @runtime_stack.push (a * b)
28
+ },
29
+
30
+ '-' => -> {
31
+ a, b = @runtime_stack.pop(2)
32
+ @runtime_stack.push (a - b)
33
+ },
34
+
35
+ '/' => -> {
36
+ a, b = @runtime_stack.pop(2)
37
+ @runtime_stack.push (a / b)
38
+ },
39
+
40
+ '=' => -> {
41
+ a, b = @runtime_stack.pop(2)
42
+ @runtime_stack.push (a == b)
43
+ },
44
+
45
+ '>' => -> {
46
+ a, b = @runtime_stack.pop(2)
47
+ @runtime_stack.push (a > b)
48
+ },
49
+
50
+ '<' => -> {
51
+ a, b = @runtime_stack.pop(2)
52
+ @runtime_stack.push (a < b)
53
+ },
54
+
55
+ 'swap' => -> {
56
+ a, b = @runtime_stack.pop(2)
57
+ @runtime_stack.push b, a
58
+ },
59
+
60
+ 'dup' => -> {
61
+ @runtime_stack.push @runtime_stack.last
62
+ },
63
+
64
+ 'drop' => -> {
65
+ @runtime_stack.pop
66
+ },
67
+
68
+ 'over' => -> {
69
+ @runtime_stack.push @runtime_stack[-2]
70
+ },
71
+
72
+ '..' => -> {
73
+ puts "stack: #{@runtime_stack.inspect}"
74
+ },
75
+
76
+ '.' => -> {
77
+ p @runtime_stack.pop
78
+ }
79
+ }
80
+
81
+ @control_words = {
82
+ ':' => -> {
83
+ if @control_stack.empty?
84
+ @control_stack.push ":"
85
+ else
86
+ raise ": inside control stack: #{@control_stack}"
87
+ end
88
+ },
89
+
90
+ ';' => -> {
91
+ unless @control_stack.first == ":"
92
+ raise ": not balanced with ; in control stack: #{@control_stack}"
93
+ end
94
+
95
+ word, *body = @control_stack[1..-1]
96
+
97
+ unless word
98
+ raise "Unnamed word definition in control stack: #{@control_stack}"
99
+ end
100
+
101
+ @runtime_words[word] = body
102
+ @control_stack = []
103
+ }
104
+ }
105
+ end
106
+
107
+ def state
108
+ [@runtime_stack.dup, @control_stack.dup, @compiled.dup]
109
+ end
110
+
111
+ def load_state state
112
+ runtime_stack, control_stack, compiled = state
113
+ @runtime_stack = runtime_stack
114
+ @control_stack = control_stack
115
+ @compiled = compiled
116
+ end
117
+
118
+ def compile line
119
+ words = line.remove_backslash_comments.split
120
+
121
+ words.each do |word|
122
+ control_action = @control_words[word]
123
+ runtime_action = @runtime_words[word]
124
+
125
+ if @control_stack.first == ":"
126
+ if @control_stack.count == 1
127
+ if control_action or runtime_action
128
+ raise "#{word} is already defined."
129
+ else
130
+ @control_stack.push word # name of new word
131
+ next
132
+ end
133
+ else
134
+ current_stack = @control_stack
135
+ end
136
+ else
137
+ current_stack = @compiled
138
+ end
139
+
140
+ if control_action
141
+ control_action.call
142
+ elsif runtime_action
143
+ if runtime_action.is_a? Array
144
+ # do dynamic lookup for now
145
+ current_stack.push -> { run_word word }
146
+ else
147
+ current_stack.push runtime_action
148
+ end
149
+ else
150
+ if /(0|[1-9]\d*)\.\d+/ =~ word
151
+ current_stack.push -> { @runtime_stack.push word.to_f }
152
+ elsif /0|[1-9]\d*/ =~ word
153
+ current_stack.push -> { @runtime_stack.push word.to_i }
154
+ else
155
+ # assume word will be defined by the time it's run
156
+ current_stack.push -> { run_word word }
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def run_word word
163
+ runtime_action = @runtime_words[word]
164
+ if runtime_action.is_a? Proc
165
+ runtime_action.call
166
+ elsif runtime_action.is_a? Array
167
+ runtime_action.each { |action| action.call }
168
+ elsif runtime_action.is_a? NilClass
169
+ raise "Undefined word: #{word}"
170
+ else
171
+ raise "Unexpected runtime word type #{word}: #{word.class}"
172
+ end
173
+ end
174
+
175
+ def run
176
+ @compiled.each do |action|
177
+ action.call
178
+ end
179
+ ensure
180
+ @compiled = []
181
+ end
182
+
183
+ def compile_and_run line
184
+ compile line
185
+ if @control_stack.empty?
186
+ run
187
+ else
188
+ raise "Control stack not empty: #{@control_stack.inspect}"
189
+ end
190
+ end
191
+
192
+ def repl
193
+ prompt = 'waltz> '
194
+ while line = Readline.readline(prompt, true)
195
+ save_state = state
196
+ begin
197
+ compile line
198
+ if @control_stack.empty?
199
+ run
200
+ prompt = 'waltz> '
201
+ else
202
+ prompt = ' ... '
203
+ end
204
+ rescue => e
205
+ p e
206
+ load_state(save_state)
207
+ end
208
+ end
209
+ end
210
+ end
211
+
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: waltz_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dave Yarwood
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-11 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |2
14
+ Waltz is a portable music theory library implemented in Forth.
15
+
16
+ waltz_rb provides an implementation of a Forth interpreter that can
17
+ load the Waltz library and evaluate strings of Waltz code.
18
+ email: dave.yarwood@gmail.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - lib/waltz.rb
24
+ homepage: http://rubygems.org/gems/waltz_rb
25
+ licenses:
26
+ - Eclipse Public License
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.4.6
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Ruby runtime for the Waltz music theory DSL
48
+ test_files: []