sbyc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENCE.textile +12 -0
- data/README.textile +44 -0
- data/lib/sbyc.rb +14 -0
- data/lib/sbyc/codetree.rb +82 -0
- data/lib/sbyc/codetree/ast_node.rb +101 -0
- data/lib/sbyc/codetree/eval.rb +3 -0
- data/lib/sbyc/codetree/eval/ast_node_ext.rb +38 -0
- data/lib/sbyc/codetree/eval/functional_eval.rb +36 -0
- data/lib/sbyc/codetree/eval/object_eval.rb +36 -0
- data/lib/sbyc/codetree/matching.rb +3 -0
- data/lib/sbyc/codetree/matching/ast_node_ext.rb +14 -0
- data/lib/sbyc/codetree/matching/match_data.rb +30 -0
- data/lib/sbyc/codetree/matching/matcher.rb +83 -0
- data/lib/sbyc/codetree/proc_parser.rb +91 -0
- data/lib/sbyc/codetree/producing.rb +1 -0
- data/lib/sbyc/codetree/producing/producer.rb +68 -0
- data/lib/sbyc/codetree/rewriting.rb +4 -0
- data/lib/sbyc/codetree/rewriting/class_methods.rb +15 -0
- data/lib/sbyc/codetree/rewriting/compiler.rb +28 -0
- data/lib/sbyc/codetree/rewriting/instance_methods.rb +92 -0
- data/lib/sbyc/codetree/rewriting/match.rb +59 -0
- data/test/spec/documentation/codetree/production.spec +59 -0
- data/test/spec/documentation/readme/assumptions.spec +33 -0
- data/test/spec/documentation/readme/functional_evaluation.spec +29 -0
- data/test/spec/documentation/readme/object_evaluation.spec +17 -0
- data/test/spec/documentation/readme/rewriting.spec +60 -0
- data/test/spec/documentation/readme/semantics.spec +21 -0
- data/test/spec/documentation/readme/synopsis.spec +27 -0
- data/test/spec/documentation/readme/syntax.spec +26 -0
- data/test/spec/spec_helper.rb +13 -0
- data/test/spec/test_all.rb +6 -0
- data/test/spec/unit/sbyc/codetree/ast_node/coerce.spec +60 -0
- data/test/spec/unit/sbyc/codetree/ast_node/equality.spec +75 -0
- data/test/spec/unit/sbyc/codetree/ast_node/inspect.spec +23 -0
- data/test/spec/unit/sbyc/codetree/ast_node/literal.spec +15 -0
- data/test/spec/unit/sbyc/codetree/ast_node/to_a.spec +27 -0
- data/test/spec/unit/sbyc/codetree/ast_node/to_s.spec +23 -0
- data/test/spec/unit/sbyc/codetree/ast_node/visit.spec +34 -0
- data/test/spec/unit/sbyc/codetree/eval/functional_compile.spec +30 -0
- data/test/spec/unit/sbyc/codetree/eval/functional_eval.spec +34 -0
- data/test/spec/unit/sbyc/codetree/eval/functional_proc.spec +36 -0
- data/test/spec/unit/sbyc/codetree/eval/object_compile.spec +36 -0
- data/test/spec/unit/sbyc/codetree/eval/object_eval.spec +38 -0
- data/test/spec/unit/sbyc/codetree/eval/object_proc.spec +36 -0
- data/test/spec/unit/sbyc/codetree/matching/matcher/args_match.spec +91 -0
- data/test/spec/unit/sbyc/codetree/matching/matcher/do_match.spec +39 -0
- data/test/spec/unit/sbyc/codetree/matching/matcher/function_match.spec +45 -0
- data/test/spec/unit/sbyc/codetree/matching/matcher/match.spec +64 -0
- data/test/spec/unit/sbyc/codetree/proc_parser/expr.spec +20 -0
- data/test/spec/unit/sbyc/codetree/proc_parser/parse.spec +83 -0
- data/test/spec/unit/sbyc/codetree/producing/producer.spec +31 -0
- data/test/spec/unit/sbyc/codetree/producing/producer/apply_args_conventions.spec +60 -0
- data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/apply_args_conventions.spec +60 -0
- data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/node.spec +19 -0
- data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/rewrite.spec +76 -0
- data/test/spec/unit/sbyc/codetree/rewriting/match/apply.spec +23 -0
- data/test/spec/unit/sbyc/codetree/rewriting/match/coerce.spec +48 -0
- data/test/spec/unit/sbyc/codetree/rewriting/match/matches.spec +27 -0
- metadata +129 -0
data/LICENCE.textile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
h1. The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Bernard Lambeau and the University of Louvain (Universite Catholique de Louvain, Louvain-la-Neuve, Belgium)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
10
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
11
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
12
|
+
|
data/README.textile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
h1. SByC - Investigating Specialization by Constraint
|
2
|
+
|
3
|
+
h2. SYNOPSIS
|
4
|
+
|
5
|
+
SByC is an investigation about Specialization by Constraint as an alternative to common type systems that we found in (object-oriented) programming languages. The library is written as a collection of Ruby tools described below. Those tools are in fact sub-gems of SByC that can often be used in isolation.
|
6
|
+
|
7
|
+
h2. CodeTree
|
8
|
+
|
9
|
+
This part of SByC provides a safe, reusable, extensible, mashallable, and non-intrusive (no monkey patching of Ruby core classes) implementation of block expressions. Block expressions are parsed using a generic DSL and converted to a parse tree, which may be analyzed, rewrited, compiled, and so on. The example below illustrates typical usage of CodeTree.
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
code = CodeTree::parse{ x > 10 & y < 20 }
|
13
|
+
# => (& (> x, 10), (< y, 20))
|
14
|
+
|
15
|
+
# See the evaluation section for details
|
16
|
+
code.eval{:x => 5, :y => 5}
|
17
|
+
# => true
|
18
|
+
|
19
|
+
# See the code-generation section for details
|
20
|
+
code.object_compile('scope', :[])
|
21
|
+
# => "scope[:x].>(10) & scope[:y].<(20)"
|
22
|
+
|
23
|
+
# CodeTree expressions may be marshaled
|
24
|
+
Marshal.dump(code)
|
25
|
+
</pre>
|
26
|
+
|
27
|
+
"Learn more about CodeTree":http://blambeau.github.com/sbyc/codetree.html
|
28
|
+
|
29
|
+
h2. INSTALL
|
30
|
+
|
31
|
+
bc. gem install sbyc
|
32
|
+
|
33
|
+
h2. DOCUMENTATION
|
34
|
+
|
35
|
+
* The official documentation can be found on "GitHub pages":http://blambeau.github.com/sbyc/
|
36
|
+
* The api documentation can be found on "rdoc.info":http://rdoc.info/projects/blambeau/sbyc
|
37
|
+
|
38
|
+
h2. CONTRIBUTE
|
39
|
+
|
40
|
+
Fork the project on "github":http://github.com/blambeau/sbyc, make a contrib, and send me a pull request
|
41
|
+
|
42
|
+
h2. CREDITS
|
43
|
+
|
44
|
+
SByC (c) 2010 by Bernard Lambeau. SByC is distributed under the MIT licence. Please see the LICENCE.md document for details.
|
data/lib/sbyc.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module CodeTree
|
2
|
+
|
3
|
+
# Operator names
|
4
|
+
OPERATOR_NAMES = {
|
5
|
+
:[] => :get,
|
6
|
+
:[]= => :set,
|
7
|
+
:** => :exponentiation,
|
8
|
+
:~ => :complement,
|
9
|
+
:== => :eq,
|
10
|
+
#:!= => :neq,
|
11
|
+
:-@ => :unary_minus,
|
12
|
+
:+@ => :unary_plus,
|
13
|
+
:- => :minus,
|
14
|
+
:+ => :plus,
|
15
|
+
:* => :times,
|
16
|
+
:/ => :divide,
|
17
|
+
:% => :modulo,
|
18
|
+
:=~ => :match,
|
19
|
+
:=== => :matches?,
|
20
|
+
:& => :bool_and,
|
21
|
+
:| => :bool_or,
|
22
|
+
:> => :gt,
|
23
|
+
:>= => :gte,
|
24
|
+
:<= => :lte,
|
25
|
+
:< => :lt,
|
26
|
+
:>> => :right_shift,
|
27
|
+
:<< => :left_shift,
|
28
|
+
:'^' => :exclusive,
|
29
|
+
:<=> => :compare
|
30
|
+
}
|
31
|
+
REVERSE_OPERATOR_NAMES = Hash[*OPERATOR_NAMES.to_a.collect{|c| c.reverse}.flatten]
|
32
|
+
|
33
|
+
# Parses some code or block
|
34
|
+
def parse(code = nil, &block)
|
35
|
+
ProcParser::parse(code, &block)
|
36
|
+
end
|
37
|
+
module_function :parse
|
38
|
+
|
39
|
+
# Alias for _parse_
|
40
|
+
def expr(code = nil, &block)
|
41
|
+
ProcParser::parse(code, &block)
|
42
|
+
end
|
43
|
+
module_function :expr
|
44
|
+
|
45
|
+
# Factors a CodeTree::Matcher instance
|
46
|
+
def matcher(code = nil, &block)
|
47
|
+
CodeTree::Matcher.new(parse(code, &block))
|
48
|
+
end
|
49
|
+
module_function :matcher
|
50
|
+
|
51
|
+
# Factors a rewriter instance
|
52
|
+
def rewriter(&definition)
|
53
|
+
CodeTree::Rewriting::Rewriter.new(&definition)
|
54
|
+
end
|
55
|
+
module_function :rewriter
|
56
|
+
|
57
|
+
# Factors a producer instance
|
58
|
+
def producer(default_rules = true, &definition)
|
59
|
+
CodeTree::Producing::Producer.new(default_rules, &definition)
|
60
|
+
end
|
61
|
+
module_function :producer
|
62
|
+
|
63
|
+
# Converts an argument to an parse tree (an ASTNode instance)
|
64
|
+
def coerce(arg)
|
65
|
+
case arg
|
66
|
+
when AstNode
|
67
|
+
arg
|
68
|
+
when Proc, String
|
69
|
+
CodeTree::parse(arg)
|
70
|
+
else
|
71
|
+
raise "Unable to coerce #{arg.inspect} to a CodeTree::AstNode"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
module_function :coerce
|
75
|
+
|
76
|
+
end # module CodeTree
|
77
|
+
require 'sbyc/codetree/ast_node'
|
78
|
+
require 'sbyc/codetree/proc_parser'
|
79
|
+
require 'sbyc/codetree/eval'
|
80
|
+
require 'sbyc/codetree/producing'
|
81
|
+
require 'sbyc/codetree/matching'
|
82
|
+
require 'sbyc/codetree/rewriting'
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module CodeTree
|
2
|
+
class AstNode
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# Name of the method call
|
6
|
+
attr_reader :name
|
7
|
+
alias :function :name
|
8
|
+
|
9
|
+
# Children nodes
|
10
|
+
attr_reader :children
|
11
|
+
alias :args :children
|
12
|
+
|
13
|
+
# Operator found by type checking
|
14
|
+
attr_reader :operator
|
15
|
+
|
16
|
+
# Creates an ASTNode instance
|
17
|
+
def initialize(name, children)
|
18
|
+
@name, @children = name, children
|
19
|
+
end
|
20
|
+
|
21
|
+
# Delegated to the children array
|
22
|
+
def [](*args, &block)
|
23
|
+
children.[](*args, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Recursively finds the first literal.
|
27
|
+
def literal
|
28
|
+
leaf? ? children[0] : children[0].literal
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns false
|
32
|
+
def leaf?
|
33
|
+
(name == :_)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Negation of leaf?
|
37
|
+
def branch?
|
38
|
+
not(leaf?)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Yields block with each child in turn
|
42
|
+
def each(&block)
|
43
|
+
children.each(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Makes a depth-first-search visit of the AST
|
47
|
+
def visit(&block)
|
48
|
+
yield(self, leaf? ? children : children.collect{|c| c.visit(&block)})
|
49
|
+
end
|
50
|
+
alias :produce :visit
|
51
|
+
|
52
|
+
# Inspection
|
53
|
+
def inspect
|
54
|
+
"(#{name} #{children.collect{|c| c.inspect}.join(', ')})"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns a short string representation
|
58
|
+
def to_s
|
59
|
+
case function
|
60
|
+
when :'_'
|
61
|
+
literal.inspect
|
62
|
+
when :'?'
|
63
|
+
literal.to_s
|
64
|
+
else
|
65
|
+
"(#{name} #{children.collect{|c| c.to_s}.join(', ')})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns an array version of this ast
|
70
|
+
def to_a
|
71
|
+
visit{|node, collected| [node.name, collected]}
|
72
|
+
end
|
73
|
+
|
74
|
+
# Checks tree equality with another node
|
75
|
+
def ==(other)
|
76
|
+
return false unless other.kind_of?(AstNode)
|
77
|
+
return false unless (function == other.function)
|
78
|
+
return false unless args.size == other.args.size
|
79
|
+
return false unless args.zip(other.args).all?{|v1, v2| v1 == v2}
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
# Coercion
|
84
|
+
def self.coerce(arg)
|
85
|
+
case arg
|
86
|
+
when AstNode
|
87
|
+
arg
|
88
|
+
when Array
|
89
|
+
name, children = arg
|
90
|
+
if name == :_ and children.size == 1
|
91
|
+
AstNode.new(:_, children)
|
92
|
+
else
|
93
|
+
AstNode.new(name, children.collect{|c| AstNode.coerce(c)})
|
94
|
+
end
|
95
|
+
else
|
96
|
+
AstNode.new(:_, [ arg ])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end # module AstNode
|
101
|
+
end # module CodeTree
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module CodeTree
|
2
|
+
class AstNode
|
3
|
+
|
4
|
+
# Generates the code of an object evaluation
|
5
|
+
def object_compile(scope_object = "scope", scope_method = :[])
|
6
|
+
CodeTree::ObjectEval.object_compile(self, scope_object, scope_method)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Generates a lambda function for object evaluation
|
10
|
+
def object_proc(scope_method = :[])
|
11
|
+
CodeTree::ObjectEval.object_proc(self, scope_method)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executes object evaluation of this ast
|
15
|
+
def object_eval(scope = {}, scope_method = :[])
|
16
|
+
CodeTree::ObjectEval.object_eval(self, scope)
|
17
|
+
end
|
18
|
+
alias :call :object_eval
|
19
|
+
alias :eval :object_eval
|
20
|
+
|
21
|
+
# Generates the code of an functional evaluation
|
22
|
+
def functional_compile(receiver_object = "receiver", scope_object = "scope", scope_method = :[])
|
23
|
+
CodeTree::FunctionalEval.functional_compile(self, receiver_object, scope_object, scope_method)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Generates a lambda function for functional evaluation
|
27
|
+
def functional_proc(scope_method = :[])
|
28
|
+
CodeTree::FunctionalEval.functional_proc(self, scope_method)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Executes functional evaluation of this ast
|
32
|
+
def functional_eval(master_object, scope = {}, scope_method = :[])
|
33
|
+
CodeTree::FunctionalEval.functional_eval(self, master_object, scope)
|
34
|
+
end
|
35
|
+
alias :apply :functional_eval
|
36
|
+
|
37
|
+
end # class AstNode
|
38
|
+
end # module CodeTree
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CodeTree
|
2
|
+
module FunctionalEval
|
3
|
+
|
4
|
+
# Generates code for a functional evaluation
|
5
|
+
def functional_compile(ast, receiver_object = "receiver", scope_object = "scope", scope_method = :[])
|
6
|
+
ast.produce{|node, collected|
|
7
|
+
case func = node.function
|
8
|
+
when :_
|
9
|
+
collected.first.inspect
|
10
|
+
when :'?'
|
11
|
+
if scope_method == :[]
|
12
|
+
"#{scope_object}[#{collected.join(', ')}]"
|
13
|
+
else
|
14
|
+
"#{scope_object}.#{scope_method}(#{collected.join(', ')})"
|
15
|
+
end
|
16
|
+
else
|
17
|
+
"#{receiver_object}.#{func}(#{collected.join(', ')})"
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
module_function :functional_compile
|
22
|
+
|
23
|
+
# Generates a lambda function for functional evaluation
|
24
|
+
def functional_proc(ast, scope_method = :[])
|
25
|
+
::Kernel.eval("::Kernel.lambda{|receiver, scope| #{functional_compile(ast, 'receiver', 'scope', scope_method)}}")
|
26
|
+
end
|
27
|
+
module_function :functional_proc
|
28
|
+
|
29
|
+
# Evaluates this AST with an object style.
|
30
|
+
def functional_eval(ast, receiver, scope = {}, scope_method = :[])
|
31
|
+
functional_proc(ast, scope_method).call(receiver, scope)
|
32
|
+
end
|
33
|
+
module_function :functional_eval
|
34
|
+
|
35
|
+
end # module FunctionalEval
|
36
|
+
end # module CodeTree
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CodeTree
|
2
|
+
module ObjectEval
|
3
|
+
|
4
|
+
# Generates code for an object evaluation
|
5
|
+
def object_compile(ast, scope_object = "scope", scope_method = :[])
|
6
|
+
ast.produce{|node, collected|
|
7
|
+
case func = node.function
|
8
|
+
when :'_'
|
9
|
+
collected.first.inspect
|
10
|
+
when :'?'
|
11
|
+
if scope_method == :[]
|
12
|
+
"#{scope_object}[#{collected.join(', ')}]"
|
13
|
+
else
|
14
|
+
"#{scope_object}.#{scope_method}(#{collected.join(', ')})"
|
15
|
+
end
|
16
|
+
else
|
17
|
+
"#{collected[0]}.#{func}(#{collected[1..-1].join(', ')})"
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
module_function :object_compile
|
22
|
+
|
23
|
+
# Generates a lambda function for object evaluation
|
24
|
+
def object_proc(ast, scope_method = :[])
|
25
|
+
::Kernel.eval "::Kernel.lambda{|scope| #{object_compile(ast, 'scope', scope_method)}}"
|
26
|
+
end
|
27
|
+
module_function :object_proc
|
28
|
+
|
29
|
+
# Evaluates this AST with an object style.
|
30
|
+
def object_eval(ast, scope = {}, scope_method = :[])
|
31
|
+
object_proc(ast, scope_method).call(scope)
|
32
|
+
end
|
33
|
+
module_function :object_eval
|
34
|
+
|
35
|
+
end # module ObjectEval
|
36
|
+
end # module CodeTree
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CodeTree
|
2
|
+
class MatchData
|
3
|
+
|
4
|
+
# Source AstNode of the matching
|
5
|
+
attr_reader :source
|
6
|
+
|
7
|
+
# Matched node
|
8
|
+
attr_reader :matched_node
|
9
|
+
|
10
|
+
# Captured variables
|
11
|
+
attr_reader :captures
|
12
|
+
|
13
|
+
# Creates a MatchData instance
|
14
|
+
def initialize(source, matched_node, captures)
|
15
|
+
@source, @matched_node, @captures = source, matched_node, captures
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns node matched under a given variable name
|
19
|
+
def [](varname)
|
20
|
+
captures[varname]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Inspects this MatchData
|
24
|
+
def inspect
|
25
|
+
"MatchData#{captures.inspect}"
|
26
|
+
end
|
27
|
+
alias :to_s :inspect
|
28
|
+
|
29
|
+
end # class MatchData
|
30
|
+
end # module CodeTree
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module CodeTree
|
2
|
+
class Matcher
|
3
|
+
|
4
|
+
# Match Abstract Syntax Tree
|
5
|
+
attr_reader :match_ast
|
6
|
+
|
7
|
+
# Creates an IMatch instance
|
8
|
+
def initialize(match_ast)
|
9
|
+
@match_ast = match_ast
|
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
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias :match :=~
|
21
|
+
alias :call :=~
|
22
|
+
|
23
|
+
# Returns true if _ast_node_ is matched by this matcher,
|
24
|
+
# false otherwise
|
25
|
+
def ===(ast_node)
|
26
|
+
not((self =~ ast_node).nil?)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Lookups for a match between _matcher_ and _matched_.
|
30
|
+
def do_match(matcher, matched, match_data = {})
|
31
|
+
return nil unless matched.kind_of?(CodeTree::AstNode)
|
32
|
+
return nil unless function_match(matcher, matched, match_data)
|
33
|
+
return nil unless args_match(matcher.args[1..-1], matched.args.dup, match_data)
|
34
|
+
return match_data
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Applies function name matching, returning true if _ast_node_'s function name
|
39
|
+
# is matched by first argument of _match_ast_.
|
40
|
+
#
|
41
|
+
# Cases that may arise:
|
42
|
+
# (match (_ :fname), ...) # true iif ast_node.function == fname
|
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
|
53
|
+
end
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Applies arguments matching, return true if there is a match,
|
59
|
+
# false otherwise.
|
60
|
+
#
|
61
|
+
def args_match(matchers, candidates, match_data = {})
|
62
|
+
matchers.each do |m|
|
63
|
+
case m.function
|
64
|
+
when :'?'
|
65
|
+
return false if candidates.empty?
|
66
|
+
match_data[m.literal] = candidates.shift
|
67
|
+
when :'_'
|
68
|
+
return false if candidates.empty?
|
69
|
+
return false unless candidates.shift.literal == m.literal
|
70
|
+
when :'[]'
|
71
|
+
return false if candidates.empty?
|
72
|
+
match_data[m.literal] = candidates
|
73
|
+
candidates = []
|
74
|
+
else
|
75
|
+
return false if candidates.empty?
|
76
|
+
return false unless do_match(m, candidates.shift, match_data)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
candidates.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
end # class Matcher
|
83
|
+
end # module CodeTree
|