maroon 0.6.1 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
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