tagged release 0.6.4
[parrot.git] / languages / lua / src / lib / luaregex.pir
blob4709f25147dab7b33c8185ceb0ca14d1bdf8bc1d
1 # Copyright (C) 2007-2008, The Perl Foundation.
2 # $Id$
4 =head1 NAME
6 lib/luaregex.pir - Lua regex compiler
8 =head1 DESCRIPTION
10 See "Lua 5.1 Reference Manual", section 5.4.1 "Patterns",
11 L<http://www.lua.org/manual/5.1/manual.html#5.4.1>.
13 =head2 Character Class:
15 A I<character class> is used to represent a set of characters. The following
16 combinations are allowed in describing a character class:
18 =over 4
20 =item B<x>
22 (where I<x> is not one of the I<magic characters> C<^$()%.[]*+-?)> represents
23 the character I<x> itself.
25 =item B<.>
27 (a dot) represents all characters.
29 =item B<%a>
31 represents all letters.
33 =item B<%c>
35 represents all control characters.
37 =item B<%d>
39 represents all digits.
41 =item B<%l>
43 represents all lowercase letters.
45 =item B<%p>
47 represents all punctuation characters.
49 =item B<%s>
51 represents all space characters.
53 =item B<%u>
55 represents all uppercase letters.
57 =item B<%w>
59 represents all alphanumeric characters.
61 =item B<%x>
63 represents all hexadecimal digits.
65 =item B<%z>
67 represents the character with representation 0.
69 =item B<%x>
71 (where I<x> is any non-alphanumeric character) represents the character I<x>.
72 This is the standard way to escape the magic characters. Any punctuation
73 character (even the non magic) can be preceded by a C<'%'> when used to
74 represent itself in a pattern.
76 =item B<[set]>
78 represents the class which is the union of all characters in I<set>. A range of
79 characters may be specified by separating the end characters of the range with
80 a C<'-'>. All classes C<%x> described above may also be used as components in
81 I<set>. All other characters in I<set> represent themselves. For example,
82 C<[%w_]> (or C<[_%w]>) represents all alphanumeric characters plus the
83 underscore, C<[0-7]> represents the octal digits, and C<[0-7%l%-]> represents
84 the octal digits plus the lowercase letters plus the C<'-'> character.
86 The interaction between ranges and classes is not defined. Therefore, patterns
87 like C<[%a-z]> or C<[a-%%]> have no meaning.
89 =item B<[^set]>
91 represents the complement of I<set>, where I<set> is interpreted as above.
93 =back
95 For all classes represented by single letters (C<%a>, C<%c>, etc.), the
96 corresponding uppercase letter represents the complement of the class. For
97 instance, C<%S> represents all non-space characters.
99 The definitions of letter, space, and other character groups depend on the
100 current locale. In particular, the class C<[a-z]> may not be equivalent to
101 C<%l>.
103 =head2 Pattern Item:
105 A I<pattern item> may be
107 =over 4
109 =item *
111 a single character class, which matches any single character in the class;
113 =item *
115 a single character class followed by C<'*'>, which matches 0 or more
116 repetitions of characters in the class. These repetition items will always
117 match the longest possible sequence;
119 =item *
121 a single character class followed by C<'+'>, which matches 1 or more
122 repetitions of characters in the class. These repetition items will always
123 match the longest possible sequence;
125 =item *
127 a single character class followed by C<'-'>, which also matches 0 or more
128 repetitions of characters in the class. Unlike C<'*'>, these repetition items
129 will always match the I<shortest> possible sequence;
131 =item *
133 a single character class followed by C<'?'>, which matches 0 or 1
134 occurrence of a character in the class;
136 =item *
138 C<%n>, for I<n> between 1 and 9; such item matches a substring equal to
139 the i<n>-th captured string (see below);
141 =item *
143 C<%bxy>, where I<x> and I<y> are two distinct characters; such item
144 matches strings that start with I<x>, end with I<y>, and where the I<x> and
145 I<y> are I<balanced>. This means that, if one reads the string from left to
146 right, counting I<+1> for an I<x> and I<-1> for a I<y>, the ending I<y> is the
147 first I<y> where the count reaches 0. For instance, the item C<%b()> matches
148 expressions with balanced parentheses.
150 =back
152 =head2 Pattern:
154 A I<pattern> is a sequence of pattern items. A C<'^'> at the beginning of a
155 pattern anchors the match at the beginning of the subject string. A C<'$'> at
156 the end of a pattern anchors the match at the end of the subject string. At
157 other positions, C<'^'> and C<'$'> have no special meaning and represent
158 themselves.
160 =head2 Captures:
162 A pattern may contain sub-patterns enclosed in parentheses; they describe
163 I<captures>. When a match succeeds, the substrings of the subject string that
164 match captures are stored (I<captured>) for future use. Captures are numbered
165 according to their left parentheses. For instance, in the pattern
166 C<"(a*(.)%w(%s*))">, the part of the string matching C<"a*(.)%w(%s*)"> is
167 stored as the first capture (and therefore has number 1); the character
168 matching C<"."> is captured with number 2, and the part matching C<"%s*"> has
169 number 3.
171 As a special case, the empty capture C<()> captures the current string
172 position (a number). For instance, if we apply the pattern C<"()aa()"> on the
173 string C<"flaaap">, there will be two captures: 3 and 5.
175 A pattern cannot contain embedded zeros. Use C<%z> instead.
177 =head1 HISTORY
179 Mostly taken from F<compilers/pge/PGE/P5Regex.pir>.
181 =head1 AUTHOR
183 Francois Perrad
185 =cut
187 .sub '__onload' :anon :load :init
188     load_bytecode 'PGE.pbc'
190     $P0 = subclass 'PGE::Exp::CCShortcut', 'PGE::Exp::LuaCCShortcut'
191     $P0 = subclass 'PGE::Exp::CGroup', 'PGE::Exp::LuaCGroup'
192     $P0 = subclass 'PGE::Exp', 'PGE::Exp::LuaBalanced'
193     $P0 = subclass 'Hash', 'PGE::Cache'
194 .end
196 .namespace [ 'PGE::LuaRegex' ]
198 .sub 'compile_luaregex'
199     .param pmc source
200     .param pmc adverbs         :slurpy :named
202     $I0 = exists adverbs['grammar']
203     if $I0 goto have_grammar
204     adverbs['grammar'] = 'PGE::Grammar'
205   have_grammar:
207     .local string target
208     target = adverbs['target']
209     target = downcase target
211     unless target == '' goto no_cache
212     .local pmc cache
213     cache = get_hll_global ['PGE::LuaRegex'], 'cache_compile'
214     $P0 = cache[source]
215     if null $P0 goto no_cache
216     .return ($P0)
217   no_cache:
219     .local pmc match
220     match = luaregex(source)
221     if target != 'parse' goto check
222     .return (match)
224   check:
225     unless match goto check_1
226     $S0 = source
227     $S1 = match
228     if $S0 == $S1 goto analyze
229   check_1:
230     null $P0
231     .return ($P0)
233   analyze:
234     .local pmc expr, pad, code
235     expr = match['expr']
236     new pad, 'Hash'
237     pad['subpats'] = 0
238     expr = expr.'luaanalyze'(pad)
239     code = expr.'compile'(adverbs :flat :named)
240     cache[source] = code
241     .return (code)
242 .end
245 .sub 'luaregex'
246     .param pmc mob
247     .local pmc optable
248     optable = get_hll_global ['PGE::LuaRegex'], '$optable'
249     $P0 = optable.'parse'(mob)
250     .return ($P0)
251 .end
254 .include 'cclass.pasm'
257 .sub '__onload' :anon :load :init
258     .local pmc optable
259     new optable, 'PGE::OPTable'
260     set_hll_global ['PGE::LuaRegex'], '$optable', optable
262     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_literal'
263     optable.newtok('term:', 'precedence'=>'=', 'nows'=>1, 'parsed'=>$P0)
265     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_anchor'
266     optable.newtok('term:^', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
267     optable.newtok('term:$', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
269     optable.newtok('term:%a', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
270     optable.newtok('term:%A', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
271     optable.newtok('term:%c', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
272     optable.newtok('term:%C', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
273     optable.newtok('term:%d', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
274     optable.newtok('term:%D', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
275     optable.newtok('term:%l', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
276     optable.newtok('term:%L', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
277     optable.newtok('term:%p', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
278     optable.newtok('term:%P', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
279     optable.newtok('term:%s', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
280     optable.newtok('term:%S', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
281     optable.newtok('term:%u', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
282     optable.newtok('term:%U', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
283     optable.newtok('term:%w', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
284     optable.newtok('term:%W', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
285     optable.newtok('term:%x', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
286     optable.newtok('term:%X', 'equiv'=>'term:', 'nows'=>1, 'match'=>'PGE::Exp::LuaCCShortcut')
288     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_backref'
289     optable.newtok('term:%1', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
290     optable.newtok('term:%2', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
291     optable.newtok('term:%3', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
292     optable.newtok('term:%4', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
293     optable.newtok('term:%5', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
294     optable.newtok('term:%6', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
295     optable.newtok('term:%7', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
296     optable.newtok('term:%8', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
297     optable.newtok('term:%9', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
299     optable.newtok('circumfix:( )', 'equiv'=>'term:', 'nows'=>1, 'nullterm'=>1, 'match'=>'PGE::Exp::LuaCGroup')
301     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_enumclass'
302     optable.newtok('term:[', 'precedence'=>'=', 'nows'=>1, 'parsed'=>$P0)
303     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_enumclass2'
304     optable.newtok('term:.', 'precedence'=>'=', 'nows'=>1, 'parsed'=>$P0)
305     optable.newtok('term:%z', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
306     optable.newtok('term:%Z', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
308     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_balanced'
309     optable.newtok('term:%b', 'equiv'=>'term:', 'nows'=>1, 'parsed'=>$P0)
311     $P0 = get_hll_global ['PGE::LuaRegex'], 'parse_quantifier'
312     optable.newtok('postfix:*', 'looser'=>'term:', 'left'=>1, 'nows'=>1, 'parsed'=>$P0)
313     optable.newtok('postfix:+', 'equiv'=>'postfix:*', 'left'=>1, 'nows'=>1, 'parsed'=>$P0)
314     optable.newtok('postfix:?', 'equiv'=>'postfix:*', 'left'=>1, 'nows'=>1, 'parsed'=>$P0)
315     optable.newtok('postfix:-', 'equiv'=>'postfix:*', 'left'=>1, 'nows'=>1, 'parsed'=>$P0)
317     optable.newtok('infix:', 'looser'=>'postfix:*', 'right'=>1, 'nows'=>1, 'match'=>'PGE::Exp::Concat')
319     .local pmc cache, mt
320     new cache, 'PGE::Cache'
321     set_hll_global ['PGE::LuaRegex'], 'cache_compile', cache
323     $P0 = get_hll_global ['PGE::LuaRegex'], 'compile_luaregex'
324     compreg 'PGE::LuaRegex', $P0
325 .end
328 .sub 'parse_error'
329     .param pmc mob
330     .param int pos
331     .param string message
332     $P0 = getattribute mob, '$.pos'
333     $P0 = pos
334     $S0 = 'luaregex parse error: '
335     $S0 .= message
336     $S0 .= ' at offset '
337     $S1 = pos
338     $S0 .= $S1
339     $S0 .= ", found '"
340     $P1 = getattribute mob, '$.target'
341     $S1 = $P1
342     $S1 = substr $S1, pos, 1
343     $S0 .= $S1
344     $S0 .= "'"
345     die $S0
346 .end
349 .sub 'parse_literal'
350     .param pmc mob
351     .local string target
352     .local int pos, lastpos
353     .local int litstart, litlen
354     .local string initchar
355     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Literal')
356     lastpos = length target
357     initchar = substr target, pos, 1
358     if initchar == ')' goto end
359     inc pos
360   term_percent:
361     if initchar != '%' goto term_literal
362     if pos < lastpos goto term_percent_ok
363     parse_error(mob, pos, "malformed pattern (ends with '%')")
364   term_percent_ok:
365     initchar = substr target, pos, 1
366     inc pos
367   term_literal:
368     litstart = pos
369     litlen = 0
370   term_literal_loop:
371     if pos >= lastpos goto term_literal_end
372     $S0 = substr target, pos, 1
373     $I0 = index '()%.[]*+-?', $S0
374     # if not in circumfix:( ) throw error on end paren
375     if $I0 >= 0 goto term_literal_end
376     inc pos
377     inc litlen
378     goto term_literal_loop
379   term_literal_end:
380     if litlen < 1 goto term_literal_one
381     dec pos
382   term_literal_one:
383     $I0 = pos - litstart
384     $S0 = substr target, litstart, $I0
385     $S0 = concat initchar, $S0
386     mob.'result_object'($S0)
387     goto end
388   end:
389     mob.'to'(pos)
390     .return (mob)
391 .end
393 .const int PGE_INF = 2147483647
394 .const int PGE_BACKTRACK_GREEDY = 1
395 .const int PGE_BACKTRACK_EAGER = 2
397 .sub 'parse_quantifier'
398     .param pmc mob
399     .local string target
400     .local int min, max, backtrack
401     .local int pos, lastpos
402     .local string key
403     key = mob['KEY']
404     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Quant')
405     lastpos = length target
406     min = 0
407     max = PGE_INF
408     backtrack = PGE_BACKTRACK_GREEDY
409     if key != '+' goto quant_max
410     min = 1
411   quant_max:
412     if key != '?' goto quant_eager
413     max = 1
414   quant_eager:
415     if key != '-' goto end
416     backtrack = PGE_BACKTRACK_EAGER
417   end:
418     mob['min'] = min
419     mob['max'] = max
420     mob['backtrack'] = backtrack
421     mob.'to'(pos)
422     .return (mob)
423 .end
426 .sub 'parse_enumclass'
427     .param pmc mob
428     .local string target
429     .local int pos, lastpos
430     .local int isrange
431     .local string charlist
432     .local string key
433     key = mob['KEY']
434     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::EnumCharList')
435     lastpos = length target
436     charlist = ''
437     mob['isnegated'] = 0
438     isrange = 0
439     $S0 = substr target, pos, 1
440     if $S0 != '^' goto scan_first
441     mob['isnegated'] = 1
442     inc pos
443   scan_first:
444     if pos >= lastpos goto err_close
445     $S0 = substr target, pos, 1
446     inc pos
447     if $S0 == '%' goto percent
448     goto addchar
449   scan:
450     if pos >= lastpos goto err_close
451     $S0 = substr target, pos, 1
452     inc pos
453     if $S0 == ']' goto endclass
454     if $S0 == '-' goto hyphenrange
455     if $S0 != '%' goto addchar
456   percent:
457     $S0 = substr target, pos, 1
458     inc pos
459   addchar:
460     if isrange goto addrange
461     charlist .= $S0
462     goto scan
463   addrange:
464     isrange = 0
465     $I2 = ord charlist, -1
466     $I0 = ord $S0
467     if $I0 < $I2 goto err_range
468   addrange_1:
469     inc $I2
470     if $I2 > $I0 goto scan
471     $S1 = chr $I2
472     charlist .= $S1
473     goto addrange_1
474   hyphenrange:
475     if isrange goto addrange
476     isrange = 1
477     goto scan
478   endclass:
479     if isrange == 0 goto end
480     charlist .= '-'
481   end:
482     mob.'to'(pos)
483     mob.'result_object'(charlist)
484     .return (mob)
486   err_close:
487     parse_error(mob, pos, "malformed pattern (missing ']')")
488   err_range:
489     $S0 = 'Invalid [] range "'
490     $S1 = chr $I2
491     $S0 .= $S1
492     $S0 .= '-'
493     $S1 = chr $I0
494     $S0 .= $S1
495     $S0 .= '"'
496     parse_error(mob, pos, $S0)
497 .end
500 .sub 'parse_enumclass2'
501     .param pmc mob
502     .local string target
503     .local int pos
504     .local string charlist
505     .local string key
506     key = mob['KEY']
507     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::EnumCharList')
508     unless key == '.' goto zero
509     charlist = ''
510     mob['isnegated'] = 1
511     goto end
512   zero:
513     charlist = "\0"
514     mob['isnegated'] = 0
515     unless key == '%Z' goto end
516     mob['isnegated'] = 1
517   end:
518     mob.'to'(pos)
519     mob.'result_object'(charlist)
520     .return (mob)
521 .end
524 .sub 'parse_balanced'
525     .param pmc mob
526     .local string target
527     .local int pos, lastpos
528     .local string xy
529     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::LuaBalanced')
530     lastpos = length target
531     if lastpos < 2 goto err
532     xy = substr target, pos, 2
533     pos += 2
534     mob.'to'(pos)
535     mob.'result_object'(xy)
536     .return (mob)
538   err:
539     parse_error(mob, pos, "unbalanced pattern")
540 .end
543 .sub 'parse_backref'
544     .param pmc mob
545     .local string target
546     .local int pos
547     .local string cname
548     $P0 = getattribute mob, '$.target'
549     target = $P0
550     $P0 = getattribute mob, '$.pos'
551     pos = $P0
552     $I0 = pos - 1
553     $S0 = substr target, $I0, 1
554     (mob, $I1, $S1) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Scalar')
555     $I0 = $S0
556     dec $I0
557     mob['cname'] = $I0
558     mob.'to'(pos)
559     .return (mob)
560 .end
563 .sub 'parse_anchor'
564     .param pmc mob
565     .local string target
566     .local int pos, lastpos
567     .local string key
568     key = mob['KEY']
569     (mob, pos, target) = mob.'new'(mob, 'grammar'=>'PGE::Exp::Anchor')
570     lastpos = length target
571     unless key == '$' goto start
572     unless pos == lastpos goto end
573     mob.'to'(pos)
574   start:
575     unless pos == 1 goto end
576     mob.'to'(pos)
577   end:
578     .return (mob)
579 .end
582 .namespace [ 'PGE::Exp' ]
584 .sub 'luaanalyze' :method
585     .param pmc pad
586     .local pmc expr
587     $I0 = 0
588   loop:
589     $I1 = defined self[$I0]
590     if $I1 == 0 goto end
591     $P0 = self[$I0]
592     $P0 = $P0.'luaanalyze'(pad)
593     self[$I0] = $P0
594     inc $I0
595     goto loop
596   end:
597     .return (self)
598 .end
601 .namespace [ 'PGE::Exp::LuaCGroup' ]
603 .sub 'luaanalyze' :method
604     .param pmc pad
605     .local pmc expr
607     self['iscapture'] = 0
608     if self != '(' goto end
609     self['iscapture'] = 1
610     self['isscope'] = 0
611     self['isarray'] = 0
612     $I0 = pad['subpats']
613     self['cname'] = $I0
614     inc $I0
615     pad['subpats'] = $I0
616   end:
617     expr = self[0]
618     expr = expr.'luaanalyze'(pad)
619     self[0] = expr
620     .return (self)
621 .end
623 .sub 'pir' :method
624     .param pmc code
625     .param string label
626     .param string next
628     $P0 = self[0]
629     $I0 = isa $P0, 'PGE::Exp::Literal'
630     unless $I0 goto super
631     $S0 = $P0
632     unless $S0 == '' goto super
634     .local pmc args
635     args = self.'getargs'(label, next)
637     .local string captgen, captsave, captback
638     (captgen, captsave, captback) = self.'gencapture'(label)
640     code.'emit'(<<"        CODE", captgen, captsave, captback, args :flat :named)
641         %L: # empty capture
642           %0
643           push ustack, captscope
644           new captob, 'Integer'
645           set captob, pos
646           inc captob
647           %1
648           bsr %S
649           %2
650           captscope = pop ustack
651           goto fail\n
652         CODE
653     .return ()
655   super:
656     $P0 = get_hll_global ['PGE::Exp::CGroup'], 'pir'
657     .return $P0(self, code, label, next)
658 .end
661 .namespace [ 'PGE::Exp::LuaCCShortcut' ]
663 .sub 'reduce' :method
664     .param pmc next
666     .local string token
667     token = self
668     self['negate'] = 1
669     if token == '%A' goto letter
670     if token == '%C' goto ctrl
671     if token == '%D' goto digit
672     if token == '%L' goto lower
673     if token == '%P' goto ponct
674     if token == '%S' goto space
675     if token == '%U' goto upper
676     if token == '%W' goto word
677     if token == '%X' goto hexa
678     self['negate'] = 0
679     if token == '%a' goto letter
680     if token == '%c' goto ctrl
681     if token == '%d' goto digit
682     if token == '%l' goto lower
683     if token == '%p' goto ponct
684     if token == '%s' goto space
685     if token == '%u' goto upper
686     if token == '%w' goto word
687     if token == '%x' goto hexa
688     self['cclass'] = .CCLASS_ANY
689     goto end
690   letter:
691     self['cclass'] = .CCLASS_ALPHABETIC
692     goto end
693   ctrl:
694     self['cclass'] = .CCLASS_CONTROL
695     goto end
696   digit:
697     self['cclass'] = .CCLASS_NUMERIC
698     goto end
699   lower:
700     self['cclass'] = .CCLASS_LOWERCASE
701     goto end
702   ponct:
703     self['cclass'] = .CCLASS_PUNCTUATION
704     goto end
705   space:
706     self['cclass'] = .CCLASS_WHITESPACE
707     goto end
708   upper:
709     self['cclass'] = .CCLASS_UPPERCASE
710     goto end
711   word:
712     self['cclass'] = .CCLASS_WORD
713     goto end
714   hexa:
715     self['cclass'] = .CCLASS_HEXADECIMAL
716   end:
717     .return (self)
718 .end
721 .namespace [ 'PGE::Exp::LuaBalanced' ]
723 .sub 'reduce' :method
724     .param pmc next
725     .return (self)
726 .end
728 .sub 'pir' :method
729     .param pmc code
730     .param string label
731     .param string next
733     .local string begin, end
734     $S0 = self
735     begin = substr $S0, 0, 1
736     begin = code.'escape'(begin)
737     end = substr $S0, 1, 1
738     end = code.'escape'(end)
740     code.'emit'(<<"        CODE", label, begin, end, next)
741         %0: # balanced
742           if pos >= lastpos goto fail
743           $S0 = substr target, pos, 1
744           if $S0 != %1 goto fail
745           $I1 = 1
746         %0_1:
747           inc pos
748           if pos >= lastpos goto fail
749           $S0 = substr target, pos, 1
750           if $S0 != %2 goto %0_2
751           dec $I1
752           if $I1 != 0 goto %0_1
753           inc pos
754           goto %3
755         %0_2:
756           if $S0 != %1 goto %0_1
757           inc $I1
758           goto %0_1
759         CODE
760     .return ()
761 .end
764 # Local Variables:
765 #   mode: pir
766 #   fill-column: 100
767 # End:
768 # vim: expandtab shiftwidth=4 ft=pir: