Skip to content

Commit

Permalink
Merge pull request #127 from eclipse/fix-egl-ast-regions
Browse files Browse the repository at this point in the history
Fix EGL AST regions
  • Loading branch information
agarciadom authored Oct 17, 2024
2 parents 79d0e2e + 8399031 commit 259e25b
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public Map<String, Object> getData() {
*/
@Override
public int hashCode() {
return Objects.hash(uri, region);
return Objects.hash(uri, region, getParent());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public class AST extends CommonTree {
protected URI uri;
protected Integer line = null;
protected Integer column = null;

// Optional: only used for undoing EGL escaping
protected Integer length = null;

protected Region region;
protected AST annotations;
protected boolean imaginary;
Expand Down Expand Up @@ -264,6 +268,7 @@ public AST getLastChild() {
}

public Region getRegion() {

if (region == null) {
region = new Region();

Expand All @@ -281,7 +286,7 @@ public Region getRegion() {
Position endPosition = new Position();
if (!isImaginary()) {
endPosition.setLine(this.getLine());
endPosition.setColumn(this.getColumn() + ((CommonToken)getToken()).getStopIndex() - ((CommonToken)getToken()).getStartIndex() + 1);
endPosition.setColumn(this.getColumn() + getLength());
}
else {
endPosition.setLine(-1);
Expand All @@ -299,23 +304,24 @@ public Region getRegion() {
}
}

for (Token token : getExtraTokens()) {
if (token == null) continue;
Position tokenStartPosition = new Position();
tokenStartPosition.setLine(token.getLine());
tokenStartPosition.setColumn(token.getCharPositionInLine());

Position tokenEndPosition = new Position();
tokenEndPosition.setLine(token.getLine());
tokenEndPosition.setColumn(token.getCharPositionInLine() + token.getText().length());

if (tokenStartPosition.isBefore(region.getStart())) {
region.setStart(tokenStartPosition);
}
if (tokenEndPosition.isAfter(region.getEnd())) {
region.setEnd(tokenEndPosition);
if (!isImaginary()) {
for (Token token : getExtraTokens()) {
if (token == null) continue;
Position tokenStartPosition = new Position();
tokenStartPosition.setLine(token.getLine());
tokenStartPosition.setColumn(token.getCharPositionInLine());

Position tokenEndPosition = new Position();
tokenEndPosition.setLine(token.getLine());
tokenEndPosition.setColumn(token.getCharPositionInLine() + token.getText().length());

if (tokenStartPosition.isBefore(region.getStart())) {
region.setStart(tokenStartPosition);
}
if (tokenEndPosition.isAfter(region.getEnd())) {
region.setEnd(tokenEndPosition);
}
}

}

}
Expand Down Expand Up @@ -379,6 +385,17 @@ public String toExtendedStringTree() {
return toExtendedStringTree(0);
}

public Integer getLength() {
if (length == null) {
return ((CommonToken)getToken()).getStopIndex() - ((CommonToken)getToken()).getStartIndex() + 1;
}
return length;
}

public void setLength(Integer length) {
this.length = length;
}

protected String toExtendedStringTree(int indent) {
String toString = "";
for (int i=0;i<indent;i++) {
Expand Down
3 changes: 2 additions & 1 deletion plugins/org.eclipse.epsilon.egl.engine/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Bundle-SymbolicName: org.eclipse.epsilon.egl.engine
Bundle-Version: 2.6.0.qualifier
Bundle-Vendor: Eclipse Modeling Project
Require-Bundle: org.eclipse.epsilon.eol.engine,
org.eclipse.epsilon.erl.engine;visibility:=reexport
org.eclipse.epsilon.erl.engine;visibility:=reexport,
com.google.guava
Export-Package: org.eclipse.epsilon.egl,
org.eclipse.epsilon.egl.concurrent,
org.eclipse.epsilon.egl.config,
Expand Down
4 changes: 4 additions & 0 deletions plugins/org.eclipse.epsilon.egl.engine/pom-plain.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<artifactId>org.eclipse.epsilon.erl.engine</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
/*******************************************************************************
* Copyright (c) 2008 The University of York.
* Copyright (c) 2008-2024 The University of York.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Louis Rose - initial API and implementation
* Dimitris Kolovos, Antonio Garcia-Dominguez - further refinements
******************************************************************************/
package org.eclipse.epsilon.egl.preprocessor;

import static org.eclipse.epsilon.egl.util.FileUtil.NEWLINE;
import static org.eclipse.epsilon.egl.util.StringUtil.isWhitespace;

import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.antlr.runtime.Token;
import org.eclipse.epsilon.common.parse.AST;
import org.eclipse.epsilon.common.parse.Position;
import org.eclipse.epsilon.common.parse.Region;
import org.eclipse.epsilon.egl.parse.EglToken.TokenType;
import org.eclipse.epsilon.egl.util.FileUtil;
Expand All @@ -29,19 +34,8 @@ public class Preprocessor {
private final Map<Integer, Integer> colNumber = new TreeMap<>();
private PreprocessorTrace trace = new PreprocessorTrace();
private AST child = null;


private static String escape(String s) {
return s
.replaceAll("\\\\","\\\\\\\\")
.replaceAll("\r","\\\\r")
.replaceAll("\n","\\\\n")
.replaceAll("\t","\\\\t")
.replaceAll("\b","\\\\b")
.replaceAll("\f","\\\\f")
.replace("'", "\\'")
.replace("\"", "\\\"");
}

private static final Pattern PATTERN_TO_ESCAPE = Pattern.compile("\\\\|[\r\n\t\b\f'\"]");

private int getOffset(int lineNumber) {
if (colNumber.containsKey(lineNumber))
Expand All @@ -56,7 +50,7 @@ private void addToOffset(int lineNumber, int addend) {

private void updateOffset(int eglLineNumber, int correction, int textLength) {
// Update trace
trace.incrementColumnCorrectionNumber(getOffset(eglLineNumber) + correction);
trace.incrementColumnCorrectionNumber(0, getOffset(eglLineNumber) + correction);

// Store new column number as current position + text length + length of %]
addToOffset(eglLineNumber, correction + textLength + 2);
Expand All @@ -70,11 +64,6 @@ private void appendNewLineToEol(int eglLineNumber, boolean appendNewLine) {
if (appendNewLine) eol.append(NEWLINE);
trace.setEglLineNumberForCurrentEolLineNumber(eglLineNumber);
}

private void appendToEolOnANewLine(String text, int eglLineNumber) {
appendNewLineToEol(eglLineNumber);
eol.append(text);
}

private boolean eolEndsWith(String suffix) {
if (suffix.length() > eol.length()) return false;
Expand Down Expand Up @@ -123,13 +112,50 @@ public String convertToEol(AST ast) {

// Gobble whitespace before [% %] and [* *] pairs
if (!isWhitespacePrecedingTagged) {
appendToEolOnANewLine("out.prinx('" + escape(text) + "');", child.getLine());

if (TokenType.typeOf(child.getType()) == TokenType.PLAIN_TEXT) {
String printCall = "out.prinx('";
// Update trace to account for length of printCall
trace.incrementColumnCorrectionNumber(getOffset(child.getLine()) + -printCall.length());
final String printCall = "out.prinx('";
appendNewLineToEol(child.getLine());
trace.incrementColumnCorrectionNumber(0, getOffset(child.getLine()) + -printCall.length());

final StringBuilder escapedLine = new StringBuilder(printCall);
final Matcher escapingMatcher = PATTERN_TO_ESCAPE.matcher(text);
int previousEnd = 0;
while (escapingMatcher.find()) {
String newRegion = text.substring(previousEnd, escapingMatcher.start());
escapedLine.append(newRegion);

String toBeEscaped = escapingMatcher.group();
String replacement;
switch (toBeEscaped) {
case "\\":
replacement = "\\\\"; break;
case "\r":
replacement = "\\r"; break;
case "\n":
replacement = "\\n"; break;
case "\t":
replacement = "\\t"; break;
case "\b":
replacement = "\\b"; break;
case "\f":
replacement = "\\f"; break;
case "'":
replacement = "\\'"; break;
case "\"":
replacement = "\\\""; break;
default:
replacement = toBeEscaped; break;
}
escapedLine.append(replacement);
trace.incrementColumnCorrectionNumber(
escapedLine.toString().length(), toBeEscaped.length() - replacement.length());

previousEnd = escapingMatcher.end();
}

// add tail after last match and close the call
escapedLine.append(text.substring(previousEnd));
escapedLine.append("');");
eol.append(escapedLine.toString());
}

addToOffset(child.getLine(), text.length());
Expand Down Expand Up @@ -184,7 +210,7 @@ public String convertToEol(AST ast) {
String printCall = "out.printdyn(";

// Update trace to account for length of printCall
trace.incrementColumnCorrectionNumber(-printCall.length());
trace.incrementColumnCorrectionNumber(0, -printCall.length());

eol.append(printCall + child.getFirstChild().getText() + ");");
}
Expand Down Expand Up @@ -288,16 +314,22 @@ protected boolean updateRegionsOfStaticTextASTs(AST ast) {
adjustedRegion = region;
}

// Turn out.print("\n") and out.print("\r\n") to imaginary
if ("\\n".equals(firstParameterAst.getText()) || "\\r\\n".equals(firstParameterAst.getText())) firstParameterAst.setImaginary(true);


// Make all involved ASTs imaginary and assign them the region of the first parameter
for (AST imaginary : Arrays.asList(ast, outAst, printAst, parametersAst)) {
imaginary.setColumn(getTrace().getEglColumnNumberFor(imaginary.getLine(), imaginary.getColumn()));
imaginary.setLine(getTrace().getEglLineNumberFor(imaginary.getLine()));
imaginary.setImaginary(true);
imaginary.setRegion(adjustedRegion);
}

// Turn out.print("\n") and out.print("\r\n") to imaginary
if ("prinx".equals(printAst.getText()) && ("\\n".equals(firstParameterAst.getText()) || "\\r\\n".equals(firstParameterAst.getText()))) {
firstParameterAst.setImaginary(true);
Position adjustedEnd = new Position(firstParameterAst.getRegion().getStart().getLine(), firstParameterAst.getRegion().getStart().getColumn());
firstParameterAst.getRegion().setEnd(adjustedEnd);
}

return true;
}
}
Expand All @@ -307,7 +339,10 @@ protected boolean updateRegionsOfStaticTextASTs(AST ast) {
}

public void updateASTLocations(AST ast) {
ast.setColumn(getTrace().getEglColumnNumberFor(ast.getLine(), ast.getColumn()));
final int eglStartColumn = getTrace().getEglColumnNumberFor(ast.getLine(), ast.getColumn());
final int eglEndColumn = getTrace().getEglColumnNumberFor(ast.getLine(), ast.getColumn() + ast.getLength());
ast.setColumn(eglStartColumn);
ast.setLength(eglEndColumn - eglStartColumn);
ast.setLine(getTrace().getEglLineNumberFor(ast.getLine()));

for (Token token : ast.getExtraTokens()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
package org.eclipse.epsilon.egl.preprocessor;

import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import org.eclipse.epsilon.egl.util.FileUtil;

import com.google.common.collect.TreeBasedTable;

public class PreprocessorTrace {

private Map<Integer, Integer> lineNumberMapping = new TreeMap<>();
private Map<Integer, Integer> columnCorrections = new TreeMap<>();


// Rows are lines. It's important that we use a tree-based table so we get row entries to be sorted by column.
private TreeBasedTable<Integer, Integer, Integer> columnCorrections = TreeBasedTable.create();

private int currentEolLine = 1;
private int maximumEglLineNumber = 1;

Expand All @@ -31,9 +37,14 @@ public int getEglLineNumberFor(int eolLine) {
}

public int getEglColumnNumberFor(int eolLine, int eolCol) {
if (columnCorrections.containsKey(eolLine))
return eolCol + columnCorrections.get(eolLine);

if (columnCorrections.containsRow(eolLine)) {
SortedMap<Integer, Integer> rowUpToColumn = columnCorrections.row(eolLine).headMap(eolCol + 1);
if (!rowUpToColumn.isEmpty()) {
int correction = rowUpToColumn.get(rowUpToColumn.lastKey());
return eolCol + correction;
}
}

return eolCol;
}

Expand All @@ -43,11 +54,22 @@ void setEglLineNumberForCurrentEolLineNumber(int eglLineNumber) {
maximumEglLineNumber = Math.max(maximumEglLineNumber, eglLineNumber);
}

void incrementColumnCorrectionNumber(int correction) {
if (columnCorrections.containsKey(currentEolLine))
columnCorrections.put(currentEolLine, correction + columnCorrections.get(currentEolLine));
else
columnCorrections.put(currentEolLine, correction);
void incrementColumnCorrectionNumber(int currentEolColumn, int correction) {
if (columnCorrections.containsRow(currentEolLine)) {
SortedMap<Integer, Integer> row = columnCorrections.row(currentEolLine);

Integer lastColumn = row.lastKey();
if (currentEolColumn < lastColumn) {
throw new IllegalStateException(String.format(
"Tried to increment column correction number for EOL column %d, "
+ "which is before the last EOL column number %d",
currentEolColumn, lastColumn));
}

row.put(currentEolColumn, row.get(lastColumn) + correction);
} else {
columnCorrections.row(currentEolLine).put(currentEolColumn, correction);
}
}

void reset() {
Expand All @@ -61,19 +83,24 @@ void reset() {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();

for (int eolLine = 1; eolLine <= currentEolLine; eolLine++) {
builder.append(eolLine);
builder.append(" -> ");
builder.append(getEglLineNumberFor(eolLine));

boolean bFirst = true;
builder.append(" [");
builder.append(getEglColumnNumberFor(eolLine, 0));
for (Entry<Integer, Integer> lineCorrection : columnCorrections.row(eolLine).entrySet()) {
if (bFirst) bFirst = false; else builder.append(", ");
builder.append(lineCorrection.getKey());
builder.append(" -> ");
builder.append(lineCorrection.getValue());
}
builder.append("]");

builder.append(FileUtil.NEWLINE);
}

return builder.toString();
}
}
Loading

0 comments on commit 259e25b

Please sign in to comment.