AmberVM 0.0.19
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.
- data/README +38 -0
- data/bin/ambervm +278 -0
- data/lib/amber/acts_as_rvm_type.rb +157 -0
- data/lib/amber/classes/association.rb +36 -0
- data/lib/amber/classes/block.rb +52 -0
- data/lib/amber/classes/boolean.rb +40 -0
- data/lib/amber/classes/class.rb +50 -0
- data/lib/amber/classes/error.rb +22 -0
- data/lib/amber/classes/list.rb +96 -0
- data/lib/amber/classes/null.rb +35 -0
- data/lib/amber/classes/number.rb +95 -0
- data/lib/amber/classes/object.rb +56 -0
- data/lib/amber/classes/string.rb +79 -0
- data/lib/amber/classes.rb +113 -0
- data/lib/amber/environment.rb +251 -0
- data/lib/amber/fukubukuro/ecma_core.rb +409 -0
- data/lib/amber/fukubukuro.rb +866 -0
- data/lib/amber/functions/all.rb +3 -0
- data/lib/amber/functions/array/append.rb +50 -0
- data/lib/amber/functions/array/at.rb +50 -0
- data/lib/amber/functions/array/set_at.rb +50 -0
- data/lib/amber/functions/array.rb +30 -0
- data/lib/amber/functions/association/assoc_get.rb +55 -0
- data/lib/amber/functions/association/assoc_set.rb +56 -0
- data/lib/amber/functions/bitwise/bitwise_and.rb +41 -0
- data/lib/amber/functions/bitwise/bitwise_not.rb +41 -0
- data/lib/amber/functions/bitwise/bitwise_or.rb +41 -0
- data/lib/amber/functions/bitwise/bitwise_xor.rb +41 -0
- data/lib/amber/functions/bitwise.rb +3 -0
- data/lib/amber/functions/collection/get.rb +66 -0
- data/lib/amber/functions/collection/set.rb +67 -0
- data/lib/amber/functions/collection/size.rb +54 -0
- data/lib/amber/functions/general/cmp.rb +43 -0
- data/lib/amber/functions/general/eq.rb +45 -0
- data/lib/amber/functions/general/gt.rb +45 -0
- data/lib/amber/functions/general/gte.rb +45 -0
- data/lib/amber/functions/general/lt.rb +45 -0
- data/lib/amber/functions/general/lte.rb +45 -0
- data/lib/amber/functions/general/neq.rb +45 -0
- data/lib/amber/functions/general/type.rb +43 -0
- data/lib/amber/functions/general.rb +3 -0
- data/lib/amber/functions/io/print.rb +45 -0
- data/lib/amber/functions/io.rb +3 -0
- data/lib/amber/functions/list/align.rb +73 -0
- data/lib/amber/functions/list/join.rb +45 -0
- data/lib/amber/functions/list/map.rb +58 -0
- data/lib/amber/functions/list/split.rb +55 -0
- data/lib/amber/functions/list.rb +3 -0
- data/lib/amber/functions/logic/and.rb +55 -0
- data/lib/amber/functions/logic/not.rb +40 -0
- data/lib/amber/functions/logic/or.rb +50 -0
- data/lib/amber/functions/logic.rb +3 -0
- data/lib/amber/functions/math/abs.rb +39 -0
- data/lib/amber/functions/math/acos.rb +39 -0
- data/lib/amber/functions/math/add.rb +40 -0
- data/lib/amber/functions/math/asin.rb +39 -0
- data/lib/amber/functions/math/atan.rb +39 -0
- data/lib/amber/functions/math/ceil.rb +39 -0
- data/lib/amber/functions/math/cos.rb +39 -0
- data/lib/amber/functions/math/dec.rb +39 -0
- data/lib/amber/functions/math/div.rb +44 -0
- data/lib/amber/functions/math/exp.rb +39 -0
- data/lib/amber/functions/math/floor.rb +39 -0
- data/lib/amber/functions/math/inc.rb +39 -0
- data/lib/amber/functions/math/log.rb +39 -0
- data/lib/amber/functions/math/mod.rb +41 -0
- data/lib/amber/functions/math/mul.rb +43 -0
- data/lib/amber/functions/math/neg.rb +43 -0
- data/lib/amber/functions/math/power.rb +43 -0
- data/lib/amber/functions/math/rand.rb +36 -0
- data/lib/amber/functions/math/round.rb +39 -0
- data/lib/amber/functions/math/shl.rb +41 -0
- data/lib/amber/functions/math/shr.rb +41 -0
- data/lib/amber/functions/math/sin.rb +39 -0
- data/lib/amber/functions/math/sub.rb +43 -0
- data/lib/amber/functions/math/tan.rb +39 -0
- data/lib/amber/functions/math.rb +3 -0
- data/lib/amber/functions/objects/send.rb +22 -0
- data/lib/amber/functions/rails/print.rb +44 -0
- data/lib/amber/functions/rails.rb +3 -0
- data/lib/amber/functions/string/ansi.rb +24 -0
- data/lib/amber/functions/string/capstr.rb +23 -0
- data/lib/amber/functions/string/center.rb +25 -0
- data/lib/amber/functions/string/chr.rb +16 -0
- data/lib/amber/functions/string/ljust.rb +26 -0
- data/lib/amber/functions/string/regmatch.rb +34 -0
- data/lib/amber/functions/string/rjust.rb +26 -0
- data/lib/amber/functions/string.rb +3 -0
- data/lib/amber/functions.rb +103 -0
- data/lib/amber/interpreter.rb +1380 -0
- data/lib/amber/languages/brainfuck.rb +153 -0
- data/lib/amber/languages/ecma/compiler.rb +1661 -0
- data/lib/amber/languages/ecma/core-math.js +67 -0
- data/lib/amber/languages/ecma/core-objects.js +57 -0
- data/lib/amber/languages/ecma.rb +9 -0
- data/lib/amber/languages/ecma_fuku/compiler.rb +1622 -0
- data/lib/amber/languages/ecma_fuku/core-math.js +67 -0
- data/lib/amber/languages/ecma_fuku/core-objects.js +56 -0
- data/lib/amber/languages/ecma_fuku.rb +13 -0
- data/lib/amber/languages/math/compiler.rb +70 -0
- data/lib/amber/languages/math/tokenizer.rb +69 -0
- data/lib/amber/languages/math/tree.rb +110 -0
- data/lib/amber/languages/math.rb +26 -0
- data/lib/amber/languages.rb +99 -0
- data/lib/amber/library.rb +79 -0
- data/lib/amber/optimisation.rb +299 -0
- data/lib/amber/plugin.rb +337 -0
- data/lib/amber/rails.rb +90 -0
- data/lib/amber.rb +106 -0
- data/spec/amber/class_spec.rb +27 -0
- data/spec/amber/enviroment_spec.rb +61 -0
- data/spec/amber/function_spec.rb +25 -0
- data/spec/amber/functions/association/assoc_get_spec.rb +41 -0
- data/spec/amber/functions/association/assoc_set_spec.rb +43 -0
- data/spec/amber/functions/collection/get_spec.rb +12 -0
- data/spec/amber/functions/collection/set_spec.rb +10 -0
- data/spec/amber/functions/collection/size_spec.rb +10 -0
- data/spec/amber/functions/list/split_spec.rb +47 -0
- data/spec/amber/functions/string/ansi_spec.rb +44 -0
- data/spec/amber/functions/string/capstr_spec.rb +42 -0
- data/spec/amber/functions/string/center_spec.rb +49 -0
- data/spec/amber/functions/string/ljust_spec.rb +49 -0
- data/spec/amber/functions/string/regmatch_spec.rb +52 -0
- data/spec/amber/functions/string/rjust_spec.rb +49 -0
- data/spec/amber/interpreter/assignment_spec.rb +22 -0
- data/spec/amber/interpreter/condition_spec.rb +103 -0
- data/spec/amber/interpreter/constant_spec.rb +31 -0
- data/spec/amber/interpreter/core_call_spec.rb +72 -0
- data/spec/amber/interpreter/interpreter_spec.rb +11 -0
- data/spec/amber/interpreter/parameter_spec.rb +24 -0
- data/spec/amber/interpreter/sequence_spec.rb +47 -0
- data/spec/amber/interpreter/variable_spec.rb +24 -0
- data/spec/amber/plugin_spec.rb +10 -0
- data/spec/classes/atom/association_spec.rb +39 -0
- data/spec/classes/atom/block_spec.rb +25 -0
- data/spec/classes/atom/boolean_spec.rb +67 -0
- data/spec/classes/atom/error_spec.rb +43 -0
- data/spec/classes/atom/list_spec.rb +68 -0
- data/spec/classes/atom/number_spec.rb +132 -0
- data/spec/classes/atom/string_spec.rb +175 -0
- data/spec/languages/ecma/ecma_array_spec.rb +79 -0
- data/spec/languages/ecma/ecma_closure_spec.rb +38 -0
- data/spec/languages/ecma/ecma_literals_spec.rb +71 -0
- data/spec/languages/ecma/ecma_objects_spec.rb +165 -0
- data/spec/languages/ecma/ecma_old_spec.rb +540 -0
- data/spec/languages/ecma/ecma_spec.rb +64 -0
- data/spec/languages/ecma_fuku/ecma_array_spec.rb +61 -0
- data/spec/languages/ecma_fuku/ecma_closure_spec.rb +33 -0
- data/spec/languages/ecma_fuku/ecma_function_spec.rb +84 -0
- data/spec/languages/ecma_fuku/ecma_literals_spec.rb +55 -0
- data/spec/languages/ecma_fuku/ecma_objects_spec.rb +133 -0
- data/spec/languages/ecma_fuku/ecma_old_spec.rb +415 -0
- data/spec/languages/ecma_fuku/ecma_operator_spec.rb +33 -0
- data/spec/languages/ecma_fuku/ecma_spec.rb +52 -0
- data/spec/languages/math/compiler_spec.rb +49 -0
- data/spec/languages/math/tokenizer_spec.rb +73 -0
- data/spec/languages/math/tree_spec.rb +153 -0
- metadata +225 -0
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= rVM
|
2
|
+
|
3
|
+
rVM is the implementation of a VirtualMachine in pure Ruby. To clarify, no virtual machine as in VMWare that lets you virtualize a computer. But rather like ruby 1.9 or JRuby that both implement a virtual machine (written in C or Java) to execute Ruby code.
|
4
|
+
Just that rVM takes it the other way around, it is written in ruby and lets you execute code within ruby.
|
5
|
+
|
6
|
+
= So what is so cool about that?
|
7
|
+
|
8
|
+
For once, the challenge to pull this off ;P. Then it has on huge advantage. It makes it pretty easy to give ruby programs a interface for scripting.
|
9
|
+
|
10
|
+
Now you might think 'wow cool but I could just use ruby!' that is right, and wrong. Imagine just short code snippets to make a query, perhaps you want to implement a SQL based language to let a user query data in your program? Also consider you want your website to allow user side scripts. I would not want to have ruby code executed for random visitors. Then again I might be more tempted to let them execute code within a VM that has no access to anything outside it's VM neither variables nor hardware nor memory.
|
11
|
+
|
12
|
+
= Example
|
13
|
+
|
14
|
+
|
15
|
+
The following example implements a pretty easy calculator using the the math language shipped with rVM. Set variables and are not used outside one line
|
16
|
+
|
17
|
+
require 'rubygems'
|
18
|
+
require 'amber' # This loads the rVM gem
|
19
|
+
require 'amber/languages/math' #This loads the math plugin as well as the math function library
|
20
|
+
s =''
|
21
|
+
compiler = AmberVM::Languages[:math].new #Lets get us the compiler
|
22
|
+
while s!= 'QUIT'
|
23
|
+
s=gets.chomp
|
24
|
+
puts compiler.compile(s).execute(compiler.env) # We pass an fresh environment as we don't need an environment.
|
25
|
+
end
|
26
|
+
|
27
|
+
Here one example that keeps set variables due to using one environment for all the calls.
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'amber' # This loads the rVM gem
|
31
|
+
require 'amber/languages/math' #This loads the math plugin as well as the math function library
|
32
|
+
s =''
|
33
|
+
compiler = AmberVM::Languages[:math].new #Lets get us the compiler
|
34
|
+
env = compiler.env
|
35
|
+
while s!= 'QUIT'
|
36
|
+
s=gets.chomp
|
37
|
+
puts compiler.compile(s).execute(env) # We pass an fresh environment as we don't need an environment.
|
38
|
+
end
|
data/bin/ambervm
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << "lib"
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'pp'
|
7
|
+
require 'amber'
|
8
|
+
require 'rubygems'
|
9
|
+
|
10
|
+
|
11
|
+
rcfile = File.expand_path('~/.amberrc')
|
12
|
+
if File.exist?(rcfile)
|
13
|
+
File.new(rcfile).each do |line|
|
14
|
+
line.chomp!
|
15
|
+
ARGV << line.gsub(/\s.*$/,'')
|
16
|
+
ARGV << line.gsub(/^.*?\s/,'')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def v text
|
21
|
+
puts text if @options.verbose
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_compiler lang
|
25
|
+
begin
|
26
|
+
if require("amber/languages/#{lang}")
|
27
|
+
v "Loading Compiler: #{lang}" if @options
|
28
|
+
@compiler = AmberVM::Languages[lang].new
|
29
|
+
else
|
30
|
+
puts "ERROR: could not find compiler: #{lang}"
|
31
|
+
exit 2
|
32
|
+
end
|
33
|
+
rescue Exception => e
|
34
|
+
puts "ERROR: could not load compiler for: #{lang} #=> #{e}"
|
35
|
+
exit 3
|
36
|
+
end
|
37
|
+
@compiler
|
38
|
+
end
|
39
|
+
|
40
|
+
class AmberVMOptParser
|
41
|
+
#
|
42
|
+
# Return a structure describing the options.
|
43
|
+
#
|
44
|
+
LANGUAGES = %w[ecma ecma_fuku bf math]
|
45
|
+
LANGUAGES_ALIASES = { "js" => "ecma", "javascript" => "ecma" }
|
46
|
+
def self.parse(args)
|
47
|
+
# The options specified on the command line will be collected in *options*.
|
48
|
+
# We set default values here.
|
49
|
+
options = OpenStruct.new
|
50
|
+
options.library = []
|
51
|
+
options.amber_library = []
|
52
|
+
options.core_library = []
|
53
|
+
options.verbose = false
|
54
|
+
options.language = :ecma
|
55
|
+
options.code = nil
|
56
|
+
options.use_default_core_libs = true
|
57
|
+
options.run_as_core = false
|
58
|
+
options.only_compilation = false
|
59
|
+
|
60
|
+
|
61
|
+
o = OptionParser.new do |opts|
|
62
|
+
opts.banner = "Usage: amber [options]"
|
63
|
+
|
64
|
+
opts.separator ""
|
65
|
+
opts.separator "Specific options:"
|
66
|
+
|
67
|
+
# Mandatory argument.
|
68
|
+
opts.on("-r", "--require LIBRARY", "Require the LIBRARY before executing your script. This is for own libraries.") do |lib|
|
69
|
+
options.library << lib;
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("-i", "--amber-require AmberVM_LIBRARY", "Require the AmberVM_LIBRARY before executing your script. This is for amber internal libraries.") do |lib|
|
73
|
+
options.amber_library << "amber/#{lib}"
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on("-b", "--no-corelibs", "Used to disable standard core libraries to be imported automatically") do |b|
|
77
|
+
options.use_default_core_libs = !b
|
78
|
+
end
|
79
|
+
opts.on("-c", "--core-require CORE_LIBRARY", "Require an additional CORE_LIBRARY before executing your script. This is for libraries that allow access to AmberVM library functions.") do |lib|
|
80
|
+
options.core_library << "#{lib}"
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("-f", "--function NAMESPACE/FUNCTION", "Require the function before executing your script. This is for amber internal functions.") do |lib|
|
84
|
+
options.amber_library << "amber/functions/#{lib}"
|
85
|
+
end
|
86
|
+
|
87
|
+
language_list = (LANGUAGES_ALIASES.keys + LANGUAGES).join(',')
|
88
|
+
opts.on("-l", "--language LANGUAGE", LANGUAGES, LANGUAGES_ALIASES, "Select interpreter language", " (#{language_list})") do |language|
|
89
|
+
options.language = language
|
90
|
+
end
|
91
|
+
|
92
|
+
# Boolean switch.
|
93
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
94
|
+
options.verbose = v
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
opts.on("-d", "--[no-]debug", "Run in debug mode (attention spammy! Implies -v") do |d|
|
99
|
+
options.verbose = true if $DEBUG = options.debug = d
|
100
|
+
end
|
101
|
+
|
102
|
+
opts.on("-e", "--execute CODE", "Executes CODE directly.") do |code|
|
103
|
+
options.code = code
|
104
|
+
end
|
105
|
+
|
106
|
+
opts.on("-o", "--optimize", "Optimizes the code prior to execution") do |optimize|
|
107
|
+
options.optimize = optimize
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on_tail("-x", "--run-as-core", "Runs the code in core library mode (direct access to the rVM libraries)") do |c|
|
111
|
+
options.run_as_core = c
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.separator ""
|
115
|
+
opts.separator "Common options:"
|
116
|
+
|
117
|
+
# No argument, shows at tail. This will print an options summary.
|
118
|
+
# Try it and see!
|
119
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
120
|
+
puts opts
|
121
|
+
exit
|
122
|
+
end
|
123
|
+
|
124
|
+
opts.on("-s", "--source", "Shows the source before executing.") do
|
125
|
+
options.show_source = true
|
126
|
+
end
|
127
|
+
|
128
|
+
opts.on("-p", "--compilation", "Only show the result of the compiler without executing it.") do
|
129
|
+
options.compilation = true
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on("-n", "--dont-execute", "The code is only compiled but not executed.") do
|
133
|
+
options.dont_execute = true
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# Another typical switch to print the version.
|
138
|
+
opts.on_tail("--version", "Show version") do
|
139
|
+
print "AmberVM version: #{AmberVM::VERSION}"
|
140
|
+
if options.language
|
141
|
+
puts ", #{options.language} compiler version: #{load_compiler(options.language).version}"
|
142
|
+
else
|
143
|
+
puts "."
|
144
|
+
end
|
145
|
+
exit
|
146
|
+
end
|
147
|
+
end
|
148
|
+
o.parse!(args)
|
149
|
+
options
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
@options = AmberVMOptParser.parse(ARGV)
|
155
|
+
@compiler = nil
|
156
|
+
@optvars = {}
|
157
|
+
|
158
|
+
v "Initializing environment."
|
159
|
+
|
160
|
+
@options.amber_library.each do |lib|
|
161
|
+
v "Loading AmberVM Library: #{lib}."
|
162
|
+
unless require(lib)
|
163
|
+
puts "ERROR: could not require internal library: #{lib}"
|
164
|
+
exit 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
load_compiler @options.language
|
169
|
+
|
170
|
+
if not @options.dont_execute
|
171
|
+
|
172
|
+
if @options.use_default_core_libs
|
173
|
+
if @options.optimize
|
174
|
+
@env = @compiler.optimized_env(@optvars)
|
175
|
+
else
|
176
|
+
@env = @compiler.env()
|
177
|
+
end
|
178
|
+
else
|
179
|
+
@env = AmberVM::Interpreter.env
|
180
|
+
end
|
181
|
+
|
182
|
+
@options.core_library.each do |lib|
|
183
|
+
v "Loading core library #{lib}."
|
184
|
+
if File.exist?(lib)
|
185
|
+
|
186
|
+
begin
|
187
|
+
v "Compiling core library #{lib}."
|
188
|
+
code = @compiler.compile(File.read(lib), true)
|
189
|
+
v "Optimizing library #{lib}" if @options.optimize
|
190
|
+
code = code.optimize(@optvars) if @options.optimize
|
191
|
+
begin
|
192
|
+
v "Executing library #{lib}."
|
193
|
+
code.execute(@env)
|
194
|
+
rescue Exception => e
|
195
|
+
puts "ERROR: could not execute core library: #{lib} #=> #{e}"
|
196
|
+
exit 4
|
197
|
+
end
|
198
|
+
rescue Exception => e
|
199
|
+
puts "ERROR: could not compile core library: #{lib} #=> #{e}"
|
200
|
+
exit 5
|
201
|
+
end
|
202
|
+
else
|
203
|
+
puts "ERROR: Could not load core library: #{lib}"
|
204
|
+
exit 6
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
@options.library.each do |lib|
|
209
|
+
v "Loading library #{lib}."
|
210
|
+
if File.exist?(lib)
|
211
|
+
begin
|
212
|
+
v "Compiling library #{lib}."
|
213
|
+
code = @compiler.compile(File.read(lib))
|
214
|
+
v "Optimizing library #{lib}" if @options.optimize
|
215
|
+
code = code.optimize(@optvars) if @options.optimize
|
216
|
+
begin
|
217
|
+
v "Executing library #{lib}."
|
218
|
+
code.execute(@env)
|
219
|
+
rescue Exception => e
|
220
|
+
puts "ERROR: could not execute library: #{lib} #=> #{e}"
|
221
|
+
exit 4
|
222
|
+
end
|
223
|
+
rescue Exception => e
|
224
|
+
puts "ERROR: could not compile library: #{lib} #=> #{e}"
|
225
|
+
exit 5
|
226
|
+
end
|
227
|
+
else
|
228
|
+
puts "ERROR: Could not load library: #{lib}"
|
229
|
+
exit 6
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
if @options.code
|
235
|
+
v "Executing: #{@options.code}."
|
236
|
+
@source = @options.code
|
237
|
+
else
|
238
|
+
if file = ARGV.first
|
239
|
+
if File.exist?(file)
|
240
|
+
@source = File.read(file)
|
241
|
+
else
|
242
|
+
puts "ERROR: Could not load source file: #{file}"
|
243
|
+
exit 7
|
244
|
+
end
|
245
|
+
else
|
246
|
+
puts "No files passed."
|
247
|
+
puts `#{$0} -h`
|
248
|
+
exit 8
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
begin
|
254
|
+
if @options.show_source
|
255
|
+
puts "\n### SOURCE ###"
|
256
|
+
i = 0; puts @source.gsub(/^/) { "%3d: " % [i += 1] }
|
257
|
+
end
|
258
|
+
v "Compiling program code."
|
259
|
+
code = @compiler.compile(@source, @options.run_as_core)
|
260
|
+
v "Optimizing code" if @options.optimize
|
261
|
+
code = code.optimize(@optvars) if @options.optimize
|
262
|
+
if @options.compilation
|
263
|
+
puts "\n### COMPILAT ###"
|
264
|
+
i = 0; puts code.pretty_inspect.gsub(/^/) { "%3d: " % [i += 1] }
|
265
|
+
end
|
266
|
+
unless @options.dont_execute
|
267
|
+
begin
|
268
|
+
v "Executing program code."
|
269
|
+
p code.execute(@env)
|
270
|
+
rescue Exception => e
|
271
|
+
puts "ERROR: could not execute program code #=> #{}"
|
272
|
+
raise e
|
273
|
+
end
|
274
|
+
end
|
275
|
+
rescue Exception => e
|
276
|
+
puts "ERROR: could not compile program code #=> #{e}"
|
277
|
+
raise e
|
278
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
=begin
|
2
|
+
The MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2007 Heinz N. 'Licenser' Gies
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Ruby Mush"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
23
|
+
=end
|
24
|
+
|
25
|
+
|
26
|
+
# AmberVM::ActsAsAmberVMType is a mixin that allows to quickly publish classes and types
|
27
|
+
# to the rVM interpreter without going through the hassle of defining each
|
28
|
+
# function on it's own and publisheing every varialbe that is watned.
|
29
|
+
#
|
30
|
+
# The function to call is ActsAsAmberVMTypeMethods::acts_as_amber_type.
|
31
|
+
#
|
32
|
+
# == Example
|
33
|
+
# class Test
|
34
|
+
# # Add the readers and writers for
|
35
|
+
# attr_accessor :var
|
36
|
+
# include AmberVM::ActsAsAmberVMType
|
37
|
+
# acts_as_amber_type
|
38
|
+
# register_variable :var
|
39
|
+
# register_function :to_s
|
40
|
+
# end
|
41
|
+
module AmberVM::ActsAsAmberVMType
|
42
|
+
|
43
|
+
# Called when included, loads the class methods and the instance methods needed.
|
44
|
+
def self.included(mod)
|
45
|
+
mod.extend(AmberVM::ActsAsAmberVMType::ActsAsAmberVMTypeMethods)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
module ActsAsAmberVMTypeMethods
|
50
|
+
# This function sets up the class to be a registerd class for rVM.
|
51
|
+
# It also sets it up to allow the use of +register_variable+ and
|
52
|
+
# +register_function+.
|
53
|
+
def acts_as_amber_type
|
54
|
+
# registering as class
|
55
|
+
extend AmberVM::Plugin
|
56
|
+
plugin_host AmberVM::Classes
|
57
|
+
register_for self.class.to_s.gsub(/(\w)([A-Z])/,"\1_" + "\2".downcase).to_sym
|
58
|
+
|
59
|
+
#initializing empty functions and variables hashes
|
60
|
+
@functions = {}
|
61
|
+
@variables = {}
|
62
|
+
|
63
|
+
#including DSL functions
|
64
|
+
extend AmberVM::ActsAsAmberVMType::ActsAsAmberVMTypeInstanceMethods
|
65
|
+
|
66
|
+
#including methods in class
|
67
|
+
include AmberVM::ActsAsAmberVMType::ActsAsAmberVMTypeSingeltonMethods
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module ActsAsAmberVMTypeSingeltonMethods
|
72
|
+
# This function will set up the variables for a rVM and replaces
|
73
|
+
# the current function with a shorter and faster one.
|
74
|
+
def variables
|
75
|
+
puts self.class
|
76
|
+
@variables = {}
|
77
|
+
#gets the variables hash from the Test class and maps it to a getter/setter Class
|
78
|
+
self.class.object_variables.each do |published_as, data|
|
79
|
+
name, writable = data
|
80
|
+
@variables[published_as.to_s] = AmberVM::Interpreter::VariableStorageCallback.new(self, name, writable)
|
81
|
+
end
|
82
|
+
#redefinces the variables method to remove overhead from mapping
|
83
|
+
instance_eval do
|
84
|
+
def variables
|
85
|
+
@variables
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Return the variables hash for the firs call.
|
90
|
+
@variables
|
91
|
+
end
|
92
|
+
|
93
|
+
# This function will set up the variables for a rVM and replaces
|
94
|
+
# the current function with a shorter and faster one.
|
95
|
+
def functions
|
96
|
+
# Copy the original functions hash so that changes to the instance
|
97
|
+
# wont't carry over to to other instances.
|
98
|
+
@functions = self.class.object_functions.dup
|
99
|
+
|
100
|
+
# Redefine the function method to speed up further accesses.
|
101
|
+
instance_eval do
|
102
|
+
def functions
|
103
|
+
@functions
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return the functions hash for the first call.
|
108
|
+
@functions
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# This module hods the instance methods for classes that are supposed to
|
114
|
+
# act as a rVM type.
|
115
|
+
#
|
116
|
+
# It includes +register_variable+ and +register_function+ to help setting up
|
117
|
+
# the class quickly.
|
118
|
+
module ActsAsAmberVMTypeInstanceMethods
|
119
|
+
# This registers a variable for the rVM interface, it allows the scripts
|
120
|
+
# to read and write them. If +writable+ is set this will be a read only
|
121
|
+
# variable. It alls an be published to rVM under a different name,
|
122
|
+
# by passing +published_as+.
|
123
|
+
def register_variable name, writable = true, published_as = name
|
124
|
+
@variables[published_as.to_s] = [name.to_sym, writable]
|
125
|
+
end
|
126
|
+
|
127
|
+
# This registers a variable for the rVM interface, it allows the scripts
|
128
|
+
# to read and write them. If +writable+ is set this will be a read only
|
129
|
+
# variable. It alls an be published to rVM under a different name,
|
130
|
+
# by passing +published_as+.
|
131
|
+
def register_function name, published_as = name
|
132
|
+
@functions[published_as.to_s] = Class.new(AmberVM::Functions::Function) do @name = name; end
|
133
|
+
class << @functions[published_as.to_s]
|
134
|
+
def execute params, env
|
135
|
+
env.read_var_val(:self).send(@name, *params)
|
136
|
+
end
|
137
|
+
|
138
|
+
def signature
|
139
|
+
[:any]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the hash of variables for to be used only internally by the
|
145
|
+
# ActsAsAmberVMTypeSingeltonMethods#variables function to set up the details.
|
146
|
+
def object_variables
|
147
|
+
@variables
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns the hash of variables for to be used only internally by the
|
151
|
+
# ActsAsAmberVMTypeSingeltonMethods#variables function to set up the details.
|
152
|
+
def object_functions
|
153
|
+
@functions
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Classes
|
3
|
+
class Association < Hash
|
4
|
+
extend Plugin
|
5
|
+
plugin_host Classes
|
6
|
+
register_for :association
|
7
|
+
@@type = :association
|
8
|
+
|
9
|
+
def data_type
|
10
|
+
:list
|
11
|
+
end
|
12
|
+
|
13
|
+
def variables
|
14
|
+
@variables ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def functions
|
19
|
+
@functions ||= {
|
20
|
+
'size' => AmberVM::Functions[:size],
|
21
|
+
'length' => AmberVM::Functions[:size],
|
22
|
+
'get' => AmberVM::Functions[:assoc_get],
|
23
|
+
'set' => AmberVM::Functions[:assoc_set],
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize source= {}, sepperator = ' '
|
28
|
+
super()
|
29
|
+
if source.is_a?(::Hash) # Okay we've to hack here to get sure we get the /real/ String
|
30
|
+
self.merge! source
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Classes
|
3
|
+
class Block < AmberVM::Classes::Class
|
4
|
+
attr_accessor :code
|
5
|
+
register_for :block
|
6
|
+
def initialize code
|
7
|
+
super()
|
8
|
+
@type = :any
|
9
|
+
@code = code
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute env
|
13
|
+
end
|
14
|
+
|
15
|
+
def execargs
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
class Variable_container
|
20
|
+
def initialize parent
|
21
|
+
@parent = parent
|
22
|
+
@data = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def [] k
|
26
|
+
@data[k] || @parent[k]
|
27
|
+
end
|
28
|
+
|
29
|
+
def []= k, v
|
30
|
+
@data[k] = v
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def optimize variables = {}
|
35
|
+
#old_keys = Set.new(variables.keys)
|
36
|
+
code = @code.optimize variables
|
37
|
+
#(Set.new(variables.keys) - old_keys).each do |key|
|
38
|
+
# variables.delete(key)
|
39
|
+
#end
|
40
|
+
Block.new(code)
|
41
|
+
end
|
42
|
+
|
43
|
+
def call params, env, pos = nil
|
44
|
+
AmberVM::debug "Calling Block at #{pos}...(evn: #{env.pretty_inspect}, params: #{params})" if $DEBUG
|
45
|
+
env = AmberVM::Interpreter::Environment.new({:params => params||[]}, env)
|
46
|
+
return (catch :return do
|
47
|
+
@code.execute(env)
|
48
|
+
end).val
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Classes
|
3
|
+
class Boolean < AmberVM::Classes::Class
|
4
|
+
register_for :boolean
|
5
|
+
|
6
|
+
def data_type
|
7
|
+
:boolean
|
8
|
+
end
|
9
|
+
|
10
|
+
def hash
|
11
|
+
@value.hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def eql?(o)
|
15
|
+
if o.is_a?(AmberVM::Classes::Boolean)
|
16
|
+
o.is_true? == is_true?
|
17
|
+
else
|
18
|
+
@value == o
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize value
|
23
|
+
super()
|
24
|
+
if value
|
25
|
+
if value.respond_to? :is_true?
|
26
|
+
@value = value.is_true?
|
27
|
+
else
|
28
|
+
@value = true
|
29
|
+
end
|
30
|
+
else
|
31
|
+
@value = false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_true?
|
36
|
+
@value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Classes
|
3
|
+
class VMClass < AmberVM::Classes::Class
|
4
|
+
register_for :class
|
5
|
+
|
6
|
+
attr_reader :object_functions
|
7
|
+
attr_reader :functions
|
8
|
+
|
9
|
+
attr_reader :variables
|
10
|
+
attr_accessor :initializer
|
11
|
+
attr_accessor :parent
|
12
|
+
|
13
|
+
def data_type
|
14
|
+
:class
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(parent = nil, initialize_name = "create");
|
18
|
+
super()
|
19
|
+
@initializer = initialize_name
|
20
|
+
@functions = {}
|
21
|
+
@variables = {}
|
22
|
+
@object_functions = {}
|
23
|
+
@parent = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def obj_send(method, params, env)
|
27
|
+
if method == @initializer
|
28
|
+
instance params, env
|
29
|
+
else
|
30
|
+
m = @functions[method]
|
31
|
+
m = @parent.functions(method) if not m and @parent
|
32
|
+
raise "Unknown method #{method} for object #{self}" if not m
|
33
|
+
AmberVM::debug "Executing object method #{method}." if $DEBUG
|
34
|
+
params.unshift self
|
35
|
+
env = AmberVM::Interpreter::Environment.new({:params => params||[], :locals => @variables, :functions => @functions}, env)
|
36
|
+
m.call(params, env)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def instance params, env
|
41
|
+
o = AmberVM::Classes::Object.new self
|
42
|
+
env = AmberVM::Interpreter::Environment.new({:params => params||[], :locals => @variables, :functions => @functions}, env)
|
43
|
+
o.obj_send(@initializer, params, env) #if @object_functions[@initializer]
|
44
|
+
AmberVM::debug "Creating instance of #{self}: #{o.inspect}." if $DEBUG
|
45
|
+
o
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Classes
|
3
|
+
class Error < AmberVM::Classes::Class
|
4
|
+
register_for :error
|
5
|
+
attr_accessor :value
|
6
|
+
@@type = :error
|
7
|
+
def initialize value, text = "This is an error!"
|
8
|
+
super()
|
9
|
+
@value = value.to_i
|
10
|
+
@text = text
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_true?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"##{@value} #{@text}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|