grammar 0.5 → 0.8

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.
@@ -0,0 +1,155 @@
1
+
2
+ class JSON
3
+
4
+ def parse(io)
5
+ @la = io.getc
6
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
7
+ value(out=[], io)
8
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
9
+ raise("EOF expected") if @la
10
+ raise(out.inspect) unless out.length==1
11
+ out[0]
12
+ end
13
+
14
+ def error(expected, found)
15
+ raise("expected #{expected}, found #{found ? ("'"<<found<<?\') : 'EOF'}")
16
+ end
17
+
18
+ def value(out, io)
19
+ if ?\"==(@la)
20
+ out << string(io)
21
+ elsif ?\{==(@la)
22
+ # object
23
+ @la=io.getc
24
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
25
+ kv = []
26
+ unless ?\}==(@la)
27
+ kv = []
28
+ ?\"==(@la) ? (kv << string(io)) : error("a string", @la)
29
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
30
+ ?\:==(@la) ? (@la=io.getc) : error("':'", @la)
31
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
32
+ value(kv, io)
33
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
34
+ until ?\}==(@la)
35
+ ?,==(@la) ? (@la=io.getc) : error("','", @la)
36
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
37
+ ?\"==(@la) ? (kv << string(io)) : error("a string", @la)
38
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
39
+ ?\:==(@la) ? (@la=io.getc) : error("':'", @la)
40
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
41
+ value(kv, io)
42
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
43
+ end
44
+ end
45
+ @la = io.getc
46
+ out << Hash[*kv]
47
+ elsif ?\[==(@la)
48
+ # array
49
+ @la=io.getc
50
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
51
+ a = []
52
+ unless ?\]==(@la)
53
+ value(a, io)
54
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
55
+ until ?\]==(@la)
56
+ ?\,==(@la) ? (@la=io.getc) : error("','", @la)
57
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
58
+ value(a, io)
59
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
60
+ end
61
+ end
62
+ @la = io.getc
63
+ out << a
64
+ elsif ?t==(@la)
65
+ @la = io.getc
66
+ ?r==(@la) ? (@la=io.getc) : error(?r, @la)
67
+ ?u==(@la) ? (@la=io.getc) : error(?u, @la)
68
+ ?e==(@la) ? (@la=io.getc) : error(?e, @la)
69
+ out << true
70
+ elsif ?f==(@la)
71
+ @la = io.getc
72
+ ?a==(@la) ? (@la=io.getc) : error(?a, @la)
73
+ ?l==(@la) ? (@la=io.getc) : error(?l, @la)
74
+ ?s==(@la) ? (@la=io.getc) : error(?s, @la)
75
+ ?e==(@la) ? (@la=io.getc) : error(?e, @la)
76
+ out << false
77
+ elsif ?n==(@la)
78
+ @la = io.getc
79
+ ?u==(@la) ? (@la=io.getc) : error(?u, @la)
80
+ ?l==(@la) ? (@la=io.getc) : error(?l, @la)
81
+ ?l==(@la) ? (@la=io.getc) : error(?l, @la)
82
+ out << nil
83
+ else
84
+ # number
85
+ n = ""
86
+ (n<<@la;@la=io.getc) if ?-==(@la)
87
+ ?0==(@la) ? (n<<@la;@la=io.getc) : digits(n, io)
88
+ (?.==(@la) ?
89
+ (n<<@la;@la=io.getc;digits(n, io);exp(n, io);true) :
90
+ exp(n, io)) ?
91
+ (out << n.to_f) :
92
+ (out << n.to_i)
93
+ end
94
+ end
95
+
96
+ # Flattening any of the methods below will improve performance further
97
+
98
+ def ws(io)
99
+ @la = io.getc while (case @la;when ?\s,?\t,?\n,?\r;true;end)
100
+ end
101
+
102
+ def digits(out, io)
103
+ (?0<=@la && ?9>=@la) ? (out<<@la;@la=io.getc) : error("a digit", @la)
104
+ while (?0<=@la && ?9>=@la); (out<<@la;@la=io.getc); end
105
+ end
106
+
107
+ def exp(out, io)
108
+ (case @la;when ?e,?E;true;end) ? (out<<@la;@la=io.getc) :
109
+ return
110
+ (out<<@la;@la=io.getc) if (case @la;when ?-,?+;true;end)
111
+ digits(out, io)
112
+ true
113
+ end
114
+
115
+ def string(io)
116
+ # we've already verified the starting "
117
+ @la=io.getc
118
+ s = ""
119
+ until ?\"==(@la)
120
+ if ?\\==(@la)
121
+ @la = io.getc
122
+ case @la
123
+ when ?\",?\\,?\/ then (s<<@la;@la=io.getc)
124
+ when ?b then (s<<?\b;@la=io.getc)
125
+ when ?f then (s<<?\f;@la=io.getc)
126
+ when ?n then (s<<?\n;@la=io.getc)
127
+ when ?r then (s<<?\r;@la=io.getc)
128
+ when ?t then (s<<?\t;@la=io.getc)
129
+ when ?u
130
+ @la = io.getc
131
+ u = ""
132
+ 4.times {
133
+ case @la
134
+ when ?0..?9, ?a..?f, ?A..?F
135
+ u<<@la;@la=io.getc
136
+ else
137
+ error("a hex character", @la)
138
+ end
139
+ }
140
+ s << u.to_i(16)
141
+ else
142
+ error("a valid escape", @la)
143
+ end
144
+ else
145
+ error("a character", @la) unless @la
146
+ s<<@la;@la=io.getc
147
+ end
148
+ end
149
+ @la = io.getc
150
+ s
151
+ end
152
+
153
+ end
154
+
155
+
@@ -0,0 +1,174 @@
1
+ class JSON < Peggy::Builder
2
+ KEYWORDS = {"true" => true, "false" => false, "null" => nil}
3
+ ESCAPES = Hash[*%W[b \b f \f n \n r \r t \t]]
4
+
5
+ def initialize
6
+ super
7
+
8
+ self.ignore_productions = [:space]
9
+ space { lit /\s+/ }
10
+
11
+ value {
12
+ seq {
13
+ opt { space }
14
+ one {
15
+ string
16
+ object
17
+ array
18
+ keyword
19
+ number
20
+ }
21
+ opt { space }
22
+ }
23
+ }
24
+
25
+ object {
26
+ seq {
27
+ lit /\{\s*/
28
+ one {
29
+ seq {
30
+ opt { many { seq { string; lit /\s*:/; value; lit /,\s*/ } } }
31
+ seq { string; lit /\s*:/; value }
32
+ lit "}"
33
+ }
34
+ lit "}"
35
+ }
36
+ }
37
+ }
38
+
39
+ array {
40
+ seq {
41
+ lit "["
42
+ one {
43
+ seq {
44
+ opt { many { seq { value; lit "," } } }; value; lit "]"
45
+ }
46
+ lit "]"
47
+ }
48
+ }
49
+ }
50
+
51
+ string {
52
+ seq {
53
+ lit '"'
54
+ one {
55
+ lit '"'
56
+ seq {
57
+ many {
58
+ one {
59
+ seq { string_content; opt { escape } }
60
+ seq { escape; opt { string_content } }
61
+ }
62
+ }
63
+ lit '"'
64
+ }
65
+ }
66
+ }
67
+ }
68
+ string_content { lit(/[^\\"]+/) }
69
+ escape {
70
+ one {
71
+ escape_literal
72
+ escape_sequence
73
+ escape_unicode
74
+ }
75
+ }
76
+
77
+ escape_literal { lit(%r{\\["\\/]}) }
78
+ escape_sequence { lit(/\\[bfnrt]/) }
79
+ escape_unicode { lit(/\\u[0-9a-f]{4}/i) }
80
+
81
+ number { lit(/-?(?:0|[1-9]\d*)(?:\.\d+(?:[eE][+-]?\d+)?)?\b/) }
82
+ keyword { lit(/\b(?:true|false|null)\b/) }
83
+ end
84
+
85
+ def to_ruby(from = parse_results.keys.min)
86
+ kind = parse_results[from][:found_order].first
87
+ to = parse_results[from][kind]
88
+ send("to_ruby_#{kind}", from, to)
89
+ end
90
+
91
+ private
92
+
93
+ def to_ruby_object(from, to)
94
+ #p parse_results
95
+ object = Hash.new
96
+ skip_to = nil
97
+ last_key = nil
98
+ parse_results.keys.select { |k| k > from and k < to }.sort.each do |key|
99
+ content = parse_results[key]
100
+ next if skip_to and key < skip_to
101
+ next unless content[:found_order] and
102
+ ( ( content[:found_order].size == 2 and
103
+ content[:found_order][1] == :value ) or
104
+ content[:found_order] == [:string] )
105
+ if content[:found_order] == [:string]
106
+ last_key = to_ruby_string(key, content[:string])
107
+ else
108
+ case content[:found_order].first
109
+ when :object
110
+ object[last_key] = to_ruby_object(key, content[:object])
111
+ skip_to = content[:object]
112
+ when :array
113
+ object[last_key] = to_ruby_array(key, content[:array])
114
+ skip_to = content[:array]
115
+ else
116
+ object[last_key] = to_ruby(key)
117
+ end
118
+ end
119
+ end
120
+ object
121
+ end
122
+
123
+ def to_ruby_array(from, to)
124
+ array = Array.new
125
+ skip_to = nil
126
+ parse_results.keys.select { |k| k > from and k < to }.sort.each do |key|
127
+ content = parse_results[key]
128
+ next if skip_to and key < skip_to
129
+ next unless content[:found_order] and
130
+ content[:found_order].size == 2 and
131
+ content[:found_order][1] == :value
132
+ case content[:found_order].first
133
+ when :object
134
+ array << to_ruby_object(key, content[:object])
135
+ skip_to = content[:object]
136
+ when :array
137
+ array << to_ruby_array(key, content[:array])
138
+ skip_to = content[:array]
139
+ else
140
+ array << to_ruby(key)
141
+ end
142
+ end
143
+ array
144
+ end
145
+
146
+ def to_ruby_string(from, to)
147
+ string = String.new
148
+ parse_results.keys.select { |k| k > from and k < to }.sort.each do |key|
149
+ content = parse_results[key]
150
+ next unless content[:found_order]
151
+ case content[:found_order].first
152
+ when :string_content
153
+ string << source_text[key...content[:string_content]]
154
+ when :escape_literal
155
+ string << source_text[content[:escape_literal] - 1, 1]
156
+ when :escape_sequence
157
+ string << ESCAPES[source_text[content[:escape_sequence] - 1, 1]]
158
+ when :escape_unicode
159
+ string << [Integer("0x#{source_text[key + 2, 4]}")].pack("U")
160
+ end
161
+ end
162
+ string
163
+ end
164
+
165
+ def to_ruby_number(from, to)
166
+ num = source_text[from...to]
167
+ num.include?(".") ? Float(num) : Integer(num)
168
+ end
169
+
170
+ def to_ruby_keyword(from, to)
171
+ KEYWORDS[source_text[from...to]]
172
+ end
173
+ end
174
+
@@ -0,0 +1,81 @@
1
+
2
+ class JSON
3
+
4
+ def parse(input)
5
+ input.scan(/\s*/)
6
+ parse_value(out=[], input)
7
+ input.eos? or error("Unexpected data", input)
8
+ out[0]
9
+ end
10
+
11
+ private
12
+
13
+ def parse_value(out, input)
14
+ if input.scan(/"/)
15
+ parse_string(out, input)
16
+ elsif input.scan(/\{\s*/)
17
+ kv = []
18
+ until input.scan(/\}\s*/)
19
+ kv.empty? or input.scan(/,\s*/) or error("Expected ,", input)
20
+ input.scan(/"/) or error("Expected string", input)
21
+ parse_string(kv, input)
22
+ input.scan(/:\s*/) or error("Expecting object separator", input)
23
+ parse_value(kv, input)
24
+ end
25
+ out << Hash[*kv]
26
+ elsif input.scan(/\[\s*/)
27
+ array = []
28
+ until input.scan(/\]\s*/)
29
+ array.empty? or input.scan(/,\s*/) or error("Expected ,", input)
30
+ parse_value(array, input)
31
+ end
32
+ out << array
33
+ elsif input.scan(/true\s*/)
34
+ out << true
35
+ elsif input.scan(/false\s*/)
36
+ out << false
37
+ elsif input.scan(/null\s*/)
38
+ out << nil
39
+ elsif text=input.scan(/-?(?:0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?\s*/)
40
+ out << ((input[1]||input[2]) ? text.to_f : text.to_i)
41
+ else
42
+ error("Illegal JSON value")
43
+ end
44
+ end
45
+
46
+ def parse_string(out, input)
47
+ s = ""
48
+ while true
49
+ if text=input.scan(/[^\\"]+/)
50
+ s.concat(text)
51
+ elsif input.scan(/\\/)
52
+ case (ch=input.getch[0])
53
+ when ?b ; s << ?\b
54
+ when ?f ; s << ?\f
55
+ when ?n ; s << ?\n
56
+ when ?r ; s << ?\r
57
+ when ?t ; s << ?\t
58
+ when ?u
59
+ text = input.scan(/[0-9a-fA-F]{4}/) or raise("expected hex*4")
60
+ s << text.to_i(16)
61
+ else
62
+ s << ch
63
+ end
64
+ else
65
+ break
66
+ end
67
+ end
68
+ input.scan(/"\s*/) or error("Unclosed string", input)
69
+ out << s
70
+ end
71
+
72
+ def error(message, input)
73
+ if input.eos?
74
+ raise "Unexpected end of input."
75
+ else
76
+ raise "#{message}: #{input.peek(input.string.length)}"
77
+ end
78
+ end
79
+ end
80
+
81
+
@@ -1,692 +1,265 @@
1
1
  #!/bin/env ruby
2
2
  # = grammar.rb - specify BNF-like grammar directly in Ruby
3
- # $Id: grammar.rb,v 1.1 2005/10/13 23:58:45 eric_mahurin Exp $
4
- # Author:: Eric Mahurin (Eric under Mahurin at yahoo dot com)
3
+ # $Id: grammar.rb,v 1.3 2008/09/05 06:01:20 eric_mahurin Exp $
4
+ # Author:: Eric Mahurin (Eric under Mahurin at yahoo period com)
5
+ # Copyright (c) Eric Mahurin 2005-2008
5
6
  # License:: Ruby license
6
7
  # Home:: http://rubyforge.org/projects/grammar
7
8
 
8
- # This base class defines common operators to the derived Grammar classes to
9
- # make specifying the Grammar look similar to BNF. This base class also serves
10
- # the purpose of handling recursion in the Grammar.
9
+ # The Grammar class defines operators and methods that allow Grammars to be
10
+ # built in a tree. The result is similar to BNF seen in other parser
11
+ # generators. No actual parsing is done by this class. That is up to an
12
+ # engine.
11
13
  class Grammar
12
- class << self
13
- alias_method(:[],:new)
14
- # With several interlocking recursive grammars, this can be used.
15
- # For each argument that the block needs, an empty Grammar is
16
- # given. The result of the block should be an Array of the final
17
- # grammars for those arguments.
18
- def multiple(&block) # :yield: *recursive_grammars
19
- grammars = (1..block.arity).map { self.new }
20
- grammars.zip(yield(*grammars)) { |g,g1| g << g1 }
21
- grammars
22
- end
23
- end
24
- # Creates a Grammar from another +grammar+. If +grammar+ is not given
25
- # and a block is instead, the block is passed +self+ (to handle recursion)
26
- # and the resulting grammar from this block will be used.
27
- def initialize(grammar=nil,&block) # :yield: +self+
28
- @grammar = grammar || block && yield(self)
29
- end
30
- # Reinitialize with another Grammar. This will be needed for recursion
31
- # unless the block form of new is used.
32
- def << (*args)
33
- initialize(*args)
34
- end
35
- # Match to elements at a Cursor while advancing. When matched, a parse
36
- # buffer is returned. Instead of an empty Array, the seed to this parse buffer
37
- # can be given by +buffer+ which should respond to #concat and #<< like Array.
38
- # When a mismatch occurs several possibilities exist. If +lookahead+ and
39
- # the Grammar is within its lookahead (defaults one element/token - can be
40
- # controlled by #lookahead), the cursor is moved back to where it started and
41
- # +false+ is returned. Otherwise an exception describing the mismatch is
42
- # raised.
43
- def scan(cursor,buffer=[],lookahead=false)
44
- @grammar.scan(cursor,buffer,lookahead)
14
+
15
+ # Create a Grammar from a block. The block is passed a Grammar engine
16
+ # which should be used to do any parsing.
17
+ def initialize(&block) # :yield: engine
18
+ @block = block
45
19
  end
46
- # Same as #scan except the +cursor+ is held in place
47
- def check(cursor,buffer=[],lookahead=false)
48
- cursor.pos { (@grammar||self).scan(cursor,buffer,lookahead) }
20
+ # Executes the Grammar with an engine. The engine simply gets passed to
21
+ # the block (actually a lambda now) contained in the Grammar.
22
+ def [](engine)
23
+ @block[engine]
49
24
  end
50
- def scanner(me,cursor,buffer,lookahead,hold) # :nodoc:
51
- hold ?
52
- "#{me}.check(#{cursor},#{buffer},#{lookahead})" :
53
- "#{me}.scan(#{cursor},#{buffer},#{lookahead})"
25
+ # Returns the lambda that the Grammar holds.
26
+ def to_proc
27
+ @block
54
28
  end
55
- def leaves # :nodoc:
56
- [@grammar||self]
29
+ # Replaces the contained lambda with one from another Grammar.
30
+ def <<(gram)
31
+ @block = gram && gram.to_proc
57
32
  end
58
- # Creates a new Grammar that matches +self+ or +other+ if that fails.
33
+ # Grammar that matches +self+ or +other+ if that fails.
59
34
  def |(other)
60
- Inline.new(self,other) { |us,them,cursor,buffer,lookahead,hold|
61
- "(#{us[cursor,buffer,true,hold]} ||
62
- #{them[cursor,buffer,lookahead,hold]})"
63
- }
35
+ Grammar { |e| e.alternation(self.to_proc, &other) }
64
36
  end
65
- # Creates a new Grammar that matches +self+ followed by +other+.
66
- # The resulting match list is a concatenation from the match lists
67
- # from +self+ and +other+.
37
+ # Grammar that matches +self+ followed by +other+.
68
38
  def +(other)
69
- Inline.new(self,other) { |us,them,cursor,buffer,lookahead|
70
- "(#{us[cursor,buffer,lookahead,false]} &&
71
- #{them[cursor,buffer,false,false]})"
72
- }
73
- end
74
- # Generates a Grammar that matches when +self+ (in-place) and +other+.
75
- def &(other)
76
- Inline.new(self,other) { |us,them,cursor,buffer,lookahead,hold|
77
- "(#{us[cursor,buffer,lookahead,true]} &&
78
- #{them[cursor,buffer,lookahead,hold]})"
79
- }
80
- end
81
- # Creates a new Grammar that matches +self+ replicated +multiplier+ times.
82
- # +multiplier+ can be a Range to specify a variable multiplier. The
83
- # +multiplier+ just needs to responds to #=== to determine the min and
84
- # max iterations.
85
- def *(multiplier)
86
- Inline.new(self,nil,multiplier) { |us,multiplier,cursor,buffer,lookahead|
87
- Inline.var { |n,ret,look| "(
88
- #{n} = -1
89
- #{ret} = false
90
- #{look} = #{lookahead}
91
- while true
92
- if #{multiplier}===(#{n}+=1)
93
- if !#{ret}
94
- #{ret} = #{buffer}
95
- #{look} = true
96
- end
97
- else
98
- break(#{ret}) if #{ret}
99
- end
100
- #{us[cursor,buffer,look,false]} or break(#{ret})
101
- #{look} = false if !#{ret}
102
- end
103
- )" }
104
- }
39
+ Grammar { |e| e.sequence(self.to_proc, &other) }
105
40
  end
106
- # Creates a new zero-width Grammar that matches +self+.
41
+ # Zero-width Grammar that matches +self+ (discards results).
107
42
  def +@
108
- Inline.new(self) { |us,cursor,buffer,lookahead,hold|
109
- "(#{us[cursor,'DISCARD',lookahead,true]} && #{buffer})"
110
- }
43
+ Grammar { |e| e.positive(&self) }
111
44
  end
112
- # Creates a new zero-width Grammar that matches anything but +self+.
45
+ # Zero-width Grammar that matches anything but +self+ (discards results).
113
46
  def -@
114
- Inline.new(self) { |us,cursor,buffer,lookahead,hold|
115
- "(!#{us[cursor,'DISCARD',true,true]} ? #{buffer} :
116
- !#{lookahead}&&raise(Error.new(cursor,'a negative syntatic predicate')))"
117
- }
47
+ Grammar { |e| e.negative(&self) }
118
48
  end
119
- # Returns a Grammar that as long as what follows doesn't match +self+, it
49
+ # Grammar that as long as what follows doesn't match +self+, it
120
50
  # matches to the next element. Most useful for a single element Grammar.
121
51
  def ~
122
- (-self)&ANY
52
+ -self + ANY
123
53
  end
124
- # Creates a new Grammar that optionally matches +self+.
54
+ # Grammar that optionally matches +self+.
125
55
  def optional
126
- self|NULL
127
- end
128
- # Matches a list of +self+ (plus possibly other stuff) one or more times.
129
- # The arguments are an alternating list of optional terminators and
130
- # separators. Along with #list0 you should be able to describe any
131
- # tail recursive grammar. This is equivalent to this recursive Grammar:
132
- #
133
- # Grammar.new { |g| a+(z|b+(y|...g)) }
134
- #
135
- # where a, b, ... are +self+ and the separators and z, y, ... are the
136
- # terminators.
137
- #
138
- # When a terminator is +nil+, the next item is treated
139
- # as optional (i.e. instead of a+(nil|g), a+(g|) is used).
140
- #
141
- # When there is a missing terminator at the end of +term_sep+ (and it is
142
- # non-empty), the list is not allowed to stop at that point.
143
- def list1(*term_sep)
144
- term_sep.push(nil) if term_sep.empty?
145
- term_sep.unshift(self)
146
- Inline.new(*term_sep.compact) { |*args|
147
- cursor,buffer,lookahead = args.slice!(-3,3)
148
- Inline.var { |look,ret|
149
- terminated = (term_sep.size&1).nonzero? || term_sep[-1]
150
- code = "(
151
- #{look} = #{lookahead}
152
- #{terminated ? (ret=false;'') : "#{ret} = false"}
153
- while true
154
- #{args[j=0][cursor,buffer,look,false]} or break(#{ret})
155
- #{look} = #{terminated ? false : true}
156
- #{terminated ? '' : "#{ret} = #{buffer}"}"
157
- 1.step(term_sep.size-1,2) { |i|
158
- if term_sep[i]
159
- code << "
160
- #{args[j+=1][cursor,buffer,true,false]} and break(#{buffer})"
161
- if i+1<term_sep.size
162
- code << "
163
- #{args[j+=1][cursor,buffer,false,false]} or break(false)"
164
- end
165
- elsif i+1<term_sep.size
166
- code << "
167
- #{args[j+=1][cursor,buffer,true,false]} or break(#{buffer})"
168
- end
169
- }
170
- code << "
171
- end
172
- )"
173
- }
174
- }
56
+ self | NULL
175
57
  end
176
- # Matches a list of +self+ (plus possibly other stuff) zero or more times.
177
- # The arguments are an alternating list of optional terminators and
178
- # separators. Along with #list1 you should be able to describe any
179
- # tail recursive grammar. This is equivalent to this recursive Grammar:
180
- #
181
- # Grammar.new { |g| x|(a+(z|b+(y|...g))) }
182
- #
183
- # where a, b, ... are +self+ and the separators and z, y, ..., x are the
184
- # terminators.
185
- #
186
- # When a terminator is +nil+/missing, the next item is treated
187
- # as optional.
188
- def list0(*term_sep)
189
- term_sep.push(nil) if (term_sep.size&1).zero?
190
- term_sep.unshift(self)
191
- Inline.new(*term_sep.compact) { |*args|
192
- cursor,buffer,lookahead = args.slice!(-3,3)
193
- Inline.var { |look,ret|
194
- code = "("
195
- code << "
196
- #{look} = #{lookahead}" if term_sep[-1]
197
- code << "
198
- while true"
199
- j = -2
200
- -1.step(term_sep.size-3,2) { |i|
201
- if term_sep[i]
202
- code << "
203
- #{args[j+=1][cursor,buffer,true,false]} and break(#{buffer})"
204
- if j.zero?
205
- code << "
206
- #{args[j+=1][cursor,buffer,look,false]} or break(false)
207
- #{look} = false"
208
- else
209
- code << "
210
- #{args[j+=1][cursor,buffer,false,false]} or break(false)"
211
- end
212
- else
213
- j += 1 if j==2
214
- code << "
215
- #{args[j+=1][cursor,buffer,true,false]} or break(#{buffer})"
216
- end
217
- }
218
- code << "
219
- end)"
220
- }
221
- }
222
- end
223
- # Creates a new Grammar where the entire grammar is considered a
224
- # part of the lookahead (instead of just the first element).
225
- def lookahead
226
- Inline.new(self) { |us,cursor,buffer,lookahead|
227
- Inline.var { |branch| "(
228
- #{branch} = #{buffer}.class.new
229
- #{cursor}.pos? { begin
230
- #{us[cursor,branch,false]}
231
- rescue Error => err
232
- raise(err) if !#{lookahead}
233
- end } && #{buffer}.concat(#{branch})
234
- )" }
235
- }
236
- end
237
- # Creates a new Grammar where the match list of +self+ is filtered by
238
- # some code.
239
- # When a +klass+ is given, +klass+.new is used as the buffer to hold what
240
- # will be passed to the code. Otherwise this temporary buffer will come
241
- # from buffer.class.new.
242
- # If the block needs 1 argument, this temporary buffer will be passed
243
- # and the block should return something that will be given to buffer.concat.
244
- # If the block needs 2 arguments, the second argument will be the buffer
245
- # and the block should do the concatenation.
246
- # If there is no block, the temporary buffer is passed to buffer.concat
247
- # directly. Use this to get some isolation.
248
- def filter(klass=nil,&code) # :yield: branch[, buffer]
249
- if !code
250
- if klass
251
- Inline.new(self,nil,klass) { |us,klass,cursor,buffer,lookahead,hold|
252
- Inline.var { |branch| "(
253
- #{branch}=#{klass}.new
254
- #{us[cursor,branch,lookahead,hold]} &&
255
- #{buffer}.concat(#{branch})
256
- )"}
257
- }
258
- else
259
- Inline.new(self) { |us,cursor,buffer,lookahead,hold|
260
- Inline.var { |branch| "(
261
- #{branch}=#{buffer}.class.new
262
- #{us[cursor,branch,lookahead,hold]} &&
263
- #{buffer}.concat(#{branch})
264
- )"}
265
- }
266
- end
267
- elsif code.arity>=2
268
- if klass
269
- Inline.new(self,nil,klass,code) { |us,klass,code,cursor,buffer,lookahead,hold|
270
- Inline.var { |branch| "(
271
- #{branch}=#{klass}.new
272
- #{us[cursor,branch,lookahead,hold]} &&
273
- (#{code}[#{branch},#{buffer}]||
274
- raise(Error.new(cursor,'a filtered '+#{branch}.inspect)))
275
- )"}
276
- }
277
- else
278
- Inline.new(self,nil,code) { |us,code,cursor,buffer,lookahead,hold|
279
- Inline.var { |branch| "(
280
- #{branch}=#{buffer}.class.new
281
- #{us[cursor,branch,lookahead,hold]} &&
282
- (#{code}[#{branch},#{buffer}]||
283
- raise(Error.new(cursor,'a filtered '+#{branch}.inspect)))
284
- )"}
285
- }
286
- end
58
+ # Grammar that matches a sequence of zero or more +self+ followed
59
+ # by an optional terminator (+term+). If +term+ is given it takes
60
+ # precedence over matching +self+ items.
61
+ def repeat0(term=nil)
62
+ if term
63
+ Recurse { |g| term | self + g }
287
64
  else
288
- if klass
289
- Inline.new(self,nil,klass,code) { |us,klass,code,cursor,buffer,lookahead,hold|
290
- Inline.var { |branch| "(
291
- #{branch}=#{klass}.new
292
- #{us[cursor,branch,lookahead,hold]} &&
293
- #{buffer}.concat(#{code}[#{branch}]||
294
- raise(Error.new(cursor,'a filtered '+#{branch}.inspect)))
295
- )"}
296
- }
297
- else
298
- Inline.new(self,nil,code) { |us,code,cursor,buffer,lookahead,hold|
299
- Inline.var { |branch| "(
300
- #{branch}=#{buffer}.class.new
301
- #{us[cursor,branch,lookahead,hold]} &&
302
- #{buffer}.concat(#{code}[#{branch}]||
303
- raise(Error.new(cursor,'a filtered '+#{branch}.inspect)))
304
- )"}
305
- }
306
- end
65
+ Recurse { |g| g + self | NULL }
307
66
  end
308
67
  end
309
- # Returns a Grammar that discards the match list from +self+
310
- def discard
311
- Inline.new(self) { |us,cursor,buffer,lookahead,hold|
312
- "(#{us[cursor,'DISCARD',lookahead,hold]}&&#{buffer})"
313
- }
314
- end
315
- # Returns a Grammar that groups the match list from +self+. A temporary
316
- # buffer is formed just list #filter, but buffer.<< is used instead of
317
- # buffer.concat.
318
- def group(klass=nil)
319
- if klass
320
- Inline.new(self,nil,klass) { |us,klass,cursor,buffer,lookahead,hold|
321
- Inline.var { |branch| "(
322
- #{branch}=#{klass}.new
323
- #{us[cursor,branch,lookahead,hold]} &&
324
- #{buffer}<<#{branch}
325
- )"}
326
- }
68
+ # Grammar that matches a sequence of one or more +self+ followed
69
+ # by an optional terminator (+term+). If +term+ is given it takes
70
+ # precedence over matching +self+ items.
71
+ def repeat1(term=nil)
72
+ if term
73
+ Recurse { |g| self + (term | g) }
327
74
  else
328
- Inline.new(self) { |us,cursor,buffer,lookahead,hold|
329
- Inline.var { |branch| "(
330
- #{branch}=#{buffer}.class.new
331
- #{us[cursor,branch,lookahead,hold]} &&
332
- #{buffer}<<#{branch}
333
- )"}
334
- }
75
+ Recurse { |g| (g | NULL) + self }
335
76
  end
336
77
  end
337
-
338
-
339
- # A Grammar that can flatten itself (with code strings) to reduce the
340
- # amount of method calls needed while parsing. This is tricky stuff.
341
- # Will explain later.
342
- class Inline < Grammar
343
- def initialize(*objects,&block) # :yield: cursor,buffer,lookahead[,hold]
344
- @objects = objects
345
- @block = block
346
- end
347
- Arg_names = %w(cursor buffer lookahead)
348
- def scan(cursor,buffer=[],lookahead=false) # :nodoc:
349
- (class << self;self;end).class_eval(
350
- "def scan(cursor,buffer=[],lookahead=false)\n"+
351
- scanner(*(_leaf_names+Arg_names+[false]))+
352
- "\nend"
353
- )
354
- scan(cursor,buffer,lookahead)
355
- end
356
- def check(cursor,buffer=[],lookahead=false) # :nodoc:
357
- (class << self;self;end).class_eval(
358
- "def check(cursor,buffer=[],lookahead=false)\n"+
359
- scanner(*(_leaf_names+Arg_names+[true]))+
360
- "\nend"
361
- )
362
- check(cursor,buffer,lookahead)
363
- end
364
- def scanner(*leaves_args) # :nodoc:
365
- objects = _extractors.map { |e| e[leaves_args] }
366
- args = objects+leaves_args
367
- if @block.arity<args.size and args.slice!(-1)
368
- "#{leaves_args[0]}.pos{#{@block.call(*args)}}"
369
- else
370
- @block.call(*args)
371
- end
372
- end
373
- def leaves # :nodoc:
374
- @_ or begin
375
- @_ = []
376
- @extractors = []
377
- @objects.inject(false) { |leaf,object|
378
- if leaf
379
- @_ << object
380
- @extractors << lambda { |leaves_args|
381
- leaves_args.slice!(0)
382
- }
383
- true
384
- elsif !object
385
- true
386
- elsif false
387
- # enable this code to disable code flattening
388
- @_ << object
389
- @extractors << lambda { |leaves_args|
390
- g = leaves_args.slice!(0)
391
- lambda { |*args|
392
- "#{g}.#{args.slice!(-1) ? 'check' : 'scan'}(#{args.join(',')})"
393
- }
394
- }
395
- false
396
- else
397
- leaves = object.leaves
398
- @_.concat(leaves)
399
- n = leaves.size
400
- @extractors << lambda { |leaves_args|
401
- leaf_names = leaves_args.slice!(0,n)
402
- lambda { |*args| object.scanner(*(leaf_names+args)) }
403
- }
404
- false
78
+ # Grammar that matches +self+ replicated +multiplier+ times.
79
+ # +multiplier+ can be a Range to specify a variable multiplier. The
80
+ # +multiplier+ just needs to responds to #=== to determine the min and
81
+ # max iterations.
82
+ def *(mult)
83
+ Common { |e|
84
+ Variables(0) { |i|
85
+ case mult
86
+ when Fixnum
87
+ start = Check { e[mult].equal?(i << i[] + e[1]) }
88
+ inside = Fail()
89
+ when Range
90
+ start = case (range0=mult.begin)
91
+ when Fixnum; Check { e[range0].equal?(i << i[] + e[1]) }
92
+ else; Check { e[range0] <= (i << i[] + e[1]) }
405
93
  end
406
- }
407
- remove_instance_variable(:@objects)
408
- @_
409
- end
410
- end
411
- def _extractors # :nodoc:
412
- @extractors or (leaves;@extractors)
413
- end
414
- def _leaf_names # :nodoc:
415
- (0...leaves.size).map { |i| "@_[#{i}]" }
416
- end
417
- def inspect # :nodoc:
418
- to_s[0..-2].concat(" #{scanner(*(leaves+Arg_names+[false]))}>")
419
- end
420
- @@symbol = "_0".to_sym
421
- # used for generating "local" variable names
422
- def self.var(&block)
423
- critical0 = Thread.critical
424
- Thread.critical = true
425
- if block
426
- begin
427
- symbol = @@symbol
428
- symbols = []
429
- block.arity.times {
430
- symbols << @@symbol
431
- @@symbol = @@symbol.to_s.succ.to_sym
432
- }
433
- # this better not need other threads - critical section
434
- yield(*symbols)
435
- ensure
436
- @@symbol = symbol
437
- end
438
- else
439
- begin
440
- @@symbol
441
- ensure
442
- @@symbol = @@symbol.to_s.succ.to_sym
94
+ range1 = mult.end
95
+ mult.exclude_end? or
96
+ range1 = begin;range1.succ;rescue;range1+1;end
97
+ inside = case range1
98
+ when Fixnum; Check { e.not(e[range1].equal?(i << i[] + e[1])) }
99
+ when 1.0/0; NULL
100
+ else; Check { e[range1] > (i << i[] + e[1]) }
101
+ end
102
+ else
103
+ start = inside = Check { e[mult] === (i << i[] + e[1]) }
443
104
  end
444
- end
445
- ensure
446
- Thread.critical = critical0
447
- end
105
+ tail = Recurse { |l| l + inside + self | NULL }
106
+ ((mult===0) ? tail : Recurse { |r| self + (start + tail | r) })
107
+ }
108
+ }
448
109
  end
449
-
450
- # A Grammar that matches using arbitrary code
451
- class Code < Inline
452
- def initialize(&code) # :yield: cursor,buffer,lookahead
453
- if code.arity<4
454
- super(nil,code) { |code,cursor,buffer,lookahead|
455
- "#{code}[#{cursor},#{buffer},#{lookahead}]"
456
- }
457
- else
458
- super(nil,code) { |code,cursor,buffer,lookahead,hold|
459
- "#{code}[#{cursor},#{buffer},#{lookahead},#{hold}]"
460
- }
461
- end
462
- end
110
+ # Grammar that redirects parsing results of +self+ to a
111
+ # +buf0+.clone and yields the resulting buffer and possibly the engine
112
+ # afterwards.
113
+ def redirect(buf0, &block) # :yield: buf[, engine]
114
+ Grammar { |e| e.redirect(self.to_proc, buf0, &block) }
463
115
  end
464
-
465
- # Lookup grammar from next token. Need to doc.
466
- class Lookup < Grammar
467
- def initialize(lookup)
468
- @lookup = lookup
469
- end
470
- def scan(cursor,buffer=[],lookahead=false) # :nodoc:
471
- v = cursor.read1next
472
- if grammar = @lookup[v]
473
- buffer << v
474
- grammar.scan(cursor,buffer,false)
475
- else
476
- raise(Error.new(cursor,"no grammar for #{v} found in #{@lookup}"))
477
- end
478
- end
116
+ # Grammar that discards parsing results of +self+ and afterwards
117
+ # yields the engine to the optional block which should return something
118
+ # to be appended to the output.
119
+ def discard(&block) # :yield: engine
120
+ Grammar { |e| e.discard(self.to_proc, &block) }
479
121
  end
480
- class LookupAhead < Grammar
481
- def initialize(lookup)
482
- @lookup = lookup
483
- end
484
- def scan(cursor,buffer=[],lookahead=false) # :nodoc:
485
- v = cursor.read1after
486
- if grammar = @lookup[v]
487
- grammar.scan(cursor,buffer,false)
488
- elsif lookahead
489
- false
490
- else
491
- raise(Error.new(cursor,"no grammar for #{v} found in #{@lookup}"))
492
- end
493
- end
122
+ # Grammar that redirects parsing results of +self+ to a
123
+ # +buf0+.clone and yields the resulting buffer and possibly the engine
124
+ # afterwards to an optional block which should return something to be
125
+ # appended to the output.
126
+ def group(buf0, &block) # :yield: buf[, engine]
127
+ block_given? ? redirect(buf0) { |buf, e|
128
+ e << (block.arity==1 ? yield(buf) : yield(buf, e))
129
+ } : redirect(buf0) { |buf, e|
130
+ e << buf
131
+ }
494
132
  end
495
-
496
-
497
- # Grammar that matches to a sequence. An object responding to #[index]
498
- # (i.e. String/Array) is used to represent this sequence. Each element
499
- # returned by #[] should respond to #== to compare each element in the
500
- # sequence.
501
- class Sequence < Grammar
502
- def initialize(value,partial=false)
503
- @value = value
504
- @partial = partial
505
- end
506
- def scan(cursor,buffer=[],lookahead=false) # :nodoc:
507
- i = cursor.scan(@value,false,false,buffer)
508
- if !i
509
- if lookahead
510
- false
511
- else
512
- raise(Error.new(cursor,@value[0]))
513
- end
514
- elsif !@partial and i<0
515
- raise(Error.new(cursor,@value[-i]))
516
- else
517
- buffer
518
- end
519
- end
520
- def inspect
521
- "#{self.class}.new(#{@value.inspect},#{@partial.inspect})"
522
- end
523
- def to_s
524
- inspect
525
- end
133
+ # not sure if this is needed or wanted right now
134
+ def backref(&block) # :nodoc: :yield: n[, engine]
135
+ Grammar { |e| e.backref(self.to_proc, &block) }
526
136
  end
527
- # Grammar that matches elements until it finds a specific sequence.
528
- # Compare to IO#gets.
529
- class SequenceUntil < Grammar
530
- def initialize(value,allow_eof=false)
531
- @value = value
532
- @allow_eof = allow_eof
533
- end
534
- def scan(cursor,buffer=[],lookahead=false) # :nodoc:
535
- len,i = cursor.scan_until(@value,false,false,buffer)
536
- if !len
537
- if lookahead
538
- false
539
- else
540
- raise(Error.new(cursor,@value[0]))
541
- end
542
- elsif !@allow_eof and len.nonzero? and i<=0
543
- raise(Error.new(cursor,@value[-i]))
544
- else
545
- buffer
546
- end
547
- end
137
+ # Grammar that matches +self+, but backtracks when it
138
+ # fails instead of raising an error.
139
+ def backtrack(len=nil)
140
+ Grammar { |e| e.backtrack(self.to_proc, len) }
548
141
  end
549
- # Grammar that matches to a single element. An object responding to #==
550
- # is used to do the matching.
551
- class Element < Inline
552
- def initialize(value)
553
- super(nil,value) { |value,cursor,buffer,lookahead,hold|
554
- condition = hold ?
555
- "#{value}==(v=#{cursor}.read1after)" :
556
- "(v=#{cursor}.scan1next(#{value}))"
557
- "(#{condition} ? " +
558
- "#{buffer} << v : " +
559
- "!#{lookahead}&&raise(Error.new(#{cursor},#{value})))"
560
- }
561
- end
142
+ # Grammar that uses a looped +self+ as a lexer to generate tokens
143
+ # for +parser+ which sends its results to the output. +buf0+.clone is used
144
+ # hold tokens between the lexer and the parser.
145
+ def supply(parser, buf0, &block) # :yield: buf[, engine]
146
+ Grammar { |e|
147
+ e.supply(self.to_proc, parser.to_proc, buf0, &block)
148
+ }
562
149
  end
563
- # Grammar that always fails (with a +message+)
564
- class Fail < Inline
565
- def initialize(message)
566
- super { |cursor,buffer,lookahead|
567
- "!#{lookahead}&&raise(Error.new(cursor,#{message.inspect}))"
568
- }
569
- end
150
+ # Grammar that uses +self+ as a lexer to generate tokens
151
+ # for +parser+ which sends its results to the output. +buf0+.clone is used
152
+ # hold tokens between the lexer and the parser.
153
+ def pipe(parser, buf0, len=nil, &block) # :yield: buf[, engine]
154
+ Grammar { |e|
155
+ e.pipe(self.to_proc, parser.to_proc, buf0, len, &block)
156
+ }
570
157
  end
571
158
 
572
- # Grammar that matches any single element
573
- ANY = Inline.new { |cursor,buffer,lookahead,hold|
574
- "((v=#{cursor}.read1#{hold ? 'after' : 'next'}) ? " +
575
- "#{buffer} << v : " +
576
- "!#{lookahead}&&raise(Error.new(#{cursor},'any element')))"
577
- }
578
- # Grammar that always passes and matches nothing
579
- NULL = Inline.new { |_,buffer,_,_| "#{buffer}" }
580
- # Grammar that matches the end-of-file (or end-of-cursor)
581
- EOF = Inline.new { |cursor,buffer,_,_|
582
- "(!#{cursor}.skip1after&&#{buffer})"
583
- }
159
+ # include this somewhere to have access to methods that
160
+ module Molecules
584
161
 
585
- # Exception class for handling Grammar errors
586
- class Error < RuntimeError
587
- attr_accessor(:cursor,:expected,:found)
588
- def initialize(cursor=nil,expected=nil,found=nil)
589
- @cursor = cursor
590
- @expected = expected
591
- @found = found
162
+ # Eliminate the need for the ".new".
163
+ # Would be better if objects were callable so we wouldn't need this.
164
+ def Grammar(&block)
165
+ Grammar.new(&block)
592
166
  end
593
- def to_s
594
- err = [super]
595
- err << "expected #{@expected.inspect}" if @expected
596
- err << "found #{@found.inspect}" if @found
597
- begin
598
- #err << @cursor.to_s if @cursor
599
- rescue
600
- end
601
- err * ", "
602
- end
603
- end
604
167
 
605
- # :stopdoc:
606
- # Parse buffer that throws out everything
607
- DISCARD = Class.new {
608
- def concat(v);self;end
609
- def << (v);self;end
610
- define_method(:class) do;self;end # using "def class" messed up rdoc
611
- def new;self;end
612
- }.new
613
- # :startdoc:
614
-
615
- end
168
+ # Grammar that matches to a single element. An object responding to #===
169
+ # is used to do the matching.
170
+ def Element(pattern)
171
+ Grammar { |e| e.match(pattern) }
172
+ end
616
173
 
174
+ alias_method(:E, :Element)
617
175
 
618
- class Cursor
619
- # A Cursor that gets its data from a producer Thread. This Thread is
620
- # generated from the block given (passed +self+). The code in this
621
- # block is expected to apply the << and concat methods to the argument
622
- # given. The current Thread is the consumer.
623
- #
624
- # Unfortunately, this Cursor isn't full-featured (yet). It is not
625
- # reversable. This will one day be reversable #pos*.
626
- class Producer < Cursor
627
- def initialize(max_size=16,&producer)
628
- @buffer = []
629
- @size = 0
630
- @max_size = max_size
631
- @consumer = Thread.current
632
- @producer = Thread.new { producer[self] }
633
- end
634
- def new_data
635
- []
636
- end
637
- def read1next
638
- while (Thread.critical=true;@buffer.empty?&&@producer.alive?)
639
- Thread.critical = false
640
- @producer.run
641
- end
642
- v = @buffer.shift
643
- @size -= 1
644
- v
645
- ensure
646
- Thread.critical = false
647
- end
648
- def read1after
649
- v = read1next
650
- unless v.nil?;begin
651
- Thread.critical = true
652
- @buffer.unshift(v)
653
- ensure
654
- Thread.critical = false
655
- end;end
656
- v
657
- end
658
- def skip1after
659
- read1after.nil? ? nil : true
176
+ # Grammar that matches the elements in +pattern_sequence+. +Element+
177
+ # is used for each pattern in +pattern_sequence+. Starting from index
178
+ # 0 #[] is used to access +pattern_sequence+ until it returns +nil+.
179
+ def Chain(pattern_sequence)
180
+ p = pattern_sequence[0] or return NULL
181
+ g = E(p)
182
+ i = 0
183
+ g += E(p) while p = pattern_sequence[i+=1]
184
+ g
660
185
  end
661
- def scan1next(v)
662
- v0 = read1next
663
- (v0.nil? || v==v0) ? v0 : begin
664
- Thread.critical = true
665
- @buffer.unshift(v0)
666
- nil
667
- ensure
668
- Thread.critical = false
669
- end
186
+
187
+ # Grammar that always fails (with a +message+)
188
+ def Fail(message=nil)
189
+ Grammar { |e| e.failure(message) }
190
+ end
191
+
192
+ # Grammar that shares/uses one or more variables. Optional initial
193
+ # values can be given for the variables. The block should take
194
+ # variable reference objects (one or more) and should return a
195
+ # Grammar that uses the variables in action blocks. Use var#[] to
196
+ # get the value in a variable reference object and var#<< to set the
197
+ # value.
198
+ def Variables(*vals, &block) # :yield: *vars
199
+ Grammar { |e|
200
+ e.variables(block.arity) { |*vars|
201
+ init = []
202
+ vals.each_with_index { |val, i|
203
+ init << (vars[i] << e[val,true])
204
+ }
205
+ init << e[true]
206
+ Grammar { e.steps(*init) } + yield(*vars)
207
+ }
208
+ }
670
209
  end
671
- def << (v)
672
- while (Thread.critical=true;@size>=@max_size&&@consumer.alive?)
673
- Thread.critical = false
674
- @consumer.run
675
- end
676
- @buffer << v
677
- @size += 1
678
- self
679
- ensure
680
- Thread.critical = false
210
+
211
+ # Grammar that handles recursion. +inner+ represents a call back to
212
+ # the resulting Grammar. An +inner+ may be given or it will be
213
+ # automatically generated (as an empty/invalid Grammar). +inner+
214
+ # is yielded to the block which should return the resulting Grammar
215
+ # (and be based on +inner+). Middle, right, and left recursion should
216
+ # be handled by the engine properly, but there may be restrictions on
217
+ # left recursion (i.e. must be the very first thing in the resulting
218
+ # Grammar).
219
+ def Recurse(inner=Grammar()) # :yield: inner
220
+ outer = yield(inner)
221
+ Grammar { |e| e.recurse(inner, &outer) }
681
222
  end
682
- def concat(value)
683
- i = 0
684
- until (v = value[i]).nil?
685
- self << v
686
- end
687
- self
223
+
224
+ # Grammar that fails with a message when the Grammar block doesn't
225
+ # pass.
226
+ def Check(message=nil, &block) # :yield: engine
227
+ Grammar(&block) | Fail(message)
228
+ end
229
+
230
+ # Grammar that yields an engine to a Grammar block and expects that
231
+ # the result always passes.
232
+ def Always(&block) # :yield: engine
233
+ Grammar { |e| e.always(&block) }
234
+ end
235
+
236
+ # Grammar that is the result of yielding an engine. This adds a
237
+ # convenience so that action blocks don't need to receive the engine.
238
+ def Common # :yield: engine
239
+ Grammar { |e| yield(e)[e] }
240
+ end
241
+
242
+ # Grammar that modifies the output buffer. The current buffer and
243
+ # optionally the engine are yielded to a block which should return
244
+ # what the new output buffer should be.
245
+ # WARNING: only use this inside of a Grammar where #group or
246
+ # #redirect has been applied. It probably won't work as expected in
247
+ # other places.
248
+ def Output(&block) # :yield: buf[, engine]
249
+ Grammar { |e| e.output(&block) }
688
250
  end
251
+
252
+ # Zero-width Grammar that always passes and matches nothing
253
+ NULL = Grammar.new { |e| e[true] }
254
+ # Zero-width Grammar that matches the end-of-file (or end-of-input)
255
+ EOF = Grammar.new { |e| e.eof }
256
+ # Grammar that matches any single element (not EOF)
257
+ ANY = Grammar.new { |e| e.any }
258
+
689
259
  end
260
+
261
+ include Molecules
262
+
690
263
  end
691
264
 
692
265