cambridge 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Guardfile +13 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +36 -0
- data/cambridge.gemspec +26 -0
- data/lib/cambridge.rb +19 -0
- data/lib/cambridge/environment.rb +11 -0
- data/lib/cambridge/parser/scan.rb +315 -0
- data/lib/cambridge/parser/scan.rl +58 -0
- data/lib/cambridge/scanner.rb +13 -0
- data/lib/cambridge/tokenizer.rb +19 -0
- data/lib/cambridge/tokens.rb +14 -0
- data/lib/cambridge/tokens/command.rb +24 -0
- data/lib/cambridge/tokens/number.rb +13 -0
- data/lib/cambridge/tokens/string.rb +18 -0
- data/lib/cambridge/version.rb +3 -0
- data/test/fixtures/hello.cambridge +1 -0
- data/test/fixtures/math.cambridge +1 -0
- data/test/helper.rb +11 -0
- data/test/test_cambridge.rb +27 -0
- data/test/test_scanner.rb +39 -0
- metadata +185 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'minitest' do
|
5
|
+
# with Minitest::Unit
|
6
|
+
watch(%r|^test/(.*)\/?test_(.*)\.rb|)
|
7
|
+
watch(%r|^lib/(.*)([^/]+)\.rb|) { "test" }
|
8
|
+
watch(%r|^test/helper\.rb|) { "test" }
|
9
|
+
end
|
10
|
+
|
11
|
+
guard 'ragel', :output => 'bin' do
|
12
|
+
watch(%r{^lib/cambridge/scan/(.+)\.rl$})
|
13
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Bryce Kerley
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Cambridge
|
2
|
+
|
3
|
+
A dumb stack-based language compiler. Don't use this! Ever!!!
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cambridge'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cambridge
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
Rake::TestTask.new(:test) do |test|
|
8
|
+
test.libs << 'lib' << 'test'
|
9
|
+
test.pattern = 'test/test_*.rb'
|
10
|
+
test.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
task :test => :scanner
|
16
|
+
|
17
|
+
desc 'Generate the Ragel scanner'
|
18
|
+
task :scanner => 'lib/cambridge/parser/scan.rb'
|
19
|
+
|
20
|
+
file 'lib/cambridge/parser/scan.rb' => ['lib/cambridge/parser/scan.rl'] do |t|
|
21
|
+
sh "ragel -R -F1 -o #{t.name} #{t.prerequisites.first}"
|
22
|
+
end
|
23
|
+
|
24
|
+
directory 'doc'
|
25
|
+
|
26
|
+
namespace :scanner do
|
27
|
+
desc 'Generate a PDF graph of the Ragel scanner'
|
28
|
+
task :pdf => 'doc/scan.pdf'
|
29
|
+
file 'doc/scan.pdf' => ['doc/scan.dot', 'doc'] do |t|
|
30
|
+
sh "dot -Tpdf -o #{t.name} #{t.prerequisites.first}"
|
31
|
+
end
|
32
|
+
|
33
|
+
file 'doc/scan.dot' => ['lib/cambridge/parser/scan.rl', 'doc'] do |t|
|
34
|
+
sh "ragel -Vp -o #{t.name} #{t.prerequisites.first}"
|
35
|
+
end
|
36
|
+
end
|
data/cambridge.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/cambridge/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Bryce Kerley"]
|
6
|
+
gem.email = ["bkerley@brycekerley.net"]
|
7
|
+
gem.description = %q{A stack-based language to demo}
|
8
|
+
gem.summary = %q{A stack-based language to demo}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "cambridge"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Cambridge::VERSION
|
17
|
+
gem.required_ruby_version = '~> 1.9.3'
|
18
|
+
|
19
|
+
gem.add_development_dependency 'minitest', '~> 3.0.0'
|
20
|
+
gem.add_development_dependency 'guard-minitest'
|
21
|
+
gem.add_development_dependency 'guard-ragel'
|
22
|
+
gem.add_development_dependency 'shoulda-context', '~> 1.0.0'
|
23
|
+
gem.add_development_dependency 'mocha', '~> 0.11.4'
|
24
|
+
gem.add_development_dependency 'bundler', '~> 1.1.3'
|
25
|
+
gem.add_development_dependency 'rake', '~> 0.9.2'
|
26
|
+
end
|
data/lib/cambridge.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
%w{version tokenizer tokens scanner environment}.each do |f|
|
2
|
+
require_relative File.join('cambridge', f)
|
3
|
+
end
|
4
|
+
|
5
|
+
module Cambridge
|
6
|
+
def self.run_file(filename)
|
7
|
+
contents = File.read filename
|
8
|
+
run_string contents
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.run_string(string)
|
12
|
+
Environment.new.eval compile_string(string)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.compile_string(string)
|
16
|
+
tokenizer = Cambridge::Tokenizer.new string
|
17
|
+
tokenizer.to_ruby
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
|
2
|
+
# line 1 "lib/cambridge/parser/scan.rl"
|
3
|
+
|
4
|
+
# line 29 "lib/cambridge/parser/scan.rl"
|
5
|
+
|
6
|
+
|
7
|
+
module Cambridge
|
8
|
+
module Parser
|
9
|
+
class Scan
|
10
|
+
def initialize
|
11
|
+
@tokens = []
|
12
|
+
@num_stack = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(line)
|
16
|
+
data = line.codepoints.to_a
|
17
|
+
stack = []
|
18
|
+
p = 0
|
19
|
+
ts = 0
|
20
|
+
te = 0
|
21
|
+
act = 0
|
22
|
+
eof = data.length
|
23
|
+
|
24
|
+
# line 25 "lib/cambridge/parser/scan.rb"
|
25
|
+
class << self
|
26
|
+
attr_accessor :_scanner_trans_keys
|
27
|
+
private :_scanner_trans_keys, :_scanner_trans_keys=
|
28
|
+
end
|
29
|
+
self._scanner_trans_keys = [
|
30
|
+
0, 0, 34, 122, 34, 34,
|
31
|
+
9, 122, 9, 122, 9,
|
32
|
+
34, 9, 57, 9, 122,
|
33
|
+
9, 57, 9, 122, 0
|
34
|
+
]
|
35
|
+
|
36
|
+
class << self
|
37
|
+
attr_accessor :_scanner_key_spans
|
38
|
+
private :_scanner_key_spans, :_scanner_key_spans=
|
39
|
+
end
|
40
|
+
self._scanner_key_spans = [
|
41
|
+
0, 89, 1, 114, 114, 26, 49, 114,
|
42
|
+
49, 114
|
43
|
+
]
|
44
|
+
|
45
|
+
class << self
|
46
|
+
attr_accessor :_scanner_index_offsets
|
47
|
+
private :_scanner_index_offsets, :_scanner_index_offsets=
|
48
|
+
end
|
49
|
+
self._scanner_index_offsets = [
|
50
|
+
0, 0, 90, 92, 207, 322, 349, 399,
|
51
|
+
514, 564
|
52
|
+
]
|
53
|
+
|
54
|
+
class << self
|
55
|
+
attr_accessor :_scanner_indicies
|
56
|
+
private :_scanner_indicies, :_scanner_indicies=
|
57
|
+
end
|
58
|
+
self._scanner_indicies = [
|
59
|
+
0, 1, 1, 1, 1, 1, 1, 1,
|
60
|
+
1, 1, 1, 1, 1, 1, 2, 2,
|
61
|
+
2, 2, 2, 2, 2, 2, 2, 2,
|
62
|
+
1, 1, 1, 1, 1, 1, 1, 3,
|
63
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
64
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
65
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
66
|
+
3, 1, 1, 1, 1, 1, 1, 3,
|
67
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
68
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
69
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
70
|
+
3, 1, 5, 4, 6, 6, 6, 6,
|
71
|
+
6, 4, 4, 4, 4, 4, 4, 4,
|
72
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
73
|
+
4, 4, 4, 6, 4, 7, 4, 4,
|
74
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
75
|
+
4, 4, 4, 8, 8, 8, 8, 8,
|
76
|
+
8, 8, 8, 8, 8, 4, 4, 4,
|
77
|
+
4, 4, 4, 4, 9, 9, 9, 9,
|
78
|
+
9, 9, 9, 9, 9, 9, 9, 9,
|
79
|
+
9, 9, 9, 9, 9, 9, 9, 9,
|
80
|
+
9, 9, 9, 9, 9, 9, 4, 4,
|
81
|
+
4, 4, 4, 4, 9, 9, 9, 9,
|
82
|
+
9, 9, 9, 9, 9, 9, 9, 9,
|
83
|
+
9, 9, 9, 9, 9, 9, 9, 9,
|
84
|
+
9, 9, 9, 9, 9, 9, 4, 10,
|
85
|
+
10, 10, 10, 10, 1, 1, 1, 1,
|
86
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
87
|
+
1, 1, 1, 1, 1, 1, 10, 1,
|
88
|
+
0, 1, 1, 1, 1, 1, 1, 1,
|
89
|
+
1, 1, 1, 1, 1, 1, 2, 2,
|
90
|
+
2, 2, 2, 2, 2, 2, 2, 2,
|
91
|
+
1, 1, 1, 1, 1, 1, 1, 3,
|
92
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
93
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
94
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
95
|
+
3, 1, 1, 1, 1, 1, 1, 3,
|
96
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
97
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
98
|
+
3, 3, 3, 3, 3, 3, 3, 3,
|
99
|
+
3, 1, 11, 11, 11, 11, 11, 4,
|
100
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
101
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
102
|
+
4, 11, 4, 5, 4, 12, 12, 12,
|
103
|
+
12, 12, 4, 4, 4, 4, 4, 4,
|
104
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
105
|
+
4, 4, 4, 4, 12, 4, 5, 4,
|
106
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
107
|
+
4, 4, 4, 4, 13, 13, 13, 13,
|
108
|
+
13, 13, 13, 13, 13, 13, 4, 14,
|
109
|
+
14, 14, 14, 14, 4, 4, 4, 4,
|
110
|
+
4, 4, 4, 4, 4, 4, 4, 4,
|
111
|
+
4, 4, 4, 4, 4, 4, 14, 4,
|
112
|
+
5, 4, 4, 4, 4, 4, 4, 4,
|
113
|
+
4, 4, 4, 4, 4, 4, 15, 15,
|
114
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
115
|
+
4, 4, 4, 4, 4, 4, 4, 15,
|
116
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
117
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
118
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
119
|
+
15, 4, 4, 4, 4, 4, 4, 15,
|
120
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
121
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
122
|
+
15, 15, 15, 15, 15, 15, 15, 15,
|
123
|
+
15, 4, 16, 16, 16, 16, 16, 1,
|
124
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
125
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
126
|
+
1, 16, 1, 1, 1, 1, 1, 1,
|
127
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
128
|
+
1, 17, 17, 17, 17, 17, 17, 17,
|
129
|
+
17, 17, 17, 1, 18, 18, 18, 18,
|
130
|
+
18, 1, 1, 1, 1, 1, 1, 1,
|
131
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
132
|
+
1, 1, 1, 18, 1, 1, 1, 1,
|
133
|
+
1, 1, 1, 1, 1, 1, 1, 1,
|
134
|
+
1, 1, 1, 19, 19, 19, 19, 19,
|
135
|
+
19, 19, 19, 19, 19, 1, 1, 1,
|
136
|
+
1, 1, 1, 1, 19, 19, 19, 19,
|
137
|
+
19, 19, 19, 19, 19, 19, 19, 19,
|
138
|
+
19, 19, 19, 19, 19, 19, 19, 19,
|
139
|
+
19, 19, 19, 19, 19, 19, 1, 1,
|
140
|
+
1, 1, 1, 1, 19, 19, 19, 19,
|
141
|
+
19, 19, 19, 19, 19, 19, 19, 19,
|
142
|
+
19, 19, 19, 19, 19, 19, 19, 19,
|
143
|
+
19, 19, 19, 19, 19, 19, 1, 0
|
144
|
+
]
|
145
|
+
|
146
|
+
class << self
|
147
|
+
attr_accessor :_scanner_trans_targs
|
148
|
+
private :_scanner_trans_targs, :_scanner_trans_targs=
|
149
|
+
end
|
150
|
+
self._scanner_trans_targs = [
|
151
|
+
2, 0, 8, 9, 2, 5, 3, 5,
|
152
|
+
6, 7, 4, 3, 3, 6, 3, 7,
|
153
|
+
4, 8, 4, 9
|
154
|
+
]
|
155
|
+
|
156
|
+
class << self
|
157
|
+
attr_accessor :_scanner_trans_actions
|
158
|
+
private :_scanner_trans_actions, :_scanner_trans_actions=
|
159
|
+
end
|
160
|
+
self._scanner_trans_actions = [
|
161
|
+
1, 0, 2, 3, 0, 0, 0, 1,
|
162
|
+
2, 3, 0, 4, 5, 0, 6, 0,
|
163
|
+
5, 0, 6, 0
|
164
|
+
]
|
165
|
+
|
166
|
+
class << self
|
167
|
+
attr_accessor :_scanner_eof_actions
|
168
|
+
private :_scanner_eof_actions, :_scanner_eof_actions=
|
169
|
+
end
|
170
|
+
self._scanner_eof_actions = [
|
171
|
+
0, 0, 0, 0, 0, 4, 5, 6,
|
172
|
+
5, 6
|
173
|
+
]
|
174
|
+
|
175
|
+
class << self
|
176
|
+
attr_accessor :scanner_start
|
177
|
+
end
|
178
|
+
self.scanner_start = 1;
|
179
|
+
class << self
|
180
|
+
attr_accessor :scanner_first_final
|
181
|
+
end
|
182
|
+
self.scanner_first_final = 5;
|
183
|
+
class << self
|
184
|
+
attr_accessor :scanner_error
|
185
|
+
end
|
186
|
+
self.scanner_error = 0;
|
187
|
+
|
188
|
+
class << self
|
189
|
+
attr_accessor :scanner_en_main
|
190
|
+
end
|
191
|
+
self.scanner_en_main = 1;
|
192
|
+
|
193
|
+
|
194
|
+
# line 48 "lib/cambridge/parser/scan.rl"
|
195
|
+
|
196
|
+
# line 197 "lib/cambridge/parser/scan.rb"
|
197
|
+
begin
|
198
|
+
p ||= 0
|
199
|
+
pe ||= data.length
|
200
|
+
cs = scanner_start
|
201
|
+
end
|
202
|
+
|
203
|
+
# line 49 "lib/cambridge/parser/scan.rl"
|
204
|
+
|
205
|
+
# line 206 "lib/cambridge/parser/scan.rb"
|
206
|
+
begin
|
207
|
+
testEof = false
|
208
|
+
_slen, _trans, _keys, _inds, _acts, _nacts = nil
|
209
|
+
_goto_level = 0
|
210
|
+
_resume = 10
|
211
|
+
_eof_trans = 15
|
212
|
+
_again = 20
|
213
|
+
_test_eof = 30
|
214
|
+
_out = 40
|
215
|
+
while true
|
216
|
+
if _goto_level <= 0
|
217
|
+
if p == pe
|
218
|
+
_goto_level = _test_eof
|
219
|
+
next
|
220
|
+
end
|
221
|
+
if cs == 0
|
222
|
+
_goto_level = _out
|
223
|
+
next
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if _goto_level <= _resume
|
227
|
+
_keys = cs << 1
|
228
|
+
_inds = _scanner_index_offsets[cs]
|
229
|
+
_slen = _scanner_key_spans[cs]
|
230
|
+
_trans = if ( _slen > 0 &&
|
231
|
+
_scanner_trans_keys[_keys] <= data[p].ord &&
|
232
|
+
data[p].ord <= _scanner_trans_keys[_keys + 1]
|
233
|
+
) then
|
234
|
+
_scanner_indicies[ _inds + data[p].ord - _scanner_trans_keys[_keys] ]
|
235
|
+
else
|
236
|
+
_scanner_indicies[ _inds + _slen ]
|
237
|
+
end
|
238
|
+
cs = _scanner_trans_targs[_trans]
|
239
|
+
if _scanner_trans_actions[_trans] != 0
|
240
|
+
case _scanner_trans_actions[_trans]
|
241
|
+
when 1 then
|
242
|
+
# line 4 "lib/cambridge/parser/scan.rl"
|
243
|
+
begin
|
244
|
+
@mark_str = p end
|
245
|
+
when 4 then
|
246
|
+
# line 5 "lib/cambridge/parser/scan.rl"
|
247
|
+
begin
|
248
|
+
@tokens << Tokens::String.new(data[@mark_str..p-1]) end
|
249
|
+
when 3 then
|
250
|
+
# line 7 "lib/cambridge/parser/scan.rl"
|
251
|
+
begin
|
252
|
+
@mark_cmd = p end
|
253
|
+
when 6 then
|
254
|
+
# line 8 "lib/cambridge/parser/scan.rl"
|
255
|
+
begin
|
256
|
+
@tokens << Tokens::Command.new(data[@mark_cmd..p-1]) end
|
257
|
+
when 2 then
|
258
|
+
# line 10 "lib/cambridge/parser/scan.rl"
|
259
|
+
begin
|
260
|
+
@mark_num = p end
|
261
|
+
when 5 then
|
262
|
+
# line 11 "lib/cambridge/parser/scan.rl"
|
263
|
+
begin
|
264
|
+
@tokens << Tokens::Number.new(data[@mark_num..p-1]) end
|
265
|
+
# line 266 "lib/cambridge/parser/scan.rb"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
if _goto_level <= _again
|
270
|
+
if cs == 0
|
271
|
+
_goto_level = _out
|
272
|
+
next
|
273
|
+
end
|
274
|
+
p += 1
|
275
|
+
if p != pe
|
276
|
+
_goto_level = _resume
|
277
|
+
next
|
278
|
+
end
|
279
|
+
end
|
280
|
+
if _goto_level <= _test_eof
|
281
|
+
if p == eof
|
282
|
+
case _scanner_eof_actions[cs]
|
283
|
+
when 4 then
|
284
|
+
# line 5 "lib/cambridge/parser/scan.rl"
|
285
|
+
begin
|
286
|
+
@tokens << Tokens::String.new(data[@mark_str..p-1]) end
|
287
|
+
when 6 then
|
288
|
+
# line 8 "lib/cambridge/parser/scan.rl"
|
289
|
+
begin
|
290
|
+
@tokens << Tokens::Command.new(data[@mark_cmd..p-1]) end
|
291
|
+
when 5 then
|
292
|
+
# line 11 "lib/cambridge/parser/scan.rl"
|
293
|
+
begin
|
294
|
+
@tokens << Tokens::Number.new(data[@mark_num..p-1]) end
|
295
|
+
# line 296 "lib/cambridge/parser/scan.rb"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
if _goto_level <= _out
|
301
|
+
break
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# line 50 "lib/cambridge/parser/scan.rl"
|
307
|
+
return @tokens
|
308
|
+
end
|
309
|
+
|
310
|
+
def atos(a)
|
311
|
+
a.map(&:chr).join
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
%%{
|
2
|
+
machine scanner;
|
3
|
+
|
4
|
+
action _string { @mark_str = p }
|
5
|
+
action string { @tokens << Tokens::String.new(data[@mark_str..p-1]) }
|
6
|
+
|
7
|
+
action _command { @mark_cmd = p }
|
8
|
+
action command { @tokens << Tokens::Command.new(data[@mark_cmd..p-1]) }
|
9
|
+
|
10
|
+
action _number { @mark_num = p }
|
11
|
+
action number { @tokens << Tokens::Number.new(data[@mark_num..p-1]) }
|
12
|
+
|
13
|
+
|
14
|
+
SingleCharacter = any;
|
15
|
+
|
16
|
+
StringComponent = SingleCharacter;
|
17
|
+
|
18
|
+
String = ('"' any* '"') >_string %string;
|
19
|
+
|
20
|
+
Number = (digit+) >_number %number;
|
21
|
+
|
22
|
+
Command = (alpha alnum*) >_command %command;
|
23
|
+
|
24
|
+
Token = String | Number | Command;
|
25
|
+
|
26
|
+
Program = Token (space+ Token)*;
|
27
|
+
|
28
|
+
main := Program;
|
29
|
+
}%%
|
30
|
+
|
31
|
+
module Cambridge
|
32
|
+
module Parser
|
33
|
+
class Scan
|
34
|
+
def initialize
|
35
|
+
@tokens = []
|
36
|
+
@num_stack = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse(line)
|
40
|
+
data = line.codepoints.to_a
|
41
|
+
stack = []
|
42
|
+
p = 0
|
43
|
+
ts = 0
|
44
|
+
te = 0
|
45
|
+
act = 0
|
46
|
+
eof = data.length
|
47
|
+
%% write data;
|
48
|
+
%% write init;
|
49
|
+
%% write exec;
|
50
|
+
return @tokens
|
51
|
+
end
|
52
|
+
|
53
|
+
def atos(a)
|
54
|
+
a.map(&:chr).join
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cambridge
|
2
|
+
class Tokenizer
|
3
|
+
def initialize(source)
|
4
|
+
@source = source
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_ruby
|
8
|
+
tokens.map(&:to_ruby).join("\n")
|
9
|
+
end
|
10
|
+
|
11
|
+
def tokens
|
12
|
+
@tokens ||= scanner.parse @source
|
13
|
+
end
|
14
|
+
|
15
|
+
def scanner
|
16
|
+
@scanner ||= Scanner.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Cambridge
|
2
|
+
module Tokens
|
3
|
+
class Base
|
4
|
+
def de_codepoint(array_of_codepoints)
|
5
|
+
return array_of_codepoints if array_of_codepoints.is_a? String
|
6
|
+
array_of_codepoints.map(&:chr).join
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
%w{string number command}.each do |f|
|
13
|
+
require_relative File.join('tokens', f)
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cambridge
|
2
|
+
module Tokens
|
3
|
+
class Command < Base
|
4
|
+
def initialize(name)
|
5
|
+
@name = de_codepoint name
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_ruby
|
9
|
+
case @name
|
10
|
+
when 'dump'
|
11
|
+
"puts @stack.inspect"
|
12
|
+
when 'prints'
|
13
|
+
"puts @stack.pop"
|
14
|
+
when 'printi'
|
15
|
+
"puts @stack.pop.to_s"
|
16
|
+
when 'add'
|
17
|
+
"@stack.push(@stack.pop + @stack.pop)"
|
18
|
+
when 'mult'
|
19
|
+
"@stack.push(@stack.pop * @stack.pop)"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Cambridge
|
2
|
+
module Tokens
|
3
|
+
class String < Base
|
4
|
+
def initialize(string)
|
5
|
+
@string = unquote de_codepoint string
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_ruby
|
9
|
+
"@stack.push #{@string.inspect}"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def unquote(string)
|
14
|
+
string.gsub(/^"/, '').gsub(/"$/, '')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
"Hello World" prints
|
@@ -0,0 +1 @@
|
|
1
|
+
5 6 add 4 mult printi
|
data/test/helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'shoulda-context'
|
2
|
+
require 'mocha'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
require_relative File.join('..', 'lib', 'cambridge')
|
6
|
+
|
7
|
+
class CambridgeCase < MiniTest::Unit::TestCase
|
8
|
+
include Shoulda::Context::Assertions
|
9
|
+
include Shoulda::Context::InstanceMethods
|
10
|
+
extend Shoulda::Context::ClassMethods
|
11
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestCambridge < CambridgeCase
|
4
|
+
context 'Hello World' do
|
5
|
+
setup do
|
6
|
+
@filename = File.join(File.dirname(__FILE__), 'fixtures', 'hello.cambridge')
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'print to stdout' do
|
10
|
+
$stdout.expects(:puts).with('Hello World')
|
11
|
+
|
12
|
+
Cambridge.run_file @filename
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'Math demo' do
|
17
|
+
setup do
|
18
|
+
@filename = File.join(File.dirname(__FILE__), 'fixtures', 'math.cambridge')
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'print to stdout' do
|
22
|
+
$stdout.expects(:puts).with('44')
|
23
|
+
|
24
|
+
Cambridge.run_file @filename
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestScanner < CambridgeCase
|
4
|
+
include Cambridge::Tokens
|
5
|
+
|
6
|
+
def self.should_parse(line, *sequence)
|
7
|
+
context "the line #{line.inspect}" do
|
8
|
+
setup do
|
9
|
+
@parsed = nil
|
10
|
+
@error = nil
|
11
|
+
begin
|
12
|
+
@parsed = @scanner.parse line
|
13
|
+
rescue => e
|
14
|
+
@error = e
|
15
|
+
end
|
16
|
+
end
|
17
|
+
should "parse without error" do
|
18
|
+
assert_nil @error, @error.inspect
|
19
|
+
refute_nil @parsed
|
20
|
+
end
|
21
|
+
should "parse into #{sequence.inspect}" do
|
22
|
+
assert_equal sequence.length, @parsed.length
|
23
|
+
@parsed.zip sequence do |result, klass|
|
24
|
+
assert_kind_of klass, result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'a scanner' do
|
31
|
+
setup do
|
32
|
+
@scanner = Cambridge::Scanner.new
|
33
|
+
end
|
34
|
+
|
35
|
+
should_parse '"hello"', Cambridge::Tokens::String
|
36
|
+
should_parse 'prints', Command
|
37
|
+
should_parse '"hello world"', Cambridge::Tokens::String
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cambridge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bryce Kerley
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: guard-minitest
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-ragel
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: shoulda-context
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.0.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.0.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: mocha
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.11.4
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.11.4
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: bundler
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.1.3
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.1.3
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rake
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.2
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.9.2
|
126
|
+
description: A stack-based language to demo
|
127
|
+
email:
|
128
|
+
- bkerley@brycekerley.net
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- Guardfile
|
136
|
+
- LICENSE
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- cambridge.gemspec
|
140
|
+
- lib/cambridge.rb
|
141
|
+
- lib/cambridge/environment.rb
|
142
|
+
- lib/cambridge/parser/scan.rb
|
143
|
+
- lib/cambridge/parser/scan.rl
|
144
|
+
- lib/cambridge/scanner.rb
|
145
|
+
- lib/cambridge/tokenizer.rb
|
146
|
+
- lib/cambridge/tokens.rb
|
147
|
+
- lib/cambridge/tokens/command.rb
|
148
|
+
- lib/cambridge/tokens/number.rb
|
149
|
+
- lib/cambridge/tokens/string.rb
|
150
|
+
- lib/cambridge/version.rb
|
151
|
+
- test/fixtures/hello.cambridge
|
152
|
+
- test/fixtures/math.cambridge
|
153
|
+
- test/helper.rb
|
154
|
+
- test/test_cambridge.rb
|
155
|
+
- test/test_scanner.rb
|
156
|
+
homepage: ''
|
157
|
+
licenses: []
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ~>
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: 1.9.3
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 1.8.23
|
177
|
+
signing_key:
|
178
|
+
specification_version: 3
|
179
|
+
summary: A stack-based language to demo
|
180
|
+
test_files:
|
181
|
+
- test/fixtures/hello.cambridge
|
182
|
+
- test/fixtures/math.cambridge
|
183
|
+
- test/helper.rb
|
184
|
+
- test/test_cambridge.rb
|
185
|
+
- test/test_scanner.rb
|