Class: Python::Parser::Combinator

Inherits:
Object
  • Object
show all
Defined in:
lib/python/parser/combinator.rb

Constant Summary collapse

ParserDefinitionError =
Class.new(RuntimeError)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&proc) ⇒ Combinator

Returns a new instance of Combinator.



18
19
20
# File 'lib/python/parser/combinator.rb', line 18

def initialize(&proc)
  @f = proc
end

Instance Attribute Details

#fObject

Returns the value of attribute f.



17
18
19
# File 'lib/python/parser/combinator.rb', line 17

def f
  @f
end

Class Method Details

.any_char(x) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/python/parser/combinator.rb', line 127

def self.any_char(x)
  case x
  when String
    chars = x.cahrs.map{|c| char(c)}
    if chars.length < 0
      raise ParserDefinitionError.new
    else
      chars.inject(&:|)
    end
  when Range
    chars = x.map{|c| char(c)}
    if chars.length < 0
      raise ParserDefinitionError.new
    else
      chars.inject(&:|)
    end
  else
    raise ParserDefinitionError.new
  end
end

.binopl(parser, op_proc_parser) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/python/parser/combinator.rb', line 178

def self.binopl(parser, op_proc_parser)
  rest = proc{|a|
    op_proc_parser >> proc{|f|
      parser >> proc{|b|
        rest.call(f.call(a, b))
      }} | ret(a)
  }
  parser >> proc{|a|
    rest.call(a)
  }
end

.char(char) ⇒ Object



123
124
125
# File 'lib/python/parser/combinator.rb', line 123

def self.char(char)
  sat{|c| c == char}
end

.discardl(parser1, parser2) ⇒ Object



80
81
82
# File 'lib/python/parser/combinator.rb', line 80

def self.discardl(parser1, parser2)
  parser1 >> proc{parser2}
end

.discardr(parser1, parser2) ⇒ Object



84
85
86
87
88
89
# File 'lib/python/parser/combinator.rb', line 84

def self.discardr(parser1, parser2)
  parser1 >> proc{|x|
    parser2 >> proc{
      ret(x)
    }}
end

.either(parser1, parser2) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/python/parser/combinator.rb', line 67

def self.either(parser1, parser2)
  new{|inp|
    case result = parser1.parse(inp)
    when Failed
      parser2.parse(inp)
    when Succeeded
      result
    else
      raise "error."
    end
  }
end

.failureObject



46
47
48
# File 'lib/python/parser/combinator.rb', line 46

def self.failure
  new{|inp| Failed.new}
end

.itemObject



50
51
52
# File 'lib/python/parser/combinator.rb', line 50

def self.item
  new{|inp| inp.size == 0 ? Failed.new : Succeeded.new(inp[0], inp[1, inp.size - 1])}
end

.many(parser) ⇒ Object



106
107
108
# File 'lib/python/parser/combinator.rb', line 106

def self.many(parser)
  many1(parser) | ret([])
end

.many1(parser) ⇒ Object



110
111
112
113
114
115
# File 'lib/python/parser/combinator.rb', line 110

def self.many1(parser)
  parser >> proc{|x|
    many(parser) >> proc{|xs|
      ret([x] + xs)
    }}
end

.optional(parser) ⇒ Object



102
103
104
# File 'lib/python/parser/combinator.rb', line 102

def self.optional(parser)
  (parser >> proc{|x| ret([x])}) | ret([])
end

.parser(name, &proc) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/python/parser/combinator.rb', line 190

def self.parser(name, &proc)
  @cache ||= {}
  spcls = class << self; self end
  spcls.send(:define_method, name) do |*args|
    key = [name, args]
    if @cache[key]
      return @cache[key]
    else
      @cache[key] = self.new{}
      @cache[key].f = proc.call(*args).f
      return @cache[key]
    end
  end
end

.ret(something) ⇒ Object



42
43
44
# File 'lib/python/parser/combinator.rb', line 42

def self.ret(something)
  new{|inp| Succeeded.new(something, inp)}
end

.sat(&proc) ⇒ Object



117
118
119
120
121
# File 'lib/python/parser/combinator.rb', line 117

def self.sat(&proc)
  item >> proc{|c|
    proc.call(c) ? ret(c) : failure
  }
end

.separator(element_parser, separating_token_str) ⇒ Object



91
92
93
94
95
96
# File 'lib/python/parser/combinator.rb', line 91

def self.separator(element_parser, separating_token_str)
  element_parser >> proc{|x|
    many(token_str(separating_token_str) + element_parser) >> proc{|xs|
      ret([x] + xs)
    }}
end

.separator_allow_empty(element_parser, separating_token_str) ⇒ Object



98
99
100
# File 'lib/python/parser/combinator.rb', line 98

def self.separator_allow_empty(element_parser, separating_token_str)
  separator(element_parser, separating_token_str) | ret([])
end

.so(parser, &proc) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/python/parser/combinator.rb', line 54

def self.so(parser, &proc)
  new{|inp|
    case result = parser.parse(inp)
    when Failed
      result
    when Succeeded
      proc.call(result.parsed).parse(result.rest)
    else
      raise "error."
    end
  }
end

.string(str) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/python/parser/combinator.rb', line 148

def self.string(str)
  if str.size == 0
    ret(str)
  else
    char(str[0]) >> proc{|c|
      string(str[1, str.size - 1]) >> proc{
        ret(str)
      }
    }
  end
end

.token(parser) ⇒ Object



166
167
168
169
170
171
172
# File 'lib/python/parser/combinator.rb', line 166

def self.token(parser)
  whitespace >> proc{
    parser >> proc{|x|
      whitespace >> proc{
        ret(x)
      }}}
end

.token_str(str) ⇒ Object



174
175
176
# File 'lib/python/parser/combinator.rb', line 174

def self.token_str(str)
  token(string(str))
end

.whitespaceObject



160
161
162
163
164
# File 'lib/python/parser/combinator.rb', line 160

def self.whitespace
  many(char("\s") | char("\t")) >> proc{|ws|
    ret(:whitespace)
  }
end

Instance Method Details

#+(other) ⇒ Object



34
35
36
# File 'lib/python/parser/combinator.rb', line 34

def +(other)
  self.class.discardl(self, other)
end

#-(other) ⇒ Object



38
39
40
# File 'lib/python/parser/combinator.rb', line 38

def -(other)
  self.class.discardr(self, other)
end

#>>(proc) ⇒ Object



26
27
28
# File 'lib/python/parser/combinator.rb', line 26

def >>(proc)
  self.class.so(self, &proc)
end

#parse(inp) ⇒ Object



22
23
24
# File 'lib/python/parser/combinator.rb', line 22

def parse(inp)
  @f.call(inp)
end

#|(other) ⇒ Object



30
31
32
# File 'lib/python/parser/combinator.rb', line 30

def |(other)
  self.class.either(self, other)
end