View Javadoc
1   package org.apache.maven.plugin.cxx.utils.svn;
2   
3   /*
4    * Copyright (C) 2011-2016, Neticoa SAS France - Tous droits réservés.
5    * Author(s) : Franck Bonin, Neticoa SAS France
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   *
19   */
20   
21  import org.apache.maven.plugin.cxx.utils.Automate;
22  import org.apache.maven.plugin.cxx.utils.AutomateException;
23  import org.apache.maven.plugin.cxx.utils.Action;
24  import org.apache.maven.plugin.cxx.utils.ActionExecutor;
25  
26  import java.text.StringCharacterIterator;
27  
28  // @formatter:off
29  /**
30   * We implement this funny automate :
31   * 
32   * @author fbonin
33   * 
34   */
35  // @formatter:on
36  public class SvnExternalsTokenizer extends Automate
37  {
38  
39      /**
40       * define automate labels
41       */
42      private enum MainLabel 
43      {
44          blank,
45          backSlack,
46          quote,
47          minusChar,
48          rChar,
49          digit,
50          diese,
51          other,
52          empty;
53  
54          /**
55           * TODO 
56           * 
57           * @param i
58           * @return enum
59           */
60          public static MainLabel fromOrdinal( final int i )
61          {
62              if ( ( i < 0 ) || ( i >= MainLabel.values().length ) )
63              {
64                  throw new IndexOutOfBoundsException( "Invalid ordinal" );
65              }
66              return MainLabel.values()[i];
67          }
68      };
69      
70      /**
71       * token types
72       */
73      public enum TokenType 
74      {
75          empty,
76          libelle,
77          revision,
78          comment;
79      };
80      
81      /**
82       * a token descriptor
83       */
84      public class Token
85      {      
86          public TokenType tokenType = TokenType.empty;
87          public Object value = null;
88      };
89  
90      /**
91       * define automate states
92       */
93      private enum MainState
94      {
95          INIT,
96          LEX,
97          LEXESC,
98          QUOBEG,
99          QUOEND,
100         MREV,
101         REV,
102         PREV,
103         COMMENT,
104         FINAL_LIBELLE,
105         FINAL_REV,
106         FINAL_EMPTY,
107         FINAL_COMMENT;
108 
109         /**
110          * 
111          * @param i
112          * @return enum
113          */
114         public static MainState fromOrdinal( final int i )
115         {
116             if ( ( i < 0 ) || ( i >= MainState.values().length ) )
117             {
118                 throw new IndexOutOfBoundsException( "Invalid ordinal" );
119             }
120             return MainState.values()[i];
121         }
122     };
123 
124     /**
125      * Automate definition
126      */
127     static {
128         Action accumulate = new Action()
129         {
130             public void action( final ActionExecutor executor, final Object aiParam )
131                 throws AutomateException
132             {
133                 ( ( SvnExternalsTokenizer ) executor ).accumulate( aiParam );
134             }
135 
136             public String getName()
137             {
138                 return "accumulate";
139             }
140         };
141         
142         Action drop = new Action()
143         {
144             public void action( final ActionExecutor executor, final Object aiParam )
145                 throws AutomateException
146             {
147                 ( ( SvnExternalsTokenizer ) executor ).drop( aiParam );
148             }
149 
150             public String getName()
151             {
152                 return "drop";
153             }
154         };
155         
156         Action nothing = new Action()
157         {
158             public void action( final ActionExecutor executor, final Object aiParam )
159                 throws AutomateException
160             {
161             }
162 
163             public String getName()
164             {
165                 return "nothing";
166             }
167         };
168         
169         Action tokenTypeLibelle = new Action()
170         {
171             public void action( final ActionExecutor executor, final Object aiParam )
172                 throws AutomateException
173             {
174                 ( ( SvnExternalsTokenizer ) executor ).currentToken.tokenType = TokenType.libelle;
175             }
176 
177             public String getName()
178             {
179                 return "tokenTypeLibelle";
180             }
181         };
182         
183         Action tokenTypeRevision = new Action()
184         {
185             public void action( final ActionExecutor executor, final Object aiParam )
186                 throws AutomateException
187             {
188                 ( ( SvnExternalsTokenizer ) executor ).currentToken.tokenType = TokenType.revision;
189             }
190 
191             public String getName()
192             {
193                 return "tokenTypeRevision";
194             }
195         };
196         
197          Action tokenTypeComment = new Action()
198         {
199             public void action( final ActionExecutor executor, final Object aiParam )
200                 throws AutomateException
201             {
202                 ( ( SvnExternalsTokenizer ) executor ).currentToken.tokenType = TokenType.comment;
203             }
204 
205             public String getName()
206             {
207                 return "tokenTypeComment";
208             }
209         };
210 
211         try
212         {
213             Automate.initializeAutomate( MainState.values().length, MainLabel.values().length );
214             
215             // override defaut transitions to handle all "other" char with state "default" case
216             Automate.setState( MainState.INIT.ordinal(), null, MainState.LEX.ordinal(), accumulate );
217             Automate.setTransition( MainState.INIT.ordinal(), MainLabel.blank.ordinal(),
218                 MainState.INIT.ordinal(), drop );
219             Automate.setTransition( MainState.INIT.ordinal(), MainLabel.quote.ordinal(),
220                 MainState.QUOBEG.ordinal(), accumulate );
221             Automate.setTransition( MainState.INIT.ordinal(), MainLabel.minusChar.ordinal(),
222                 MainState.MREV.ordinal(), accumulate );
223             Automate.setTransition( MainState.INIT.ordinal(), MainLabel.diese.ordinal(),
224                 MainState.COMMENT.ordinal(), accumulate );
225             Automate.setTransition( MainState.INIT.ordinal(), MainLabel.empty.ordinal(),
226                 MainState.FINAL_EMPTY.ordinal(), nothing );
227                 
228             // override defaut transitions to handle all "other" char with state "default" case
229             Automate.setState( MainState.QUOBEG.ordinal(), null, MainState.QUOBEG.ordinal(), accumulate );
230             Automate.setTransition( MainState.QUOBEG.ordinal(), MainLabel.quote.ordinal(),
231                 MainState.QUOEND.ordinal(), accumulate );                                  
232             Automate.setTransition( MainState.QUOBEG.ordinal(), MainLabel.empty.ordinal(),
233                 MainState.FINAL_LIBELLE.ordinal(), nothing );
234 
235             // override defaut transitions to handle all "other" char with state "default" case
236             Automate.setState( MainState.QUOEND.ordinal(), null, MainState.QUOBEG.ordinal(), accumulate );
237             Automate.setTransition( MainState.QUOEND.ordinal(), MainLabel.blank.ordinal(),
238                 MainState.FINAL_LIBELLE.ordinal(), drop );
239             Automate.setTransition( MainState.QUOEND.ordinal(), MainLabel.quote.ordinal(),
240                 MainState.QUOEND.ordinal(), accumulate );                               
241             Automate.setTransition( MainState.QUOEND.ordinal(), MainLabel.empty.ordinal(),
242                 MainState.FINAL_LIBELLE.ordinal(), nothing );
243                 
244             // override defaut transitions to handle all "other" char with state "default" case
245             Automate.setState( MainState.LEX.ordinal(), null, MainState.LEX.ordinal(), accumulate );                
246             Automate.setTransition( MainState.LEX.ordinal(), MainLabel.blank.ordinal(),
247                 MainState.FINAL_LIBELLE.ordinal(), drop );
248             Automate.setTransition( MainState.LEX.ordinal(), MainLabel.backSlack.ordinal(),
249                 MainState.LEXESC.ordinal(), accumulate );                                
250             Automate.setTransition( MainState.LEX.ordinal(), MainLabel.empty.ordinal(),
251                 MainState.FINAL_LIBELLE.ordinal(), nothing );
252 
253             // override defaut transitions to handle all "other" char with state "default" case
254             Automate.setState( MainState.LEXESC.ordinal(), null, MainState.LEX.ordinal(), accumulate );                 
255             Automate.setTransition( MainState.LEXESC.ordinal(), MainLabel.backSlack.ordinal(),
256                 MainState.LEXESC.ordinal(), accumulate );                                  
257             Automate.setTransition( MainState.LEXESC.ordinal(), MainLabel.empty.ordinal(),
258                 MainState.FINAL_LIBELLE.ordinal(), nothing );
259                 
260             // override defaut transitions to handle all "other" char with state "default" case
261             Automate.setState( MainState.MREV.ordinal(), null, MainState.LEX.ordinal(), accumulate );     
262             Automate.setTransition( MainState.MREV.ordinal(), MainLabel.rChar.ordinal(),
263                 MainState.REV.ordinal(), accumulate );
264             Automate.setTransition( MainState.MREV.ordinal(), MainLabel.blank.ordinal(),
265                 MainState.FINAL_LIBELLE.ordinal(), drop );
266             Automate.setTransition( MainState.MREV.ordinal(), MainLabel.empty.ordinal(),
267                 MainState.FINAL_LIBELLE.ordinal(), nothing );
268                 
269             // override defaut transitions to handle all "other" char with state "default" case
270             Automate.setState( MainState.REV.ordinal(), null, MainState.LEX.ordinal(), accumulate );     
271             Automate.setTransition( MainState.REV.ordinal(), MainLabel.digit.ordinal(),
272                 MainState.PREV.ordinal(), accumulate );
273             Automate.setTransition( MainState.REV.ordinal(), MainLabel.blank.ordinal(),
274                 MainState.FINAL_LIBELLE.ordinal(), drop );
275             Automate.setTransition( MainState.REV.ordinal(), MainLabel.empty.ordinal(),
276                 MainState.FINAL_LIBELLE.ordinal(), nothing );
277                 
278             // override defaut transitions to handle all "other" char with state "default" case
279             Automate.setState( MainState.PREV.ordinal(), null, MainState.LEX.ordinal(), accumulate );     
280             Automate.setTransition( MainState.PREV.ordinal(), MainLabel.digit.ordinal(),
281                 MainState.PREV.ordinal(), accumulate );
282             Automate.setTransition( MainState.PREV.ordinal(), MainLabel.blank.ordinal(),
283                 MainState.FINAL_REV.ordinal(), drop );
284             Automate.setTransition( MainState.PREV.ordinal(), MainLabel.empty.ordinal(),
285                 MainState.FINAL_REV.ordinal(), nothing );
286                 
287             // override defaut transitions to handle all "other" char with state "default" case
288             Automate.setState( MainState.COMMENT.ordinal(), null, MainState.COMMENT.ordinal(), accumulate );     
289             Automate.setTransition( MainState.COMMENT.ordinal(), MainLabel.empty.ordinal(),
290                 MainState.FINAL_COMMENT.ordinal(), nothing );
291                               
292             // not needed : empty is defaut token type
293             //Automate.setState( MainState.FINAL_EMPTY.ordinal(), tokenTypeEmpty);
294             Automate.setState( MainState.FINAL_LIBELLE.ordinal(), tokenTypeLibelle );
295             Automate.setState( MainState.FINAL_REV.ordinal(), tokenTypeRevision );
296             Automate.setState( MainState.FINAL_COMMENT.ordinal(), tokenTypeComment );
297         }
298         catch ( Exception e )
299         {
300             e.printStackTrace();
301         }
302     }
303 
304     private StringCharacterIterator iterator = null;
305     private Token currentToken = new Token();
306     
307     /**
308      * Default constructor enter in initial state executor is
309      * SvnExternalsTokenizer itself
310      * 
311      * @throws AutomateException
312      */
313     public SvnExternalsTokenizer( StringCharacterIterator iterator ) throws AutomateException
314     {
315         super( MainState.INIT.ordinal(), null );
316         this.iterator = iterator;
317     }
318      
319     public Token nextToken() throws AutomateException
320     {
321         Token ret = currentToken;
322         do
323         {
324             char current = iterator.current();
325             int etiquette = current == StringCharacterIterator.DONE ? MainLabel.empty.ordinal()
326                 : current == '-' ? MainLabel.minusChar.ordinal()
327                 : current == 'r' ? MainLabel.rChar.ordinal()
328                 : current == '\\' ? MainLabel.backSlack.ordinal()
329                 : current == '"' ? MainLabel.quote.ordinal()
330                 : current == '#' ? MainLabel.diese.ordinal()
331                 : Character.isWhitespace( current ) ? MainLabel.blank.ordinal()
332                 : Character.isDigit( current ) ? MainLabel.digit.ordinal()
333                 : MainLabel.other.ordinal();
334                     
335             //System.out.println("nextToken call event with : " + etiquette + "," + current);
336             event( etiquette, new Character( current ) ); //  iterator may change here !
337         }
338         while ( ! isInFinalState() );
339         
340         initializer( MainState.INIT.ordinal(), null );
341         currentToken = new Token();
342         
343         return ret;
344     }
345 
346     @Override
347     public String getName()
348     {
349         return "SvnExternalsTokenizer";
350     }
351 
352     /**
353      * @param s
354      * 
355      */
356     public void accumulate( final Object s )
357     {
358         if ( currentToken.value == null )
359         {
360             currentToken.value = new StringBuilder();
361         }
362         if ( currentToken.value instanceof StringBuilder )
363         {
364             //System.out.println("accumulate : " + iterator.current() );
365             ( (StringBuilder) currentToken.value ).append( iterator.current() );
366         }
367         char t = iterator.next();
368         //System.out.println("accumulate next is : " + iterator.current() );
369     }
370     
371     /**
372      * @param s
373      * 
374      */
375     public void drop( final Object s )
376     {
377         iterator.next();
378         //System.out.println("drop next is : " + iterator.current() );
379     }
380 
381     @Override
382     protected boolean isInFinalState()
383     {
384         return getCurrentState() == MainState.FINAL_LIBELLE.ordinal()
385                || getCurrentState() == MainState.FINAL_REV.ordinal()
386                || getCurrentState() == MainState.FINAL_EMPTY.ordinal()
387                || getCurrentState() == MainState.FINAL_COMMENT.ordinal();
388     }
389 
390     @Override
391     protected void notifyCurrentStateChanged()
392     {
393         //System.out.println("State changed to : " + MainState.fromOrdinal(getCurrentState()));
394     }
395 };