Imported File#ftype spec from rubyspecs.
[rbx.git] / lib / irb / slex.rb
bloba79cf2a0e5a43cc4508d7516639f06476d775722
2 #   irb/slex.rb - symple lex analizer
3 #       $Release Version: 0.9.5$
4 #       $Revision: 11708 $
5 #       $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
6 #       by Keiju ISHITSUKA(keiju@ruby-lang.org)
8 # --
10 #   
13 require "e2mmap"
14 require "irb/notifier"
16 module IRB
17   class SLex
18     @RCS_ID='-$Id: slex.rb 11708 2007-02-12 23:01:19Z shyouhei $-'
20     extend Exception2MessageMapper
21     def_exception :ErrNodeNothing, "node nothing"
22     def_exception :ErrNodeAlreadyExists, "node already exists"
24     DOUT = Notifier::def_notifier("SLex::")
25     D_WARN = DOUT::def_notifier(1, "Warn: ")
26     D_DEBUG = DOUT::def_notifier(2, "Debug: ")
27     D_DETAIL = DOUT::def_notifier(4, "Detail: ")
28     
29     DOUT.level = Notifier::D_NOMSG
31     def initialize
32       @head = Node.new("")
33     end
34     
35     def def_rule(token, preproc = nil, postproc = nil, &block)
36       D_DETAIL.pp token
38       postproc = block if block_given?
39       node = create(token, preproc, postproc)
40     end
41     
42     def def_rules(*tokens, &block)
43       if block_given?
44         p = block
45       end
46       for token in tokens
47         def_rule(token, nil, p)
48       end
49     end
50     
51     def preproc(token, proc)
52       node = search(token)
53       node.preproc=proc
54     end
55     
56     #\e$BMW%A%'%C%/\e(B? 
57     def postproc(token)
58       node = search(token, proc)
59       node.postproc=proc
60     end
61     
62     def search(token)
63       @head.search(token.split(//))
64     end
66     def create(token, preproc = nil, postproc = nil)
67       @head.create_subnode(token.split(//), preproc, postproc)
68     end
69     
70     def match(token)
71       case token
72       when Array
73       when String
74         return match(token.split(//))
75       else
76         return @head.match_io(token)
77       end
78       ret = @head.match(token)
79       D_DETAIL.exec_if{D_DEATIL.printf "match end: %s:%s\n", ret, token.inspect}
80       ret
81     end
82     
83     def inspect
84       format("<SLex: @head = %s>", @head.inspect)
85     end
87     #----------------------------------------------------------------------
88     #
89     #   class Node - 
90     #
91     #----------------------------------------------------------------------
92     class Node
93       # if postproc is nil, this node is an abstract node.
94       # if postproc is non-nil, this node is a real node.
95       def initialize(preproc = nil, postproc = nil)
96         @Tree = {}
97         @preproc = preproc
98         @postproc = postproc
99       end
101       attr_accessor :preproc
102       attr_accessor :postproc
103       
104       def search(chrs, opt = nil)
105         return self if chrs.empty?
106         ch = chrs.shift
107         if node = @Tree[ch]
108           node.search(chrs, opt)
109         else
110           if opt
111             chrs.unshift ch
112             self.create_subnode(chrs)
113           else
114             SLex.fail ErrNodeNothing
115           end
116         end
117       end
118       
119       def create_subnode(chrs, preproc = nil, postproc = nil)
120         if chrs.empty?
121           if @postproc
122             D_DETAIL.pp node
123             SLex.fail ErrNodeAlreadyExists
124           else
125             D_DEBUG.puts "change abstract node to real node."
126             @preproc = preproc
127             @postproc = postproc
128           end
129           return self
130         end
131         
132         ch = chrs.shift
133         if node = @Tree[ch]
134           if chrs.empty?
135             if node.postproc
136               DebugLogger.pp node
137               DebugLogger.pp self
138               DebugLogger.pp ch
139               DebugLogger.pp chrs
140               SLex.fail ErrNodeAlreadyExists
141             else
142               D_WARN.puts "change abstract node to real node"
143               node.preproc = preproc
144               node.postproc = postproc
145             end
146           else
147             node.create_subnode(chrs, preproc, postproc)
148           end
149         else
150           if chrs.empty?
151             node = Node.new(preproc, postproc)
152           else
153             node = Node.new
154             node.create_subnode(chrs, preproc, postproc)
155           end
156           @Tree[ch] = node
157         end
158         node
159       end
161       #
162       # chrs: String
163       #       character array
164       #       io must have getc()/ungetc(); and ungetc() must be
165       #       able to be called arbitrary number of times. 
166       #
167       def match(chrs, op = "")
168         D_DETAIL.print "match>: ", chrs, "op:", op, "\n"
169         if chrs.empty?
170           if @preproc.nil? || @preproc.call(op, chrs)
171             DOUT.printf(D_DETAIL, "op1: %s\n", op)
172             @postproc.call(op, chrs)
173           else
174             nil
175           end
176         else
177           ch = chrs.shift
178           if node = @Tree[ch]
179             if ret = node.match(chrs, op+ch)
180               return ret
181             else
182               chrs.unshift ch
183               if @postproc and @preproc.nil? || @preproc.call(op, chrs)
184                 DOUT.printf(D_DETAIL, "op2: %s\n", op.inspect)
185                 ret = @postproc.call(op, chrs)
186                 return ret
187               else
188                 return nil
189               end
190             end
191           else
192             chrs.unshift ch
193             if @postproc and @preproc.nil? || @preproc.call(op, chrs)
194               DOUT.printf(D_DETAIL, "op3: %s\n", op)
195               @postproc.call(op, chrs)
196               return ""
197             else
198               return nil
199             end
200           end
201         end
202       end
204       def match_io(io, op = "")
205         if op == ""
206           ch = io.getc
207           if ch == nil
208             return nil
209           end
210         else
211           ch = io.getc_of_rests
212         end
213         if ch.nil?
214           if @preproc.nil? || @preproc.call(op, io)
215             D_DETAIL.printf("op1: %s\n", op)
216             @postproc.call(op, io)
217           else
218             nil
219           end
220         else
221           if node = @Tree[ch]
222             if ret = node.match_io(io, op+ch)
223               ret
224             else
225               io.ungetc ch
226               if @postproc and @preproc.nil? || @preproc.call(op, io)
227                 DOUT.exec_if{D_DETAIL.printf "op2: %s\n", op.inspect}
228                 @postproc.call(op, io)
229               else
230                 nil
231               end
232             end
233           else
234             io.ungetc ch
235             if @postproc and @preproc.nil? || @preproc.call(op, io)
236               D_DETAIL.printf("op3: %s\n", op)
237               @postproc.call(op, io)
238             else
239               nil
240             end
241           end
242         end
243       end
244     end
245   end
248 SLex=IRB::SLex
250 if $0 == __FILE__
251   #    Tracer.on
252   case $1
253   when "1"
254     tr = SLex.new
255     print "0: ", tr.inspect, "\n"
256     tr.def_rule("=") {print "=\n"}
257     print "1: ", tr.inspect, "\n"
258     tr.def_rule("==") {print "==\n"}
259     print "2: ", tr.inspect, "\n"
260     
261     print "case 1:\n"
262     print tr.match("="), "\n"
263     print "case 2:\n"
264     print tr.match("=="), "\n"
265     print "case 3:\n"
266     print tr.match("=>"), "\n"
267     
268   when "2"
269     tr = SLex.new
270     print "0: ", tr.inspect, "\n"
271     tr.def_rule("=") {print "=\n"}
272     print "1: ", tr.inspect, "\n"
273     tr.def_rule("==", proc{false}) {print "==\n"}
274     print "2: ", tr.inspect, "\n"
275     
276     print "case 1:\n"
277     print tr.match("="), "\n"
278     print "case 2:\n"
279     print tr.match("=="), "\n"
280     print "case 3:\n"
281     print tr.match("=>"), "\n"
282   end
283   exit