myco 0.1.0.dev → 0.1.0

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