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.
- checksums.yaml +7 -7
- data/LICENSE +1 -1
- data/README.md +79 -0
- data/lib/myco/backtrace.rb +1 -1
- data/lib/myco/bootstrap/component.rb +78 -39
- data/lib/myco/bootstrap/find_constant.rb +12 -1
- data/lib/myco/bootstrap/instance.rb +5 -12
- data/lib/myco/bootstrap/meme.rb +176 -28
- data/lib/myco/bootstrap.my +8 -7
- data/lib/myco/code_loader.rb +332 -0
- data/lib/myco/command/inoculate.my +83 -0
- data/lib/myco/command.my +26 -26
- data/lib/myco/core/BasicDecorators.my +62 -0
- data/lib/myco/core/BasicObject.my +12 -34
- data/lib/myco/core/Decorator.my +1 -0
- data/lib/myco/core/FileToplevel.my +0 -3
- data/lib/myco/core/Myco.my +4 -0
- data/lib/myco/core/Object.my +6 -4
- data/lib/myco/eval.rb +17 -18
- data/lib/myco/misc.rb +16 -0
- data/lib/myco/parser/ast/argument_assembly.rb +76 -0
- data/lib/myco/parser/ast/array_assembly.rb +57 -0
- data/lib/myco/parser/ast/branch_operator.rb +73 -0
- data/lib/myco/parser/ast/constant_access.rb +4 -18
- data/lib/myco/parser/ast/constant_define.rb +3 -3
- data/lib/myco/parser/ast/constant_reopen.rb +12 -13
- data/lib/myco/parser/ast/declare_category.rb +8 -6
- data/lib/myco/parser/ast/declare_decorator.rb +4 -4
- data/lib/myco/parser/ast/declare_file.rb +4 -4
- data/lib/myco/parser/ast/declare_meme.rb +53 -11
- data/lib/myco/parser/ast/declare_object.rb +9 -7
- data/lib/myco/parser/ast/declare_string.rb +5 -5
- data/lib/myco/parser/ast/invoke.rb +18 -36
- data/lib/myco/parser/ast/invoke_method.rb +28 -0
- data/lib/myco/parser/ast/local_variable_access_ambiguous.rb +9 -13
- data/lib/myco/parser/ast/misc.rb +128 -33
- data/lib/myco/parser/ast/myco_module_scope.rb +26 -0
- data/lib/myco/parser/ast/quest.rb +3 -3
- data/lib/myco/parser/ast/to_ruby/array_assembly.rb +15 -0
- data/lib/myco/parser/ast/to_ruby/block.rb +14 -0
- data/lib/myco/parser/ast/to_ruby/block_pass.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/branch_operator.rb +9 -0
- data/lib/myco/parser/ast/to_ruby/constant_access.rb +10 -0
- data/lib/myco/parser/ast/to_ruby/constant_assignment.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/constant_define.rb +9 -0
- data/lib/myco/parser/ast/to_ruby/constant_reopen.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/declare_category.rb +7 -0
- data/lib/myco/parser/ast/to_ruby/declare_decorator.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/declare_file.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/declare_meme.rb +16 -0
- data/lib/myco/parser/ast/to_ruby/declare_object.rb +8 -0
- data/lib/myco/parser/ast/to_ruby/declare_string.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/dynamic_string.rb +14 -0
- data/lib/myco/parser/ast/to_ruby/dynamic_symbol.rb +7 -0
- data/lib/myco/parser/ast/to_ruby/eval_expression.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/false_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/hash_literal.rb +16 -0
- data/lib/myco/parser/ast/to_ruby/invoke.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/invoke_method.rb +35 -0
- data/lib/myco/parser/ast/to_ruby/iter.rb +10 -0
- data/lib/myco/parser/ast/to_ruby/local_variable_access_ambiguous.rb +16 -0
- data/lib/myco/parser/ast/to_ruby/local_variable_assignment.rb +8 -0
- data/lib/myco/parser/ast/to_ruby/myco_module_scope.rb +8 -0
- data/lib/myco/parser/ast/to_ruby/null_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/parameters.rb +60 -0
- data/lib/myco/parser/ast/to_ruby/quest.rb +13 -0
- data/lib/myco/parser/ast/to_ruby/return.rb +7 -0
- data/lib/myco/parser/ast/to_ruby/scoped_constant.rb +11 -0
- data/lib/myco/parser/ast/to_ruby/self.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/splat_value.rb +33 -0
- data/lib/myco/parser/ast/to_ruby/string_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/symbol_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/toplevel_constant.rb +11 -0
- data/lib/myco/parser/ast/to_ruby/true_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby/void_literal.rb +6 -0
- data/lib/myco/parser/ast/to_ruby.rb +138 -0
- data/lib/myco/parser/ast.rb +6 -0
- data/lib/myco/parser/peg_parser.rb +361 -181
- data/lib/myco/parser.rb +27 -11
- data/lib/myco/tools/BasicCommand.my +42 -0
- data/lib/myco/tools/Generator.my +18 -0
- data/lib/myco/toolset.rb +0 -3
- data/lib/myco/version.rb +1 -4
- data/lib/myco.rb +2 -0
- metadata +230 -160
- data/lib/myco/parser/builder.output +0 -3995
- data/lib/myco/parser/builder.racc +0 -585
- data/lib/myco/parser/builder.rb +0 -1592
- data/lib/myco/parser/lexer.rb +0 -2306
- data/lib/myco/parser/lexer.rl +0 -393
- data/lib/myco/parser/lexer_char_classes.rl +0 -56
- data/lib/myco/parser/lexer_common.rb +0 -95
- data/lib/myco/parser/lexer_skeleton.rl +0 -154
- data/lib/myco/parser/peg_parser.kpeg +0 -759
- data/lib/myco/tools/OptionParser.my +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
5
|
-
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
+
```
|
data/lib/myco/backtrace.rb
CHANGED
@@ -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.
|
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
|
-
|
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 =
|
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 = {
|
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
|
-
|
66
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
data/lib/myco/bootstrap/meme.rb
CHANGED
@@ -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 :
|
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
|
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
|
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
|
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
|
-
|
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
|
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
|
141
|
-
|
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
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|
data/lib/myco/bootstrap.my
CHANGED
@@ -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",
|
8
|
-
Myco.eval_file("core/
|
9
|
-
Myco.eval_file("core/
|
10
|
-
Myco.eval_file("core/
|
11
|
-
Myco.eval_file("core/
|
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",
|
15
|
+
Myco.eval_file("core/Switch.my", [Myco::CoreLoadPath])
|
15
16
|
@@@
|