refactor: prepare preprocessor error improvement (in progress)

https://github.com/plantuml/plantuml/pull/1668
This commit is contained in:
Arnaud Roques 2024-02-22 19:32:38 +01:00
parent 436fb37f1a
commit 6329d9a8d5
53 changed files with 331 additions and 306 deletions

View File

@ -1,4 +1,4 @@
# Warning, "version" should be the same in gradle.properties and Version.java
# Any idea anyone how to magically synchronize those :-) ?
version = 1.2024.4beta2
version = 1.2024.4beta3
org.gradle.workers.max = 3

View File

@ -143,7 +143,7 @@ public class BlockUml {
this.data = new ArrayList<>(strings);
} else {
final TimLoader timLoader = new TimLoader(mode.getImportedFiles(), defines, charset,
(DefinitionsContainer) mode);
(DefinitionsContainer) mode, strings.get(0));
this.included.addAll(timLoader.load(strings));
this.data = timLoader.getResultList();
this.debug = timLoader.getDebug();

View File

@ -55,6 +55,7 @@ import net.sourceforge.plantuml.file.AParentFolder;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SecurityProfile;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.TVariableScope;
@ -81,11 +82,11 @@ public class Defines implements Truth {
return new Defines();
}
public void copyTo(TMemory memory) throws EaterException {
public void copyTo(TMemory memory, StringLocated location) throws EaterException {
for (Entry<String, Define> ent : values.entrySet()) {
final String name = ent.getKey();
final Define def = ent.getValue();
memory.putVariable(name, def.asTVariable(), TVariableScope.GLOBAL);
memory.putVariable(name, def.asTVariable(), TVariableScope.GLOBAL, location);
}
}
@ -114,10 +115,10 @@ public class Defines implements Truth {
final Defines result = createEmpty();
result.overrideFilename(file.getName());
result.environment.put("filedate", new Date(file.lastModified()).toString());
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
result.environment.put("dirpath",
file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/'));
}
return result;
}
@ -126,10 +127,10 @@ public class Defines implements Truth {
final Defines result = createEmpty();
result.overrideFilename(file.getName());
result.environment.put("filedate", new Date(file.lastModified()).toString());
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
result.environment.put("dirpath",
file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/'));
}
return result;
}
@ -147,9 +148,9 @@ public class Defines implements Truth {
private static String nameNoExtension(String name) {
final int x = name.lastIndexOf('.');
if (x == -1) {
if (x == -1)
return name;
}
return name.substring(0, x);
}
@ -169,11 +170,10 @@ public class Defines implements Truth {
}
public boolean isTrue(String name) {
for (String key : values.keySet()) {
if (key.equals(name) || key.startsWith(name + "(")) {
for (String key : values.keySet())
if (key.equals(name) || key.startsWith(name + "("))
return true;
}
}
return false;
}
@ -192,9 +192,9 @@ public class Defines implements Truth {
}
private String method1(String line) {
for (Define def : values.values()) {
for (Define def : values.values())
line = def.apply(line);
}
return line;
}
@ -215,18 +215,17 @@ public class Defines implements Truth {
private String method2(String line) {
final Set<String> words = words(line);
if (magic == null) {
if (magic == null)
magic = getAll();
}
for (String w : words) {
Collection<Define> tmp = magic.get(w);
if (tmp == null) {
if (tmp == null)
continue;
}
for (Define def : tmp) {
for (Define def : tmp)
line = def.apply(line);
}
}
return line;
}
@ -236,9 +235,9 @@ public class Defines implements Truth {
Pattern p = Pattern.compile(ID);
Matcher m = p.matcher(line);
final Set<String> words = new HashSet<>();
while (m.find()) {
while (m.find())
words.add(m.group(0));
}
return words;
}

View File

@ -36,6 +36,7 @@
package net.sourceforge.plantuml.preproc;
public interface Truth {
public boolean isTrue(String name);
}

View File

@ -139,21 +139,21 @@ public class PreprocessorUtils {
if (StartDiagramExtractReader.containsStartDiagram(url, s, charset))
return StartDiagramExtractReader.build(url, s, suf, charset);
return getReaderInclude(url, s.getLocation(), charset);
return getReaderInclude(url, s, charset);
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("Cannot open URL " + e.getMessage());
throw EaterException.located("Cannot open URL " + e.getMessage(), s);
}
}
public static ReadLine getReaderInclude(SURL url, LineLocation lineLocation, Charset charset)
public static ReadLine getReaderInclude(SURL url, StringLocated s, Charset charset)
throws EaterException, UnsupportedEncodingException {
final InputStream is = url.openStream();
if (is == null)
throw EaterException.located("Cannot open URL");
throw EaterException.located("Cannot open URL", s);
return ReadLineReader.create(new InputStreamReader(is, charset), url.toString(), lineLocation);
return ReadLineReader.create(new InputStreamReader(is, charset), url.toString(), s.getLocation());
}
}

View File

@ -93,7 +93,7 @@ public abstract class Eater {
final TokenStack tokenStack = new TokenStack();
addIntoTokenStack(tokenStack, false);
if (tokenStack.size() == 0)
throw EaterException.located("Missing expression");
throw EaterException.located("Missing expression", stringLocated);
return tokenStack;
}
@ -121,7 +121,7 @@ public abstract class Eater {
final public String eatAndGetQuotedString() throws EaterException {
final char separator = peekChar();
if (TLineType.isQuote(separator) == false)
throw EaterException.located("quote10");
throw EaterException.located("quote10", stringLocated);
checkAndEatChar(separator);
final StringBuilder value = new StringBuilder();
@ -142,7 +142,7 @@ public abstract class Eater {
while (true) {
char ch = peekChar();
if (ch == 0)
throw EaterException.located("until001");
throw EaterException.located("until001", stringLocated);
if (level == 0 && (ch == ',' || ch == ')'))
return value.toString().trim();
@ -190,7 +190,7 @@ public abstract class Eater {
final protected String eatAndGetVarname() throws EaterException {
final StringBuilder varname = new StringBuilder("" + eatOneChar());
if (TLineType.isLetterOrUnderscoreOrDollar(varname.charAt(0)) == false)
throw EaterException.located("a002");
throw EaterException.located("a002", stringLocated);
addUpToLastLetterOrUnderscoreOrDigit(varname);
return varname.toString();
@ -199,7 +199,7 @@ public abstract class Eater {
final protected String eatAndGetFunctionName() throws EaterException {
final StringBuilder varname = new StringBuilder("" + eatOneChar());
if (TLineType.isLetterOrUnderscoreOrDollar(varname.charAt(0)) == false)
throw EaterException.located("a003");
throw EaterException.located("a003", stringLocated);
addUpToLastLetterOrUnderscoreOrDigit(varname);
return varname.toString();
@ -249,7 +249,7 @@ public abstract class Eater {
final protected void checkAndEatChar(char ch) throws EaterException {
if (i >= stringLocated.length() || stringLocated.charAt(i) != ch)
throw EaterException.located("a001");
throw EaterException.located("a001", stringLocated);
i++;
}
@ -299,7 +299,7 @@ public abstract class Eater {
}
final protected TFunctionImpl eatDeclareFunction(TContext context, TMemory memory, boolean unquoted,
LineLocation location, boolean allowNoParenthesis, TFunctionType type)
StringLocated location, boolean allowNoParenthesis, TFunctionType type)
throws EaterException, EaterExceptionLocated {
final List<TFunctionArgument> args = new ArrayList<>();
final String functionName = eatAndGetFunctionName();
@ -308,7 +308,7 @@ public abstract class Eater {
if (allowNoParenthesis)
return new TFunctionImpl(functionName, args, unquoted, type);
throw EaterException.located("Missing opening parenthesis");
throw EaterException.located("Missing opening parenthesis", stringLocated);
}
while (true) {
skipSpaces();
@ -320,7 +320,7 @@ public abstract class Eater {
if (peekChar() == '=') {
eatOneChar();
final TokenStack def = TokenStack.eatUntilCloseParenthesisOrComma(this);
def.guessFunctions();
def.guessFunctions(location);
defValue = def.getResult(getStringLocated(), context, memory);
// System.err.println("result=" + defValue);
} else {
@ -333,7 +333,7 @@ public abstract class Eater {
checkAndEatChar(")");
break;
} else {
throw EaterException.located("Error in function definition");
throw EaterException.located("Error in function definition", stringLocated);
}
}
skipSpaces();
@ -341,25 +341,25 @@ public abstract class Eater {
}
final protected TFunctionImpl eatDeclareReturnFunctionWithOptionalReturn(TContext context, TMemory memory,
boolean unquoted, LineLocation location) throws EaterException, EaterExceptionLocated {
boolean unquoted, StringLocated location) throws EaterException, EaterExceptionLocated {
final TFunctionImpl result = eatDeclareFunction(context, memory, unquoted, location, false,
TFunctionType.RETURN_FUNCTION);
if (peekChar() == 'r') {
checkAndEatChar("return");
skipSpaces();
final String line = "!return " + eatAllToEnd();
result.addBody(new StringLocated(line, location));
result.addBody(new StringLocated(line, location.getLocation()));
} else if (peekChar() == '!') {
checkAndEatChar("!return");
skipSpaces();
final String line = "!return " + eatAllToEnd();
result.addBody(new StringLocated(line, location));
result.addBody(new StringLocated(line, location.getLocation()));
}
return result;
}
final protected TFunctionImpl eatDeclareProcedure(TContext context, TMemory memory, boolean unquoted,
LineLocation location) throws EaterException, EaterExceptionLocated {
StringLocated location) throws EaterException, EaterExceptionLocated {
final TFunctionImpl result = eatDeclareFunction(context, memory, unquoted, location, false,
TFunctionType.PROCEDURE);
return result;

View File

@ -53,7 +53,7 @@ public class EaterAffectation extends Eater {
if (scope != null) {
skipSpaces();
if (peekChar() == '?' || peekChar() == '=') {
// The variable itself is "local" or "glocal", which is not a good idea by the
// The variable itself is "local" or "global", which is not a good idea by the
// way
scope = null;
} else
@ -72,7 +72,7 @@ public class EaterAffectation extends Eater {
skipSpaces();
final TValue value = eatExpression(context, memory);
memory.putVariable(varname, value, scope);
memory.putVariable(varname, value, scope, getStringLocated());
}
}

View File

@ -56,7 +56,7 @@ public class EaterAffectationDefine extends Eater {
// if (memory instanceof TMemoryLocal) {
// memory = ((TMemoryLocal) memory).getGlobalForInternalUseOnly();
// }
memory.putVariable(varname, value, TVariableScope.GLOBAL);
memory.putVariable(varname, value, TVariableScope.GLOBAL, getStringLocated());
}
}

View File

@ -55,9 +55,9 @@ public class EaterAssert extends Eater {
if (ch == ':') {
checkAndEatChar(':');
final TValue message = eatExpression(context, memory);
throw EaterException.located("Assertion error : " + message.toString());
throw EaterException.located("Assertion error : " + message.toString(), getStringLocated());
}
throw EaterException.located("Assertion error");
throw EaterException.located("Assertion error", getStringLocated());
}
}

View File

@ -35,17 +35,16 @@
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.utils.LineLocation;
public class EaterDeclareProcedure extends Eater {
private TFunctionImpl function;
private final LineLocation location;
private final StringLocated location;
private boolean finalFlag;
public EaterDeclareProcedure(StringLocated s) {
super(s.getTrimmed());
this.location = s.getLocation();
this.location = s;
}
@Override

View File

@ -35,17 +35,16 @@
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.utils.LineLocation;
public class EaterDeclareReturnFunction extends Eater {
private TFunctionImpl function;
private final LineLocation location;
private final StringLocated location;
private boolean finalFlag;
public EaterDeclareReturnFunction(StringLocated s) {
super(s.getTrimmed());
this.location = s.getLocation();
this.location = s;
}
@Override

View File

@ -40,16 +40,16 @@ public class EaterException extends Exception {
private final String message;
private EaterException(String message) {
private EaterException(String message, StringLocated location) {
this.message = message;
}
public static EaterException unlocated(String message) {
return new EaterException(message);
public static EaterException unlocated(String message, StringLocated location) {
return new EaterException(message, location);
}
public static EaterException located(String message) {
return unlocated(message);
public static EaterException located(String message, StringLocated location) {
return unlocated(message, location);
}
public final String getMessage() {

View File

@ -100,12 +100,12 @@ public class EaterFunctionCall extends Eater {
checkAndEatChar('=');
skipSpaces();
final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace();
tokens.guessFunctions();
tokens.guessFunctions(getStringLocated());
final TValue result = tokens.getResult(getStringLocated(), context, memory);
namedArguments.put(varname, result);
} else {
final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace();
tokens.guessFunctions();
tokens.guessFunctions(getStringLocated());
final TValue result = tokens.getResult(getStringLocated(), context, memory);
values.add(result);
}
@ -119,9 +119,9 @@ public class EaterFunctionCall extends Eater {
break;
}
if (unquoted) {
throw EaterException.located("unquoted function/procedure cannot use expression.");
throw EaterException.located("unquoted function/procedure cannot use expression.", getStringLocated());
}
throw EaterException.located("call001");
throw EaterException.located("call001", getStringLocated());
}
}

View File

@ -39,7 +39,7 @@ import net.sourceforge.plantuml.text.StringLocated;
public class EaterInclude extends Eater {
private String location;
private String what;
private PreprocessorIncludeStrategy strategy = PreprocessorIncludeStrategy.DEFAULT;
public EaterInclude(StringLocated s) {
@ -65,15 +65,15 @@ public class EaterInclude extends Eater {
}
}
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory,
this.what = context.applyFunctionsAndVariables(memory,
new StringLocated(this.eatAllToEnd(), getLineLocation()));
// final TValue value = eatExpression(context, memory);
// this.location = value.toString();
}
public final String getLocation() {
return location;
public final String getWhat() {
return what;
}
public final PreprocessorIncludeStrategy getPreprocessorIncludeStrategy() {

View File

@ -38,7 +38,7 @@ import net.sourceforge.plantuml.text.StringLocated;
public class EaterIncludesub extends Eater {
private String location;
private String what;
public EaterIncludesub(StringLocated s) {
super(s);
@ -49,13 +49,13 @@ public class EaterIncludesub extends Eater {
skipSpaces();
checkAndEatChar("!includesub");
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory,
this.what = context.applyFunctionsAndVariables(memory,
new StringLocated(this.eatAllToEnd(), getLineLocation()));
}
public final String getLocation() {
return location;
public final String getWhat() {
return what;
}
}

View File

@ -49,7 +49,7 @@ public class EaterLegacyDefine extends Eater {
skipSpaces();
checkAndEatChar("!define");
skipSpaces();
function = eatDeclareFunction(context, memory, true, getLineLocation(), false, TFunctionType.LEGACY_DEFINE);
function = eatDeclareFunction(context, memory, true, getStringLocated(), false, TFunctionType.LEGACY_DEFINE);
final String def = this.eatAllToEnd();
// function.setFunctionType(TFunctionType.LEGACY_DEFINE);
function.setLegacyDefinition(def);

View File

@ -49,7 +49,7 @@ public class EaterLegacyDefineLong extends Eater {
skipSpaces();
checkAndEatChar("!definelong");
skipSpaces();
function = eatDeclareFunction(context, memory, true, getLineLocation(), true, TFunctionType.LEGACY_DEFINELONG);
function = eatDeclareFunction(context, memory, true, getStringLocated(), true, TFunctionType.LEGACY_DEFINELONG);
// function.setFunctionType(TFunctionType.LEGACY_DEFINELONG);
}

View File

@ -50,9 +50,9 @@ public class EaterStartsub extends Eater {
checkAndEatChar("!startsub");
skipSpaces();
this.subname = eatAllToEnd();
if (this.subname.matches("\\w+") == false) {
throw EaterException.located("Bad sub name");
}
if (this.subname.matches("\\w+") == false)
throw EaterException.located("Bad sub name", getStringLocated());
}
public final String getSubname() {

View File

@ -101,24 +101,24 @@ public class EaterTheme extends Eater {
} catch (IOException e) {
Logme.error(e);
}
throw EaterException.located("Cannot load " + realName);
throw EaterException.located("Cannot load " + realName, getStringLocated());
}
if (from.startsWith("<") && from.endsWith(">")) {
final ReadLine reader = ThemeUtils.getReaderTheme(realName, from);
if (reader == null)
throw EaterException.located("No such theme " + realName + " in " + from);
throw EaterException.located("No such theme " + realName + " in " + from, getStringLocated());
return reader;
} else if (from.startsWith("http://") || from.startsWith("https://")) {
final SURL url = SURL.create(ThemeUtils.getFullPath(from, realName));
if (url == null)
throw EaterException.located("Cannot open URL");
throw EaterException.located("Cannot open URL", getStringLocated());
try {
return PreprocessorUtils.getReaderInclude(url, getLineLocation(), UTF_8);
return PreprocessorUtils.getReaderInclude(url, getStringLocated(), UTF_8);
} catch (UnsupportedEncodingException e) {
Logme.error(e);
throw EaterException.located("Cannot decode charset");
throw EaterException.located("Cannot decode charset", getStringLocated());
}
}
@ -126,12 +126,12 @@ public class EaterTheme extends Eater {
final FileWithSuffix file = context.getFileWithSuffix(from, realName);
final Reader tmp = file.getReader(UTF_8);
if (tmp == null)
throw EaterException.located("No such theme " + realName);
throw EaterException.located("No such theme " + realName, getStringLocated());
return ReadLineReader.create(tmp, "theme " + realName);
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("Cannot load " + realName);
throw EaterException.located("Cannot load " + realName, getStringLocated());
}
}

View File

@ -51,16 +51,16 @@ public class FunctionsSet {
public TFunction getFunctionSmart(TFunctionSignature searched) {
final TFunction func = this.functions.get(searched);
if (func != null) {
if (func != null)
return func;
}
for (TFunction candidate : this.functions.values()) {
if (candidate.getSignature().sameFunctionNameAs(searched) == false) {
if (candidate.getSignature().sameFunctionNameAs(searched) == false)
continue;
}
if (candidate.canCover(searched.getNbArg(), searched.getNamedArguments())) {
if (candidate.canCover(searched.getNbArg(), searched.getNamedArguments()))
return candidate;
}
}
return null;
}
@ -82,9 +82,9 @@ public class FunctionsSet {
}
public void addFunction(TFunction func) {
if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) {
if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG)
((TFunctionImpl) func).finalizeEnddefinelong();
}
this.functions.put(func.getSignature(), func);
this.functions3.add(func.getSignature().getFunctionName() + "(");
}
@ -96,9 +96,9 @@ public class FunctionsSet {
public void executeLegacyDefine(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0048");
}
if (this.pendingFunction != null)
throw EaterException.located("already0048", s);
final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s);
legacyDefine.analyze(context, memory);
final TFunction function = legacyDefine.getFunction();
@ -108,9 +108,9 @@ public class FunctionsSet {
public void executeLegacyDefineLong(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0068");
}
if (this.pendingFunction != null)
throw EaterException.located("already0068", s);
final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s);
legacyDefineLong.analyze(context, memory);
this.pendingFunction = legacyDefineLong.getFunction();
@ -118,48 +118,48 @@ public class FunctionsSet {
public void executeDeclareReturnFunction(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0068");
}
if (this.pendingFunction != null)
throw EaterException.located("already0068", s);
final EaterDeclareReturnFunction declareFunction = new EaterDeclareReturnFunction(s);
declareFunction.analyze(context, memory);
final boolean finalFlag = declareFunction.getFinalFlag();
final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature();
final TFunction previous = this.functions.get(declaredSignature);
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature))) {
throw EaterException.located("This function is already defined");
}
if (finalFlag) {
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature)))
throw EaterException.located("This function is already defined", s);
if (finalFlag)
this.functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) {
if (declareFunction.getFunction().hasBody())
this.addFunction(declareFunction.getFunction());
} else {
else
this.pendingFunction = declareFunction.getFunction();
}
}
public void executeDeclareProcedure(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0068");
}
if (this.pendingFunction != null)
throw EaterException.located("already0068", s);
final EaterDeclareProcedure declareFunction = new EaterDeclareProcedure(s);
declareFunction.analyze(context, memory);
final boolean finalFlag = declareFunction.getFinalFlag();
final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature();
final TFunction previous = this.functions.get(declaredSignature);
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature))) {
throw EaterException.located("This function is already defined");
}
if (finalFlag) {
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature)))
throw EaterException.located("This function is already defined", s);
if (finalFlag)
this.functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) {
if (declareFunction.getFunction().hasBody())
this.addFunction(declareFunction.getFunction());
} else {
else
this.pendingFunction = declareFunction.getFunction();
}
}
}

View File

@ -322,7 +322,7 @@ public class TContext {
if (e instanceof EaterExceptionLocated)
throw (EaterExceptionLocated) e;
Logme.error(e);
throw EaterException.located("Fatal parsing error");
throw EaterException.located("Fatal parsing error", s);
}
}
@ -382,7 +382,7 @@ public class TContext {
} else if (s.getString().matches("^\\s+$")) {
return null;
} else {
throw EaterException.located("Compile Error " + ftype + " " + type);
throw EaterException.located("Compile Error " + ftype + " " + type, s);
}
}
@ -465,7 +465,7 @@ public class TContext {
call.getNamedArguments().keySet());
final TFunction function = functionsSet.getFunctionSmart(signature);
if (function == null)
throw EaterException.located("Function not found " + presentFunction);
throw EaterException.located("Function not found " + presentFunction, str);
if (function.getFunctionType() == TFunctionType.PROCEDURE) {
this.pendingAdd = result.toString();
@ -488,8 +488,8 @@ public class TContext {
call.getNamedArguments());
result.append(functionReturn.toString());
i += call.getCurrentPosition() - 1;
} else if (new VariableManager(this, memory, str.getLocation()).getVarnameAt(str.getString(), i) != null) {
i = new VariableManager(this, memory, str.getLocation()).replaceVariables(str.getString(), i, result);
} else if (new VariableManager(this, memory, str).getVarnameAt(str.getString(), i) != null) {
i = new VariableManager(this, memory, str).replaceVariables(str.getString(), i, result);
} else {
result.append(c);
}
@ -512,18 +512,18 @@ public class TContext {
_import.analyze(this, memory);
try {
final SFile file = FileSystem.getInstance().getFile(
applyFunctionsAndVariables(memory, new StringLocated(_import.getWhat(), s.getLocation())));
final SFile file = FileSystem.getInstance()
.getFile(applyFunctionsAndVariables(memory, new StringLocated(_import.getWhat(), s.getLocation())));
if (file.exists() && file.isDirectory() == false) {
importedFiles.add(file);
return;
}
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("Cannot import " + e.getMessage());
throw EaterException.located("Cannot import " + e.getMessage(), s);
}
throw EaterException.located("Cannot import");
throw EaterException.located("Cannot import", s);
}
private void executeLog(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
@ -543,12 +543,12 @@ public class TContext {
try {
final EaterIncludesub include = new EaterIncludesub(s.getTrimmed());
include.analyze(this, memory);
final String location = include.getLocation();
final int idx = location.indexOf('!');
final String what = include.getWhat();
final int idx = what.indexOf('!');
Sub sub = null;
if (idx != -1) {
final String filename = location.substring(0, idx);
final String blocname = location.substring(idx + 1);
final String filename = what.substring(0, idx);
final String blocname = what.substring(idx + 1);
try {
final FileWithSuffix f2 = importedFiles.getFile(filename, null);
if (f2.fileOk()) {
@ -556,10 +556,10 @@ public class TContext {
this.importedFiles = this.importedFiles.withCurrentDir(f2.getParentFile());
final Reader reader = f2.getReader(charset);
if (reader == null)
throw EaterException.located("cannot include " + location);
throw EaterException.located("cannot include " + what, s);
try {
ReadLine readerline = ReadLineReader.create(reader, location, s.getLocation());
ReadLine readerline = ReadLineReader.create(reader, what, s.getLocation());
readerline = new UncommentReadLine(readerline);
sub = Sub.fromFile(readerline, blocname, this, memory);
} finally {
@ -568,14 +568,14 @@ public class TContext {
}
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("cannot include " + location);
throw EaterException.located("cannot include " + what, s);
}
}
if (sub == null)
sub = subs.get(location);
sub = subs.get(what);
if (sub == null)
throw EaterException.located("cannot include " + location);
throw EaterException.located("cannot include " + what, s);
executeLinesInternal(memory, sub.lines(), null);
} finally {
@ -604,7 +604,7 @@ public class TContext {
} while (true);
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("" + e);
throw EaterException.located("" + e, s);
} finally {
try {
reader2.close();
@ -619,7 +619,7 @@ public class TContext {
eater.analyze(this, memory);
final ReadLine reader = eater.getTheme();
if (reader == null)
throw EaterException.located("No such theme " + eater.getName());
throw EaterException.located("No such theme " + eater.getName(), s);
try {
final List<StringLocated> body = new ArrayList<>();
@ -633,7 +633,7 @@ public class TContext {
} while (true);
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("Error reading theme " + e);
throw EaterException.located("Error reading theme " + e, s);
} finally {
try {
reader.close();
@ -646,7 +646,7 @@ public class TContext {
private void executeInclude(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterInclude include = new EaterInclude(s.getTrimmed());
include.analyze(this, memory);
String location = include.getLocation();
String location = include.getWhat();
final PreprocessorIncludeStrategy strategy = include.getPreprocessorIncludeStrategy();
final int idx = location.lastIndexOf('!');
String suf = null;
@ -661,7 +661,7 @@ public class TContext {
if (location.startsWith("http://") || location.startsWith("https://")) {
final SURL url = SURL.create(location);
if (url == null)
throw EaterException.located("Cannot open URL");
throw EaterException.located("Cannot open URL", s);
reader = PreprocessorUtils.getReaderIncludeUrl(url, s, suf, charset);
} else if (location.startsWith("<") && location.endsWith(">")) {
@ -677,14 +677,14 @@ public class TContext {
return;
if (strategy == PreprocessorIncludeStrategy.ONCE && filesUsedCurrent.contains(f2))
throw EaterException.located("This file has already been included");
throw EaterException.located("This file has already been included", s);
if (StartDiagramExtractReader.containsStartDiagram(f2, s, charset)) {
reader = StartDiagramExtractReader.build(f2, s, charset);
} else {
final Reader tmp = f2.getReader(charset);
if (tmp == null)
throw EaterException.located("Cannot include file");
throw EaterException.located("Cannot include file", s);
reader = ReadLineReader.create(tmp, location, s.getLocation());
}
@ -713,7 +713,7 @@ public class TContext {
}
} catch (IOException e) {
Logme.error(e);
throw EaterException.located("cannot include " + e);
throw EaterException.located("cannot include " + e, s);
} finally {
if (reader != null) {
try {
@ -724,7 +724,7 @@ public class TContext {
}
}
throw EaterException.located("cannot include " + location);
throw EaterException.located("cannot include " + location, s);
}
public boolean isLegacyDefine(String functionName) {

View File

@ -148,12 +148,12 @@ public class TFunctionImpl implements TFunction {
return executeReturnLegacyDefine(location.getLocation(), context, memory, args);
if (functionType != TFunctionType.RETURN_FUNCTION)
throw EaterException.unlocated("Illegal call here. Is there a return directive in your function?");
throw EaterException.unlocated("Illegal call here. Is there a return directive in your function?", location);
final TMemory copy = getNewMemory(memory, args, named);
final TValue result = context.executeLines(copy, body, TFunctionType.RETURN_FUNCTION, true);
if (result == null)
throw EaterException.unlocated("No return directive found in your function");
throw EaterException.unlocated("No return directive found in your function", location);
return result;
}

View File

@ -37,13 +37,15 @@ package net.sourceforge.plantuml.tim;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public interface TMemory {
public TValue getVariable(String varname);
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException;
public void putVariable(String varname, TValue value, TVariableScope scope, StringLocated location)
throws EaterException;
public void removeVariable(String varname);

View File

@ -41,6 +41,7 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.utils.Log;
@ -49,10 +50,12 @@ public class TMemoryGlobal extends ExecutionContexts implements TMemory {
private final Map<String, TValue> globalVariables = new HashMap<String, TValue>();
private final TrieImpl variables = new TrieImpl();
@Override
public TValue getVariable(String varname) {
return this.globalVariables.get(varname);
}
@Override
public void dumpDebug(String message) {
Log.error("[MemGlobal] Start of memory_dump " + message);
dumpMemoryInternal();
@ -68,32 +71,39 @@ public class TMemoryGlobal extends ExecutionContexts implements TMemory {
}
}
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException {
@Override
public void putVariable(String varname, TValue value, TVariableScope scope, StringLocated location)
throws EaterException {
Log.info("[MemGlobal] Setting " + varname);
if (scope == TVariableScope.LOCAL) {
throw EaterException.unlocated("Cannot use local variable here");
}
if (scope == TVariableScope.LOCAL)
throw EaterException.unlocated("Cannot use local variable here", location);
this.globalVariables.put(varname, value);
this.variables.add(varname);
}
@Override
public void removeVariable(String varname) {
this.globalVariables.remove(varname);
this.variables.remove(varname);
}
@Override
public boolean isEmpty() {
return globalVariables.isEmpty();
}
@Override
public Set<String> variablesNames() {
return Collections.unmodifiableSet(globalVariables.keySet());
}
@Override
public Trie variablesNames3() {
return variables;
}
@Override
public TMemory forkFromGlobal(Map<String, TValue> input) {
return new TMemoryLocal(this, input);
}

View File

@ -40,6 +40,7 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.utils.Log;
@ -76,19 +77,21 @@ public class TMemoryLocal extends ExecutionContexts implements TMemory {
Log.error("[MemGlobal] End of memory_dump");
}
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException {
@Override
public void putVariable(String varname, TValue value, TVariableScope scope, StringLocated location)
throws EaterException {
if (scope == TVariableScope.GLOBAL) {
memoryGlobal.putVariable(varname, value, scope);
memoryGlobal.putVariable(varname, value, scope, location);
return;
}
if (scope == TVariableScope.LOCAL || overridenVariables01.containsKey(varname)) {
this.overridenVariables01.put(varname, value);
if (this.overridenVariables00 != null) {
if (this.overridenVariables00 != null)
this.overridenVariables00.add(varname);
}
Log.info("[MemLocal/overrriden] Setting " + varname);
} else if (memoryGlobal.getVariable(varname) != null) {
memoryGlobal.putVariable(varname, value, scope);
memoryGlobal.putVariable(varname, value, scope, location);
} else {
this.localVariables01.put(varname, value);
this.localVariables00.add(varname);
@ -96,12 +99,13 @@ public class TMemoryLocal extends ExecutionContexts implements TMemory {
}
}
@Override
public void removeVariable(String varname) {
if (overridenVariables01.containsKey(varname)) {
this.overridenVariables01.remove(varname);
if (this.overridenVariables00 != null) {
if (this.overridenVariables00 != null)
this.overridenVariables00.remove(varname);
}
} else if (memoryGlobal.getVariable(varname) != null) {
memoryGlobal.removeVariable(varname);
} else {
@ -110,25 +114,27 @@ public class TMemoryLocal extends ExecutionContexts implements TMemory {
}
}
@Override
public TValue getVariable(String varname) {
TValue result = overridenVariables01.get(varname);
if (result != null) {
if (result != null)
return result;
}
result = memoryGlobal.getVariable(varname);
if (result != null) {
if (result != null)
return result;
}
result = localVariables01.get(varname);
return result;
}
@Override
public Trie variablesNames3() {
if (overridenVariables00 == null) {
overridenVariables00 = new TrieImpl();
for (String name : overridenVariables01.keySet()) {
for (String name : overridenVariables01.keySet())
overridenVariables00.add(name);
}
}
return new Trie() {
public void add(String s) {
@ -140,12 +146,12 @@ public class TMemoryLocal extends ExecutionContexts implements TMemory {
final String s2 = overridenVariables00.getLonguestMatchStartingIn(s);
final String s3 = localVariables00.getLonguestMatchStartingIn(s);
if (s1.length() >= s2.length() && s1.length() >= s3.length()) {
if (s1.length() >= s2.length() && s1.length() >= s3.length())
return s1;
}
if (s2.length() >= s3.length() && s2.length() >= s1.length()) {
if (s2.length() >= s3.length() && s2.length() >= s1.length())
return s2;
}
return s3;
}
};
@ -162,14 +168,17 @@ public class TMemoryLocal extends ExecutionContexts implements TMemory {
// return result;
}
@Override
public boolean isEmpty() {
return memoryGlobal.isEmpty() && localVariables01.isEmpty() && overridenVariables01.isEmpty();
}
@Override
public Set<String> variablesNames() {
throw new UnsupportedOperationException();
}
@Override
public TMemory forkFromGlobal(Map<String, TValue> input) {
return new TMemoryLocal(memoryGlobal, input);
}

View File

@ -53,10 +53,10 @@ public class TimLoader {
private List<StringLocated> resultList;
public TimLoader(ImportedFiles importedFiles, Defines defines, Charset charset,
DefinitionsContainer definitionsContainer) {
DefinitionsContainer definitionsContainer, StringLocated location) {
this.context = new TContext(importedFiles, defines, charset, definitionsContainer);
try {
defines.copyTo(global);
defines.copyTo(global, location);
} catch (EaterException e) {
Logme.error(e);
}

View File

@ -46,9 +46,9 @@ public class VariableManager {
private final TMemory memory;
private final TContext context;
private final LineLocation location;
private final StringLocated location;
public VariableManager(TContext context, TMemory memory, LineLocation location) {
public VariableManager(TContext context, TMemory memory, StringLocated location) {
this.memory = memory;
this.context = context;
this.location = location;
@ -56,9 +56,9 @@ public class VariableManager {
public int replaceVariables(String str, int i, StringBuilder result) throws EaterException, EaterExceptionLocated {
final String presentVariable = getVarnameAt(str, i);
if (result.toString().endsWith("##")) {
if (result.toString().endsWith("##"))
result.setLength(result.length() - 2);
}
final TValue value = memory.getVariable(presentVariable);
i += presentVariable.length() - 1;
if (value.isJson()) {
@ -75,9 +75,9 @@ public class VariableManager {
} else {
result.append(value.toString());
}
if (i + 2 < str.length() && str.charAt(i + 1) == '#' && str.charAt(i + 2) == '#') {
if (i + 2 < str.length() && str.charAt(i + 1) == '#' && str.charAt(i + 2) == '#')
i += 2;
}
return i;
}
@ -89,9 +89,9 @@ public class VariableManager {
i++;
final StringBuilder fieldName = new StringBuilder();
while (i < str.length()) {
if (Character.isJavaIdentifierPart(str.charAt(i)) == false) {
if (Character.isJavaIdentifierPart(str.charAt(i)) == false)
break;
}
fieldName.append(str.charAt(i));
i++;
}
@ -101,9 +101,9 @@ public class VariableManager {
final StringBuilder inBracket = new StringBuilder();
int level = 0;
while (true) {
if (str.charAt(i) == '[') {
if (str.charAt(i) == '[')
level++;
}
if (str.charAt(i) == ']') {
if (level == 0)
break;
@ -113,29 +113,29 @@ public class VariableManager {
i++;
}
final String nbString = context.applyFunctionsAndVariables(memory,
new StringLocated(inBracket.toString(), location));
new StringLocated(inBracket.toString(), location.getLocation()));
if (jsonValue instanceof JsonArray) {
final int nb = Integer.parseInt(nbString);
jsonValue = ((JsonArray) jsonValue).get(nb);
} else if (jsonValue instanceof JsonObject) {
jsonValue = ((JsonObject) jsonValue).get(nbString);
} else {
throw EaterException.unlocated("Major parsing error");
}
if (jsonValue == null) {
throw EaterException.unlocated("Data parsing error");
throw EaterException.unlocated("Major parsing error", location);
}
if (jsonValue == null)
throw EaterException.unlocated("Data parsing error", location);
i++;
} else {
break;
}
}
if (jsonValue != null) {
if (jsonValue.isString()) {
if (jsonValue.isString())
result.append(jsonValue.asString());
} else {
else
result.append(jsonValue.toString());
}
}
return i;
}
@ -146,13 +146,13 @@ public class VariableManager {
return null;
}
final String varname = memory.variablesNames3().getLonguestMatchStartingIn(s.substring(pos));
if (varname.length() == 0) {
if (varname.length() == 0)
return null;
}
if (pos + varname.length() == s.length()
|| TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos + varname.length())) == false) {
|| TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos + varname.length())) == false)
return varname;
}
return null;
}

View File

@ -47,18 +47,12 @@ import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunction;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.utils.LineLocation;
public class ReversePolishInterpretor {
private final TValue result;
private final boolean trace = false;
public ReversePolishInterpretor(TokenStack queue, Knowledge knowledge, TMemory memory, TContext context)
throws EaterException, EaterExceptionLocated {
this(null, queue, knowledge, memory, context);
}
public ReversePolishInterpretor(StringLocated location, TokenStack queue, Knowledge knowledge, TMemory memory,
TContext context) throws EaterException, EaterExceptionLocated {
@ -79,45 +73,45 @@ public class ReversePolishInterpretor {
final TValue v2 = stack.removeFirst();
final TValue v1 = stack.removeFirst();
final TokenOperator op = token.getTokenOperator();
if (op == null) {
throw EaterException.unlocated("bad op");
}
if (op == null)
throw EaterException.unlocated("bad op", location);
final TValue tmp = op.operate(v1, v2);
stack.addFirst(tmp);
} else if (token.getTokenType() == TokenType.OPEN_PAREN_FUNC) {
final int nb = Integer.parseInt(token.getSurface());
final Token token2 = it.nextToken();
if (token2.getTokenType() != TokenType.FUNCTION_NAME) {
throw EaterException.unlocated("rpn43");
}
if (token2.getTokenType() != TokenType.FUNCTION_NAME)
throw EaterException.unlocated("rpn43", location);
if (trace)
System.err.println("token2=" + token2);
final TFunction function = knowledge.getFunction(new TFunctionSignature(token2.getSurface(), nb));
if (trace)
System.err.println("function=" + function);
if (function == null) {
throw EaterException.unlocated("Unknown built-in function " + token2.getSurface());
}
if (function.canCover(nb, Collections.<String>emptySet()) == false) {
throw EaterException
.unlocated("Bad number of arguments for " + function.getSignature().getFunctionName());
}
if (function == null)
throw EaterException.unlocated("Unknown built-in function " + token2.getSurface(), location);
if (function.canCover(nb, Collections.<String>emptySet()) == false)
throw EaterException.unlocated(
"Bad number of arguments for " + function.getSignature().getFunctionName(), location);
final List<TValue> args = new ArrayList<>();
for (int i = 0; i < nb; i++) {
for (int i = 0; i < nb; i++)
args.add(0, stack.removeFirst());
}
if (trace)
System.err.println("args=" + args);
if (location == null) {
throw EaterException.unlocated("rpn44");
}
if (location == null)
throw EaterException.unlocated("rpn44", location);
final TValue r = function.executeReturnFunction(context, memory, location, args,
Collections.<String, TValue>emptyMap());
if (trace)
System.err.println("r=" + r);
stack.addFirst(r);
} else {
throw EaterException.unlocated("rpn41");
throw EaterException.unlocated("rpn41", location);
}
}
result = stack.removeFirst();

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.tim.expression;
import java.util.ArrayDeque;
import java.util.Deque;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
@ -58,7 +59,8 @@ public class ShuntingYard {
System.err.println("");
}
public ShuntingYard(TokenIterator it, Knowledge knowledge) throws EaterException, EaterExceptionLocated {
public ShuntingYard(TokenIterator it, Knowledge knowledge, StringLocated location)
throws EaterException, EaterExceptionLocated {
while (it.hasMoreTokens()) {
final Token token = it.nextToken();
@ -74,7 +76,7 @@ public class ShuntingYard {
final TValue variable = knowledge.getVariable(name);
if (variable == null) {
if (isVariableName(name) == false)
throw EaterException.unlocated("Parsing syntax error about " + name);
throw EaterException.unlocated("Parsing syntax error about " + name, location);
ouputQueue.add(new Token(name, TokenType.QUOTED_STRING, null));
} else {

View File

@ -48,7 +48,6 @@ import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.utils.LineLocation;
public class TokenStack {
@ -96,7 +95,7 @@ public class TokenStack {
eater.skipSpaces();
final char ch = eater.peekChar();
if (ch == 0)
throw EaterException.unlocated("until001");
throw EaterException.unlocated("until001", eater.getStringLocated());
if (level == 0 && (ch == ',' || ch == ')'))
return result;
@ -114,12 +113,12 @@ public class TokenStack {
}
}
static public void eatUntilCloseParenthesisOrComma(TokenIterator it) throws EaterException {
static public void eatUntilCloseParenthesisOrComma(TokenIterator it, StringLocated location) throws EaterException {
int level = 0;
while (true) {
final Token ch = it.peekToken();
if (ch == null)
throw EaterException.unlocated("until002");
throw EaterException.unlocated("until002", location);
final TokenType typech = ch.getTokenType();
if (level == 0 && (typech == TokenType.COMMA || typech == TokenType.CLOSE_PAREN_MATH)
@ -136,7 +135,7 @@ public class TokenStack {
}
}
private int countFunctionArg(TokenIterator it) throws EaterException {
private int countFunctionArg(TokenIterator it, StringLocated location) throws EaterException {
// return 42;
final TokenType type1 = it.peekToken().getTokenType();
if (type1 == TokenType.CLOSE_PAREN_MATH || type1 == TokenType.CLOSE_PAREN_FUNC)
@ -144,7 +143,7 @@ public class TokenStack {
int result = 1;
while (it.hasMoreTokens()) {
eatUntilCloseParenthesisOrComma(it);
eatUntilCloseParenthesisOrComma(it, location);
final Token token = it.nextToken();
final TokenType type = token.getTokenType();
if (type == TokenType.CLOSE_PAREN_MATH || type == TokenType.CLOSE_PAREN_FUNC)
@ -152,13 +151,13 @@ public class TokenStack {
else if (type == TokenType.COMMA)
result++;
else
throw EaterException.unlocated("count13");
throw EaterException.unlocated("count13", location);
}
throw EaterException.unlocated("count12");
throw EaterException.unlocated("count12", location);
}
public void guessFunctions() throws EaterException {
public void guessFunctions(StringLocated location) throws EaterException {
final Deque<Integer> open = new ArrayDeque<>();
final Map<Integer, Integer> parens = new HashMap<Integer, Integer>();
for (int i = 0; i < tokens.size(); i++) {
@ -178,7 +177,7 @@ public class TokenStack {
assert tokens.get(iclose).getTokenType() == TokenType.CLOSE_PAREN_MATH;
if (iopen > 0 && tokens.get(iopen - 1).getTokenType() == TokenType.PLAIN_TEXT) {
tokens.set(iopen - 1, new Token(tokens.get(iopen - 1).getSurface(), TokenType.FUNCTION_NAME, null));
final int nbArg = countFunctionArg(subTokenStack(iopen + 1).tokenIterator());
final int nbArg = countFunctionArg(subTokenStack(iopen + 1).tokenIterator(), location);
tokens.set(iopen, new Token("" + nbArg, TokenType.OPEN_PAREN_FUNC, null));
tokens.set(iclose, new Token(")", TokenType.CLOSE_PAREN_FUNC, null));
}
@ -215,9 +214,9 @@ public class TokenStack {
throws EaterException, EaterExceptionLocated {
final Knowledge knowledge = context.asKnowledge(memory, location.getLocation());
final TokenStack tmp = withoutSpace();
tmp.guessFunctions();
tmp.guessFunctions(location);
final TokenIterator it = tmp.tokenIterator();
final ShuntingYard shuntingYard = new ShuntingYard(it, knowledge);
final ShuntingYard shuntingYard = new ShuntingYard(it, knowledge, location);
final ReversePolishInterpretor rpn = new ReversePolishInterpretor(location, shuntingYard.getQueue(), knowledge,
memory, context);
return rpn.getResult();

View File

@ -34,6 +34,7 @@
*/
package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
@ -45,16 +46,19 @@ public abstract class AbstractCodeIterator implements CodeIterator {
this.source = source;
}
@Override
public void next() throws EaterException, EaterExceptionLocated {
source.next();
}
@Override
final public CodePosition getCodePosition() {
return source.getCodePosition();
}
final public void jumpToCodePosition(CodePosition newPosition) throws EaterException {
source.jumpToCodePosition(newPosition);
@Override
final public void jumpToCodePosition(CodePosition newPosition, StringLocated location) throws EaterException {
source.jumpToCodePosition(newPosition, location);
}
}

View File

@ -39,7 +39,7 @@ import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
public interface CodeIterator {
// ::remove folder when __HAXE__
// ::remove folder when __HAXE__
public StringLocated peek() throws EaterException, EaterExceptionLocated;
@ -47,6 +47,6 @@ public interface CodeIterator {
public CodePosition getCodePosition();
public void jumpToCodePosition(CodePosition newPosition) throws EaterException;
public void jumpToCodePosition(CodePosition newPosition, StringLocated location) throws EaterException;
}

View File

@ -58,6 +58,7 @@ public class CodeIteratorAffectation extends AbstractCodeIterator {
this.logs = log;
}
@Override
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
@ -81,9 +82,9 @@ public class CodeIteratorAffectation extends AbstractCodeIterator {
this.executeAffectation(context, memory, result);
return;
} catch (ParseException e) {
if (e.getColumn() <= lastLocation) {
throw EaterException.located("Error in JSON format");
}
if (e.getColumn() <= lastLocation)
throw EaterException.located("Error in JSON format", result);
lastLocation = e.getColumn();
next();
final StringLocated forward = source.peek();

View File

@ -65,9 +65,8 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
int level = 0;
while (true) {
final StringLocated result = source.peek();
if (result == null) {
if (result == null)
return null;
}
final ExecutionContextForeach foreach = memory.peekForeach();
if (foreach != null && foreach.isSkipMe()) {
@ -91,15 +90,15 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
continue;
} else if (result.getType() == TLineType.ENDFOREACH) {
logs.add(result);
if (foreach == null) {
throw EaterException.located("No foreach related to this endforeach");
}
if (foreach == null)
throw EaterException.located("No foreach related to this endforeach", result);
foreach.inc();
if (foreach.isSkipMe()) {
memory.pollForeach();
} else {
setLoopVariable(memory, foreach, result);
source.jumpToCodePosition(foreach.getStartForeach());
source.jumpToCodePosition(foreach.getStartForeach(), result);
}
next();
continue;
@ -114,18 +113,18 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
condition.analyze(context, memory);
final ExecutionContextForeach foreach = ExecutionContextForeach.fromValue(condition.getVarname(),
condition.getJsonArray(), source.getCodePosition());
if (condition.isSkip()) {
if (condition.isSkip())
foreach.skipMeNow();
} else {
else
setLoopVariable(memory, foreach, s);
}
memory.addForeach(foreach);
}
private void setLoopVariable(TMemory memory, ExecutionContextForeach foreach, StringLocated position)
throws EaterException {
final JsonValue first = foreach.getJsonArray().get(foreach.currentIndex());
memory.putVariable(foreach.getVarname(), TValue.fromJson(first), TVariableScope.GLOBAL);
memory.putVariable(foreach.getVarname(), TValue.fromJson(first), TVariableScope.GLOBAL, position);
}
}

View File

@ -118,18 +118,17 @@ public class CodeIteratorIf extends AbstractCodeIterator {
private void executeElseIf(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf();
if (poll == null) {
throw EaterException.located("No if related to this else");
}
if (poll == null)
throw EaterException.located("No if related to this else", s);
poll.enteringElseIf();
if (poll.hasBeenBurn() == false) {
final EaterElseIf condition = new EaterElseIf(s);
condition.analyze(context, memory);
final boolean isTrue = condition.isTrue();
if (isTrue) {
if (isTrue)
poll.nowInSomeElseIf();
}
}
}
@ -149,17 +148,17 @@ public class CodeIteratorIf extends AbstractCodeIterator {
private void executeElse(TContext context, TMemory memory, StringLocated s) throws EaterException {
final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf();
if (poll == null) {
throw EaterException.located("No if related to this else");
}
if (poll == null)
throw EaterException.located("No if related to this else", s);
poll.nowInElse();
}
private void executeEndif(TContext context, TMemory memory, StringLocated s) throws EaterException {
final ExecutionContextIf poll = (ExecutionContextIf) memory.pollIf();
if (poll == null) {
throw EaterException.located("No if related to this endif");
}
if (poll == null)
throw EaterException.located("No if related to this endif", s);
}
}

View File

@ -62,34 +62,38 @@ public class CodeIteratorImpl implements CodeIterator {
this.list = list;
}
@Override
public StringLocated peek() {
if (current == list.size()) {
if (current == list.size())
return null;
}
if (current > list.size()) {
if (current > list.size())
throw new IllegalStateException();
}
return list.get(current);
}
@Override
public void next() {
if (current >= list.size()) {
if (current >= list.size())
throw new IllegalStateException();
}
assert current < list.size();
current++;
assert current <= list.size();
}
@Override
public CodePosition getCodePosition() {
return new Position(current);
}
public void jumpToCodePosition(CodePosition newPosition) throws EaterException {
@Override
public void jumpToCodePosition(CodePosition newPosition, StringLocated location) throws EaterException {
this.countJump++;
if (this.countJump > 999) {
throw EaterException.unlocated("Infinite loop?");
}
if (this.countJump > 999)
throw EaterException.unlocated("Infinite loop?", location);
final Position pos = (Position) newPosition;
this.current = pos.pos;

View File

@ -67,13 +67,13 @@ public class CodeIteratorSub extends AbstractCodeIterator {
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
if (readingInProgress != null) {
if (readingInProgress != null)
return readingInProgress.peek();
}
StringLocated result = source.peek();
if (result == null) {
if (result == null)
return null;
}
if (result.getType() == TLineType.STARTSUB) {
final EaterStartsub eater = new EaterStartsub(result.getTrimmed());
eater.analyze(context, memory);
@ -83,7 +83,7 @@ public class CodeIteratorSub extends AbstractCodeIterator {
StringLocated s = null;
while ((s = source.peek()) != null) {
if (s.getType() == TLineType.STARTSUB) {
throw EaterException.located("Cannot nest sub");
throw EaterException.located("Cannot nest sub", result);
} else if (s.getType() == TLineType.ENDSUB) {
source.next();
readingInProgress = new CodeIteratorImpl(created.lines());
@ -94,9 +94,9 @@ public class CodeIteratorSub extends AbstractCodeIterator {
}
}
}
if (readingInProgress != null) {
if (readingInProgress != null)
return readingInProgress.peek();
}
return result;
}
@ -107,9 +107,9 @@ public class CodeIteratorSub extends AbstractCodeIterator {
return;
}
readingInProgress.next();
if (readingInProgress.peek() == null) {
if (readingInProgress.peek() == null)
readingInProgress = null;
}
}
}

View File

@ -64,9 +64,8 @@ public class CodeIteratorWhile extends AbstractCodeIterator {
int level = 0;
while (true) {
final StringLocated result = source.peek();
if (result == null) {
if (result == null)
return null;
}
final ExecutionContextWhile currentWhile = memory.peekWhile();
if (currentWhile != null && currentWhile.isSkipMe()) {
@ -91,14 +90,14 @@ public class CodeIteratorWhile extends AbstractCodeIterator {
} else if (result.getType() == TLineType.ENDWHILE) {
logs.add(result);
if (currentWhile == null)
throw EaterException.located("No while related to this endwhile");
throw EaterException.located("No while related to this endwhile", result);
final TValue value = currentWhile.conditionValue(result, context, memory);
if (value.toBoolean()) {
source.jumpToCodePosition(currentWhile.getStartWhile());
} else {
if (value.toBoolean())
source.jumpToCodePosition(currentWhile.getStartWhile(), result);
else
memory.pollWhile();
}
next();
continue;
}

View File

@ -65,9 +65,9 @@ public class CallUserFunction extends SimpleReturnFunction {
final List<TValue> args = values.subList(1, values.size());
final TFunctionSignature signature = new TFunctionSignature(fname, args.size());
final TFunction func = context.getFunctionSmart(signature);
if (func == null) {
throw EaterException.unlocated("Cannot find void function " + fname);
}
if (func == null)
throw EaterException.unlocated("Cannot find void function " + fname, location);
return func.executeReturnFunction(context, memory, location, args, named);
}

View File

@ -71,7 +71,7 @@ public class Darken extends SimpleReturnFunction {
color = color.darken(ratio);
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -71,10 +71,11 @@ public class DateFunction extends SimpleReturnFunction {
now = 1000L * values.get(1).toInt();
else
now = System.currentTimeMillis();
try {
return TValue.fromString(new SimpleDateFormat(format).format(now));
} catch (Exception e) {
throw EaterException.unlocated("Bad date pattern");
throw EaterException.unlocated("Bad date pattern", location);
}
}
}

View File

@ -99,7 +99,8 @@ public class GetAllStdlib extends SimpleReturnFunction {
}
default:
throw EaterException.located("Error on get_all_stdlib: Too many arguments");
assert false; // Should not append because of canCover()
throw EaterException.located("Error on get_all_stdlib: Too many arguments", location);
}
}
}

View File

@ -65,7 +65,8 @@ public class GetJsonKey extends SimpleReturnFunction {
Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final TValue data = values.get(0);
if (data.isJson() == false)
throw EaterException.unlocated("Not JSON data");
throw EaterException.unlocated("Not JSON data", location);
final JsonValue json = data.toJson();
if (json.isObject()) {
final JsonObject object = (JsonObject) json;
@ -87,7 +88,7 @@ public class GetJsonKey extends SimpleReturnFunction {
return TValue.fromJson(result);
}
throw EaterException.unlocated("Bad JSON type");
throw EaterException.unlocated("Bad JSON type", location);
}

View File

@ -71,7 +71,7 @@ public class InvokeProcedure implements TFunction {
final TFunctionSignature signature = new TFunctionSignature(fname, sublist.size());
final TFunction func = context.getFunctionSmart(signature);
if (func == null)
throw EaterException.located("Cannot find void function " + fname);
throw EaterException.located("Cannot find void function " + fname, location);
func.executeProcedureInternal(context, memory, location, sublist, named);
}

View File

@ -69,7 +69,7 @@ public class IsDark extends SimpleReturnFunction {
final HColor color = HColorSet.instance().getColorLEGACY(colorString);
return TValue.fromBoolean(color.isDark());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -69,7 +69,7 @@ public class IsLight extends SimpleReturnFunction {
final HColor color = HColorSet.instance().getColorLEGACY(colorString);
return TValue.fromBoolean(!color.isDark());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -71,7 +71,7 @@ public class Lighten extends SimpleReturnFunction {
color = color.lighten(ratio);
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -120,10 +120,11 @@ public class LoadJson extends SimpleReturnFunction {
return TValue.fromJson(jsonValue);
} catch (ParseException pe) {
Logme.error(pe);
throw EaterException.unlocated("JSON parse issue in source " + path + " on location " + pe.getLocation());
throw EaterException.unlocated("JSON parse issue in source " + path + " on location " + pe.getLocation(),
location);
} catch (UnsupportedEncodingException e) {
Logme.error(e);
throw EaterException.unlocated("JSON encoding issue in source " + path + ": " + e.getMessage());
throw EaterException.unlocated("JSON encoding issue in source " + path + ": " + e.getMessage(), location);
}
}

View File

@ -77,7 +77,8 @@ public class RandomFunction extends SimpleReturnFunction {
return TValue.fromInt(random.nextInt(max - min) + min);
default:
throw EaterException.located("Error on Random: Too many argument");
assert false; // Should not append because of canCover()
throw EaterException.located("Error on Random: Too many argument", location);
}
}
}

View File

@ -69,7 +69,7 @@ public class ReverseColor extends SimpleReturnFunction {
color = color.reverse();
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -69,7 +69,7 @@ public class ReverseHsluvColor extends SimpleReturnFunction {
color = color.reverseHsluv();
return TValue.fromString(color.asString());
} catch (NoSuchColorException e) {
throw EaterException.located("No such color");
throw EaterException.located("No such color", location);
}
}
}

View File

@ -66,7 +66,7 @@ public class SetVariableValue extends SimpleReturnFunction {
// }
final String name = values.get(0).toString();
final TValue value = values.get(1);
memory.putVariable(name, value, TVariableScope.GLOBAL);
memory.putVariable(name, value, TVariableScope.GLOBAL, location);
return TValue.fromString("");
}

View File

@ -46,7 +46,7 @@ public class Version {
// Warning, "version" should be the same in gradle.properties and Version.java
// Any idea anyone how to magically synchronize those :-) ?
private static final String version = "1.2024.4beta2";
private static final String version = "1.2024.4beta3";
public static String versionString() {
return version;