myco 0.1.0.dev
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 -0
- data/LICENSE +2 -0
- data/bin/myco +7 -0
- data/lib/myco/backtrace.rb +56 -0
- data/lib/myco/bootstrap/component.rb +142 -0
- data/lib/myco/bootstrap/empty_object.rb +4 -0
- data/lib/myco/bootstrap/file_toplevel.rb +5 -0
- data/lib/myco/bootstrap/find_constant.rb +86 -0
- data/lib/myco/bootstrap/instance.rb +52 -0
- data/lib/myco/bootstrap/meme.rb +160 -0
- data/lib/myco/bootstrap/void.rb +40 -0
- data/lib/myco/bootstrap.my +15 -0
- data/lib/myco/bootstrap.rb +10 -0
- data/lib/myco/command.my +33 -0
- data/lib/myco/core/BasicObject.my +46 -0
- data/lib/myco/core/Category.my +5 -0
- data/lib/myco/core/Decorator.my +18 -0
- data/lib/myco/core/FileToplevel.my +23 -0
- data/lib/myco/core/Object.my +24 -0
- data/lib/myco/core/Switch.my +31 -0
- data/lib/myco/eval.rb +63 -0
- data/lib/myco/parser/ast/constant_access.rb +29 -0
- data/lib/myco/parser/ast/constant_define.rb +40 -0
- data/lib/myco/parser/ast/constant_reopen.rb +47 -0
- data/lib/myco/parser/ast/declare_category.rb +51 -0
- data/lib/myco/parser/ast/declare_decorator.rb +35 -0
- data/lib/myco/parser/ast/declare_file.rb +54 -0
- data/lib/myco/parser/ast/declare_meme.rb +44 -0
- data/lib/myco/parser/ast/declare_object.rb +75 -0
- data/lib/myco/parser/ast/declare_string.rb +37 -0
- data/lib/myco/parser/ast/invoke.rb +66 -0
- data/lib/myco/parser/ast/local_variable_access_ambiguous.rb +38 -0
- data/lib/myco/parser/ast/misc.rb +61 -0
- data/lib/myco/parser/ast/myco_module_scope.rb +58 -0
- data/lib/myco/parser/ast/quest.rb +82 -0
- data/lib/myco/parser/ast.rb +15 -0
- data/lib/myco/parser/builder.output +3995 -0
- data/lib/myco/parser/builder.racc +585 -0
- data/lib/myco/parser/builder.rb +1592 -0
- data/lib/myco/parser/lexer.rb +2306 -0
- data/lib/myco/parser/lexer.rl +393 -0
- data/lib/myco/parser/lexer_char_classes.rl +56 -0
- data/lib/myco/parser/lexer_common.rb +95 -0
- data/lib/myco/parser/lexer_skeleton.rl +154 -0
- data/lib/myco/parser/peg_parser.kpeg +759 -0
- data/lib/myco/parser/peg_parser.rb +7094 -0
- data/lib/myco/parser.rb +40 -0
- data/lib/myco/tools/OptionParser.my +38 -0
- data/lib/myco/tools/mycompile.my +51 -0
- data/lib/myco/toolset.rb +16 -0
- data/lib/myco/version.rb +22 -0
- data/lib/myco.rb +15 -0
- metadata +247 -0
checksums.yaml
ADDED
@@ -0,0 +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
|
data/LICENSE
ADDED
data/bin/myco
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
class Rubinius::Backtrace
|
3
|
+
def self.backtrace locations
|
4
|
+
::Myco::Backtrace.new(locations || [Rubinius::Location::Missing.new])
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
class Myco::Backtrace < Rubinius::Backtrace
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@gem_color = "\033[0;36m"
|
13
|
+
@gem_paths = [Rubinius::GEMS_PATH, Rubinius::RUNTIME_PATH]
|
14
|
+
end
|
15
|
+
|
16
|
+
def show(sep="\n", show_color=true)
|
17
|
+
show_color &&= @colorize
|
18
|
+
clear = show_color ? "\033[0m" : ""
|
19
|
+
bold = show_color ? "\033[1m" : ""
|
20
|
+
sbullet = "{"
|
21
|
+
ebullet = "}"
|
22
|
+
|
23
|
+
@locations.map do |loc|
|
24
|
+
file = (loc.position(Dir.getwd) || "").sub /(\:\d+)$/, ' \1'
|
25
|
+
color = show_color ? color_from_loc(file, false) : ""
|
26
|
+
color = @gem_color if try_gem_path file
|
27
|
+
file_width = file.length + 1 + sbullet.length
|
28
|
+
|
29
|
+
place = loc.instance_variable_get(:@method_module).to_s + '#'
|
30
|
+
place += loc.describe_method
|
31
|
+
place_width = place.length + 1 + ebullet.length
|
32
|
+
|
33
|
+
padding = @width - file_width - place_width
|
34
|
+
padding += @width until padding >= 0
|
35
|
+
|
36
|
+
file_line = bold + color + sbullet + ' ' + clear + color + file
|
37
|
+
place_line = color + bold + place + ' ' + ebullet + clear
|
38
|
+
|
39
|
+
output = file_line + ' '*padding + place_line
|
40
|
+
output = nil if file == "(myco_internal) :1"
|
41
|
+
output
|
42
|
+
end.compact.reverse.join sep
|
43
|
+
end
|
44
|
+
|
45
|
+
# If file is in one of the GEM_PATHs, mutate the string and return true
|
46
|
+
def try_gem_path file
|
47
|
+
@gem_paths.each do |gem_path|
|
48
|
+
if file.start_with? gem_path and not gem_path.empty?
|
49
|
+
file.sub! File.join(gem_path, 'gems'), ''
|
50
|
+
file.sub! %r{/[^/]*/}, ''
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
|
2
|
+
module Myco
|
3
|
+
class Component < Module
|
4
|
+
attr_accessor :__last__
|
5
|
+
attr_accessor :__name__
|
6
|
+
|
7
|
+
attr_reader :parent
|
8
|
+
attr_reader :parent_meme
|
9
|
+
attr_reader :memes
|
10
|
+
attr_reader :categories
|
11
|
+
|
12
|
+
attr_reader :constant_scope
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
if defined?(::Myco::Category) && (self < ::Myco::Category)
|
16
|
+
"#{parent.to_s}[#{@__name__}]"
|
17
|
+
elsif @__name__
|
18
|
+
@__name__.to_s
|
19
|
+
else
|
20
|
+
"#{@super_components.map(&:to_s).join(',')}" \
|
21
|
+
"(#{@basename}:#{@line.to_s} 0x#{object_id.to_s 16})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.new super_components=[], parent=nil, filename=nil, line=nil
|
26
|
+
locations = Rubinius::VM.backtrace(1,false)
|
27
|
+
|
28
|
+
# Walk backwards on the backtrace until a lexical parent meme is found
|
29
|
+
i = 0
|
30
|
+
parent_meme = nil
|
31
|
+
current = nil
|
32
|
+
while true
|
33
|
+
current = locations[i]
|
34
|
+
break unless current
|
35
|
+
parent_meme = current.constant_scope.myco_meme
|
36
|
+
break if parent_meme
|
37
|
+
i += 1
|
38
|
+
end
|
39
|
+
@constant_scope = current.constant_scope if current
|
40
|
+
|
41
|
+
# Get the filename and line from the VM if not specified
|
42
|
+
if !filename || !line
|
43
|
+
location = locations.first
|
44
|
+
filename ||= location.file
|
45
|
+
line ||= location.line
|
46
|
+
end
|
47
|
+
|
48
|
+
this = super()
|
49
|
+
|
50
|
+
this.instance_eval {
|
51
|
+
@super_components = super_components
|
52
|
+
@memes = { }
|
53
|
+
@parent = parent
|
54
|
+
@filename = filename
|
55
|
+
@line = line
|
56
|
+
@basename = File.basename @filename
|
57
|
+
@dirname = File.dirname @filename
|
58
|
+
@categories = { nil => this }
|
59
|
+
@parent_meme = parent_meme
|
60
|
+
}
|
61
|
+
|
62
|
+
all_categories = Hash.new { |h,k| h[k] = Array.new }
|
63
|
+
|
64
|
+
super_components.each do |other|
|
65
|
+
this.include other if other
|
66
|
+
other.categories.each { |name, cat| all_categories[name] << cat }
|
67
|
+
end
|
68
|
+
|
69
|
+
all_categories.each do |name, supers|
|
70
|
+
if name.nil?
|
71
|
+
this.categories[name] = this
|
72
|
+
else
|
73
|
+
this.categories[name] = this.__new_category__ name, supers, filename, line
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
this
|
78
|
+
end
|
79
|
+
|
80
|
+
def __category__ name
|
81
|
+
@categories[name] ||= __new_category__(name)
|
82
|
+
end
|
83
|
+
|
84
|
+
def __new_category__ name, super_cats=[Category], filename=nil, line=nil
|
85
|
+
# Get the filename and line from the VM if not specified
|
86
|
+
if !filename || !line
|
87
|
+
location = Rubinius::VM.backtrace(2,false).first
|
88
|
+
filename ||= location.file
|
89
|
+
line ||= location.line
|
90
|
+
end
|
91
|
+
|
92
|
+
category = Component.new super_cats, self, filename, line
|
93
|
+
category.__name__ = name
|
94
|
+
category_instance = category.instance
|
95
|
+
declare_meme(name) { category_instance }
|
96
|
+
@memes[name].cache = true
|
97
|
+
|
98
|
+
category
|
99
|
+
end
|
100
|
+
|
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
|
+
def instance
|
121
|
+
if !@instance
|
122
|
+
@instance = Instance.new(self)
|
123
|
+
@instance.extend self
|
124
|
+
yield @instance if block_given?
|
125
|
+
@instance.__signal__ :creation if @instance.respond_to? :__signal__
|
126
|
+
else
|
127
|
+
yield @instance if block_given?
|
128
|
+
end
|
129
|
+
|
130
|
+
@instance
|
131
|
+
end
|
132
|
+
|
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
|
+
}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
# TODO: Move monkey patch to different file
|
3
|
+
module Rubinius
|
4
|
+
class ConstantScope
|
5
|
+
attr_reader :myco_file
|
6
|
+
attr_reader :myco_component
|
7
|
+
attr_reader :myco_category
|
8
|
+
attr_reader :myco_meme
|
9
|
+
|
10
|
+
def myco_levels
|
11
|
+
@myco_levels ||= (parent ? parent.myco_levels.dup : [])
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_myco_file
|
15
|
+
raise "myco_file already set for thie ConstantScope" \
|
16
|
+
if @myco_file
|
17
|
+
@myco_component = self.module
|
18
|
+
@myco_file = self.module
|
19
|
+
|
20
|
+
@myco_file.instance_variable_set(:@constant_scope, self)
|
21
|
+
|
22
|
+
myco_levels << @myco_file
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_myco_component
|
26
|
+
raise "myco_component already set for thie ConstantScope" \
|
27
|
+
if @myco_component
|
28
|
+
@myco_component = self.module
|
29
|
+
@myco_file = parent.myco_file
|
30
|
+
|
31
|
+
myco_levels << @myco_component
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_myco_category
|
35
|
+
raise "myco_category already set for thie ConstantScope" \
|
36
|
+
if @myco_category
|
37
|
+
@myco_category = self.module
|
38
|
+
@myco_component = parent.myco_component
|
39
|
+
@myco_file = parent.myco_file
|
40
|
+
|
41
|
+
myco_levels << @myco_category
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_myco_meme value
|
45
|
+
raise "myco_meme already set for thie ConstantScope" \
|
46
|
+
if @myco_meme
|
47
|
+
@myco_meme = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Myco
|
53
|
+
|
54
|
+
def self.find_constant(name, scope)
|
55
|
+
name = ::Rubinius::Type.coerce_to_constant_name name
|
56
|
+
|
57
|
+
category = scope.myco_category
|
58
|
+
component = scope.myco_component
|
59
|
+
file = scope.myco_file
|
60
|
+
|
61
|
+
# TODO: optimize this constant search
|
62
|
+
# (it currently searches each ancestor of each nested component scope)
|
63
|
+
bucket = nil
|
64
|
+
scope.myco_levels.detect { |level|
|
65
|
+
bucket = find_constant_bucket_in_module(level, name)
|
66
|
+
}
|
67
|
+
bucket ? bucket.constant : ::Rubinius::Type.const_get(::Myco, name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.find_constant_bucket_in_module(mod, name, inherit=true)
|
71
|
+
current, constant = mod, nil
|
72
|
+
|
73
|
+
while current and ::Rubinius::Type.object_kind_of? current, Module
|
74
|
+
if bucket = current.constant_table.lookup(name)
|
75
|
+
return bucket
|
76
|
+
end
|
77
|
+
|
78
|
+
return nil unless inherit
|
79
|
+
|
80
|
+
current = current.direct_superclass
|
81
|
+
end
|
82
|
+
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module Myco
|
3
|
+
class Instance < ::BasicObject
|
4
|
+
include ::Kernel
|
5
|
+
|
6
|
+
# TODO: clean this up
|
7
|
+
prepend (::Module.new {
|
8
|
+
def method_missing name, *args
|
9
|
+
msg = "#{to_s} has no method called '#{name}'"
|
10
|
+
::Kernel.raise ::NoMethodError.new(msg, name, args)
|
11
|
+
end
|
12
|
+
})
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"#<#{@component.to_s}>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: remove (for now it makes debugging easier with RSpec)
|
23
|
+
def pretty_print str
|
24
|
+
p str
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize component
|
28
|
+
@component = component
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :component
|
32
|
+
|
33
|
+
def parent
|
34
|
+
@component.parent && @component.parent.instance
|
35
|
+
end
|
36
|
+
|
37
|
+
def parent_meme
|
38
|
+
@component.parent_meme
|
39
|
+
end
|
40
|
+
|
41
|
+
def memes
|
42
|
+
@component.memes
|
43
|
+
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
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
|
2
|
+
module Myco
|
3
|
+
class Meme
|
4
|
+
attr_accessor :target
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :body
|
7
|
+
attr_accessor :cache
|
8
|
+
attr_accessor :expose
|
9
|
+
|
10
|
+
attr_reader :caches # TODO: don't expose; dynamic meth should send privately
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#<#{self.class}:#{self.name.to_s}>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize target, name, body=nil, &blk
|
21
|
+
self.target = target
|
22
|
+
self.name = name
|
23
|
+
self.body = body || blk
|
24
|
+
self.cache = false
|
25
|
+
self.expose = true
|
26
|
+
|
27
|
+
@caches = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def body= value
|
31
|
+
case value
|
32
|
+
when Rubinius::Executable
|
33
|
+
@body = value
|
34
|
+
@body.scope.set_myco_meme self # Set meme for lexical scope
|
35
|
+
when Proc
|
36
|
+
block_env = value.block.dup
|
37
|
+
block_env.change_name name
|
38
|
+
@body = Rubinius::BlockEnvironment::AsMethod.new block_env
|
39
|
+
value = value.dup
|
40
|
+
value.lambda_style!
|
41
|
+
else
|
42
|
+
raise ArgumentError,
|
43
|
+
"Meme body must be a Rubinius::Executable or a Proc"
|
44
|
+
end
|
45
|
+
|
46
|
+
@body
|
47
|
+
end
|
48
|
+
|
49
|
+
def bind
|
50
|
+
return if not @expose
|
51
|
+
|
52
|
+
meme = self
|
53
|
+
target.memes[@name] = meme
|
54
|
+
|
55
|
+
##
|
56
|
+
# This dynamic method is nearly the same as Meme#result_for
|
57
|
+
# (but written from the perspective of the receiver)
|
58
|
+
# implemented in bytecode to avoid forwarding to another method
|
59
|
+
# on the call stack.
|
60
|
+
# TODO: move this bytecode generation to a helper method
|
61
|
+
target.dynamic_method @name, '(myco_internal)' do |g|
|
62
|
+
g.splat_index = 0 # *args
|
63
|
+
|
64
|
+
invoke = g.new_label
|
65
|
+
ret = g.new_label
|
66
|
+
|
67
|
+
##
|
68
|
+
# meme = <this meme>
|
69
|
+
#
|
70
|
+
g.push_literal meme
|
71
|
+
g.set_local 1 # meme
|
72
|
+
g.pop
|
73
|
+
|
74
|
+
##
|
75
|
+
# caches = <this meme's @caches>
|
76
|
+
#
|
77
|
+
g.push_literal @caches
|
78
|
+
g.set_local 2 # caches
|
79
|
+
g.pop
|
80
|
+
|
81
|
+
##
|
82
|
+
# cache_key = [obj.hash, args.hash, blk.hash]
|
83
|
+
#
|
84
|
+
g.push_self; g.send :hash, 0
|
85
|
+
g.push_local 0; g.send :hash, 0 # args
|
86
|
+
g.push_block; g.send :hash, 0
|
87
|
+
g.make_array 3
|
88
|
+
g.set_local 3 # cache_key
|
89
|
+
g.pop
|
90
|
+
|
91
|
+
##
|
92
|
+
# if meme.cache.false? || !caches.has_key?(cache_key)
|
93
|
+
# return caches[cache_key]
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
g.push_local 1 # meme
|
97
|
+
g.send :cache, 0
|
98
|
+
g.send :false?, 0
|
99
|
+
g.goto_if_true invoke
|
100
|
+
|
101
|
+
g.push_local 2 # caches
|
102
|
+
g.push_local 3 # cache_key
|
103
|
+
g.send :has_key?, 1
|
104
|
+
g.goto_if_false invoke
|
105
|
+
|
106
|
+
g.push_local 2 # caches
|
107
|
+
g.push_local 3 # cache_key
|
108
|
+
g.send :[], 1
|
109
|
+
g.goto ret
|
110
|
+
|
111
|
+
##
|
112
|
+
# result = meme.body.invoke meme.name, @target, obj, args, blk
|
113
|
+
#
|
114
|
+
invoke.set!
|
115
|
+
|
116
|
+
g.push_local 1 # meme
|
117
|
+
g.send :body, 0
|
118
|
+
g.push_local 1; g.send :name, 0 # meme.name
|
119
|
+
g.push_local 1; g.send :target, 0 # meme.target
|
120
|
+
g.push_self
|
121
|
+
g.push_local 0 # args
|
122
|
+
g.push_block
|
123
|
+
g.send :invoke, 5
|
124
|
+
g.set_local 4 # result
|
125
|
+
g.pop
|
126
|
+
|
127
|
+
##
|
128
|
+
# return (caches[cache_key] = result)
|
129
|
+
#
|
130
|
+
g.push_local 2 # caches
|
131
|
+
g.push_local 3 # cache_key
|
132
|
+
g.push_local 4 # result
|
133
|
+
g.send :[]=, 2
|
134
|
+
|
135
|
+
ret.set!
|
136
|
+
g.ret
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def result *args, &blk
|
141
|
+
result_for target.instance, *args, &blk
|
142
|
+
end
|
143
|
+
|
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]
|
148
|
+
end
|
149
|
+
|
150
|
+
result = @body.invoke @name, @target, obj, args, blk
|
151
|
+
|
152
|
+
@caches[cache_key] = result
|
153
|
+
end
|
154
|
+
|
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
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module Myco
|
3
|
+
class VoidClass < ::BasicObject
|
4
|
+
def self.new
|
5
|
+
@singleton ||= super
|
6
|
+
end
|
7
|
+
|
8
|
+
def inspect
|
9
|
+
"void"
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
16
|
+
def false?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def void?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing *args
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def hash
|
29
|
+
nil.hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Void = VoidClass.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# Patch the base classes to make them respond_to :false?
|
37
|
+
class ::NilClass; def false?; true end; def void?; false end end
|
38
|
+
class ::TrueClass; def false?; false end; def void?; false end end
|
39
|
+
class ::FalseClass; def false?; true end; def void?; false end end
|
40
|
+
class ::BasicObject; def false?; false end; def void?; false end end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
RubyEval < EmptyObject {
|
3
|
+
from_string: |string| ::Kernel.instance_method(:eval).bind(self).call(string)
|
4
|
+
}
|
5
|
+
|
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])
|
12
|
+
|
13
|
+
# Below are not necessary for bootstrapping; TODO: move out of RubyEval
|
14
|
+
Myco.eval_file("core/Switch.my", [Myco::CoreLoadPath])
|
15
|
+
@@@
|
@@ -0,0 +1,10 @@
|
|
1
|
+
|
2
|
+
require_relative 'bootstrap/find_constant'
|
3
|
+
|
4
|
+
require_relative 'bootstrap/void'
|
5
|
+
require_relative 'bootstrap/meme'
|
6
|
+
require_relative 'bootstrap/instance'
|
7
|
+
require_relative 'bootstrap/component'
|
8
|
+
|
9
|
+
require_relative 'bootstrap/file_toplevel'
|
10
|
+
require_relative 'bootstrap/empty_object'
|
data/lib/myco/command.my
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
import "tools/OptionParser.my"
|
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
|
+
}
|
26
|
+
|
27
|
+
run: |*argv| {
|
28
|
+
files = options.parse(argv)
|
29
|
+
files.uniq.each |file| { Myco.eval_file(file, [::Dir.pwd]) }
|
30
|
+
}
|
31
|
+
|
32
|
+
on creation: run(*ARGV)
|
33
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
::Myco::BasicObject < ::Myco::EmptyObject {
|
3
|
+
# Basic conditional handling
|
4
|
+
if: |cond, &blk| cond && blk.call
|
5
|
+
unless: |cond, &blk| cond || blk.call
|
6
|
+
switch: |input,comparator=:"=="|
|
7
|
+
Switch.new(input:input, comparator:comparator)
|
8
|
+
|
9
|
+
puts: |*args| STDOUT.puts(*args)
|
10
|
+
p: |*args| STDOUT.puts(args.map |a| { a.inspect }.join(', '))
|
11
|
+
|
12
|
+
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
|
+
}
|