sbyc 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sbyc.rb +1 -5
- data/lib/sbyc/codetree.rb +79 -77
- data/lib/sbyc/codetree/ast_node.rb +117 -115
- data/lib/sbyc/codetree/eval/ast_node_ext.rb +33 -31
- data/lib/sbyc/codetree/eval/functional_eval.rb +33 -31
- data/lib/sbyc/codetree/eval/object_eval.rb +33 -31
- data/lib/sbyc/codetree/matching/ast_node_ext.rb +13 -11
- data/lib/sbyc/codetree/matching/match_data.rb +25 -23
- data/lib/sbyc/codetree/matching/matcher.rb +73 -71
- data/lib/sbyc/codetree/name2x/delegate.rb +56 -54
- data/lib/sbyc/codetree/name2x/module_delegate.rb +23 -22
- data/lib/sbyc/codetree/proc_parser.rb +101 -99
- data/lib/sbyc/codetree/producing/producer.rb +69 -67
- data/lib/sbyc/codetree/producing/tracing_methods.rb +66 -64
- data/lib/sbyc/codetree/rewriting/class_methods.rb +15 -13
- data/lib/sbyc/codetree/rewriting/compiler.rb +27 -25
- data/lib/sbyc/codetree/rewriting/instance_methods.rb +80 -78
- data/lib/sbyc/codetree/rewriting/match.rb +51 -49
- data/lib/sbyc/shortspaces.rb +3 -0
- data/lib/sbyc/type_system.rb +4 -2
- data/lib/sbyc/type_system/contract.rb +38 -36
- data/lib/sbyc/type_system/errors.rb +8 -6
- data/lib/sbyc/type_system/ruby.rb +137 -121
- data/test/spec/spec_helper.rb +1 -1
- data/test/spec/unit/sbyc/type_system/ruby/boolean.spec +14 -0
- data/test/spec/unit/sbyc/type_system/ruby/coerce.spec +10 -1
- metadata +6 -4
@@ -1,25 +1,26 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module Name2X
|
4
|
+
class ModuleDelegate < Delegate
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
# Overrides the default behavior to use const_get instead.
|
7
|
+
def fetch(name)
|
8
|
+
name = name2name(name)
|
9
|
+
delegate.const_defined?(name) ? delegate.const_get(name) : nil
|
10
|
+
rescue NameError
|
11
|
+
nil
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
# Capitalize a name
|
15
|
+
def name2name(name)
|
16
|
+
src = name.to_s
|
17
|
+
src.gsub!(/[^a-zA-Z\s]/," ")
|
18
|
+
src = " " + src.split.join(" ")
|
19
|
+
src.gsub!(/ (.)/) { $1.upcase }
|
20
|
+
src.to_sym
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
end # module CodeTree
|
25
|
-
|
23
|
+
end # class ModuleDelegate
|
24
|
+
end # module Name2X
|
25
|
+
end # module CodeTree
|
26
|
+
end # module SByC
|
@@ -1,124 +1,126 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class ProcParser
|
4
|
+
#
|
5
|
+
# Collector when :multiline option is set to true.
|
6
|
+
#
|
7
|
+
class Collector
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
# Which nodes are kept?
|
10
|
+
attr_reader :kept
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
# Creates a collector instance
|
13
|
+
def initialize
|
14
|
+
@kept = []
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
# Callback when a new Expr is created
|
18
|
+
def built(who, children)
|
19
|
+
@kept << who
|
20
|
+
children.each{|c| @kept.delete_if{|k| k.__id__ == c.__id__}}
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
# Returns expressions as an array of AstNodes
|
24
|
+
def to_a
|
25
|
+
kept.collect{|c| c.__to_functional_code}
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
+
end # class Collector
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
# An expression
|
31
|
+
class Expr
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
# Methods that we keep
|
34
|
+
KEPT_METHODS = [ "__send__", "__id__", "instance_eval", "initialize", "object_id",
|
35
|
+
"singleton_method_added", "singleton_method_undefined", "method_missing",
|
36
|
+
"__evaluate__", "coerce", "kind_of?"]
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
class << self
|
39
|
+
def __clean_scope__
|
40
|
+
# Removes all methods that are not needed to the class
|
41
|
+
(instance_methods + private_instance_methods).each do |m|
|
42
|
+
m_to_s = m.to_s
|
43
|
+
undef_method(m_to_s.to_sym) unless ('__' == m_to_s[0..1]) or KEPT_METHODS.include?(m_to_s)
|
44
|
+
end
|
43
45
|
end
|
44
46
|
end
|
45
|
-
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
# Creates an expression instance
|
49
|
+
def initialize(name, children, collector)
|
50
|
+
class << self; __clean_scope__; end
|
51
|
+
@name, @children, @collector = name, children, collector
|
52
|
+
if @collector and @name
|
53
|
+
@collector.built(self, children)
|
54
|
+
end
|
53
55
|
end
|
54
|
-
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
# Returns the associated functional code
|
58
|
+
def __to_functional_code
|
59
|
+
children = (@children || []).collect{|c|
|
60
|
+
c.kind_of?(Expr) ? c.__to_functional_code : AstNode.coerce(c)
|
61
|
+
}
|
62
|
+
CodeTree::AstNode.coerce([@name, children])
|
63
|
+
end
|
64
|
+
alias :inspect :__to_functional_code
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
# Called when a method is missing
|
67
|
+
def method_missing(name, *args)
|
68
|
+
if @name.nil?
|
69
|
+
if name == :[]
|
70
|
+
Expr.new(:'?', args, @collector)
|
71
|
+
elsif args.empty?
|
72
|
+
Expr.new(:'?', [name], @collector)
|
73
|
+
else
|
74
|
+
Expr.new(name, args, @collector)
|
75
|
+
end
|
72
76
|
else
|
77
|
+
args.unshift(self)
|
73
78
|
Expr.new(name, args, @collector)
|
74
79
|
end
|
75
|
-
else
|
76
|
-
args.unshift(self)
|
77
|
-
Expr.new(name, args, @collector)
|
78
80
|
end
|
79
|
-
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
def coerce(other)
|
83
|
+
[self, other]
|
84
|
+
end
|
84
85
|
|
85
|
-
|
86
|
+
end # class Expr
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
88
|
+
# Parses a Proc object
|
89
|
+
def self.parse_proc(block, options = {})
|
90
|
+
collector = options[:multiline] ? Collector.new : nil
|
91
|
+
e = case block.arity
|
92
|
+
when -1, 0
|
93
|
+
expr = Expr.new(nil, nil, collector)
|
94
|
+
expr.instance_eval(&block)
|
95
|
+
when 1
|
96
|
+
block.call(Expr.new(nil, nil, collector))
|
97
|
+
else
|
98
|
+
raise ArgumentError, "Unexpected block arity #{block.arity}"
|
99
|
+
end
|
100
|
+
return collector.to_a if collector
|
101
|
+
case e
|
102
|
+
when Expr
|
103
|
+
e.__to_functional_code
|
104
|
+
else
|
105
|
+
CodeTree::AstNode.coerce(e)
|
106
|
+
end
|
105
107
|
end
|
106
|
-
end
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
109
|
+
# Parses a block
|
110
|
+
def self.parse(code = nil, options = {}, &block)
|
111
|
+
block = code || block
|
112
|
+
case block
|
113
|
+
when Proc
|
114
|
+
parse_proc(block, options)
|
115
|
+
when AstNode
|
116
|
+
block
|
117
|
+
when String
|
118
|
+
parse(Kernel.eval("proc{ #{block} }"), options)
|
119
|
+
else
|
120
|
+
raise ArgumentError, "Unable to parse #{block}"
|
121
|
+
end
|
120
122
|
end
|
121
|
-
end
|
122
123
|
|
123
|
-
|
124
|
-
end # module CodeTree
|
124
|
+
end # class ProcParser
|
125
|
+
end # module CodeTree
|
126
|
+
end # module SByC
|
@@ -1,80 +1,82 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module Producing
|
4
|
+
class Producer
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
# Rules kepts by node function
|
7
|
+
attr_reader :rules
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
# Extension options.
|
10
|
+
attr_reader :extension_options
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
# Creates a producer instance
|
13
|
+
def initialize(default_rules = true)
|
14
|
+
@rules = {}
|
15
|
+
@extension_options = {}
|
16
|
+
if default_rules
|
17
|
+
rule(:_) {|r,node| node.literal}
|
18
|
+
rule("*"){|r,node| r.apply(node.children)}
|
19
|
+
end
|
20
|
+
yield(self) if block_given?
|
18
21
|
end
|
19
|
-
yield(self) if block_given?
|
20
|
-
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
# Adds an extension module
|
24
|
+
def add_extension(mod, options = {})
|
25
|
+
self.extend(mod)
|
26
|
+
options = mod.send(:prepare_options, options || {}) if mod.respond_to?(:prepare_options)
|
27
|
+
extension_options[mod] = options
|
28
|
+
self
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
# Adds a rule
|
32
|
+
def rule(function_name, &block)
|
33
|
+
rules[function_name] = block
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
# Applies on some arguments
|
37
|
+
def apply(*args)
|
38
|
+
case args = apply_args_conventions(*args)
|
39
|
+
when CodeTree::AstNode
|
40
|
+
apply_on_node(args)
|
41
|
+
when Array
|
42
|
+
args.collect{|c| apply(c)}
|
43
|
+
else
|
44
|
+
args
|
45
|
+
end
|
44
46
|
end
|
45
|
-
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
# Applies on a given node
|
49
|
+
def apply_on_node(node)
|
50
|
+
func = node.function
|
51
|
+
if rules.key?(func)
|
52
|
+
@rules[func].call(self, node)
|
53
|
+
elsif rules.key?("*")
|
54
|
+
@rules["*"].call(self, node)
|
55
|
+
else
|
56
|
+
nil
|
57
|
+
end
|
56
58
|
end
|
57
|
-
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
60
|
+
# Applies arument conventions allowed by _apply_
|
61
|
+
def apply_args_conventions(*args)
|
62
|
+
if args.size == 1 and args[0].kind_of?(CodeTree::AstNode)
|
63
|
+
args[0]
|
64
|
+
elsif args.size > 1 and args[0].kind_of?(Symbol)
|
65
|
+
function = args.shift
|
66
|
+
children = args.collect{|c| apply_args_conventions(c)}.flatten
|
67
|
+
CodeTree::AstNode.coerce([function, children])
|
68
|
+
elsif args.all?{|a| a.kind_of?(CodeTree::AstNode)}
|
69
|
+
args
|
70
|
+
elsif args.size == 1
|
71
|
+
args[0]
|
72
|
+
else
|
73
|
+
raise ArgumentError, "Unable to apply on #{args.inspect} (#{args.size})", caller
|
74
|
+
end
|
73
75
|
end
|
74
|
-
end
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end # module CodeTree
|
77
|
+
private :apply_on_node
|
78
|
+
private :apply_args_conventions
|
79
|
+
end # class Producer
|
80
|
+
end # module Producing
|
81
|
+
end # module CodeTree
|
82
|
+
end # module SByC
|
@@ -1,77 +1,79 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
module
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module Producing
|
4
|
+
module TracingMethods
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
# Returns the default options
|
7
|
+
def self.default_options
|
8
|
+
{:indent_support => true,
|
9
|
+
:indent_string => " ",
|
10
|
+
:newline_support => true,
|
11
|
+
:io => STDOUT}
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
# Merge the default options and the options
|
15
|
+
def self.prepare_options(options)
|
16
|
+
default_options.merge(options)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
# Returns tracing extension options
|
20
|
+
def tracing_options
|
21
|
+
extension_options[TracingMethods] ||= {}
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
# Is indentation support installed?
|
25
|
+
def tracing_indent_support?
|
26
|
+
!!tracing_options[:indent_support]
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
# Is new line support installed?
|
30
|
+
def tracing_newline_support?
|
31
|
+
!!tracing_options[:newline_support]
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
# Returns the string to use for indentation
|
35
|
+
def tracing_indent_string
|
36
|
+
tracing_options[:indent_string] ||= " "
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
# Returns the current indentation level
|
40
|
+
def tracing_indent_level
|
41
|
+
tracing_options[:indent_level] ||= 0
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
# Returns the IO object (actually, any object supporting the << operator)
|
45
|
+
# that must be used for tracing the Producer.
|
46
|
+
def tracing_io
|
47
|
+
tracing_options[:io] ||= STDOUT
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
# Logs a message on the IO object, without any other side effect (no
|
51
|
+
# depth increment, for instance).
|
52
|
+
def trace(message)
|
53
|
+
message = (tracing_indent_string*tracing_indent_level + message.to_s) if tracing_indent_support? and tracing_indent_level>0
|
54
|
+
message = "#{message}\n" if tracing_newline_support?
|
55
|
+
if tracing_io.kind_of?(IO)
|
56
|
+
tracing_io << message
|
57
|
+
else
|
58
|
+
tracing_io << message
|
59
|
+
end
|
58
60
|
end
|
59
|
-
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
# Logs that a rule has been entered and increment the depth
|
63
|
+
# level
|
64
|
+
def trace_rule_entered(message)
|
65
|
+
trace(message)
|
66
|
+
tracing_options[:indent_level] = tracing_indent_level+1
|
67
|
+
end
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
69
|
+
# Logs that a rule has been exited and decrements the depth
|
70
|
+
# level
|
71
|
+
def trace_rule_exited(message)
|
72
|
+
tracing_options[:indent_level] = tracing_indent_level-1
|
73
|
+
trace(message)
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
end # module CodeTree
|
76
|
+
end # module TracingMethods
|
77
|
+
end # module Producing
|
78
|
+
end # module CodeTree
|
79
|
+
end # module SByC
|