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 # Warning, "version" should be the same in gradle.properties and Version.java
# Any idea anyone how to magically synchronize those :-) ? # Any idea anyone how to magically synchronize those :-) ?
version = 1.2024.4beta2 version = 1.2024.4beta3
org.gradle.workers.max = 3 org.gradle.workers.max = 3

View File

@ -143,7 +143,7 @@ public class BlockUml {
this.data = new ArrayList<>(strings); this.data = new ArrayList<>(strings);
} else { } else {
final TimLoader timLoader = new TimLoader(mode.getImportedFiles(), defines, charset, final TimLoader timLoader = new TimLoader(mode.getImportedFiles(), defines, charset,
(DefinitionsContainer) mode); (DefinitionsContainer) mode, strings.get(0));
this.included.addAll(timLoader.load(strings)); this.included.addAll(timLoader.load(strings));
this.data = timLoader.getResultList(); this.data = timLoader.getResultList();
this.debug = timLoader.getDebug(); 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.SFile;
import net.sourceforge.plantuml.security.SecurityProfile; import net.sourceforge.plantuml.security.SecurityProfile;
import net.sourceforge.plantuml.security.SecurityUtils; import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException; import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.TVariableScope; import net.sourceforge.plantuml.tim.TVariableScope;
@ -81,11 +82,11 @@ public class Defines implements Truth {
return new Defines(); 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()) { for (Entry<String, Define> ent : values.entrySet()) {
final String name = ent.getKey(); final String name = ent.getKey();
final Define def = ent.getValue(); 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(); final Defines result = createEmpty();
result.overrideFilename(file.getName()); result.overrideFilename(file.getName());
result.environment.put("filedate", new Date(file.lastModified()).toString()); result.environment.put("filedate", new Date(file.lastModified()).toString());
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) { if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
result.environment.put("dirpath", result.environment.put("dirpath",
file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/')); file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/'));
}
return result; return result;
} }
@ -126,10 +127,10 @@ public class Defines implements Truth {
final Defines result = createEmpty(); final Defines result = createEmpty();
result.overrideFilename(file.getName()); result.overrideFilename(file.getName());
result.environment.put("filedate", new Date(file.lastModified()).toString()); result.environment.put("filedate", new Date(file.lastModified()).toString());
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) { if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
result.environment.put("dirpath", result.environment.put("dirpath",
file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/')); file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/'));
}
return result; return result;
} }
@ -147,9 +148,9 @@ public class Defines implements Truth {
private static String nameNoExtension(String name) { private static String nameNoExtension(String name) {
final int x = name.lastIndexOf('.'); final int x = name.lastIndexOf('.');
if (x == -1) { if (x == -1)
return name; return name;
}
return name.substring(0, x); return name.substring(0, x);
} }
@ -169,11 +170,10 @@ public class Defines implements Truth {
} }
public boolean isTrue(String name) { public boolean isTrue(String name) {
for (String key : values.keySet()) { for (String key : values.keySet())
if (key.equals(name) || key.startsWith(name + "(")) { if (key.equals(name) || key.startsWith(name + "("))
return true; return true;
}
}
return false; return false;
} }
@ -192,9 +192,9 @@ public class Defines implements Truth {
} }
private String method1(String line) { private String method1(String line) {
for (Define def : values.values()) { for (Define def : values.values())
line = def.apply(line); line = def.apply(line);
}
return line; return line;
} }
@ -215,18 +215,17 @@ public class Defines implements Truth {
private String method2(String line) { private String method2(String line) {
final Set<String> words = words(line); final Set<String> words = words(line);
if (magic == null) { if (magic == null)
magic = getAll(); magic = getAll();
}
for (String w : words) { for (String w : words) {
Collection<Define> tmp = magic.get(w); Collection<Define> tmp = magic.get(w);
if (tmp == null) { if (tmp == null)
continue; continue;
}
for (Define def : tmp) { for (Define def : tmp)
line = def.apply(line); line = def.apply(line);
}
} }
return line; return line;
} }
@ -236,9 +235,9 @@ public class Defines implements Truth {
Pattern p = Pattern.compile(ID); Pattern p = Pattern.compile(ID);
Matcher m = p.matcher(line); Matcher m = p.matcher(line);
final Set<String> words = new HashSet<>(); final Set<String> words = new HashSet<>();
while (m.find()) { while (m.find())
words.add(m.group(0)); words.add(m.group(0));
}
return words; return words;
} }

View File

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

View File

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

View File

