/tags/v-2007-08-21-b/src/il/ac/technion/cs/ssdl/parsing/Location.java

https://bitbucket.org/yossi_gil/services · Java · 201 lines · 110 code · 20 blank · 71 comment · 23 complexity · c2c929c74f9b761b62b83bd7a1190afc MD5 · raw file

  1. package il.ac.technion.cs.ssdl.parsing;
  2. import static il.ac.technion.cs.ssdl.utils.DBC.require;
  3. import il.ac.technion.cs.ssdl.utils.Position;
  4. import java.io.IOException;
  5. import java.io.Serializable;
  6. import java.util.List;
  7. /**
  8. * Desciption of a location in a source code. Contains the the beginning
  9. * position, the end position and a description of the source file.
  10. *
  11. * @author imaman
  12. */
  13. public class Location implements Serializable, Comparable<Location> {
  14. private final String sourceFileName;
  15. private final int sourceFileId;
  16. private static final long serialVersionUID = -2173713610989691041L;
  17. /**
  18. * Where does this location begin
  19. */
  20. public final Position begin;
  21. /**
  22. * Where does this location end
  23. */
  24. public final Position end;
  25. /**
  26. * True if this instance represents a synthetic location (that is a location
  27. * that was forced by the parser to represent a location in another source
  28. * file)
  29. */
  30. public final boolean synthetic;
  31. /**
  32. * The actual piece of source code that this object specifes
  33. */
  34. private final String fragment;
  35. /**
  36. * Where was this location defined
  37. *
  38. * @return The name of the source file object
  39. */
  40. public String enclosingFile() {
  41. return sourceFileName;
  42. }
  43. @Override public String toString() {
  44. return begin.toString() + (begin.equals(end) ? "" : ".." + end);
  45. }
  46. /**
  47. * Provide a short textual description of this location
  48. *
  49. * @return the string "Line NNN" where NNN is the line where this location
  50. * begins.
  51. * @see #toString()
  52. */
  53. public String where() {
  54. return "Line " + begin.line;
  55. }
  56. /**
  57. * Create a location from a {@link TokenInfo}
  58. *
  59. * @param inputResource
  60. * InputResource to which this locations belongs
  61. * @param t
  62. * a token with the positioning information to initialize the newly
  63. * created {@link Location}
  64. */
  65. public Location(InputResource inputResource, TokenInfo t) {
  66. this(inputResource, t.beginLine, t.beginColumn, t.endLine, t.endColumn, false);
  67. }
  68. public Location(InputResource ir, int beginLine, int beginColumn, int endLine, int endColumn) {
  69. this(ir, beginLine, beginColumn, endLine, endColumn, false);
  70. }
  71. /**
  72. * Create a new {@link Location} object
  73. *
  74. * @param inputResource
  75. * InputResource to which this locations belongs
  76. * @param beginLine
  77. * the line where this {@link Location} begins
  78. * @param beginColumn
  79. * the column where this {@link Location} begins
  80. * @param endLine
  81. * the line where this {@link Location} ends
  82. * @param endColumn
  83. * the columns where this {@link Location} begins
  84. * @param synthetic
  85. * Does this location represent a position in another source file?
  86. */
  87. public Location(InputResource inputResource, int beginLine, int beginColumn, int endLine, int endColumn, boolean synthetic) {
  88. require(inputResource != null);
  89. sourceFileName = inputResource.name();
  90. sourceFileId = inputResource.id();
  91. require(endLine > beginLine || endColumn >= beginColumn);
  92. begin = new Position(beginLine, beginColumn);
  93. end = new Position(endLine, endColumn);
  94. this.synthetic = synthetic;
  95. this.fragment = computeFragment(inputResource);
  96. }
  97. /**
  98. * Create a {@link Location} from its begin and end {@link Position}s
  99. *
  100. * @param inputResource
  101. * InputResource to which this locations belongs
  102. * @param begin
  103. * where does this {@link Location} begin
  104. * @param end
  105. * where does this {@link Location} end
  106. */
  107. public Location(InputResource inputResource, Position begin, Position end) {
  108. require(!end.before(begin));
  109. require(inputResource != null);
  110. sourceFileName = inputResource.name();
  111. sourceFileId = inputResource.id();
  112. this.begin = begin;
  113. this.end = end;
  114. this.synthetic = false;
  115. this.fragment = computeFragment(inputResource);
  116. }
  117. private Location(int sourceFileId, String sourceFileName, Position b, Position e, boolean synthetic, String fragment) {
  118. this(sourceFileId, sourceFileName, b.line, b.column, e.line, e.column, synthetic, fragment);
  119. }
  120. private Location(int sourceFileId, String sourceFileName, int bl, int bc, int el, int ec, boolean synthetic, String fragment) {
  121. this.sourceFileId = sourceFileId;
  122. this.sourceFileName = sourceFileName;
  123. this.begin = new Position(bl, bc);
  124. this.end = new Position(el, ec);
  125. this.synthetic = synthetic;
  126. this.fragment = fragment;
  127. }
  128. private String computeFragment(InputResource ir) {
  129. try {
  130. List<String> lines = ir.lines();
  131. StringBuilder sb = new StringBuilder(100);
  132. for (int i = this.begin.line; i <= this.end.line; ++i)
  133. sb.append(lines.get(i - 1));
  134. return sb.toString();
  135. } catch (IOException e) {
  136. throw new RuntimeException(e);
  137. }
  138. }
  139. public boolean startsBefore(Location other) {
  140. return begin.before(other.begin);
  141. }
  142. public boolean endsBefore(Location other) {
  143. return end.before(other.end);
  144. }
  145. public boolean contained(Location other) {
  146. if (other == null)
  147. return false;
  148. return !startsBefore(other) && !other.endsBefore(this);
  149. }
  150. public Location merge(Location other) {
  151. require(other == null || this.sourceFileId == other.sourceFileId);
  152. if (other == null)
  153. return this;
  154. return new Location(sourceFileId, sourceFileName, startsBefore(other) ? begin : other.begin, endsBefore(other) ? other.end : end,
  155. this.synthetic || other.synthetic, startsBefore(other) ? fragment : other.fragment);
  156. }
  157. public int compareTo(Location other) {
  158. int diff = this.sourceFileId - other.sourceFileId;
  159. if (diff != 0)
  160. return diff;
  161. return begin.compareTo(other.begin);
  162. }
  163. @Override public int hashCode() {
  164. return begin.hashCode() ^ end.hashCode();
  165. }
  166. @Override public boolean equals(Object o) {
  167. if (this == o)
  168. return true;
  169. if (o == null || !getClass().equals(o.getClass()))
  170. return false;
  171. Location that = (Location) o;
  172. return (sourceFileId == that.sourceFileId) && begin.equals(that.begin) && end.equals(that.end);
  173. }
  174. // public Location shiftLines(int delta) {
  175. // return new Location(sourceFileId, sourceFileName, begin.line + delta,
  176. // begin.column, end.line + delta, end.column, this.synthetic);
  177. // }
  178. public String getSourceCode() {
  179. return fragment;
  180. }
  181. }