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