001/* 002 * Copyright (c) 2005 Peter Palotas, Fredrik Johansson, Einar Pehrson, 003 * Sebastian Kekkonen, Lars Magnus Lang, 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 */ 023package csheets.ext.assertion; 024 025import java.io.StringReader; 026import java.util.Iterator; 027import java.util.List; 028import java.util.ListIterator; 029import java.util.Vector; 030 031/** 032 * This class represents an Assertion. 033 * @author Fredrik Johansson 034 * @author Peter Palotas 035 */ 036public 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}