AmberVM 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/README +38 -0
  2. data/bin/ambervm +278 -0
  3. data/lib/amber/acts_as_rvm_type.rb +157 -0
  4. data/lib/amber/classes/association.rb +36 -0
  5. data/lib/amber/classes/block.rb +52 -0
  6. data/lib/amber/classes/boolean.rb +40 -0
  7. data/lib/amber/classes/class.rb +50 -0
  8. data/lib/amber/classes/error.rb +22 -0
  9. data/lib/amber/classes/list.rb +96 -0
  10. data/lib/amber/classes/null.rb +35 -0
  11. data/lib/amber/classes/number.rb +95 -0
  12. data/lib/amber/classes/object.rb +56 -0
  13. data/lib/amber/classes/string.rb +79 -0
  14. data/lib/amber/classes.rb +113 -0
  15. data/lib/amber/environment.rb +251 -0
  16. data/lib/amber/fukubukuro/ecma_core.rb +409 -0
  17. data/lib/amber/fukubukuro.rb +866 -0
  18. data/lib/amber/functions/all.rb +3 -0
  19. data/lib/amber/functions/array/append.rb +50 -0
  20. data/lib/amber/functions/array/at.rb +50 -0
  21. data/lib/amber/functions/array/set_at.rb +50 -0
  22. data/lib/amber/functions/array.rb +30 -0
  23. data/lib/amber/functions/association/assoc_get.rb +55 -0
  24. data/lib/amber/functions/association/assoc_set.rb +56 -0
  25. data/lib/amber/functions/bitwise/bitwise_and.rb +41 -0
  26. data/lib/amber/functions/bitwise/bitwise_not.rb +41 -0
  27. data/lib/amber/functions/bitwise/bitwise_or.rb +41 -0
  28. data/lib/amber/functions/bitwise/bitwise_xor.rb +41 -0
  29. data/lib/amber/functions/bitwise.rb +3 -0
  30. data/lib/amber/functions/collection/get.rb +66 -0
  31. data/lib/amber/functions/collection/set.rb +67 -0
  32. data/lib/amber/functions/collection/size.rb +54 -0
  33. data/lib/amber/functions/general/cmp.rb +43 -0
  34. data/lib/amber/functions/general/eq.rb +45 -0
  35. data/lib/amber/functions/general/gt.rb +45 -0
  36. data/lib/amber/functions/general/gte.rb +45 -0
  37. data/lib/amber/functions/general/lt.rb +45 -0
  38. data/lib/amber/functions/general/lte.rb +45 -0
  39. data/lib/amber/functions/general/neq.rb +45 -0
  40. data/lib/amber/functions/general/type.rb +43 -0
  41. data/lib/amber/functions/general.rb +3 -0
  42. data/lib/amber/functions/io/print.rb +45 -0
  43. data/lib/amber/functions/io.rb +3 -0
  44. data/lib/amber/functions/list/align.rb +73 -0
  45. data/lib/amber/functions/list/join.rb +45 -0
  46. data/lib/amber/functions/list/map.rb +58 -0
  47. data/lib/amber/functions/list/split.rb +55 -0
  48. data/lib/amber/functions/list.rb +3 -0
  49. data/lib/amber/functions/logic/and.rb +55 -0
  50. data/lib/amber/functions/logic/not.rb +40 -0
  51. data/lib/amber/functions/logic/or.rb +50 -0
  52. data/lib/amber/functions/logic.rb +3 -0
  53. data/lib/amber/functions/math/abs.rb +39 -0
  54. data/lib/amber/functions/math/acos.rb +39 -0
  55. data/lib/amber/functions/math/add.rb +40 -0
  56. data/lib/amber/functions/math/asin.rb +39 -0
  57. data/lib/amber/functions/math/atan.rb +39 -0
  58. data/lib/amber/functions/math/ceil.rb +39 -0
  59. data/lib/amber/functions/math/cos.rb +39 -0
  60. data/lib/amber/functions/math/dec.rb +39 -0
  61. data/lib/amber/functions/math/div.rb +44 -0
  62. data/lib/amber/functions/math/exp.rb +39 -0
  63. data/lib/amber/functions/math/floor.rb +39 -0
  64. data/lib/amber/functions/math/inc.rb +39 -0
  65. data/lib/amber/functions/math/log.rb +39 -0
  66. data/lib/amber/functions/math/mod.rb +41 -0
  67. data/lib/amber/functions/math/mul.rb +43 -0
  68. data/lib/amber/functions/math/neg.rb +43 -0
  69. data/lib/amber/functions/math/power.rb +43 -0
  70. data/lib/amber/functions/math/rand.rb +36 -0
  71. data/lib/amber/functions/math/round.rb +39 -0
  72. data/lib/amber/functions/math/shl.rb +41 -0
  73. data/lib/amber/functions/math/shr.rb +41 -0
  74. data/lib/amber/functions/math/sin.rb +39 -0
  75. data/lib/amber/functions/math/sub.rb +43 -0
  76. data/lib/amber/functions/math/tan.rb +39 -0
  77. data/lib/amber/functions/math.rb +3 -0
  78. data/lib/amber/functions/objects/send.rb +22 -0
  79. data/lib/amber/functions/rails/print.rb +44 -0
  80. data/lib/amber/functions/rails.rb +3 -0
  81. data/lib/amber/functions/string/ansi.rb +24 -0
  82. data/lib/amber/functions/string/capstr.rb +23 -0
  83. data/lib/amber/functions/string/center.rb +25 -0
  84. data/lib/amber/functions/string/chr.rb +16 -0
  85. data/lib/amber/functions/string/ljust.rb +26 -0
  86. data/lib/amber/functions/string/regmatch.rb +34 -0
  87. data/lib/amber/functions/string/rjust.rb +26 -0
  88. data/lib/amber/functions/string.rb +3 -0
  89. data/lib/amber/functions.rb +103 -0
  90. data/lib/amber/interpreter.rb +1380 -0
  91. data/lib/amber/languages/brainfuck.rb +153 -0
  92. data/lib/amber/languages/ecma/compiler.rb +1661 -0
  93. data/lib/amber/languages/ecma/core-math.js +67 -0
  94. data/lib/amber/languages/ecma/core-objects.js +57 -0
  95. data/lib/amber/languages/ecma.rb +9 -0
  96. data/lib/amber/languages/ecma_fuku/compiler.rb +1622 -0
  97. data/lib/amber/languages/ecma_fuku/core-math.js +67 -0
  98. data/lib/amber/languages/ecma_fuku/core-objects.js +56 -0
  99. data/lib/amber/languages/ecma_fuku.rb +13 -0
  100. data/lib/amber/languages/math/compiler.rb +70 -0
  101. data/lib/amber/languages/math/tokenizer.rb +69 -0
  102. data/lib/amber/languages/math/tree.rb +110 -0
  103. data/lib/amber/languages/math.rb +26 -0
  104. data/lib/amber/languages.rb +99 -0
  105. data/lib/amber/library.rb +79 -0
  106. data/lib/amber/optimisation.rb +299 -0
  107. data/lib/amber/plugin.rb +337 -0
  108. data/lib/amber/rails.rb +90 -0
  109. data/lib/amber.rb +106 -0
  110. data/spec/amber/class_spec.rb +27 -0
  111. data/spec/amber/enviroment_spec.rb +61 -0
  112. data/spec/amber/function_spec.rb +25 -0
  113. data/spec/amber/functions/association/assoc_get_spec.rb +41 -0
  114. data/spec/amber/functions/association/assoc_set_spec.rb +43 -0
  115. data/spec/amber/functions/collection/get_spec.rb +12 -0
  116. data/spec/amber/functions/collection/set_spec.rb +10 -0
  117. data/spec/amber/functions/collection/size_spec.rb +10 -0
  118. data/spec/amber/functions/list/split_spec.rb +47 -0
  119. data/spec/amber/functions/string/ansi_spec.rb +44 -0
  120. data/spec/amber/functions/string/capstr_spec.rb +42 -0
  121. data/spec/amber/functions/string/center_spec.rb +49 -0
  122. data/spec/amber/functions/string/ljust_spec.rb +49 -0
  123. data/spec/amber/functions/string/regmatch_spec.rb +52 -0
  124. data/spec/amber/functions/string/rjust_spec.rb +49 -0
  125. data/spec/amber/interpreter/assignment_spec.rb +22 -0
  126. data/spec/amber/interpreter/condition_spec.rb +103 -0
  127. data/spec/amber/interpreter/constant_spec.rb +31 -0
  128. data/spec/amber/interpreter/core_call_spec.rb +72 -0
  129. data/spec/amber/interpreter/interpreter_spec.rb +11 -0
  130. data/spec/amber/interpreter/parameter_spec.rb +24 -0
  131. data/spec/amber/interpreter/sequence_spec.rb +47 -0
  132. data/spec/amber/interpreter/variable_spec.rb +24 -0
  133. data/spec/amber/plugin_spec.rb +10 -0
  134. data/spec/classes/atom/association_spec.rb +39 -0
  135. data/spec/classes/atom/block_spec.rb +25 -0
  136. data/spec/classes/atom/boolean_spec.rb +67 -0
  137. data/spec/classes/atom/error_spec.rb +43 -0
  138. data/spec/classes/atom/list_spec.rb +68 -0
  139. data/spec/classes/atom/number_spec.rb +132 -0
  140. data/spec/classes/atom/string_spec.rb +175 -0
  141. data/spec/languages/ecma/ecma_array_spec.rb +79 -0
  142. data/spec/languages/ecma/ecma_closure_spec.rb +38 -0
  143. data/spec/languages/ecma/ecma_literals_spec.rb +71 -0
  144. data/spec/languages/ecma/ecma_objects_spec.rb +165 -0
  145. data/spec/languages/ecma/ecma_old_spec.rb +540 -0
  146. data/spec/languages/ecma/ecma_spec.rb +64 -0
  147. data/spec/languages/ecma_fuku/ecma_array_spec.rb +61 -0
  148. data/spec/languages/ecma_fuku/ecma_closure_spec.rb +33 -0
  149. data/spec/languages/ecma_fuku/ecma_function_spec.rb +84 -0
  150. data/spec/languages/ecma_fuku/ecma_literals_spec.rb +55 -0
  151. data/spec/languages/ecma_fuku/ecma_objects_spec.rb +133 -0
  152. data/spec/languages/ecma_fuku/ecma_old_spec.rb +415 -0
  153. data/spec/languages/ecma_fuku/ecma_operator_spec.rb +33 -0
  154. data/spec/languages/ecma_fuku/ecma_spec.rb +52 -0
  155. data/spec/languages/math/compiler_spec.rb +49 -0
  156. data/spec/languages/math/tokenizer_spec.rb +73 -0
  157. data/spec/languages/math/tree_spec.rb +153 -0
  158. 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,13 @@
1
+ module AmberVM
2
+ module Languages
3
+ # A compiler for JavaScript.
4
+ class ECMA_Fuku < AmberVM::Languages::Language
5
+ register_for :'ecma_fuku'
6
+ plugin_id
7
+ helper :compiler
8
+ def default_env
9
+ @compiler.env
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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
+