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