maroon 0.7.1 → 0.8.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -6
  3. data/Rakefile +3 -3
  4. data/Test/Context_test.rb +16 -16
  5. data/{Examples/Dijkstra → Test/Examples}/CalculateShortestDistance.rb +11 -13
  6. data/Test/Examples/MoneyTransfer_test.rb +76 -0
  7. data/{Examples/Dijkstra → Test/Examples}/calculate_shortest_path.rb +77 -89
  8. data/{Examples/Dijkstra → Test/Examples}/data.rb +0 -0
  9. data/{Examples/Dijkstra/dijkstra.rb → Test/Examples/dijkstra_test.rb} +34 -24
  10. data/Test/Examples/greeter_test.rb +48 -0
  11. data/{Examples/meter.rb → Test/Examples/meter_test.rb} +44 -30
  12. data/Test/abstract_syntax_tree_test.rb +17 -26
  13. data/Test/alltests.rb +1 -1
  14. data/Test/test_helper.rb +2 -0
  15. data/base/AbstractSyntaxTree.rb +24 -3
  16. data/base/ImmutableStack.rb +1 -1
  17. data/base/dependency_graph.rb +94 -0
  18. data/base/immutable_queue.rb +1 -1
  19. data/base/maroon_base.rb +50 -11
  20. data/base/transfomer.rb +196 -197
  21. data/generated/Tokens.rb +64 -2
  22. data/generated/build.rb +1 -3
  23. data/generated/maroon/kernel.rb +7 -0
  24. data/lib/AbstractSyntaxTree.rb +120 -0
  25. data/lib/AstRewritter.rb +53 -58
  26. data/lib/Context.rb +104 -126
  27. data/lib/DependencyGraph.rb +76 -0
  28. data/lib/ImmutableQueue.rb +28 -39
  29. data/lib/ImmutableStack.rb +20 -34
  30. data/lib/Tokens.rb +64 -2
  31. data/lib/Transformer.rb +125 -165
  32. data/lib/build.rb +2 -4
  33. data/lib/maroon/kernel.rb +1 -1
  34. data/lib/maroon/version.rb +1 -1
  35. metadata +13 -11
  36. data/Examples/MoneyTransfer.rb +0 -62
  37. data/Examples/greeter.rb +0 -46
  38. data/Test/Greeter_test_disabled.rb +0 -203
  39. data/lib/Production.rb +0 -149
@@ -1,6 +1,11 @@
1
1
  class Tokens
2
2
  def self.define_token(name)
3
- class_eval("@@#{name} = Tokens.new :#{name};def Tokens.#{name};@@#{name};end")
3
+ class_eval %{
4
+ @#{name} = Tokens.new :#{name};
5
+ def Tokens.#{name}
6
+ @#{name}
7
+ end
8
+ }
4
9
  end
5
10
 
6
11
  def to_s
@@ -21,4 +26,61 @@ class Tokens
21
26
  define_token :indexer
22
27
  define_token :block
23
28
  define_token :block_with_bind
24
- end
29
+ define_token :initializer
30
+ define_token :const
31
+ end
32
+
33
+ class DependencyGraphModel
34
+
35
+ def initialize(dependencies)
36
+ @dependencies = dependencies
37
+ end
38
+
39
+ def to_hash
40
+ @dependecies
41
+ end
42
+
43
+ def to_s
44
+ print_dependencies @dependencies,0
45
+ end
46
+
47
+ def to_dot
48
+ res = ''
49
+ dependencies = denormalize @dependencies
50
+ dependencies.each{|d| res << d.reverse.join('->') << '
51
+ '}
52
+ 'digraph g{
53
+ ' + res + '}'
54
+ end
55
+
56
+ private
57
+ def print_dependencies(dependencies,indent)
58
+ res = ''
59
+ dependencies.each do |key,value|
60
+ res << key.to_s
61
+ if value.instance_of? Hash
62
+ res << '->' << (print_dependencies value,indent != nil ? indent+4 : nil)
63
+ elsif
64
+ res << ':' << value.to_s + '
65
+ '
66
+ indent.times {res << ' '} unless indent == nil
67
+ end
68
+ res << '
69
+ '
70
+ end
71
+ res
72
+ end
73
+
74
+ def denormalize(dependencies)
75
+ res = []
76
+ dependencies.each do |key,value|
77
+ if value.instance_of? Hash
78
+ res = denormalize value
79
+ res.each{|a| a << key}
80
+ else
81
+ res << [key]
82
+ end
83
+ end
84
+ res
85
+ end
86
+ end
@@ -9,6 +9,4 @@ require_relative './interpretation_context'
9
9
  require_relative './AbstractSyntaxTree'
