View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2005 Open World Ltd
4   //
5   // This file is part of MillScript.
6   //
7   // MillScript is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
20  ////////////////////////////////////////////////////////////////////////////////
21  package org.millscript.millscript.functions;
22  
23  import org.millscript.commons.util.list.IDynamicList;
24  import org.millscript.commons.util.list.IEmptyList;
25  import org.millscript.commons.util.list.IDynamicList.ListEntry;
26  import org.millscript.millscript.datatypes.Binding;
27  import org.millscript.millscript.tools.CastLibrary;
28  
29  import java.util.regex.Matcher;
30  
31  /**
32   * This class implements the MillScript <code>findSuccessiveMatches</code>
33   * function.
34   */
35  public final class FindSuccessiveMatchesFunction extends BinaryFunction {
36  
37      /**
38       * This class implements a dynamic list entry for a binding list.
39       */
40      private static final class BindingListEntry extends IDynamicList.ListEntry< Binding > {
41  
42          /**
43           * This is the ID from the release 10.2.0 for future compatibility.
44           */
45          private static final long serialVersionUID = -5309136978073166788L;
46  
47          /**
48           * The matcher used to construct this binding.
49           */
50          private Matcher matcher;
51  
52          /**
53           * The original string the regular expression was matched against.
54           */
55          private final String originalString;
56  
57          /**
58           * Constructs a new binding list entry for the specified binding, which
59           * will use the specified matcher and string for calculating successive
60           * bindings.
61           *
62           * @param m the matcher to find successive bindings from
63           * @param s the original string that was matched against
64           * @param val   the binding for this entry in the list
65           */
66          public BindingListEntry( final Matcher m, final String s, final Binding val ) {
67              super( val );
68              this.matcher = m;
69              this.originalString = s;
70          }
71  
72          /**
73           * @see org.millscript.commons.util.list.IDynamicList.ListEntry#calculateNext()
74           */
75          @Override
76          public ListEntry< Binding > calculateNext() {
77              // There is no next element, so we must try and find one
78              if ( matcher != null ) {
79                  if ( matcher.find() ) {
80                      // Set the next element, with this element as it's previous
81                      return new BindingListEntry(
82                          this.matcher,
83                          this.originalString,
84                          Binding.newBinding( originalString, matcher )
85                      );
86                  } else {
87                      // We have to remove the matcher as the find() method
88                      // doesn't work as expected. If you call it several times
89                      // until it returns false, it seems to reset automatically
90                      // and subsequent calls will start from the begining. 
91                      matcher = null;
92                  }
93              }
94              return null;
95          }
96  
97      }
98  
99      /**
100      * @see org.millscript.millscript.functions.BinaryFunction#apply2(java.lang.Object, java.lang.Object)
101      */
102     @Override
103     public Object apply2( final Object a1, final Object a2 ) {
104         // Get the string we want to match the regex against
105         final String input = CastLibrary.toString( a2 );
106         // Get the compiled regex and create a matcher to match the regex
107         // against the input and push the result
108         final Matcher matcher = CastLibrary.toPattern( a1 ).matcher( input );
109         // Are there any matches?
110         if ( matcher.find() ) {
111             // There is at least one match, so make a binding list from this
112             // matcher
113             return new IDynamicList< Binding >(
114                 new BindingListEntry(
115                     matcher,
116                     input,
117                     Binding.newBinding( input, matcher )
118                 )
119             );
120         } else {
121             // No matches so we return an empty list
122             return IEmptyList.EMPTY_LIST;
123         }
124     }
125 
126 }