sbyc 0.1.3 → 0.1.4
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.
- 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
data/lib/sbyc.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module SByC
|
2
2
|
|
3
3
|
# Version
|
4
|
-
VERSION = "0.1.
|
4
|
+
VERSION = "0.1.4".freeze
|
5
5
|
|
6
6
|
# Provides tools around functional source code trees.
|
7
7
|
module CodeTree
|
@@ -14,9 +14,5 @@ module SByC
|
|
14
14
|
end # module CodeTree
|
15
15
|
|
16
16
|
end # module SByC
|
17
|
-
|
18
|
-
CodeTree = ::SByC::CodeTree
|
19
17
|
require 'sbyc/codetree'
|
20
|
-
|
21
|
-
TypeSystem = ::SByC::TypeSystem
|
22
18
|
require 'sbyc/type_system'
|
data/lib/sbyc/codetree.rb
CHANGED
@@ -1,81 +1,83 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
code, options = nil,
|
37
|
-
|
38
|
-
|
39
|
-
module_function :parse
|
40
|
-
|
41
|
-
# Alias for _parse_
|
42
|
-
def expr(code = nil, options = nil, &block)
|
43
|
-
parse(code, options || {}, &block)
|
44
|
-
end
|
45
|
-
module_function :expr
|
46
|
-
|
47
|
-
# Factors a CodeTree::Matcher instance
|
48
|
-
def matcher(code = nil, &block)
|
49
|
-
CodeTree::Matcher.new(parse(code, &block))
|
50
|
-
end
|
51
|
-
module_function :matcher
|
52
|
-
|
53
|
-
# Factors a rewriter instance
|
54
|
-
def rewriter(&definition)
|
55
|
-
CodeTree::Rewriting::Rewriter.new(&definition)
|
56
|
-
end
|
57
|
-
module_function :rewriter
|
58
|
-
|
59
|
-
# Factors a producer instance
|
60
|
-
def producer(default_rules = true, &definition)
|
61
|
-
CodeTree::Producing::Producer.new(default_rules, &definition)
|
62
|
-
end
|
63
|
-
module_function :producer
|
64
|
-
|
65
|
-
# Converts an argument to an parse tree (an ASTNode instance)
|
66
|
-
def coerce(arg)
|
67
|
-
case arg
|
68
|
-
when AstNode
|
69
|
-
arg
|
70
|
-
when Proc, String
|
71
|
-
CodeTree::parse(arg)
|
72
|
-
else
|
73
|
-
raise "Unable to coerce #{arg.inspect} to a CodeTree::AstNode"
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
|
4
|
+
# Operator names
|
5
|
+
OPERATOR_NAMES = {
|
6
|
+
:'?' => :varref,
|
7
|
+
:[] => :get,
|
8
|
+
:[]= => :set,
|
9
|
+
:** => :exponentiation,
|
10
|
+
:~ => :complement,
|
11
|
+
:== => :eq,
|
12
|
+
#:!= => :neq,
|
13
|
+
:-@ => :unary_minus,
|
14
|
+
:+@ => :unary_plus,
|
15
|
+
:- => :minus,
|
16
|
+
:+ => :plus,
|
17
|
+
:* => :times,
|
18
|
+
:/ => :divide,
|
19
|
+
:% => :modulo,
|
20
|
+
:=~ => :match,
|
21
|
+
:=== => :matches?,
|
22
|
+
:& => :and,
|
23
|
+
:| => :or,
|
24
|
+
:> => :gt,
|
25
|
+
:>= => :gte,
|
26
|
+
:<= => :lte,
|
27
|
+
:< => :lt,
|
28
|
+
:>> => :right_shift,
|
29
|
+
:<< => :left_shift,
|
30
|
+
:'^' => :exclusive,
|
31
|
+
:<=> => :compare
|
32
|
+
}
|
33
|
+
REVERSE_OPERATOR_NAMES = Hash[*OPERATOR_NAMES.to_a.collect{|c| c.reverse}.flatten]
|
34
|
+
|
35
|
+
# Parses some code or block
|
36
|
+
def parse(code = nil, options = nil, &block)
|
37
|
+
code, options = nil, code if code.kind_of?(Hash) and options.nil?
|
38
|
+
ProcParser::parse(code, options || {}, &block)
|
74
39
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
40
|
+
module_function :parse
|
41
|
+
|
42
|
+
# Alias for _parse_
|
43
|
+
def expr(code = nil, options = nil, &block)
|
44
|
+
parse(code, options || {}, &block)
|
45
|
+
end
|
46
|
+
module_function :expr
|
47
|
+
|
48
|
+
# Factors a CodeTree::Matcher instance
|
49
|
+
def matcher(code = nil, &block)
|
50
|
+
CodeTree::Matcher.new(parse(code, &block))
|
51
|
+
end
|
52
|
+
module_function :matcher
|
53
|
+
|
54
|
+
# Factors a rewriter instance
|
55
|
+
def rewriter(&definition)
|
56
|
+
CodeTree::Rewriting::Rewriter.new(&definition)
|
57
|
+
end
|
58
|
+
module_function :rewriter
|
59
|
+
|
60
|
+
# Factors a producer instance
|
61
|
+
def producer(default_rules = true, &definition)
|
62
|
+
CodeTree::Producing::Producer.new(default_rules, &definition)
|
63
|
+
end
|
64
|
+
module_function :producer
|
65
|
+
|
66
|
+
# Converts an argument to an parse tree (an ASTNode instance)
|
67
|
+
def coerce(arg)
|
68
|
+
case arg
|
69
|
+
when AstNode
|
70
|
+
arg
|
71
|
+
when Proc, String
|
72
|
+
CodeTree::parse(arg)
|
73
|
+
else
|
74
|
+
raise "Unable to coerce #{arg.inspect} to a CodeTree::AstNode"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
module_function :coerce
|
78
|
+
|
79
|
+
end # module CodeTree
|
80
|
+
end # module SByC
|
79
81
|
require 'sbyc/codetree/ast_node'
|
80
82
|
require 'sbyc/codetree/proc_parser'
|
81
83
|
require 'sbyc/codetree/eval'
|
@@ -1,140 +1,142 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class AstNode
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
# Name of the method call
|
6
|
+
attr_accessor :name
|
7
|
+
alias :function :name
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
# Children nodes
|
10
|
+
attr_reader :children
|
11
|
+
alias :args :children
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
# Operator found by type checking
|
14
|
+
attr_reader :operator
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# Creates an ASTNode instance
|
17
|
+
def initialize(name, children)
|
18
|
+
@name, @children = name, children
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# Delegated to the children array
|
22
|
+
def [](*args, &block)
|
23
|
+
children.[](*args, &block)
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
# Recursively finds the first literal.
|
27
|
+
def literal
|
28
|
+
leaf? ? children[0] : children[0].literal
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
# Returns false
|
32
|
+
def leaf?
|
33
|
+
(name == :_)
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
# Negation of leaf?
|
37
|
+
def branch?
|
38
|
+
not(leaf?)
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
# Yields block with each child in turn
|
42
|
+
def each(&block)
|
43
|
+
children.each(&block)
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
# Makes a depth-first-search visit of the AST
|
47
|
+
def visit(&block)
|
48
|
+
yield(self, leaf? ? children : children.collect{|c| c.respond_to?(:visit) ? c.visit(&block) : c})
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
# Renames some nodes, given a name2name map.
|
52
|
+
def rename!(map = nil, &block)
|
53
|
+
map = CodeTree::Name2X::Delegate.coerce(map || block)
|
54
|
+
visit{|node, collected|
|
55
|
+
newname = map.name2name(node.name)
|
56
|
+
node.send(:name=, newname) if newname
|
57
|
+
nil
|
58
|
+
}
|
59
|
+
self
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
62
|
+
# Inject code through module mapped to function names
|
63
|
+
def code_inject!(map = nil, &block)
|
64
|
+
map = CodeTree::Name2X::Delegate.coerce(map || block)
|
65
|
+
visit{|node, collected|
|
66
|
+
ext = map.name2module(node.function)
|
67
|
+
node.extend(ext) if ext
|
68
|
+
nil
|
69
|
+
}
|
70
|
+
self
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
73
|
+
# Create class instances
|
74
|
+
def digest(map = nil, &block)
|
75
|
+
map = CodeTree::Name2X::Delegate.coerce(map || block)
|
76
|
+
visit{|node, collected|
|
77
|
+
if node.leaf?
|
78
|
+
node.literal
|
79
|
+
else
|
80
|
+
ext = map.name2class(node.function)
|
81
|
+
raise "Unexpected node function: #{node.function}" unless ext
|
82
|
+
ext.new(*collected)
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
# Inspection
|
88
|
+
def inspect
|
89
|
+
"(#{name} #{children.collect{|c| c.inspect}.join(', ')})"
|
90
|
+
end
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
92
|
+
# Returns a short string representation
|
93
|
+
def to_s
|
94
|
+
case function
|
95
|
+
when :'_'
|
96
|
+
literal.inspect
|
97
|
+
when :'?'
|
98
|
+
literal.to_s
|
99
|
+
else
|
100
|
+
"(#{name} #{children.collect{|c| c.to_s}.join(', ')})"
|
101
|
+
end
|
100
102
|
end
|
101
|
-
end
|
102
103
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
# Returns an array version of this ast
|
105
|
+
def to_a
|
106
|
+
visit{|node, collected| [node.name, collected]}
|
107
|
+
end
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
109
|
+
# Checks tree equality with another node
|
110
|
+
def ==(other)
|
111
|
+
return false unless other.kind_of?(AstNode)
|
112
|
+
return false unless (function == other.function)
|
113
|
+
return false unless args.size == other.args.size
|
114
|
+
return false unless args.zip(other.args).all?{|v1, v2| v1 == v2}
|
115
|
+
true
|
116
|
+
end
|
116
117
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
118
|
+
# Coercion
|
119
|
+
def self.coerce(arg)
|
120
|
+
case arg
|
121
|
+
when AstNode
|
122
|
+
arg
|
123
|
+
when Array
|
124
|
+
name, children = arg
|
125
|
+
if name.kind_of?(Symbol) and children.kind_of?(Array)
|
126
|
+
if name == :_ and children.size == 1
|
127
|
+
AstNode.new(:_, children)
|
128
|
+
else
|
129
|
+
AstNode.new(name, children.collect{|c| AstNode.coerce(c)})
|
130
|
+
end
|
127
131
|
else
|
128
|
-
AstNode.new(
|
132
|
+
AstNode.new(:_, [ arg ])
|
129
133
|
end
|
130
134
|
else
|
131
135
|
AstNode.new(:_, [ arg ])
|
132
|
-
|
133
|
-
else
|
134
|
-
AstNode.new(:_, [ arg ])
|
136
|
+
end
|
135
137
|
end
|
136
|
-
end
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
end # module CodeTree
|
139
|
+
private :name=
|
140
|
+
end # module AstNode
|
141
|
+
end # module CodeTree
|
142
|
+
end # module SByC
|
@@ -1,38 +1,40 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class AstNode
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# Generates the code of an object evaluation
|
6
|
+
def object_compile(scope_object = "scope", scope_method = :[])
|
7
|
+
CodeTree::ObjectEval.object_compile(self, scope_object, scope_method)
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
# Generates a lambda function for object evaluation
|
11
|
+
def object_proc(scope_method = :[])
|
12
|
+
CodeTree::ObjectEval.object_proc(self, scope_method)
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
# Executes object evaluation of this ast
|
16
|
+
def object_eval(scope = {}, scope_method = :[])
|
17
|
+
CodeTree::ObjectEval.object_eval(self, scope)
|
18
|
+
end
|
19
|
+
alias :call :object_eval
|
20
|
+
alias :eval :object_eval
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
# Generates the code of an functional evaluation
|
23
|
+
def functional_compile(receiver_object = "receiver", scope_object = "scope", scope_method = :[])
|
24
|
+
CodeTree::FunctionalEval.functional_compile(self, receiver_object, scope_object, scope_method)
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# Generates a lambda function for functional evaluation
|
28
|
+
def functional_proc(scope_method = :[])
|
29
|
+
CodeTree::FunctionalEval.functional_proc(self, scope_method)
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
# Executes functional evaluation of this ast
|
33
|
+
def functional_eval(master_object, scope = {}, scope_method = :[])
|
34
|
+
CodeTree::FunctionalEval.functional_eval(self, master_object, scope)
|
35
|
+
end
|
36
|
+
alias :apply :functional_eval
|
36
37
|
|
37
|
-
|
38
|
-
end # module CodeTree
|
38
|
+
end # class AstNode
|
39
|
+
end # module CodeTree
|
40
|
+
end # module SByC
|