tagged release 0.6.4
[parrot.git] / runtime / parrot / library / PGE / Glob.pir
blob2b6a592c9e866c9e484e8fa34e44b584ada2d445
1 =head1 TITLE
3 Glob - Parse and compile glob notation expressions.
5 =head1 DESCRIPTION
7 A parser for shell-stype glob notation.
9 =head2 Functions
11 =over 4
13 =item C<compile_glob(PMC source, PMC adverbs :slurpy :named)>
15 Return the result of compiling the glob expression given by
16 C<source>.   Normally this function is obtained using
17 C<compreg 'PGE::Glob'> instead of calling it directly.
19 Returns the compiled regular expression.  If a C<target>
20 named parameter is supplied, then it will return the parse tree
21 (target='parse'), the expression tree (target='exp'),
22 or the resulting PIR code (target='PIR').
24 =cut
26 .namespace [ 'PGE::Glob' ]
28 .sub 'compile_glob'
29     .param pmc source
30     .param pmc adverbs         :slurpy :named
32     .local string target
33     target = adverbs['target']
34     target = downcase target
36     .local pmc match
37     null match
38     if source == '' goto analyze
39     $P0 = get_global 'glob'
40     match = $P0(source)
41     if target != 'parse' goto check
42     .return (match)
44   check:
45     unless match goto check_1
46     $S0 = source
47     $S1 = match
48     if $S0 == $S1 goto analyze
49   check_1:
50     null $P0
51     .return ($P0)
53   analyze:
54     .local pmc exp, pad
55     exp = new 'PGE::Exp::Concat'
56     $I0 = 1
57     $P0 = new 'PGE::Exp::Anchor'
58     $P0.'result_object'('^')
59     exp[0] = $P0
60     if null match goto analyze_1
61     $P0 = match['expr']
62     exp[$I0] = $P0
63     inc $I0
64   analyze_1:
65     $P0 = new 'PGE::Exp::Anchor'
66     $P0.'result_object'('$')
67     exp[$I0] = $P0
69     .return exp.'compile'(adverbs :flat :named)
70 .end
73 .sub 'main' :main
74     .param pmc args
76     load_bytecode 'PGE.pbc'
77     load_bytecode 'PGE/Dumper.pbc'
79     $P0 = compreg 'PGE::Glob'
80     .return $P0.'command_line'(args)
81 .end
84 .sub '__onload' :load :init
85     .local pmc optable
86     load_bytecode 'PGE.pbc'
88     optable = new 'PGE::OPTable'
89     store_global '$optable', optable
91     $P0 = find_global 'glob_literal'
92     optable.newtok('term:', 'precedence'=>'=', 'nows'=>1, 'parsed'=>$P0)
94     $P0 = find_global 'glob_quest'
95     optable.newtok('term:?', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
97     $P0 = find_global 'glob_star'
98     optable.newtok('term:*', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
100     $P0 = find_global 'glob_enum'
101     optable.newtok('term:[', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
103     $P0 = find_global 'glob_alt'
104     optable.newtok('term:{', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
106     optable.newtok('infix:', 'looser'=>'term:', 'assoc'=>'list', 'nows'=>1, 'match'=>'PGE::Exp::Concat')
108     $P2 = newclass [ 'PGE::Glob::Compiler' ]
109     addattribute $P2, '$!compsub'
111     $P0 = get_global 'compile_glob'
112     $P1 = new [ 'PGE::Glob::Compiler' ]
113     $P1.'register'('PGE::Glob', $P0)
114     .return ()
115 .end
118 =item C<glob(PMC mob, PMC adverbs :slurpy :named)>
120 Parses a glob expression, returning the corresponding
121 parse C<PGE::Match> object.
123 =cut
125 .const int GLOB_INF = 2147483647
127 .sub 'glob'
128     .param pmc mob
129     .param pmc adverbs         :slurpy :named
131     .local pmc optable, match
132     optable = find_global 'PGE::Glob', '$optable'
133     match = optable.'parse'(mob)
134     .return (match)
135 .end
138 .sub 'scan_literal'
139     .param string target
140     .param int pos
141     .param string delim
143     .local int lastpos
144     lastpos = length target
145     .local string literal
146     literal = ''
147   literal_loop:
148     if pos >= lastpos goto literal_end
149     $S0 = substr target, pos, 1
150     $I0 = index delim, $S0
151     if $I0 >= 0 goto literal_end
152     if $S0 != '\' goto literal_add
153     inc pos
154     $S0 = substr target, pos, 1
155   literal_add:
156     literal .= $S0
157     inc pos
158     goto literal_loop
159   literal_end:
160     .return (literal, pos)
161 .end
164 =item C<glob_literal(PMC mob, PMC adverbs)>
166 Scan a literal from a string, stopping at any metacharacters such
167 as C<*> or C<[>.  Return the matched portion, with the C<result_object>
168 set to the decoded literal.
170 =cut
172 .sub 'glob_literal'
173     .param pmc mob
174     .param pmc adverbs         :slurpy :named
176     .local string target
177     .local int pos
178     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Literal')
179     ($S0, $I0) = 'scan_literal'(target, pos, '*?[{')
180     if $I0 <= pos goto end
181     mob.'to'($I0)
182     mob.'result_object'($S0)
183   end:
184     .return (mob)
185 .end
188 =item C<glob_quest(PMC mob, PMC adverbs)>
190 Process a C<?> wildcard character in a glob.  For this we just
191 return a CCShortcut that is set to '.'
193 =cut
195 .sub 'glob_quest'
196     .param pmc mob
197     .param pmc adverbs         :slurpy :named
198     ##   The '?' is already in mob['KEY'], so we don't need to find it here.
199     (mob, $I0) = mob.'new'(mob, 'grammar'=>'PGE::Exp::CCShortcut')
200     mob.'to'($I0)
201     mob.'result_object'('.')
202     .return (mob)
203 .end
206 =item C<glob_star(PMC mob, PMC adverbs)>
208 Process a C<*> wildcard character in a glob.  This is a little
209 bit more complex, as we have to return a quantified '.'.
211 =cut
213 .sub 'glob_star'
214     .param pmc mob
215     .param pmc adverbs         :slurpy :named
216     .local int pos
217     ##   The '*' is already in mob['KEY'], so we don't need to find it here.
218     ##   We create a Quant object, then a CCShortcut inside of it.
219     (mob, pos) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Quant')
220     mob.'to'(pos)
221     mob['min'] = 0
222     mob['max'] = GLOB_INF
223     $P0 = mob.'new'(mob, 'grammar'=>'PGE::Exp::CCShortcut')
224     $P0.'to'(pos)
225     $P0.'result_object'('.')
226     mob[0] = $P0
227     .return (mob)
228 .end
230 =item C<glob_enum(PMC mob, PMC adverbs)>
232 Parse an enumerated character list, such as [abcd],
233 [!abcd], and [^0-9].
235 =cut
237 .sub glob_enum
238     .param pmc mob
239     .param pmc adverbs         :slurpy :named
241     .local string target
242     .local int pos, lastpos
243     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::EnumCharList')
244     lastpos = length target
246     $S0 = substr target, pos, 1
247     if $S0 == '!' goto negate
248     if $S0 == '^' goto negate
249     mob['isnegated'] = 0
250     goto firstchar
251   negate:
252     mob['isnegated'] = 1
253     inc pos
254   firstchar:
255     .local string charlist
256     charlist = ''
257     $S0 = substr target, pos, 1
258     if $S0 == '-' goto addfirst
259     if $S0 == ']' goto addfirst
260     goto scan_loop
261   addfirst:
262     charlist .= $S0
263     inc pos
264   scan_loop:
265     ($S0, pos) = 'scan_literal'(target, pos, '-]')
266     if pos >= lastpos goto err_noclose
267     charlist .= $S0
268     $S0 = substr target, pos, 1
269     if $S0 == ']' goto scan_end
270     inc pos
271     $S0 = substr target, pos, 1
272     if $S0 == ']' goto scan_endhyphen
273     inc pos
274     $I1 = ord $S0
275     $I0 = ord charlist, -1
276   add_range:
277     if $I0 > $I1 goto scan_loop
278     $S1 = chr $I0
279     charlist .= $S1
280     inc $I0
281     goto add_range
282   scan_endhyphen:
283     charlist .= '-'
284   scan_end:
285     inc pos
286     mob.'to'(pos)
287     mob.'result_object'(charlist)
288     .return (mob)
290   err_noclose:
291     mob.'to'(-1)
292     .return (mob)
293 .end
295 =item C<glob_alt(PMC mob, PMC adverbs)>
297 Parse an enumerated character list, such as [abcd],
298 [!abcd], and [^0-9].
300 =cut
302 .sub glob_alt
303     .param pmc mob
304     .param pmc adverbs         :slurpy :named
306     .local string target
307     .local int pos, lastpos
308     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Literal')
309     lastpos = length target
311     ($S0, pos) = 'scan_literal'(target, pos, ',}')
312     mob.'to'(pos)
313     mob.'result_object'($S0)
314   alt_loop:
315     if pos >= lastpos goto err_noclose
316     $S0 = substr target, pos, 1
317     if $S0 == '}' goto end
318     $P0 = mob.'new'(mob, 'grammar'=>'PGE::Exp::Alt')
319     inc pos
320     mob.'to'(pos)
321     $P0[0] = mob
322     mob = $P0
323     $P0 = mob.'new'(mob, 'grammar'=>'PGE::Exp::Literal')
324     ($S0, pos) = 'scan_literal'(target, pos, ',}')
325     mob.'to'(pos)
326     $P0.'result_object'($S0)
327     mob[1] = $P0
328     goto alt_loop
329   end:
330     inc pos
331     mob.'to'(pos)
332     .return (mob)
334   err_noclose:
335     mob.'to'(-1)
336     .return (mob)
337 .end
339 .namespace [ 'PGE::Glob::Compiler' ]
341 =item register(string name, pmc compsub)
343 Registers this compiler object as C<name> and
344 using C<compsub> as the subroutine to call for performing compilation.
346 =cut
348 .sub 'register' :method
349     .param string name
350     .param pmc compsub
352     setattribute self, '$!compsub', compsub
353     compreg name, self
355     .return ()
356 .end
358 =item compile(pmc code [, "option" => value, ... ])
360 Compile C<source> (possibly modified by any provided options).
362 =cut
364 .sub 'compile' :method
365     .param pmc source
366     .param pmc adverbs         :slurpy :named
368     .local pmc compsub
370     #   $!compsub is deprecated
371     compsub = getattribute self, '$!compsub'
373     .return compsub(source, adverbs :flat :named)
374 .end
376 =back
378 =head1 AUTHOR
380 PGE::Glob was originally authored by Jonathan Scott Duff (duff@pobox.com),
381 It has been updated for later versions of PGE by Patrick R. Michaud
382 (pmichaud@pobox.com).
384 =cut
386 # Local Variables:
387 #   mode: pir
388 #   fill-column: 100
389 # End:
390 # vim: expandtab shiftwidth=4 ft=pir: