JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / unused / com / stevesoft / pat / parsePerl.java
1 //
2 // This software is now distributed according to
3 // the Lesser Gnu Public License.  Please see
4 // http://www.gnu.org/copyleft/lesser.txt for
5 // the details.
6 //    -- Happy Computing!
7 //
8 package com.stevesoft.pat;
9
10 /**
11  * This class provides a method for parsing the "s/.../.../" constructs of
12  * Regex.perlCode.
13  * 
14  * @see Regex#perlCode
15  */
16 class parsePerl
17 {
18   final static char close(char c)
19   {
20     // This switch statement does not behave
21     // properly when compiled with jdk1.1.5
22     // and the -O flag.
23     /*
24      * switch(c) { case '[': return ']'; case '(': return ')'; case '{': return
25      * '}'; } return c;
26      */
27     if (c == '<')
28     {
29       return '>';
30     }
31     if (c == '[')
32     {
33       return ']';
34     }
35     if (c == '(')
36     {
37       return ')';
38     }
39     if (c == '{')
40     {
41       return '}';
42     }
43     return c;
44   }
45
46   final public static String codify(String s, boolean keepbs)
47   {
48     return codify(s, 0, s.length(), keepbs);
49   }
50
51   final public static String codify(String s, int i0, int iN, boolean keepbs)
52   {
53     javajs.util.SB sb = new javajs.util.SB();
54     boolean ucmode = false, lcmode = false, litmode = false;
55     boolean uc1 = false, lc1 = false;
56     boolean modified = false;
57     for (int i = i0; i < iN; i++)
58     {
59       char c = s.charAt(i);
60       boolean mf = true, app = true;
61       if (c == '\\')
62       {
63         app = false;
64         i++;
65         if (i < s.length())
66         {
67           char c2 = s.charAt(i);
68           switch (c2)
69           {
70           case 'Q':
71             litmode = true;
72             break;
73           case 'U':
74             ucmode = true;
75             break;
76           case 'L':
77             lcmode = true;
78             break;
79           case 'u':
80             uc1 = true;
81             break;
82           case 'l':
83             lc1 = true;
84             break;
85           case 'E':
86             uc1 = lc1 = ucmode = lcmode = litmode = false;
87             break;
88           default:
89             if (keepbs)
90             {
91               sb.appendC('\\');
92             }
93             c = c2;
94             if (keepbs)
95             {
96               mf = false;
97             }
98             app = true;
99             break;
100           }
101           modified |= mf;
102         }
103       }
104       if (app)
105       {
106         if (lc1)
107         {
108           c = lc(c);
109           lc1 = false;
110         }
111         else if (uc1)
112         {
113           c = uc(c);
114           uc1 = false;
115         }
116         else if (ucmode)
117         {
118           c = uc(c);
119         }
120         else if (lcmode)
121         {
122           c = lc(c);
123         }
124         if (litmode && needbs(c))
125         {
126           sb.appendC('\\');
127         }
128         sb.appendC(c);
129       }
130     }
131     return modified ? sb.toString() : s;
132   }
133
134   final static char uc(char c)
135   {
136     return CaseMgr.toUpperCase(c);
137   }
138
139   final static char lc(char c)
140   {
141     return CaseMgr.toLowerCase(c);
142   }
143
144   final static boolean needbs(char c)
145   {
146     if (c >= 'a' && c <= 'z')
147     {
148       return false;
149     }
150     if (c >= 'A' && c <= 'Z')
151     {
152       return false;
153     }
154     if (c >= '0' && c <= '9')
155     {
156       return false;
157     }
158     if (c == '_')
159     {
160       return false;
161     }
162     return true;
163   }
164
165   final static Regex parse(String s)
166   {
167     boolean igncase = false, optim = false, gFlag = false;
168     boolean sFlag = false, mFlag = false, xFlag = false;
169
170     javajs.util.SB s1 = new javajs.util.SB();
171     javajs.util.SB s2 = new javajs.util.SB();
172     int i = 0, count = 0;
173     char mode, delim = '/', cdelim = '/';
174     if (s.length() >= 3 && s.charAt(0) == 's')
175     {
176       mode = 's';
177       delim = s.charAt(1);
178       cdelim = close(delim);
179       i = 2;
180     }
181     else if (s.length() >= 2 && s.charAt(0) == 'm')
182     {
183       mode = 'm';
184       delim = s.charAt(1);
185       cdelim = close(delim);
186       i = 2;
187     }
188     else if (s.length() >= 1 && s.charAt(0) == '/')
189     {
190       mode = 'm';
191       i = 1;
192     }
193     else
194     {
195       try
196       {
197         RegSyntaxError.endItAll("Regex.perlCode should be of the "
198                 + "form s/// or m// or //");
199       } catch (RegSyntax rs)
200       {
201       }
202       return null;
203     }
204     for (; i < s.length(); i++)
205     {
206       if (s.charAt(i) == '\\')
207       {
208         s1.appendC('\\');
209         i++;
210       }
211       else if (s.charAt(i) == cdelim && count == 0)
212       {
213         i++;
214         break;
215       }
216       else if (s.charAt(i) == delim && cdelim != delim)
217       {
218         count++;
219       }
220       else if (s.charAt(i) == cdelim && cdelim != delim)
221       {
222         count--;
223       }
224       s1.appendC(s.charAt(i));
225     }
226     if (mode == 's' && cdelim != delim)
227     {
228       while (i < s.length() && Prop.isWhite(s.charAt(i)))
229       {
230         i++;
231       }
232       if (i >= s.length())
233       {
234         try
235         {
236           RegSyntaxError.endItAll("" + mode + delim + " needs " + cdelim);
237         } catch (RegSyntax rs)
238         {
239         }
240         return null;
241       }
242       cdelim = close(delim = s.charAt(i));
243       i++;
244     }
245     count = 0;
246     if (mode == 's')
247     {
248       for (; i < s.length(); i++)
249       {
250         if (s.charAt(i) == '\\')
251         {
252           s2.appendC('\\');
253           i++;
254         }
255         else if (s.charAt(i) == cdelim && count == 0)
256         {
257           i++;
258           break;
259         }
260         else if (s.charAt(i) == delim && cdelim != delim)
261         {
262           count++;
263         }
264         else if (s.charAt(i) == cdelim && cdelim != delim)
265         {
266           count--;
267         }
268         s2.appendC(s.charAt(i));
269       }
270     }
271     for (; i < s.length(); i++)
272     {
273       char c = s.charAt(i);
274       switch (c)
275       {
276       case 'x':
277         xFlag = true;
278         break;
279       case 'i':
280         igncase = true;
281         break;
282       case 'o':
283         optim = true;
284         break;
285       case 's':
286         sFlag = true;
287         break;
288       case 'm':
289         mFlag = true;
290         break;
291       case 'g':
292         gFlag = true;
293         break;
294       default:
295
296         // syntax error!
297         try
298         {
299           RegSyntaxError.endItAll("Illegal flag to pattern: " + c);
300         } catch (RegSyntax rs)
301         {
302         }
303         return null;
304       }
305     }
306     Regex r = new Regex();
307     try
308     {
309       String pat = s1.toString(), reprul = s2.toString();
310       if (xFlag)
311       {
312         pat = strip(pat);
313         reprul = strip(reprul);
314       }
315       r.compile(pat);
316       r.ignoreCase |= igncase;
317       r.gFlag |= gFlag;
318       r.sFlag |= sFlag;
319       r.mFlag |= mFlag;
320       if (optim)
321       {
322         r.optimize();
323       }
324       if (delim == '\'')
325       {
326         r.setReplaceRule(new StringRule(reprul));
327       }
328       else
329       {
330         r.setReplaceRule(parsePerl.perlCode(reprul));
331       }
332     } catch (RegSyntax rs)
333     {
334       r = null;
335     }
336     return r;
337   }
338
339   static String strip(String s)
340   {
341     javajs.util.SB sb = new javajs.util.SB();
342     for (int i = 0; i < s.length(); i++)
343     {
344       char c = s.charAt(i);
345       if (Prop.isWhite(c))
346       {
347         ;
348       }
349       else if (c == '#')
350       {
351         i++;
352         while (i < s.length())
353         {
354           if (s.charAt(i) == '\n')
355           {
356             break;
357           }
358           i++;
359         }
360       }
361       else if (c == '\\')
362       {
363         sb.appendC(c);
364         sb.appendC(s.charAt(++i));
365       }
366       else
367       {
368         sb.appendC(c);
369       }
370     }
371     return sb.toString();
372   }
373
374         /**
375          * Compile a ReplaceRule using the text that would go between the second and
376          * third /'s in a typical substitution pattern in Perl: s/ ... / <i>The
377          * argument to ReplaceRule.perlCode</i> /.
378          */
379         public static ReplaceRule perlCode(String s)
380         {
381           // String sav_backGs = Regex.backGs;
382           // int sav_backGto = Regex.backGto;
383           try
384           {
385             int mf = 0, mt = 0;
386             Regex gv = ReplaceRule.getv();
387             ReplaceRule head = null;
388             Object tmp = null;
389             while (gv.searchFrom(s, mt))
390             {
391               int off = Regex.BackRefOffset - 1;
392               mf = gv.matchedFrom();
393               if (mf > mt)
394               {
395                 head = ReplaceRule.add(head, new StringRule(s.substring(mt, mf)));
396               }
397               String var = null;
398               if ((var = gv.stringMatched(1 + off)) != null
399                       || (var = gv.stringMatched(2 + off)) != null
400                       || (var = gv.stringMatched(5 + off)) != null)
401               {
402                 int d = 0;
403                 for (int i = 0; i < var.length(); i++)
404                 {
405                   d = 8 * d + (var.charAt(i) - '0');
406                 }
407                 if (var.length() == 1)
408                 {
409                   head = ReplaceRule.add(head, new BackRefRule(d));
410                 }
411                 else
412                 {
413                   head = new StringRule("" + (char) d);
414                 }
415               }
416               else if ((var = gv.stringMatched(10 + off)) != null)
417               {
418                 if ("QELlUu".indexOf(var) >= 0)
419                 {
420                   head = ReplaceRule.add(head, new CodeRule(var.charAt(0)));
421                 }
422                 else
423                 {
424                   head = ReplaceRule.add(head, new StringRule(var));
425                 }
426               }
427               else if ((var = gv.stringMatched(3 + off)) != null
428                       || (var = gv.stringMatched(4 + off)) != null
429                       || (var = gv.stringMatched(6 + off)) != null)
430               {
431                 String arg = "";
432                 int pc;
433                 if ((pc = var.indexOf(':')) > 0)
434                 {
435                   arg = var.substring(pc + 1);
436                   var = var.substring(0, pc);
437                 }
438                 if (var.equals("&") || var.equals("MATCH"))
439                 {
440                   head = ReplaceRule.add(head, new AmpersandRule());
441                 }
442                 else if (var.equals("`") || var.equals("PREMATCH"))
443                 {
444                   head = ReplaceRule.add(head, new LeftRule());
445                 }
446                 else if (var.equals("'") || var.equals("POSTMATCH"))
447                 {
448                   head = ReplaceRule.add(head, new RightRule());
449                 }
450                 else if (var.equals("WANT_MORE_TEXT"))
451                 {
452                   head = ReplaceRule.add(head, new WantMoreTextReplaceRule());
453                 }
454                 else if (var.equals("POP"))
455                 {
456                   head = ReplaceRule.add(head, new PopRule());
457                 }
458                 else if (var.startsWith("+")
459                         && (tmp = ReplaceRule.defs.get(var.substring(1))) != null)
460                 {
461                   if (tmp instanceof Regex)
462                   {
463                     head = ReplaceRule.add(head, new PushRule(var.substring(1), (Regex) tmp));
464                   }
465                   else if (tmp instanceof Transformer)
466                   {
467                     head = ReplaceRule.add(head, new PushRule(var.substring(1),
468                             (Transformer) tmp));
469                   }
470                   else
471                   {
472                     head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
473                   }
474                 }
475                 else if (var.startsWith("=")
476                         && (tmp = ReplaceRule.defs.get(var.substring(1))) != null)
477                 {
478                   if (tmp instanceof Regex)
479                   {
480                     head = ReplaceRule.add(head,
481                             new ChangeRule(var.substring(1), (Regex) tmp));
482                   }
483                   else if (tmp instanceof Transformer)
484                   {
485                     head = ReplaceRule.add(head, new ChangeRule(var.substring(1),
486                             (Transformer) tmp));
487                   }
488                   else
489                   {
490                     head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
491                   }
492                 }
493                 else if ((tmp = ReplaceRule.defs.get(var)) != null)
494                 {
495                   if (tmp instanceof ReplaceRule)
496                   {
497                     ReplaceRule alt = ((ReplaceRule) tmp).arg(arg);
498                     if (alt == null)
499                     {
500                       alt = ((ReplaceRule) tmp);
501                     }
502                     head = ReplaceRule.add(head, (ReplaceRule) (alt.clone()));
503                   }
504                 }
505                 else
506                 // can't figure out how to transform this thing...
507                 {
508                   head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
509                 }
510               }
511               else if ((var = gv.stringMatched(7 + off)) != null)
512               {
513                 char c = var.charAt(0);
514                 if (c == 'n')
515                 {
516                   head = ReplaceRule.add(head, new StringRule("\n"));
517                 }
518                 else if (c == 't')
519                 {
520                   head = ReplaceRule.add(head, new StringRule("\t"));
521                 }
522                 else if (c == 'r')
523                 {
524                   head = ReplaceRule.add(head, new StringRule("\r"));
525                 }
526                 else if (c == 'b')
527                 {
528                   head = ReplaceRule.add(head, new StringRule("\r"));
529                 }
530                 else if (c == 'a')
531                 {
532                   head = ReplaceRule.add(head, new StringRule("" + (char) 7));
533                 }
534                 else if (c == 'e')
535                 {
536                   head = ReplaceRule.add(head, new StringRule("" + (char) 27));
537                 }
538                 else if (c == 'f')
539                 {
540                   head = ReplaceRule.add(head, new StringRule("" + (char) 12));
541                 }
542               }
543               else if ((var = gv.stringMatched(8 + off)) != null)
544               {
545                 char c = var.charAt(0);
546                 if (c < Ctrl.cmap.length)
547                 {
548                   c = Ctrl.cmap[c];
549                 }
550                 head = ReplaceRule.add(head, new StringRule("" + c));
551               }
552               else if ((var = gv.stringMatched(9 + off)) != null)
553               {
554                 int d = 16 * ReplaceRule.getHexDigit(var.charAt(0))
555                         + ReplaceRule.getHexDigit(var.charAt(1));
556                 head = ReplaceRule.add(head, new StringRule("" + (char) d));
557               }
558               mt = gv.matchedTo();
559             }
560             if (mt <= s.length())
561             {
562               head = ReplaceRule.add(head, new StringRule(s.substring(mt)));
563             }
564             return head;
565           } finally
566           {
567             // Regex.backGs = sav_backGs;
568             // Regex.backGto = sav_backGto;
569           }
570         }
571 }