package scotch.compiler.text;
import static lombok.AccessLevel.PRIVATE;
import static scotch.compiler.text.SourcePoint.point;
import static scotch.compiler.text.TextUtil.repeat;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import lombok.AllArgsConstructor;
import me.qmx.jitescript.CodeBlock;
import org.objectweb.asm.tree.LabelNode;
@AllArgsConstructor(access = PRIVATE)
public class SourceLocation {
public static final SourceLocation NULL_SOURCE = source("<unknown>", point(-1, -1, -1), point(-1, -1, -1));
public static SourceLocation extent(Collection<SourceLocation> locations) {
Iterator<SourceLocation> iterator = locations.iterator();
if (iterator.hasNext()) {
SourceLocation location = iterator.next();
while (iterator.hasNext()) {
location = location.extend(iterator.next());
}
return location;
} else {
return NULL_SOURCE;
}
}
public static SourceLocation source(String source, SourcePoint start, SourcePoint end) {
return new SourceLocation(source, start, end);
}
private final String source;
private final SourcePoint start;
private final SourcePoint end;
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof SourceLocation) {
SourceLocation other = (SourceLocation) o;
return this == NULL_SOURCE || other == NULL_SOURCE || (
Objects.equals(source, other.source)
&& Objects.equals(start, other.start)
&& Objects.equals(end, other.end)
);
} else {
return false;
}
}
public SourceLocation extend(SourceLocation sourceLocation) {
if (this == NULL_SOURCE) {
return sourceLocation;
} else if (sourceLocation == NULL_SOURCE) {
return this;
} else {
return source(source, start.min(sourceLocation.start), end.max(sourceLocation.end));
}
}
public NamedSourcePoint getEnd() {
return end.withSource(source);
}
public int getEndOffset() {
return end.getOffset();
}
public SourceLocation getEndPoint() {
return new SourceLocation(source, end, end);
}
public String getSource() {
return source;
}
public NamedSourcePoint getStart() {
return start.withSource(source);
}
public int getStartOffset() {
return start.getOffset();
}
public SourceLocation getStartPoint() {
return new SourceLocation(source, start, start);
}
@Override
public int hashCode() {
return 79;
}
public void markLine(CodeBlock block) {
if (this != NULL_SOURCE) {
LabelNode label = new LabelNode();
int line = start.getLine();
if (line != -1) {
block.label(label);
block.line(line - 1, label);
}
}
}
public String prettyPrint() {
return "[" + prettyPrint_() + "]";
}
public String report(String indent, int indentLevel) {
return repeat(indent, indentLevel) + prettyPrint_();
}
@Override
public String toString() {
return prettyPrint();
}
private String prettyPrint_() {
return getSource() + " " + start.prettyPrint() + ", " + end.prettyPrint();
}
}