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
@@ -0,0 +1,67 @@
|
|
1
|
+
Math = {
|
2
|
+
sin: function(x) {
|
3
|
+
return __AmberVM__.sin(x);
|
4
|
+
},
|
5
|
+
cos: function(x) {
|
6
|
+
return __AmberVM__.cos(x);
|
7
|
+
},
|
8
|
+
pow: function(x,y) {
|
9
|
+
return __AmberVM__.power(x, y);
|
10
|
+
},
|
11
|
+
abs: function(x) {
|
12
|
+
return __AmberVM__.abs(x);
|
13
|
+
},
|
14
|
+
acos: function(x) {
|
15
|
+
return __AmberVM__.acos(x);
|
16
|
+
},
|
17
|
+
asin: function(x) {
|
18
|
+
return __AmberVM__.asin(x);
|
19
|
+
},
|
20
|
+
atan: function(x) {
|
21
|
+
return __AmberVM__.atan(x);
|
22
|
+
},
|
23
|
+
atan2: function(x, y) {
|
24
|
+
return __AmberVM__.atan(x, y);
|
25
|
+
},
|
26
|
+
ceil: function(x) {
|
27
|
+
return __AmberVM__.ceil(x);
|
28
|
+
},
|
29
|
+
exp: function(x) {
|
30
|
+
return __AmberVM__.exp(x);
|
31
|
+
},
|
32
|
+
floor: function(x) {
|
33
|
+
return __AmberVM__.floor(x);
|
34
|
+
},
|
35
|
+
log: function(x) {
|
36
|
+
return __AmberVM__.log(x);
|
37
|
+
},
|
38
|
+
random: function() {
|
39
|
+
return __AmberVM__.rand();
|
40
|
+
//return 4;
|
41
|
+
},
|
42
|
+
round: function(x) {
|
43
|
+
return __AmberVM__.round(x);
|
44
|
+
},
|
45
|
+
sqrt: function(x) {
|
46
|
+
//return __AmberVM__.sqrt(x); //Do we want that or do we just use power?
|
47
|
+
return __AmberVM__.power(x, 0.5);
|
48
|
+
},
|
49
|
+
tan: function(x) {
|
50
|
+
return __AmberVM__.tan(x);
|
51
|
+
},
|
52
|
+
/*NOT IMPLEMENTED! TODO: Implement functions with a variable number of arguments, or rather how to handle them.
|
53
|
+
max: function(*x) {
|
54
|
+
return __AmberVM__.max(x);
|
55
|
+
},
|
56
|
+
min: function(*x) {
|
57
|
+
return __AmberVM__.min(x);
|
58
|
+
}*/
|
59
|
+
E: 2.7182818284590452354,
|
60
|
+
LN10: 2.302585092994046,
|
61
|
+
LN2: 0.6931471805599453,
|
62
|
+
LOG2E: 1.4426950408889634,
|
63
|
+
LOG10E: 0.4342944819032518,
|
64
|
+
PI: 3.1415926535897932,
|
65
|
+
SQRT1_2: 0.7071067811865476,
|
66
|
+
SQRT2: 1.4142135623730951
|
67
|
+
};
|
@@ -0,0 +1,56 @@
|
|
1
|
+
function Array(n) {
|
2
|
+
a = [];
|
3
|
+
if (n && (n >= 1)) {
|
4
|
+
a = a + [null];
|
5
|
+
while (n > 1) {
|
6
|
+
if ((n % 2) == 0) {
|
7
|
+
a = a + a;
|
8
|
+
n = n/2;
|
9
|
+
} else {
|
10
|
+
a = a + [null];
|
11
|
+
n--;
|
12
|
+
};
|
13
|
+
};
|
14
|
+
};
|
15
|
+
return a;
|
16
|
+
};
|
17
|
+
|
18
|
+
function print(x) {
|
19
|
+
__AmberVM__.print(x, "\n");
|
20
|
+
}
|
21
|
+
|
22
|
+
Core = {
|
23
|
+
inc: function(x) {
|
24
|
+
return __AmberVM__.add(1, x);
|
25
|
+
},
|
26
|
+
dec: function(x) {
|
27
|
+
return __AmberVM__.add(-1, x);
|
28
|
+
},
|
29
|
+
type: function(x) {
|
30
|
+
t = __AmberVM__.type(x);
|
31
|
+
if (t == "AmberVM::Classes::String")
|
32
|
+
return "string";
|
33
|
+
else if (t == "AmberVM::Classes::Number")
|
34
|
+
return "number";
|
35
|
+
else if (t == "AmberVM::Classes::Boolen")
|
36
|
+
return "boolean";
|
37
|
+
else if (t == "AmberVM::Classes::List")
|
38
|
+
return "array";
|
39
|
+
else if (t == "AmberVM::Classes::Object")
|
40
|
+
return "object";
|
41
|
+
else
|
42
|
+
return t;
|
43
|
+
},
|
44
|
+
plus: function(a,b) {
|
45
|
+
if (__AmberVM__.type(a) == "AmberVM::Classes::String" || __AmberVM__.type(b) == "AmberVM::Classes::String")
|
46
|
+
return __AmberVM__.add("", a,b);
|
47
|
+
else
|
48
|
+
return __AmberVM__.add(a,b);
|
49
|
+
}
|
50
|
+
};
|
51
|
+
|
52
|
+
Undefined = {
|
53
|
+
undefined: null
|
54
|
+
};
|
55
|
+
|
56
|
+
Null = null;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Languages
|
3
|
+
class Math
|
4
|
+
class Compiler
|
5
|
+
include AmberVM::Interpreter
|
6
|
+
FUNCTION_MAP = {
|
7
|
+
'+' => :add,
|
8
|
+
'-' => :sub,
|
9
|
+
'/' => :div,
|
10
|
+
'*' => :mul,
|
11
|
+
'^' => :power
|
12
|
+
}
|
13
|
+
def Compiler.compile tree
|
14
|
+
if tree.is_a? Array
|
15
|
+
compile(tree.first)
|
16
|
+
elsif tree.is_a? Hash
|
17
|
+
case tree[:type]
|
18
|
+
when :number
|
19
|
+
Interpreter.const(:number, tree[:number])
|
20
|
+
when :function
|
21
|
+
params = tree[:params].map {|p| compile(p)}
|
22
|
+
case tree[:op]
|
23
|
+
when '-'
|
24
|
+
CoreCall.new :neg, params
|
25
|
+
else
|
26
|
+
FunctionCall.new tree[:op], params
|
27
|
+
end
|
28
|
+
when :ident
|
29
|
+
Interpreter::Variable.new(Interpreter.const(:string, tree[:ident]))
|
30
|
+
when :op
|
31
|
+
case tree[:op]
|
32
|
+
when ';'
|
33
|
+
s = Interpreter::Sequence.new()
|
34
|
+
if (tree[:left][:type] == :op) and (tree[:left][:op] == ';')
|
35
|
+
s += compile(tree[:left])
|
36
|
+
else
|
37
|
+
s << compile(tree[:left])
|
38
|
+
end
|
39
|
+
if (tree[:right][:type] == :op) and (tree[:right][:op] == ';')
|
40
|
+
s += compile(tree[:right])
|
41
|
+
else
|
42
|
+
s << compile(tree[:right])
|
43
|
+
end
|
44
|
+
when '='
|
45
|
+
case tree[:left][:type]
|
46
|
+
when :ident
|
47
|
+
Interpreter::Assignment.new(Interpreter.const(:string, tree[:left][:ident]),compile(tree[:right]))
|
48
|
+
when :function
|
49
|
+
body = Interpreter::Sequence.new()
|
50
|
+
i = 0
|
51
|
+
tree[:left][:params].each do |p|
|
52
|
+
raise ArgumentError, "Bad ype for a function parameter: #{p[:type]} " if p[:type] != :ident
|
53
|
+
body << Interpreter::Assignment.new(Interpreter.const(:string, p[:ident]), Interpreter::Parameter.new(Interpreter.const(:number, i)))
|
54
|
+
i += 1
|
55
|
+
end
|
56
|
+
body << compile(tree[:right])
|
57
|
+
Interpreter::FunctionDefinition.new(Interpreter.const(:string, tree[:left][:op]), AmberVM::Classes::Block.new(body))
|
58
|
+
else
|
59
|
+
raise ArgumentError, "Bad name for a variable!"
|
60
|
+
end
|
61
|
+
else
|
62
|
+
CoreCall.new(FUNCTION_MAP[tree[:op]], [compile(tree[:left]),compile(tree[:right])])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
module AmberVM
|
3
|
+
module Languages
|
4
|
+
class Math
|
5
|
+
class Tokenizer
|
6
|
+
def Tokenizer.tokenize str
|
7
|
+
s = StringScanner.new str
|
8
|
+
tokens = []
|
9
|
+
state = :number
|
10
|
+
paren_deepth = 0
|
11
|
+
while not s.eos?
|
12
|
+
s.skip(/\s*/)
|
13
|
+
if state == :number
|
14
|
+
if s.scan(/[+-]+/)
|
15
|
+
t = s.matched.gsub('+','').gsub('--','')
|
16
|
+
if t == '-'
|
17
|
+
tokens << [t, :function]
|
18
|
+
end
|
19
|
+
elsif s.scan(/[_a-z][_a-z0-9]*/i)
|
20
|
+
r = s.matched
|
21
|
+
if s.scan(/\(/)
|
22
|
+
tokens << [r, :function]
|
23
|
+
if s.scan(/\)/)
|
24
|
+
tokens << [s.matched, :paren_close]
|
25
|
+
else
|
26
|
+
paren_deepth += 1
|
27
|
+
end
|
28
|
+
else
|
29
|
+
tokens << [r, :ident]
|
30
|
+
state = :opperator
|
31
|
+
end
|
32
|
+
elsif s.scan(/((\d+(\.\d+)?)|(\.\d+))(e-?\d+)?/i)
|
33
|
+
tokens << [s.matched, :number]
|
34
|
+
state = :opperator
|
35
|
+
elsif s.scan(/\(/)
|
36
|
+
paren_deepth += 1
|
37
|
+
tokens << [s.matched, :paren_open]
|
38
|
+
else
|
39
|
+
raise "Unknown literal in term at positin #{s.pos}."
|
40
|
+
end
|
41
|
+
else
|
42
|
+
if s.scan(/\)/)
|
43
|
+
paren_deepth -= 1
|
44
|
+
raise "Unmatched parenthes at #{s.pos}" if paren_deepth < 0
|
45
|
+
tokens << [s.matched, :paren_close]
|
46
|
+
elsif s.scan(/,/)
|
47
|
+
tokens << [s.matched, :function_sep]
|
48
|
+
state = :number
|
49
|
+
elsif s.scan(/[*+\/^=-]/)
|
50
|
+
tokens << [s.matched, :opperator]
|
51
|
+
state = :number
|
52
|
+
elsif s.scan(/;/)
|
53
|
+
if paren_deepth == 0
|
54
|
+
tokens << [s.matched, :opperator]
|
55
|
+
state = :number
|
56
|
+
else
|
57
|
+
raise "Expression sepperator enclosed in parenthes at #{s.pos}"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise "Unknown literal in term at positin #{s.pos}."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
tokens
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module AmberVM
|
2
|
+
module Languages
|
3
|
+
class Math
|
4
|
+
class Tree
|
5
|
+
PRIORITIES = {
|
6
|
+
';' => -100,
|
7
|
+
'=' => -50,
|
8
|
+
'(' => 0,
|
9
|
+
'+' => 10,
|
10
|
+
'-' => 10,
|
11
|
+
'*' => 20,
|
12
|
+
'/' => 20,
|
13
|
+
'^' => 30,
|
14
|
+
}
|
15
|
+
ASSOSICATIONS = {
|
16
|
+
';' => :right,
|
17
|
+
'+' => :left,
|
18
|
+
'-' => :left,
|
19
|
+
'*' => :left,
|
20
|
+
'/' => :left,
|
21
|
+
'^' => :right,
|
22
|
+
'=' => :right
|
23
|
+
}
|
24
|
+
def Tree.generate tokens
|
25
|
+
output = []
|
26
|
+
dbgoutput = []
|
27
|
+
stack = []
|
28
|
+
dbgstack = []
|
29
|
+
while not tokens.empty?
|
30
|
+
token = tokens.shift
|
31
|
+
case token[1]
|
32
|
+
when :function
|
33
|
+
fun = token[0]
|
34
|
+
stack << {:type => :function, :op => fun}
|
35
|
+
output << {:type => :function_end}
|
36
|
+
dbgoutput << ')'
|
37
|
+
dbgstack << fun
|
38
|
+
when :function_sep
|
39
|
+
while stack.last && (stack.last[:type] != :function)
|
40
|
+
output << stack.pop
|
41
|
+
dbgoutput << dbgstack.pop
|
42
|
+
end
|
43
|
+
when :paren_open
|
44
|
+
op = token[0]
|
45
|
+
stack << {:type => :op, :op => op}
|
46
|
+
dbgstack << op
|
47
|
+
when :paren_close
|
48
|
+
while stack.last && (stack.last[:op] != '(')
|
49
|
+
output << stack.pop
|
50
|
+
dbgoutput << dbgstack.pop
|
51
|
+
end
|
52
|
+
stack.pop
|
53
|
+
dbgstack.pop
|
54
|
+
when :number
|
55
|
+
output << {:type => :number, :number => token[0]}
|
56
|
+
dbgoutput << token[0]
|
57
|
+
when :ident
|
58
|
+
output << {:type => :ident, :ident => token[0]}
|
59
|
+
dbgoutput << token[0]
|
60
|
+
when :opperator
|
61
|
+
op = token[0]
|
62
|
+
ass = ASSOSICATIONS[op]
|
63
|
+
o1p = PRIORITIES[op]
|
64
|
+
while stack.last && (stack.last[:type] != :function) &&
|
65
|
+
(((ass == :left) && (o1p <= PRIORITIES[stack.last[:op]])) ||
|
66
|
+
((ass == :right) && (o1p < PRIORITIES[stack.last[:op]])))
|
67
|
+
output << stack.pop
|
68
|
+
dbgoutput << dbgstack.pop
|
69
|
+
end
|
70
|
+
stack << {:type => :op, :op => op}
|
71
|
+
dbgstack << op
|
72
|
+
else
|
73
|
+
raise "Unknown element in parser tree: #{token.inspect}"
|
74
|
+
end
|
75
|
+
p(dbgstack) if $DEBUG
|
76
|
+
p(dbgoutput) if $DEBUG
|
77
|
+
end
|
78
|
+
while not stack.empty?
|
79
|
+
output << stack.pop
|
80
|
+
end
|
81
|
+
gen_tree output
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def Tree.gen_tree data
|
86
|
+
item = data.pop
|
87
|
+
case item[:type]
|
88
|
+
when :number, :ident
|
89
|
+
item
|
90
|
+
when :op
|
91
|
+
item[:right] = gen_tree(data)
|
92
|
+
if item[:op] == ';' and data.empty?
|
93
|
+
item = item[:right]
|
94
|
+
else
|
95
|
+
item[:left] = gen_tree(data)
|
96
|
+
end
|
97
|
+
item
|
98
|
+
when :function
|
99
|
+
item[:params] = []
|
100
|
+
while data.last && data.last[:type] != :function_end
|
101
|
+
item[:params] << gen_tree(data)
|
102
|
+
end
|
103
|
+
data.pop
|
104
|
+
item
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'amber/functions/math'
|
2
|
+
module AmberVM
|
3
|
+
module Languages
|
4
|
+
# This compiler handels mathematical expressions.
|
5
|
+
#
|
6
|
+
# It is limited to smiple terms, as in for example integration of functions is not offered.
|
7
|
+
# Yet it is hopefully enough to serve most mathematical needs.
|
8
|
+
#
|
9
|
+
# Included are:
|
10
|
+
# * Opperators: +, -, *, /, ^
|
11
|
+
# * Parenthetes
|
12
|
+
# * Functions (as in proveded by the 'amber/funcions/math' library or custom loaded)
|
13
|
+
# * Currect prioriets in execution
|
14
|
+
# * Support for variables (getting and setting)
|
15
|
+
# * Multiple concatinated statemetns sepperated by ';'
|
16
|
+
# * Custom functions (as in defining as well as calling)
|
17
|
+
class Math < AmberVM::Languages::Language
|
18
|
+
register_for :math
|
19
|
+
helper :tokenizer, :tree, :compiler
|
20
|
+
|
21
|
+
def compile text
|
22
|
+
Compiler.compile(Tree.generate(Tokenizer.tokenize(text)))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# = languages.rb - Class Plugin Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Heinz N. Gies (heinz@licenser.net)
|
4
|
+
#
|
5
|
+
# This file is published under the MIT Licenser, see LICENSE for details.
|
6
|
+
require 'amber/plugin'
|
7
|
+
module AmberVM
|
8
|
+
# This module is the basic language container, classes are supposed to be
|
9
|
+
# used by this as in: AmberVM::Language[<class id>] this guarnatees that,
|
10
|
+
# in the case of overwriting a standard compilers the code still works.
|
11
|
+
#
|
12
|
+
# This are *COMPILERS* not *INTERPRETERS* they compile source code to a
|
13
|
+
# VM bytecode to be executed later
|
14
|
+
#
|
15
|
+
# Have a look at AmberVM::Interpreter for details
|
16
|
+
#
|
17
|
+
# == Example
|
18
|
+
#
|
19
|
+
# === COMPILING A MATHEMATICAL EQUILATION
|
20
|
+
#
|
21
|
+
# require 'lib/base/languages'
|
22
|
+
# code = AmberVM::Classes[:math].compile '(1 + 1) * 3^2'
|
23
|
+
module Languages
|
24
|
+
extend AmberVM::PluginHost
|
25
|
+
plugin_path File.dirname(__FILE__), 'languages'
|
26
|
+
|
27
|
+
# The Compiler class, it holds the compiler. As those grow big I suggest
|
28
|
+
# to split the actuall code into multiple fils. Have a look at the MUSHCode
|
29
|
+
# compile for an example.
|
30
|
+
class Language
|
31
|
+
extend AmberVM::Plugin
|
32
|
+
plugin_host Languages
|
33
|
+
|
34
|
+
def initialize *args
|
35
|
+
@compiler = self.class::Compiler.new(*args)
|
36
|
+
@core_libs = nil
|
37
|
+
core_libs
|
38
|
+
end
|
39
|
+
|
40
|
+
# Loads the core libaries for a language, they have to be in the directory
|
41
|
+
# amber/langauges/LANGUAGE_ID/ directory and have to be named core-* to be
|
42
|
+
# recongnized ase core libraries.
|
43
|
+
# For speed reasons the core libraries will be cahced, to force them to be
|
44
|
+
# recompiled use the force_reload parameter as true.
|
45
|
+
def core_libs force_reload=false, additional_core_libs=[]
|
46
|
+
if not @core_libs or force_reload
|
47
|
+
@core_libs = additional_core_libs
|
48
|
+
Dir[File.join(File.dirname(__FILE__), 'languages', self.class.plugin_id.to_s, 'core-*')].each do |f|
|
49
|
+
begin
|
50
|
+
@core_libs << compile(File.read(f),true)
|
51
|
+
rescue Exception => e
|
52
|
+
puts "Failed to compile core library: #{f}."
|
53
|
+
raise e
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def version
|
59
|
+
@compiler.version
|
60
|
+
end
|
61
|
+
|
62
|
+
@core_libs
|
63
|
+
end
|
64
|
+
|
65
|
+
# This method returns a environment that has the needed core libraries loaded.
|
66
|
+
#
|
67
|
+
# When your langauge uses core libraries to publish AmberVM functions to the program
|
68
|
+
# this should be used.
|
69
|
+
# The first parameter force_reload can be passed to forcefully reload the core
|
70
|
+
# libraries.
|
71
|
+
# The second parameter can be passed to add the core libraries to an existing
|
72
|
+
# environment.
|
73
|
+
def env force_reload=false, additional_core_libs=[], core_env=nil
|
74
|
+
core_env ||= default_env
|
75
|
+
core_libs(force_reload, additional_core_libs).each do |lib|
|
76
|
+
lib.execute(core_env)
|
77
|
+
end
|
78
|
+
core_env
|
79
|
+
end
|
80
|
+
|
81
|
+
def optimized_env variables={}, force_reload=false, additional_core_libs=[], core_env=nil
|
82
|
+
core_env ||= default_env
|
83
|
+
core_libs(force_reload, additional_core_libs).each do |lib|
|
84
|
+
lib.optimize(variables).execute(core_env)
|
85
|
+
end
|
86
|
+
core_env
|
87
|
+
end
|
88
|
+
|
89
|
+
def default_env
|
90
|
+
AmberVM::Interpreter.env
|
91
|
+
end
|
92
|
+
|
93
|
+
# Compiles a code with the generated compiler.
|
94
|
+
def compile code, *args
|
95
|
+
@compiler.compile code, *args
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'amber'
|
2
|
+
|
3
|
+
module AmberVM
|
4
|
+
|
5
|
+
# The Library class is made to provide library loading capabilites
|
6
|
+
# using any rVM supporte langauges and build a frontend between
|
7
|
+
# the rVM code and the Ruby code
|
8
|
+
#
|
9
|
+
# A Library can hold the content of more then one, file and the loaded
|
10
|
+
# files are not required to have the same langauge
|
11
|
+
class Library
|
12
|
+
# This maps rVM classes to usual Ruby classes so you won't need to take care of it
|
13
|
+
CLASS_MAP={
|
14
|
+
String => AmberVM::Classes::String,
|
15
|
+
Fixnum => AmberVM::Classes::Number,
|
16
|
+
Bignum => AmberVM::Classes::Number,
|
17
|
+
Float => AmberVM::Classes::Number,
|
18
|
+
FalseClass => AmberVM::Classes::Boolean,
|
19
|
+
TrueClass => AmberVM::Classes::Boolean,
|
20
|
+
Array => AmberVM::Classes::List
|
21
|
+
}
|
22
|
+
# Initializes library, if anguage and file are given, they are loaded
|
23
|
+
# Optionally a saftey object can be passed to handle securing the
|
24
|
+
# interpreted code
|
25
|
+
def initialize(language, file = nil, safety = AmberVM::Safety.new)
|
26
|
+
@lang = AmberVM::Languages[language].new
|
27
|
+
@env = AmberVM::Interpreter.env #@lang.env
|
28
|
+
@safety = safety
|
29
|
+
load_library(file) if file
|
30
|
+
end
|
31
|
+
|
32
|
+
#Loads a file into the Library, attention it is executed!
|
33
|
+
def load_library(file)
|
34
|
+
@safety.execute(@lang.compile(File.read(file)),@env)
|
35
|
+
end
|
36
|
+
|
37
|
+
def call_function(name, *args)
|
38
|
+
# First we convert the args
|
39
|
+
vmargs = args.map do |arg|
|
40
|
+
if c = CLASS_MAP[arg.class]
|
41
|
+
c.new(arg)
|
42
|
+
else
|
43
|
+
arg
|
44
|
+
end
|
45
|
+
end
|
46
|
+
n = name.to_s
|
47
|
+
if fun = @env.function(n)
|
48
|
+
fun.call(vmargs, @env)
|
49
|
+
elsif v = @env[n]
|
50
|
+
v.val
|
51
|
+
elsif n =~ /=$/
|
52
|
+
@env[n.gsub(/=$/,'')] = vmargs.first
|
53
|
+
else
|
54
|
+
raise "oops!"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# This is the most important part, so to say, the ruby magic in here
|
58
|
+
# If a unknown method is called this gets executed to try to resole it form the
|
59
|
+
# loaded libraires
|
60
|
+
#
|
61
|
+
# Priorities are:
|
62
|
+
# 1) check the functions
|
63
|
+
# 2) check if it was a variable
|
64
|
+
# 3) check if the call ended with a '=' then set it's as variable
|
65
|
+
# 4) call super
|
66
|
+
def method_missing(m, *args)
|
67
|
+
begin
|
68
|
+
call_function(m, args)
|
69
|
+
rescue Exception => e
|
70
|
+
super(m, args)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|