net.intelie.pipes.ast.SourceLocation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pipes-api Show documentation
Show all versions of pipes-api Show documentation
Intelie Pipes' API classes and interfaces
package net.intelie.pipes.ast;
import net.intelie.pipes.PipeCompiler;
import net.intelie.pipes.util.Preconditions;
import java.io.Serializable;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Function;
public class SourceLocation implements Serializable {
private static final long serialVersionUID = 1L;
private final Type type;
private final String fullCode;
private final int position;
private final int length;
private final int beginLine;
private final int beginColumn;
private final int endLine;
private final int endColumn;
public SourceLocation(int line, int column) {
this("", 0, line, column);
}
public SourceLocation(String fullCode, int position, int line, int column) {
this(Type.NONE, fullCode, position, 0, line, column, line, column);
}
public SourceLocation(SourceLocation begin, SourceLocation end) {
this(begin.type,
assertSameFullCode(begin, end),
begin.position, end.position - begin.position,
begin.beginLine, begin.beginColumn,
end.endLine, end.endColumn);
}
@SuppressWarnings("StringEquality")
private static String assertSameFullCode(SourceLocation begin, SourceLocation end) {
Preconditions.checkArgument(begin.fullCode == end.fullCode,
"SourceLocations must have exactly same instance of full code");
return begin.fullCode != null ? begin.fullCode : end.fullCode;
}
private SourceLocation(Type type, String fullCode, int position, int length,
int beginLine, int beginColumn, int endLine, int endColumn) {
Preconditions.checkArgument(fullCode != null,
"must have full code reference");
if (length > 0) {
Preconditions.checkPositionIndex(position, fullCode.length(),
"position must be inside full code");
Preconditions.checkPositionIndex(position + length, fullCode.length(),
"position end must be inside full code");
}
this.type = type;
this.fullCode = fullCode;
this.position = position;
this.length = length;
this.beginLine = beginLine;
this.beginColumn = beginColumn;
this.endLine = endLine;
this.endColumn = endColumn;
}
public String getCode() {
if (fullCode == null) return null;
if (length == 0) return "";
return fullCode.substring(position, position + length);
}
public SourceLocation subLocation(Type type, int start, int end) {
Preconditions.checkArgument(0 <= start && start <= end && end <= length,
"invalid bounds, [%s, %s] (len=%s)", start, end, length);
return new SourceLocation(type, fullCode, position + start, end - start,
beginLine, beginColumn + start,
beginLine, beginColumn + Math.max(start, end - 1));
}
public SourceLocation begin() {
return new SourceLocation(Type.NONE, fullCode, position, 0, beginLine, beginColumn, beginLine, beginColumn);
}
public SourceLocation end() {
return new SourceLocation(Type.NONE, fullCode, position + Math.max(0, length - 1), 0, endLine, endColumn, endLine, endColumn);
}
public int getPosition() {
return position;
}
public int getLength() {
return length;
}
public int getBeginLine() {
return beginLine;
}
public int getBeginColumn() {
return beginColumn;
}
public int getEndLine() {
return endLine;
}
public int getEndColumn() {
return endColumn;
}
public Type getType() {
return type;
}
@Override
public String toString() {
if (length == 0)
return String.format((Locale) null, "%d, %d", beginLine, beginColumn);
else
return String.format((Locale) null, "%d, %d->%d, %d", beginLine, beginColumn, endLine, endColumn);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SourceLocation that = (SourceLocation) o;
return position == that.position &&
length == that.length &&
beginLine == that.beginLine &&
beginColumn == that.beginColumn &&
endLine == that.endLine &&
endColumn == that.endColumn &&
type == that.type;
}
@Override
public int hashCode() {
return Objects.hash(position, length, beginLine, beginColumn, endLine, endColumn, type);
}
public SourceLocation withType(Type type) {
return new SourceLocation(type, fullCode, position, length, beginLine, beginColumn, endLine, endColumn);
}
public boolean isInside(SourceLocation that) {
return (position >= that.position)
&& (position + length <= that.position + that.length)
&& (beginLine >= that.beginLine)
&& (beginLine > that.beginLine || beginColumn >= that.beginColumn)
&& (endLine <= that.endLine)
&& (endLine < that.endLine || endColumn <= that.endColumn);
}
public boolean comesAfter(SourceLocation that) {
return beginLine > that.endLine ||
beginLine == that.endLine && beginColumn > that.endColumn;
}
public enum Type {
FULL(PipeCompiler::full),
PIPE(PipeCompiler::pipe),
EXPRESSION(PipeCompiler::expression),
SELECT(PipeCompiler::select),
FILTER(PipeCompiler::filter),
MODULE(PipeCompiler::module),
FUNCTION_DEF(PipeCompiler::functionDef),
NONE(null);
private final Function, PipeCompiler> change;
Type(java.util.function.Function, PipeCompiler> change) {
this.change = change;
}
public PipeCompiler apply(PipeCompiler compiler) {
Preconditions.checkArgument(change != null, "No compiler defined for source type");
return change.apply(compiler);
}
}
}