10
10
  require_relative './AstRewritter'
11
11
  require_relative './Transformer'
12
-
13
-
14
-
12
+ require_relative './DependencyGraph'
@@ -0,0 +1,7 @@
1
+ require_relative '../Context'
2
+
3
+ unless Kernel::methods.detect { |m| m== :context }
4
+ def context(*args, &b)
5
+ Context.define *args, &b
6
+ end
7
+ end
@@ -0,0 +1,120 @@
1
+ class AbstractSyntaxTree
2
+ def initialize(ast,interpretation_context) rebind(ImmutableQueue.empty.push(ast), interpretation_context) end
3
+ def type() case
4
+ when (nil == production) then
5
+ nil
6
+ when self_production_is_block_with_bind? then
7
+ Tokens.block_with_bind
8
+ when self_production_is_block? then
9
+ Tokens.block
10
+ when (production.instance_of?(Fixnum) or production.instance_of?(Symbol)) then
11
+ Tokens.terminal
12
+ when self_production_is_rolemethod_call? then
13
+ Tokens.rolemethod_call
14
+ when self_production_is_role? then
15
+ Tokens.role
16
+ when self_production_is_indexer? then
17
+ Tokens.indexer
18
+ when self_production_is_const? then
19
+ Tokens.const
20
+ when self_production_is_initializer? then
21
+ Tokens.initializer
22
+ when self_production_is_call? then
23
+ Tokens.call
24
+ else
25
+ Tokens.other
26
+ end end
27
+ def [](i) @production[i] end
28
+ def []=(i,v) @production[i] = v end
29
+ def length() @production.length end
30
+ def last() @production.last end
31
+ def first() @production.first end
32
+ def data() return @data if @data
33
+ @data = case
34
+ when self_production_is_call? then
35
+ @production[2]
36
+ else
37
+ @production
38
+ end
39
+ end
40
+ def each_production() yield(self)
41
+ if production.instance_of?((Sexp or production.instance_of?(Array))) then
42
+ @queue = @queue.push_array(production)
43
+ end
44
+ while @queue.!=(ImmutableQueue.empty) do
45
+ rebind(@queue, @interpretation_context)
46
+ yield(self)
47
+ if production.instance_of?((Sexp or production.instance_of?(Array))) then
48
+ @queue = @queue.push_array(production)
49
+ end
50
+ end
51
+ end
52
+ private
53
+ def rebind(queue,ctx) @data = nil
54
+ @production, @queue = queue.pop
55
+ @interpretation_context = ctx
56
+ end
57
+ def self_production_is_role?() case
58
+ when (self_production_is_call? and interpretation_context.roles.has_key?(production[2])) then
59
+ @data = [production[2]]
60
+ return true
61
+ when (((production == :self) or ((self_production_is_indexer? and ((production[1] == nil) or (production[1] == :self))) or (production and ((production.instance_of?(Sexp) or production.instance_of?(Array)) and (production[0] == :self))))) and @interpretation_context.defining_role) then
62
+ @data = @interpretation_context.defining_role
63
+ return true
64
+ else
65
+ false
66
+ end end
67
+ def self_production_is_indexer?() self_production_is_call? and ((production[2] == :[]) or (production[2] == :[]=)) end
68
+ def self_production_is_call?() production and ((production.instance_of?(Sexp) or production.instance_of?(Array)) and (production[0] == :call)) end
69
+ def self_production_is_block?() production and ((production.instance_of?(Sexp) or production.instance_of?(Array)) and (production[0] == :iter)) end
70
+ def self_production_is_block_with_bind?() if self_production_is_block? then
71
+ body = @production.last
72
+ if body and exp = body[1] then
73
+ bind = AbstractSyntaxTree.new(exp, @interpretation_context)
74
+ if (bind.type == Tokens.call) and (bind.data == :bind) then
75
+ aliases = {}
76
+ list = exp.last[(1..-1)]
77
+ (list.length / 2).times do |i|
78
+ local = list[(i * 2)].last
79
+ role_name = list[((i * 2) + 1)].last
80
+ raise("Local in bind should be a symbol") unless local.instance_of?(Symbol)
81
+ unless role_name.instance_of?(Symbol) then
82
+ raise("Role name in bind should be a symbol")
83
+ end
84
+ aliases[local] = role_name
85
+ end
86
+ @data = aliases
87
+ true
88
+ end
89
+ end
90
+ end end
91
+ def self_production_is_const?() if production.instance_of?(Sexp) and ((production.length == 2) and ((production[0] == :const) and production[1].instance_of?(Symbol))) then
92
+ @data = [production[1]]
93
+ true
94
+ else
95
+ false
96
+ end end
97
+ def self_production_is_initializer?() if self_production_is_call? then
98
+ if (AbstractSyntaxTree.new(production[1], @interpretation_context).type == Tokens.const) then
99
+ return true if (production[2] == :new)
100
+ end
101
+ end
102
+ false
103
+ end
104
+ def self_production_is_rolemethod_call?() can_be = self_production_is_call?
105
+ if can_be then
106
+ instance = AbstractSyntaxTree.new(production[1], @interpretation_context)
107
+ can_be = (instance.type == Tokens.role)
108
+ if can_be then
109
+ instance_data = instance.data[0]
110
+ role = @interpretation_context.roles[instance_data]
111
+ data = production[2]
112
+ can_be = role.has_key?(data)
113
+ @data = [data, instance_data]
114
+ end
115
+ end
116
+ can_be
117
+ end
118
+ attr_reader :interpretation_context, :queue, :production
119
+
120
+ end
@@ -1,65 +1,60 @@
1
1
  class AstRewritter