@ -53,7 +53,7 @@ public class EaterAffectation extends Eater {
if (scope != null) { if (scope != null) {
skipSpaces(); skipSpaces();
if (peekChar() == '?' || peekChar() == '=') { 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 // way
scope = null; scope = null;
} else } else
@ -72,7 +72,7 @@ public class EaterAffectation extends Eater {
skipSpaces(); skipSpaces();
final TValue value = eatExpression(context, memory); 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) { // if (memory instanceof TMemoryLocal) {
// memory = ((TMemoryLocal) memory).getGlobalForInternalUseOnly(); // 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 == ':') { if (ch == ':') {
checkAndEatChar(':'); checkAndEatChar(':');
final TValue message = eatExpression(context, memory); 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; package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.text.StringLocated; import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.utils.LineLocation;
public class EaterDeclareProcedure extends Eater { public class EaterDeclareProcedure extends Eater {
private TFunctionImpl function; private TFunctionImpl function;
private final LineLocation location; private final StringLocated location;
private boolean finalFlag; private boolean finalFlag;
public EaterDeclareProcedure(StringLocated s) { public EaterDeclareProcedure(StringLocated s) {
super(s.getTrimmed()); super(s.getTrimmed());
this.location = s.getLocation(); this.location = s;
} }
@Override @Override

View File

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

View File

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

View File

@ -100,12 +100,12 @@ public class EaterFunctionCall extends Eater {
checkAndEatChar('='); checkAndEatChar('=');
skipSpaces(); skipSpaces();
final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace(); final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace();
tokens.guessFunctions(); tokens.guessFunctions(getStringLocated());
final TValue result = tokens.getResult(getStringLocated(), context, memory); final TValue result = tokens.getResult(getStringLocated(), context, memory);
namedArguments.put(varname, result); namedArguments.put(varname, result);
} else { } else {
final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace(); final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace();
tokens.guessFunctions(); tokens.guessFunctions(getStringLocated());
final TValue result = tokens.getResult(getStringLocated(), context, memory); final TValue result = tokens.getResult(getStringLocated(), context, memory);
values.add(result); values.add(result);
} }
@ -119,9 +119,9 @@ public class EaterFunctionCall extends Eater {
break; break;
} }
if (unquoted) { 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 { public class EaterInclude extends Eater {
private String location; private String what;
private PreprocessorIncludeStrategy strategy = PreprocessorIncludeStrategy.DEFAULT; private PreprocessorIncludeStrategy strategy = PreprocessorIncludeStrategy.DEFAULT;
public EaterInclude(StringLocated s) { public EaterInclude(StringLocated s) {
@ -65,15 +65,15 @@ public class EaterInclude extends Eater {
} }
} }
skipSpaces(); skipSpaces();
this.location = context.applyFunctionsAndVariables(memory, this.what = context.applyFunctionsAndVariables(memory,
new StringLocated(this.eatAllToEnd(), getLineLocation())); new StringLocated(this.eatAllToEnd(), getLineLocation()));
// final TValue value = eatExpression(context, memory); // final TValue value = eatExpression(context, memory);
// this.location = value.toString(); // this.location = value.toString();
} }
public final String getLocation() { public final String getWhat() {
return location; return what;
} }
public final PreprocessorIncludeStrategy getPreprocessorIncludeStrategy() { public final PreprocessorIncludeStrategy getPreprocessorIncludeStrategy() {

View File

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

View File

@ -49,7 +49,7 @@ public class EaterLegacyDefine extends Eater {
skipSpaces(); skipSpaces();
checkAndEatChar("!define"); checkAndEatChar("!define");
skipSpaces(); 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(); final String def = this.eatAllToEnd();
// function.setFunctionType(TFunctionType.LEGACY_DEFINE); // function.setFunctionType(TFunctionType.LEGACY_DEFINE);
function.setLegacyDefinition(def); function.setLegacyDefinition(def);

View File

@ -49,7 +49,7 @@ public class EaterLegacyDefineLong extends Eater {
skipSpaces(); skipSpaces();
checkAndEatChar("!definelong"); checkAndEatChar("!definelong");
skipSpaces(); 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); // function.setFunctionType(TFunctionType.LEGACY_DEFINELONG);
} }

View File

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

View File

@ -101,24 +101,24 @@ public class EaterTheme extends Eater {
} catch (IOException e) { } catch (IOException e) {
Logme.error(e); Logme.error(e);
} }
throw EaterException.located("Cannot load " + realName); throw EaterException.located("Cannot load " + realName, getStringLocated());
} }
if (from.startsWith("<") && from.endsWith(">")) { if (from.startsWith("<") && from.endsWith(">")) {
final ReadLine reader = ThemeUtils.getReaderTheme(realName, from); final ReadLine reader = ThemeUtils.getReaderTheme(realName, from);
if (reader == null) if (reader == null)
throw EaterException.located("No such theme " + realName + " in " + from); throw EaterException.located("No such theme " + realName + " in " + from, getStringLocated());
return reader; return reader;
} else if (from.startsWith("http://") || from.startsWith("https://")) { } else if (from.startsWith("http://") || from.startsWith("https://")) {
final SURL url = SURL.create(ThemeUtils.getFullPath(from, realName)); final SURL url = SURL.create(ThemeUtils.getFullPath(from, realName));
if (url == null) if (url == null)
throw EaterException.located("Cannot open URL"); throw EaterException.located("Cannot open URL", getStringLocated());
try { try {
return PreprocessorUtils.getReaderInclude(url, getLineLocation(), UTF_8); return PreprocessorUtils.getReaderInclude(url, getStringLocated(), UTF_8);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
Logme.error(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 FileWithSuffix file = context.getFileWithSuffix(from, realName);
final Reader tmp = file.getReader(UTF_8); final Reader tmp = file.getReader(UTF_8);
if (tmp == null) if (tmp == null)
throw EaterException.located("No such theme " + realName); throw EaterException.located("No such theme " + realName, getStringLocated());
return ReadLineReader.create(tmp, "theme " + realName); return ReadLineReader.create(tmp, "theme " + realName);
} catch (IOException e) { } catch (IOException e) {
Logme.error(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) { public TFunction getFunctionSmart(TFunctionSignature searched) {
final TFunction func = this.functions.get(searched); final TFunction func = this.functions.get(searched);
if (func != null) { if (func != null)
return func; return func;
}
for (TFunction candidate : this.functions.values()) { for (TFunction candidate : this.functions.values()) {
if (candidate.getSignature().sameFunctionNameAs(searched) == false) { if (candidate.getSignature().sameFunctionNameAs(searched) == false)
continue; continue;
}
if (candidate.canCover(searched.getNbArg(), searched.getNamedArguments())) { if (candidate.canCover(searched.getNbArg(), searched.getNamedArguments()))
return candidate; return candidate;
}
} }
return null; return null;
} }
@ -82,9 +82,9 @@ public class FunctionsSet {
} }
public void addFunction(TFunction func) { public void addFunction(TFunction func) {
if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) { if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG)
((TFunctionImpl) func).finalizeEnddefinelong(); ((TFunctionImpl) func).finalizeEnddefinelong();
}
this.functions.put(func.getSignature(), func); this.functions.put(func.getSignature(), func);
this.functions3.add(func.getSignature().getFunctionName() + "("); this.functions3.add(func.getSignature().getFunctionName() + "(");
} }
@ -96,9 +96,9 @@ public class FunctionsSet {
public void executeLegacyDefine(TContext context, TMemory memory, StringLocated s) public void executeLegacyDefine(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated { throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) { if (this.pendingFunction != null)
throw EaterException.located("already0048"); throw EaterException.located("already0048", s);
}
final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s); final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s);
legacyDefine.analyze(context, memory); legacyDefine.analyze(context, memory);
final TFunction function = legacyDefine.getFunction(); final TFunction function = legacyDefine.getFunction();
@ -108,9 +108,9 @@ public class FunctionsSet {
public void executeLegacyDefineLong(TContext context, TMemory memory, StringLocated s) public void executeLegacyDefineLong(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated { throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) { if (this.pendingFunction != null)
throw EaterException.located("already0068"); throw EaterException.located("already0068", s);
}
final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s); final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s);
legacyDefineLong.analyze(context, memory); legacyDefineLong.analyze(context, memory);
this.pendingFunction = legacyDefineLong.getFunction(); this.pendingFunction = legacyDefineLong.getFunction();
@ -118,48 +118,48 @@ public class FunctionsSet {
public void executeDeclareReturnFunction(TContext context, TMemory memory, StringLocated s) public void executeDeclareReturnFunction(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated { throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) { if (this.pendingFunction != null)
throw EaterException.located("already0068"); throw EaterException.located("already0068", s);
}
final EaterDeclareReturnFunction declareFunction = new EaterDeclareReturnFunction(s); final EaterDeclareReturnFunction declareFunction = new EaterDeclareReturnFunction(s);
declareFunction.analyze(context, memory); declareFunction.analyze(context, memory);
final boolean finalFlag = declareFunction.getFinalFlag(); final boolean finalFlag = declareFunction.getFinalFlag();
final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature(); final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature();
final TFunction previous = this.functions.get(declaredSignature); final TFunction previous = this.functions.get(declaredSignature);
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature))) { if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature)))
throw EaterException.located("This function is already defined"); throw EaterException.located("This function is already defined", s);
}
if (finalFlag) { if (finalFlag)
this.functionsFinal.add(declaredSignature); this.functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) { if (declareFunction.getFunction().hasBody())
this.addFunction(declareFunction.getFunction()); this.addFunction(declareFunction.getFunction());
} else { else
this.pendingFunction = declareFunction.getFunction(); this.pendingFunction = declareFunction.getFunction();
}
} }
public void executeDeclareProcedure(TContext context, TMemory memory, StringLocated s) public void executeDeclareProcedure(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated { throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) { if (this.pendingFunction != null)
throw EaterException.located("already0068"); throw EaterException.located("already0068", s);
}
final EaterDeclareProcedure declareFunction = new EaterDeclareProcedure(s); final EaterDeclareProcedure declareFunction = new EaterDeclareProcedure(s);
declareFunction.analyze(context, memory); declareFunction.analyze(context, memory);
final boolean finalFlag = declareFunction.getFinalFlag(); final boolean finalFlag = declareFunction.getFinalFlag();
final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature(); final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature();
final TFunction previous = this.functions.get(declaredSignature); final TFunction previous = this.functions.get(declaredSignature);
if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature))) { if (previous != null && (finalFlag || this.functionsFinal.contains(declaredSignature)))
throw EaterException.located("This function is already defined"); throw EaterException.located("This function is already defined", s);
}
if (finalFlag) { if (finalFlag)
this.functionsFinal.add(declaredSignature); this.functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) { if (declareFunction.getFunction().hasBody())
this.addFunction(declareFunction.getFunction()); this.addFunction(declareFunction.getFunction());
} else { else
this.pendingFunction = declareFunction.getFunction(); this.pendingFunction = declareFunction.getFunction();
}
} }
} }

