maroon 0.6.1 → 0.6.5

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/Examples/Dijkstra/CalculateShortestDistance.rb +16 -12
  3. data/Examples/Dijkstra/calculate_shortest_path.rb +47 -27
  4. data/Examples/Dijkstra/data.rb +41 -14
  5. data/Examples/Dijkstra/dijkstra.rb +4 -3
  6. data/Examples/MoneyTransfer.rb +61 -60
  7. data/Examples/greeter.rb +8 -7
  8. data/Examples/meter.rb +35 -29
  9. data/Gemfile +9 -4
  10. data/LICENSE.txt +21 -21
  11. data/README.md +13 -0
  12. data/Rakefile +41 -1
  13. data/Test/Generate/method_info_test.rb +12 -0
  14. data/Test/{Greeter_test.rb → Greeter_test_disabled.rb} +24 -20
  15. data/Test/ImmutableQueue_test.rb +18 -0
  16. data/Test/MethodInfo_test.rb +65 -0
  17. data/Test/alltests.rb +1 -0
  18. data/Test/{source_assertions.rb → assertions.rb} +15 -7
  19. data/Test/bind_test.rb +13 -0
  20. data/Test/expression_test.rb +105 -0
  21. data/Test/method_call_test.rb +83 -0
  22. data/Test/self_test.rb +46 -0
  23. data/Test/stack_test.rb +17 -0
  24. data/Test/test_helper.rb +14 -0
  25. data/base/ImmutableStack.rb +32 -0
  26. data/base/MethodDefinition.rb +124 -0
  27. data/base/bind_rewriter.rb +58 -0
  28. data/base/immutable_queue.rb +50 -0
  29. data/base/maroon_base.rb +267 -0
  30. data/base/method_call.rb +78 -0
  31. data/base/method_info.rb +86 -0
  32. data/base/self.rb +60 -0
  33. data/generated/build.rb +13 -0
  34. data/generated/interpretation_context.rb +29 -0
  35. data/lib/Bind.rb +65 -0
  36. data/lib/Context.rb +187 -0
  37. data/lib/ImmutableQueue.rb +50 -0
  38. data/lib/ImmutableStack.rb +38 -0
  39. data/lib/MethodCall.rb +91 -0
  40. data/lib/MethodDefinition.rb +114 -0
  41. data/lib/MethodInfo.rb +78 -0
  42. data/lib/Self.rb +71 -0
  43. data/lib/build.rb +14 -0
  44. data/lib/interpretation_context.rb +30 -0
  45. data/lib/maroon/contracts.rb +43 -0
  46. data/lib/maroon/kernel.rb +2 -0
  47. data/lib/maroon/version.rb +3 -3
  48. data/maroon.gemspec +26 -26
  49. metadata +49 -31
  50. data/lib/Source_cleaner.rb +0 -34
  51. data/lib/maroon.rb +0 -165
  52. 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
@@ -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
@@ -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
@@ -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
@@ -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