2
- def initialize(ast, interpretation_context)
3
- @ast = Production.new(ast, interpretation_context)
4
- @roles = interpretation_context.roles
5
- end
6
-
7
- def rewrite!()
8
- ast.each do |production|
9
- case production.type
10
- when Tokens.rolemethod_call then
11
- data = production.data
12
- production[2] = ((("self_" + data[1].to_s) + "_") + data[0].to_s).to_sym
13
- production[1] = nil
14
- when Tokens.block_with_bind then
15
- block = production.last
16
- block.delete_at(1)
17
- production.data.each do |local, aliased_role|
18
- must_b_sym = "aliased_role must be a Symbol".to_sym
19
- local_must_b_sym = "local must be a Symbol".to_sym
20
- raise(must_b_sym) unless aliased_role.instance_of?(Symbol)
21
- raise(local_must_b_sym) unless local.instance_of?(Symbol)
22
- unless @roles.has_key?(aliased_role) then
23
- role_names = []
24
- @interpretation_context.each { |k, v| (role_names << k.to_s) }
25
- raise(((aliased_role.to_s + " is not a role. Available roles are ") + role_names.join(",")))
26
- end
27
- aliased_field = ("@" + aliased_role.to_s).to_sym
28
- temp_symbol = ("temp____" + aliased_role.to_s).to_sym
29
- assignment = Sexp.new
30
- assignment[0] = :iasgn
31
- assignment[1] = aliased_field
32
- load_arg = Sexp.new
33
- load_arg[0] = :lvar
34
- load_arg[1] = local
35
- assignment[2] = load_arg
36
- block.insert(1, assignment)
37
- assignment = Sexp.new
38
- assignment[0] = :lasgn
39
- assignment[1] = temp_symbol
40
- load_field = Sexp.new
41
- load_field[0] = :ivar
42
- load_field[1] = aliased_field
43
- assignment[2] = load_field
44
- block.insert(1, assignment)
45
- assignment = Sexp.new
46
- assignment[0] = :iasgn
47
- assignment[1] = aliased_field
48
- load_temp = Sexp.new
49
- load_temp[0] = :lvar
50
- load_temp[1] = temp_symbol
51
- assignment[2] = load_temp
52
- block[block.length] = assignment
53
- end
54
- else
55
- # do nothing
2
+ def initialize(ast,interpretation_context) @ast = AbstractSyntaxTree.new(ast, interpretation_context)
3
+ @roles = interpretation_context.roles
4
+ end
5
+ def rewrite!() ast.each_production do |production|
6
+ case production.type
7
+ when Tokens.rolemethod_call then
8
+ data = production.data
9
+ production[2] = ((("self_" + data[1].to_s) + "_") + data[0].to_s).to_sym
10
+ production[1] = nil
11
+ when Tokens.block_with_bind then
12
+ block = production.last
13
+ block.delete_at(1)
14
+ production.data.each do |local, aliased_role|
15
+ must_b_sym = "aliased_role must be a Symbol".to_sym
16
+ local_must_b_sym = "local must be a Symbol".to_sym
17
+ raise(must_b_sym) unless aliased_role.instance_of?(Symbol)
18
+ raise(local_must_b_sym) unless local.instance_of?(Symbol)
19
+ unless @roles.has_key?(aliased_role) then
20
+ role_names = []
21
+ @interpretation_context.each { |k, v| (role_names << k.to_s) }
22
+ raise(((aliased_role.to_s + " is not a role. Available roles are ") + role_names.join(",")))
56
23
  end
