rVM 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rvm/interpreter.rb +0 -23
- data/lib/rvm/languages/math/compiler.rb +1 -1
- data/lib/rvm/languages/math/tokenizer.rb +7 -3
- data/lib/rvm/languages/math/tree.rb +19 -18
- data/lib/rvm/languages/simple.rb +15 -0
- data/lib/rvm/languages/simple/compiler.rb +73 -0
- data/lib/rvm/languages/simple/tokenizer.rb +75 -0
- data/lib/rvm/languages/simple/tree.rb +144 -0
- metadata +8 -3
data/lib/rvm/interpreter.rb
CHANGED
@@ -40,8 +40,6 @@ module RVM
|
|
40
40
|
@data = {
|
41
41
|
:locals => {},
|
42
42
|
:functions => {},
|
43
|
-
:caller => nil,
|
44
|
-
:self => nil,
|
45
43
|
:evaldeepth => 0,
|
46
44
|
:params => []
|
47
45
|
}.merge(data)
|
@@ -50,27 +48,6 @@ module RVM
|
|
50
48
|
|
51
49
|
end
|
52
50
|
|
53
|
-
# returns the object that issued the VM call - so to say it's owner.
|
54
|
-
#
|
55
|
-
# If the current enviroment has no caller it tries it's 'oldenv' attrib
|
56
|
-
# to see if that had a owner.
|
57
|
-
def caller
|
58
|
-
r = @data[:caller] || (@prev.is_a?(Enviroment) ? @prev.caller : nil)
|
59
|
-
RVM::debug "Getting caller: #{r}"
|
60
|
-
r
|
61
|
-
end
|
62
|
-
|
63
|
-
# returns the object that the code is run as, so it has the rights of
|
64
|
-
# this object.
|
65
|
-
#
|
66
|
-
# If the current enviroment has no object it tries it's 'oldenv' attrib
|
67
|
-
# to see if that had a object.
|
68
|
-
def object
|
69
|
-
r = @data[:self] || (@prev.is_a?(Enviroment) ? @prev.object : nil)
|
70
|
-
RVM::debug "Getting object: #{r}"
|
71
|
-
r
|
72
|
-
end
|
73
|
-
|
74
51
|
# returns a parameter that was passed to the call. For function calls
|
75
52
|
# this is especially important, it beginns with 0.
|
76
53
|
#
|
@@ -51,10 +51,10 @@ module RVM
|
|
51
51
|
tree[:left][:params].each do |p|
|
52
52
|
raise ArgumentError, "Bad ype for a function parameter: #{p[:type]} " if p[:type] != :ident
|
53
53
|
body << Interpreter::Assignment.new(Interpreter.const(:string, p[:ident]), Interpreter::Parameter.new(Interpreter.const(:number, i)))
|
54
|
+
i += 1
|
54
55
|
end
|
55
56
|
body << compile(tree[:right])
|
56
57
|
Interpreter::FunctionDefinition.new(Interpreter.const(:string, tree[:left][:op]), Interpreter.const(:block,body))
|
57
|
-
|
58
58
|
else
|
59
59
|
raise ArgumentError, "Bad name for a variable!"
|
60
60
|
end
|
@@ -16,16 +16,20 @@ module RVM
|
|
16
16
|
if t == '-'
|
17
17
|
tokens << [t, :function]
|
18
18
|
end
|
19
|
-
elsif s.scan(/[
|
19
|
+
elsif s.scan(/[_a-z][_a-z0-9]*/i)
|
20
20
|
r = s.matched
|
21
21
|
if s.scan(/\(/)
|
22
22
|
tokens << [r, :function]
|
23
|
-
|
23
|
+
if s.scan(/\)/)
|
24
|
+
tokens << [s.matched, :paren_close]
|
25
|
+
else
|
26
|
+
paren_deepth += 1
|
27
|
+
end
|
24
28
|
else
|
25
29
|
tokens << [r, :ident]
|
26
30
|
state = :opperator
|
27
31
|
end
|
28
|
-
elsif s.scan(/
|
32
|
+
elsif s.scan(/((\d+(\.\d+)?)|(\.\d+))(e-?\d+)?/i)
|
29
33
|
tokens << [s.matched, :number]
|
30
34
|
state = :opperator
|
31
35
|
elsif s.scan(/\(/)
|
@@ -3,17 +3,17 @@ module RVM
|
|
3
3
|
module Math
|
4
4
|
class Tree
|
5
5
|
PRIORITIES = {
|
6
|
-
';' => -
|
7
|
-
'=' =>
|
6
|
+
';' => -100,
|
7
|
+
'=' => -50,
|
8
8
|
'(' => 0,
|
9
|
-
'+' =>
|
10
|
-
'-' =>
|
11
|
-
'*' =>
|
12
|
-
'/' =>
|
13
|
-
'^' =>
|
9
|
+
'+' => 10,
|
10
|
+
'-' => 10,
|
11
|
+
'*' => 20,
|
12
|
+
'/' => 20,
|
13
|
+
'^' => 30,
|
14
14
|
}
|
15
15
|
ASSOSICATIONS = {
|
16
|
-
';' => :right,
|
16
|
+
';' => :right,
|
17
17
|
'+' => :left,
|
18
18
|
'-' => :left,
|
19
19
|
'*' => :left,
|
@@ -36,7 +36,7 @@ module RVM
|
|
36
36
|
dbgoutput << ')'
|
37
37
|
dbgstack << fun
|
38
38
|
when :function_sep
|
39
|
-
while stack.last && (stack.last[:
|
39
|
+
while stack.last && (stack.last[:type] != :function)
|
40
40
|
output << stack.pop
|
41
41
|
dbgoutput << dbgstack.pop
|
42
42
|
end
|
@@ -51,10 +51,6 @@ module RVM
|
|
51
51
|
end
|
52
52
|
stack.pop
|
53
53
|
dbgstack.pop
|
54
|
-
if stack.last && (stack.last[:type] == :function)
|
55
|
-
output << stack.pop
|
56
|
-
dbgoutput << dbgstack.pop
|
57
|
-
end
|
58
54
|
when :number
|
59
55
|
output << {:type => :number, :number => token[0]}
|
60
56
|
dbgoutput << token[0]
|
@@ -65,7 +61,7 @@ module RVM
|
|
65
61
|
op = token[0]
|
66
62
|
ass = ASSOSICATIONS[op]
|
67
63
|
o1p = PRIORITIES[op]
|
68
|
-
while stack.last &&
|
64
|
+
while stack.last && (stack.last[:type] != :function) &&
|
69
65
|
(((ass == :left) && (o1p <= PRIORITIES[stack.last[:op]])) ||
|
70
66
|
((ass == :right) && (o1p < PRIORITIES[stack.last[:op]])))
|
71
67
|
output << stack.pop
|
@@ -74,25 +70,30 @@ module RVM
|
|
74
70
|
stack << {:type => :op, :op => op}
|
75
71
|
dbgstack << op
|
76
72
|
else
|
73
|
+
raise "Unknown element in parser tree: #{token.inspect}"
|
77
74
|
end
|
75
|
+
p(dbgstack) if $DEBUG
|
76
|
+
p(dbgoutput) if $DEBUG
|
78
77
|
end
|
79
78
|
while not stack.empty?
|
80
79
|
output << stack.pop
|
81
80
|
end
|
82
|
-
p output
|
83
81
|
gen_tree output
|
84
82
|
end
|
85
83
|
|
86
84
|
private
|
87
85
|
def Tree.gen_tree data
|
88
|
-
p data
|
89
86
|
item = data.pop
|
90
87
|
case item[:type]
|
91
88
|
when :number, :ident
|
92
89
|
item
|
93
|
-
|
90
|
+
when :op
|
94
91
|
item[:right] = gen_tree(data)
|
95
|
-
item[:
|
92
|
+
if item[:op] == ';' and data.empty?
|
93
|
+
item = item[:right]
|
94
|
+
else
|
95
|
+
item[:left] = gen_tree(data)
|
96
|
+
end
|
96
97
|
item
|
97
98
|
when :function
|
98
99
|
item[:params] = []
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/simple/tokenizer'
|
2
|
+
require File.dirname(__FILE__) + '/simple/tree'
|
3
|
+
require File.dirname(__FILE__) + '/simple/compiler'
|
4
|
+
require 'rvm/functions/math'
|
5
|
+
module RVM
|
6
|
+
module Languages
|
7
|
+
class SimpleLanguage < Language
|
8
|
+
include Simple
|
9
|
+
def compile text
|
10
|
+
Compiler.compile(Tree.generate(Tokenizer.tokenize(text)))
|
11
|
+
end
|
12
|
+
register_for :simple
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module RVM
|
2
|
+
module Languages
|
3
|
+
module Simple
|
4
|
+
class Compiler
|
5
|
+
include RVM::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 :paren
|
19
|
+
compile tree[:content]
|
20
|
+
when :number
|
21
|
+
Interpreter.const(:number, tree[:number])
|
22
|
+
when :function
|
23
|
+
params = tree[:params].map {|p| compile(p)}
|
24
|
+
case tree[:op]
|
25
|
+
when '-'
|
26
|
+
FunctionCall.new :neg, params
|
27
|
+
else
|
28
|
+
FunctionCall.new tree[:op], params
|
29
|
+
end
|
30
|
+
when :ident
|
31
|
+
Interpreter::Variable.new(Interpreter.const(:string, tree[:ident]))
|
32
|
+
when :op
|
33
|
+
case tree[:op]
|
34
|
+
when ';'
|
35
|
+
s = Interpreter::Sequence.new()
|
36
|
+
if (tree[:left][:type] == :op) and (tree[:left][:op] == ';')
|
37
|
+
s += compile(tree[:left])
|
38
|
+
else
|
39
|
+
s << compile(tree[:left])
|
40
|
+
end
|
41
|
+
if (tree[:right][:type] == :op) and (tree[:right][:op] == ';')
|
42
|
+
s += compile(tree[:right])
|
43
|
+
else
|
44
|
+
s << compile(tree[:right])
|
45
|
+
end
|
46
|
+
when '='
|
47
|
+
case tree[:left][:type]
|
48
|
+
when :ident
|
49
|
+
Interpreter::Assignment.new(Interpreter.const(:string, tree[:left][:ident]),compile(tree[:right]))
|
50
|
+
when :function
|
51
|
+
body = Interpreter::Sequence.new()
|
52
|
+
i = 0
|
53
|
+
tree[:left][:params].each do |p|
|
54
|
+
raise ArgumentError, "Bad ype for a function parameter: #{p[:type]} " if p[:type] != :ident
|
55
|
+
body << Interpreter::Assignment.new(Interpreter.const(:string, p[:ident]), Interpreter::Parameter.new(Interpreter.const(:number, i)))
|
56
|
+
i += 1
|
57
|
+
end
|
58
|
+
body << compile(tree[:right])
|
59
|
+
Interpreter::FunctionDefinition.new(Interpreter.const(:string, tree[:left][:op]), Interpreter.const(:block,body))
|
60
|
+
|
61
|
+
else
|
62
|
+
raise ArgumentError, "Bad name for a variable!"
|
63
|
+
end
|
64
|
+
else
|
65
|
+
FunctionCall.new(FUNCTION_MAP[tree[:op]], [compile(tree[:left]),compile(tree[:right])])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
module RVM
|
3
|
+
module Languages
|
4
|
+
module Simple
|
5
|
+
class Tokenizer
|
6
|
+
|
7
|
+
def Tokenizer.tokenize str
|
8
|
+
s = StringScanner.new str
|
9
|
+
tokens = []
|
10
|
+
state = :number
|
11
|
+
paren_deepth = 0
|
12
|
+
block_deepth = 0
|
13
|
+
while not s.eos?
|
14
|
+
s.skip(/\s*/)
|
15
|
+
if state == :number
|
16
|
+
if s.scan(/[+-]+/)
|
17
|
+
t = s.matched.gsub('+','').gsub('--','')
|
18
|
+
if t == '-'
|
19
|
+
tokens << [t, :function]
|
20
|
+
end
|
21
|
+
elsif s.scan(/[a-z][a-z0-9]*/i)
|
22
|
+
r = s.matched
|
23
|
+
if s.scan(/[(]/)
|
24
|
+
tokens << [r, :function]
|
25
|
+
paren_deepth += 1
|
26
|
+
else
|
27
|
+
tokens << [r, :ident]
|
28
|
+
state = :opperator
|
29
|
+
end
|
30
|
+
elsif s.scan(/[\d]+(\.\d+)?/i)
|
31
|
+
tokens << [s.matched, :number]
|
32
|
+
state = :opperator
|
33
|
+
elsif s.scan(/[(]/)
|
34
|
+
paren_deepth += 1
|
35
|
+
tokens << [s.matched, :paren_open]
|
36
|
+
elsif s.scan(/[{]/)
|
37
|
+
block_deepth += 1
|
38
|
+
tokens << [s.matched, :block_close]
|
39
|
+
else
|
40
|
+
raise "Unknown literal in term at positin #{s.pos}."
|
41
|
+
end
|
42
|
+
else
|
43
|
+
if s.scan(/[)]/)
|
44
|
+
paren_deepth -= 1
|
45
|
+
raise "Unmatched ')' parenthes at #{s.pos}" if paren_deepth < 0
|
46
|
+
tokens << [s.matched, :paren_close]
|
47
|
+
elsif s.scan(/[}]/)
|
48
|
+
block_deepth -= 1
|
49
|
+
raise "Unmatched '}' parenthes at #{s.pos}" if paren_deepth < 0
|
50
|
+
tokens << [s.matched, :block_close]
|
51
|
+
elsif s.scan(/,/)
|
52
|
+
tokens << [s.matched, :function_sep]
|
53
|
+
state = :number
|
54
|
+
elsif s.scan(/[*+\/^=-]/)
|
55
|
+
tokens << [s.matched, :opperator]
|
56
|
+
state = :number
|
57
|
+
elsif s.scan(/;/)
|
58
|
+
if paren_deepth == 0
|
59
|
+
tokens << [s.matched, :opperator]
|
60
|
+
state = :number
|
61
|
+
else
|
62
|
+
raise "Expression sepperator enclosed in parenthes at #{s.pos}"
|
63
|
+
end
|
64
|
+
else
|
65
|
+
raise "Unknown literal in term at positin #{s.pos}."
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
tokens
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module RVM
|
2
|
+
module Languages
|
3
|
+
module Simple
|
4
|
+
class Tree
|
5
|
+
PRIORITIES = {
|
6
|
+
|
7
|
+
';' => -100,
|
8
|
+
'{' => -50,
|
9
|
+
'=' => -50,
|
10
|
+
'(' => 0,
|
11
|
+
'+' => 10,
|
12
|
+
'-' => 10,
|
13
|
+
'*' => 20,
|
14
|
+
'/' => 20,
|
15
|
+
'^' => 30,
|
16
|
+
}
|
17
|
+
ASSOSICATIONS = {
|
18
|
+
'{' => :left,
|
19
|
+
'+' => :left,
|
20
|
+
'-' => :left,
|
21
|
+
'*' => :left,
|
22
|
+
'/' => :left,
|
23
|
+
';' => :right,
|
24
|
+
'^' => :right,
|
25
|
+
'=' => :right
|
26
|
+
}
|
27
|
+
PARENS = {
|
28
|
+
'(' => ')',
|
29
|
+
'{' => '}'
|
30
|
+
}
|
31
|
+
def Tree.generate tokens
|
32
|
+
output = []
|
33
|
+
dbgoutput = []
|
34
|
+
pstack = []
|
35
|
+
stack = []
|
36
|
+
dbgstack = []
|
37
|
+
|
38
|
+
while not tokens.empty?
|
39
|
+
token = tokens.shift
|
40
|
+
case token[1]
|
41
|
+
when :function
|
42
|
+
fun = token[0]
|
43
|
+
stack << {:type => :function, :op => fun}
|
44
|
+
output << {:type => :function_end}
|
45
|
+
dbgoutput << ')'
|
46
|
+
dbgstack << fun
|
47
|
+
when :function_sep
|
48
|
+
while stack.last && (stack.last[:type] != :function)
|
49
|
+
output << stack.pop
|
50
|
+
dbgoutput << dbgstack.pop
|
51
|
+
end
|
52
|
+
#Parenthetes
|
53
|
+
when :paren_open
|
54
|
+
op = token[0]
|
55
|
+
pstack << op
|
56
|
+
stack << {:type => :paren, :op => op}
|
57
|
+
dbgstack << op
|
58
|
+
when :paren_close
|
59
|
+
while stack.last && (stack.last[:op] != ')')
|
60
|
+
output << stack.pop
|
61
|
+
dbgoutput << dbgstack.pop
|
62
|
+
end
|
63
|
+
stack.pop
|
64
|
+
dbgstack.pop
|
65
|
+
if stack.last && (stack.last[:type] == :function)
|
66
|
+
output << stack.pop
|
67
|
+
dbgoutput << dbgstack.pop
|
68
|
+
end
|
69
|
+
#Blocks
|
70
|
+
when :block_open
|
71
|
+
op = token[0]
|
72
|
+
pstack << op
|
73
|
+
stack << {:type => :block, :op => op}
|
74
|
+
dbgstack << op
|
75
|
+
when :block_close
|
76
|
+
while stack.last && (stack.last[:op] != '}')
|
77
|
+
output << stack.pop
|
78
|
+
dbgoutput << dbgstack.pop
|
79
|
+
end
|
80
|
+
stack.pop
|
81
|
+
dbgstack.pop
|
82
|
+
#numbers
|
83
|
+
when :number
|
84
|
+
output << {:type => :number, :number => token[0]}
|
85
|
+
dbgoutput << token[0]
|
86
|
+
#idents
|
87
|
+
when :ident
|
88
|
+
output << {:type => :ident, :ident => token[0]}
|
89
|
+
dbgoutput << token[0]
|
90
|
+
# opperators
|
91
|
+
when :opperator
|
92
|
+
op = token[0]
|
93
|
+
ass = ASSOSICATIONS[op]
|
94
|
+
o1p = PRIORITIES[op]
|
95
|
+
while stack.last &&
|
96
|
+
(((ass == :left) && (o1p <= PRIORITIES[stack.last[:op]])) ||
|
97
|
+
((ass == :right) && (o1p < PRIORITIES[stack.last[:op]])))
|
98
|
+
output << stack.pop
|
99
|
+
dbgoutput << dbgstack.pop
|
100
|
+
end
|
101
|
+
stack << {:type => :op, :op => op}
|
102
|
+
dbgstack << op
|
103
|
+
else
|
104
|
+
end
|
105
|
+
if $DEBUG
|
106
|
+
p dbgstack
|
107
|
+
p dbgoutput
|
108
|
+
end
|
109
|
+
end
|
110
|
+
while not stack.empty?
|
111
|
+
output << stack.pop
|
112
|
+
end
|
113
|
+
p output if $DEBUG
|
114
|
+
gen_tree output
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
def Tree.gen_tree data
|
119
|
+
p data if $DEBUG
|
120
|
+
item = data.pop
|
121
|
+
p item
|
122
|
+
case item[:type]
|
123
|
+
when :number, :ident
|
124
|
+
item
|
125
|
+
when :op
|
126
|
+
item[:right] = gen_tree(data)
|
127
|
+
item[:left] = gen_tree(data)
|
128
|
+
item
|
129
|
+
when :paren, :block
|
130
|
+
item[:content] = gen_tree(data)
|
131
|
+
item
|
132
|
+
when :function
|
133
|
+
item[:params] = []
|
134
|
+
while data.last && data.last[:type] != :function_end
|
135
|
+
item[:params] << gen_tree(data)
|
136
|
+
end
|
137
|
+
data.pop
|
138
|
+
item
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rVM
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Heinz N. Gies
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-03-
|
12
|
+
date: 2008-03-06 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -73,6 +73,11 @@ files:
|
|
73
73
|
- lib/rvm/languages/math/tokenizer.rb
|
74
74
|
- lib/rvm/languages/math/tree.rb
|
75
75
|
- lib/rvm/languages/math.rb
|
76
|
+
- lib/rvm/languages/simple
|
77
|
+
- lib/rvm/languages/simple/compiler.rb
|
78
|
+
- lib/rvm/languages/simple/tokenizer.rb
|
79
|
+
- lib/rvm/languages/simple/tree.rb
|
80
|
+
- lib/rvm/languages/simple.rb
|
76
81
|
- lib/rvm/languages.rb
|
77
82
|
- lib/rvm/plugin.rb
|
78
83
|
- lib/rvm.rb
|