rattler 0.3.0 → 0.4.0
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/README.rdoc +57 -37
- data/features/command_line/dest_option.feature +8 -21
- data/features/command_line/lib_option.feature +37 -0
- data/features/command_line/parser_generator.feature +7 -4
- data/features/grammar/back_reference.feature +37 -0
- data/features/grammar/fail.feature +3 -3
- data/features/grammar/labels.feature +11 -3
- data/features/grammar/list_matching.feature +14 -5
- data/features/grammar/literal.feature +30 -4
- data/features/grammar/nonterminal.feature +1 -1
- data/features/grammar/ordered_choice.feature +2 -2
- data/features/grammar/skip_operator.feature +1 -1
- data/features/grammar/symantic_action.feature +7 -7
- data/features/grammar/whitespace.feature +2 -2
- data/features/step_definitions/grammar_steps.rb +2 -2
- data/lib/rattler/back_end.rb +1 -0
- data/lib/rattler/back_end/compiler.rb +19 -20
- data/lib/rattler/back_end/optimizer.rb +100 -0
- data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
- data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
- data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
- data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
- data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
- data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
- data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
- data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
- data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
- data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
- data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
- data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
- data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
- data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
- data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
- data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
- data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
- data/lib/rattler/back_end/parser_generator.rb +21 -14
- data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
- data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
- data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
- data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
- data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
- data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
- data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
- data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
- data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
- data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
- data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
- data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
- data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
- data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
- data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
- data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
- data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
- data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
- data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
- data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
- data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
- data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
- data/lib/rattler/grammar.rb +4 -3
- data/lib/rattler/grammar/analysis.rb +91 -0
- data/lib/rattler/grammar/grammar.rb +37 -25
- data/lib/rattler/grammar/grammar_parser.rb +19 -11
- data/lib/rattler/grammar/metagrammar.rb +569 -800
- data/lib/rattler/grammar/rattler.rtlr +162 -144
- data/lib/rattler/parsers.rb +5 -1
- data/lib/rattler/parsers/action_code.rb +29 -15
- data/lib/rattler/parsers/apply.rb +5 -5
- data/lib/rattler/parsers/assert.rb +4 -18
- data/lib/rattler/parsers/back_reference.rb +46 -0
- data/lib/rattler/parsers/choice.rb +6 -39
- data/lib/rattler/parsers/combinator_parser.rb +32 -0
- data/lib/rattler/parsers/combining.rb +3 -29
- data/lib/rattler/parsers/direct_action.rb +27 -30
- data/lib/rattler/parsers/disallow.rb +4 -18
- data/lib/rattler/parsers/dispatch_action.rb +30 -25
- data/lib/rattler/parsers/label.rb +9 -18
- data/lib/rattler/parsers/list.rb +3 -34
- data/lib/rattler/parsers/list1.rb +4 -36
- data/lib/rattler/parsers/list_parser.rb +64 -0
- data/lib/rattler/parsers/match.rb +7 -42
- data/lib/rattler/parsers/node_code.rb +44 -0
- data/lib/rattler/parsers/one_or_more.rb +7 -27
- data/lib/rattler/parsers/optional.rb +5 -25
- data/lib/rattler/parsers/parser.rb +16 -44
- data/lib/rattler/parsers/parser_dsl.rb +13 -3
- data/lib/rattler/parsers/predicate.rb +4 -12
- data/lib/rattler/parsers/rule.rb +18 -19
- data/lib/rattler/parsers/rule_set.rb +63 -0
- data/lib/rattler/parsers/sequence.rb +12 -46
- data/lib/rattler/parsers/skip.rb +12 -26
- data/lib/rattler/parsers/token.rb +6 -21
- data/lib/rattler/parsers/zero_or_more.rb +6 -26
- data/lib/rattler/runner.rb +66 -28
- data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
- data/lib/rattler/runtime/packrat_parser.rb +17 -21
- data/lib/rattler/runtime/parser.rb +12 -2
- data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
- data/lib/rattler/util.rb +2 -1
- data/lib/rattler/util/graphviz.rb +29 -0
- data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
- data/lib/rattler/util/graphviz/node_builder.rb +84 -0
- data/lib/rattler/util/node.rb +37 -19
- data/lib/rattler/util/parser_spec_helper.rb +61 -35
- data/spec/rattler/back_end/compiler_spec.rb +6 -860
- data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
- data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
- data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
- data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
- data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
- data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
- data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
- data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
- data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
- data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
- data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
- data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
- data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
- data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
- data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
- data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
- data/spec/rattler/grammar/analysis_spec.rb +167 -0
- data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
- data/spec/rattler/grammar/grammar_spec.rb +24 -21
- data/spec/rattler/parsers/action_code_spec.rb +64 -19
- data/spec/rattler/parsers/apply_spec.rb +9 -9
- data/spec/rattler/parsers/back_reference_spec.rb +38 -0
- data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
- data/spec/rattler/parsers/direct_action_spec.rb +16 -2
- data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
- data/spec/rattler/parsers/fail_spec.rb +6 -4
- data/spec/rattler/parsers/label_spec.rb +10 -28
- data/spec/rattler/parsers/node_code_spec.rb +48 -0
- data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
- data/spec/rattler/parsers/rule_set_spec.rb +35 -0
- data/spec/rattler/parsers/sequence_spec.rb +15 -24
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
- data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
- data/spec/rattler/runtime/parse_node_spec.rb +15 -19
- data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
- data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
- data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
- data/spec/rattler/util/node_spec.rb +92 -65
- data/spec/rattler_spec.rb +16 -16
- data/spec/support/combinator_parser_spec_helper.rb +19 -18
- data/spec/support/compiler_spec_helper.rb +56 -87
- data/spec/support/runtime_parser_spec_helper.rb +6 -14
- metadata +117 -22
- data/features/grammar/regex.feature +0 -24
- data/lib/rattler/parsers/match_joining.rb +0 -67
- data/lib/rattler/parsers/rules.rb +0 -43
@@ -0,0 +1,71 @@
|
|
1
|
+
#
|
2
|
+
# = rattler/util/graphviz/digraph_builder.rb
|
3
|
+
#
|
4
|
+
# Author:: Jason Arhart
|
5
|
+
# Documentation:: Author
|
6
|
+
#
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'graphviz'
|
10
|
+
rescue LoadError => e
|
11
|
+
abort "I need the ruby-graphviz gem and GraphViz installed and in the PATH.\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'rattler/util/graphviz'
|
15
|
+
|
16
|
+
module Rattler::Util::GraphViz
|
17
|
+
#
|
18
|
+
# +DigraphBuilder+ is used to build GraphViz objects representing trees of
|
19
|
+
# nodes.
|
20
|
+
#
|
21
|
+
# @author Jason Arhart
|
22
|
+
#
|
23
|
+
class DigraphBuilder
|
24
|
+
|
25
|
+
# Return a new +GraphViz+ digraph object representing +root+.
|
26
|
+
#
|
27
|
+
# @return a new +GraphViz+ digraph object representing +root+
|
28
|
+
def self.digraph(root, name='G')
|
29
|
+
self.new(root, name).digraph
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a new digraph builder for +root+.
|
33
|
+
def initialize(root, name='G')
|
34
|
+
@root = root
|
35
|
+
@g = ::GraphViz.digraph(name)
|
36
|
+
@nodes = {}
|
37
|
+
@node_serial = 0
|
38
|
+
@node_builder = NodeBuilder.new
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return a new +GraphViz+ digraph object representing the root object
|
42
|
+
def digraph
|
43
|
+
@digraph ||= begin
|
44
|
+
node(@root)
|
45
|
+
@g
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a <tt>GraphViz::Node</tt> object for +o+. Multiple requests with
|
50
|
+
# the same object return the same node object.
|
51
|
+
#
|
52
|
+
# @return a <tt>GraphViz::Node</tt> object for +o+
|
53
|
+
def node(o)
|
54
|
+
@nodes.fetch(o.object_id) do
|
55
|
+
new_node = @g.add_node new_node_name, @node_builder.node_options(o)
|
56
|
+
@nodes[o.object_id] = new_node
|
57
|
+
@node_builder.each_child_of(o) {|_| new_node << node(_) }
|
58
|
+
new_node
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def new_node_name
|
65
|
+
name = "n#{@node_serial}"
|
66
|
+
@node_serial += 1
|
67
|
+
name
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#
|
2
|
+
# = rattler/util/graphviz/node_builder.rb
|
3
|
+
#
|
4
|
+
# Author:: Jason Arhart
|
5
|
+
# Documentation:: Author
|
6
|
+
#
|
7
|
+
require 'rattler/util/graphviz'
|
8
|
+
|
9
|
+
module Rattler::Util::GraphViz
|
10
|
+
#
|
11
|
+
# +NodeBuilder+ is used by +DigraphBuilder+ to build nodes for a GraphViz
|
12
|
+
# digraph object representing a tree of nodes.
|
13
|
+
#
|
14
|
+
# @author Jason Arhart
|
15
|
+
#
|
16
|
+
class NodeBuilder
|
17
|
+
|
18
|
+
# Yield any children of +o+ that should be represented as separate nodes in
|
19
|
+
# the graph.
|
20
|
+
def each_child_of(o)
|
21
|
+
o.each {|_| yield _ } if array_like? o and not record_like? o
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return the options for a node representing +o+.
|
25
|
+
# @return the options for a node representing +o+.
|
26
|
+
def node_options(o)
|
27
|
+
{ :shape => node_shape(o), :label => node_label(o) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the shape option for a node representing +o+.
|
31
|
+
# @return the shape option for a node representing +o+.
|
32
|
+
def node_shape(o)
|
33
|
+
case o
|
34
|
+
when Hash, Array
|
35
|
+
'circle'
|
36
|
+
when String, Numeric, Symbol
|
37
|
+
'plaintext'
|
38
|
+
else
|
39
|
+
'Mrecord'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the label option for a node representing +o+.
|
44
|
+
# @return the label option for a node representing +o+.
|
45
|
+
def node_label(o)
|
46
|
+
if o.is_a? ::Rattler::Util::Node
|
47
|
+
record_label(o, o.attrs)
|
48
|
+
elsif record_like? o
|
49
|
+
record_label(o, o)
|
50
|
+
elsif array_like? o
|
51
|
+
type_label(o)
|
52
|
+
else
|
53
|
+
o.inspect
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def type_label(o)
|
58
|
+
case o
|
59
|
+
when Hash then '\\{\\}'
|
60
|
+
when Array then '\\[\\]'
|
61
|
+
else o.respond_to?(:name) ? o.name : o.class.name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def array_like?(o)
|
66
|
+
o.respond_to? :each and
|
67
|
+
not o.respond_to? :to_str
|
68
|
+
end
|
69
|
+
|
70
|
+
def record_like?(o)
|
71
|
+
o.respond_to? :each_pair and
|
72
|
+
o.none? {|k, v| array_like? v or record_like? v }
|
73
|
+
end
|
74
|
+
|
75
|
+
def record_label(o, h)
|
76
|
+
'{' + ([type_label(o)] + hash_content_labels(h)).join('|') + '}'
|
77
|
+
end
|
78
|
+
|
79
|
+
def hash_content_labels(h)
|
80
|
+
h.map {|pair| '{' + pair.map {|_| _.inspect }.join('|') + '}' }
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/lib/rattler/util/node.rb
CHANGED
@@ -16,7 +16,7 @@ module Rattler::Util
|
|
16
16
|
#
|
17
17
|
class Node
|
18
18
|
include Enumerable
|
19
|
-
|
19
|
+
|
20
20
|
# Create a +Node+ object.
|
21
21
|
#
|
22
22
|
# @return [Node]
|
@@ -32,7 +32,7 @@ module Rattler::Util
|
|
32
32
|
def self.[](*args)
|
33
33
|
self.new(*args)
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
# Create a +Node+ object.
|
37
37
|
#
|
38
38
|
# @overload initialize()
|
@@ -47,7 +47,7 @@ module Rattler::Util
|
|
47
47
|
@attrs = args.last.respond_to?(:to_hash) ? args.pop : {}
|
48
48
|
@__children__ = args
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# Return an array of the node's children
|
52
52
|
#
|
53
53
|
# @return [Array] the node's children
|
@@ -62,7 +62,7 @@ module Rattler::Util
|
|
62
62
|
[]
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
# Return the node's child at +index+, or the first/only child if no index
|
67
67
|
# is given.
|
68
68
|
#
|
@@ -72,14 +72,14 @@ module Rattler::Util
|
|
72
72
|
def child(index = 0)
|
73
73
|
children[index]
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
# Return a the node's attributes.
|
77
77
|
#
|
78
78
|
# @return [Hash] the node's attributes
|
79
79
|
def attrs
|
80
80
|
@attrs ||= {}
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
# Return the node's name, which is the node's +name+ attribute if it has
|
84
84
|
# one, otherwise the name of the node's class.
|
85
85
|
#
|
@@ -87,21 +87,35 @@ module Rattler::Util
|
|
87
87
|
def name
|
88
88
|
attrs.fetch(:name, self.class.name)
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
# Call _block_ once for each child, passing that child as an argument.
|
92
92
|
#
|
93
93
|
# @yield [child]
|
94
94
|
def each # :yield: child
|
95
|
-
children.each { |_| yield _ }
|
95
|
+
block_given? ? children.each { |_| yield _ } : children.each
|
96
|
+
end
|
97
|
+
|
98
|
+
def with_children(new_children)
|
99
|
+
self.class.new(new_children, attrs)
|
100
|
+
end
|
101
|
+
|
102
|
+
alias_method :with_child, :with_children
|
103
|
+
|
104
|
+
def with_attrs(new_attrs)
|
105
|
+
self.with_attrs!(attrs.merge new_attrs)
|
106
|
+
end
|
107
|
+
|
108
|
+
def with_attrs!(new_attrs)
|
109
|
+
self.class.new(children, new_attrs)
|
96
110
|
end
|
97
|
-
|
111
|
+
|
98
112
|
# Return +true+ if the node has no children.
|
99
113
|
#
|
100
114
|
# @return [Boolean] +true+ if the node has no children
|
101
115
|
def empty?
|
102
116
|
children.empty?
|
103
117
|
end
|
104
|
-
|
118
|
+
|
105
119
|
# Access the node's children as if the node were an array of its children.
|
106
120
|
#
|
107
121
|
# @overload [](index)
|
@@ -122,7 +136,7 @@ module Rattler::Util
|
|
122
136
|
def [](*args)
|
123
137
|
children[*args]
|
124
138
|
end
|
125
|
-
|
139
|
+
|
126
140
|
# Return +true+ if the node is equal to +other+. Normally this means
|
127
141
|
# +other+ is an instance of the same class or a subclass and has equal
|
128
142
|
# children and attributes.
|
@@ -133,7 +147,7 @@ module Rattler::Util
|
|
133
147
|
other.can_equal?(self) and
|
134
148
|
self.same_contents?(other)
|
135
149
|
end
|
136
|
-
|
150
|
+
|
137
151
|
# Return +true+ if the node has the same value as +other+, i.e. +other+
|
138
152
|
# is an instance of the same class and has equal children and attributes.
|
139
153
|
#
|
@@ -142,28 +156,28 @@ module Rattler::Util
|
|
142
156
|
self.class == other.class and
|
143
157
|
self.same_contents?(other)
|
144
158
|
end
|
145
|
-
|
159
|
+
|
146
160
|
# Allow attributes to be accessed as methods.
|
147
161
|
def method_missing(symbol, *args)
|
148
|
-
(args.empty? and
|
162
|
+
(args.empty? and attrs.has_key?(symbol)) ? attrs[symbol] : super
|
149
163
|
end
|
150
|
-
|
164
|
+
|
151
165
|
# @private
|
152
166
|
def respond_to?(symbol) #:nodoc:
|
153
167
|
super || @attrs.has_key?(symbol)
|
154
168
|
end
|
155
|
-
|
169
|
+
|
156
170
|
# @private
|
157
171
|
def can_equal?(other) #:nodoc:
|
158
172
|
self.class == other.class
|
159
173
|
end
|
160
|
-
|
174
|
+
|
161
175
|
# @private
|
162
176
|
def same_contents?(other) #:nodoc:
|
163
177
|
self.children == other.children and
|
164
178
|
self.attrs == other.attrs
|
165
179
|
end
|
166
|
-
|
180
|
+
|
167
181
|
# @private
|
168
182
|
def inspect #:nodoc:
|
169
183
|
"#{self.class}[" +
|
@@ -171,6 +185,10 @@ module Rattler::Util
|
|
171
185
|
attrs.map {|k, v| k.inspect + '=>' + v.inspect}).join(',') +
|
172
186
|
']'
|
173
187
|
end
|
174
|
-
|
188
|
+
|
189
|
+
def to_graphviz
|
190
|
+
Rattler::Util::GraphViz.digraph(self)
|
191
|
+
end
|
192
|
+
|
175
193
|
end
|
176
194
|
end
|
@@ -12,17 +12,17 @@ module Rattler::Util
|
|
12
12
|
# for parsers.
|
13
13
|
#
|
14
14
|
# @example
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# require 'rattler/grammar/grammar_parser'
|
17
17
|
# require 'rattler/util/parser_spec_helper'
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# describe Rattler::Grammar::GrammarParser do
|
20
20
|
# include Rattler::Util::ParserSpecHelper
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# describe '#match(:var_name)' do
|
23
23
|
# it 'recognizes variable names' do
|
24
|
-
#
|
25
|
-
#
|
24
|
+
# matching(' fooBar ').as(:var_name).should result_in('fooBar').at(7)
|
25
|
+
# matching(' FooBar ').as(:var_name).should fail.with_message('variable name expected')
|
26
26
|
# end
|
27
27
|
# end
|
28
28
|
# end
|
@@ -30,39 +30,58 @@ module Rattler::Util
|
|
30
30
|
# @author Jason Arhart
|
31
31
|
#
|
32
32
|
module ParserSpecHelper
|
33
|
-
|
33
|
+
|
34
34
|
# Return a parse result to be matched using #result_in or #fail
|
35
|
-
#
|
36
|
-
# parsing(source)
|
37
|
-
# parsing(source).
|
35
|
+
#
|
36
|
+
# parsing(source)
|
37
|
+
# parsing(source).from(pos)
|
38
38
|
#
|
39
39
|
def parsing(source)
|
40
|
-
Parsing.new(
|
40
|
+
Parsing.new(parser(source))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return a match result to be matched using #result_in or #fail
|
44
|
+
#
|
45
|
+
# matching(source).as(rule_name)
|
46
|
+
# matching(source).as(rule_name).from(pos)
|
47
|
+
#
|
48
|
+
def matching(source)
|
49
|
+
Matching.new(parser(source))
|
50
|
+
end
|
51
|
+
|
52
|
+
def parser(source)
|
53
|
+
(self.respond_to?(:parser_class) ? parser_class : described_class).new(source)
|
41
54
|
end
|
42
|
-
|
55
|
+
|
43
56
|
# Expect parse to succeed.
|
44
|
-
#
|
45
|
-
# parsing(source).as(rule_name).should result_in(result)
|
46
57
|
#
|
47
|
-
#
|
48
|
-
#
|
58
|
+
# parsing(source).should result_in(result)
|
59
|
+
#
|
60
|
+
# Passes if parsing _source_ succeeds returning _result_.
|
49
61
|
#
|
50
|
-
# parsing(source).
|
62
|
+
# parsing(source).should result_in(result).at(pos)
|
51
63
|
#
|
52
|
-
# Passes if parsing _source_
|
64
|
+
# Passes if parsing _source_ succeeds returning
|
53
65
|
# _result_ with the parse position at _pos_.
|
54
66
|
#
|
55
67
|
# @return [Matcher]
|
56
68
|
RSpec::Matchers.define :result_in do |expected|
|
57
69
|
match do |target|
|
58
|
-
(target.result == expected)
|
59
|
-
(
|
70
|
+
(target.result == expected) and
|
71
|
+
(not @expected_pos or
|
72
|
+
target.pos == @expected_pos) and
|
73
|
+
(not @expected_bindings or
|
74
|
+
@expected_bindings.all?{|k, v| target.scope[k] == v })
|
60
75
|
end
|
61
|
-
|
76
|
+
|
62
77
|
chain :at do |pos|
|
63
78
|
@expected_pos = pos
|
64
79
|
end
|
65
|
-
|
80
|
+
|
81
|
+
chain :with_scope do |bindings|
|
82
|
+
@expected_bindings = bindings
|
83
|
+
end
|
84
|
+
|
66
85
|
failure_message_for_should do |target|
|
67
86
|
if target.result != expected
|
68
87
|
<<-MESSAGE
|
@@ -79,15 +98,15 @@ MESSAGE
|
|
79
98
|
end
|
80
99
|
end
|
81
100
|
end
|
82
|
-
|
101
|
+
|
83
102
|
# Expect parse to fail.
|
84
103
|
#
|
85
104
|
# parsing(source).as(rule_name).should fail
|
86
|
-
#
|
105
|
+
#
|
87
106
|
# Passes if parsing _source_ with _parser_class_ fails.
|
88
|
-
#
|
107
|
+
#
|
89
108
|
# parsing(source).as(rule_name).should fail.at(pos)
|
90
|
-
#
|
109
|
+
#
|
91
110
|
# Passes if parsing _source_ with _parser_class_ fails with the parse
|
92
111
|
# position at _pos_
|
93
112
|
#
|
@@ -98,15 +117,15 @@ MESSAGE
|
|
98
117
|
(!@expected_message || (target.failure.message == @expected_message)) &&
|
99
118
|
(!@expected_pos || (target.failure.pos == @expected_pos))
|
100
119
|
end
|
101
|
-
|
120
|
+
|
102
121
|
chain :with_message do |message|
|
103
122
|
@expected_message = message
|
104
123
|
end
|
105
|
-
|
124
|
+
|
106
125
|
chain :at do |pos|
|
107
126
|
@expected_pos = pos
|
108
127
|
end
|
109
|
-
|
128
|
+
|
110
129
|
failure_message_for_should do |target|
|
111
130
|
if target.result
|
112
131
|
"expected parse to fail but got #{target.result.inspect}"
|
@@ -125,7 +144,7 @@ MESSAGE
|
|
125
144
|
end
|
126
145
|
end
|
127
146
|
end
|
128
|
-
|
147
|
+
|
129
148
|
# @private
|
130
149
|
class Parsing #:nodoc:
|
131
150
|
def initialize(parser)
|
@@ -136,12 +155,8 @@ MESSAGE
|
|
136
155
|
@parser.pos = pos
|
137
156
|
self
|
138
157
|
end
|
139
|
-
def as(rule_name)
|
140
|
-
@rule_name = rule_name
|
141
|
-
self
|
142
|
-
end
|
143
158
|
def result
|
144
|
-
@result ||= @parser.
|
159
|
+
@result ||= @parser.parse
|
145
160
|
end
|
146
161
|
def pos
|
147
162
|
@parser.pos
|
@@ -150,6 +165,17 @@ MESSAGE
|
|
150
165
|
@parser.failure
|
151
166
|
end
|
152
167
|
end
|
153
|
-
|
168
|
+
|
169
|
+
# @private
|
170
|
+
class Matching < Parsing #:nodoc:
|
171
|
+
def as(rule_name)
|
172
|
+
@rule_name = rule_name
|
173
|
+
self
|
174
|
+
end
|
175
|
+
def result
|
176
|
+
@result ||= @parser.match(@rule_name)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
154
180
|
end
|
155
181
|
end
|