24
+ aliased_field = ("@" + aliased_role.to_s).to_sym
25
+ temp_symbol = ("temp____" + aliased_role.to_s).to_sym
26
+ assignment = Sexp.new
27
+ assignment[0] = :iasgn
28
+ assignment[1] = aliased_field
29
+ load_arg = Sexp.new
30
+ load_arg[0] = :lvar
31
+ load_arg[1] = local
32
+ assignment[2] = load_arg
33
+ block.insert(1, assignment)
34
+ assignment = Sexp.new
35
+ assignment[0] = :lasgn
36
+ assignment[1] = temp_symbol
37
+ load_field = Sexp.new
38
+ load_field[0] = :ivar
39
+ load_field[1] = aliased_field
40
+ assignment[2] = load_field
41
+ block.insert(1, assignment)
42
+ assignment = Sexp.new
43
+ assignment[0] = :iasgn
44
+ assignment[1] = aliased_field
45
+ load_temp = Sexp.new
46
+ load_temp[0] = :lvar
47
+ load_temp[1] = temp_symbol
48
+ assignment[2] = load_temp
49
+ block[block.length] = assignment
57
50
  end
51
+ else
52
+ # do nothing
58
53
  end
59
-
60
- private
54
+ end end
55
+ private
61
56
 
62
57
 
63
- attr_reader :ast
58
+ attr_reader :ast
64
59
 
65
- end
60
+ end
@@ -1,133 +1,111 @@
1
1
  class Context
