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
@@ -0,0 +1,332 @@
1
+
2
+ module Myco
3
+
4
+ class CodeLoader
5
+
6
+ class << self
7
+ attr_accessor :emit_rb # Whether to cache generated ruby code to disk.
8
+ attr_accessor :emit_rbc # Whether to cache rubinius bytecode to disk.
9
+ attr_accessor :precedence # Order of precedence for file types.
10
+ end
11
+ self.emit_rb = false # Do not emit ruby code by default.
12
+ self.emit_rbc = true # Do cache rubinius bytecode by default.
13
+
14
+ # Use cached rubinius bytecode files if they are up to date.
15
+ # Use Myco files otherwise.
16
+ # Use generated ruby files only when Myco files cannot be found or loaded.
17
+ self.precedence = [:rbc, :myco, :rb]
18
+
19
+ # TODO: a more elegant solution than env vars
20
+ # Emit ruby if env var indicates
21
+ # Load from ruby exclusively if env var indicates
22
+ self.emit_rb = true if ENV['MYCO_TO_RUBY'] == 'PRE'
23
+ self.precedence = [:myco] if ENV['MYCO_TO_RUBY'] == 'PRE'
24
+
25
+ # Try to resolve the given file path
26
+ # in the current working directory or in the given load paths.
27
+ def self.resolve_file path, load_paths=[]
28
+ tmp_path = File.expand_path(path)
29
+ use_path = File.file?(tmp_path) && tmp_path
30
+ load_paths.each { |load_path|
31
+ break if use_path
32
+ tmp_path = File.expand_path(path, load_path)
33
+ use_path = File.file?(tmp_path) && tmp_path
34
+ }
35
+
36
+ use_path
37
+ end
38
+
39
+ # Select a loader and file path for the given path,
40
+ # considering the currently selected order of precedence for file types.
41
+ def self.loader_for_file path, load_paths=[]
42
+ use_path = resolve_file(path, load_paths)
43
+
44
+ # TODO: This logic could be refactored to look cleaner
45
+ if use_path
46
+ # Try to find an implementation with higher precedence than :myco
47
+ # With a file that has been modified at least as recently as
48
+ # the resolved file in use_path.
49
+ ref_mtime = File.mtime(use_path)
50
+ precedence.each { |type|
51
+ begin
52
+ if type==:myco
53
+ return loader_for(type, use_path)
54
+ else
55
+ alt_path = use_path + ".#{type}"
56
+ if File.file?(alt_path) && (File.mtime(alt_path) >= ref_mtime)
57
+ return loader_for(type, alt_path)
58
+ end
59
+ end
60
+ rescue NotImplementedError # Skip loader if not implemented
61
+ end
62
+ }
63
+ else
64
+ # Try to find any implementation other than :myco, in precedence order.
65
+ precedence.each { |type|
66
+ if type != :myco
67
+ alt_path = resolve_file(path + ".#{type}", load_paths)
68
+ if alt_path && File.file?(alt_path)
69
+ return loader_for(type, alt_path)
70
+ end
71
+ end
72
+ }
73
+ end
74
+
75
+ raise ArgumentError, "Couldn't resolve file: #{path.inspect} \n" \
76
+ "in load_paths: #{load_paths.inspect}" \
77
+ end
78
+
79
+ # Return a loader of the given type with the given arguments
80
+ def self.loader_for type, *args
81
+ case type
82
+ when :myco; MycoLoader.new(*args)
83
+ when :rbc; BytecodeLoader.new(*args)
84
+ when :rb; RubyLoader.new(*args)
85
+ else; raise NotImplementedError
86
+ end
87
+ end
88
+
89
+ # Load from the given path and load_paths and call
90
+ # under the given ConstantScope, VariableScope, and receiver.
91
+ # If cscope or vscope or receiver are nil, they are pulled from
92
+ # the given call_depth, corresponding to one of the calling frames.
93
+ #
94
+ def self.load path, load_paths=[], call_depth:1, **kwargs
95
+ begin
96
+ loader = loader_for_file(path, load_paths)
97
+ loader.bind_to(call_depth:call_depth+1, **kwargs)
98
+ loader.compile
99
+ loader.emit_rb! if self.emit_rb
100
+ loader.emit_rbc! if self.emit_rbc
101
+ loader.load
102
+ rescue Rubinius::InvalidRBC
103
+ retry
104
+ end
105
+ end
106
+
107
+ class AbstractLoader
108
+ attr_accessor :filename, :line
109
+ attr_accessor :constant_scope, :variable_scope, :receiver
110
+
111
+ attr_accessor :string
112
+ attr_accessor :ast
113
+ attr_accessor :generator
114
+ attr_accessor :compiled_code
115
+ attr_accessor :block_environment
116
+
117
+ def initialize filename, line = 1
118
+ @filename = filename
119
+ @line = line
120
+ end
121
+
122
+ def bind_to cscope:nil, vscope:nil, receiver:nil,
123
+ call_depth:1
124
+ loc = Rubinius::VM.backtrace(call_depth, true).first
125
+ @constant_scope = cscope || loc.constant_scope
126
+ @variable_scope = vscope || loc.variables
127
+ @receiver = receiver || loc.instance_variable_get(:@receiver)
128
+
129
+ self
130
+ end
131
+
132
+ def make_string
133
+ @string = File.read(filename)
134
+ end
135
+
136
+ def make_ast
137
+ @string || make_string
138
+
139
+ parser = parser_type.new(@filename, @line, [])
140
+ ast = parser.parse_string(@string)
141
+
142
+ ast = ast_root_type.new(ast) if ast_root_type
143
+ ast.file = filename.to_sym
144
+ ast.variable_scope = @variable_scope
145
+
146
+ @ast = ast
147
+ end
148
+
149
+ def make_generator
150
+ @ast || make_ast
151
+
152
+ g = generator_type.new
153
+ @ast.bytecode(g)
154
+
155
+ g.close
156
+ g.encode
157
+
158
+ @generator = g
159
+ end
160
+
161
+ def make_compiled_code
162
+ @generator || make_generator
163
+
164
+ code = @generator.package(Rubinius::CompiledCode)
165
+
166
+ @compiled_code = code
167
+ end
168
+
169
+ def make_block_environment
170
+ @compiled_code || make_compiled_code
171
+ code = @compiled_code
172
+
173
+ code.scope = @constant_scope
174
+ script = Rubinius::CompiledCode::Script.new(code, @filename, true)
175
+ script.eval_source = @string
176
+ code.scope.script = script
177
+
178
+ be = Rubinius::BlockEnvironment.new
179
+ be.under_context(@variable_scope, code)
180
+
181
+ @block_environment = be
182
+ end
183
+
184
+ def compile
185
+ @block_environment || make_block_environment
186
+ end
187
+
188
+ def load
189
+ compile
190
+ @block_environment.call_on_instance(@receiver)
191
+ end
192
+
193
+ def emit_rb! filename=nil
194
+ @ast || make_ast
195
+
196
+ filename = emit_filename('.rb', filename)
197
+ return nil unless filename
198
+
199
+ File.open(filename, "w+") { |file| file.write(@ast.to_ruby_code) }
200
+ end
201
+
202
+ def emit_rbc! filename=nil
203
+ @compiled_code || make_compiled_code
204
+
205
+ filename = emit_filename('.rbc', filename)
206
+ return nil unless filename
207
+
208
+ compiled_file_type.dump(
209
+ @compiled_code, filename, Rubinius::Signature, 0
210
+ )
211
+ end
212
+
213
+ def is_rb?; false end
214
+ def is_rbc?; false end
215
+
216
+ private
217
+
218
+ # Return @filename, stripped of any .rbc or .rb file extension
219
+ def myco_filename
220
+ @filename.sub(/\.rbc?$/, '')
221
+ end
222
+
223
+ def mkdir_p dir
224
+ # TODO: do manually, without depending on FileUtils
225
+ require 'fileutils'
226
+ FileUtils.mkdir_p(dir)
227
+ end
228
+
229
+ # Return the filename to emit, or nil if the file is already current
230
+ # relative to modification time of the file at the myco_filename.
231
+ def emit_filename file_ext, override=nil
232
+ if override
233
+ filename = override
234
+ else
235
+ orig_filename = myco_filename
236
+ filename ||= orig_filename + file_ext
237
+
238
+ if File.file?(myco_filename)
239
+ ref_mtime = File.mtime(myco_filename)
240
+ if File.file?(filename) && (File.mtime(filename) >= ref_mtime)
241
+ return nil
242
+ end
243
+ end
244
+ end
245
+
246
+ mkdir_p(File.dirname(filename))
247
+ return filename
248
+ end
249
+ end
250
+
251
+ class MycoLoader < AbstractLoader
252
+ def initialize *args
253
+ # TODO: a more elegant solution than env vars
254
+ raise NotImplementedError if ENV['MYCO_TO_RUBY'] == 'POST'
255
+ super
256
+ end
257
+
258
+ def ast_root_type
259
+ Myco::ToolSet::AST::EvalExpression
260
+ end
261
+
262
+ def parser_type
263
+ Myco::ToolSet::Parser
264
+ end
265
+
266
+ def generator_type
267
+ Myco::ToolSet::Generator
268
+ end
269
+
270
+ def compiled_file_type
271
+ Myco::ToolSet::CompiledFile
272
+ end
273
+ end
274
+
275
+ class RubyLoader < AbstractLoader
276
+ def is_rb?; true end
277
+
278
+ def emit_rb!; nil end
279
+
280
+ def initialize *args
281
+ super *args
282
+ end
283
+
284
+ def ast_root_type
285
+ Rubinius::ToolSets::Runtime::AST::EvalExpression
286
+ end
287
+
288
+ def parser_type
289
+ Rubinius::ToolSets::Runtime::Melbourne
290
+ end
291
+
292
+ def generator_type
293
+ Rubinius::ToolSets::Runtime::Generator
294
+ end
295
+
296
+ def compiled_file_type
297
+ Rubinius::ToolSets::Runtime::CompiledFile
298
+ end
299
+ end
300
+
301
+ class BytecodeLoader < AbstractLoader
302
+ def is_rbc?; true end
303
+
304
+ def emit_rb!; nil end
305
+ def emit_rbc!; nil end
306
+
307
+ def initialize *args
308
+ # TODO: a more elegant solution than env vars
309
+ raise NotImplementedError if ENV['MYCO_TO_RUBY'] == 'POST'
310
+ super
311
+ end
312
+
313
+ def make_compiled_code
314
+ begin
315
+ @compiled_code = primitive_load_file \
316
+ @filename, Rubinius::Signature, Rubinius::RUBY_LIB_VERSION
317
+ rescue Rubinius::InvalidRBC => e
318
+ File.delete @filename
319
+ raise e
320
+ end
321
+ end
322
+
323
+ private
324
+
325
+ def primitive_load_file(path, signature, version)
326
+ Rubinius.primitive :compiledfile_load
327
+ raise Rubinius::InvalidRBC, "Invalid RBC file: #{path}"
328
+ end
329
+ end
330
+ end
331
+
332
+ end
@@ -0,0 +1,83 @@
1
+
2
+ import "../tools/BasicCommand.my"
3
+
4
+ BasicCommand {
5
+ banner: "Usage: myco inoculate [options]"
6
+
7
+ # TODO: move this out of here
8
+ shell: |*a,&b| Kernel.instance_method(:system).bind(self).call(*a,&b)
9
+
10
+ run: |*argv| {
11
+ destinations = options_parse(*argv)
12
+ destinations.size == 1
13
+ |? show_help
14
+ ?? destinations.each |dest| {
15
+ config.dest = dest
16
+
17
+ run_operation(:copy, files(config.source, 'bin'))
18
+ run_operation(:copy, files(config.source, 'lib', '.rb'))
19
+ run_operation(:copy, files(config.source, 'lib', '.my'))
20
+ run_operation(:myrb, files(config.dest, 'lib', '.my'))
21
+
22
+ if(config.verbose) {
23
+ prog = Rubinius::Globals[:"$PROGRAM_NAME"]
24
+ puts("DONE "prog" "ARGV.join(" ")"")
25
+ }
26
+ }
27
+ }
28
+
29
+ run_operation: |opcode, source_list| {
30
+ source_list.each |source| {
31
+ dest = transforms.send(opcode, source)
32
+
33
+ unless(operation_is_unnecessary(source, dest)) {
34
+ if(config.verbose) {
35
+ puts(""opcode.upcase" "source"")
36
+ puts(" => "dest"")
37
+ }
38
+ operations.send(opcode, source, dest)
39
+ }
40
+ }
41
+ }
42
+
43
+ operation_is_unnecessary: |source, dest|
44
+ File.file?(dest) && File.mtime(dest) >= File.mtime(source)
45
+
46
+ files: |prefix, subdir, ext=''| {
47
+ prefix && (subdir = File.join(prefix, subdir))
48
+ Dir.glob(File.join(subdir, "**", "*"ext""))
49
+ }
50
+
51
+ [operations]
52
+
53
+ copy: |source, dest|
54
+ shell("mkdir -p "File.dirname(dest)" && cp "source" "dest"")
55
+ myrb: |source, dest|
56
+ Myco::CodeLoader::MycoLoader.new(source).emit_rb!
57
+
58
+ [transforms]
59
+
60
+ copy: |filename| File.join(config.dest, filename)
61
+ myrb: |filename| ""filename".rb"
62
+
63
+ [config]
64
+
65
+ var source
66
+ var dest
67
+ var verbose
68
+
69
+ [options]
70
+
71
+ "-d": Option {
72
+ description: "The destination directory to clone material into."
73
+ long_form: "--dest"
74
+ argument: "STRING"
75
+ do: |arg| parent.config.dest = arg
76
+ }
77
+
78
+ "-v": Option {
79
+ description: "Show details about material cloning operations."
80
+ long_form: "--verbose"
81
+ do: |arg| parent.config.verbose = true
82
+ }
83
+ }
data/lib/myco/command.my CHANGED
@@ -1,33 +1,33 @@
1
1
 
