/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package edu.mit.csail.sdg.alloy4; import java.io.Serializable; /** Immutable; stores the filename and line/column position. * * <p> <b>Invariant:</b> filename!=null && x>0 && y>0 && ((y2>y && x2>0) || (y2==y && x2>=x)) * * <p><b>Thread Safety:</b> Safe (since objects of this class are immutable). */ public final class Pos implements Serializable { /** To make sure the serialization form is stable. */ private static final long serialVersionUID = 0; /** The filename (it can be an empty string if unknown) */ public final String filename; /** The starting column position (from 1..) */ public final int x; /** The starting row position (from 1..) */ public final int y; /** The ending column position (from 1..) */ public final int x2; /** The ending row position (from 1..) */ public final int y2; /** The default "unknown" location. */ public static final Pos UNKNOWN = new Pos("",1,1); /** Constructs a new Pos object. * @param filename - the filename (it can be an empty string if unknown) * @param x - the column position (from 1..) * @param y - the row position (from 1..) */ public Pos(String filename, int x, int y) { this.filename = (filename==null ? "" : filename); this.x = (x>0 ? x : 1); this.y = (y>0 ? y : 1); this.x2 = this.x; this.y2 = this.y; } /** Constructs a new Pos object. * @param filename - the filename (it can be an empty string if unknown) * @param x - the starting column position (from 1..) * @param y - the starting row position (from 1..) * @param x2 - the ending column position (from 1..) * @param y2 - the ending row position (from 1..) */ public Pos(String filename, int x, int y, int x2, int y2) { this.filename = (filename==null ? "" : filename); this.x = (x>0 ? x : 1); this.y = (y>0 ? y : 1); if (y2<(this.y)) y2=this.y; if (y2==this.y) { if (x2<(this.x)) x2=this.x; } else { if (x2<1) x2=1; } this.x2 = x2; this.y2 = y2; } /** Return a new position that merges this and that (it is assumed that the two Pos objects have same filename) * @param that - the other position object */ public Pos merge(Pos that) { if (that==null || that==UNKNOWN || that==this) return this; if (this==UNKNOWN) return that; int x=this.x, y=this.y, x2=that.x2, y2=that.y2; if (that.y<y || (that.y==y && that.x<x)) { x=that.x; y=that.y; } if (this.y2>y2 || (this.y2==y2 && this.x2>x2)) { x2=this.x2; y2=this.y2; } if (x==this.x && y==this.y && x2==this.x2 && y2==this.y2) return this; // avoid creating unnecessary new object if (x==that.x && y==that.y && x2==that.x2 && y2==that.y2) return that; // avoid creating unnecessary new object return new Pos(filename, x, y, x2, y2); } /** Returns true if neither argument is null nor UNKNOWN, * and that the ending position of "a" is before the starting position of "b". */ public static boolean before(Pos a, Pos b) { if (a==null || a==Pos.UNKNOWN || b==null || b==Pos.UNKNOWN || !a.filename.equals(b.filename)) return false; return a.y2<b.y || (a.y2==b.y && a.x2<b.x); } /** Two Pos objects are equal if the filename x y x2 y2 are the same. */ @Override public boolean equals(Object other) { if (this==other) return true; if (!(other instanceof Pos)) return false; Pos that = (Pos) other; return x==that.x && y==that.y && x2==that.x2 && y2==that.y2 && filename.equals(that.filename); } /** Returns a hash code consistent with equals() */ @Override public int hashCode() { return x*111 + y*171 + x2*1731 + y2*2117; } /** Returns a short String representation of this position value. */ public String toShortString() { String f=filename; int a=f.lastIndexOf('/'), b=f.lastIndexOf('\\'); if (a<b) a=b; if (a>=0) f=f.substring(a+1); if (f.length()==0) return "line "+y+", column "+x; else return "line "+y+", column "+x+", filename="+f; } /** Returns a String representation of this position value. */ @Override public String toString() { if (filename.length()==0) return "line "+y+", column "+x; else return "line "+y+", column "+x+", filename="+filename; } }