2
- def self.define(*args, &block)
3
- name, base_class, default_interaction = *args
4
- if default_interaction and (not base_class.instance_of?(Class)) then
5
- base_class = eval(base_class.to_s)
6
- end
7
- if base_class and ((not default_interaction) and (not base_class.instance_of?(Class))) then
8
- base_class, default_interaction = default_interaction, base_class
9
- end
10
- @@with_contracts ||= nil
11
- @@generate_file_path ||= nil
12
- ctx = self.send(:create_context_factory, name, base_class, default_interaction, block)
13
- transformer = Transformer.new(name, ctx.roles, ctx.interactions, ctx.private_interactions, base_class, default_interaction)
14
- return transformer.transform(@@generate_file_path, @@with_contracts)
15
- end
16
-
17
- def self.generate_files_in(*args, &b)
18
- @@generate_file_path = args[0]
19
- end
20
-
21
- def roles()
22
- @roles
23
- end
24
-
25
- def interactions()
26
- @interactions
27
- end
28
-
29
- def private_interactions()
30
- @private_interactions
31
- end
32
-
33
- private
34
- def get_definitions(b)
35
- sexp = b.to_sexp
36
- unless is_definition?(sexp[3]) then
37
- sexp = sexp[3]
38
- sexp = sexp.select { |exp| is_definition?(exp) } if sexp
39
- sexp ||= []
40
- end
41
- sexp.select { |exp| is_definition?(exp) }
42
- end
43
-
44
- def self.create_context_factory(name, base_class, default_interaction, block)
45
- ctx = Context.new(name, base_class, default_interaction)
46
- ctx.instance_eval do
47
- sexp = block.to_sexp
48
- temp_block = sexp[3]
49
- i = 0
50
- while (i < temp_block.length) do
51
- exp = temp_block[i]
52
- unless temp_block[(i - 2)] and ((temp_block[(i - 2)][0] == :call) and (temp_block[(i - 1)] and (temp_block[(i - 1)][0] == :args))) then
53
- if ((exp[0] == :defn) or (exp[0] == :defs)) then
54
- add_method(exp)
55
- temp_block.delete_at(i)
56
- i = (i - 1)
57
- else
58
- if (exp[0] == :call) and ((exp[1] == nil) and (exp[2] == :private)) then
59
- @private = true
60
- end
61
- end
2
+ def self.define(*args,&block) name, base_class, default_interaction = *args
3
+ if default_interaction and (not base_class.instance_of?(Class)) then
4
+ base_class = eval(base_class.to_s)
5
+ end
6
+ if base_class and ((not default_interaction) and (not base_class.instance_of?(Class))) then
7
+ base_class, default_interaction = default_interaction, base_class
8
+ end
9
+ @with_contracts ||= nil
10
+ ctx = self.send(:create_context_factory, name, base_class, default_interaction, block)
11
+ if self.generate_dependency_graph then
12
+ dependencies = {}
13
+ ctx.dependencies = DependencyGraphModel.new(DependencyGraph.new(name, ctx.roles, ctx.interactions, dependencies).create!)
14
+ end
15
+ transformer = Transformer.new(name, ctx.roles, ctx.interactions, ctx.private_interactions, base_class, default_interaction)
16
+ ctx.generated_class = transformer.transform(generate_files_in, @with_contracts)
17
+ ctx
18
+ end
19
+ def self.generate_files_in() @generate_files_in end
20
+ def self.generate_files_in=(folder) @generate_files_in = folder end
21
+ def self.generate_code=(value) @generate_code = value end
22
+ def self.generate_dependency_graph=(value) @generate_dependency_graph = value end
23
+ def self.generate_code() (@generate_code or ((not generate_dependency_graph) or generate_files_in)) end
24
+ def self.generate_dependency_graph() @generate_dependency_graph end
25
+ def dependencies() @dependencies end
26
+ def generated_class() @generated_class end
27
+ def dependencies=(value) @dependencies = value end
28
+ def generated_class=(value) @generated_class = value end
29
+ def roles() @roles end
30
+ def interactions() @interactions end
31
+ def private_interactions() @private_interactions end
32
+ private
33
+ def get_definitions(b) sexp = b.to_sexp
34
+ unless is_definition?(sexp[3]) then
35
+ sexp = sexp[3]
36
+ sexp = sexp.select { |exp| is_definition?(exp) } if sexp
37
+ sexp ||= []
38
+ end
39
+ sexp.select { |exp| is_definition?(exp) }
40
+ end
41
+ def self.create_context_factory(name,base_class,default_interaction,block) ctx = Context.new(name, base_class, default_interaction)
42
+ ctx.instance_eval do
43
+ sexp = block.to_sexp
44
+ temp_block = sexp[3]
45
+ i = 0
46
+ while (i < temp_block.length) do
47
+ exp = temp_block[i]
48
+ unless temp_block[(i - 2)] and ((temp_block[(i - 2)][0] == :call) and (temp_block[(i - 1)] and (temp_block[(i - 1)][0] == :args))) then
49
+ if ((exp[0] == :defn) or (exp[0] == :defs)) then
50
+ add_method(exp)
51
+ temp_block.delete_at(i)
52
+ i = (i - 1)
53
+ else
54
+ if (exp[0] == :call) and ((exp[1] == nil) and (exp[2] == :private)) then
55
+ @private = true
62
56
  end
63
- i = (i + 1)
64
57
  end
