mirror of
https://github.com/processing/processing4.git
synced 2026-05-09 12:22:43 +02:00
292 lines
8.1 KiB
Java
292 lines
8.1 KiB
Java
package processing.mode.java;
|
|
|
|
import com.google.classpath.ClassPath;
|
|
|
|
import org.eclipse.jdt.core.compiler.IProblem;
|
|
import org.eclipse.jdt.core.dom.ASTNode;
|
|
import org.eclipse.jdt.core.dom.CompilationUnit;
|
|
|
|
import java.net.URLClassLoader;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import processing.app.Problem;
|
|
import processing.app.Sketch;
|
|
import processing.core.PApplet;
|
|
import processing.mode.java.preproc.ImportStatement;
|
|
import processing.mode.java.preproc.TextTransform.OffsetMapper;
|
|
|
|
public class PreprocSketch {
|
|
|
|
public final Sketch sketch;
|
|
|
|
public final CompilationUnit compilationUnit;
|
|
|
|
public final String[] classPathArray;
|
|
public final ClassPath classPath;
|
|
public final URLClassLoader classLoader;
|
|
|
|
public final String[] searchClassPathArray;
|
|
|
|
public final int[] tabStartOffsets;
|
|
|
|
public final String scrubbedPdeCode;
|
|
public final String pdeCode;
|
|
public final String javaCode;
|
|
|
|
public final OffsetMapper offsetMapper;
|
|
|
|
public final boolean hasSyntaxErrors;
|
|
public final boolean hasCompilationErrors;
|
|
|
|
public final List<ImportStatement> programImports;
|
|
public final List<ImportStatement> coreAndDefaultImports;
|
|
public final List<ImportStatement> codeFolderImports;
|
|
public final List<Problem> otherProblems;
|
|
public final List<IProblem> iproblems;
|
|
|
|
public final Map<String, Integer> javaFileMapping;
|
|
|
|
/// JAVA -> SKETCH -----------------------------------------------------------
|
|
|
|
|
|
public boolean inRange(SketchInterval interval) {
|
|
return interval != SketchInterval.BEFORE_START &&
|
|
interval.stopPdeOffset < pdeCode.length();
|
|
}
|
|
|
|
|
|
public String getPdeCode(SketchInterval si) {
|
|
if (si == SketchInterval.BEFORE_START) return "";
|
|
int stop = Math.min(si.stopPdeOffset, pdeCode.length());
|
|
int start = Math.min(si.startPdeOffset, stop);
|
|
return pdeCode.substring(start, stop);
|
|
}
|
|
|
|
|
|
public SketchInterval mapJavaToSketch(ASTNode node) {
|
|
return mapJavaToSketch(node.getStartPosition(),
|
|
node.getStartPosition() + node.getLength());
|
|
}
|
|
|
|
|
|
public boolean isJavaTab(String fileName) {
|
|
return javaFileMapping.containsKey(fileName);
|
|
}
|
|
|
|
|
|
public int getJavaTabIndex(String fileName) {
|
|
return javaFileMapping.get(fileName);
|
|
}
|
|
|
|
|
|
public SketchInterval mapJavaToSketch(IProblem iproblem) {
|
|
String originalFile = new String(iproblem.getOriginatingFileName());
|
|
boolean isJavaTab = javaFileMapping.containsKey(originalFile);
|
|
|
|
// If is a ".java" tab, do not need to map into combined sketch source.
|
|
if (isJavaTab) {
|
|
return new SketchInterval(
|
|
javaFileMapping.get(originalFile),
|
|
iproblem.getSourceStart(),
|
|
iproblem.getSourceEnd() + 1,
|
|
iproblem.getSourceStart(), // Is outside main sketch code
|
|
iproblem.getSourceEnd() + 1 // Is outside main sketch code
|
|
);
|
|
} else {
|
|
return mapJavaToSketch(
|
|
iproblem.getSourceStart(),
|
|
iproblem.getSourceEnd() + 1 // make it exclusive
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
public SketchInterval mapJavaToSketch(int startJavaOffset, int stopJavaOffset) {
|
|
int length = stopJavaOffset - startJavaOffset;
|
|
int startPdeOffset = javaOffsetToPdeOffset(startJavaOffset);
|
|
int stopPdeOffset;
|
|
if (length == 0) {
|
|
stopPdeOffset = startPdeOffset;
|
|
} else {
|
|
stopPdeOffset = javaOffsetToPdeOffset(stopJavaOffset-1);
|
|
if (stopPdeOffset >= 0 && (stopPdeOffset > startPdeOffset || length == 1)) {
|
|
stopPdeOffset += 1;
|
|
}
|
|
}
|
|
|
|
if (startPdeOffset < 0 || stopPdeOffset < 0) {
|
|
return SketchInterval.BEFORE_START;
|
|
}
|
|
|
|
int tabIndex = pdeOffsetToTabIndex(startPdeOffset);
|
|
|
|
if (startPdeOffset >= pdeCode.length()) {
|
|
startPdeOffset = pdeCode.length() - 1;
|
|
stopPdeOffset = startPdeOffset + 1;
|
|
}
|
|
|
|
return new SketchInterval(tabIndex,
|
|
pdeOffsetToTabOffset(tabIndex, startPdeOffset),
|
|
pdeOffsetToTabOffset(tabIndex, stopPdeOffset),
|
|
startPdeOffset, stopPdeOffset);
|
|
}
|
|
|
|
|
|
private int javaOffsetToPdeOffset(int javaOffset) {
|
|
return offsetMapper.getInputOffset(javaOffset);
|
|
}
|
|
|
|
|
|
public int pdeOffsetToTabIndex(int pdeOffset) {
|
|
pdeOffset = Math.max(0, pdeOffset);
|
|
int tab = Arrays.binarySearch(tabStartOffsets, pdeOffset);
|
|
if (tab < 0) {
|
|
tab = -(tab + 1) - 1;
|
|
}
|
|
return tab;
|
|
}
|
|
|
|
|
|
public int pdeOffsetToTabOffset(int tabIndex, int pdeOffset) {
|
|
int tabStartOffset = tabStartOffsets[clipTabIndex(tabIndex)];
|
|
return pdeOffset - tabStartOffset;
|
|
}
|
|
|
|
|
|
|
|
/// SKETCH -> JAVA -----------------------------------------------------------
|
|
|
|
|
|
public int tabOffsetToJavaOffset(int tabIndex, int tabOffset) {
|
|
int tabStartOffset = tabStartOffsets[clipTabIndex(tabIndex)];
|
|
int pdeOffset = tabStartOffset + tabOffset;
|
|
return offsetMapper.getOutputOffset(pdeOffset);
|
|
}
|
|
|
|
|
|
|
|
/// LINE NUMBERS -------------------------------------------------------------
|
|
|
|
|
|
public int tabOffsetToJavaLine(int tabIndex, int tabOffset) {
|
|
int javaOffset = tabOffsetToJavaOffset(tabIndex, tabOffset);
|
|
return offsetToLine(javaCode, javaOffset);
|
|
}
|
|
|
|
|
|
public int tabOffsetToTabLine(int tabIndex, int tabOffset) {
|
|
int tabStartOffset = tabStartOffsets[clipTabIndex(tabIndex)];
|
|
return offsetToLine(pdeCode, tabStartOffset, tabStartOffset + tabOffset);
|
|
}
|
|
|
|
|
|
// TODO: optimize
|
|
private static int offsetToLine(String text, int offset) {
|
|
return offsetToLine(text, 0, offset);
|
|
}
|
|
|
|
|
|
// TODO: optimize
|
|
private static int offsetToLine(String text, int start, int offset) {
|
|
int line = 0;
|
|
while (offset >= start) {
|
|
offset = text.lastIndexOf('\n', offset-1);
|
|
line++;
|
|
}
|
|
return line - 1;
|
|
}
|
|
|
|
|
|
|
|
/// Util ---------------------------------------------------------------------
|
|
|
|
private int clipTabIndex(int tabIndex) {
|
|
return PApplet.constrain(tabIndex, 0, tabStartOffsets.length - 1);
|
|
}
|
|
|
|
|
|
|
|
/// BUILDER BUSINESS /////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* There is a lot of fields and having constructor with this many parameters
|
|
* is just not practical. Fill stuff into builder and then simply build it.
|
|
* Builder also guards against calling methods in the middle of building process.
|
|
*/
|
|
|
|
public static class Builder {
|
|
public Sketch sketch;
|
|
|
|
public CompilationUnit compilationUnit;
|
|
|
|
public String[] classPathArray;
|
|
public ClassPath classPath;
|
|
public URLClassLoader classLoader;
|
|
|
|
public String[] searchClassPathArray;
|
|
|
|
public int[] tabStartOffsets = new int[0];
|
|
|
|
public String scrubbedPdeCode;
|
|
public String pdeCode;
|
|
public String javaCode;
|
|
|
|
public OffsetMapper offsetMapper;
|
|
|
|
public boolean hasSyntaxErrors;
|
|
public boolean hasCompilationErrors;
|
|
|
|
public final List<ImportStatement> programImports = new ArrayList<>();
|
|
public final List<ImportStatement> coreAndDefaultImports = new ArrayList<>();
|
|
public final List<ImportStatement> codeFolderImports = new ArrayList<>();
|
|
public final List<Problem> otherProblems = new ArrayList<>();
|
|
public List<IProblem> iproblems;
|
|
|
|
public Map<String, Integer> javaFileMapping;
|
|
|
|
public PreprocSketch build() {
|
|
return new PreprocSketch(this);
|
|
}
|
|
}
|
|
|
|
public static PreprocSketch empty() {
|
|
return new Builder().build();
|
|
}
|
|
|
|
private PreprocSketch(Builder b) {
|
|
sketch = b.sketch;
|
|
|
|
compilationUnit = b.compilationUnit;
|
|
|
|
classPathArray = b.classPathArray;
|
|
classPath = b.classPath;
|
|
classLoader = b.classLoader;
|
|
|
|
searchClassPathArray = b.searchClassPathArray;
|
|
|
|
tabStartOffsets = b.tabStartOffsets;
|
|
|
|
scrubbedPdeCode = b.scrubbedPdeCode;
|
|
pdeCode = b.pdeCode;
|
|
javaCode = b.javaCode;
|
|
|
|
offsetMapper = b.offsetMapper != null ? b.offsetMapper : OffsetMapper.EMPTY_MAPPER;
|
|
|
|
hasSyntaxErrors = b.hasSyntaxErrors;
|
|
hasCompilationErrors = b.hasCompilationErrors;
|
|
|
|
otherProblems = b.otherProblems;
|
|
|
|
javaFileMapping = b.javaFileMapping;
|
|
iproblems = b.iproblems;
|
|
|
|
programImports = Collections.unmodifiableList(b.programImports);
|
|
coreAndDefaultImports = Collections.unmodifiableList(b.coreAndDefaultImports);
|
|
codeFolderImports = Collections.unmodifiableList(b.codeFolderImports);
|
|
}
|
|
}
|