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,36 +1,38 @@
|
|
1
|
-
module
|
2
|
-
module
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module FunctionalEval
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
# Generates code for a functional evaluation
|
6
|
+
def functional_compile(ast, receiver_object = "receiver", scope_object = "scope", scope_method = :[])
|
7
|
+
ast.visit{|node, collected|
|
8
|
+
case func = node.function
|
9
|
+
when :_
|
10
|
+
collected.first.inspect
|
11
|
+
when :'?'
|
12
|
+
if scope_method == :[]
|
13
|
+
"#{scope_object}[#{collected.join(', ')}]"
|
14
|
+
else
|
15
|
+
"#{scope_object}.#{scope_method}(#{collected.join(', ')})"
|
16
|
+
end
|
13
17
|
else
|
14
|
-
"#{
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
}
|
20
|
-
end
|
21
|
-
module_function :functional_compile
|
18
|
+
"#{receiver_object}.#{func}(#{collected.join(', ')})"
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
module_function :functional_compile
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# Generates a lambda function for functional evaluation
|
25
|
+
def functional_proc(ast, scope_method = :[])
|
26
|
+
::Kernel.eval("::Kernel.lambda{|receiver, scope| #{functional_compile(ast, 'receiver', 'scope', scope_method)}}")
|
27
|
+
end
|
28
|
+
module_function :functional_proc
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
# Evaluates this AST with an object style.
|
31
|
+
def functional_eval(ast, receiver, scope = {}, scope_method = :[])
|
32
|
+
functional_proc(ast, scope_method).call(receiver, scope)
|
33
|
+
end
|
34
|
+
module_function :functional_eval
|
34
35
|
|
35
|
-
|
36
|
-
end # module CodeTree
|
36
|
+
end # module FunctionalEval
|
37
|
+
end # module CodeTree
|
38
|
+
end # module SByC
|
@@ -1,36 +1,38 @@
|
|
1
|
-
module
|
2
|
-
module
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module ObjectEval
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
# Generates code for an object evaluation
|
6
|
+
def object_compile(ast, scope_object = "scope", scope_method = :[])
|
7
|
+
ast.visit{|node, collected|
|
8
|
+
case func = node.function
|
9
|
+
when :'_'
|
10
|
+
collected.first.inspect
|
11
|
+
when :'?'
|
12
|
+
if scope_method == :[]
|
13
|
+
"#{scope_object}[#{collected.join(', ')}]"
|
14
|
+
else
|
15
|
+
"#{scope_object}.#{scope_method}(#{collected.join(', ')})"
|
16
|
+
end
|
13
17
|
else
|
14
|
-
"#{
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
}
|
20
|
-
end
|
21
|
-
module_function :object_compile
|
18
|
+
"#{collected[0]}.#{func}(#{collected[1..-1].join(', ')})"
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
module_function :object_compile
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# Generates a lambda function for object evaluation
|
25
|
+
def object_proc(ast, scope_method = :[])
|
26
|
+
::Kernel.eval "::Kernel.lambda{|scope| #{object_compile(ast, 'scope', scope_method)}}"
|
27
|
+
end
|
28
|
+
module_function :object_proc
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
# Evaluates this AST with an object style.
|
31
|
+
def object_eval(ast, scope = {}, scope_method = :[])
|
32
|
+
object_proc(ast, scope_method).call(scope)
|
33
|
+
end
|
34
|
+
module_function :object_eval
|
34
35
|
|
35
|
-
|
36
|
-
end # module CodeTree
|
36
|
+
end # module ObjectEval
|
37
|
+
end # module CodeTree
|
38
|
+
end # module SByC
|
@@ -1,14 +1,16 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class AstNode
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
# Applies ast node matching
|
6
|
+
def ===(other)
|
7
|
+
if other.kind_of?(CodeTree::AstNode)
|
8
|
+
CodeTree::Matcher.new(self) === other
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
10
12
|
end
|
11
|
-
end
|
12
13
|
|
13
|
-
|
14
|
-
end # module CodeTree
|
14
|
+
end # class AstNode
|
15
|
+
end # module CodeTree
|
16
|
+
end # module SByC
|
@@ -1,30 +1,32 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class MatchData
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
# Source AstNode of the matching
|
6
|
+
attr_reader :source
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
# Matched node
|
9
|
+
attr_reader :matched_node
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
# Captured variables
|
12
|
+
attr_reader :captures
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
# Creates a MatchData instance
|
15
|
+
def initialize(source, matched_node, captures)
|
16
|
+
@source, @matched_node, @captures = source, matched_node, captures
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
# Returns node matched under a given variable name
|
20
|
+
def [](varname)
|
21
|
+
captures[varname]
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# Inspects this MatchData
|
25
|
+
def inspect
|
26
|
+
"MatchData#{captures.inspect}"
|
27
|
+
end
|
28
|
+
alias :to_s :inspect
|
28
29
|
|
29
|
-
|
30
|
-
end # module CodeTree
|
30
|
+
end # class MatchData
|
31
|
+
end # module CodeTree
|
32
|
+
end # module SByC
|
@@ -1,83 +1,85 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
class Matcher
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
# Match Abstract Syntax Tree
|
6
|
+
attr_reader :match_ast
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
# Looks for a match against some ast node
|
13
|
-
def =~(ast_node)
|
14
|
-
if captures = do_match(match_ast, ast_node)
|
15
|
-
CodeTree::MatchData.new(ast_node, ast_node, captures)
|
16
|
-
else
|
17
|
-
nil
|
8
|
+
# Creates an IMatch instance
|
9
|
+
def initialize(match_ast)
|
10
|
+
@match_ast = match_ast
|
18
11
|
end
|
19
|
-
end
|
20
|
-
alias :match :=~
|
21
|
-
alias :call :=~
|
22
12
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
13
|
+
# Looks for a match against some ast node
|
14
|
+
def =~(ast_node)
|
15
|
+
if captures = do_match(match_ast, ast_node)
|
16
|
+
CodeTree::MatchData.new(ast_node, ast_node, captures)
|
17
|
+
else
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias :match :=~
|
22
|
+
alias :call :=~
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
return match_data
|
35
|
-
end
|
24
|
+
# Returns true if _ast_node_ is matched by this matcher,
|
25
|
+
# false otherwise
|
26
|
+
def ===(ast_node)
|
27
|
+
not((self =~ ast_node).nil?)
|
28
|
+
end
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# (match (? (_ :x)), ...) # true and match_data[x] = ast_node.function
|
44
|
-
# false otherwise
|
45
|
-
#
|
46
|
-
def function_match(match_ast, ast_node, match_data = {})
|
47
|
-
case fname = match_ast[0].function
|
48
|
-
when :'_'
|
49
|
-
return (match_ast[0].literal == ast_node.function ? true : false)
|
50
|
-
when :'?'
|
51
|
-
match_data[match_ast[0].literal] = ast_node.function
|
52
|
-
return true
|
30
|
+
# Lookups for a match between _matcher_ and _matched_.
|
31
|
+
def do_match(matcher, matched, match_data = {})
|
32
|
+
return nil unless matched.kind_of?(CodeTree::AstNode)
|
33
|
+
return nil unless function_match(matcher, matched, match_data)
|
34
|
+
return nil unless args_match(matcher.args[1..-1], matched.args.dup, match_data)
|
35
|
+
return match_data
|
53
36
|
end
|
54
|
-
false
|
55
|
-
end
|
56
37
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
38
|
+
#
|
39
|
+
# Applies function name matching, returning true if _ast_node_'s function name
|
40
|
+
# is matched by first argument of _match_ast_.
|
41
|
+
#
|
42
|
+
# Cases that may arise:
|
43
|
+
# (match (_ :fname), ...) # true iif ast_node.function == fname
|
44
|
+
# (match (? (_ :x)), ...) # true and match_data[x] = ast_node.function
|
45
|
+
# false otherwise
|
46
|
+
#
|
47
|
+
def function_match(match_ast, ast_node, match_data = {})
|
48
|
+
case fname = match_ast[0].function
|
67
49
|
when :'_'
|
68
|
-
return
|
69
|
-
|
70
|
-
|
71
|
-
return
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
50
|
+
return (match_ast[0].literal == ast_node.function ? true : false)
|
51
|
+
when :'?'
|
52
|
+
match_data[match_ast[0].literal] = ast_node.function
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Applies arguments matching, return true if there is a match,
|
60
|
+
# false otherwise.
|
61
|
+
#
|
62
|
+
def args_match(matchers, candidates, match_data = {})
|
63
|
+
matchers.each do |m|
|
64
|
+
case m.function
|
65
|
+
when :'?'
|
66
|
+
return false if candidates.empty?
|
67
|
+
match_data[m.literal] = candidates.shift
|
68
|
+
when :'_'
|
69
|
+
return false if candidates.empty?
|
70
|
+
return false unless candidates.shift.literal == m.literal
|
71
|
+
when :'[]'
|
72
|
+
return false if candidates.empty?
|
73
|
+
match_data[m.literal] = candidates
|
74
|
+
candidates = []
|
75
|
+
else
|
76
|
+
return false if candidates.empty?
|
77
|
+
return false unless do_match(m, candidates.shift, match_data)
|
78
|
+
end
|
77
79
|
end
|
80
|
+
candidates.empty?
|
78
81
|
end
|
79
|
-
candidates.empty?
|
80
|
-
end
|
81
82
|
|
82
|
-
|
83
|
-
end # module CodeTree
|
83
|
+
end # class Matcher
|
84
|
+
end # module CodeTree
|
85
|
+
end # module SByC
|
@@ -1,57 +1,59 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
when Module
|
22
|
-
ModuleDelegate.new(arg)
|
23
|
-
else
|
24
|
-
if arg.respond_to?(:[])
|
1
|
+
module SByC
|
2
|
+
module CodeTree
|
3
|
+
module Name2X
|
4
|
+
class Delegate
|
5
|
+
|
6
|
+
# Hash delegate
|
7
|
+
attr_reader :delegate
|
8
|
+
|
9
|
+
# Creates FromHash instance
|
10
|
+
def initialize(delegate)
|
11
|
+
@delegate = delegate
|
12
|
+
end
|
13
|
+
|
14
|
+
# Converts an argument to a sub-class of this
|
15
|
+
# delegate implementation
|
16
|
+
def self.coerce(arg)
|
17
|
+
case arg
|
18
|
+
when Delegate
|
19
|
+
arg
|
20
|
+
when Hash, Proc
|
25
21
|
Delegate.new(arg)
|
22
|
+
when Module
|
23
|
+
ModuleDelegate.new(arg)
|
26
24
|
else
|
27
|
-
|
28
|
-
|
25
|
+
if arg.respond_to?(:[])
|
26
|
+
Delegate.new(arg)
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Unable to convert #{arg} to a Name2X::Delegate", caller
|
29
|
+
end
|
30
|
+
end
|
29
31
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end #
|
56
|
-
end # module
|
57
|
-
end # module
|
32
|
+
|
33
|
+
# Make a fetch on from_hash
|
34
|
+
def fetch(name)
|
35
|
+
delegate[name]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convert a name to a module
|
39
|
+
def name2module(name)
|
40
|
+
result = fetch(name)
|
41
|
+
result.kind_of?(Module) ? result : nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Convert a name to a class
|
45
|
+
def name2class(name)
|
46
|
+
result = fetch(name)
|
47
|
+
result.kind_of?(Class) ? result : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Convert a name to another name
|
51
|
+
def name2name(name)
|
52
|
+
result = fetch(name)
|
53
|
+
result.kind_of?(Symbol) ? result : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
end # class FromHash
|
57
|
+
end # module Name2X
|
58
|
+
end # module CodeTree
|
59
|
+
end # module SByC
|