2
- import "tools/OptionParser.my"
2
+ import "tools/BasicCommand.my"
3
3
 
4
- Object {
5
- var options: OptionParser {
6
- storage results: null
7
-
8
- banner: "Usage: myco [options] [files]"
9
-
10
- [options]
11
-
12
- "-E": Option {
13
- description: "Evaluate a string of declarative Myco"
14
- long_form: "--eval"
15
- argument: "STRING"
16
- do: |arg| Myco.eval(arg)
17
- }
18
-
19
- "-e": Option {
20
- description: "Evaluate a string of procedural Myco inside an Object"
21
- long_form: "--eval-meme"
22
- argument: "STRING"
23
- do: |arg| Myco.eval("Object { on creation: "arg" }")
24
- }
25
- }
4
+ BasicCommand {
5
+ banner: "Usage: myco [subcommand] [options] [files]"
6
+
7
+ on creation: run(*ARGV)
26
8
 
27
9
  run: |*argv| {
28
- files = options.parse(argv)
29
- files.uniq.each |file| { Myco.eval_file(file, [::Dir.pwd]) }
10
+ files = options_parse(*argv)
11
+ files && files.uniq.each |file| { Myco.eval_file(file, [::Dir.pwd]) }
30
12
  }
31
13
 
32
- on creation: run(*ARGV)
14
+ [options]
15
+
16
+ "-E": Option {
17
+ description: "Evaluate a string of declarative Myco"
18
+ long_form: "--eval"
19
+ argument: "STRING"
20
+ do: |arg| Myco.eval(arg)
21
+ }
22
+
23
+ "-e": Option {
24
+ description: "Evaluate a string of procedural Myco inside an Object"
25
+ long_form: "--eval-meme"
26
+ argument: "STRING"
27
+ do: |arg| Myco.eval("Object { on creation: { "arg" } }")
28
+ }
29
+
30
+ [commands]
31
+
32
+ "inoculate": Myco.eval_file("command/inoculate.my")
33
33
  }
@@ -0,0 +1,62 @@
1
+
2
+ ::Myco::BasicDecorators < ::Myco::EmptyObject {
3
+ [decorators]
4
+
5
+ # The 'storage' decorator acts like a set of var decorators
6
+ # TODO: consolidate with 'var'
7
+ storage: Decorator {
8
+ # Create a corresponding "writer" meme to go with this "reader" meme
9
+ apply: |meme| {
10
+ meme.target.declare_meme(:""meme.name"=") |new_value, *args| {
11
+ meme.set_result_for(self, new_value, *args)
12
+ }
13
+ }
14
+
15
+ [transforms]
16
+ cache: true # Enable caching of the value to act as storage
17
+ }
18
+
19
+ # The 'var' decorator creates an instance variable getter and setter:
20
+ var: Decorator {
21
+ [transforms]
22
+ var: true
23
+ }
24
+
25
+ # The 'memoize' decorator enables caching of the result
26
+ memoize: Decorator {
27
+ [transforms]
28
+ cache: true
29
+ }
30
+
31
+ # The 'sclass' decorator makes the component's singleton class the target
32
+ sclass: Decorator {
33
+ [transforms]
34
+ target: |meme| meme.target.singleton_class
35
+ }
36
+
37
+ # The 'before' decorator defines a wrapper that runs before the existing meme
38
+ before: Decorator {
39
+ apply: |meme| {
40
+ orig_meme = meme.target.memes[meme.name]
41
+ wrap_meme = meme.dup
42
+ meme.body = Proc.new |*a,&b| {
43
+ wrap_meme.result_for(self,*a,&b)
44
+ orig_meme.result_for(self,*a,&b)
45
+ }
46
+ }
47
+ }
48
+
49
+ # The 'after' decorator defines a wrapper that runs after the existing meme
50
+ after: Decorator {
51
+ apply: |meme| {
52
+ orig_meme = meme.target.memes[meme.name]
53
+ wrap_meme = meme.dup
54
+ meme.body = Proc.new |*a,&b| {
55
+ result = \
56
+ orig_meme.result_for(self,*a,&b)
57
+ wrap_meme.result_for(self,*a,&b)
58
+ result
59
+ }
60
+ }
61
+ }
62
+ }
@@ -1,46 +1,24 @@
1
1
 
2
- ::Myco::BasicObject < ::Myco::EmptyObject {
2
+ ::Myco::BasicObject < ::Myco::EmptyObject, ::Myco::BasicDecorators {
3
3
  # Basic conditional handling
4
4
  if: |cond, &blk| cond && blk.call
5
5
  unless: |cond, &blk| cond || blk.call
6
6
  switch: |input,comparator=:"=="|
7
7
  Switch.new(input:input, comparator:comparator)
8
8
 
9
+ # TODO: alias more efficiently
10
+ # alias(::Kernel, :raise) raise
11
+ # alias(::Kernel, :loop) loop
12
+ raise: |*args| ::Kernel.instance_method(:raise).bind(self).call(*args)
13
+ loop: |&block| ::Kernel.instance_method(:loop).bind(self).call(&block)
14
+ break: raise(::StopIteration)
15
+
9
16
  puts: |*args| STDOUT.puts(*args)
10
17
  p: |*args| STDOUT.puts(args.map |a| { a.inspect }.join(', '))
11
18
 
12
19
  ruby_require: |arg| Object.send(:require, arg)
13
-
14
- [decorators]
15
-
16
- # The 'var' decorator creates what is effectively an instance variable by:
17
- # 1) enabling caching, keeping the given block from being re-run,
18
- # unless run from an inheriting object (which would get its own "copy")
19
- # 2) TODO: prohibiting sending of any arguments
20
- # 3) creating a "writer" function in addition to the "reader"
21
- var: Decorator {
22
- # Create a corresponding "writer" meme to go with this "reader" meme
23
- apply: |meme| {
24
- meme.target.declare_meme(:""meme.name"=") |new_value| {
25
- meme.set_result_for(self, new_value)
26
- }
27
- }
28
-
29
- [transforms]
30
- cache: true # Enable caching of the value to act as storage
31
- }
32
-
33
- # The 'storage' decorator acts like a set of var decorators
34
- # TODO: consolidate with 'var'
35
- storage: Decorator {
36
- # Create a corresponding "writer" meme to go with this "reader" meme
37
- apply: |meme| {
38
- meme.target.declare_meme(:""meme.name"=") |new_value, *args| {
39
- meme.set_result_for(self, new_value, *args)
40
- }
41
- }
42
-
43
- [transforms]
44
- cache: true # Enable caching of the value to act as storage
45
- }
46
20
  }
21
+
22
+ # Because ::Myco::Instance is a ::BasicObject, we must shadow ::BasicObject here
23
+ ::Myco::Instance::BasicObject: ::Myco::BasicObject
24
+
@@ -13,6 +13,7 @@
13
13
  self .? name(meme) .tap |x| { meme.name = x }
14
14
  self .? body(meme) .tap |x| { meme.body = x }
15
15
  self .? cache(meme) .tap |x| { meme.cache = x }
16
+ self .? var(meme) .tap |x| { meme.var = x }
16
17
  self .? expose(meme) .tap |x| { meme.expose = x }
17
18
  }
18
19
  }
@@ -11,9 +11,6 @@
11
11
  # importing the constants defined therein into the current namespace.
12
12
  import: Decorator {
13
13
  apply: |meme, *args| {
14
- # TODO: shouldn't have to use meme.target here;
15
- # should be able to use 'parent' to reach the outer objects
16
- # while still referring to distinct instances rather than the originals.
17
14
  load_paths = [meme.target.instance.dirname]
18
15
  scope = meme.target.constant_scope
19
16
  component = Myco.eval_file(meme.name.to_s, load_paths, false, scope)
@@ -0,0 +1,4 @@
1
+
2
+ Myco << {
3
+ sclass foo: 88
4
+ }
@@ -3,10 +3,12 @@
3
3
  # Send the named signal to all handlers for this object
4
4
  __signal__: |name, *args, &block| {
5
5
  component.ancestors.reverse.each |other| {
6
- inst = (component == other) && self || other.instance
7
- inst.?decorators.?on.?signal_handlers(name).each |meme| {
8
- meme.result_for(self, *args, &block)
9
- }
6
+ other.is_a?(Component) && (
7
+ inst = (component == other) &? self ?? other.instance
8
+ inst.?decorators.?on.?signal_handlers(name).each |meme| {
9
+ meme.result_for(self, *args, &block)
10
+ }
11
+ )
10
12
  }
11
13
  }
12
14
 
data/lib/myco/eval.rb CHANGED
@@ -2,7 +2,8 @@
2
2
  module Myco
3
3
 
4
4
  # Most of method is stolen from Rubinius implementation of Kernel#eval
5
- def self.eval(string, scope=nil, filename=nil, lineno=nil)
5
+ # TODO: remove in favor of CodeLoader
6
+ def self.eval(string, scope=nil, filename=nil, lineno=nil, type=:myco)
6
7
  string = StringValue(string)
7
8
  filename = StringValue(filename) if filename
8
9
  lineno = Rubinius::Type.coerce_to lineno, Fixnum, :to_i if lineno
@@ -20,34 +21,32 @@ module Myco
20
21
  existing_scope = binding.constant_scope
21
22
  binding.constant_scope = existing_scope.dup
22
23
 
23
- c = Myco::ToolSet::Compiler
24
- be = c.construct_block string, binding, filename, lineno
24
+ compiler_class = case type
25
+ when :myco; Myco::ToolSet::Compiler
26
+ when :ruby; Rubinius::ToolSets::Runtime::Compiler
27
+ else; raise NotImplementedError
28
+ end
29
+
30
+ be = compiler_class.construct_block string, binding, filename, lineno
25
31
 
26
32
  result = be.call_on_instance(binding.self)
27
33
  binding.constant_scope = existing_scope
28
34
  result
29
35
  end
30
36
 
31
- # TODO: replace with proper import set of functions
37
+ # TODO: deprecate with proper import set of functions
32
38
  def self.eval_file path, load_paths=nil, get_last=true, scope=nil
33
39
  load_paths ||= [File.dirname(Rubinius::VM.backtrace(1).first.file)]
34
-
35
- tmp_path = File.expand_path(path)
36
- use_path = File.file?(tmp_path) && tmp_path
37
- load_paths.each do |load_path|
38
- break if use_path
39
- tmp_path = File.expand_path(path, load_path)
40
- use_path = File.file?(tmp_path) && tmp_path
41
- end
42
-
43
- raise ArgumentError, "Couldn't resolve file: #{path.inspect} \n" \
44
- "in load_paths: #{load_paths.inspect}" \
45
- unless use_path
46
-
47
- file_toplevel = Myco.eval File.read(use_path), scope, use_path, 1
40
+ file_toplevel = CodeLoader.load(path, load_paths, cscope:scope, call_depth:1)
48
41
  get_last ? file_toplevel.component.__last__ : file_toplevel.component
49
42
  end
50
43
 
44
+ def self.file_to_ruby use_path
45
+ parser = Myco::ToolSet::Parser.new(use_path, 1, [])
46
+ ast = parser.parse_string File.read(use_path)
47
+ ast.to_ruby_code
48
+ end
49
+
51
50
  def self.rescue
52
51
  begin
53
52
  yield