View File

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

View File

@ -148,12 +148,12 @@ public class TFunctionImpl implements TFunction {
return executeReturnLegacyDefine(location.getLocation(), context, memory, args); return executeReturnLegacyDefine(location.getLocation(), context, memory, args);
if (functionType != TFunctionType.RETURN_FUNCTION) 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 TMemory copy = getNewMemory(memory, args, named);
final TValue result = context.executeLines(copy, body, TFunctionType.RETURN_FUNCTION, true); final TValue result = context.executeLines(copy, body, TFunctionType.RETURN_FUNCTION, true);
if (result == null) 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; return result;
} }

View File

@ -37,13 +37,15 @@ package net.sourceforge.plantuml.tim;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue; import net.sourceforge.plantuml.tim.expression.TValue;
public interface TMemory { public interface TMemory {
public TValue getVariable(String varname); 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); public void removeVariable(String varname);

View File

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

View File

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

View File

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

View File

@ -46,9 +46,9 @@ public class VariableManager {
private final TMemory memory; private final TMemory memory;
private final TContext context; 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.memory = memory;
this.context = context; this.context = context;
this.location = location; this.location = location;
@ -56,9 +56,9 @@ public class VariableManager {
public int replaceVariables(String str, int i, StringBuilder result) throws EaterException, EaterExceptionLocated { public int replaceVariables(String str, int i, StringBuilder result) throws EaterException, EaterExceptionLocated {
final String presentVariable = getVarnameAt(str, i); final String presentVariable = getVarnameAt(str, i);
if (result.toString().endsWith("##")) { if (result.toString().endsWith("##"))
result.setLength(result.length() - 2); result.setLength(result.length() - 2);
}
final TValue value = memory.getVariable(presentVariable); final TValue value = memory.getVariable(presentVariable);
i += presentVariable.length() - 1; i += presentVariable.length() - 1;
if (value.isJson()) { if (value.isJson()) {
@ -75,9 +75,9 @@ public class VariableManager {
} else { } else {
result.append(value.toString()); 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; i += 2;
}
return i; return i;
} }
@ -89,9 +89,9 @@ public class VariableManager {
i++; i++;
final StringBuilder fieldName = new StringBuilder(); final StringBuilder fieldName = new StringBuilder();
while (i < str.length()) { while (i < str.length()) {
if (Character.isJavaIdentifierPart(str.charAt(i)) == false) { if (Character.isJavaIdentifierPart(str.charAt(i)) == false)
break; break;
}
fieldName.append(str.charAt(i)); fieldName.append(str.charAt(i));
i++; i++;
} }
@ -101,9 +101,9 @@ public class VariableManager {
final StringBuilder inBracket = new StringBuilder(); final StringBuilder inBracket = new StringBuilder();
int level = 0; int level = 0;
while (true) { while (true) {
if (str.charAt(i) == '[') { if (str.charAt(i) == '[')
level++; level++;
}
if (str.charAt(i) == ']') { if (str.charAt(i) == ']') {
if (level == 0) if (level == 0)
break; break;
@ -113,29 +113,29 @@ public class VariableManager {
i++; i++;
} }
final String nbString = context.applyFunctionsAndVariables(memory, final String nbString = context.applyFunctionsAndVariables(memory,
new StringLocated(inBracket.toString(), location)); new StringLocated(inBracket.toString(), location.getLocation()));
if (jsonValue instanceof JsonArray) { if (jsonValue instanceof JsonArray) {
final int nb = Integer.parseInt(nbString); final int nb = Integer.parseInt(nbString);
jsonValue = ((JsonArray) jsonValue).get(nb); jsonValue = ((JsonArray) jsonValue).get(nb);
} else if (jsonValue instanceof JsonObject) { } else if (jsonValue instanceof JsonObject) {
jsonValue = ((JsonObject) jsonValue).get(nbString); jsonValue = ((JsonObject) jsonValue).get(nbString);
} else { } else {
throw EaterException.unlocated("Major parsing error"); throw EaterException.unlocated("Major parsing error", location);
}
if (jsonValue == null) {
throw EaterException.unlocated("Data parsing error");
} }
if (jsonValue == null)
throw EaterException.unlocated("Data parsing error", location);
i++; i++;
} else { } else {
break; break;
} }
} }
if (jsonValue != null) { if (jsonValue != null) {
if (jsonValue.isString()) { if (jsonValue.isString())
result.append(jsonValue.asString()); result.append(jsonValue.asString());
} else { else
result.append(jsonValue.toString()); result.append(jsonValue.toString());
}
} }
return i; return i;
} }
@ -146,13 +146,13 @@ public class VariableManager {
return null; return null;
} }
final String varname = memory.variablesNames3().getLonguestMatchStartingIn(s.substring(pos)); final String varname = memory.variablesNames3().getLonguestMatchStartingIn(s.substring(pos));
if (varname.length() == 0) { if (varname.length() == 0)
return null; return null;
}
if (pos + varname.length() == s.length() 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 varname;
}
return null; 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.TFunction;
import net.sourceforge.plantuml.tim.TFunctionSignature; import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.utils.LineLocation;
public class ReversePolishInterpretor { public class ReversePolishInterpretor {
private final TValue result; private final TValue result;
private final boolean trace = false; 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, public ReversePolishInterpretor(StringLocated location, TokenStack queue, Knowledge knowledge, TMemory memory,
TContext context) throws EaterException, EaterExceptionLocated { TContext context) throws EaterException, EaterExceptionLocated {
@ -79,45 +73,45 @@ public class ReversePolishInterpretor {
final TValue v2 = stack.removeFirst(); final TValue v2 = stack.removeFirst();
final TValue v1 = stack.removeFirst(); final TValue v1 = stack.removeFirst();
final TokenOperator op = token.getTokenOperator(); final TokenOperator op = token.getTokenOperator();
if (op == null) { if (op == null)
throw EaterException.unlocated("bad op"); throw EaterException.unlocated("bad op", location);
}
final TValue tmp = op.operate(v1, v2); final TValue tmp = op.operate(v1, v2);
stack.addFirst(tmp); stack.addFirst(tmp);
} else if (token.getTokenType() == TokenType.OPEN_PAREN_FUNC) { } else if (token.getTokenType() == TokenType.OPEN_PAREN_FUNC) {
final int nb = Integer.parseInt(token.getSurface()); final int nb = Integer.parseInt(token.getSurface());
final Token token2 = it.nextToken(); final Token token2 = it.nextToken();
if (token2.getTokenType() != TokenType.FUNCTION_NAME) { if (token2.getTokenType() != TokenType.FUNCTION_NAME)
throw EaterException.unlocated("rpn43"); throw EaterException.unlocated("rpn43", location);
}
if (trace) if (trace)
System.err.println("token2=" + token2); System.err.println("token2=" + token2);
final TFunction function = knowledge.getFunction(new TFunctionSignature(token2.getSurface(), nb)); final TFunction function = knowledge.getFunction(new TFunctionSignature(token2.getSurface(), nb));
if (trace) if (trace)
System.err.println("function=" + function); System.err.println("function=" + function);
if (function == null) { if (function == null)
throw EaterException.unlocated("Unknown built-in function " + token2.getSurface()); throw EaterException.unlocated("Unknown built-in function " + token2.getSurface(), location);
}
if (function.canCover(nb, Collections.<String>emptySet()) == false) { if (function.canCover(nb, Collections.<String>emptySet()) == false)
throw EaterException throw EaterException.unlocated(
.unlocated("Bad number of arguments for " + function.getSignature().getFunctionName()); "Bad number of arguments for " + function.getSignature().getFunctionName(), location);
}
final List<TValue> args = new ArrayList<>(); 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()); args.add(0, stack.removeFirst());
}
if (trace) if (trace)
System.err.println("args=" + args); System.err.println("args=" + args);
if (location == null) { if (location == null)
throw EaterException.unlocated("rpn44"); throw EaterException.unlocated("rpn44", location);
}
final TValue r = function.executeReturnFunction(context, memory, location, args, final TValue r = function.executeReturnFunction(context, memory, location, args,
Collections.<String, TValue>emptyMap()); Collections.<String, TValue>emptyMap());
if (trace) if (trace)
System.err.println("r=" + r); System.err.println("r=" + r);
stack.addFirst(r); stack.addFirst(r);
} else { } else {
throw EaterException.unlocated("rpn41"); throw EaterException.unlocated("rpn41", location);
} }
} }
result = stack.removeFirst(); result = stack.removeFirst();

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.tim.expression;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException; import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated; import net.sourceforge.plantuml.tim.EaterExceptionLocated;
@ -58,7 +59,8 @@ public class ShuntingYard {
System.err.println(""); 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()) { while (it.hasMoreTokens()) {
final Token token = it.nextToken(); final Token token = it.nextToken();
@ -74,7 +76,7 @@ public class ShuntingYard {
final TValue variable = knowledge.getVariable(name); final TValue variable = knowledge.getVariable(name);
if (variable == null) { if (variable == null) {
if (isVariableName(name) == false) 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)); ouputQueue.add(new Token(name, TokenType.QUOTED_STRING, null));
} else { } else {

View File

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

View File

@ -34,6 +34,7 @@
*/ */
package net.sourceforge.plantuml.tim.iterator; package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.tim.EaterException; import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterExceptionLocated; import net.sourceforge.plantuml.tim.EaterExceptionLocated;
@ -45,16 +46,19 @@ public abstract class AbstractCodeIterator implements CodeIterator {
this.source = source; this.source = source;
} }
@Override
public void next() throws EaterException, EaterExceptionLocated { public void next() throws EaterException, EaterExceptionLocated {
source.next(); source.next();
} }
@Override
final public CodePosition getCodePosition() { final public CodePosition getCodePosition() {
return source.getCodePosition(); return source.getCodePosition();
} }
final public void jumpToCodePosition(CodePosition newPosition) throws EaterException { @Override
source.jumpToCodePosition(newPosition); 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; import net.sourceforge.plantuml.tim.EaterExceptionLocated;
public interface CodeIterator { public interface CodeIterator {
// ::remove folder when __HAXE__ // ::remove folder when __HAXE__
public StringLocated peek() throws EaterException, EaterExceptionLocated; public StringLocated peek() throws EaterException, EaterExceptionLocated;
@ -47,6 +47,6 @@ public interface CodeIterator {
public CodePosition getCodePosition(); 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; this.logs = log;
} }
@Override
public StringLocated peek() throws EaterException, EaterExceptionLocated { public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) { while (true) {
final StringLocated result = source.peek(); final StringLocated result = source.peek();
@ -81,9 +82,9 @@ public class CodeIteratorAffectation extends AbstractCodeIterator {
this.executeAffectation(context, memory, result); this.executeAffectation(context, memory, result);
return; return;
} catch (ParseException e) { } catch (ParseException e) {
if (e.getColumn() <= lastLocation) { if (e.getColumn() <= lastLocation)
throw EaterException.located("Error in JSON format"); throw EaterException.located("Error in JSON format", result);
}
lastLocation = e.getColumn(); lastLocation = e.getColumn();
next(); next();
final StringLocated forward = source.peek(); final StringLocated forward = source.peek();

View File

@ -65,9 +65,8 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
int level = 0; int level = 0;
while (true) { while (true) {
final StringLocated result = source.peek(); final StringLocated result = source.peek();
if (result == null) { if (result == null)
return null; return null;
}
final ExecutionContextForeach foreach = memory.peekForeach(); final ExecutionContextForeach foreach = memory.peekForeach();
if (foreach != null && foreach.isSkipMe()) { if (foreach != null && foreach.isSkipMe()) {
@ -91,15 +90,15 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
continue; continue;
} else if (result.getType() == TLineType.ENDFOREACH) { } else if (result.getType() == TLineType.ENDFOREACH) {
logs.add(result); logs.add(result);
if (foreach == null) { if (foreach == null)
throw EaterException.located("No foreach related to this endforeach"); throw EaterException.located("No foreach related to this endforeach", result);
}
foreach.inc(); foreach.inc();
if (foreach.isSkipMe()) { if (foreach.isSkipMe()) {
memory.pollForeach(); memory.pollForeach();
} else { } else {
setLoopVariable(memory, foreach, result); setLoopVariable(memory, foreach, result);
source.jumpToCodePosition(foreach.getStartForeach()); source.jumpToCodePosition(foreach.getStartForeach(), result);
} }
next(); next();
continue; continue;
@ -114,18 +113,18 @@ public class CodeIteratorForeach extends AbstractCodeIterator {
condition.analyze(context, memory); condition.analyze(context, memory);
final ExecutionContextForeach foreach = ExecutionContextForeach.fromValue(condition.getVarname(), final ExecutionContextForeach foreach = ExecutionContextForeach.fromValue(condition.getVarname(),
condition.getJsonArray(), source.getCodePosition()); condition.getJsonArray(), source.getCodePosition());
if (condition.isSkip()) { if (condition.isSkip())
foreach.skipMeNow(); foreach.skipMeNow();
} else { else
setLoopVariable(memory, foreach, s); setLoopVariable(memory, foreach, s);
}
memory.addForeach(foreach); memory.addForeach(foreach);
} }
private void setLoopVariable(TMemory memory, ExecutionContextForeach foreach, StringLocated position) private void setLoopVariable(TMemory memory, ExecutionContextForeach foreach, StringLocated position)
throws EaterException { throws EaterException {
final JsonValue first = foreach.getJsonArray().get(foreach.currentIndex()); 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) private void executeElseIf(TContext context, TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated { throws EaterException, EaterExceptionLocated {
final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf(); final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf();
if (poll == null) { if (poll == null)
throw EaterException.located("No if related to this else"); throw EaterException.located("No if related to this else", s);
}
poll.enteringElseIf(); poll.enteringElseIf();
if (poll.hasBeenBurn() == false) { if (poll.hasBeenBurn() == false) {
final EaterElseIf condition = new EaterElseIf(s); final EaterElseIf condition = new EaterElseIf(s);
condition.analyze(context, memory); condition.analyze(context, memory);
final boolean isTrue = condition.isTrue(); final boolean isTrue = condition.isTrue();
if (isTrue) { if (isTrue)
poll.nowInSomeElseIf(); poll.nowInSomeElseIf();
}
} }
} }
@ -149,17 +148,17 @@ public class CodeIteratorIf extends AbstractCodeIterator {
private void executeElse(TContext context, TMemory memory, StringLocated s) throws EaterException { private void executeElse(TContext context, TMemory memory, StringLocated s) throws EaterException {
final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf(); final ExecutionContextIf poll = (ExecutionContextIf) memory.peekIf();
if (poll == null) { if (poll == null)
throw EaterException.located("No if related to this else"); throw EaterException.located("No if related to this else", s);
}
poll.nowInElse(); poll.nowInElse();
} }
private void executeEndif(TContext context, TMemory memory, StringLocated s) throws EaterException { private void executeEndif(TContext context, TMemory memory, StringLocated s) throws EaterException {
final ExecutionContextIf poll = (ExecutionContextIf) memory.pollIf(); final ExecutionContextIf poll = (ExecutionContextIf) memory.pollIf();
if (poll == null) { if (poll == null)
throw EaterException.located("No if related to this endif"); throw EaterException.located("No if related to this endif", s);
}
} }
} }

View File

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

View File

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

View File

@ -64,9 +64,8 @@ public class CodeIteratorWhile extends AbstractCodeIterator {
int level = 0; int level = 0;
while (true) { while (true) {
final StringLocated result = source.peek(); final StringLocated result = source.peek();
if (result == null) { if (result == null)
return null; return null;
}
final ExecutionContextWhile currentWhile = memory.peekWhile(); final ExecutionContextWhile currentWhile = memory.peekWhile();
if (currentWhile != null && currentWhile.isSkipMe()) { if (currentWhile != null && currentWhile.isSkipMe()) {
@ -91,14 +90,14 @@ public class CodeIteratorWhile extends AbstractCodeIterator {
} else if (result.getType() == TLineType.ENDWHILE) { } else if (result.getType() == TLineType.ENDWHILE) {
logs.add(result); logs.add(result);
if (currentWhile == null) 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); final TValue value = currentWhile.conditionValue(result, context, memory);
if (value.toBoolean()) { if (value.toBoolean())
source.jumpToCodePosition(currentWhile.getStartWhile()); source.jumpToCodePosition(currentWhile.getStartWhile(), result);
} else { else
memory.pollWhile(); memory.pollWhile();
}
next(); next();
continue; continue;
} }

View File

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

View File

@ -71,7 +71,7 @@ public class Darken extends SimpleReturnFunction {
color = color.darken(ratio); color = color.darken(ratio);
return TValue.fromString(color.asString()); return TValue.fromString(color.asString());
} catch (NoSuchColorException e) { } 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(); now = 1000L * values.get(1).toInt();
else else
now = System.currentTimeMillis(); now = System.currentTimeMillis();
try { try {
return TValue.fromString(new SimpleDateFormat(format).format(now)); return TValue.fromString(new SimpleDateFormat(format).format(now));
} catch (Exception e) { } 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: 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 { Map<String, TValue> named) throws EaterException, EaterExceptionLocated {
final TValue data = values.get(0); final TValue data = values.get(0);
if (data.isJson() == false) if (data.isJson() == false)
throw EaterException.unlocated("Not JSON data"); throw EaterException.unlocated("Not JSON data", location);
final JsonValue json = data.toJson(); final JsonValue json = data.toJson();
if (json.isObject()) { if (json.isObject()) {
final JsonObject object = (JsonObject) json; final JsonObject object = (JsonObject) json;
@ -87,7 +88,7 @@ public class GetJsonKey extends SimpleReturnFunction {
return TValue.fromJson(result); 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 TFunctionSignature signature = new TFunctionSignature(fname, sublist.size());
final TFunction func = context.getFunctionSmart(signature); final TFunction func = context.getFunctionSmart(signature);
if (func == null) 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); 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); final HColor color = HColorSet.instance().getColorLEGACY(colorString);
return TValue.fromBoolean(color.isDark()); return TValue.fromBoolean(color.isDark());
} catch (NoSuchColorException e) { } 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); final HColor color = HColorSet.instance().getColorLEGACY(colorString);
return TValue.fromBoolean(!color.isDark()); return TValue.fromBoolean(!color.isDark());
} catch (NoSuchColorException e) { } 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); color = color.lighten(ratio);
return TValue.fromString(color.asString()); return TValue.fromString(color.asString());
} catch (NoSuchColorException e) { } 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); return TValue.fromJson(jsonValue);
} catch (ParseException pe) { } catch (ParseException pe) {
Logme.error(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) { } catch (UnsupportedEncodingException e) {
Logme.error(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); return TValue.fromInt(random.nextInt(max - min) + min);
default: 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(); color = color.reverse();
return TValue.fromString(color.asString()); return TValue.fromString(color.asString());
} catch (NoSuchColorException e) { } 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(); color = color.reverseHsluv();
return TValue.fromString(color.asString()); return TValue.fromString(color.asString());
} catch (NoSuchColorException e) { } 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 String name = values.get(0).toString();
final TValue value = values.get(1); final TValue value = values.get(1);
memory.putVariable(name, value, TVariableScope.GLOBAL); memory.putVariable(name, value, TVariableScope.GLOBAL, location);
return TValue.fromString(""); return TValue.fromString("");
} }

View File

@ -46,7 +46,7 @@ public class Version {
// Warning, "version" should be the same in gradle.properties and Version.java // Warning, "version" should be the same in gradle.properties and Version.java
// Any idea anyone how to magically synchronize those :-) ? // 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() { public static String versionString() {
return version; return version;