waltz_rb 0.0.1

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.
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: []