All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.css.SourceCodeLocation Maven / Gradle / Ivy

Go to download

Closure Stylesheets is an extension to CSS that adds variables, functions, conditionals, and mixins to standard CSS. The tool also supports minification, linting, RTL flipping, and CSS class renaming.

There is a newer version: 20160212
Show newest version
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.css;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Ints;

import javax.annotation.Nullable;

/**
 * A location in source code. A location is a sequence of adjacent characters
 * that usually represent a token or a larger language construct.
 *
 * 

Error messages represent the most common use of this class, as an error * message usually relates to a source code location. The location related to * some messages might not be known; this class has a special value that * represents an "unknown" location. * *

Character sequences this class points to can have 0 length. If that is the * case, the actual location is that "point" between two source code characters. * This usually means that something happens from that point onwards, or that an * error has been detected at that point but there is no information regarding * the actual token that caused the error. * *

Instances of this class are immutable. * */ public class SourceCodeLocation implements Comparable { /** * This describes a point in a string. A point is the location between two * characters and is indicated by the character index of the immediately * following character. For example, in the string "abc", point 0 refers to * the location immediately before the 'a' and point 2 to the location before * the 'c'. * *

For convenience we also store the line number of the point (the line * that contains the character following the point) and the index in that * line. Both of these indices start at 1. The first line of a file is line 1 * and the point before its first character has index 1 on line 1. * *

The exact definition of lines depends on the language conventions and is * best left for the parser to handle. If you want to display the text at that * location, either use the character index or use the line number and the * index in the line together with lines as they were split by the parser. * *

It might happen that the source code point for something is not known. * This is modeled by a point with the special value -1 for the character * index. The line and the index on the line must be 0 in this case. * *

Instances of this class are immutable. */ @VisibleForTesting public static class SourceCodePoint implements Comparable { /** * The index of the character immediately after the source code point. * Indices start at 0; -1 means the location is not known. */ private final int characterIndex; /** * The number of the line that contains the character at characterIndex. * Numbers start at 1; 0 means the location is not known. */ private final int lineNumber; /** * The index in the line identified by lineNumber of the character at * characterIndex. Numbers start at 1; 0 means the location is not known. */ private final int indexInLine; SourceCodePoint(int characterIndex, int lineNumber, int indexInLine) { this.lineNumber = lineNumber; this.indexInLine = indexInLine; this.characterIndex = characterIndex; if (!hasValidKnownCoordinates() && !hasValidUnknownCoordinates()) { throw new IllegalArgumentException( String.format( "The location passed " + "(lineNumber %d, indexInLine %d, characterIndex %d) " + "is not valid.", lineNumber, indexInLine, characterIndex)); } if (!hasPlausibleCoordinates()) { throw new IllegalArgumentException( String.format( "The location passed " + "(lineNumber %d, indexInLine %d, characterIndex %d) " + "is not plausible.", lineNumber, indexInLine, characterIndex)); } } SourceCodePoint(SourceCodePoint that) { this(that.characterIndex, that.lineNumber, that.indexInLine); } boolean hasValidKnownCoordinates() { return lineNumber >= 1 && indexInLine >= 1 && characterIndex >= 0; } boolean hasValidUnknownCoordinates() { return characterIndex == -1 && lineNumber == 0 && indexInLine == 0; } boolean hasPlausibleCoordinates() { return characterIndex >= lineNumber - 1 + indexInLine - 1; } int getCharacterIndex() { return characterIndex; } int getLineNumber() { return lineNumber; } int getIndexInLine() { return indexInLine; } boolean isUnknown() { return characterIndex == -1; } @Override public boolean equals(@Nullable Object o) { if (o == null) { return false; } if (!(o instanceof SourceCodePoint)) { return false; } SourceCodePoint other = (SourceCodePoint) o; boolean areEqual = this.characterIndex == other.characterIndex; if (areEqual) { Preconditions.checkState((this.lineNumber == other.lineNumber) && (this.indexInLine == other.indexInLine), "Character indexes are equal but line numbers and indexes within " + "the line do not match."); } else { Preconditions.checkState((this.lineNumber != other.lineNumber) || (this.indexInLine != other.indexInLine), "Line numbers and indexes within the line match but character " + "indexes are not equal"); } return areEqual; } @Override public int hashCode() { return characterIndex; } @Override public int compareTo(SourceCodePoint o) { Preconditions.checkNotNull(o); return Ints.compare(this.characterIndex, o.characterIndex); } } private static final SourceCode UNKNOWN_SOURCE_CODE = new SourceCode("unknown", ""); /** * Returns an unknown location. */ public static SourceCodeLocation getUnknownLocation() { SourceCodeLocation result = new SourceCodeLocation( UNKNOWN_SOURCE_CODE, -1 /* beginCharacterIndex */, 0 /* beginLineNumber */, 0 /* beginIndexInLine */, -1 /* endCharacterindex */, 0 /* endLineNumber */, 0 /* endIndexInLine */); Preconditions.checkState(result.isUnknown()); Preconditions.checkState(result.begin.hasValidUnknownCoordinates()); Preconditions.checkState(result.end.hasValidUnknownCoordinates()); return result; } private final SourceCode sourceCode; /** * The sequence starts at the character immediately following the begin point. */ private final SourceCodePoint begin; /** * The sequence ends at the character immediately before the end point. The * character immediately after the end point (the one indicated by the end's * {@link SourceCodePoint#characterIndex}) is not part of the sequence. The * empty sequence's begin point and end point are the same: * {@code begin.equals(end)}. */ private final SourceCodePoint end; @VisibleForTesting public SourceCodeLocation(SourceCode sourceCode, int beginCharacterIndex, int beginLineNumber, int beginIndexInLine, int endCharacterIndex, int endLineNumber, int endIndexInLine) { Preconditions.checkNotNull(sourceCode); this.sourceCode = sourceCode; this.begin = new SourceCodePoint(beginCharacterIndex, beginLineNumber, beginIndexInLine); this.end = new SourceCodePoint(endCharacterIndex, endLineNumber, endIndexInLine); Preconditions.checkArgument(begin.compareTo(end) <= 0, "Beginning location must come before the end location."); } public SourceCode getSourceCode() { return sourceCode; } public boolean isUnknown() { Preconditions.checkState(begin.isUnknown() == end.isUnknown()); return begin.isUnknown(); } public int getBeginCharacterIndex() { return begin.getCharacterIndex(); } public int getBeginLineNumber() { return begin.getLineNumber(); } public int getBeginIndexInLine() { return begin.getIndexInLine(); } public int getEndCharacterIndex() { return end.getCharacterIndex(); } public int getEndLineNumber() { return end.getLineNumber(); } public int getEndIndexInLine() { return end.getIndexInLine(); } public int getCharacterIndex() { return getBeginCharacterIndex(); } public int getLineNumber() { return getBeginLineNumber(); } public int getIndexInLine() { return getBeginIndexInLine(); } public SourceCodePoint getBegin() { return begin; } public SourceCodePoint getEnd() { return end; } @Override public boolean equals(@Nullable Object o) { if (o == null) { return false; } if (!(o instanceof SourceCodeLocation)) { return false; } SourceCodeLocation other = (SourceCodeLocation) o; return sourceCode == other.sourceCode && begin.equals(other.begin) && end.equals(other.end); } @Override public int hashCode() { return sourceCode.hashCode() ^ begin.hashCode() ^ (end.hashCode() << 16); } /** * Comparison and ordering of locations for source code in different * input files is supported because we don't always preserve * locations during AST mutations and yet we still want to be able * to sort error reports, doing the best job we can for the errors * that have known locations. For the semantics of this method, see * {@link Comparable#compareTo(Object)}. */ @Override public int compareTo(SourceCodeLocation o) { Preconditions.checkNotNull(o); if (sourceCode != o.sourceCode) { if (sourceCode == null) { return -1; } else if (o.sourceCode == null) { return 1; } else { return sourceCode.hashCode() - o.sourceCode.hashCode(); } } int startPointsComparison = begin.compareTo(o.begin); if (startPointsComparison != 0) { return startPointsComparison; } return end.compareTo(o.end); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy