KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > innig > macker > rule > MackerRegex


1 /*______________________________________________________________________________
2  *
3  * Macker http://innig.net/macker/
4  *
5  * Copyright 2002-2003 Paul Cantrell
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License version 2, as published by the
9  * Free Software Foundation. See the file LICENSE.html for more information.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the license for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
17  * Place, Suite 330 / Boston, MA 02111-1307 / USA.
18  *______________________________________________________________________________
19  */

20  
21 package net.innig.macker.rule;
22
23 import java.util.*;
24
25 import org.apache.regexp.RE;
26 import org.apache.regexp.RESyntaxException;
27
28 public final class MackerRegex
29     {
30     //--------------------------------------------------------------------------
31
// Constructors
32
//--------------------------------------------------------------------------
33

34     public MackerRegex(String JavaDoc regexStr)
35         throws MackerRegexSyntaxException
36         { this(regexStr, true); }
37         
38     public MackerRegex(String JavaDoc regexStr, boolean allowParts)
39         throws MackerRegexSyntaxException
40         {
41         if(regexStr == null)
42             throw new NullPointerException JavaDoc("regexStr == null");
43         buildStaticPatterns();
44
45         this.regexStr = regexStr;
46         parts = null;
47         regex = null;
48         prevVarValues = new HashMap();
49
50         if(!(allowParts ? allowable : allowableNoParts).match(regexStr))
51             throw new MackerRegexSyntaxException(regexStr);
52         }
53         
54     //--------------------------------------------------------------------------
55
// Properties
56
//--------------------------------------------------------------------------
57

58     public String JavaDoc getPatternString()
59         { return regexStr; }
60
61     private final String JavaDoc regexStr;
62
63     //--------------------------------------------------------------------------
64
// Evaluation
65
//--------------------------------------------------------------------------
66

67     public boolean matches(EvaluationContext context, String JavaDoc s)
68         throws UndeclaredVariableException, MackerRegexSyntaxException
69         { return getMatch(context, s) != null; }
70     
71     public String JavaDoc getMatch(EvaluationContext context, String JavaDoc s)
72         throws UndeclaredVariableException, MackerRegexSyntaxException
73         {
74         parseExpr(context);
75         Boolean JavaDoc match = (Boolean JavaDoc) matchCache.get(s);
76         if(Boolean.FALSE.equals(match))
77             return null;
78         if(Boolean.TRUE.equals(match))
79             return (String JavaDoc) matchResultCache.get(s);
80             
81         match = regex.match('.' + s) ? Boolean.TRUE : Boolean.FALSE;
82         matchCache.put(s, match);
83         if(match.booleanValue())
84             {
85             String JavaDoc matchResult = regex.getParen(regex.getParenCount() - 1);
86             matchResultCache.put(s, matchResult);
87             return matchResult;
88             }
89         else
90             return null;
91         }
92     
93     private void parseExpr(EvaluationContext context)
94         throws UndeclaredVariableException, MackerRegexSyntaxException
95         {
96         buildStaticPatterns();
97         
98         if(parts == null)
99             {
100             parts = new ArrayList();
101             for(int pos = 0; pos >= 0; )
102                 {
103                 boolean hasAnotherVar = var.match(regexStr, pos);
104                 int expEnd = hasAnotherVar ? var.getParenStart(0) : regexStr.length();
105                 
106                 if(pos < expEnd)
107                     parts.add(new ExpPart(parseSubexpr(regexStr.substring(pos, expEnd))));
108                 if(hasAnotherVar)
109                     parts.add(new VarPart(var.getParen(1)));
110                 
111                 pos = hasAnotherVar ? var.getParenEnd(0) : -1;
112                 }
113             }
114         
115         // Building the regexp is expensive; there's no point in doing it if we
116
// already have one cached, and the relevant variables haven't changed
117

118         boolean changed = (regex == null);
119         for(Iterator i = prevVarValues.entrySet().iterator(); !changed && i.hasNext(); )
120             {
121             Map.Entry entry = (Map.Entry) i.next();
122             String JavaDoc name = (String JavaDoc) entry.getKey();
123             String JavaDoc value = (String JavaDoc) entry.getValue();
124             if(!context.getVariableValue(name).equals(value))
125                 changed = true;
126             }
127             
128         if(changed)
129             {
130             StringBuffer JavaDoc builtRegexStr = new StringBuffer JavaDoc("^\\.?");
131             for(Iterator i = parts.iterator(); i.hasNext(); )
132                 {
133                 Part part = (Part) i.next();
134                 if(part instanceof VarPart)
135                     {
136                     String JavaDoc varName = ((VarPart) part).varName;
137                     String JavaDoc varValue = context.getVariableValue(varName);
138                     prevVarValues.put(varName, varValue);
139                     builtRegexStr.append(
140                         parseSubexpr(varValue));
141                     }
142                 else if(part instanceof ExpPart)
143                     builtRegexStr.append(
144                         ((ExpPart) part).exp);
145                 }
146             builtRegexStr.append('$');
147             
148             try { regex = new RE(builtRegexStr.toString()); }
149             catch(RESyntaxException rese)
150                 {
151                 System.out.println("builtRegexStr = " + builtRegexStr);
152                 throw new MackerRegexSyntaxException(regexStr, rese);
153                 }
154                 
155 //! if(???)
156
//! throw new MackerRegexSyntaxException(regexStr, "Too many parenthesized expressions");
157
matchCache = new HashMap();
158             matchResultCache = new HashMap();
159             }
160         }
161     
162     private String JavaDoc parseSubexpr(String JavaDoc exp)
163         {
164         exp = partBoundary.subst(exp, "[\\.\\$]");
165         exp = packageBoundary.subst(exp, "\\.");
166         exp = innerClassBoundary.subst(exp, "\\$");
167         exp = star.subst(exp, "@");
168         exp = matchAcross.subst(exp, ".*");
169         exp = matchWithin.subst(exp, "[^\\.]*");
170 // exp = matchWithinInner.subst(exp, "[^\\.\\$]*");
171
return exp;
172         }
173
174     private static void buildStaticPatterns()
175         {
176         if(allowable == null)
177             try {
178                 star = new RE("\\*");
179                 matchWithin = new RE("@");
180                 matchAcross = new RE("@@");
181                 partBoundary = new RE("\\.");
182                 packageBoundary = new RE("/");
183                 innerClassBoundary = new RE("\\$");
184
185                 String JavaDoc varS = "\\$\\{([A-Za-z0-9_\\.\\-]+)\\}";
186                 String JavaDoc partS = "(([A-Za-z_]|[\\(\\)]|\\*|" + varS + ")"
187                                + "([A-Za-z0-9_]|[\\(\\)]|\\*|" + varS + ")*)";
188                 var = new RE(varS);
189                 allowable = new RE("^([\\$\\./]?" + partS + ")+$", RE.MATCH_SINGLELINE);
190                 allowableNoParts = new RE("^" + partS + "$", RE.MATCH_SINGLELINE);
191                 }
192             catch(RESyntaxException rese)
193                 {
194                 rese.printStackTrace(System.out);
195                 throw new RuntimeException JavaDoc("Can't initialize RegexPattern: " + rese);
196                 }
197         }
198     
199     private RE regex;
200     private List/*<Part>*/ parts;
201     private Map prevVarValues, matchCache, matchResultCache;
202     static private RE star, matchWithin, matchAcross,
203         partBoundary, packageBoundary, innerClassBoundary, var,
204         allowable, allowableNoParts;
205     
206     private class Part { }
207     private class VarPart extends Part
208         {
209         public VarPart(String JavaDoc varName) { this.varName = varName; }
210         public String JavaDoc varName;
211         public String JavaDoc toString() { return "var(" + varName + ")"; }
212         }
213     private class ExpPart extends Part
214         {
215         public ExpPart(String JavaDoc exp) { this.exp = exp; }
216         public String JavaDoc exp;
217         public String JavaDoc toString() { return "exp(" + exp + ")"; }
218         }
219
220     //--------------------------------------------------------------------------
221
// Object
222
//--------------------------------------------------------------------------
223

224     public String JavaDoc toString()
225         { return '"' + regexStr + '"'; }
226     }
227
228
Popular Tags