Class: Grammar

Inherits:
Object
  • Object
show all
Includes:
Molecules
Defined in:
lib/grammar.rb,
lib/grammar/ruby.rb,
lib/grammar/ruby0.rb,
lib/grammar/rubycall.rb,
lib/grammar/ruby/code.rb,
lib/grammar/ruby2cext.rb,
lib/grammar/ruby2cext_hack.rb

Overview

The Grammar class defines operators and methods that allow Grammars to be built in a tree. The result is similar to BNF seen in other parser generators. No actual parsing is done by this class. That is up to an engine.

Defined Under Namespace

Modules: Molecules Classes: Ruby, Ruby0, Ruby2CExt, RubyCall

Constant Summary

Constants included from Molecules

Molecules::ANY, Molecules::EOF, Molecules::NULL

Instance Method Summary collapse

Methods included from Molecules

#Always, #Chain, #Check, #Common, #Element, #Fail, #Grammar, #Output, #Recurse, #Variables

Constructor Details

#initialize(&block) ⇒ Grammar

Create a Grammar from a block. The block is passed a Grammar engine which should be used to do any parsing.



17
18
19
# File 'lib/grammar.rb', line 17

def initialize(&block) # :yield: engine
    @block = block
end

Instance Method Details

#*(mult) ⇒ Object

Grammar that matches self replicated multiplier times. multiplier can be a Range to specify a variable multiplier. The multiplier just needs to responds to #=== to determine the min and max iterations.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/grammar.rb', line 82

def *(mult)
    Common { |e|
        Variables(0) { |i|
            case mult
            when Fixnum
                start = Check { e[mult].equal?(i << i[] + e[1]) }
                inside = Fail()
            when Range
                start = case (range0=mult.begin)
                when Fixnum; Check { e[range0].equal?(i << i[] + e[1]) }
                else; Check { e[range0] <= (i << i[] + e[1]) }
                end
                range1 = mult.end
                mult.exclude_end? or
                    range1 = begin;range1.succ;rescue;range1+1;end 
                inside = case range1
                when Fixnum; Check { e.not(e[range1].equal?(i << i[] + e[1])) }
                when 1.0/0; NULL
                else; Check { e[range1] > (i << i[] + e[1]) }
                end
            else
                start = inside = Check { e[mult] === (i << i[] + e[1]) }
            end
            tail = Recurse { |l| l + inside + self | NULL }
            ((mult===0) ? tail : Recurse { |r| self + (start + tail | r) })
        }
    }
end

#+(other) ⇒ Object

Grammar that matches self followed by other.



38
39
40
# File 'lib/grammar.rb', line 38

def +(other)
    Grammar { |e| e.sequence(self.to_proc, &other) }
end

#+@Object

Zero-width Grammar that matches self (discards results).



42
43
44
# File 'lib/grammar.rb', line 42

def +@
    Grammar { |e| e.positive(&self) }
end

#-@Object

Zero-width Grammar that matches anything but self (discards results).



46
47
48
# File 'lib/grammar.rb', line 46

def -@
    Grammar { |e| e.negative(&self) }
end

#<<(gram) ⇒ Object

Replaces the contained lambda with one from another Grammar.



30
31
32
# File 'lib/grammar.rb', line 30

def <<(gram)
    @block = gram && gram.to_proc
end

#[](engine) ⇒ Object

Executes the Grammar with an engine. The engine simply gets passed to the block (actually a lambda now) contained in the Grammar.



22
23
24
# File 'lib/grammar.rb', line 22

def [](engine)
    @block[engine]
end

#backref(&block) ⇒ Object

not sure if this is needed or wanted right now



134
135
136
# File 'lib/grammar.rb', line 134

def backref(&block) # :nodoc: :yield: n[, engine]
    Grammar { |e| e.backref(self.to_proc, &block) }
end

#backtrack(len = nil) ⇒ Object

