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

net.intelie.pipes.ast.SourceLocation Maven / Gradle / Ivy

There is a newer version: 0.25.5
Show newest version
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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy