myco 0.1.0.dev → 0.1.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 (95) hide show
  1. checksums.yaml +7 -7
  2. data/LICENSE +1 -1
  3. data/README.md +79 -0
  4. data/lib/myco/backtrace.rb +1 -1
  5. data/lib/myco/bootstrap/component.rb +78 -39
  6. data/lib/myco/bootstrap/find_constant.rb +12 -1
  7. data/lib/myco/bootstrap/instance.rb +5 -12
  8. data/lib/myco/bootstrap/meme.rb +176 -28
  9. data/lib/myco/bootstrap.my +8 -7
  10. data/lib/myco/code_loader.rb +332 -0
  11. data/lib/myco/command/inoculate.my +83 -0
  12. data/lib/myco/command.my +26 -26
  13. data/lib/myco/core/BasicDecorators.my +62 -0
  14. data/lib/myco/core/BasicObject.my +12 -34
  15. data/lib/myco/core/Decorator.my +1 -0
  16. data/lib/myco/core/FileToplevel.my +0 -3
  17. data/lib/myco/core/Myco.my +4 -0
  18. data/lib/myco/core/Object.my +6 -4
  19. data/lib/myco/eval.rb +17 -18
  20. data/lib/myco/misc.rb +16 -0
  21. data/lib/myco/parser/ast/argument_assembly.rb +76 -0
  22. data/lib/myco/parser/ast/array_assembly.rb +57 -0
  23. data/lib/myco/parser/ast/branch_operator.rb +73 -0
  24. data/lib/myco/parser/ast/constant_access.rb +4 -18
  25. data/lib/myco/parser/ast/constant_define.rb +3 -3
  26. data/lib/myco/parser/ast/constant_reopen.rb +12 -13
  27. data/lib/myco/parser/ast/declare_category.rb +8 -6
  28. data/lib/myco/parser/ast/declare_decorator.rb +4 -4
  29. data/lib/myco/parser/ast/declare_file.rb +4 -4
  30. data/lib/myco/parser/ast/declare_meme.rb +53 -11
  31. data/lib/myco/parser/ast/declare_object.rb +9 -7
  32. data/lib/myco/parser/ast/declare_string.rb +5 -5
  33. data/lib/myco/parser/ast/invoke.rb +18 -36
  34. data/lib/myco/parser/ast/invoke_method.rb +28 -0
  35. data/lib/myco/parser/ast/local_variable_access_ambiguous.rb +9 -13
  36. data/lib/myco/parser/ast/misc.rb +128 -33
  37. data/lib/myco/parser/ast/myco_module_scope.rb +26 -0
  38. data/lib/myco/parser/ast/quest.rb +3 -3
  39. data/lib/myco/parser/ast/to_ruby/array_assembly.rb +15 -0
  40. data/lib/myco/parser/ast/to_ruby/block.rb +14 -0
  41. data/lib/myco/parser/ast/to_ruby/block_pass.rb +6 -0
  42. data/lib/myco/parser/ast/to_ruby/branch_operator.rb +9 -0
  43. data/lib/myco/parser/ast/to_ruby/constant_access.rb +10 -0
  44. data/lib/myco/parser/ast/to_ruby/constant_assignment.rb +6 -0
  45. data/lib/myco/parser/ast/to_ruby/constant_define.rb +9 -0
  46. data/lib/myco/parser/ast/to_ruby/constant_reopen.rb +6 -0
  47. data/lib/myco/parser/ast/to_ruby/declare_category.rb +7 -0
  48. data/lib/myco/parser/ast/to_ruby/declare_decorator.rb +6 -0
  49. data/lib/myco/parser/ast/to_ruby/declare_file.rb +6 -0
  50. data/lib/myco/parser/ast/to_ruby/declare_meme.rb +16 -0
  51. data/lib/myco/parser/ast/to_ruby/declare_object.rb +8 -0
  52. data/lib/myco/parser/ast/to_ruby/declare_string.rb +6 -0
  53. data/lib/myco/parser/ast/to_ruby/dynamic_string.rb +14 -0
  54. data/lib/myco/parser/ast/to_ruby/dynamic_symbol.rb +7 -0
  55. data/lib/myco/parser/ast/to_ruby/eval_expression.rb +6 -0
  56. data/lib/myco/parser/ast/to_ruby/false_literal.rb +6 -0
  57. data/lib/myco/parser/ast/to_ruby/hash_literal.rb +16 -0
  58. data/lib/myco/parser/ast/to_ruby/invoke.rb +6 -0
  59. data/lib/myco/parser/ast/to_ruby/invoke_method.rb +35 -0
  60. data/lib/myco/parser/ast/to_ruby/iter.rb +10 -0
  61. data/lib/myco/parser/ast/to_ruby/local_variable_access_ambiguous.rb +16 -0
  62. data/lib/myco/parser/ast/to_ruby/local_variable_assignment.rb +8 -0
  63. data/lib/myco/parser/ast/to_ruby/myco_module_scope.rb +8 -0
  64. data/lib/myco/parser/ast/to_ruby/null_literal.rb +6 -0
  65. data/lib/myco/parser/ast/to_ruby/parameters.rb +60 -0
  66. data/lib/myco/parser/ast/to_ruby/quest.rb +13 -0
  67. data/lib/myco/parser/ast/to_ruby/return.rb +7 -0
  68. data/lib/myco/parser/ast/to_ruby/scoped_constant.rb +11 -0
  69. data/lib/myco/parser/ast/to_ruby/self.rb +6 -0
  70. data/lib/myco/parser/ast/to_ruby/splat_value.rb +33 -0
  71. data/lib/myco/parser/ast/to_ruby/string_literal.rb +6 -0
  72. data/lib/myco/parser/ast/to_ruby/symbol_literal.rb +6 -0
  73. data/lib/myco/parser/ast/to_ruby/toplevel_constant.rb +11 -0
  74. data/lib/myco/parser/ast/to_ruby/true_literal.rb +6 -0
  75. data/lib/myco/parser/ast/to_ruby/void_literal.rb +6 -0
  76. data/lib/myco/parser/ast/to_ruby.rb +138 -0
  77. data/lib/myco/parser/ast.rb +6 -0
  78. data/lib/myco/parser/peg_parser.rb +361 -181
  79. data/lib/myco/parser.rb +27 -11
  80. data/lib/myco/tools/BasicCommand.my +42 -0
  81. data/lib/myco/tools/Generator.my +18 -0
  82. data/lib/myco/toolset.rb +0 -3
  83. data/lib/myco/version.rb +1 -4
  84. data/lib/myco.rb +2 -0
  85. metadata +230 -160
  86. data/lib/myco/parser/builder.output +0 -3995
  87. data/lib/myco/parser/builder.racc +0 -585
  88. data/lib/myco/parser/builder.rb +0 -1592
  89. data/lib/myco/parser/lexer.rb +0 -2306
  90. data/lib/myco/parser/lexer.rl +0 -393
  91. data/lib/myco/parser/lexer_char_classes.rl +0 -56
  92. data/lib/myco/parser/lexer_common.rb +0 -95
  93. data/lib/myco/parser/lexer_skeleton.rl +0 -154
  94. data/lib/myco/parser/peg_parser.kpeg +0 -759
  95. data/lib/myco/tools/OptionParser.my +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 3da0c78adac1604211cf6cd16c6eacd6e714591c
4
- data.tar.gz: b6444fe6690546c9ed22b96fedc9a3bb1083030e
5
- SHA512:
6
- metadata.gz: e9b05edc6272eee428e038f4fae2b91d73aa83c0dd7e5941c50ec5d457a88d0920fc453826161606d8374d5fae0d9fc8bc3cea6d28bb394d1586ec87cb107195
7
- data.tar.gz: 8b6193c91a85706f18cb09a529e575b571b4895a4e18f9f767b4e43ff525d84f871fd5d422219b28f372bbbcb8972afe275bcc086a4b6b3a895d1501b9896a11
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 417744da4484853e229b10a6f5de25b140e67af1
4
+ data.tar.gz: 9e4e018656fef08864d79948f9ff58731fa33c65
5
+ SHA512:
6
+ metadata.gz: c81eb1fd9f81a6c1c5d02d29929c9922b749e9a6833c6190b88eb996f56ad9d1ed4cb60e3edd276b8bcf6fd0f151634129f4e4754b3f591594b0e600abae0be4
7
+ data.tar.gz: b2db5fe48fd80b3c49aa472ed3dc89d32b3b15ff800f943760a7f36480aa2aef2851832a88cccc1eed40064a48c690471b44e0d9aa12edf27a5dd0df29d4be5e
data/LICENSE CHANGED
@@ -1,2 +1,2 @@
1
- Copyright 2014 Joe McIlvain.
1
+ Copyright 2013-2015 Joe McIlvain.
2
2
  All rights reserved.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+