Grammar that matches self, but backtracks when it fails instead of raising an error.



139
140
141
# File 'lib/grammar.rb', line 139

def backtrack(len=nil)
    Grammar { |e| e.backtrack(self.to_proc, len) }
end

#discard(&block) ⇒ Object

Grammar that discards parsing results of self and afterwards yields the engine to the optional block which should return something to be appended to the output.



119
120
121
# File 'lib/grammar.rb', line 119

def discard(&block) # :yield: engine
    Grammar { |e| e.discard(self.to_proc, &block) }
end

#group(buf0, &block) ⇒ Object

Grammar that redirects parsing results of self to a buf0.clone and yields the resulting buffer and possibly the engine afterwards to an optional block which should return something to be appended to the output.



126
127
128
129
130
131
132
# File 'lib/grammar.rb', line 126

def group(buf0, &block) # :yield: buf[, engine]
    block_given? ? redirect(buf0) { |buf, e|
        e << (block.arity==1 ? yield(buf) : yield(buf, e))
    } : redirect(buf0) { |buf, e|
        e << buf
    }
end

#optionalObject

Grammar that optionally matches self.



55
56
57
# File 'lib/grammar.rb', line 55

def optional
    self | NULL
end

#pipe(parser, buf0, len = nil, &block) ⇒ Object

Grammar that uses self as a lexer to generate tokens for parser which sends its results to the output. buf0.clone is used hold tokens between the lexer and the parser.



153
154
155
156
157
# File 'lib/grammar.rb', line 153

def pipe(parser, buf0, len=nil, &block) # :yield: buf[, engine]
    Grammar { |e|
        e.pipe(self.to_proc, parser.to_proc, buf0, len, &block)
    }
end

#redirect(buf0, &block) ⇒ Object

Grammar that redirects parsing results of self to a buf0.clone and yields the resulting buffer and possibly the engine afterwards.



113
114
115
# File 'lib/grammar.rb', line 113

def redirect(buf0, &block) # :yield: buf[, engine]
    Grammar { |e| e.redirect(self.to_proc, buf0, &block) }
end

#repeat0(term = nil) ⇒ Object

Grammar that matches a sequence of zero or more self followed by an optional terminator (term). If term is given it takes precedence over matching self items.



61
62
63
64
65
66
67
# File 'lib/grammar.rb', line 61

def repeat0(term=nil)
    if term
        Recurse { |g| term | self + g }
    else
        Recurse { |g| g + self | NULL }
    end
end

#repeat1(term = nil) ⇒ Object

Grammar that matches a sequence of one or more self followed by an optional terminator (term). If term is given it takes precedence over matching self items.



71
72
73
74
75
76
77
# File 'lib/grammar.rb', line 71

def repeat1(term=nil)
    if term
        Recurse { |g| self + (term | g) }
    else
        Recurse { |g| (g | NULL) + self }
    end
end

#supply(parser, buf0, &block) ⇒ Object

Grammar that uses a looped self as a lexer to generate tokens for parser which sends its results to the output. buf0.clone is used hold tokens between the lexer and the parser.



145
146
147
148
149
# File 'lib/grammar.rb', line 145

def supply(parser, buf0, &block) # :yield: buf[, engine]
    Grammar { |e|
        e.supply(self.to_proc, parser.to_proc, buf0, &block)
    }
end

#to_procObject

Returns the lambda that the Grammar holds.



26
27
28
# File 'lib/grammar.rb', line 26

def to_proc
    @block
end

#|(other) ⇒ Object

Grammar that matches self or other if that fails.



34
35
36
# File 'lib/grammar.rb', line 34

def |(other)
    Grammar { |e| e.alternation(self.to_proc, &other) }
end

#~Object

Grammar that as long as what follows doesn’t match self, it matches to the next element. Most useful for a single element Grammar.



51
52
53
# File 'lib/grammar.rb', line 51

def ~
    -self + ANY
end