001 /*
002 * Copyright (c) 2005 Peter Palotas, Fredrik Johansson, Einar Pehrson,
003 * Sebastian Kekkonen, Lars Magnus Lång, Malin Johansson and Sofia Nilsson
004 *
005 * This file is part of
006 * CleanSheets Extension for Assertions
007 *
008 * CleanSheets Extension for Assertions is free software; you can
009 * redistribute it and/or modify it under the terms of the GNU General Public
010 * License as published by the Free Software Foundation; either version 2 of
011 * the License, or (at your option) any later version.
012 *
013 * CleanSheets Extension for Assertions is distributed in the hope that
014 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
015 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with CleanSheets Extension for Assertions; if not, write to the
020 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
021 * Boston, MA 02111-1307 USA
022 */
023 package csheets.ext.assertion;
024
025 import java.io.StringReader;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.ListIterator;
029 import java.util.Vector;
030
031 /**
032 * This class represents an Assertion.
033 * @author Fredrik Johansson
034 * @author Peter Palotas
035 */
036 public class USAssertion extends Assertion {
037
038 /** The unique version identifier used for serialization */
039 private static final long serialVersionUID = -7911803174007268562L;
040
041 /** The original assertion string as entered by the user. */
042 protected String assertion;
043
044 /** A list of warnings or inconsitencies in the current assertion */
045 private List<AssertionWarning> warnings = new Vector<AssertionWarning>();
046
047
048 /**
049 * Constructs an Assertion object
050 * @param assertion is a string representation of an assertion
051 * @throws AssertionException is thrown if a syntactic or semantic error occurs
052 */
053 public USAssertion(String assertion) throws AssertionException {
054
055 List<Interval> orIntervals = new Vector<Interval>();
056 List<Interval> exceptIntervals = new Vector<Interval>();
057
058 AssertionLexer lexer = new AssertionLexer(new StringReader(assertion));
059 AssertionParser parser = new AssertionParser(lexer);
060
061 try {
062 parser.assertion(this, orIntervals, exceptIntervals);
063 } catch (antlr.MismatchedCharException mce) {
064 throw new AssertionException(mce);
065 } catch (antlr.MismatchedTokenException mte) {
066 throw new AssertionException(mte);
067 } catch (antlr.NoViableAltException nvae) {
068 throw new AssertionException(nvae);
069 } catch (antlr.NoViableAltForCharException nvafce) {
070 throw new AssertionException(nvafce);
071 } catch (antlr.SemanticException se) {
072 throw new AssertionException(se);
073 } catch (antlr.RecognitionException re) {
074 throw new AssertionException(re);
075 } catch (antlr.TokenStreamException tse) {
076 throw new AssertionException(tse);
077 }
078
079 this.assertion = assertion;
080
081 // To do: Make the inconsistency checks more efficient and add more conditions to check for.
082
083 // Check the consistency of the assertion, and create warnings for
084 // suspected inconsistencies.
085
086 // Check for intersections between or-intervals
087 for (ListIterator<Interval> it1 = orIntervals.listIterator(); it1.hasNext(); ) {
088 Interval i1 = it1.next();
089 for (ListIterator<Interval> it2 = orIntervals.listIterator(it1.nextIndex()); it2.hasNext(); ) {
090 Interval i2 = it2.next();
091 if (i1.intersects(i2)) {
092 // Check if either interval completely encloses the other.
093 if (i1.encloses(i2))
094 warnings.add(new AssertionWarning(AssertionWarning.Type.ENCLOSING, i2, i1));
095 else if (i2.encloses(i1))
096 warnings.add(new AssertionWarning(AssertionWarning.Type.ENCLOSING, i1, i2));
097 else
098 warnings.add(new AssertionWarning(AssertionWarning.Type.INTERSECTING, i1, i2));
099 }
100 }
101 }
102
103 // Check for intersections between exclusion intervals
104 for (ListIterator<Interval> it1 = exceptIntervals.listIterator(); it1.hasNext(); ) {
105 Interval i1 = it1.next();
106 for (ListIterator<Interval> it2 = exceptIntervals.listIterator(it1.nextIndex()); it2.hasNext(); ) {
107 Interval i2 = it2.next();
108 if (i1.intersects(i2)) {
109 // Check if either interval completely encloses the other.
110 if (i1.encloses(i2))
111 warnings.add(new AssertionWarning(AssertionWarning.Type.ENCLOSING, i2, i1));
112 else if (i2.encloses(i1))
113 warnings.add(new AssertionWarning(AssertionWarning.Type.ENCLOSING, i1, i2));
114 else
115 warnings.add(new AssertionWarning(AssertionWarning.Type.INTERSECTING, i1, i2));
116 }
117 }
118 }
119
120 // Check for complete exclusions of intervals and exclusions of nothing.
121 for (ListIterator<Interval> it1 = exceptIntervals.listIterator(); it1.hasNext(); ) {
122 Interval i1 = it1.next();
123 for (ListIterator<Interval> it2 = orIntervals.listIterator(); it2.hasNext(); ) {
124 Interval i2 = it2.next();
125 if (i1.encloses(i2))
126 warnings.add(new AssertionWarning(AssertionWarning.Type.EXCLUDING, i1, i2));
127 }
128 }
129
130 // Build the MultiInterval
131 for (Interval io : orIntervals) {
132 intervals.include(io);
133 }
134
135 for (Interval ie : exceptIntervals) {
136 intervals.exclude(ie);
137 }
138
139 // Special case if only "integer" was specified as an assertion
140 if (isInteger && orIntervals.isEmpty() && exceptIntervals.isEmpty()) {
141 intervals.include(new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false));
142 }
143 }
144
145 /**
146 * Indicates wether the assertion is consistent or wether it may contain
147 * some inconsistencies. If there are inconsistecies the details can be
148 * retrieved by calling <code>getWarnings()</code>.
149 * @return <code>true</code> if there are no inconsitencies, <code>false</code> otherwise.
150 */
151 public boolean isConsistent() {
152 return warnings.isEmpty();
153 }
154
155 /**
156 * Retrieves the warnings associated with this assertion describing possible
157 * inconsitencies in the assertion.
158 * @return a <code>List</code> of <code>AssertionWarning</code> objects describing any
159 * warnings/inconsistencies in the assertion represented by this object. This <code>List</code>
160 * will be non-empty if <code>isConsistent()</code> returns <code>false</code>, and empty otherwise.
161 */
162 public List<AssertionWarning> getWarnings() {
163 return warnings;
164 }
165
166 /**
167 * @return the String representation of the assertion as specified in the
168 * constructor.
169 */
170 public String toString() {
171 return assertion;
172 }
173
174
175
176 /** Used for "pretty printing" an assertion. The assertion string
177 is re-constructed from the parsed data.
178 @return a pretty printed version of the assertion.
179 */
180 public String prettyString()
181 {
182 return super.toString();
183 }
184
185 /** Used to print all warnings that were generated while parsing the assertion.
186 Used only for debugging purposes.
187 @deprecated printWarnings
188 */
189 public void printWarnings()
190 {
191 List w = getWarnings();
192 Iterator i = w.iterator();
193 System.out.println("\nWarnings for: " + toString());
194 for ( ; i.hasNext() ;)
195 {
196 AssertionWarning aw = (AssertionWarning)i.next();
197 System.out.println(aw.toString());
198 }
199 }
200 }