AmberVM 0.0.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|