blob: 88998b7b9640c6503cded053798b88f99e15d903 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.flex.compiler.common;
import org.apache.flex.utils.FilenameNormalization;
/**
* Common class to store file/location information across all source types
* such as AS, CSS etc
*/
public class SourceLocation implements ISourceLocation
{
/**
* Constructor for a known source location.
*/
public SourceLocation(String sourcePath, int start, int end, int line, int column)
{
this.sourcePath = sourcePath;
this.start = start;
this.end = end;
this.line = line;
this.column = column;
}
/**
* Copy Constructor for a known source location.
*/
public SourceLocation(ISourceLocation location)
{
this(location.getSourcePath(),
location.getStart(),
location.getEnd(),
location.getLine(),
location.getColumn());
}
/**
* Constructor for an unknown source location.
*/
public SourceLocation()
{
this(null, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN);
}
/**
* Source path.
*/
private String sourcePath;
/**
* Zero-based starting offset.
* <p>
* This class does not distinguish between local and absolute offsets,
* but subclasses may. If so, they should store the absolute starting
* offset in this field and use it to compute the local starting offset.
*/
private int start;
/**
* Zero-based ending offset.
* <p>
* This class does not distinguish between local and absolute offsets,
* but subclasses may. If so, they should store the absolute ending
* offset in this field and use it to compute the local ending offset.
*/
private int end;
/**
* Zero-based line number.
* Corresponds to start, not end.
*/
private int line;
/**
* Zero-based column number.
* Corresponds to start, not end.
*/
private int column;
/**
* Copies source location information from another instance
* into this instance.
*/
public final void setSourceLocation(ISourceLocation src)
{
assert src != null : "source location can't be null";
this.start = src.getStart();
this.end = src.getEnd();
this.line = src.getLine();
this.column = src.getColumn();
this.sourcePath = src.getSourcePath();
}
/**
* @return The local start offset
*/
@Override
public int getStart()
{
assert start >= 0 || start == UNKNOWN : "Invalid value for start: " + start;
return start;
}
/**
* @return The absolute start offset.
*/
@Override
public int getAbsoluteStart()
{
assert start >= 0 || start == UNKNOWN : "Invalid value for start: " + start;
return start;
}
/**
* @return The absolute end offset.
*/
@Override
public int getAbsoluteEnd()
{
assert end >= 0 || end == UNKNOWN : "Invalid value for end: " + end;
return end;
}
/**
* Set the absolute offset where this node starts.
*/
public void setStart(int start)
{
if (start != UNKNOWN)
this.start = start;
}
/**
* @return The local end offset.
*/
@Override
public int getEnd()
{
assert end >= 0 || end == UNKNOWN : "Invalid value for end: " + end;
return end;
}
/**
* Set the absolute offset where this node ends.
*/
public void setEnd(int end)
{
if (end != UNKNOWN)
this.end = end;
}
/**
* Get the line number where this node starts.
* Line numbers start at 0, not 1.
* @return The line number
*/
@Override
public int getLine()
{
assert line >= 0 || line == UNKNOWN : "Invalid value for line: " + line;
return line;
}
/**
* Set the line number where this node starts.
* Column numbers start at 0, not 1.
* @param line The line number
*/
public void setLine(int line)
{
if (line != UNKNOWN)
this.line = line;
}
/**
* Get the column number where this node starts.
* @return The column number
*/
@Override
public int getColumn()
{
assert column >= 0 || column == UNKNOWN : "Invalid value for column: " + column;
return column;
}
/**
* Set the column number where this node starts.
* @param column The column number
*/
public void setColumn(int column)
{
if (column != UNKNOWN)
this.column = column;
}
/**
* Get the source path for this node.
* @return The source path for this node
*/
@Override
public final String getSourcePath()
{
// null means the source is unknown.
// "" means the source is a buffer that hasn't yet been saved to a file.
// Something like "framework.swc:defaults.css" means the source is a file inside a SWC.
// TODO Shouldn't the part before the colon be normalized?
// Anything else should be a normalized path to a source file.
assert sourcePath == null ||
sourcePath.isEmpty() ||
sourcePath.contains(".swc:") ||
FilenameNormalization.isNormalized(sourcePath) :
"Invalid value for sourcePath: " + sourcePath;
return sourcePath;
}
/**
* Set the source path of the node.
* @param sourcePath The source path
*/
public final void setSourcePath(String sourcePath)
{
this.sourcePath = sourcePath;
}
/**
* Displays line, column, start, end, and sourcepath in a format such as
* <pre>
* "17:5 160-188 C:\test.as"
* </pre>
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getLineColumnString());
sb.append(getOffsetsString());
sb.append(getSourcePathString());
return sb.toString();
}
/**
* Displays Line and Column numbers
*/
protected String getLineColumnString()
{
StringBuilder sb = new StringBuilder();
int line = getLine();
if (line != UNKNOWN)
sb.append(line);
else
sb.append('?');
sb.append(':');
int column = getColumn();
if (column != UNKNOWN)
sb.append(column);
else
sb.append('?');
sb.append(' ');
return sb.toString();
}
/**
* Displays sourcepath
*
*/
protected String getSourcePathString()
{
StringBuilder sb = new StringBuilder();
sb.append(' ');
String sourcePath = getSourcePath();
if (sourcePath != null)
sb.append(sourcePath);
else
sb.append('?');
return sb.toString();
}
/**
* Displays line, column, start, end
*
*/
protected String getOffsetsString()
{
StringBuilder sb = new StringBuilder();
sb.append("loc: ");
int start = getStart();
if (start != UNKNOWN)
sb.append(start);
else
sb.append('?');
sb.append('-');
int end = getEnd();
if (end != UNKNOWN)
sb.append(end);
else
sb.append('?');
sb.append(' ');
sb.append("abs: ");
int absoluteStart = getAbsoluteStart();
if (absoluteStart != UNKNOWN)
sb.append(absoluteStart);
else
sb.append('?');
sb.append('-');
int absoluteEnd = getAbsoluteEnd();
if (absoluteEnd != UNKNOWN)
sb.append(absoluteEnd);
else
sb.append('?');
return sb.toString();
}
/**
* Span the location range from {@code start} to {@code end}.
*
* @param start Start location.
* @param end End location.
*/
public final void span(ISourceLocation start, ISourceLocation end)
{
setSourcePath(start.getSourcePath());
setStart(start.getStart());
setEnd(end.getEnd());
setLine(start.getLine());
setColumn(start.getColumn());
}
/**
* Span the location range from {@code start} to {@code end}.
*
* @param location The location
*/
public final void span(ISourceLocation location)
{
if (location != null)
setSourceLocation(location);
}
}