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
@@ -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