maroon 0.6.1 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Examples/Dijkstra/CalculateShortestDistance.rb +16 -12
- data/Examples/Dijkstra/calculate_shortest_path.rb +47 -27
- data/Examples/Dijkstra/data.rb +41 -14
- data/Examples/Dijkstra/dijkstra.rb +4 -3
- data/Examples/MoneyTransfer.rb +61 -60
- data/Examples/greeter.rb +8 -7
- data/Examples/meter.rb +35 -29
- data/Gemfile +9 -4
- data/LICENSE.txt +21 -21
- data/README.md +13 -0
- data/Rakefile +41 -1
- data/Test/Generate/method_info_test.rb +12 -0
- data/Test/{Greeter_test.rb → Greeter_test_disabled.rb} +24 -20
- data/Test/ImmutableQueue_test.rb +18 -0
- data/Test/MethodInfo_test.rb +65 -0
- data/Test/alltests.rb +1 -0
- data/Test/{source_assertions.rb → assertions.rb} +15 -7
- data/Test/bind_test.rb +13 -0
- data/Test/expression_test.rb +105 -0
- data/Test/method_call_test.rb +83 -0
- data/Test/self_test.rb +46 -0
- data/Test/stack_test.rb +17 -0
- data/Test/test_helper.rb +14 -0
- data/base/ImmutableStack.rb +32 -0
- data/base/MethodDefinition.rb +124 -0
- data/base/bind_rewriter.rb +58 -0
- data/base/immutable_queue.rb +50 -0
- data/base/maroon_base.rb +267 -0
- data/base/method_call.rb +78 -0
- data/base/method_info.rb +86 -0
- data/base/self.rb +60 -0
- data/generated/build.rb +13 -0
- data/generated/interpretation_context.rb +29 -0
- data/lib/Bind.rb +65 -0
- data/lib/Context.rb +187 -0
- data/lib/ImmutableQueue.rb +50 -0
- data/lib/ImmutableStack.rb +38 -0
- data/lib/MethodCall.rb +91 -0
- data/lib/MethodDefinition.rb +114 -0
- data/lib/MethodInfo.rb +78 -0
- data/lib/Self.rb +71 -0
- data/lib/build.rb +14 -0
- data/lib/interpretation_context.rb +30 -0
- data/lib/maroon/contracts.rb +43 -0
- data/lib/maroon/kernel.rb +2 -0
- data/lib/maroon/version.rb +3 -3
- data/maroon.gemspec +26 -26
- metadata +49 -31
- data/lib/Source_cleaner.rb +0 -34
- data/lib/maroon.rb +0 -165
- data/lib/rewriter.rb +0 -185
@@ -0,0 +1,38 @@
|
|
1
|
+
class ImmutableStack
|
2
|
+
|
3
|
+
def pop()
|
4
|
+
[@head, @tail]
|
5
|
+
end
|
6
|
+
|
7
|
+
def push(element)
|
8
|
+
ImmutableStack.new(element, self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.empty()
|
12
|
+
@@empty ||= self.new(nil, nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def each()
|
16
|
+
yield(head)
|
17
|
+
t = tail
|
18
|
+
while t.!=(ImmutableStack.empty) do
|
19
|
+
h, t = t.pop
|
20
|
+
yield(h)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(h,t)
|
26
|
+
@head = h
|
27
|
+
@tail = t
|
28
|
+
self.freeze
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
attr_reader :head
|
34
|
+
attr_reader :tail
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
end
|
data/lib/MethodCall.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
class MethodCall
|
2
|
+
|
3
|
+
def rewrite_call?()
|
4
|
+
method_name = method[2]
|
5
|
+
if (method[0] == :call) then
|
6
|
+
if (method[1] == nil) and ((method.length < 5) and (method[3] and ((method[3].length == 1) and (method[3][0] == :arglist)))) then
|
7
|
+
is_role = interpretation_context.roles.has_key?(method[3])
|
8
|
+
method[3] = (":@" + method[3].to_sym) if is_role
|
9
|
+
else
|
10
|
+
role_name, is_role_method = self_method_role_method_call?(method_name)
|
11
|
+
if is_role_method then
|
12
|
+
method[1] = nil
|
13
|
+
method[2] = ((("self_" + role_name.to_s) + "_") + method_name.to_s).to_sym
|
14
|
+
else
|
15
|
+
if interpretation_context.roles.has_key?(role_name) then
|
16
|
+
unless (method.length == 3) and ((method[1] == nil) and (method[2] == role_name)) then
|
17
|
+
contract_methods = interpretation_context.contracts[role_name] ||= {}
|
18
|
+
contract_methods[method_name] ||= 0
|
19
|
+
contract_methods[method_name] += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(method,interpretation_context)
|
29
|
+
raise("No method supplied") unless method
|
30
|
+
@method = method
|
31
|
+
@interpretation_context = interpretation_context
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.call(*args)
|
36
|
+
arity = MethodCall.method(:new).arity
|
37
|
+
newArgs = args[0..arity-1]
|
38
|
+
obj = MethodCall.new *newArgs
|
39
|
+
if arity < args.length
|
40
|
+
methodArgs = args[arity..-1]
|
41
|
+
obj.rewrite_call? *methodArgs
|
42
|
+
else
|
43
|
+
obj.rewrite_call?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def call(*args);rewrite_call? *args; end
|
48
|
+
|
49
|
+
private
|
50
|
+
attr_reader :interpretation_context
|
51
|
+
attr_reader :method
|
52
|
+
|
53
|
+
|
54
|
+
def self_interpretation_context_role_aliases()
|
55
|
+
(@interpretation_context.role_aliases or {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def self_method_call_in_block?()
|
59
|
+
@in_block unless (@in_block == nil)
|
60
|
+
@in_block = (method and (method[0] == :lvar))
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def self_method_get_role_definition()
|
65
|
+
is_call_expression = (method and (method[0] == :call))
|
66
|
+
self_is_instance_expression = (is_call_expression and (not method[1]))
|
67
|
+
role_name = nil
|
68
|
+
role_name = method[2] if self_is_instance_expression
|
69
|
+
if (not self_is_instance_expression) and method[1] then
|
70
|
+
if (method[1][1] == nil) and (method[1][0] == :call) then
|
71
|
+
role_name = method[1][2]
|
72
|
+
end
|
73
|
+
if (method[1][0] == :lvar) then
|
74
|
+
role_name = self_interpretation_context_role_aliases[method[1][1]]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
role = role_name ? (interpretation_context.roles[role_name]) : (nil)
|
78
|
+
[role, role ? (role_name) : (nil)]
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def self_method_role_method_call?(method_name)
|
83
|
+
return [nil, nil] unless method
|
84
|
+
role, role_name = self_method_get_role_definition
|
85
|
+
is_role_method = (role and role.has_key?(method_name))
|
86
|
+
return [role_name, is_role_method]
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class MethodDefinition
|
2
|
+
|
3
|
+
def rebind()
|
4
|
+
@exp, @expressions = expressions.pop
|
5
|
+
@block, @potential_bind = nil
|
6
|
+
if @exp and (@exp.instance_of?(Sexp) and (@exp[0] == :iter)) then
|
7
|
+
@exp[(1..-1)].each do |expr|
|
8
|
+
if expr and (expr.length and (expr[0] == :block)) then
|
9
|
+
@block, @potential_bind = expr, expr[1]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
@expressions = @exp.instance_of?(Sexp) ? (@expressions.push_array(exp)) : (@expressions)
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def transform()
|
18
|
+
until self_expressions_empty? do
|
19
|
+
(self_block_transform
|
20
|
+
if exp and exp.instance_of?(Sexp) then
|
21
|
+
is_indexer = ((exp[0] == :call) and ((exp[1] == nil) and ((exp[2] == :[]) or (exp[2] == :[]=))))
|
22
|
+
if (is_indexer or (exp[0] == :self)) and @interpretation_context.defining_role then
|
23
|
+
Self.new(exp, interpretation_context).execute
|
24
|
+
end
|
25
|
+
if (exp[0] == :call) then
|
26
|
+
MethodCall.new(exp, interpretation_context).rewrite_call?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rebind)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(exp,interpretationcontext)
|
34
|
+
no_exp = "No expression supplied".to_sym
|
35
|
+
no_ctx = "No interpretation context".to_sym
|
36
|
+
raise(no_exp) unless exp
|
37
|
+
raise(no_ctx) unless interpretationcontext
|
38
|
+
@interpretation_context = interpretationcontext
|
39
|
+
@expressions = ImmutableQueue.empty.push(exp)
|
40
|
+
rebind
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.call(*args)
|
45
|
+
arity = MethodDefinition.method(:new).arity
|
46
|
+
newArgs = args[0..arity-1]
|
47
|
+
obj = MethodDefinition.new *newArgs
|
48
|
+
if arity < args.length
|
49
|
+
methodArgs = args[arity..-1]
|
50
|
+
obj.transform *methodArgs
|
51
|
+
else
|
52
|
+
obj.transform
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(*args);transform *args; end
|
57
|
+
|
58
|
+
private
|
59
|
+
attr_reader :interpretation_context
|
60
|
+
attr_reader :exp
|
61
|
+
attr_reader :expressions
|
62
|
+
attr_reader :potential_bind
|
63
|
+
attr_reader :block
|
64
|
+
|
65
|
+
|
66
|
+
def self_interpretation_context_addalias(key,value)
|
67
|
+
@interpretation_context.role_aliases[key] = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def self_expressions_empty?()
|
71
|
+
(expressions == ImmutableQueue.empty)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self_potential_bind_is_bind?()
|
75
|
+
potential_bind and (potential_bind.length and ((potential_bind[0] == :call) and ((potential_bind[1] == nil) and (potential_bind[2] == :bind))))
|
76
|
+
end
|
77
|
+
|
78
|
+
def self_block_transform()
|
79
|
+
if block then
|
80
|
+
@expressions.push_array(block[(1..-1)]) if self_block_transform_bind?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self_block_transform_bind?()
|
85
|
+
self_potential_bind_is_bind? and self_block_rewrite
|
86
|
+
end
|
87
|
+
|
88
|
+
def self_block_rewrite()
|
89
|
+
changed = false
|
90
|
+
arguments = potential_bind[3]
|
91
|
+
if arguments and (arguments[0] == :hash) then
|
92
|
+
block.delete_at(1)
|
93
|
+
count = ((arguments.length - 1) / 2)
|
94
|
+
(1..count).each do |j|
|
95
|
+
temp = (j * 2)
|
96
|
+
local = arguments[(temp - 1)][1]
|
97
|
+
local = local[1] if local.instance_of?(Sexp)
|
98
|
+
raise("invalid value for role alias") unless local.instance_of?(Symbol)
|
99
|
+
aliased_role = arguments[temp][1]
|
100
|
+
aliased_role = aliased_role[1] if aliased_role.instance_of?(Sexp)
|
101
|
+
unless aliased_role.instance_of?(Symbol) and interpretation_context.roles.has_key?(aliased_role) then
|
102
|
+
raise(((aliased_role.to_s + "used in binding is an unknown role ") + roles.to_s))
|
103
|
+
end
|
104
|
+
self_interpretation_context_addalias(local, aliased_role)
|
105
|
+
Bind.new(local, aliased_role, block).execute
|
106
|
+
changed = true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
changed
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
end
|
data/lib/MethodInfo.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class MethodInfo
|
2
|
+
|
3
|
+
def initialize(on_self,block_source,is_private)
|
4
|
+
raise("Must be S-Expressions") unless block_source.instance_of?(Sexp)
|
5
|
+
if on_self.instance_of?(Hash) then
|
6
|
+
@block = on_self[:block]
|
7
|
+
@on_self = on_self[:self]
|
8
|
+
else
|
9
|
+
@on_self = on_self
|
10
|
+
end
|
11
|
+
@block_source = block_source
|
12
|
+
@private = is_private
|
13
|
+
self.freeze
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_private()
|
18
|
+
@private
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_as_context_method(context_method_name,interpretation_context)
|
22
|
+
MethodDefinition.new(self_block_source_body, interpretation_context).transform
|
23
|
+
body = Ruby2Ruby.new.process(self_block_source_body)
|
24
|
+
args = if self_block_source_arguments then
|
25
|
+
(("(" + self_block_source_arguments) + ")")
|
26
|
+
else
|
27
|
+
""
|
28
|
+
end
|
29
|
+
on = on_self ? ("self.") : ("")
|
30
|
+
(((((("\ndef " + on.to_s) + context_method_name.to_s) + args) + "\n ") + body) + "\n end\n")
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
attr_reader :on_self
|
36
|
+
attr_reader :block
|
37
|
+
attr_reader :block_source
|
38
|
+
|
39
|
+
|
40
|
+
def self_block_source_get_arguments()
|
41
|
+
sexp = block_source[2]
|
42
|
+
return nil unless sexp
|
43
|
+
return sexp[1] if (sexp[0] == :lasgn)
|
44
|
+
return [] if (sexp[1] == nil)
|
45
|
+
sexp = sexp[(1..-1)]
|
46
|
+
args = []
|
47
|
+
sexp.each do |e|
|
48
|
+
(args << (if e.instance_of?(Symbol) then
|
49
|
+
e
|
50
|
+
else
|
51
|
+
(e[0] == :splat) ? (("*" + e[1][1].to_s)) : (e[1])
|
52
|
+
end))
|
53
|
+
end
|
54
|
+
if block then
|
55
|
+
b = ("&" + block.to_s)
|
56
|
+
if args then
|
57
|
+
args = [args] unless args.instance_of?(Array)
|
58
|
+
(args << b)
|
59
|
+
else
|
60
|
+
args = [b]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
args
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def self_block_source_arguments()
|
68
|
+
args = self_block_source_get_arguments
|
69
|
+
args and args.length ? (args.join(",")) : (nil)
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def self_block_source_body()
|
74
|
+
block_source[3]
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
data/lib/Self.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class Self
|
2
|
+
|
3
|
+
def initialize(abstract_syntax_tree,interpretationcontext)
|
4
|
+
raise("Interpretation context missing") unless interpretationcontext
|
5
|
+
unless interpretationcontext.defining_role then
|
6
|
+
raise("Must have a defining role")
|
7
|
+
end
|
8
|
+
@abstract_syntax_tree = abstract_syntax_tree
|
9
|
+
@interpretation_context = interpretationcontext
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute()
|
14
|
+
if abstract_syntax_tree then
|
15
|
+
if (abstract_syntax_tree[0] == :self) then
|
16
|
+
abstract_syntax_tree[0] = :call
|
17
|
+
abstract_syntax_tree[1] = nil
|
18
|
+
abstract_syntax_tree[2] = interpretation_context.defining_role
|
19
|
+
else
|
20
|
+
if (abstract_syntax_tree[0] == :call) and (abstract_syntax_tree[1] == nil) then
|
21
|
+
method_name = abstract_syntax_tree[2]
|
22
|
+
if ((method_name == :[]) or (method_name == :[]=)) then
|
23
|
+
get_role = Sexp.new
|
24
|
+
get_role[0] = :call
|
25
|
+
get_role[1] = nil
|
26
|
+
get_role[2] = interpretation_context.defining_role
|
27
|
+
abstract_syntax_tree[1] = get_role
|
28
|
+
end
|
29
|
+
else
|
30
|
+
if abstract_syntax_tree.instance_of?(Sexp) then
|
31
|
+
if self_abstract_syntax_tree_is_indexer_call_on_self then
|
32
|
+
getter = new(Sexp.new)
|
33
|
+
getter[0] = :call
|
34
|
+
getter[1] = nil
|
35
|
+
getter[2] = interpretation_context.defining_role
|
36
|
+
arglist = Sexp.new
|
37
|
+
getter[3] = arglist
|
38
|
+
arglist[0] = :arglist
|
39
|
+
abstract_syntax_tree[1] = getter
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.call(*args)
|
48
|
+
arity = Self.method(:new).arity
|
49
|
+
newArgs = args[0..arity-1]
|
50
|
+
obj = Self.new *newArgs
|
51
|
+
if arity < args.length
|
52
|
+
methodArgs = args[arity..-1]
|
53
|
+
obj.execute *methodArgs
|
54
|
+
else
|
55
|
+
obj.execute
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def call(*args);execute *args; end
|
60
|
+
|
61
|
+
private
|
62
|
+
attr_reader :abstract_syntax_tree
|
63
|
+
attr_reader :interpretation_context
|
64
|
+
|
65
|
+
|
66
|
+
def self_abstract_syntax_tree_is_indexer_call_on_self()
|
67
|
+
(abstract_syntax_tree.length == 4) and ((abstract_syntax_tree[0] == :call) and ((abstract_syntax_tree[1] == nil) and ((abstract_syntax_tree[2] == :[]) and (abstract_syntax_tree[3][0] == :argslist))))
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
end
|
data/lib/build.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'sorcerer'
|
2
|
+
require 'sourcify'
|
3
|
+
|
4
|
+
require_relative 'self'
|
5
|
+
require_relative 'bind'
|
6
|
+
require_relative 'ImmutableQueue'
|
7
|
+
require_relative 'ImmutableStack'
|
8
|
+
require_relative 'interpretation_context'
|
9
|
+
require_relative 'MethodDefinition'
|
10
|
+
require_relative 'MethodInfo'
|
11
|
+
require_relative 'MethodCall'
|
12
|
+
|
13
|
+
require_relative 'Context'
|
14
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class InterpretationContext
|
2
|
+
def contracts
|
3
|
+
(@contracts ||= {})
|
4
|
+
end
|
5
|
+
|
6
|
+
def roles
|
7
|
+
(@roles ||= {})
|
8
|
+
end
|
9
|
+
|
10
|
+
def role_aliases
|
11
|
+
(@role_aliases ||= {})
|
12
|
+
end
|
13
|
+
|
14
|
+
def defining_role
|
15
|
+
@defining_role
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(roles, contracts, role_aliases, defining_role)
|
19
|
+
raise "Aliases must be a hash" unless role_aliases.instance_of? Hash or role_aliases == nil
|
20
|
+
raise "Roles must be a hash" unless roles.instance_of? Hash or roles == nil
|
21
|
+
raise "Contracts must be a hash" unless contracts.instance_of? Hash or contracts == nil
|
22
|
+
|
23
|
+
@roles = roles
|
24
|
+
raise "Defining role is undefined" if defining_role && (!self.roles.has_key? defining_role)
|
25
|
+
|
26
|
+
@contracts = contracts
|
27
|
+
@role_aliases = role_aliases
|
28
|
+
@defining_role = defining_role
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
if Kernel::const_defined? :MiniTest
|
2
|
+
class ContextAsserterBase < MiniTest::Unit::TestCase
|
3
|
+
|
4
|
+
end
|
5
|
+
else
|
6
|
+
class ContextAsserterBase
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ContextAsserter < ContextAsserterBase
|
12
|
+
def initialize(contracts, obj, is_asserting = true)
|
13
|
+
raise 'Contracts must be supplied' unless contracts
|
14
|
+
@obj = obj
|
15
|
+
@contracts = contracts
|
16
|
+
@is_asserting = is_asserting
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_test
|
20
|
+
Kernel::const_defined? :MiniTest
|
21
|
+
end
|
22
|
+
|
23
|
+
def can_play(role)
|
24
|
+
msg = "#{@is_asserting ? 'Was' : "wasn't"} expected to be able to play #{role}".intern
|
25
|
+
if is_test
|
26
|
+
assert_equal(@is_asserting, can_play?(role), msg)
|
27
|
+
else
|
28
|
+
raise msg if @is_asserting != can_play?(role)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def can_play?(role)
|
35
|
+
required_methods = @contracts[role]
|
36
|
+
methods = @obj.public_methods
|
37
|
+
missing = required_methods.select do |rm|
|
38
|
+
!methods.include? rm.to_sym
|
39
|
+
end
|
40
|
+
missing.length == 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
Context::with_contracts = true
|