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
data/lib/rattler/runner.rb
CHANGED
@@ -12,24 +12,26 @@ require 'pathname'
|
|
12
12
|
module Rattler
|
13
13
|
# <tt>Rattler::Runner</tt> defines the command-line parser generator.
|
14
14
|
class Runner
|
15
|
-
|
15
|
+
|
16
16
|
ERRNO_USAGE = 1 # Invalid command line arguments
|
17
17
|
ERRNO_READ_ERROR = 2 # Error reading grammar file
|
18
18
|
ERRNO_WRITE_ERROR = 3 # Error writing parser file
|
19
19
|
ERRNO_PARSE_ERROR = 4 # Error parsing grammar
|
20
20
|
ERRNO_GEN_ERROR = 5 # Error generaing ruby code
|
21
|
-
|
21
|
+
|
22
22
|
# Run the command-line parser
|
23
23
|
#
|
24
24
|
# @param (see #initialize)
|
25
25
|
def self.run(args)
|
26
26
|
self.new(args).run
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Create a new command-line parser.
|
30
30
|
#
|
31
31
|
# @param [Array] args the command-line arguments
|
32
32
|
def initialize(args)
|
33
|
+
@standalone = false
|
34
|
+
@optimize = true
|
33
35
|
options.parse!(args)
|
34
36
|
if args.size == 1
|
35
37
|
@srcfname = Pathname.new(args.shift)
|
@@ -38,7 +40,7 @@ module Rattler
|
|
38
40
|
exit ERRNO_USAGE
|
39
41
|
end
|
40
42
|
end
|
41
|
-
|
43
|
+
|
42
44
|
# Run the command-line parser.
|
43
45
|
def run
|
44
46
|
if result = analyze
|
@@ -48,48 +50,69 @@ module Rattler
|
|
48
50
|
exit ERRNO_PARSE_ERROR
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
53
|
+
|
52
54
|
private
|
53
|
-
|
55
|
+
|
54
56
|
def options
|
55
57
|
@options ||= OptionParser.new do |opts|
|
58
|
+
|
56
59
|
opts.banner = "Usage: #{File.basename($0)} FILENAME [options]"
|
60
|
+
|
57
61
|
opts.separator ''
|
62
|
+
|
63
|
+
opts.on '-l', '--lib DIRECTORY',
|
64
|
+
'Specify the destination lib directory' do |libdir|
|
65
|
+
@libdir = Pathname.new(libdir)
|
66
|
+
end
|
67
|
+
|
58
68
|
opts.on '-d', '--dest DIRECTORY',
|
59
|
-
'Specify
|
60
|
-
@destdir = Pathname.new(destdir)
|
69
|
+
'Specify an explicit destination directory' do |destdir|
|
70
|
+
@destdir = Pathname.new(destdir)
|
61
71
|
end
|
72
|
+
|
62
73
|
opts.on '-o', '--output FILENAME',
|
63
|
-
'Specify a different output filename' do |ofname|
|
74
|
+
'Specify a different output filename ("-" = STDOUT)' do |ofname|
|
64
75
|
@ofname = ofname
|
65
76
|
end
|
77
|
+
|
66
78
|
opts.on '-f', '--force',
|
67
79
|
'Force overwrite if the output file exists' do |f|
|
68
80
|
@force = f
|
69
81
|
end
|
82
|
+
|
83
|
+
opts.on '-s', '--standalone',
|
84
|
+
'Optimize for use as a standalone parser' do |s|
|
85
|
+
@standalone = s
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on '-n', '--no-optimize',
|
89
|
+
'Disable optimization' do |n|
|
90
|
+
@optimize = n
|
91
|
+
end
|
92
|
+
|
70
93
|
opts.separator ''
|
94
|
+
|
71
95
|
opts.on_tail '-h', '--help', 'Show this message' do
|
72
|
-
|
73
|
-
exit
|
96
|
+
abort "#{opts}\n"
|
74
97
|
end
|
75
98
|
end
|
76
99
|
end
|
77
|
-
|
100
|
+
|
78
101
|
def parser
|
79
102
|
@parser ||= Rattler::Grammar::GrammarParser.new(@srcfname.read)
|
80
103
|
end
|
81
|
-
|
104
|
+
|
82
105
|
def analyze
|
83
106
|
parser.parse
|
84
107
|
rescue Exception => e
|
85
108
|
puts e
|
86
109
|
exit ERRNO_READ_ERROR
|
87
110
|
end
|
88
|
-
|
111
|
+
|
89
112
|
def synthesize(g)
|
90
113
|
open_output(g) do |io|
|
91
114
|
begin
|
92
|
-
io.puts
|
115
|
+
io.puts code_for(g)
|
93
116
|
rescue Exception => e
|
94
117
|
puts e
|
95
118
|
exit ERRNO_GEN_ERROR
|
@@ -99,7 +122,15 @@ module Rattler
|
|
99
122
|
puts e
|
100
123
|
exit ERRNO_WRITE_ERROR
|
101
124
|
end
|
102
|
-
|
125
|
+
|
126
|
+
def code_for(g)
|
127
|
+
Rattler::BackEnd::ParserGenerator.code_for g, generator_options
|
128
|
+
end
|
129
|
+
|
130
|
+
def generator_options
|
131
|
+
{ :standalone => @standalone, :no_optimize => !@optimize }
|
132
|
+
end
|
133
|
+
|
103
134
|
def open_output(g)
|
104
135
|
if @ofname == '-'
|
105
136
|
yield $stdout
|
@@ -107,32 +138,39 @@ module Rattler
|
|
107
138
|
open_to_write(full_dest_name(g)) {|io| yield io }
|
108
139
|
end
|
109
140
|
end
|
110
|
-
|
141
|
+
|
111
142
|
def report(dest)
|
112
143
|
puts "#{relative_path @srcfname} -> #{relative_path dest}"
|
113
144
|
end
|
114
|
-
|
145
|
+
|
115
146
|
def open_to_write(dest)
|
116
|
-
|
147
|
+
if dest.exist? and not @force
|
148
|
+
raise "File exists - #{relative_path dest} (use --force to overwrite)"
|
149
|
+
end
|
117
150
|
dest.dirname.mkpath
|
118
151
|
report(dest)
|
119
152
|
dest.open('w') { |f| yield f }
|
120
153
|
end
|
121
|
-
|
154
|
+
|
122
155
|
def full_dest_name(g)
|
123
156
|
names = g.name.split('::').map {|_| underscore _ }
|
124
|
-
|
125
|
-
destdir
|
157
|
+
ofname = @ofname || (names[-1] + '.rb')
|
158
|
+
if @destdir
|
159
|
+
@destdir.join(ofname)
|
160
|
+
else
|
161
|
+
names[-1] = ofname
|
162
|
+
libdir.join(*names)
|
163
|
+
end
|
126
164
|
end
|
127
|
-
|
128
|
-
def
|
129
|
-
@
|
165
|
+
|
166
|
+
def libdir
|
167
|
+
@libdir ||= Pathname.getwd
|
130
168
|
end
|
131
|
-
|
169
|
+
|
132
170
|
def relative_path(p)
|
133
171
|
p.dirname.realpath.relative_path_from(Pathname.getwd) + p.basename
|
134
172
|
end
|
135
|
-
|
173
|
+
|
136
174
|
# copied shamelessly from ActiveSupport
|
137
175
|
def underscore(camel_cased_word)
|
138
176
|
camel_cased_word.to_s.gsub(/::/, '/').
|
@@ -141,6 +179,6 @@ module Rattler
|
|
141
179
|
tr("-", "_").
|
142
180
|
downcase
|
143
181
|
end
|
144
|
-
|
182
|
+
|
145
183
|
end
|
146
184
|
end
|
@@ -28,33 +28,39 @@ module Rattler::Runtime
|
|
28
28
|
@lr_stack = []
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
lr = LR.new(false, rule_name, nil)
|
36
|
-
@lr_stack.push lr
|
37
|
-
m = inject_memo rule_name, start_pos, lr, start_pos, nil, nil
|
38
|
-
result = eval_rule rule_name
|
39
|
-
@lr_stack.pop
|
40
|
-
if lr.head
|
41
|
-
m.end_pos = @scanner.pos
|
42
|
-
lr.seed = result
|
43
|
-
lr_answer rule_name, start_pos, m
|
31
|
+
def apply(rule_name)
|
32
|
+
start_pos = @scanner.pos
|
33
|
+
if m = memo_lr(rule_name, start_pos)
|
34
|
+
recall m, rule_name
|
44
35
|
else
|
45
|
-
|
36
|
+
lr = LR.new(false, rule_name, nil)
|
37
|
+
@lr_stack.push lr
|
38
|
+
m = inject_memo rule_name, start_pos, lr, start_pos
|
39
|
+
result = eval_rule rule_name
|
40
|
+
@lr_stack.pop
|
41
|
+
if lr.head
|
42
|
+
m.end_pos = @scanner.pos
|
43
|
+
lr.seed = result
|
44
|
+
lr_answer rule_name, start_pos, m
|
45
|
+
else
|
46
|
+
save m, result
|
47
|
+
end
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
51
|
+
alias_method :memoize_lr, :apply
|
52
|
+
|
53
|
+
private
|
54
|
+
|
49
55
|
# @private
|
50
|
-
def
|
51
|
-
m =
|
56
|
+
def memo_lr(rule_name, start_pos) #:nodoc:
|
57
|
+
m = memo(rule_name, start_pos)
|
52
58
|
head = @heads[start_pos] or return m
|
53
59
|
if !m && !head.involves?(rule_name)
|
54
|
-
return
|
60
|
+
return inject_fail rule_name, start_pos
|
55
61
|
end
|
56
62
|
if head.eval_set.delete(rule_name)
|
57
|
-
|
63
|
+
save m, eval_rule(rule_name)
|
58
64
|
end
|
59
65
|
return m
|
60
66
|
end
|
@@ -84,7 +90,7 @@ module Rattler::Runtime
|
|
84
90
|
if head.rule_name == rule_name
|
85
91
|
grow_lr(rule_name, start_pos, m, head) if m.result = m.result.seed
|
86
92
|
else
|
87
|
-
|
93
|
+
save m, m.result.seed
|
88
94
|
end
|
89
95
|
end
|
90
96
|
|
@@ -99,7 +105,7 @@ module Rattler::Runtime
|
|
99
105
|
@heads.delete(start_pos)
|
100
106
|
return recall m, rule_name
|
101
107
|
end
|
102
|
-
|
108
|
+
save m, result
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
@@ -27,10 +27,6 @@ module Rattler::Runtime
|
|
27
27
|
@memo = Hash.new {|h, rule_name| h[rule_name] = {} }
|
28
28
|
end
|
29
29
|
|
30
|
-
# @private
|
31
|
-
alias_method :eval_rule, :apply
|
32
|
-
private :eval_rule
|
33
|
-
|
34
30
|
protected
|
35
31
|
|
36
32
|
# Apply a rule by dispatching to the method associated with the given rule
|
@@ -47,51 +43,51 @@ module Rattler::Runtime
|
|
47
43
|
if m = memo(rule_name, start_pos)
|
48
44
|
recall m, rule_name
|
49
45
|
else
|
50
|
-
|
46
|
+
m = inject_fail rule_name, start_pos
|
47
|
+
save m, eval_rule(rule_name)
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
51
|
+
alias_method :memoize, :apply
|
52
|
+
|
53
|
+
alias_method :eval_rule, :send
|
54
|
+
|
54
55
|
private
|
55
56
|
|
56
57
|
# @private
|
57
|
-
def
|
58
|
-
|
59
|
-
memorize m, eval_rule(rule_name)
|
58
|
+
def memo(rule_name, start_pos) #:nodoc:
|
59
|
+
@memo[rule_name][start_pos]
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
# @private
|
63
|
+
def inject_memo(rule_name, start_pos, result, end_pos) #:nodoc:
|
64
|
+
@memo[rule_name][start_pos] = MemoEntry.new(result, end_pos)
|
64
65
|
end
|
65
66
|
|
66
|
-
|
67
|
-
|
67
|
+
# @private
|
68
|
+
def inject_fail(rule_name, fail_pos) #:nodoc:
|
69
|
+
@memo[rule_name][fail_pos] = MemoEntry.new(false, fail_pos)
|
68
70
|
end
|
69
71
|
|
70
72
|
# @private
|
71
|
-
def
|
73
|
+
def save(m, result) #:nodoc:
|
72
74
|
m.end_pos = @scanner.pos
|
73
|
-
m.failure_pos = @failure_pos
|
74
|
-
m.failure_msg = @failure_msg
|
75
75
|
m.result = result
|
76
76
|
end
|
77
77
|
|
78
78
|
# @private
|
79
79
|
def recall(m, rule_name) #:nodoc:
|
80
80
|
@scanner.pos = m.end_pos
|
81
|
-
@failure_pos = m.failure_pos
|
82
|
-
@failure_msg = m.failure_msg
|
83
81
|
m.result
|
84
82
|
end
|
85
83
|
|
86
84
|
# @private
|
87
85
|
class MemoEntry #:nodoc:
|
88
|
-
def initialize(result, end_pos
|
86
|
+
def initialize(result, end_pos)
|
89
87
|
@result = result
|
90
88
|
@end_pos = end_pos
|
91
|
-
@failure_pos = failure_pos
|
92
|
-
@failure_msg = failure_msg
|
93
89
|
end
|
94
|
-
attr_accessor :result, :end_pos
|
90
|
+
attr_accessor :result, :end_pos
|
95
91
|
end
|
96
92
|
|
97
93
|
end
|
@@ -14,7 +14,7 @@ module Rattler::Runtime
|
|
14
14
|
#
|
15
15
|
# @author Jason Arhart
|
16
16
|
#
|
17
|
-
class Parser
|
17
|
+
class Parser < Rattler::Util::Node
|
18
18
|
|
19
19
|
# Parse +source+ and raise a {SyntaxError} if the parse fails.
|
20
20
|
#
|
@@ -25,6 +25,16 @@ module Rattler::Runtime
|
|
25
25
|
self.new(source, options).parse!
|
26
26
|
end
|
27
27
|
|
28
|
+
# Parse the entirety of +source+ and raise a {SyntaxError} if the parse
|
29
|
+
# fails.
|
30
|
+
#
|
31
|
+
# @param (see #initialize)
|
32
|
+
# @raise (see #parse!)
|
33
|
+
# @return (see #parse!)
|
34
|
+
def self.parse_fully!(source, options={})
|
35
|
+
self.new(source, options).parse_fully!
|
36
|
+
end
|
37
|
+
|
28
38
|
# Create a new parser to parse +source+.
|
29
39
|
#
|
30
40
|
# @param [String] source the source to parse
|
@@ -71,7 +81,7 @@ module Rattler::Runtime
|
|
71
81
|
#
|
72
82
|
# @return (see #parse_fully)
|
73
83
|
def parse_fully!
|
74
|
-
|
84
|
+
parse_fully or raise_error
|
75
85
|
end
|
76
86
|
|
77
87
|
# The current parse position
|
@@ -38,7 +38,7 @@ module Rattler::Runtime
|
|
38
38
|
# @return (see #apply)
|
39
39
|
#
|
40
40
|
def match(rule_name)
|
41
|
-
|
41
|
+
send @rule_method_names[rule_name] or fail { rule_name }
|
42
42
|
end
|
43
43
|
|
44
44
|
def method_missing(symbol, *args)
|
@@ -59,16 +59,8 @@ module Rattler::Runtime
|
|
59
59
|
match start_rule
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
# called by +match+ and should not be called directly.
|
65
|
-
#
|
66
|
-
# @param [Symbol] rule_name the name of the rule to apply
|
67
|
-
#
|
68
|
-
# @return the result of applying the rule
|
69
|
-
#
|
70
|
-
def apply(rule_name)
|
71
|
-
send @rule_method_names[rule_name]
|
62
|
+
def apply(rule_method_name)
|
63
|
+
send rule_method_name
|
72
64
|
end
|
73
65
|
|
74
66
|
end
|
data/lib/rattler/util.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# = rattler/util/graphviz.rb
|
3
|
+
#
|
4
|
+
# Author:: Jason Arhart
|
5
|
+
# Documentation:: Author
|
6
|
+
#
|
7
|
+
require 'rattler/util'
|
8
|
+
|
9
|
+
module Rattler::Util
|
10
|
+
#
|
11
|
+
# The +GraphViz+ provides utilities to build GraphViz objects representing
|
12
|
+
# trees of nodes.
|
13
|
+
#
|
14
|
+
# @author Jason Arhart
|
15
|
+
#
|
16
|
+
module GraphViz
|
17
|
+
|
18
|
+
autoload :DigraphBuilder, 'rattler/util/graphviz/digraph_builder'
|
19
|
+
autoload :NodeBuilder, 'rattler/util/graphviz/node_builder'
|
20
|
+
|
21
|
+
# Return a new +GraphViz+ digraph object representing +root+.
|
22
|
+
#
|
23
|
+
# @return a new +GraphViz+ digraph object representing +root+
|
24
|
+
def self.digraph(root)
|
25
|
+
DigraphBuilder.digraph(root)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|