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 @@
1
+ `git ls-files`.split($/).grep(%r{(test|spec|features).rb}).select {|f| p f; require_relative("../#{f}")}
@@ -1,13 +1,21 @@
1
- module Source_assertions
1
+ require 'ripper'
2
+ require 'ruby2ruby'
3
+
4
+ module SourceAssertions
2
5
  def assert_source_equal(expected, actual)
3
- expected_sexp = Ripper::sexp expected
4
- actual_sexp = Ripper::sexp actual
5
- assert_sexp_with_ident(expected_sexp, actual_sexp, "Expected #{expected} but got #{actual}")
6
+
7
+ expected_sexp = if expected.instance_of? String then Ripper::sexp expected else expected end
8
+ actual_sexp = if actual.instance_of? String then Ripper::sexp actual else actual end
9
+
10
+ message = "
11
+ Expected: #{expected}
12
+ but got: #{actual}"
13
+ assert_sexp_with_ident(expected_sexp, actual_sexp, message)
6
14
  assert_equal(1,1) #just getting the correct assertion count
7
15
  end
8
16
 
9
17
  def is_terminal(sexp)
10
- sexp == :@ident || sexp == :@int || sexp == :@ivar
18
+ sexp == :@ident || sexp == :@int || sexp == :@ivar || :@tstring_content
11
19
  end
12
20
 
13
21
  def assert_sexp_with_ident(expected, actual, message)
@@ -28,11 +36,11 @@ module Source_assertions
28
36
  if actual[i].instance_of? Array
29
37
  assert_sexp_with_ident(expected[i], actual[i], message)
30
38
  else
31
- assert_fail(message || "the arrays differ at index #{i}. Actual was an element but an array was expected")
39
+ refute(true, message || "the arrays differ at index #{i}. Actual was an element but an array was expected")
32
40
  end
33
41
  else
34
42
  if expected[i] != actual[i]
35
- assert_fail (message || "the arrays differ at index #{i}")
43
+ assert_equal(expected[i],actual[i], message || "the arrays differ at index #{i}")
36
44
  end
37
45
  end
38
46
  end