2
+ ```myco
3
+ Myco < Ruby, QML, Ioke {
4
+ primary author: "Joe Eli McIlvain"
5
+
6
+ latest gem version: 0.1.0
7
+ development status: [:alpha, :experimental]
8
+
9
+ dependency "Rubinius VM": git(:master)
10
+
11
+ development dependency 'bundler': 1.6
12
+ development dependency 'rake': 10.3
13
+ development dependency 'rspec': 3.0
14
+ development dependency 'fivemat': 1.3
15
+
16
+ [features]
17
+
18
+ "innovative declarative syntax layer around a familiar Ruby-like layer"
19
+ "ease of expression of intent" : "consistent but powerful rules"
20
+ todo "runtime parsing rule intercession"
21
+ todo "nested blocks parsed by user parsers"
22
+
23
+ "patterns for a responsibly localized import system": ImportSystemMethods {
24
+ import 'some/library'
25
+ import as(:SomeLibrary) 'some/library'
26
+ private import 'some/library'
27
+ export as(:MyGlobalLibrary) 'my/library'
28
+ arbitrary user_defined import_mechanism 'special/library'
29
+ }
30
+
31
+ "fluid integration with the host Ruby runtime": {
32
+ ruby_require('some_ruby_gem')
33
+ obj = SomeRubyGem::Object.new(1, 2, *rest, foo:8, bar:9)
34
+
35
+ RubyEval """
36
+ Myco::SomeObject.new(foo:8, bar:9)
37
+ """
38
+ }
39
+
40
+ rich support_for(:decorators) in: user_space
41
+
42
+ [decorators]
43
+
44
+ support_for: Decorator {
45
+ apply: |meme|
46
+ arguments.each |feature| { meme.supported_features.push(feature) }
47
+ }
48
+
49
+ rich: Decorator {
50
+ [transforms]
51
+ richness: true
52
+ memoize: true
53
+ }
54
+
55
+ [contributing]
56
+
57
+ Github < RepositoryHost {
58
+ URL: "https://github.com/jemc/myco"
59
+ IssueTracker: URL + "/issues"
60
+ }
61
+
62
+ contributing_process: |user, problem| {
63
+ issue = user.file_bug_report(problem, on: Github::IssueTracker)
64
+
65
+ if(user.can_implement?) {
66
+ pr = PullRequest {
67
+ name: "Fix for issue #"issue.number" - "issue.description"."
68
+ branch: snake_case(issue.name)
69
+ user: user
70
+
71
+ include fix: for(problem)
72
+ include tests: for(fix)
73
+
74
+ user.file_pull_request(pr, on: Github::IssueTracker)
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
@@ -27,7 +27,7 @@ class Myco::Backtrace < Rubinius::Backtrace
27
27
  file_width = file.length + 1 + sbullet.length
28
28
 
29
29
  place = loc.instance_variable_get(:@method_module).to_s + '#'
30
- place += loc.describe_method
30
+ place += loc.method.name.to_s
31
31
  place_width = place.length + 1 + ebullet.length
32
32
 
33
33
  padding = @width - file_width - place_width
@@ -1,12 +1,13 @@
1
1
 
2
2
  module Myco
3
- class Component < Module
3
+ module Component
4
+ include MemeBindable
5
+
4
6
  attr_accessor :__last__
5
7
  attr_accessor :__name__
6
8
 
7
9
  attr_reader :parent
8
10
  attr_reader :parent_meme
9
- attr_reader :memes
10
11
  attr_reader :categories
11
12
 
12
13
  attr_reader :constant_scope
@@ -45,29 +46,36 @@ module Myco
45
46
  line ||= location.line
46
47
  end
47
48
 
48
- this = super()
49
+ this = Class.new Instance
50
+ # TODO: avoid extending here to avoid touching/making the singleton_class
51
+ this.extend self
49
52
 
50
53
  this.instance_eval {
51
54
  @super_components = super_components
52
- @memes = { }
53
55
  @parent = parent
54
56
  @filename = filename
55
57
  @line = line
56
58
  @basename = File.basename @filename
57
59
  @dirname = File.dirname @filename
58
- @categories = { nil => this }
60
+ @categories = { main: this }
59
61
  @parent_meme = parent_meme
60
62
  }
61
63
 
62
64
  all_categories = Hash.new { |h,k| h[k] = Array.new }
63
65
 
64
66
  super_components.each do |other|
65
- this.include other if other
66
- other.categories.each { |name, cat| all_categories[name] << cat }
67
+ raise TypeError, "Got non-Component in supers for new Component: "\
68
+ "#{super_components.inspect}" \
69
+ unless other.is_a? Component
70
+
71
+ this.include other
72
+ other.categories.each do |name, cat|
73
+ all_categories[name] << cat
74
+ end
67
75
  end
68
76
 
69
77
  all_categories.each do |name, supers|
70
- if name.nil?
78
+ if name == :main
71
79
  this.categories[name] = this
72
80
  else
73
81
  this.categories[name] = this.__new_category__ name, supers, filename, line
@@ -77,6 +85,11 @@ module Myco
77
85
  this
78
86
  end
79
87
 
88
+ # Get a reference to the main Component from main or from any inner Category
89
+ def main
90
+ self < Category ? parent : self
91
+ end
92
+
80
93
  def __category__ name
81
94
  @categories[name] ||= __new_category__(name)
82
95
  end
@@ -92,50 +105,76 @@ module Myco
92
105
  category = Component.new super_cats, self, filename, line
93
106
  category.__name__ = name
94
107
  category_instance = category.instance
95
- declare_meme(name) { category_instance }
96
- @memes[name].cache = true
108
+ meme = declare_meme(name) { category_instance }
109
+ meme.cache = true
97
110
 
98
111
  category
99
112
  end
100
113
 
101
- def declare_meme name, decorations=[], body=nil, scope=nil, varscope=nil, &blk
102
- body.scope = scope.dup if scope && body.respond_to?(:scope=)
103
- meme = Meme.new self, name, body, &blk
104
-
105
- decorations.each do |decoration, arguments|
106
- search_component = self<Category ? parent : self
107
- decorators = search_component.categories[:decorators].instance
108
-
109
- raise KeyError, "Unknown decorator for #{self}##{name}: #{decoration}" \
110
- unless decorators.respond_to?(decoration)
111
- decorator = decorators.send(decoration)
112
- decorator.transforms.apply meme, *arguments
113
- decorator.apply meme, *arguments
114
- end
115
- meme.bind
116
-
117
- meme
118
- end
119
-
120
114
  def instance
121
- if !@instance
122
- @instance = Instance.new(self)
123
- @instance.extend self
115
+ if @instance
124
116
  yield @instance if block_given?
125
- @instance.__signal__ :creation if @instance.respond_to? :__signal__
126
117
  else
118
+ @instance = allocate
119
+ @instance.instance_variable_set(:@component, self)
127
120
  yield @instance if block_given?
121
+ @instance.__signal__ :creation if @instance.respond_to? :__signal__
128
122
  end
129
123
 
130
124
  @instance
131
125
  end
132
126
 
133
- def new parent=nil, **kwargs
134
- loc = Rubinius::VM.backtrace(1,false).first
135
-
136
- Component.new([self], parent, loc.file, loc.line).instance { |instance|
137
- kwargs.each { |key,val| instance.send :"#{key}=", val }
138
- }
127
+ # Override Module#include to bypass type checks of others
128
+ def include *others
129
+ others.reverse_each do |other|
130
+ Rubinius::Type.include_modules_from(other, self.origin)
131
+ Rubinius::Type.infect(self, other)
132
+ other.__send__ :included, self
133
+ end
134
+ self
135
+ end
136
+
137
+ # Extend the given object with this component's features
138
+ # Called on object.extend(component)
139
+ def extend_object object
140
+ singleton_class = Rubinius::Type.object_singleton_class(object)
141
+ Rubinius::Type.include_modules_from(self, singleton_class.origin)
142
+ Rubinius::Type.infect(singleton_class, self)
143
+ object
144
+ end
145
+
146
+ # Create a child component of self to act as the component of the object,
147
+ # which is allowed to be a Ruby object (not a Myco::Instance).
148
+ # TODO: re-evaluate usefulness and possibly remove in favor of using extend.
149
+ def inject_into object
150
+ object.extend InstanceMethods unless object.is_a? InstanceMethods
151
+ object.instance_variable_set(:@component, self)
152
+ extend_object object
153
+ object
154
+ end
155
+
156
+ # Create an untracked instance of this component and
157
+ # call setters on the instance with the values given by kwargs.
158
+ def new **kwargs
159
+ instance = allocate
160
+ instance.instance_variable_set(:@component, self)
161
+ kwargs.each { |key,val| instance.send :"#{key}=", val }
162
+ instance
163
+ end
164
+
165
+ # Like module_eval, but it also shifts the ConstantScope of the block
166
+ def component_eval &block
167
+ block_env = block.block
168
+ cscope = Rubinius::ConstantScope.new(self, block_env.constant_scope)
169
+ if defined? ::Myco::FileToplevel && self < ::Myco::FileToplevel
170
+ cscope.set_myco_file
171
+ elsif defined? ::Myco::Category && self < ::Myco::Category
172
+ cscope.set_myco_category
173
+ else
174
+ cscope.set_myco_component
175
+ end
176
+ result = block_env.call_under(self, cscope, true, self)
177
+ result
139
178
  end
140
179
  end
141
180
 
@@ -7,6 +7,11 @@ module Rubinius
7
7
  attr_reader :myco_category
8
8
  attr_reader :myco_meme
9
9
 
10
+ # TODO: Can this be more graceful and more eager?
11
+ def myco_file
12
+ @myco_file ||= parent.myco_file
13
+ end
14
+
10
15
  def myco_levels
11
16
  @myco_levels ||= (parent ? parent.myco_levels.dup : [])
12
17
  end
@@ -51,8 +56,14 @@ end
51
56
 
52
57
  module Myco
53
58
 
54
- def self.find_constant(name, scope)
59
+ # Get the "current" ConstantScope (from the caller's perspective)
60
+ def self.cscope
61
+ Rubinius::ConstantScope.of_sender
62
+ end
63
+
64
+ def self.find_constant(name, scope=nil)
55
65
  name = ::Rubinius::Type.coerce_to_constant_name name
66
+ scope ||= ::Rubinius::ConstantScope.of_sender
56
67
 
57
68
  category = scope.myco_category
58
69
  component = scope.myco_component
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Myco
3
- class Instance < ::BasicObject
3
+ module InstanceMethods
4
4
  include ::Kernel
5
5
 
6
6
  # TODO: clean this up
@@ -24,10 +24,6 @@ module Myco
24
24
  p str
25
25
  end
26
26
 
27
- def initialize component
28
- @component = component
29
- end
30
-
31
27
  attr_reader :component
32
28
 
33
29
  def parent
@@ -41,12 +37,9 @@ module Myco
41
37
  def memes
42
38
  @component.memes
43
39
  end
44
-
45
- # Commandeer a few methods implemented in Kernel
46
- %i{ extend respond_to? method_missing hash }.each do |sym|
47
- define_method sym do |*args, &blk|
48
- ::Kernel.instance_method(sym).bind(self).call(*args)
49
- end
50
- end
40
+ end
41
+
42
+ class Instance < ::BasicObject
43
+ include InstanceMethods
51
44
  end
52
45
  end
@@ -1,13 +1,54 @@
1
1
 
2
2
  module Myco
3
+ module MemeBindable
4
+ def memes
5
+ @memes ||= {}
6
+ end
7
+
8
+ def declare_meme name, decorations=[], body=nil, cscope=nil, &blk
9
+ meme = Meme.new self, name
10
+ if cscope && blk
11
+ body = blk.block.dup
12
+ blk = nil
13
+ body.instance_variable_set(:@constant_scope, cscope)
14
+ end
15
+ meme.body = body || blk
16
+
17
+ decorations = decorations.map do |decoration, arguments|
18
+ decorators = main.categories[:decorators]
19
+ decorators = decorators && decorators.instance
20
+
21
+ unless decorators.respond_to?(decoration)
22
+ reason = if decorators.nil?
23
+ "#{self} has no [decorators] category."
24
+ else
25
+ "Known decorators in #{decorators}: " \
26
+ "#{decorators.component.memes.keys.inspect}."
27
+ end
28
+ raise KeyError,
29
+ "Unknown decorator for #{self}##{name}: '#{decoration}'. #{reason}"
30
+ end
31
+
32
+ [decorators.send(decoration), arguments]
33
+ end
34
+ decorations.each { |deco, args| deco.transforms.apply meme, *args }
35
+ decorations.each { |deco, args| deco.apply meme, *args }
36
+
37
+ meme.bind
38
+
39
+ meme
40
+ end
41
+ end
42
+
3
43
  class Meme
4
44
  attr_accessor :target
5
45
  attr_accessor :name
6
46
  attr_accessor :body
7
47
  attr_accessor :cache
48
+ attr_accessor :var
8
49
  attr_accessor :expose
9
50
 
10
- attr_reader :caches # TODO: don't expose; dynamic meth should send privately
51
+ attr_reader :metadata
11
52
 
12
53
  def to_s
13
54
  "#<#{self.class}:#{self.name.to_s}>"
@@ -20,10 +61,14 @@ module Myco
20
61
  def initialize target, name, body=nil, &blk
21
62
  self.target = target
22
63
  self.name = name
23
- self.body = body || blk
64
+ self.body = body if body
65
+ self.body = blk if blk
24
66
  self.cache = false
67
+ self.var = false
25
68
  self.expose = true
26
69
 
70
+ @metadata = {}
71
+
27
72
  @caches = {}
28
73
  end
29
74
 
@@ -31,33 +76,96 @@ module Myco
31
76
  case value
32
77
  when Rubinius::Executable
33
78
  @body = value
34
- @body.scope.set_myco_meme self # Set meme for lexical scope
79
+ @body.scope.set_myco_meme self
80
+ when Rubinius::BlockEnvironment
81
+ block_env = value
82
+ block_env.change_name name
83
+ block_env.constant_scope.set_myco_meme self
84
+ @body = Rubinius::BlockEnvironment::AsMethod.new block_env
35
85
  when Proc
36
86
  block_env = value.block.dup
37
87
  block_env.change_name name
88
+ block_env.constant_scope.set_myco_meme self \
89
+ unless block_env.constant_scope.myco_meme
38
90
  @body = Rubinius::BlockEnvironment::AsMethod.new block_env
39
- value = value.dup
40
- value.lambda_style!
41
91
  else
42
92
  raise ArgumentError,
43
- "Meme body must be a Rubinius::Executable or a Proc"
93
+ "Meme body must be a Rubinius::Executable, " \
94
+ "Rubinius::BlockEnvironment or a Proc; got: #{value.inspect}"
44
95
  end
45
96
 
97
+ @effective_body = @body
98
+
99
+ bind if @bound
46
100
  @body
47
101
  end
48
102
 
103
+ def target= value
104
+ @target = value
105
+ @target.extend(MemeBindable) unless @target.is_a?(MemeBindable)
106
+ bind if @bound
107
+ @target
108
+ end
109
+
110
+ def cache= value
111
+ @cache = value
112
+ bind if @bound
113
+ @cache
114
+ end
115
+
116
+ def var= value
117
+ @var = value
118
+ bind if @bound
119
+ @var
120
+ end
121
+
122
+ def to_proc
123
+ Proc.__from_block__(@body.block_env)
124
+ end
125
+
49
126
  def bind
127
+ @bound = true
50
128
  return if not @expose
51
129
 
52
- meme = self
53
- target.memes[@name] = meme
130
+ @target.memes[@name] = self
54
131
 
132
+ if @var
133
+ bind_var_getter
134
+ bind_var_setter
135
+ @effective_body = @target.instance_method(@name).executable
136
+ elsif @cache
137
+ bind_cache_method
138
+ @effective_body = @target.instance_method(@name).executable
139
+ else
140
+ Rubinius.add_method @name, @body, @target, :public
141
+ end
142
+ end
143
+
144
+ def result *args, &blk
145
+ result_for target.instance, *args, &blk
146
+ end
147
+
148
+ def result_for obj, *args, &blk
149
+ result = @effective_body.invoke @name, @target, obj, args, blk
150
+ end
151
+
152
+ def set_result_for obj, result, *args, &blk
153
+ raise "Can't set_result_for this Meme" unless @cache
154
+ cache_key = [obj.hash, args.hash, blk.hash]
155
+ @caches[cache_key] = result
156
+ end
157
+
158
+ private
159
+
160
+ def bind_cache_method
55
161
  ##
56
162
  # This dynamic method is nearly the same as Meme#result_for
57
163
  # (but written from the perspective of the receiver)
58
164
  # implemented in bytecode to avoid forwarding to another method
59
165
  # on the call stack.
60
166
  # TODO: move this bytecode generation to a helper method
167
+ meme = self
168
+
61
169
  target.dynamic_method @name, '(myco_internal)' do |g|
62
170
  g.splat_index = 0 # *args
63
171
 
@@ -89,15 +197,10 @@ module Myco
89
197
  g.pop
90
198
 
91
199
  ##
92
- # if meme.cache.false? || !caches.has_key?(cache_key)
200
+ # if caches.has_key?(cache_key)
93
201
  # return caches[cache_key]
94
202
  # end
95
203
  #
96
- g.push_local 1 # meme
97
- g.send :cache, 0
98
- g.send :false?, 0
99
- g.goto_if_true invoke
100
-
101
204
  g.push_local 2 # caches
102
205
  g.push_local 3 # cache_key
103
206
  g.send :has_key?, 1
@@ -137,24 +240,69 @@ module Myco
137
240
  end
138
241
  end
139
242
 
140
- def result *args, &blk
141
- result_for target.instance, *args, &blk
243
+ def bind_var_getter
244
+ # TODO: move this bytecode generation to a helper method
245
+ meme = self
246
+
247
+ target.dynamic_method @name, '(myco_internal)' do |g|
248
+ get = g.new_label
249
+ ret = g.new_label
250
+
251
+ ##
252
+ # meme = <this meme>
253
+ #
254
+ g.push_literal meme
255
+ g.set_local 1 # meme
256
+ g.pop
257
+
258
+ ##
259
+ # if @#{:"__#{@name}_defined__"}
260
+ # @#{name} = meme.body.invoke meme.name, @target, obj, [], nil
261
+ # end
262
+ # return @#{name}
263
+ #
264
+ g.push_ivar(:"__#{@name}_defined__")
265
+ g.goto_if_true(get)
266
+
267
+ g.push_local 1 # meme
268
+ g.send :body, 0
269
+ g.push_local 1; g.send :name, 0 # meme.name
270
+ g.push_local 1; g.send :target, 0 # meme.target
271
+ g.push_self
272
+ g.make_array 0
273
+ g.push_nil
274
+ g.send :invoke, 5
275
+ g.set_ivar(@name)
276
+
277
+ g.push_true
278
+ g.set_ivar(:"__#{@name}_defined__")
279
+ g.pop
280
+ g.goto(ret)
281
+
282
+ get.set!
283
+ g.push_ivar(@name)
284
+
285
+ ret.set!
286
+ g.ret
287
+ end
142
288
  end
143
289
 
144
- def result_for obj, *args, &blk
145
- cache_key = [obj.hash, args.hash, blk.hash]
146
- if @cache && @caches.has_key?(cache_key)
147
- return @caches[cache_key]
290
+ def bind_var_setter
291
+ # TODO: move this bytecode generation to a helper method
292
+ target.dynamic_method :"#{@name}=", '(myco_internal)' do |g|
293
+ g.total_args = 1
294
+ g.local_count = 1
295
+
296
+ g.push_true
297
+ g.set_ivar(:"__#{@name}_defined__")
298
+ g.pop
299
+
300
+ g.push_local 0 # value
301
+ g.set_ivar @name
302
+
303
+ g.ret
148
304
  end
149
-
150
- result = @body.invoke @name, @target, obj, args, blk
151
-
152
- @caches[cache_key] = result
153
305
  end
154
306
 
155
- def set_result_for obj, result, *args, &blk
156
- cache_key = [obj.hash, args.hash, blk.hash]
157
- @caches[cache_key] = result
158
- end
159
307
  end
160
308
  end
@@ -1,15 +1,16 @@
1
1
 
2
- RubyEval < EmptyObject {
2
+ ::Myco::RubyEval < EmptyObject {
3
3
  from_string: |string| ::Kernel.instance_method(:eval).bind(self).call(string)
4
4
  }
5
5
 
6
6
  RubyEval @@@
7
- Myco.eval_file("core/Category.my", [Myco::CoreLoadPath])
8
- Myco.eval_file("core/BasicObject.my", [Myco::CoreLoadPath])
9
- Myco.eval_file("core/Decorator.my", [Myco::CoreLoadPath])
10
- Myco.eval_file("core/Object.my", [Myco::CoreLoadPath])
11
- Myco.eval_file("core/FileToplevel.my", [Myco::CoreLoadPath])
7
+ Myco.eval_file("core/Category.my", [Myco::CoreLoadPath])
8
+ Myco.eval_file("core/BasicDecorators.my", [Myco::CoreLoadPath])
9
+ Myco.eval_file("core/BasicObject.my", [Myco::CoreLoadPath])
10
+ Myco.eval_file("core/Decorator.my", [Myco::CoreLoadPath])
11
+ Myco.eval_file("core/Object.my", [Myco::CoreLoadPath])
12
+ Myco.eval_file("core/FileToplevel.my", [Myco::CoreLoadPath])
12
13
 
13
14
  # Below are not necessary for bootstrapping; TODO: move out of RubyEval
14
- Myco.eval_file("core/Switch.my", [Myco::CoreLoadPath])
15
+ Myco.eval_file("core/Switch.my", [Myco::CoreLoadPath])
15
16
  @@@