65
- ctx.instance_eval(&block)
66
- end
67
- ctx
68
- end
69
-
70
- def self.with_contracts(*args)
71
- return @@with_contracts if (args.length == 0)
72
- value = args[0]
73
- if @@with_contracts and (not value) then
74
- raise("make up your mind! disabling contracts during execution will result in undefined behavior")
75
- end
76
- @@with_contracts = value
77
- end
78
-
79
- def is_definition?(exp)
80
- exp and ((exp[0] == :defn) or (exp[0] == :defs))
81
- end
82
-
83
- def role(*args, &b)
84
- role_name = args[0]
85
- @defining_role = role_name
86
- @roles = {} unless @roles
87
- @roles[role_name] = Hash.new
88
- if block_given? then
89
- definitions = get_definitions(b)
90
- definitions.each { |exp| add_method(exp) }
91
- end
92
- end
93
-
94
- def get_methods(*args, &b)
95
- name = args[0]
96
- sources = (@defining_role ? (@roles[@defining_role]) : (@interactions))[name]
97
- if @defining_role and (not sources) then
98
- @roles[@defining_role][name] = []
99
- else
100
- @private_interactions[name] = true if @private
101
- @interactions[name] = []
102
58
  end
59
+ i = (i + 1)
103
60
  end
61
+ ctx.instance_eval(&block)
62
+ end
63
+ ctx
64
+ end
65
+ def self.with_contracts(*args) return @with_contracts if (args.length == 0)
66
+ value = args[0]
67
+ if @with_contracts and (not value) then
68
+ raise("make up your mind! disabling contracts during execution will result in undefined behavior")
69
+ end
70
+ @with_contracts = value
71
+ end
72
+ def is_definition?(exp) exp and ((exp[0] == :defn) or (exp[0] == :defs)) end
73
+ def role(*args,&b) role_name = args[0]
74
+ @defining_role = role_name
75
+ @roles = {} unless @roles
76
+ @roles[role_name] = Hash.new
77
+ if block_given? then
78
+ definitions = get_definitions(b)
79
+ definitions.each { |exp| add_method(exp) }
80
+ end
81
+ end
82
+ def get_methods(*args,&b) name = args[0]
83
+ sources = (@defining_role ? (@roles[@defining_role]) : (@interactions))[name]
84
+ if @defining_role and (not sources) then
85
+ @roles[@defining_role][name] = []
86
+ else
87
+ @private_interactions[name] = true if @private
88
+ @interactions[name] = []
89
+ end
90
+ end
91
+ def add_method(definition) name = if definition[1].instance_of?(Symbol) then
92
+ definition[1]
93
+ else
94
+ ((definition[1].select { |e| e.instance_of?(Symbol) }.map { |e| e.to_s }.join(".") + ".") + definition[2].to_s).to_sym
95
+ end
96
+ sources = get_methods(name)
97
+ (sources << definition)
98
+ end
99
+ def private() @private = true end
100
+ def initialize(name,base_class,default_interaction) @roles = {}
101
+ @interactions = {}
102
+ @private_interactions = {}
103
+ @role_alias = {}
104
+ @name = name
105
+ @base_class = base_class
106
+ @default_interaction = default_interaction
107
+ end
104
108
 
105
- def add_method(definition)
106
- name = if definition[1].instance_of?(Symbol) then
107
- definition[1]
108
- else
109
- ((definition[1].select { |e| e.instance_of?(Symbol) }.map { |e| e.to_s }.join(".") + ".") + definition[2].to_s).to_sym
110
- end
111
- sources = get_methods(name)
112
- (sources << definition)
113
- end
114
-
115
- def private()
116
- @private = true
117
- end
118
-
119
- def initialize(name, base_class, default_interaction)
120
- @roles = {}
121
- @interactions = {}
122
- @private_interactions = {}
123
- @role_alias = {}
124
- @name = name
125
- @base_class = base_class
126
- @default_interaction = default_interaction
127
- end
128
-
129
- attr_reader :name
130
- attr_reader :base_class
131
- attr_reader :default_interaction
109
+ attr_reader :name, :base_class, :default_interaction
132
110
 
133
- end
111
+ end