@@ -0,0 +1,13 @@
1
+ require_relative '../generated/bind'
2
+ require_relative 'test_helper'
3
+
4
+ class Bind_test < MiniTest::Unit::TestCase
5
+ def test_sunny
6
+ block = Sexp.new
7
+ Bind.new(:role, :alias, block).execute
8
+ assert_equal(nil, block[0])
9
+ assert_equal(:@alias, block[1][2][1])
10
+ assert_equal(:role, block[2][2][1])
11
+ assert_equal(:@alias, block.last()[1])
12
+ end
13
+ end
@@ -0,0 +1,105 @@
1
+ require_relative '../generated/MethodDefinition'
2
+ require_relative 'test_helper'
3
+ require 'ripper'
4
+
5
+ class Expression_test < MiniTest::Unit::TestCase
6
+ include SourceAssertions
7
+ def get_context
8
+ contracts = {}
9
+ roles = {:foo=>{:bar=>nil},:baz=>{:rolemethod=>nil},:role=>{}}
10
+ aliases = {}
11
+ InterpretationContext.new(roles,contracts,aliases,:role)
12
+ end
13
+ def assert_transform(expected,block)
14
+ raise "No block" unless block
15
+
16
+ ctx = get_context
17
+ md = MethodDefinition.new(block,ctx)
18
+ md.transform
19
+
20
+ assert_source_equal(expected,block)
21
+ ctx
22
+ end
23
+ def test_method_call
24
+ block = (get_sexp { baz.rolemethod })[3]
25
+
26
+ expected = (get_sexp { self_baz_rolemethod })[3]
27
+
28
+ assert_transform(expected,block)
29
+ end
30
+ def test_index
31
+ block = (get_sexp do
32
+ self[0]
33
+ end)[3]
34
+ expected = (get_sexp do
35
+ role[0]
36
+ end)[3]
37
+ ctx = assert_transform(expected,block)
38
+ assert_equal(1,ctx.contracts[:role][:[]])
39
+ end
40
+ def test_bind
41
+ block = get_sexp do [].each do |r|
42
+ bind :r=>:foo
43
+ r.bar
44
+ foo.baz
45
+ end
46
+ end
47
+ expected = (get_sexp do
48
+ [].each do |r|
49
+ temp____foo = @foo
50
+ @foo = r
51
+ self_foo_bar
52
+ foo.baz
53
+ @foo = temp____foo
54
+ end
55
+ end)
56
+ assert_transform(expected,block)
57
+ end
58
+
59
+ def test_sunny
60
+ block = get_sexp do
61
+ [].each do |r|
62
+ bind :r => :foo
63
+ r.bar
64
+ r.baz
65
+ baz.rolemethod
66
+ self[boo]
67
+ end
68
+ self[0]
69
+ end
70
+ expected = (get_sexp do
71
+ [].each do |r|
72
+ temp____foo = @foo
73
+ @foo = r
74
+ self_foo_bar
75
+ r.baz
76
+ self_baz_rolemethod
77
+ role[boo]
78
+ @foo = temp____foo
79
+ end
80
+ role[0]
81
+ end)
82
+
83
+ interpretation_context = get_context
84
+ MethodDefinition.new(block,interpretation_context).transform
85
+ assert_source_equal(expected,block)
86
+ contracts = interpretation_context.contracts
87
+ assert_equal(2,contracts.length)
88
+ assert(contracts[:role].has_key? :[])
89
+ assert_equal(1,contracts[:role].length)
90
+ assert(contracts[:foo].has_key? :baz)
91
+ assert_nil(contracts[:baz])
92
+ end
93
+
94
+ def test_nested_lambda
95
+
96
+ block = (get_sexp {lambda {
97
+ lambda {baz.rolemethod}}.call})
98
+
99
+ expected = (get_sexp {lambda {
100
+ lambda {self_baz_rolemethod}}.call})
101
+
102
+ assert_transform(expected,block)
103
+ end
104
+
105
+ end
@@ -0,0 +1,83 @@
1
+ require_relative '../generated/MethodCall'
2
+ require_relative 'test_helper'
3
+
4
+ class Method_call_test < MiniTest::Unit::TestCase
5
+ def get_method_call &b
6
+ exp = get_sexp &b
7
+ exp[3]
8
+ end
9
+ include SourceAssertions
10
+ def test_adding_to_contracts_no_role
11
+ method_call = get_method_call {foo.bar}
12
+
13
+ contracts ={}
14
+ MethodCall.new(method_call, InterpretationContext.new({},contracts,nil,nil)).rewrite_call?
15
+ assert_nil(contracts[nil]) #wasn't a role
16
+ end
17
+
18
+ def test_adding_to_contracts_with_role
19
+ method_call = get_method_call {foo.bar}
20
+
21
+ contracts ={}
22
+ roles = Hash.new
23
+ roles[:foo] = Hash.new
24
+ MethodCall.new(method_call, InterpretationContext.new(roles,contracts,nil,nil)).rewrite_call?
25
+ assert_equal(1,contracts.length)
26
+ assert_equal(1, contracts[:foo].length)
27
+ assert_equal(1, contracts[:foo][:bar])
28
+ end
29
+ def test_role_methods_not_added_to_contracts
30
+ method_call = get_method_call {foo.bar}
31
+
32
+ contracts ={}
33
+ roles = Hash.new
34
+ roles[:foo] = {:bar => nil}
35
+ MethodCall.new(method_call, InterpretationContext.new(roles,contracts,nil,nil)).rewrite_call?
36
+ assert_equal(0,contracts.length)
37
+ assert_source_equal(get_method_call {self_foo_bar},method_call)
38
+ end
39
+
40
+ def test_contract_and_bind
41
+ block =get_sexp do [].each do |r|
42
+ temp____foo = @foo
43
+ @foo = r
44
+ r.bar
45
+ foo.baz
46
+ @foo = temp____foo
47
+ end
48
+ end
49
+
50
+ contracts ={}
51
+ roles = {:foo=> {:bar => nil},:role=>{}}
52
+ methodcall1 = block[3][3][3]
53
+ methodcall2 = block[3][3][4]
54
+ expected1 = get_method_call {self_foo_bar}
55
+ expected2 = get_method_call {foo.baz}
56
+
57
+ MethodCall.new(methodcall1, InterpretationContext.new(roles,contracts,{:r=>:foo},:role)).rewrite_call?
58
+ MethodCall.new(methodcall2, InterpretationContext.new(roles,contracts,{:r=>:foo},:role)).rewrite_call?
59
+
60
+ assert_source_equal(expected2,methodcall2)
61
+ assert_source_equal(expected1,methodcall1)
62
+ assert_equal(1,contracts.length)
63
+ assert_equal(1,contracts[:foo].length)
64
+ assert_equal(1,contracts[:foo][:baz])
65
+ assert_nil(contracts[:bar])
66
+ end
67
+ def test_index_contracts
68
+ methodcall = (get_sexp do
69
+ role[boo]
70
+ end)[3]
71
+
72
+ contracts = {}
73
+ roles = {:foo=>{:bar=>nil},:baz=>{:rolemethod=>nil},:role=>{}}
74
+ aliases = {}
75
+ interpretation_context = InterpretationContext.new(roles,contracts,aliases,:role)
76
+ mc = MethodCall.new(methodcall, interpretation_context)
77
+ mc.rewrite_call?
78
+
79
+ assert_equal(1,contracts.length)
80
+ assert_equal(1,interpretation_context.contracts[:role].length)
81
+ assert_equal(1,interpretation_context.contracts[:role][:[]])
82
+ end
83
+ end
@@ -0,0 +1,46 @@
1
+ require_relative '../generated/self'
2
+ require_relative 'test_helper'
3
+
4
+ require 'ruby2ruby'
5
+
6
+ class Self_test < MiniTest::Unit::TestCase
7
+ include SourceAssertions
8
+ def assert_self(abstract_syntax_tree, defining_role)
9
+ assert_equal(:call,abstract_syntax_tree[0])
10
+ assert_nil(abstract_syntax_tree[1])
11
+ assert_equal(defining_role, abstract_syntax_tree[2])
12
+ assert_instance_of(Sexp,abstract_syntax_tree[3])
13
+ assert_equal(abstract_syntax_tree[3][0], :arglist)
14
+ end
15
+ def interpretation_context
16
+ InterpretationContext.new({:role=>{}},nil,nil,:role)
17
+ end
18
+ def test_sunny
19
+ ast = (get_sexp { self.bar })[3]
20
+
21
+ Self.new(ast[1],interpretation_context).execute
22
+
23
+ expected = (get_sexp { role.bar })[3]
24
+ assert_source_equal(expected,ast)
25
+ end
26
+
27
+ def test_indexer
28
+ ast = (get_sexp {self[0]})[3]
29
+
30
+ Self.new(ast,interpretation_context).execute
31
+
32
+ expected = (get_sexp { role[0] })[3]
33
+ assert_source_equal(expected,ast)
34
+ end
35
+
36
+ def test_as_index
37
+ ast = (get_sexp {bar[self]})[3]
38
+
39
+ Self.new(ast[3],interpretation_context).execute
40
+
41
+ expected = (get_sexp { bar[role] })[3]
42
+ refute_nil(ast)
43
+ refute_equal(0,ast.length)
44
+ assert_source_equal(expected,ast)
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+ require_relative '../generated/ImmutableStack'
3
+
4
+ ImmutableStack.new nil,nil
5
+
6
+ class Stack_Test < Test::Unit::TestCase
7
+
8
+ def test_push_pop
9
+ stack = ImmutableStack.empty.push(1)
10
+ stack = stack.push 2
11
+ f,stack = stack.pop
12
+ s,stack = stack.pop
13
+ assert_equal(2,f)
14
+ assert_equal(1,s)
15
+ assert_equal(stack,ImmutableStack::empty)
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require 'minitest/autorun'
2
+ require 'sourcify'
3
+ require_relative 'assertions'
4
+ require_relative '../generated/interpretation_context'
5
+ #require 'debugger'
6
+
7
+ def get_sexp &b
8
+ begin
9
+ b.to_sexp
10
+ rescue
11
+ puts "failed to get expression"
12
+ end
13
+
14
+ end
@@ -0,0 +1,32 @@
1
+ context :ImmutableStack do
2
+ role :head do
3
+ end
4
+ role :tail do
5
+ end
6
+ pop do
7
+ [@head, @tail]
8
+ end
9
+ push do |element|
10
+ ImmutableStack.new element, self
11
+ end
12
+
13
+ empty self do
14
+ @@empty ||= self.new(nil, nil)
15
+ end
16
+
17
+ each do
18
+ yield head
19
+ t = tail
20
+ while t != ImmutableStack::empty do
21
+ h, t = t.pop
22
+ yield h
23
+ end
24
+ end
25
+
26
+ initialize do |h, t|
27
+ @head = h
28
+ @tail = t
29
+ self.freeze
30
+ end
31
+ end
32
+
@@ -0,0 +1,124 @@
1
+ context :MethodDefinition, :transform do
2
+
3
+ rebind do
4
+ @exp, @expressions = expressions.pop
5
+ @block, @potential_bind = nil
6
+ if @exp && (@exp.instance_of? Sexp) && @exp[0] == :iter
7
+ @exp[1..-1].each do |expr|
8
+ #find the block
9
+ if expr && expr.length && expr[0] == :block
10
+ @block, @potential_bind = expr, expr[1]
11
+ end
12
+ end
13
+ end
14
+ @expressions = if @exp.instance_of? Sexp then
15
+ @expressions.push_array(exp)
16
+ else
17
+ @expressions
18
+ end
19
+ end
20
+
21
+ transform do
22
+ #could have been recursive but the stack depth isn't enough for even simple contexts
23
+ until expressions.empty?
24
+
25
+ block.transform
26
+ if exp && (exp.instance_of? Sexp)
27
+ is_indexer = exp[0] == :call && exp[1] == nil && (exp[2] == :[] || exp[2] == :[]=)
28
+ if (is_indexer || (exp[0] == :self)) && @interpretation_context.defining_role
29
+ Self.new(exp, interpretation_context).execute
30
+ end
31
+ if exp[0] == :call
32
+ MethodCall.new(exp, interpretation_context).rewrite_call?
33
+ end
34
+ end
35
+ rebind
36
+ end
37
+ end
38
+
39
+ initialize do |exp, interpretationcontext|
40
+ no_exp = 'No expression supplied'.to_sym
41
+ no_ctx = 'No interpretation context'.to_sym
42
+
43
+ raise no_exp unless exp
44
+ raise no_ctx unless interpretationcontext
45
+
46
+ @interpretation_context = interpretationcontext
47
+ @expressions = ImmutableQueue::empty.push exp
48
+ rebind
49
+ end
50
+
51
+ role :interpretation_context do
52
+ addalias do |key, value|
53
+ @interpretation_context.role_aliases[key] = value
54
+ end
55
+ end
56
+ role :exp do
57
+ end
58
+ role :expressions do
59
+ empty? do
60
+ expressions == ImmutableQueue::empty
61
+ end
62
+ end
63
+ role :potential_bind do
64
+ is_bind? do
65
+ potential_bind &&
66
+ potential_bind.length &&
67
+ (potential_bind[0] == :call &&
68
+ potential_bind[1] == nil &&
69
+ potential_bind[2] == :bind)
70
+ end
71
+ end
72
+ role :block do
73
+ ##
74
+ #Transforms blocks as needed
75
+ #-Rewrites self in role methods to the role getter
76
+ #-Rewrites binds when needed
77
+ #-Rewrites role method calls to instance method calls on the context
78
+ ##
79
+ transform {
80
+ if block
81
+ if block.transform_bind?
82
+ @expressions.push_array(block[1..-1])
83
+ end
84
+ end
85
+ }
86
+ ##
87
+ #Calls rewrite_block if needed and will return true if the AST was changed otherwise false
88
+ ##
89
+ transform_bind? {
90
+ #check if the first call is a bind call
91
+ potential_bind.is_bind? && block.rewrite
92
+ }
93
+
94
+ rewrite {
95
+ changed = false
96
+ arguments = potential_bind[3]
97
+
98
+ if arguments && arguments[0] == :hash
99
+ block.delete_at 1
100
+ count = (arguments.length-1) / 2
101
+ (1..count).each do |j|
102
+ temp = j * 2
103
+ local = arguments[temp-1][1]
104
+ if local.instance_of? Sexp
105
+ local = local[1]
106
+ end
107
+ raise 'invalid value for role alias' unless local.instance_of? Symbol
108
+ #find the name of the role being bound to
109
+ aliased_role = arguments[temp][1]
110
+ if aliased_role.instance_of? Sexp
111
+ aliased_role = aliased_role[1]
112
+ end
113
+ raise aliased_role.to_s + 'used in binding is an unknown role ' + roles.to_s unless aliased_role.instance_of? Symbol and interpretation_context.roles.has_key? aliased_role
114
+ interpretation_context.addalias local, aliased_role
115
+ #replace bind call with assignment of iteration variable to role field
116
+ Bind.new(local, aliased_role, block).execute
117
+ changed = true
118
+ end
119
+ end
120
+ changed
121
+ }
122
+ end
123
+
124
+ end