1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-12-22 10:59:01 +00:00

version 1.2020.2

This commit is contained in:
Arnaud Roques 2020-03-03 23:29:34 +01:00
parent 3a156f1ff4
commit 7a5b515bf6
127 changed files with 3298 additions and 866 deletions

View File

@ -35,7 +35,7 @@
<groupId>net.sourceforge.plantuml</groupId>
<artifactId>plantuml</artifactId>
<version>1.2020.2-SNAPSHOT</version>
<version>1.2020.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>PlantUML</name>

View File

@ -36,6 +36,7 @@
package net.sourceforge.plantuml;
import net.sourceforge.plantuml.command.regex.FoxSignature;
import net.sourceforge.plantuml.tim.TLineType;
final public class StringLocated {
@ -43,6 +44,10 @@ final public class StringLocated {
private final LineLocation location;
private final String preprocessorError;
private StringLocated trimmed;
private long fox = -1;
private TLineType type;
public StringLocated(String s, LineLocation location) {
this(s, location, null);
}
@ -76,12 +81,14 @@ final public class StringLocated {
return new StringLocated(s, location, preprocessorError);
}
public StringLocated sub(int start, int end) {
public StringLocated substring(int start, int end) {
return new StringLocated(this.getString().substring(start, end), this.getLocation(),
this.getPreprocessorError());
}
private StringLocated trimmed;
public StringLocated substring(int start) {
return new StringLocated(this.getString().substring(start), this.getLocation(), this.getPreprocessorError());
}
public StringLocated getTrimmed() {
if (trimmed == null) {
@ -134,8 +141,6 @@ final public class StringLocated {
return preprocessorError;
}
private long fox = -1;
public long getFoxSignature() {
if (fox == -1) {
fox = FoxSignature.getFoxSignature(getString());
@ -143,4 +148,11 @@ final public class StringLocated {
return fox;
}
public TLineType getType() {
if (type == null) {
type = TLineType.getFromLineInternal(s);
}
return type;
}
}

View File

@ -334,6 +334,9 @@ public class StringUtils {
if (uml.startsWith("@startuml\nauthor\n")) {
return false;
}
if (uml.startsWith("@startuml\ndonors\n")) {
return false;
}
if (uml.startsWith("@startuml\ncheckversion")) {
return false;
}
@ -343,6 +346,9 @@ public class StringUtils {
if (uml.startsWith("@startuml\nsudoku\n")) {
return false;
}
if (uml.startsWith("@startuml\nstdlib\n")) {
return false;
}
return true;
}

View File

@ -38,8 +38,9 @@ package net.sourceforge.plantuml;
import java.util.Comparator;
import net.sourceforge.plantuml.cucadiagram.dot.DotMaker2;
import net.sourceforge.plantuml.project.lang.Complement;
public class Url implements EnsureVisible {
public class Url implements EnsureVisible, Complement {
private final String url;
private final String tooltip;

View File

@ -194,7 +194,7 @@ public class BlocLines implements Iterable<StringLocated> {
for (int i = 0; i < copy.size(); i++) {
final StringLocated s = copy.get(i);
if (s.getString().length() > 0) {
copy.set(i, s.sub(1, s.getString().length()));
copy.set(i, s.substring(1, s.getString().length()));
}
}
} while (firstColumnRemovable(copy));
@ -229,7 +229,7 @@ public class BlocLines implements Iterable<StringLocated> {
copy.set(0, new StringLocated(data, null));
final int n = copy.size() - 1;
final StringLocated s = copy.get(n);
copy.set(n, s.sub(0, s.getString().length() - 1));
copy.set(n, s.substring(0, s.getString().length() - 1));
return new BlocLines(copy);
}
@ -278,7 +278,7 @@ public class BlocLines implements Iterable<StringLocated> {
if (i == 0) {
return arg;
}
return arg.sub(i, arg.getString().length());
return arg.substring(i, arg.getString().length());
}
public BlocLines subExtract(int margeStart, int margeEnd) {

View File

@ -71,6 +71,7 @@ import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.graphic.VerticalAlignment;
import net.sourceforge.plantuml.sequencediagram.MessageNumber;
import net.sourceforge.plantuml.skin.VisibilityModifier;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.ugraphic.UFont;
import net.sourceforge.plantuml.ugraphic.UStroke;
@ -84,7 +85,11 @@ public class Display implements Iterable<CharSequence> {
public final static Display NULL = new Display(null, null, true, CreoleMode.FULL);
public Display withoutStereotype(Style usedStyle) {
public Display withoutStereotypeIfNeeded(Style usedStyle) {
final boolean showStereotype = usedStyle.value(PName.ShowStereotype).asBoolean();
if (showStereotype) {
return this;
}
final List<CharSequence> copy = new ArrayList<CharSequence>(displayData);
final Display result = new Display(naturalHorizontalAlignment, isNull, defaultCreoleMode);
for (Iterator<CharSequence> it = copy.iterator(); it.hasNext();) {
@ -441,8 +446,8 @@ public class Display implements Iterable<CharSequence> {
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer, CreoleMode creoleMode) {
return create(fontConfiguration, horizontalAlignment, spriteContainer, LineBreakStrategy.NONE, creoleMode,
null, null);
return create(fontConfiguration, horizontalAlignment, spriteContainer, LineBreakStrategy.NONE, creoleMode, null,
null);
}
public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
@ -513,15 +518,15 @@ public class Display implements Iterable<CharSequence> {
FontConfiguration stereotypeConfiguration) {
final Sheet sheet = new CreoleParser(fontConfiguration, horizontalAlignment, spriteContainer, creoleMode,
stereotypeConfiguration).createSheet(this);
final SheetBlock1 sheetBlock1 = new SheetBlock1(sheet, maxMessageSize, spriteContainer == null ? 0
: spriteContainer.getPadding());
final SheetBlock1 sheetBlock1 = new SheetBlock1(sheet, maxMessageSize,
spriteContainer == null ? 0 : spriteContainer.getPadding());
return new SheetBlock2(sheetBlock1, sheetBlock1, new UStroke(1.5));
}
private TextBlock createMessageNumber(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment,
ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, FontConfiguration stereotypeConfiguration) {
TextBlock tb1 = subList(0, 1).getCreole(fontConfiguration, horizontalAlignment, spriteContainer,
maxMessageSize, CreoleMode.FULL, stereotypeConfiguration);
TextBlock tb1 = subList(0, 1).getCreole(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize,
CreoleMode.FULL, stereotypeConfiguration);
tb1 = TextBlockUtils.withMargin(tb1, 0, 4, 0, 0);
final TextBlock tb2 = subList(1, size()).getCreole(fontConfiguration, horizontalAlignment, spriteContainer,
maxMessageSize, CreoleMode.FULL, stereotypeConfiguration);

View File

@ -71,24 +71,24 @@ public class PSystemDonors extends AbstractPSystem {
private static final int COLS = 6;
private static final int FREE_LINES = 6;
public static final String DONORS = "6qOA02mFU3XMJbc44wzsfuUeUc2VR6qyRpkVqESmi8ZJNK3y1jWxFUutqbz4LxhtJJEYBLjJd6SKnOAW"
+ "nzlacc6RUtiWLXFpLN9dtkWNveKX2Mr8WEjmHyIdof0IVEycQbqbNzfRkOJbCk0By7OGIqNtNoPkJxUE"
+ "2t6mGuLG3YdksVytfxRkNbM58LrMhTFH5Ih0gi0ZOdS_QdDfrCPtKvlUX09qAd45DrMLy7hZfYBDuAxZ"
+ "N3gqw1GZpI8bNZUE43SwC_JKfF1ByaH6vZ_g1RJfNAufaJEXF4Q9HDTjVqVs7PG_BNb1H48ks2ImW4gE"
+ "m0cANXinFY8oQEZgIMDihcRC4oyCAUZ4lloZKTIufsHw6bfyH5s1ahYlSG3Iatgqu6nXDA2i9rkCQ9Ag"
+ "C_CbtByEorDwpJJS3nPHbhG9hYd8cz0JFk6hBfcSuwMeuIy_JVB8rmGQBbi6t9iEVOjhaqIvdMsQkVDf"
+ "KssUqjdgQkD_DeVSDMNLyfjHH2D7SEzl2obON5e0FmAzD2SgoPzb7rd8Xd1jfHVITQvUkHeHBjcGgM9T"
+ "_eWjh-d_wE9ocn7Bus2HpvwlCqt9G4jTYLo6lj3AvhRE5qfAK-FpoAEbupFXcgpPlUFqFihcDF-_RYip"
+ "un80dPbY5dJze1YifjNmP0CHc1QwFUGcG5v0TPZSoiFg4R_E1mHlAYCHXGrAB-Hzi-MGYnGciBmxIdG0"
+ "9ayfxU4Zve48HUs2daQLUgGiGh_TfATjsPYuJ_fWVzPW3FAOpjOu2Nyi18umpAf5ixvR-m8z1LUvNEPL"
+ "Ty_Fgm3M5juBBbBz90DwfGKZ8hL6DFQzx99mQA0mYxFahI6-PrXZvQ7x1vpMeatCQ3CVCWsI6ybgfRSO"
+ "tZKP_kOXgzcnMkGvi4V4PaWpenMyFveyKejBV4Hqi9mWMm0Ivk8LU_72dIjLkPoSRAvJcEgnMWiLyhla"
+ "4rYgmCBJWxNo7i0piaUnSpZlbJKVZTUGuda1bNAOe2wTA7Ea56NQMY33rghrRBGEjf_gM31lurivAmw5"
+ "jqrqrhX1mHGsdHAuqOYHA2SQ5NhPay80V_twbNfoKmSPl_QooJYriY6MGgMSByiNfw3nTWoj-rlqVzks"
+ "lQsSF_zUDvkSUkFjAmNGSv0S_nxAhAEBajNzDFWRR9WCSC1AAjeuuSf3Isy5aXRinpk3gFFjZEQTd2ot"
+ "f1QzSlvGsT_zoIm7LtF3YejwYdBu4gTiUsi45M_x_ZS6MpaC_4LKcPFXwgzUBICAnFOsuZoDVOzIt5cL"
+ "11BCZii4pdxrqscQXupPHoYp7Yu2-Vc8T3c4XnRKqhGuJWHMnHdUUwTroOJ_9JU9kEgdh2tLGq_ZL6vg"
+ "5sZuTYMA6qQ1uI9cny3uTfEJ5RZvfeTwgBOVwVGN4oSkAeRTtdDs0W00";
public static final String DONORS = "6taA0AmEU9ELAujmujswMQFg3ojH8OBbUK9n65Z4qzs0-0FSEptkDz9VH5UwzqqpeYr_pV7pZA4O27ey"
+ "VrqDs_nl3nxxgV8W-Ev2KDA92uXiAx7-a7f_TK3C5DrlcT3URXqNwk24ckSZ-BYouVtDS9vl6X-zz0nO"
+ "GjLFqNtj_qrTPLrULOLPkblL-UWAbR5LkrbpkljHu8ues7Seq23Kc4vTN8T3LOUvTgAlJemGOEAT4tpR"
+ "jPWLenuY9LKtjY0b1YDqjqdhb-GN6RN_g1VGfhrSKo9dGddC4ecksqg7znrqFolvvOW7Nx19O06L7E4J"
+ "5Brjn934UT3GEPlHsCAHBKy2C6IWZNtuHr4SAPwIcMreaIIaG4dAjt40CYfrQn6pvSs0yfxHObYJXCxt"
+ "Xt3VE4och3feU0Wi4Yof3Qefo9lG4pxLLrqoEET3KSLVVflairaCD2XR0kJDZBw5HvD4-Py-aFdyRbBR"
+ "FAMnrNNC_puSYg8fiuRVz3PgEO9xVrb8mU920SeHwAK-KKb-Vyg-iH23S6sb5z8njrr9emYNR4YhM9UV"
+ "Oearwz-wnCQcnRBSMBIF_nTyKpBG4YkHPEXjMlbaxNoXf6bglB_arT3vRc9Dtapl6Ar7wPpc_tV3Iise"
+ "X85ETp7AT4EWs8o6QgXPc0XC2zqS2XCW3w3sDBdbJwilyMkV8FEc4ed8RRZqWB_-JAvouS9KhEds9cO0"
+ "auUKUf8aBOXGrY7eIQ1K8sKH-XacBTEMZedxf0qUfysCWH_LCSL9-6aXS7N3l9etMxkspp5RS8FlPJvr"
+ "7zAuYkTqS-zv5wdv6mpeBIte4QanejZtial2LGCbihXB7XhYkuSTN3nqtu8pMRI16MsEGsP2vLeoQkaj"
+ "HXcQTBubapNjrLPK6X1U7EFWZenEy7WZUQGMbqZYPZ2325i0qlhY4xiauSw4gbjkTZRN5gODNxq8BS7l"
+ "Kfd0KeKNdYxiwEv-SKPZ5DadvhqoUsayfXGV2wYIKmLLQQFqcLBaQMiP6JBMe6Uz3R3BgMuB-3O_rR1E"
+ "ABojejCM6tIRGeQhX6yqYYTg5UqQkDYaC82lUNaAdZRMGSPtUbb7722RIq885Lfp-0UdfR7w22rblKN_"
+ "jstRoyhvy-zrP0MdddZcLGNG8qZpVpzble15h-jx6_fMvLCUs06pnP0UR2rM7b1w9v3KO1-biugwDCs8"
+ "htX7kKLjqSgF3vN_wNIFM4m7tx3yefeYdxx4QRQzD9nAqdtV5ukJ73R-AQhCokIgrAg94Tt4Te_YF8sT"
+ "Podkkde54lIEImNkdhhUJjDyIf_p1QM7uOeXFn-H8PlghWMra9RZjC0sSTRtPhOXcUf_IGy-2RLrdDN3"
+ "qC7sRt8NQFRjJMxS40K6HVo1WNtsc9CJ5CSR0kt6r1rfkPYoSz4ztIuMhB7Vz8_8ieG_B6kLYJ3NowrO" + "B0lnh6sq0m00";
/*
* Special thanks to our sponsors and donors:

View File

@ -221,11 +221,11 @@ public abstract class PSystemError extends AbstractPSystem {
}
final int min = (int) (System.currentTimeMillis() / 60000L) % 60;
// udrawable = addMessageAdopt(udrawable);
if (min == 1 || min == 8) {
if (min == 1 || min == 8 || min == 13 || min == 55) {
udrawable = addMessagePatreon(udrawable);
} else if (min == 15) {
udrawable = addMessageLiberapay(udrawable);
} else if (min == 30) {
} else if (min == 30 || min == 39 || min == 48) {
udrawable = addMessageDedication(udrawable);
} else if (getSource().containsIgnoreCase("arecibo")) {
udrawable = addMessageArecibo(udrawable);

View File

@ -244,7 +244,10 @@ public class QuoteUtils {
"Obhagl Uhagvat vf n pbzcyvpngrq cebsrffvba.",
"Znahsnpghere'f cebgbpby qvpgngrf V pna abg or pncgherq. V zhfg frys-qrfgehpg.", "Snvyher vf abg na bcgvba",
"Rirelguvat snvyf nyy gur gvzr", "Gur orfg jnl gb nibvq snvyher vf gb snvy pbafgnagyl",
"Cerzngher bcgvzvmngvba vf gur ebbg bs nyy rivy", "Chgnva, w'ra nv zneer q'nibve gbhwbhef envfba");
"Cerzngher bcgvzvmngvba vf gur ebbg bs nyy rivy", "Chgnva, w'ra nv zneer q'nibve gbhwbhef envfba",
"Guvf vf gur jnl", "Cngvrapr lbh zhfg unir zl lbhat cnqnjna", "V gubhtug lbh jrer ba zl fvqr",
"Qba'g cnavp. Abar bs lbh cnavp. Nofbyhgryl ab ernfba gb cnavp.",
"Gung jnf hacyrnfnag. V'z fbeel lbh unq gb frr gung.", "Gur neg bs fvzcyvpvgl vf n chmmyr bs pbzcyrkvgl.");
private QuoteUtils() {
}

View File

@ -42,7 +42,6 @@ import java.util.regex.Pattern;
import net.sourceforge.plantuml.AParentFolder;
import net.sourceforge.plantuml.BackSlash;
import net.sourceforge.plantuml.tim.TVariable;
import net.sourceforge.plantuml.tim.expression.TValue;
public class Define {
@ -124,7 +123,7 @@ public class Define {
return signature.getFonctionName();
}
public TVariable asTVariable() {
return new TVariable(TValue.fromString(definition));
public TValue asTVariable() {
return TValue.fromString(definition);
}
}

View File

@ -46,11 +46,13 @@ import net.sourceforge.plantuml.tim.EaterStartsub;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorImpl;
public class Sub {
private final String name;
private final List<StringLocated> lines = new ArrayList<StringLocated>();
// private boolean indentationDone = false;
public Sub(String name) {
this.name = name;
@ -62,37 +64,47 @@ public class Sub {
}
public void add(StringLocated s) {
// if (indentationDone) {
// throw new IllegalStateException();
// }
this.lines.add(s);
}
public final List<StringLocated> lines() {
// if (indentationDone == false) {
// CodeIteratorImpl.indentNow(lines);
// indentationDone = true;
// }
return Collections.unmodifiableList(lines);
}
public static Sub fromFile(ReadLine reader, String blocname, TContext context, TMemory memory) throws IOException,
EaterException {
public static Sub fromFile(ReadLine reader, String blocname, TContext context, TMemory memory)
throws IOException, EaterException {
Sub result = null;
StringLocated s = null;
boolean skip = false;
while ((s = reader.readLine()) != null) {
final TLineType type = TLineType.getFromLine(s.getTrimmed().getString());
final TLineType type = s.getTrimmed().getType();
if (type == TLineType.STARTSUB) {
final EaterStartsub eater = new EaterStartsub(s.getTrimmed().getString());
eater.execute(context, memory);
final EaterStartsub eater = new EaterStartsub(s.getTrimmed());
eater.analyze(context, memory);
if (eater.getSubname().equals(blocname)) {
result = new Sub(blocname);
skip = false;
if (result == null) {
result = new Sub(blocname);
}
}
continue;
}
if (type == TLineType.ENDSUB && result != null) {
reader.close();
return result;
skip = true;
}
if (result != null) {
if (result != null && skip == false) {
result.add(s);
}
}
reader.close();
return null;
return result;
}
}

View File

@ -76,7 +76,7 @@ public class UncommentReadLine implements ReadLine {
return new StringLocated("", result.getLocation());
}
if (headerToRemove != null && result.getString().startsWith(headerToRemove)) {
return result.sub(headerToRemove.length(), result.getString().length());
return result.substring(headerToRemove.length(), result.getString().length());
}
return result;
}

View File

@ -128,7 +128,7 @@ public class PreprocessorUtils {
return ReadLineReader.create(new InputStreamReader(is, charset), url.toString(), s.getLocation());
} catch (IOException e) {
e.printStackTrace();
throw new EaterException("Cannot open URL");
throw EaterException.located("Cannot open URL", s);
}
}

View File

@ -35,6 +35,7 @@
*/
package net.sourceforge.plantuml.project.core;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.project.Load;
import net.sourceforge.plantuml.project.draw.TaskDraw;
import net.sourceforge.plantuml.project.lang.ComplementColors;
@ -70,5 +71,7 @@ public interface Task extends Subject, Moment {
public void setCompletion(int completion);
public void setUrl(Url url);
}

View File

@ -39,6 +39,7 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.project.Load;
import net.sourceforge.plantuml.project.LoadPlanable;
import net.sourceforge.plantuml.project.PlanUtils;
@ -53,6 +54,14 @@ public class TaskImpl implements Task, LoadPlanable {
private final Map<Resource, Integer> resources2 = new LinkedHashMap<Resource, Integer>();
private final LoadPlanable defaultPlan;
private boolean diamond;
private Url url;
private TaskDraw taskDraw;
private ComplementColors colors;
public void setUrl(Url url) {
this.url = url;
}
public TaskImpl(TaskCode code, LoadPlanable defaultPlan) {
this.code = code;
@ -72,7 +81,8 @@ public class TaskImpl implements Task, LoadPlanable {
}
public int loadForResource(Resource res, Wink instant) {
if (resources2.keySet().contains(res) && instant.compareTo(getStart()) >= 0 && instant.compareTo(getEnd()) <= 0) {
if (resources2.keySet().contains(res) && instant.compareTo(getStart()) >= 0
&& instant.compareTo(getEnd()) <= 0) {
if (res.isClosedAt(instant)) {
return 0;
}
@ -172,11 +182,9 @@ public class TaskImpl implements Task, LoadPlanable {
solver.setData(TaskAttribute.END, end);
}
private TaskDraw taskDraw;
private ComplementColors colors;
public void setTaskDraw(TaskDraw taskDraw) {
taskDraw.setColorsAndCompletion(colors, completion);
taskDraw.setColorsAndCompletion(colors, completion, url);
this.taskDraw = taskDraw;
}
@ -199,7 +207,7 @@ public class TaskImpl implements Task, LoadPlanable {
public boolean isDiamond() {
return this.diamond;
}
private int completion = 100;
public void setCompletion(int completion) {

View File

@ -35,6 +35,7 @@
*/
package net.sourceforge.plantuml.project.core;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.project.Load;
import net.sourceforge.plantuml.project.draw.TaskDraw;
import net.sourceforge.plantuml.project.lang.ComplementColors;
@ -112,4 +113,8 @@ public class TaskSeparator implements Task {
throw new UnsupportedOperationException();
}
public void setUrl(Url url) {
throw new UnsupportedOperationException();
}
}

View File

@ -36,13 +36,14 @@
package net.sourceforge.plantuml.project.draw;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.project.lang.ComplementColors;
import net.sourceforge.plantuml.ugraphic.UGraphic;
public interface TaskDraw extends UDrawable {
public void setColorsAndCompletion(ComplementColors colors, int completion);
public void setColorsAndCompletion(ComplementColors colors, int completion, Url url);
public double getY();

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.project.draw;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
@ -66,6 +67,7 @@ public class TaskDrawRegular implements TaskDraw {
private final double y;
private ComplementColors colors;
private int completion = 100;
private Url url;
private final double margin = 2;
@ -125,22 +127,29 @@ public class TaskDrawRegular implements TaskDraw {
if (fullLength < 10) {
return;
}
if (url != null) {
ug.startUrl(url);
}
final URectangle full = new URectangle(fullLength, getShapeHeight(), 8, 8);
if (completion == 100) {
ug.draw(full);
return;
} else {
final double partialLength = fullLength * completion / 100.;
ug.apply(new UChangeColor(HtmlColorUtils.WHITE)).apply(new UChangeBackColor(HtmlColorUtils.WHITE))
.draw(full);
if (partialLength > 2) {
final URectangle partial = new URectangle(partialLength, getShapeHeight(), 8, 8);
ug.apply(new UChangeColor(null)).draw(partial);
}
if (partialLength > 10 && partialLength < fullLength - 10) {
final URectangle patch = new URectangle(8, getShapeHeight());
ug.apply(new UChangeColor(null)).apply(new UTranslate(partialLength - 8, 0)).draw(patch);
}
ug.apply(new UChangeBackColor(null)).draw(full);
}
final double partialLength = fullLength * completion / 100.;
ug.apply(new UChangeColor(HtmlColorUtils.WHITE)).apply(new UChangeBackColor(HtmlColorUtils.WHITE)).draw(full);
if (partialLength > 2) {
final URectangle partial = new URectangle(partialLength, getShapeHeight(), 8, 8);
ug.apply(new UChangeColor(null)).draw(partial);
if (url != null) {
ug.closeAction();
}
if (partialLength > 10 && partialLength < fullLength - 10) {
final URectangle patch = new URectangle(8, getShapeHeight());
ug.apply(new UChangeColor(null)).apply(new UTranslate(partialLength - 8, 0)).draw(patch);
}
ug.apply(new UChangeBackColor(null)).draw(full);
}
@ -185,8 +194,9 @@ public class TaskDrawRegular implements TaskDraw {
return y + getHeight() / 2;
}
public void setColorsAndCompletion(ComplementColors colors, int completion) {
public void setColorsAndCompletion(ComplementColors colors, int completion, Url url) {
this.colors = colors;
this.completion = completion;
this.url = url;
}
}

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.project.draw;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.SpriteContainerEmpty;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
@ -126,7 +127,7 @@ public class TaskDrawSeparator implements TaskDraw {
return y + getHeight() / 2;
}
public void setColorsAndCompletion(ComplementColors colors, int completion) {
public void setColorsAndCompletion(ComplementColors colors, int completion, Url url) {
}
}

View File

@ -48,7 +48,7 @@ public class ComplementBeforeOrAfterOrAtTaskStartOrEnd implements ComplementPatt
public IRegex toRegex(String suffix) {
return new RegexLeaf("COMPLEMENT" + suffix,
"(?:at|(\\d+)[%s]+days?[%s]+(before|after))[%s]+\\[([^\\[\\]]+?)\\].?s[%s]+(start|end)");
"(?:at|with|after|(\\d+)[%s]+days?[%s]+(before|after))[%s]+\\[([^\\[\\]]+?)\\].?s[%s]+(start|end)");
}
public Failable<Complement> getComplement(GanttDiagram system, RegexResult arg, String suffix) {

View File

@ -0,0 +1,62 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.project.lang;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.UrlBuilder;
import net.sourceforge.plantuml.UrlBuilder.ModeUrl;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
import net.sourceforge.plantuml.project.Failable;
import net.sourceforge.plantuml.project.GanttDiagram;
public class ComplementUrl implements ComplementPattern {
public IRegex toRegex(String suffix) {
return new RegexConcat( //
new RegexLeaf("COMPLEMENT" + suffix, "(" + UrlBuilder.getRegexp() + ")")); //
}
public Failable<Complement> getComplement(GanttDiagram diagram, RegexResult arg, String suffix) {
final String urlString = arg.get("COMPLEMENT" + suffix, 0);
final UrlBuilder urlBuilder = new UrlBuilder("", ModeUrl.STRICT);
final Url url = urlBuilder.getUrl(urlString);
return Failable.<Complement>ok(url);
}
}

View File

@ -50,10 +50,9 @@ import net.sourceforge.plantuml.project.core.Task;
public class SubjectTask implements SubjectPattern {
public Collection<VerbPattern> getVerbs() {
return Arrays
.<VerbPattern> asList(new VerbLasts(), new VerbTaskStarts(), new VerbTaskStartsAbsolute(),
new VerbHappens(), new VerbEnds(), new VerbTaskEndsAbsolute(), new VerbIsColored(),
new VerbIsDeleted(), new VerbIsForTask());
return Arrays.<VerbPattern>asList(new VerbLasts(), new VerbTaskStarts(), new VerbTaskStartsAbsolute(),
new VerbHappens(), new VerbEnds(), new VerbTaskEndsAbsolute(), new VerbIsColored(), new VerbIsDeleted(),
new VerbIsForTask(), new VerbLinksTo());
}
public IRegex toRegex() {

View File

@ -0,0 +1,70 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.project.lang;
import java.util.Arrays;
import java.util.Collection;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
import net.sourceforge.plantuml.project.GanttDiagram;
import net.sourceforge.plantuml.project.core.Task;
public class VerbLinksTo implements VerbPattern {
public Collection<ComplementPattern> getComplements() {
return Arrays.<ComplementPattern>asList(new ComplementUrl());
}
public IRegex toRegex() {
return new RegexLeaf("links to");
}
public Verb getVerb(GanttDiagram project, RegexResult arg) {
return new Verb() {
public CommandExecutionResult execute(Subject subject, Complement complement) {
final Task task = (Task) subject;
final Url url = (Url) complement;
task.setUrl(url);
return CommandExecutionResult.ok();
}
};
}
}

View File

@ -67,8 +67,8 @@ abstract class CommandExoArrowAny extends SingleLineCommand2<SequenceDiagram> {
final protected CommandExecutionResult executeArg(SequenceDiagram diagram, LineLocation location, RegexResult arg) {
final String body = arg.getLazzy("ARROW_BODYA", 0) + arg.getLazzy("ARROW_BODYB", 0);
final String dressing = arg.getLazzy("ARROW_DRESSING", 0);
final Participant p = diagram.getOrCreateParticipant(StringUtils
.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get("PARTICIPANT", 0)));
final Participant p = diagram.getOrCreateParticipant(
StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.get("PARTICIPANT", 0)));
final boolean sync = dressing.length() == 2;
final boolean dotted = body.contains("--");
@ -82,25 +82,25 @@ abstract class CommandExoArrowAny extends SingleLineCommand2<SequenceDiagram> {
final boolean bothDirection = arg.get("ARROW_BOTHDRESSING", 0) != null;
ArrowConfiguration config = bothDirection ? ArrowConfiguration.withDirectionBoth() : ArrowConfiguration
.withDirectionNormal();
ArrowConfiguration config = bothDirection ? ArrowConfiguration.withDirectionBoth()
: ArrowConfiguration.withDirectionNormal();
if (dotted) {
config = config.withBody(ArrowBody.DOTTED);
}
if (sync) {
config = config.withHead(ArrowHead.ASYNC);
}
config = config.withPart(getArrowPart(dressing));
final MessageExoType messageExoType = getMessageExoType(arg);
config = config.withPart(getArrowPart(dressing, messageExoType));
config = CommandArrow.applyStyle(arg.getLazzy("ARROW_STYLE", 0), config);
final String activationSpec = arg.get("ACTIVATION", 0);
if (activationSpec != null && activationSpec.charAt(0) == '*') {
diagram.activate(p, LifeEventType.CREATE, null);
}
final MessageExoType messageExoType = getMessageExoType(arg);
if (messageExoType == MessageExoType.TO_RIGHT || messageExoType == MessageExoType.TO_LEFT) {
if (containsSymbolExterior(arg, "o")) {
config = config.withDecoration2(ArrowDecoration.CIRCLE);
@ -178,12 +178,18 @@ abstract class CommandExoArrowAny extends SingleLineCommand2<SequenceDiagram> {
return CommandExecutionResult.ok();
}
private ArrowPart getArrowPart(String dressing) {
private ArrowPart getArrowPart(String dressing, MessageExoType messageExoType) {
if (dressing.contains("/")) {
return ArrowPart.BOTTOM_PART;
if (messageExoType.getDirection() == 1) {
return ArrowPart.BOTTOM_PART;
}
return ArrowPart.TOP_PART;
}
if (dressing.contains("\\")) {
return ArrowPart.TOP_PART;
if (messageExoType.getDirection() == 1) {
return ArrowPart.TOP_PART;
}
return ArrowPart.BOTTOM_PART;
}
return ArrowPart.FULL;
}

View File

@ -118,7 +118,9 @@ public class PlayingSpace implements Bordered {
for (LinkAnchor linkAnchor : linkAnchors) {
final YPositionedTile tile1 = getFromAnchor(positionedTiles, linkAnchor.getAnchor1());
final YPositionedTile tile2 = getFromAnchor(positionedTiles, linkAnchor.getAnchor2());
linkAnchor.drawAnchor(ug, tile1, tile2, skinParam);
if (tile1 != null && tile2 != null) {
linkAnchor.drawAnchor(ug, tile1, tile2, skinParam);
}
}
// System.err.println("MainTile::drawUInternal finalY=" + y);
return y;

View File

@ -97,7 +97,7 @@ public abstract class AbstractTextualComponent extends AbstractComponent {
horizontalAlignment = style.getHorizontalAlignment();
fontForStereotype = stereo.getUFont();
htmlColorForStereotype = stereo.value(PName.FontColor).asColor(getIHtmlColorSet());
this.display = display.withoutStereotype(style);
this.display = display.withoutStereotypeIfNeeded(style);
} else {
this.font = fc.getFont();
this.fontColor = fc.getColor();

View File

@ -55,6 +55,7 @@ public enum PName {
ExportedName, //
Image, //
HorizontalAlignment, //
ShowStereotype, //
ImagePosition;
public static PName getFromName(String name) {

View File

@ -49,6 +49,8 @@ public interface Value {
public double asDouble();
public boolean asBoolean();
public int asFontStyle();
public HorizontalAlignment asHorizontalAlignment();

View File

@ -57,6 +57,10 @@ public abstract class ValueAbstract implements Value {
throw new UnsupportedOperationException("Class=" + getClass());
}
public boolean asBoolean() {
throw new UnsupportedOperationException("Class=" + getClass());
}
public int asFontStyle() {
throw new UnsupportedOperationException("Class=" + getClass());
}

View File

@ -67,6 +67,10 @@ public class ValueImpl implements Value {
return set.getColorIfValid(value);
}
public boolean asBoolean() {
return "true".equalsIgnoreCase(value);
}
public int asInt() {
return Integer.parseInt(value);
}

View File

@ -59,6 +59,11 @@ public class ValueNull extends ValueAbstract implements Value {
return 0;
}
@Override
public boolean asBoolean() {
return false;
}
@Override
public String asString() {
return "";

View File

@ -50,12 +50,28 @@ public abstract class Eater {
private int i = 0;
private final String s;
private final StringLocated sl;
public Eater(String s) {
this.s = s;
public Eater(StringLocated sl) {
this.s = sl.getString();
this.sl = sl;
}
public abstract void execute(TContext context, TMemory memory) throws EaterException;
public final StringLocated getStringLocated() {
if (sl == null) {
throw new UnsupportedOperationException();
}
return sl;
}
public final LineLocation getLineLocation() {
if (sl == null) {
throw new UnsupportedOperationException();
}
return sl.getLocation();
}
public abstract void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated;
public int getCurrentPosition() {
return i;
@ -67,26 +83,31 @@ public abstract class Eater {
return result;
}
final protected TValue eatExpression(TContext context, TMemory memory) throws EaterException {
final protected TValue eatExpression(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
if (peekChar() == '{') {
String data = eatAllToEnd();
System.err.println("data=" + data);
JsonValue json = Json.parse(data);
System.err.println("json=" + json);
// System.err.println("data=" + data);
final JsonValue json = Json.parse(data);
// System.err.println("json=" + json);
return TValue.fromJson(json);
}
final TokenStack tokenStack = eatTokenStack();
return tokenStack.getResult(getLineLocation(), context, memory);
}
final protected TokenStack eatTokenStack() throws EaterException {
final TokenStack tokenStack = new TokenStack();
addIntoTokenStack(tokenStack, false);
if (tokenStack.size() == 0) {
throw new EaterException("Missing expression");
throw EaterException.located("Missing expression", getStringLocated());
}
return tokenStack.getResult(context, memory);
return tokenStack;
}
final protected TValue eatExpressionStopAtColon(TContext context, TMemory memory) throws EaterException {
final protected TValue eatExpressionStopAtColon(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
final TokenStack tokenStack = new TokenStack();
addIntoTokenStack(tokenStack, true);
return tokenStack.getResult(context, memory);
return tokenStack.getResult(getLineLocation(), context, memory);
}
final protected void addIntoTokenStack(TokenStack tokenStack, boolean stopAtColon) throws EaterException {
@ -103,7 +124,7 @@ public abstract class Eater {
final public String eatAndGetQuotedString() throws EaterException {
final char separator = peekChar();
if (TLineType.isQuote(separator) == false) {
throw new EaterException("quote10");
throw EaterException.located("quote10", getStringLocated());
}
checkAndEatChar(separator);
final StringBuilder value = new StringBuilder();
@ -124,7 +145,7 @@ public abstract class Eater {
while (true) {
char ch = peekChar();
if (ch == 0) {
throw new EaterException("until001");
throw EaterException.located("until001", getStringLocated());
}
if (level == 0 && (ch == ',' || ch == ')')) {
return value.toString().trim();
@ -167,7 +188,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 new EaterException("a002");
throw EaterException.located("a002", getStringLocated());
}
addUpToLastLetterOrUnderscoreOrDigit(varname);
return varname.toString();
@ -176,7 +197,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 new EaterException("a003");
throw EaterException.located("a003", getStringLocated());
}
addUpToLastLetterOrUnderscoreOrDigit(varname);
return varname.toString();
@ -220,7 +241,7 @@ public abstract class Eater {
final protected void checkAndEatChar(char ch) throws EaterException {
if (i >= s.length() || s.charAt(i) != ch) {
throw new EaterException("a001");
throw EaterException.located("a001", getStringLocated());
}
i++;
}
@ -269,7 +290,8 @@ public abstract class Eater {
}
}
// final protected void addUpToUnused(char separator1, char separator2, StringBuilder sb) {
// final protected void addUpToUnused(char separator1, char separator2,
// StringBuilder sb) {
// while (i < s.length()) {
// final char ch = peekChar();
// if (ch == separator1 || ch == separator2) {
@ -281,7 +303,7 @@ public abstract class Eater {
// }
final protected TFunctionImpl eatDeclareFunction(TContext context, TMemory memory, boolean unquoted,
LineLocation location, boolean allowNoParenthesis) throws EaterException {
LineLocation location, boolean allowNoParenthesis) throws EaterException, EaterExceptionLocated {
final List<TFunctionArgument> args = new ArrayList<TFunctionArgument>();
final String functionName = eatAndGetFunctionName();
skipSpaces();
@ -289,7 +311,7 @@ public abstract class Eater {
if (allowNoParenthesis) {
return new TFunctionImpl(functionName, args, unquoted);
}
throw new EaterException("Missing opening parenthesis");
throw EaterException.located("Missing opening parenthesis", getStringLocated());
}
while (true) {
skipSpaces();
@ -302,7 +324,7 @@ public abstract class Eater {
eatOneChar();
final TokenStack def = TokenStack.eatUntilCloseParenthesisOrComma(this);
def.guessFunctions();
defValue = def.getResult(context, memory);
defValue = def.getResult(getLineLocation(), context, memory);
// System.err.println("result=" + defValue);
} else {
defValue = null;
@ -314,7 +336,7 @@ public abstract class Eater {
checkAndEatChar(")");
break;
} else {
throw new EaterException("Error in function definition");
throw EaterException.located("Error in function definition", getStringLocated());
}
}
skipSpaces();
@ -322,7 +344,7 @@ public abstract class Eater {
}
final protected TFunctionImpl eatDeclareFunctionWithOptionalReturn(TContext context, TMemory memory,
boolean unquoted, LineLocation location) throws EaterException {
boolean unquoted, LineLocation location) throws EaterException, EaterExceptionLocated {
final TFunctionImpl result = eatDeclareFunction(context, memory, unquoted, location, false);
if (peekChar() == 'r') {
checkAndEatChar("return");

View File

@ -34,16 +34,17 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterAffectation extends Eater {
public EaterAffectation(String s) {
super(s);
public EaterAffectation(StringLocated sl) {
super(sl.getTrimmed());
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!");
skipSpaces();
@ -58,7 +59,7 @@ public class EaterAffectation extends Eater {
checkAndEatChar('=');
skipSpaces();
final TValue value = eatExpression(context, memory);
memory.putVariable(varname, new TVariable(value), scope);
memory.putVariable(varname, value, scope);
}
}

View File

@ -34,28 +34,29 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterAffectationDefine extends Eater {
public EaterAffectationDefine(String s) {
super(s);
public EaterAffectationDefine(StringLocated s) {
super(s.getTrimmed());
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!define");
skipSpaces();
final String varname = eatAndGetVarname();
skipSpaces();
final String tmp = eatAllToEnd();
final String tmp2 = context.applyFunctionsAndVariables(memory, tmp);
final String tmp2 = context.applyFunctionsAndVariables(memory, getLineLocation(), tmp);
final TValue value = TValue.fromString(tmp2);
// if (memory instanceof TMemoryLocal) {
// memory = ((TMemoryLocal) memory).getGlobalForInternalUseOnly();
// }
memory.putVariable(varname, new TVariable(value), TVariableScope.GLOBAL);
memory.putVariable(varname, value, TVariableScope.GLOBAL);
}
}

View File

@ -34,16 +34,17 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterAssert extends Eater {
public EaterAssert(String s) {
public EaterAssert(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!assert");
skipSpaces();
@ -54,9 +55,9 @@ public class EaterAssert extends Eater {
if (ch == ':') {
checkAndEatChar(':');
final TValue message = eatExpression(context, memory);
throw new EaterException("Assertion error : " + message.toString());
throw EaterException.located("Assertion error : " + message.toString(), getStringLocated());
}
throw new EaterException("Assertion error");
throw EaterException.located("Assertion error", getStringLocated());
}
}

View File

@ -44,12 +44,12 @@ public class EaterDeclareFunction extends Eater {
private boolean finalFlag;
public EaterDeclareFunction(StringLocated s) {
super(s.getTrimmed().getString());
super(s.getTrimmed());
this.location = s.getLocation();
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!");
boolean unquoted = false;

View File

@ -34,14 +34,16 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
public class EaterDumpMemory extends Eater {
public EaterDumpMemory(String s) {
public EaterDumpMemory(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!dump_memory");
skipSpaces();

View File

@ -34,18 +34,19 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterElseIf extends Eater {
private boolean booleanValue;
public EaterElseIf(String s) {
public EaterElseIf(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!elseif");
skipSpaces();

View File

@ -39,23 +39,25 @@ import net.sourceforge.plantuml.StringLocated;
public class EaterException extends Exception {
private final String message;
private final StringLocated location;
public EaterException(String message, StringLocated location) {
private EaterException(String message) {
this.message = message;
this.location = location;
}
public EaterException(String message) {
this(message, null);
public static EaterException unlocated(String message) {
return new EaterException(message);
}
public static EaterException located(String message, StringLocated unused) {
return new EaterException(message);
}
public final String getMessage() {
return message;
}
public final StringLocated getLocation() {
return location;
public EaterExceptionLocated withLocation(StringLocated sl) {
return EaterExceptionLocated.located(message, sl);
}
}

View File

@ -34,32 +34,31 @@
*/
package net.sourceforge.plantuml.tim;
import java.util.Deque;
import java.util.LinkedList;
import net.sourceforge.plantuml.StringLocated;
public abstract class ConditionalContexts {
public class EaterExceptionLocated extends Exception {
private final Deque<ConditionalContext> allIfs = new LinkedList<ConditionalContext>();
private final String message;
private final StringLocated location;
public ConditionalContext peekConditionalContext() {
return allIfs.peekLast();
private EaterExceptionLocated(String message, StringLocated location) {
this.message = message;
this.location = location;
}
public void addConditionalContext(ConditionalContext fromValue) {
allIfs.addLast(fromValue);
}
public ConditionalContext pollConditionalContext() {
return allIfs.pollLast();
}
public boolean areAllIfOk() {
for (ConditionalContext conditionalContext : allIfs) {
if (conditionalContext.conditionIsOkHere() == false) {
return false;
}
public static EaterExceptionLocated located(String message, StringLocated location) {
if (location == null) {
throw new IllegalArgumentException();
}
return true;
return new EaterExceptionLocated(message, location);
}
public final String getMessage() {
return message;
}
public final StringLocated getLocation() {
return location;
}
}

View File

@ -0,0 +1,78 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.json.JsonArray;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterForeach extends Eater {
private String varname;
private JsonArray jsonArray;
public EaterForeach(StringLocated s) {
super(s);
}
@Override
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!foreach");
skipSpaces();
this.varname = eatAndGetVarname();
skipSpaces();
checkAndEatChar("in");
skipSpaces();
final TValue value = eatExpression(context, memory);
this.jsonArray = (JsonArray) value.toJson();
}
public boolean isSkip() {
if (this.jsonArray == null) {
return true;
}
return this.jsonArray.size() == 0;
}
public final String getVarname() {
return varname;
}
public final JsonArray getJsonArray() {
return jsonArray;
}
}

View File

@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.tim.expression.TokenStack;
@ -47,14 +48,14 @@ public class EaterFunctionCall extends Eater {
private final boolean isLegacyDefine;
private final boolean unquoted;
public EaterFunctionCall(String s, boolean isLegacyDefine, boolean unquoted) {
public EaterFunctionCall(StringLocated s, boolean isLegacyDefine, boolean unquoted) {
super(s);
this.isLegacyDefine = isLegacyDefine;
this.unquoted = unquoted;
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipUntilChar('(');
checkAndEatChar('(');
skipSpaces();
@ -66,7 +67,7 @@ public class EaterFunctionCall extends Eater {
skipSpaces();
if (isLegacyDefine || unquoted) {
final String tmp = eatAndGetOptionalQuotedString();
final String tmp2 = context.applyFunctionsAndVariables(memory, tmp);
final String tmp2 = context.applyFunctionsAndVariables(memory, getLineLocation(), tmp);
// final TVariable var = memory.getVariable(tmp);
// final TValue result = var == null ? TValue.fromString(tmp) : var.getValue2();
final TValue result = TValue.fromString(tmp2);
@ -74,7 +75,7 @@ public class EaterFunctionCall extends Eater {
} else {
final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace();
tokens.guessFunctions();
final TValue result = tokens.getResult(context, memory);
final TValue result = tokens.getResult(getLineLocation(), context, memory);
values.add(result);
}
skipSpaces();
@ -85,7 +86,7 @@ public class EaterFunctionCall extends Eater {
if (ch == ')') {
break;
}
throw new EaterException("call001");
throw EaterException.located("call001", getStringLocated());
}
}

View File

@ -34,18 +34,19 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterIf extends Eater {
private boolean booleanValue;
public EaterIf(String s) {
public EaterIf(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!if");
skipSpaces();

View File

@ -34,19 +34,21 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.preproc.EvalBoolean;
import net.sourceforge.plantuml.preproc.Truth;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterIfdef extends Eater {
private String expression;
public EaterIfdef(String s) {
public EaterIfdef(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!ifdef");
skipSpaces();
@ -57,7 +59,7 @@ public class EaterIfdef extends Eater {
final EvalBoolean eval = new EvalBoolean(expression, new Truth() {
public boolean isTrue(String varname) {
final TVariable currentValue = memory.getVariable(varname);
final TValue currentValue = memory.getVariable(varname);
return currentValue != null || context.doesFunctionExist(varname);
}
});

View File

@ -34,16 +34,19 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterIfndef extends Eater {
private String varname;
public EaterIfndef(String s) {
public EaterIfndef(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!ifndef");
skipSpaces();
@ -51,7 +54,7 @@ public class EaterIfndef extends Eater {
}
public boolean isTrue(TContext context, TMemory memory) {
final TVariable currentValue = memory.getVariable(varname);
final TValue currentValue = memory.getVariable(varname);
return currentValue == null && context.doesFunctionExist(varname) == false;
}

View File

@ -34,20 +34,22 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
public class EaterImport extends Eater {
private String location;
public EaterImport(String s) {
public EaterImport(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!import");
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd());
this.location = context.applyFunctionsAndVariables(memory, getLineLocation(), this.eatAllToEnd());
}

View File

@ -34,6 +34,7 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.preproc2.PreprocessorIncludeStrategy;
public class EaterInclude extends Eater {
@ -41,12 +42,12 @@ public class EaterInclude extends Eater {
private String location;
private PreprocessorIncludeStrategy strategy = PreprocessorIncludeStrategy.DEFAULT;
public EaterInclude(String s) {
public EaterInclude(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!include");
final char peekChar = peekChar();
@ -64,7 +65,7 @@ public class EaterInclude extends Eater {
}
}
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd());
this.location = context.applyFunctionsAndVariables(memory, getLineLocation(), this.eatAllToEnd());
}

View File

@ -34,21 +34,22 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
public class EaterIncludeDef extends Eater {
private String location;
public EaterIncludeDef(String s) {
public EaterIncludeDef(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!includedef");
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd());
this.location = context.applyFunctionsAndVariables(memory, getLineLocation(), this.eatAllToEnd());
}

View File

@ -34,20 +34,22 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
public class EaterIncludesub extends Eater {
private String location;
public EaterIncludesub(String s) {
public EaterIncludesub(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!includesub");
skipSpaces();
this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd());
this.location = context.applyFunctionsAndVariables(memory, getLineLocation(), this.eatAllToEnd());
}

View File

@ -34,25 +34,22 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.StringLocated;
public class EaterLegacyDefine extends Eater {
private TFunctionImpl function;
private final LineLocation location;
public EaterLegacyDefine(StringLocated s) {
super(s.getTrimmed().getString());
this.location = s.getLocation();
super(s.getTrimmed());
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!define");
skipSpaces();
function = eatDeclareFunction(context, memory, true, location, false);
function = eatDeclareFunction(context, memory, true, getLineLocation(), false);
final String def = this.eatAllToEnd();
function.setFunctionType(TFunctionType.LEGACY_DEFINE);
function.setLegacyDefinition(def);

View File

@ -34,25 +34,22 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.StringLocated;
public class EaterLegacyDefineLong extends Eater {
private TFunctionImpl function;
private final LineLocation location;
public EaterLegacyDefineLong(StringLocated s) {
super(s.getTrimmed().getString());
this.location = s.getLocation();
super(s.getTrimmed());
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!definelong");
skipSpaces();
function = eatDeclareFunction(context, memory, true, location, true);
function = eatDeclareFunction(context, memory, true, getLineLocation(), true);
function.setFunctionType(TFunctionType.LEGACY_DEFINELONG);
}

View File

@ -35,19 +35,20 @@
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.StringLocated;
public class EaterLog extends Eater {
public EaterLog(String s) {
public EaterLog(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!log");
skipSpaces();
final String logData = context.applyFunctionsAndVariables(memory, this.eatAllToEnd());
final String logData = context.applyFunctionsAndVariables(memory, getLineLocation(), this.eatAllToEnd());
Log.error("[Log] " + logData);
}

View File

@ -34,18 +34,19 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
public class EaterReturn extends Eater {
private TValue value;
public EaterReturn(String s) {
public EaterReturn(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
skipSpaces();
checkAndEatChar("!return");
skipSpaces();

View File

@ -34,22 +34,24 @@
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
public class EaterStartsub extends Eater {
private String subname;
public EaterStartsub(String s) {
public EaterStartsub(StringLocated s) {
super(s);
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!startsub");
skipSpaces();
this.subname = eatAllToEnd();
if (this.subname.matches("\\w+") == false) {
throw new EaterException("Bad sub name");
throw EaterException.located("Bad sub name", getStringLocated());
}
}

View File

@ -39,11 +39,11 @@ import net.sourceforge.plantuml.StringLocated;
public class EaterUndef extends Eater {
public EaterUndef(StringLocated s) {
super(s.getTrimmed().getString());
super(s.getTrimmed());
}
@Override
public void execute(TContext context, TMemory memory) throws EaterException {
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!undef");
skipSpaces();

View File

@ -0,0 +1,59 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TokenStack;
public class EaterWhile extends Eater {
private TokenStack expression;
public EaterWhile(StringLocated s) {
super(s);
}
@Override
public void analyze(TContext context, TMemory memory) throws EaterException {
skipSpaces();
checkAndEatChar("!while");
skipSpaces();
this.expression = eatTokenStack();
}
public final TokenStack getWhileExpression() {
return expression;
}
}

View File

@ -0,0 +1,89 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.json.JsonArray;
import net.sourceforge.plantuml.tim.iterator.CodePosition;
public class ExecutionContextForeach {
private final String varname;
private final JsonArray jsonArray;
private final CodePosition codePosition;
private boolean skipMe;
private int currentIndex;
private ExecutionContextForeach(String varname, JsonArray jsonArray, CodePosition codePosition) {
this.varname = varname;
this.jsonArray = jsonArray;
this.codePosition = codePosition;
}
public static ExecutionContextForeach fromValue(String varname, JsonArray jsonArray, CodePosition codePosition) {
return new ExecutionContextForeach(varname, jsonArray, codePosition);
}
public void skipMeNow() {
skipMe = true;
}
public final boolean isSkipMe() {
return skipMe;
}
public CodePosition getStartForeach() {
return codePosition;
}
public final int currentIndex() {
return currentIndex;
}
public final void inc() {
this.currentIndex++;
if (currentIndex >= jsonArray.size()) {
this.skipMe = true;
}
}
public final String getVarname() {
return varname;
}
public final JsonArray getJsonArray() {
return jsonArray;
}
}

View File

@ -34,20 +34,20 @@
*/
package net.sourceforge.plantuml.tim;
public class ConditionalContext {
public class ExecutionContextIf {
private boolean isTrue;
private boolean hasBeenBurn;
private ConditionalContext(boolean isTrue) {
private ExecutionContextIf(boolean isTrue) {
this.isTrue = isTrue;
if (this.isTrue) {
hasBeenBurn = true;
}
}
public static ConditionalContext fromValue(boolean isTrue) {
return new ConditionalContext(isTrue);
public static ExecutionContextIf fromValue(boolean isTrue) {
return new ExecutionContextIf(isTrue);
}
public boolean conditionIsOkHere() {

View File

@ -0,0 +1,78 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.tim.expression.TokenStack;
import net.sourceforge.plantuml.tim.iterator.CodePosition;
public class ExecutionContextWhile {
private final TokenStack whileExpression;
private final CodePosition codePosition;
private boolean skipMe;
private ExecutionContextWhile(TokenStack whileExpression, CodePosition codePosition) {
this.whileExpression = whileExpression;
this.codePosition = codePosition;
}
@Override
public String toString() {
return whileExpression.toString() + " " + codePosition;
}
public static ExecutionContextWhile fromValue(TokenStack whileExpression, CodePosition codePosition) {
return new ExecutionContextWhile(whileExpression, codePosition);
}
public TValue conditionValue(LineLocation location, TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
return whileExpression.getResult(location, context, memory);
}
public void skipMe() {
skipMe = true;
}
public final boolean isSkipMe() {
return skipMe;
}
public CodePosition getStartWhile() {
return codePosition;
}
}

View File

@ -0,0 +1,91 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import java.util.Deque;
import java.util.LinkedList;
public abstract class ExecutionContexts {
private final Deque<ExecutionContextIf> allIfs = new LinkedList<ExecutionContextIf>();
private final Deque<ExecutionContextWhile> allWhiles = new LinkedList<ExecutionContextWhile>();
private final Deque<ExecutionContextForeach> allForeachs = new LinkedList<ExecutionContextForeach>();
public void addIf(ExecutionContextIf value) {
allIfs.addLast(value);
}
public void addWhile(ExecutionContextWhile value) {
allWhiles.addLast(value);
}
public void addForeach(ExecutionContextForeach value) {
allForeachs.addLast(value);
}
public ExecutionContextIf peekIf() {
return allIfs.peekLast();
}
public ExecutionContextWhile peekWhile() {
return allWhiles.peekLast();
}
public ExecutionContextForeach peekForeach() {
return allForeachs.peekLast();
}
public ExecutionContextIf pollIf() {
return allIfs.pollLast();
}
public ExecutionContextWhile pollWhile() {
return allWhiles.pollLast();
}
public ExecutionContextForeach pollForeach() {
return allForeachs.pollLast();
}
public boolean areAllIfOk(TContext context, TMemory memory) throws EaterException {
for (ExecutionContextIf conditionalContext : allIfs) {
if (conditionalContext.conditionIsOkHere() == false) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,139 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.StringLocated;
public class FunctionsSet {
private final Map<TFunctionSignature, TFunction> functions = new HashMap<TFunctionSignature, TFunction>();
private final Set<TFunctionSignature> functionsFinal = new HashSet<TFunctionSignature>();
private final Trie functions3 = new TrieImpl();
private TFunctionImpl pendingFunction;
public TFunction getFunctionSmart(TFunctionSignature searched) {
final TFunction func = this.functions.get(searched);
if (func != null) {
return func;
}
for (TFunction candidate : this.functions.values()) {
if (candidate.getSignature().sameNameAs(searched) == false) {
continue;
}
if (candidate.canCover(searched.getNbArg())) {
return candidate;
}
}
return null;
}
public int size() {
return functions().size();
}
public Map<TFunctionSignature, TFunction> functions() {
return Collections.unmodifiableMap(functions);
}
public String getLonguestMatchStartingIn(String s) {
return functions3.getLonguestMatchStartingIn(s);
}
public TFunctionImpl pendingFunction() {
return pendingFunction;
}
public void addFunction(TFunction func) {
if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) {
((TFunctionImpl) func).finalizeEnddefinelong();
}
this.functions.put(func.getSignature(), func);
this.functions3.add(func.getSignature().getFunctionName() + "(");
}
public void executeEndfunction() {
this.addFunction(this.pendingFunction);
this.pendingFunction = null;
}
public void executeLegacyDefine(TContext context, TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0048", s);
}
final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s);
legacyDefine.analyze(context, memory);
final TFunction function = legacyDefine.getFunction();
this.functions.put(function.getSignature(), function);
this.functions3.add(function.getSignature().getFunctionName() + "(");
}
public void executeLegacyDefineLong(TContext context, TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0068", s);
}
final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s);
legacyDefineLong.analyze(context, memory);
this.pendingFunction = legacyDefineLong.getFunction();
}
public void executeDeclareFunction(TContext context, TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
if (this.pendingFunction != null) {
throw EaterException.located("already0068", s);
}
final EaterDeclareFunction declareFunction = new EaterDeclareFunction(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", s);
}
if (finalFlag) {
this.functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) {
this.addFunction(declareFunction.getFunction());
} else {
this.pendingFunction = declareFunction.getFunction();
}
}
}

View File

@ -47,6 +47,7 @@ import java.util.Set;
import net.sourceforge.plantuml.DefinitionsContainer;
import net.sourceforge.plantuml.FileSystem;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.json.JsonObject;
@ -64,6 +65,18 @@ import net.sourceforge.plantuml.preproc2.PreprocessorIncludeStrategy;
import net.sourceforge.plantuml.preproc2.PreprocessorUtils;
import net.sourceforge.plantuml.tim.expression.Knowledge;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.tim.iterator.CodeIterator;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorAffectation;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorForeach;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorFunction;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorIf;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorImpl;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorInnerComment;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorLegacyDefine;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorLongComment;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorShortComment;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorSub;
import net.sourceforge.plantuml.tim.iterator.CodeIteratorWhile;
import net.sourceforge.plantuml.tim.stdlib.AlwaysFalse;
import net.sourceforge.plantuml.tim.stdlib.AlwaysTrue;
import net.sourceforge.plantuml.tim.stdlib.CallUserFunction;
@ -91,15 +104,12 @@ public class TContext {
private final List<StringLocated> resultList = new ArrayList<StringLocated>();
private final List<StringLocated> debug = new ArrayList<StringLocated>();
private final Map<TFunctionSignature, TFunction> functions2 = new HashMap<TFunctionSignature, TFunction>();
private final Set<TFunctionSignature> functionsFinal = new HashSet<TFunctionSignature>();
private final Trie functions3 = new TrieImpl();
public final FunctionsSet functionsSet = new FunctionsSet();
private ImportedFiles importedFiles;
private final String charset;
private TFunctionImpl pendingFunction;
private Sub pendingSub;
private boolean inLongComment;
private final Map<String, Sub> subs = new HashMap<String, Sub>();
private final DefinitionsContainer definitionsContainer;
@ -107,28 +117,28 @@ public class TContext {
private final Set<FileWithSuffix> filesUsedCurrent = new HashSet<FileWithSuffix>();
private void addStandardFunctions(Defines defines) {
addFunction(new Strlen());
addFunction(new Substr());
addFunction(new FileExists());
addFunction(new Getenv());
addFunction(new Dirpath(defines));
addFunction(new Filename(defines));
addFunction(new DateFunction());
addFunction(new Strpos());
addFunction(new InvokeVoidFunction());
addFunction(new AlwaysFalse());
addFunction(new AlwaysTrue());
addFunction(new LogicalNot());
addFunction(new FunctionExists());
addFunction(new VariableExists());
addFunction(new CallUserFunction());
addFunction(new RetrieveVoidFunction());
addFunction(new SetVariableValue());
addFunction(new GetVariableValue());
addFunction(new IntVal());
addFunction(new GetVersion());
addFunction(new Upper());
addFunction(new Lower());
functionsSet.addFunction(new Strlen());
functionsSet.addFunction(new Substr());
functionsSet.addFunction(new FileExists());
functionsSet.addFunction(new Getenv());
functionsSet.addFunction(new Dirpath(defines));
functionsSet.addFunction(new Filename(defines));
functionsSet.addFunction(new DateFunction());
functionsSet.addFunction(new Strpos());
functionsSet.addFunction(new InvokeVoidFunction());
functionsSet.addFunction(new AlwaysFalse());
functionsSet.addFunction(new AlwaysTrue());
functionsSet.addFunction(new LogicalNot());
functionsSet.addFunction(new FunctionExists());
functionsSet.addFunction(new VariableExists());
functionsSet.addFunction(new CallUserFunction());
functionsSet.addFunction(new RetrieveVoidFunction());
functionsSet.addFunction(new SetVariableValue());
functionsSet.addFunction(new GetVariableValue());
functionsSet.addFunction(new IntVal());
functionsSet.addFunction(new GetVersion());
functionsSet.addFunction(new Upper());
functionsSet.addFunction(new Lower());
// !exit
// !log
// %min
@ -151,155 +161,101 @@ public class TContext {
public Knowledge asKnowledge(final TMemory memory) {
return new Knowledge() {
public TVariable getVariable(String name) {
public TValue getVariable(String name) {
if (name.contains(".")) {
return fromJson(memory, name);
}
return memory.getVariable(name);
}
public TFunction getFunction(TFunctionSignature name) {
return getFunctionSmart(name);
return functionsSet.getFunctionSmart(name);
}
};
}
public TFunction getFunctionSmart(TFunctionSignature searched) {
final TFunction func = functions2.get(searched);
if (func != null) {
return func;
private TValue fromJson(TMemory memory, String name) {
final int x = name.indexOf('.');
final TValue data = memory.getVariable(name.substring(0, x));
if (data == null) {
return null;
}
for (TFunction candidate : functions2.values()) {
if (candidate.getSignature().sameNameAs(searched) == false) {
continue;
}
if (candidate.canCover(searched.getNbArg())) {
return candidate;
}
}
return null;
final JsonObject json = (JsonObject) data.toJson();
// System.err.println("json=" + json);
// System.err.println("json=" + json.getClass());
// System.err.println("json2=" + name.substring(x + 1));
final JsonValue result = json.get(name.substring(x + 1));
// System.err.println("result=" + result);
return TValue.fromJson(result);
}
public void executeOneLine(TMemory memory, TLineType type, StringLocated s, TFunctionType fromType)
throws EaterException {
private CodeIterator buildCodeIterator(TMemory memory, List<StringLocated> body) {
final CodeIterator it10 = new CodeIteratorImpl(body);
final CodeIterator it20 = new CodeIteratorLongComment(it10, debug);
final CodeIterator it30 = new CodeIteratorShortComment(it20, debug);
final CodeIterator it40 = new CodeIteratorInnerComment(it30);
final CodeIterator it50 = new CodeIteratorSub(it40, subs, this, memory);
final CodeIterator it60 = new CodeIteratorFunction(it50, this, memory, functionsSet, debug);
final CodeIterator it70 = new CodeIteratorIf(it60, this, memory, debug);
final CodeIterator it80 = new CodeIteratorLegacyDefine(it70, this, memory, functionsSet, debug);
final CodeIterator it90 = new CodeIteratorWhile(it80, this, memory, debug);
final CodeIterator it100 = new CodeIteratorForeach(it90, this, memory, debug);
final CodeIterator it110 = new CodeIteratorAffectation(it100, this, memory, debug);
this.debug.add(s);
assert type == TLineType.getFromLine(s.getString());
final CodeIterator it = it110;
return it;
}
if (this.inLongComment == false && type == TLineType.STARTSUB) {
if (pendingSub != null) {
throw new EaterException("Cannot nest sub");
public void executeLines(TMemory memory, List<StringLocated> body, TFunctionType ftype)
throws EaterExceptionLocated {
final CodeIterator it = buildCodeIterator(memory, body);
StringLocated s = null;
try {
while ((s = it.peek()) != null) {
executeOneLineSafe(memory, s, ftype);
it.next();
}
final EaterStartsub eater = new EaterStartsub(s.getTrimmed().getString());
eater.execute(this, memory);
this.pendingSub = new Sub(eater.getSubname());
this.subs.put(eater.getSubname(), this.pendingSub);
return;
}
if (this.inLongComment == false && type == TLineType.ENDSUB) {
if (pendingSub == null) {
throw new EaterException("No corresponding !startsub");
}
final Sub newly = this.pendingSub;
this.pendingSub = null;
this.runSub(memory, newly);
return;
}
// if (this.inLongComment == false && type == TLineType.INCLUDESUB) {
// this.executeIncludesub(memory, s);
// return;
// }
if (pendingSub != null) {
pendingSub.add(s);
return;
} catch (EaterException e) {
throw e.withLocation(s);
}
if (this.getPendingFunction() != null) {
if (this.inLongComment == false && type == TLineType.END_FUNCTION) {
this.executeEndfunction();
} else {
this.getPendingFunction().addBody(s);
}
return;
}
private void executeLinesInternal(TMemory memory, List<StringLocated> body, TFunctionType ftype)
throws EaterExceptionLocated, EaterException {
final CodeIterator it = buildCodeIterator(memory, body);
StringLocated s = null;
while ((s = it.peek()) != null) {
executeOneLineSafe(memory, s, ftype);
it.next();
}
if (this.inLongComment && s.getTrimmed().getString().endsWith("'/")) {
this.inLongComment = false;
return;
}
}
if (type == TLineType.COMMENT_LONG_START) {
this.inLongComment = true;
return;
private void executeOneLineSafe(TMemory memory, StringLocated s, TFunctionType ftype)
throws EaterException, EaterExceptionLocated {
try {
this.debug.add(s);
executeOneLineNotSafe(memory, s, ftype);
} catch (Exception e) {
if (e instanceof EaterException)
throw (EaterException) e;
if (e instanceof EaterExceptionLocated)
throw (EaterExceptionLocated) e;
e.printStackTrace();
throw EaterException.located("Fatal parsing error", s);
}
if (this.inLongComment) {
return;
}
if (type == TLineType.COMMENT_SIMPLE) {
return;
}
s = s.removeInnerComment();
}
if (type == TLineType.IF) {
this.executeIf(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.IFDEF) {
this.executeIfdef(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.IFNDEF) {
this.executeIfndef(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.ELSE) {
this.executeElse(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.ELSEIF) {
this.executeElseIf(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.ENDIF) {
this.executeEndif(memory, s.getTrimmed().getString());
return;
}
private void executeOneLineNotSafe(TMemory memory, StringLocated s, TFunctionType ftype)
throws EaterException, EaterExceptionLocated {
final TLineType type = s.getType();
final ConditionalContext conditionalContext = memory.peekConditionalContext();
if (conditionalContext != null && memory.areAllIfOk() == false) {
return;
}
if (this.inLongComment == false && type == TLineType.INCLUDESUB) {
if (type == TLineType.INCLUDESUB) {
this.executeIncludesub(memory, s);
return;
}
if (type == TLineType.DUMP_MEMORY) {
this.executeDumpMemory(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.ASSERT) {
this.executeAssert(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.UNDEF) {
this.executeUndef(memory, s);
return;
} else if (fromType != TFunctionType.RETURN && type == TLineType.PLAIN) {
this.addPlain(memory, s);
return;
} else if (fromType == TFunctionType.RETURN && type == TLineType.RETURN) {
// Actually, ignore because we are in a if
return;
} else if (type == TLineType.LEGACY_DEFINE) {
this.executeLegacyDefine(memory, s);
return;
} else if (type == TLineType.LEGACY_DEFINELONG) {
this.executeLegacyDefineLong(memory, s);
return;
} else if (type == TLineType.AFFECTATION_DEFINE) {
this.executeAffectationDefine(memory, s.getTrimmed().getString());
return;
} else if (type == TLineType.AFFECTATION) {
this.executeAffectation(memory, s.getTrimmed().getString());
return;
} else if (fromType == null && type == TLineType.DECLARE_FUNCTION) {
this.executeDeclareFunction(memory, s);
return;
} else if (fromType == null && type == TLineType.END_FUNCTION) {
CommandExecutionResult.error("error endfunc");
return;
} else if (type == TLineType.INCLUDE) {
this.executeInclude(memory, s);
return;
@ -309,18 +265,39 @@ public class TContext {
} else if (type == TLineType.IMPORT) {
this.executeImport(memory, s);
return;
}
if (type == TLineType.DUMP_MEMORY) {
this.executeDumpMemory(memory, s.getTrimmed());
return;
} else if (type == TLineType.ASSERT) {
this.executeAssert(memory, s.getTrimmed());
return;
} else if (type == TLineType.UNDEF) {
this.executeUndef(memory, s);
return;
} else if (ftype != TFunctionType.RETURN && type == TLineType.PLAIN) {
this.addPlain(memory, s);
return;
} else if (ftype == TFunctionType.RETURN && type == TLineType.RETURN) {
// Actually, ignore because we are in a if
return;
} else if (type == TLineType.AFFECTATION_DEFINE) {
this.executeAffectationDefine(memory, s);
return;
} else if (ftype == null && type == TLineType.END_FUNCTION) {
CommandExecutionResult.error("error endfunc");
return;
} else if (type == TLineType.LOG) {
this.executeLog(memory, s);
return;
} else {
// Thread.dumpStack();
throw new EaterException("Parsing Error");
// throw new UnsupportedOperationException("type=" + type + " fromType=" + fromType);
throw EaterException.located("Parsing Error", s);
}
}
private void addPlain(TMemory memory, StringLocated s) throws EaterException {
StringLocated tmp = applyFunctionsAndVariables(memory, s);
private void addPlain(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
StringLocated tmp = applyFunctionsAndVariablesInternal(memory, s);
if (tmp != null) {
if (pendingAdd != null) {
tmp = new StringLocated(pendingAdd + tmp.getString(), tmp.getLocation());
@ -330,136 +307,32 @@ public class TContext {
}
}
private void executeAffectationDefine(TMemory memory, String s) throws EaterException {
new EaterAffectationDefine(s).execute(this, memory);
private void executeAffectationDefine(TMemory memory, StringLocated s)
throws EaterException, EaterExceptionLocated {
new EaterAffectationDefine(s).analyze(this, memory);
}
private void executeAffectation(TMemory memory, String s) throws EaterException {
new EaterAffectation(s).execute(this, memory);
}
private void executeIf(TMemory memory, String s) throws EaterException {
final EaterIf condition = new EaterIf(s);
condition.execute(this, memory);
final boolean isTrue = condition.isTrue();
memory.addConditionalContext(ConditionalContext.fromValue(isTrue));
}
private void executeElseIf(TMemory memory, String s) throws EaterException {
final ConditionalContext poll = memory.peekConditionalContext();
if (poll == null) {
throw new EaterException("No if related to this else");
}
poll.enteringElseIf();
if (poll.hasBeenBurn() == false) {
final EaterElseIf condition = new EaterElseIf(s);
condition.execute(this, memory);
final boolean isTrue = condition.isTrue();
if (isTrue) {
poll.nowInSomeElseIf();
}
}
}
private void executeDumpMemory(TMemory memory, String s) throws EaterException {
private void executeDumpMemory(TMemory memory, StringLocated s) throws EaterException {
final EaterDumpMemory condition = new EaterDumpMemory(s);
condition.execute(this, memory);
condition.analyze(this, memory);
}
private void executeAssert(TMemory memory, String s) throws EaterException {
private void executeAssert(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterAssert condition = new EaterAssert(s);
condition.execute(this, memory);
}
private void executeIfdef(TMemory memory, String s) throws EaterException {
final EaterIfdef condition = new EaterIfdef(s);
condition.execute(this, memory);
final boolean isTrue = condition.isTrue(this, memory);
memory.addConditionalContext(ConditionalContext.fromValue(isTrue));
}
private void executeIfndef(TMemory memory, String s) throws EaterException {
final EaterIfndef condition = new EaterIfndef(s);
condition.execute(this, memory);
final boolean isTrue = condition.isTrue(this, memory);
memory.addConditionalContext(ConditionalContext.fromValue(isTrue));
}
private void executeElse(TMemory memory, String s) throws EaterException {
final ConditionalContext poll = memory.peekConditionalContext();
if (poll == null) {
throw new EaterException("No if related to this else");
}
poll.nowInElse();
}
private void executeEndif(TMemory memory, String s) throws EaterException {
final ConditionalContext poll = memory.pollConditionalContext();
if (poll == null) {
throw new EaterException("No if related to this endif");
}
}
private void executeDeclareFunction(TMemory memory, StringLocated s) throws EaterException {
if (this.pendingFunction != null) {
throw new EaterException("already0068");
}
final EaterDeclareFunction declareFunction = new EaterDeclareFunction(s);
declareFunction.execute(this, memory);
final boolean finalFlag = declareFunction.getFinalFlag();
final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature();
final TFunction previous = functions2.get(declaredSignature);
if (previous != null && (finalFlag || functionsFinal.contains(declaredSignature))) {
throw new EaterException("This function is already defined");
}
if (finalFlag) {
functionsFinal.add(declaredSignature);
}
if (declareFunction.getFunction().hasBody()) {
addFunction(declareFunction.getFunction());
} else {
this.pendingFunction = declareFunction.getFunction();
}
condition.analyze(this, memory);
}
private void executeUndef(TMemory memory, StringLocated s) throws EaterException {
final EaterUndef undef = new EaterUndef(s);
undef.execute(this, memory);
undef.analyze(this, memory);
}
private void executeLegacyDefine(TMemory memory, StringLocated s) throws EaterException {
if (this.pendingFunction != null) {
throw new EaterException("already0048");
}
final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s);
legacyDefine.execute(this, memory);
final TFunction function = legacyDefine.getFunction();
// if (functions2.containsKey(function.getSignature())) {
// throw new EaterException("already0047");
// }
this.functions2.put(function.getSignature(), function);
this.functions3.add(function.getSignature().getFunctionName() + "(");
}
private void executeLegacyDefineLong(TMemory memory, StringLocated s) throws EaterException {
if (this.pendingFunction != null) {
throw new EaterException("already0068");
}
final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s);
legacyDefineLong.execute(this, memory);
// if (functions2.containsKey(legacyDefineLong.getFunction().getSignature())) {
// throw new EaterException("already0066");
// }
this.pendingFunction = legacyDefineLong.getFunction();
}
private StringLocated applyFunctionsAndVariables(TMemory memory, StringLocated located) throws EaterException {
if (memory.isEmpty() && functions2.size() == 0) {
private StringLocated applyFunctionsAndVariablesInternal(TMemory memory, StringLocated located)
throws EaterException, EaterExceptionLocated {
if (memory.isEmpty() && functionsSet.size() == 0) {
return located;
}
final String s = located.getString();
final String result = applyFunctionsAndVariables(memory, s);
final String result = applyFunctionsAndVariables(memory, located.getLocation(), located.getString());
if (result == null) {
return null;
}
@ -468,127 +341,89 @@ public class TContext {
private String pendingAdd = null;
public String applyFunctionsAndVariables(TMemory memory, String s) throws EaterException {
public String applyFunctionsAndVariables(TMemory memory, LineLocation location, String str)
throws EaterException, EaterExceptionLocated {
// https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
// https://stackoverflow.com/questions/1326682/java-replacing-multiple-different-substring-in-a-string-at-once-or-in-the-most
// https://en.wikipedia.org/wiki/String-searching_algorithm
// https://www.quora.com/What-is-the-most-efficient-algorithm-to-replace-all-occurrences-of-a-pattern-P-in-a-string-with-a-pattern-P
// https://en.wikipedia.org/wiki/Trie
if (memory.isEmpty() && functions2.size() == 0) {
return s;
if (memory.isEmpty() && functionsSet.size() == 0) {
return str;
}
final StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
final String presentFunction = getFunctionNameAt(s, i);
for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
final String presentFunction = getFunctionNameAt(str, i);
if (presentFunction != null) {
final String sub = s.substring(i);
final EaterFunctionCall call = new EaterFunctionCall(sub, isLegacyDefine(presentFunction),
isUnquoted(presentFunction));
call.execute(this, memory);
final TFunction function = getFunctionSmart(new TFunctionSignature(presentFunction, call.getValues()
.size()));
final String sub = str.substring(i);
final EaterFunctionCall call = new EaterFunctionCall(new StringLocated(sub, location),
isLegacyDefine(presentFunction), isUnquoted(presentFunction));
call.analyze(this, memory);
final TFunction function = functionsSet
.getFunctionSmart(new TFunctionSignature(presentFunction, call.getValues().size()));
if (function == null) {
throw new EaterException("Function not found " + presentFunction);
throw EaterException.located("Function not found " + presentFunction,
new StringLocated(str, location));
}
if (function.getFunctionType() == TFunctionType.VOID) {
this.pendingAdd = result.toString();
executeVoid3(memory, sub, function);
executeVoid3(location, memory, sub, function);
return null;
}
if (function.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) {
this.pendingAdd = s.substring(0, i);
executeVoid3(memory, sub, function);
this.pendingAdd = str.substring(0, i);
executeVoid3(location, memory, sub, function);
return null;
}
assert function.getFunctionType() == TFunctionType.RETURN
|| function.getFunctionType() == TFunctionType.LEGACY_DEFINE;
final TValue functionReturn = function.executeReturn(this, memory, call.getValues());
final TValue functionReturn = function.executeReturn(this, memory, location, call.getValues());
result.append(functionReturn.toString());
i += call.getCurrentPosition() - 1;
continue;
} else if (new VariableManager(this, memory, location).getVarnameAt(str, i) != null) {
i = new VariableManager(this, memory, location).replaceVariables(str, i, result);
} else {
result.append(c);
}
final String presentVariable = getVarnameAt(memory, s, i);
if (presentVariable != null) {
if (result.toString().endsWith("##")) {
result.setLength(result.length() - 2);
}
final TValue value = memory.getVariable(presentVariable).getValue();
i += presentVariable.length() - 1;
if (value.isJson()) {
JsonValue jsonValue = (JsonObject) value.toJson();
// System.err.println("jsonValue1=" + jsonValue);
i++;
while (true) {
final char n = s.charAt(i);
// System.err.println("n=" + n);
if (n != '.') {
if (jsonValue.isString()) {
result.append(jsonValue.asString());
} else {
result.append(jsonValue.toString());
}
break;
}
i++;
final StringBuilder fieldName = new StringBuilder();
while (true) {
if (Character.isJavaIdentifierPart(s.charAt(i)) == false) {
break;
}
fieldName.append(s.charAt(i));
i++;
}
// System.err.println("fieldName=" + fieldName);
jsonValue = ((JsonObject) jsonValue).get(fieldName.toString());
// System.err.println("jsonValue2=" + jsonValue);
}
} else {
result.append(value.toString());
}
if (i + 2 < s.length() && s.charAt(i + 1) == '#' && s.charAt(i + 2) == '#') {
i += 2;
}
continue;
}
result.append(c);
}
return result.toString();
}
private void executeVoid3(TMemory memory, String s, TFunction function) throws EaterException {
function.executeVoid(this, memory, s);
private void executeVoid3(LineLocation location, TMemory memory, String s, TFunction function)
throws EaterException, EaterExceptionLocated {
function.executeVoid(this, memory, location, s);
}
private void executeImport(TMemory memory, StringLocated s) throws EaterException {
final EaterImport _import = new EaterImport(s.getTrimmed().getString());
_import.execute(this, memory);
private void executeImport(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterImport _import = new EaterImport(s.getTrimmed());
_import.analyze(this, memory);
try {
final File file = FileSystem.getInstance().getFile(
applyFunctionsAndVariables(memory, _import.getLocation()));
final File file = FileSystem.getInstance()
.getFile(applyFunctionsAndVariables(memory, s.getLocation(), _import.getLocation()));
if (file.exists() && file.isDirectory() == false) {
importedFiles.add(file);
return;
}
} catch (IOException e) {
e.printStackTrace();
throw new EaterException("Cannot import " + e.getMessage());
throw EaterException.located("Cannot import " + e.getMessage(), s);
}
throw new EaterException("Cannot import");
throw EaterException.located("Cannot import", s);
}
private void executeLog(TMemory memory, StringLocated s) throws EaterException {
final EaterLog log = new EaterLog(s.getTrimmed().getString());
log.execute(this, memory);
private void executeLog(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterLog log = new EaterLog(s.getTrimmed());
log.analyze(this, memory);
}
private void executeIncludesub(TMemory memory, StringLocated s) throws EaterException {
private void executeIncludesub(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
ImportedFiles saveImportedFiles = null;
try {
final EaterIncludesub include = new EaterIncludesub(s.getTrimmed().getString());
include.execute(this, memory);
final EaterIncludesub include = new EaterIncludesub(s.getTrimmed());
include.analyze(this, memory);
final String location = include.getLocation();
final int idx = location.indexOf('!');
Sub sub = null;
@ -603,21 +438,20 @@ public class TContext {
final Reader reader = f2.getReader(charset);
ReadLine readerline = ReadLineReader.create(reader, location, s.getLocation());
readerline = new UncommentReadLine(readerline);
// readerline = new ReadLineQuoteComment(true).applyFilter(readerline);
sub = Sub.fromFile(readerline, blocname, this, memory);
}
} catch (IOException e) {
e.printStackTrace();
throw new EaterException("cannot include " + e);
throw EaterException.located("cannot include " + e, s);
}
}
if (sub == null) {
sub = subs.get(location);
}
if (sub == null) {
throw new EaterException("cannot include " + location);
throw EaterException.located("cannot include " + location, s);
}
runSub(memory, sub);
executeLinesInternal(memory, sub.lines(), null);
} finally {
if (saveImportedFiles != null) {
this.importedFiles = saveImportedFiles;
@ -625,37 +459,32 @@ public class TContext {
}
}
private void runSub(TMemory memory, final Sub sub) throws EaterException {
for (StringLocated sl : sub.lines()) {
executeOneLine(memory, TLineType.getFromLine(sl.getString()), sl, null);
}
}
private void executeIncludeDef(TMemory memory, StringLocated s) throws EaterException {
final EaterIncludeDef include = new EaterIncludeDef(s.getTrimmed().getString());
include.execute(this, memory);
private void executeIncludeDef(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterIncludeDef include = new EaterIncludeDef(s.getTrimmed());
include.analyze(this, memory);
final String definitionName = include.getLocation();
final List<String> definition = definitionsContainer.getDefinition(definitionName);
ReadLine reader2 = new ReadLineList(definition, s.getLocation());
try {
// reader2 = new ReadLineQuoteComment(true).applyFilter(reader2);
final List<StringLocated> body = new ArrayList<StringLocated>();
do {
final StringLocated sl = reader2.readLine();
if (sl == null) {
executeLinesInternal(memory, body, null);
return;
}
executeOneLine(memory, TLineType.getFromLine(sl.getString()), sl, null);
body.add(sl);
} while (true);
} catch (IOException e) {
e.printStackTrace();
throw new EaterException("" + e);
throw EaterException.located("" + e, s);
}
}
private void executeInclude(TMemory memory, StringLocated s) throws EaterException {
final EaterInclude include = new EaterInclude(s.getTrimmed().getString());
include.execute(this, memory);
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();
final PreprocessorIncludeStrategy strategy = include.getPreprocessorIncludeStrategy();
final int idx = location.lastIndexOf('!');
@ -682,7 +511,7 @@ public class TContext {
return;
}
if (strategy == PreprocessorIncludeStrategy.ONCE && filesUsedCurrent.contains(f2)) {
throw new EaterException("This file has already been included");
throw EaterException.located("This file has already been included", s);
}
if (StartDiagramExtractReader.containsStartDiagram(f2, s, charset)) {
@ -690,7 +519,7 @@ public class TContext {
} else {
final Reader reader = f2.getReader(charset);
if (reader == null) {
throw new EaterException("Cannot include file");
throw EaterException.located("Cannot include file", s);
}
reader2 = ReadLineReader.create(reader, location, s.getLocation());
}
@ -698,18 +527,18 @@ public class TContext {
this.importedFiles = this.importedFiles.withCurrentDir(f2.getParentFile());
assert reader2 != null;
filesUsedCurrent.add(f2);
// filesUsedGlobal.add(f2);
}
}
if (reader2 != null) {
// reader2 = new ReadLineQuoteComment(true).applyFilter(reader2);
try {
final List<StringLocated> body = new ArrayList<StringLocated>();
do {
final StringLocated sl = reader2.readLine();
if (sl == null) {
executeLines(memory, body, null);
return;
}
executeOneLine(memory, TLineType.getFromLine(sl.getString()), sl, null);
body.add(sl);
} while (true);
} finally {
if (saveImportedFiles != null) {
@ -719,14 +548,14 @@ public class TContext {
}
} catch (IOException e) {
e.printStackTrace();
throw new EaterException("cannot include " + e);
throw EaterException.located("cannot include " + e, s);
}
throw new EaterException("cannot include " + location);
throw EaterException.located("cannot include " + location, s);
}
public boolean isLegacyDefine(String functionName) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functions2.entrySet()) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functionsSet.functions().entrySet()) {
if (ent.getKey().getFunctionName().equals(functionName) && ent.getValue().getFunctionType().isLegacy()) {
return true;
}
@ -735,7 +564,7 @@ public class TContext {
}
public boolean isUnquoted(String functionName) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functions2.entrySet()) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functionsSet.functions().entrySet()) {
if (ent.getKey().getFunctionName().equals(functionName) && ent.getValue().isUnquoted()) {
return true;
}
@ -744,7 +573,7 @@ public class TContext {
}
public boolean doesFunctionExist(String functionName) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functions2.entrySet()) {
for (Map.Entry<TFunctionSignature, TFunction> ent : functionsSet.functions().entrySet()) {
if (ent.getKey().getFunctionName().equals(functionName)) {
return true;
}
@ -752,30 +581,12 @@ public class TContext {
return false;
}
private static String getVarnameAt(TMemory memory, String s, int pos) {
if (pos > 0 && TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos - 1)) && justAfterBackslashN(s, pos) == false) {
return null;
}
final String varname = memory.variablesNames3().getLonguestMatchStartingIn(s.substring(pos));
if (varname.length() == 0) {
return null;
}
if (pos + varname.length() == s.length()
|| TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos + varname.length())) == false) {
return varname;
}
return null;
}
private static boolean justAfterBackslashN(String s, int pos) {
return pos > 1 && s.charAt(pos - 2) == '\\' && s.charAt(pos - 1) == 'n';
}
private String getFunctionNameAt(String s, int pos) {
if (pos > 0 && TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos - 1)) && justAfterBackslashN(s, pos) == false) {
if (pos > 0 && TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos - 1))
&& VariableManager.justAfterBackslashN(s, pos) == false) {
return null;
}
final String fname = functions3.getLonguestMatchStartingIn(s.substring(pos));
final String fname = functionsSet.getLonguestMatchStartingIn(s.substring(pos));
if (fname.length() == 0) {
return null;
}
@ -790,23 +601,6 @@ public class TContext {
return debug;
}
public final TFunctionImpl getPendingFunction() {
return pendingFunction;
}
private void addFunction(TFunction func) {
if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) {
((TFunctionImpl) func).finalizeEnddefinelong();
}
this.functions2.put(func.getSignature(), func);
this.functions3.add(func.getSignature().getFunctionName() + "(");
}
public void executeEndfunction() {
addFunction(pendingFunction);
pendingFunction = null;
}
public String extractFromResultList(int n1) {
final StringBuilder sb = new StringBuilder();
while (resultList.size() > n1) {
@ -828,4 +622,8 @@ public class TContext {
}
}
public TFunction getFunctionSmart(TFunctionSignature signature) {
return functionsSet.getFunctionSmart(signature);
}
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.expression.TValue;
public interface TFunction {
@ -46,11 +47,11 @@ public interface TFunction {
public TFunctionType getFunctionType();
public void executeVoid(TContext context, TMemory memory, String s) throws EaterException;
public void executeVoid(TContext context, TMemory memory, LineLocation location, String s) throws EaterException, EaterExceptionLocated;
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException;
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException, EaterExceptionLocated;
public void executeVoidInternal(TContext context, TMemory memory, List<TValue> args) throws EaterException;
public void executeVoidInternal(TContext context, TMemory memory, List<TValue> args) throws EaterException, EaterExceptionLocated;
public boolean isUnquoted();

View File

@ -35,10 +35,12 @@
package net.sourceforge.plantuml.tim;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.expression.TValue;
@ -76,72 +78,75 @@ public class TFunctionImpl implements TFunction {
public void addBody(StringLocated s) {
body.add(s);
if (TLineType.getFromLine(s.getString()) == TLineType.RETURN) {
if (s.getType() == TLineType.RETURN) {
this.functionType = TFunctionType.RETURN;
}
}
public void executeVoid(TContext context, TMemory memory, String s) throws EaterException {
final EaterFunctionCall call = new EaterFunctionCall(s, context.isLegacyDefine(signature.getFunctionName()),
unquoted);
call.execute(context, memory);
public void executeVoid(TContext context, TMemory memory, LineLocation location, String s)
throws EaterException, EaterExceptionLocated {
final EaterFunctionCall call = new EaterFunctionCall(new StringLocated(s, location),
context.isLegacyDefine(signature.getFunctionName()), unquoted);
call.analyze(context, memory);
final String endOfLine = call.getEndOfLine();
final List<TValue> args = call.getValues();
executeVoidInternal(context, memory, args);
context.appendEndOfLine(endOfLine);
}
public void executeVoidInternal(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public void executeVoidInternal(TContext context, TMemory memory, List<TValue> args)
throws EaterException, EaterExceptionLocated {
if (functionType != TFunctionType.VOID && functionType != TFunctionType.LEGACY_DEFINELONG) {
throw new IllegalStateException();
}
final TMemory copy = getNewMemory(memory, args);
for (StringLocated sl : body) {
context.executeOneLine(copy, TLineType.getFromLine(sl.getString()), sl, TFunctionType.VOID);
}
context.executeLines(copy, body, TFunctionType.VOID);
}
private TMemory getNewMemory(TMemory memory, List<TValue> values) {
final Map<String, TVariable> foo = new HashMap<String, TVariable>();
final Map<String, TValue> foo = new HashMap<String, TValue>();
for (int i = 0; i < args.size(); i++) {
final TValue tmp = i < values.size() ? values.get(i) : args.get(i).getOptionalDefaultValue();
foo.put(args.get(i).getName(), new TVariable(tmp));
foo.put(args.get(i).getName(), tmp);
}
final TMemory copy = memory.forkFromGlobal(foo);
return copy;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args)
throws EaterException, EaterExceptionLocated {
if (functionType == TFunctionType.LEGACY_DEFINE) {
return executeReturnLegacyDefine(context, memory, args);
return executeReturnLegacyDefine(location, context, memory, args);
}
if (functionType != TFunctionType.RETURN) {
throw new EaterException("Illegal call here");
throw EaterException.unlocated("Illegal call here");
}
final TMemory copy = getNewMemory(memory, args);
for (StringLocated sl : body) {
final TLineType lineType = TLineType.getFromLine(sl.getString());
final ConditionalContext conditionalContext = copy.peekConditionalContext();
if ((conditionalContext == null || conditionalContext.conditionIsOkHere()) && lineType == TLineType.RETURN) {
final TLineType lineType = sl.getType();
final ExecutionContextIf conditionalContext = copy.peekIf();
if ((conditionalContext == null || ((ExecutionContextIf) conditionalContext).conditionIsOkHere())
&& lineType == TLineType.RETURN) {
// System.err.println("s2=" + sl.getString());
final EaterReturn eaterReturn = new EaterReturn(sl.getString());
eaterReturn.execute(context, copy);
final EaterReturn eaterReturn = new EaterReturn(sl);
eaterReturn.analyze(context, copy);
// System.err.println("s3=" + eaterReturn.getValue2());
return eaterReturn.getValue2();
}
context.executeOneLine(copy, lineType, sl, TFunctionType.RETURN);
context.executeLines(copy, Arrays.asList(sl), TFunctionType.RETURN);
}
throw new EaterException("no return");
throw EaterException.unlocated("no return");
// return TValue.fromString("(NONE)");
}
private TValue executeReturnLegacyDefine(TContext context, TMemory memory, List<TValue> args) throws EaterException {
private TValue executeReturnLegacyDefine(LineLocation location, TContext context, TMemory memory, List<TValue> args)
throws EaterException, EaterExceptionLocated {
if (legacyDefinition == null) {
throw new IllegalStateException();
}
final TMemory copy = getNewMemory(memory, args);
final String tmp = context.applyFunctionsAndVariables(copy, legacyDefinition);
final String tmp = context.applyFunctionsAndVariables(copy, location, legacyDefinition);
if (tmp == null) {
return TValue.fromString("");
}

View File

@ -36,9 +36,23 @@ package net.sourceforge.plantuml.tim;
public enum TLineType {
PLAIN, AFFECTATION_DEFINE, AFFECTATION, ASSERT, IF, IFDEF, UNDEF, IFNDEF, ELSE, ELSEIF, ENDIF, DECLARE_FUNCTION, END_FUNCTION, RETURN, LEGACY_DEFINE, LEGACY_DEFINELONG, INCLUDE, INCLUDE_DEF, IMPORT, STARTSUB, ENDSUB, INCLUDESUB, LOG, DUMP_MEMORY, COMMENT_SIMPLE, COMMENT_LONG_START;
PLAIN, AFFECTATION_DEFINE, AFFECTATION, ASSERT, IF, IFDEF, UNDEF, IFNDEF, ELSE, ELSEIF, ENDIF, WHILE, ENDWHILE,
FOREACH, ENDFOREACH, DECLARE_FUNCTION, END_FUNCTION, RETURN, LEGACY_DEFINE, LEGACY_DEFINELONG, INCLUDE, INCLUDE_DEF,
IMPORT, STARTSUB, ENDSUB, INCLUDESUB, LOG, DUMP_MEMORY, COMMENT_SIMPLE, COMMENT_LONG_START;
public static TLineType getFromLine(String s) {
// private boolean elseLike() {
// return this == ELSE || this == ELSEIF;
// }
//
// public boolean incIndentAfter() {
// return this == IF || this == IFDEF || this == IFNDEF || elseLike();
// }
//
// public boolean decIndentBefore() {
// return this == ENDIF || elseLike();
// }
public static TLineType getFromLineInternal(String s) {
if (s.matches("^\\s*!define\\s+[\\p{L}_][\\p{L}_0-9]*\\(.*")) {
return LEGACY_DEFINE;
}
@ -87,6 +101,18 @@ public enum TLineType {
if (s.matches("^\\s*!endif\\b.*")) {
return ENDIF;
}
if (s.matches("^\\s*!while\\s+.*")) {
return WHILE;
}
if (s.matches("^\\s*!endwhile\\b.*")) {
return ENDWHILE;
}
if (s.matches("^\\s*!foreach\\s+.*")) {
return FOREACH;
}
if (s.matches("^\\s*!endfor\\b.*")) {
return ENDFOREACH;
}
if (s.matches("^\\s*!(endfunction|enddefinelong)\\b.*")) {
return END_FUNCTION;
}

View File

@ -37,11 +37,13 @@ package net.sourceforge.plantuml.tim;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.tim.expression.TValue;
public interface TMemory {
public TVariable getVariable(String varname);
public TValue getVariable(String varname);
public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException;
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException;
public void removeVariable(String varname);
@ -51,15 +53,28 @@ public interface TMemory {
public Trie variablesNames3();
public TMemory forkFromGlobal(Map<String, TVariable> input);
public TMemory forkFromGlobal(Map<String, TValue> input);
public ConditionalContext peekConditionalContext();
public ExecutionContextIf peekIf();
public boolean areAllIfOk();
public boolean areAllIfOk(TContext context, TMemory memory) throws EaterException;
public void addConditionalContext(ConditionalContext context);
public void addIf(ExecutionContextIf context);
public ConditionalContext pollConditionalContext();
public void addWhile(ExecutionContextWhile value);
public void addForeach(ExecutionContextForeach value);
public ExecutionContextIf pollIf();
public ExecutionContextWhile pollWhile();
public ExecutionContextWhile peekWhile();
public ExecutionContextForeach pollForeach();
public ExecutionContextForeach peekForeach();
public void dumpDebug(String message);
}

View File

@ -44,12 +44,12 @@ import java.util.TreeMap;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.tim.expression.TValue;
public class TMemoryGlobal extends ConditionalContexts implements TMemory {
public class TMemoryGlobal extends ExecutionContexts implements TMemory {
private final Map<String, TVariable> globalVariables = new HashMap<String, TVariable>();
private final Map<String, TValue> globalVariables = new HashMap<String, TValue>();
private final TrieImpl variables = new TrieImpl();
public TVariable getVariable(String varname) {
public TValue getVariable(String varname) {
return this.globalVariables.get(varname);
}
@ -61,17 +61,17 @@ public class TMemoryGlobal extends ConditionalContexts implements TMemory {
void dumpMemoryInternal() {
Log.error("[MemGlobal] Number of variable(s) : " + globalVariables.size());
for (Entry<String, TVariable> ent : new TreeMap<String, TVariable>(globalVariables).entrySet()) {
for (Entry<String, TValue> ent : new TreeMap<String, TValue>(globalVariables).entrySet()) {
final String name = ent.getKey();
final TValue value = ent.getValue().getValue();
final TValue value = ent.getValue();
Log.error("[MemGlobal] " + name + " = " + value);
}
}
public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException {
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException {
Log.info("[MemGlobal] Setting " + varname);
if (scope == TVariableScope.LOCAL) {
throw new EaterException("Cannot use local variable here");
throw EaterException.unlocated("Cannot use local variable here");
}
this.globalVariables.put(varname, value);
this.variables.add(varname);
@ -94,7 +94,7 @@ public class TMemoryGlobal extends ConditionalContexts implements TMemory {
return variables;
}
public TMemory forkFromGlobal(Map<String, TVariable> input) {
public TMemory forkFromGlobal(Map<String, TValue> input) {
return new TMemoryLocal(this, input);
}

View File

@ -43,15 +43,15 @@ import java.util.TreeMap;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.tim.expression.TValue;
public class TMemoryLocal extends ConditionalContexts implements TMemory {
public class TMemoryLocal extends ExecutionContexts implements TMemory {
private final TMemoryGlobal memoryGlobal;
private TrieImpl overridenVariables00;
private final Map<String, TVariable> overridenVariables01 = new HashMap<String, TVariable>();
private final Map<String, TValue> overridenVariables01 = new HashMap<String, TValue>();
private final TrieImpl localVariables00 = new TrieImpl();
private final Map<String, TVariable> localVariables01 = new HashMap<String, TVariable>();
private final Map<String, TValue> localVariables01 = new HashMap<String, TValue>();
public TMemoryLocal(TMemoryGlobal global, Map<String, TVariable> input) {
public TMemoryLocal(TMemoryGlobal global, Map<String, TValue> input) {
this.memoryGlobal = global;
this.overridenVariables01.putAll(input);
}
@ -59,24 +59,24 @@ public class TMemoryLocal extends ConditionalContexts implements TMemory {
public void dumpDebug(String message) {
Log.error("[MemLocal] Start of memory_dump " + message);
memoryGlobal.dumpMemoryInternal();
final TreeMap<String, TVariable> over = new TreeMap<String, TVariable>(overridenVariables01);
final TreeMap<String, TValue> over = new TreeMap<String, TValue>(overridenVariables01);
Log.error("[MemLocal] Number of overriden variable(s) : " + over.size());
for (Entry<String, TVariable> ent : over.entrySet()) {
for (Entry<String, TValue> ent : over.entrySet()) {
final String name = ent.getKey();
final TValue value = ent.getValue().getValue();
final TValue value = ent.getValue();
Log.error("[MemLocal] " + name + " = " + value);
}
final TreeMap<String, TVariable> local = new TreeMap<String, TVariable>(localVariables01);
final TreeMap<String, TValue> local = new TreeMap<String, TValue>(localVariables01);
Log.error("[MemLocal] Number of local variable(s) : " + local.size());
for (Entry<String, TVariable> ent : local.entrySet()) {
for (Entry<String, TValue> ent : local.entrySet()) {
final String name = ent.getKey();
final TValue value = ent.getValue().getValue();
final TValue value = ent.getValue();
Log.error("[MemLocal] " + name + " = " + value);
}
Log.error("[MemGlobal] End of memory_dump");
}
public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException {
public void putVariable(String varname, TValue value, TVariableScope scope) throws EaterException {
if (scope == TVariableScope.GLOBAL) {
memoryGlobal.putVariable(varname, value, scope);
return;
@ -110,8 +110,8 @@ public class TMemoryLocal extends ConditionalContexts implements TMemory {
}
}
public TVariable getVariable(String varname) {
TVariable result = overridenVariables01.get(varname);
public TValue getVariable(String varname) {
TValue result = overridenVariables01.get(varname);
if (result != null) {
return result;
}
@ -170,7 +170,7 @@ public class TMemoryLocal extends ConditionalContexts implements TMemory {
throw new UnsupportedOperationException();
}
public TMemory forkFromGlobal(Map<String, TVariable> input) {
public TMemory forkFromGlobal(Map<String, TValue> input) {
return new TMemoryLocal(memoryGlobal, input);
}

View File

@ -58,18 +58,14 @@ public class TimLoader {
}
}
public void load(List<StringLocated> input) {
for (StringLocated s : input) {
final TLineType type = TLineType.getFromLine(s.getTrimmed().getString());
try {
context.executeOneLine(global, type, s, null);
} catch (EaterException e) {
context.getResultList().add(s.withErrorPreprocessor(e.getMessage()));
this.resultList = context.getResultList();
changeLastLine(context.getDebug(), e.getMessage());
this.preprocessorError = true;
return;
}
public void load(List<StringLocated> list) {
// CodeIteratorImpl.indentNow(list);
try {
context.executeLines(global, list, null);
} catch (EaterExceptionLocated e) {
context.getResultList().add(e.getLocation().withErrorPreprocessor(e.getMessage()));
changeLastLine(context.getDebug(), e.getMessage());
this.preprocessorError = true;
}
this.resultList = context.getResultList();
}

View File

@ -0,0 +1,143 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.json.JsonArray;
import net.sourceforge.plantuml.json.JsonObject;
import net.sourceforge.plantuml.json.JsonValue;
import net.sourceforge.plantuml.tim.expression.TValue;
public class VariableManager {
private final TMemory memory;
private final TContext context;
private final LineLocation location;
public VariableManager(TContext context, TMemory memory, LineLocation location) {
this.memory = memory;
this.context = context;
this.location = location;
}
public int replaceVariables(String str, int i, StringBuilder result) throws EaterException, EaterExceptionLocated {
final String presentVariable = getVarnameAt(str, i);
if (result.toString().endsWith("##")) {
result.setLength(result.length() - 2);
}
final TValue value = memory.getVariable(presentVariable);
i += presentVariable.length() - 1;
if (value.isJson()) {
if (value.toJson().isString()) {
result.append(value.toJson().asString());
} else {
JsonValue jsonValue = (JsonObject) value.toJson();
i++;
i = replaceJson(jsonValue, str, i, result) - 1;
}
} else {
result.append(value.toString());
}
if (i + 2 < str.length() && str.charAt(i + 1) == '#' && str.charAt(i + 2) == '#') {
i += 2;
}
return i;
}
private int replaceJson(JsonValue jsonValue, String str, int i, StringBuilder result)
throws EaterException, EaterExceptionLocated {
while (true) {
final char n = str.charAt(i);
if (n == '.') {
i++;
final StringBuilder fieldName = new StringBuilder();
while (true) {
if (i >= str.length()) {
throw EaterException.unlocated("Parsing error");
}
if (Character.isJavaIdentifierPart(str.charAt(i)) == false) {
break;
}
fieldName.append(str.charAt(i));
i++;
}
jsonValue = ((JsonObject) jsonValue).get(fieldName.toString());
} else if (n == '[') {
i++;
final StringBuilder inBracket = new StringBuilder();
while (true) {
if (str.charAt(i) == ']') {
break;
}
inBracket.append(str.charAt(i));
i++;
}
final String nbString = context.applyFunctionsAndVariables(memory, location, inBracket.toString());
final int nb = Integer.parseInt(nbString);
jsonValue = ((JsonArray) jsonValue).get(nb);
i++;
} else {
if (jsonValue.isString()) {
result.append(jsonValue.asString());
} else {
result.append(jsonValue.toString());
}
break;
}
}
return i;
}
public String getVarnameAt(String s, int pos) {
if (pos > 0 && TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos - 1))
&& justAfterBackslashN(s, pos) == false) {
return null;
}
final String varname = memory.variablesNames3().getLonguestMatchStartingIn(s.substring(pos));
if (varname.length() == 0) {
return null;
}
if (pos + varname.length() == s.length()
|| TLineType.isLetterOrUnderscoreOrDigit(s.charAt(pos + varname.length())) == false) {
return varname;
}
return null;
}
public static boolean justAfterBackslashN(String s, int pos) {
return pos > 1 && s.charAt(pos - 2) == '\\' && s.charAt(pos - 1) == 'n';
}
}

View File

@ -36,11 +36,10 @@ package net.sourceforge.plantuml.tim.expression;
import net.sourceforge.plantuml.tim.TFunction;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TVariable;
public interface Knowledge {
public TVariable getVariable(String name);
public TValue getVariable(String name);
public TFunction getFunction(TFunctionSignature signature);

View File

@ -39,6 +39,8 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunction;
@ -51,7 +53,12 @@ public class ReversePolishInterpretor {
private boolean trace = false;
public ReversePolishInterpretor(TokenStack queue, Knowledge knowledge, TMemory memory, TContext context)
throws EaterException {
throws EaterException, EaterExceptionLocated {
this(null, queue, knowledge, memory, context);
}
public ReversePolishInterpretor(LineLocation location, TokenStack queue, Knowledge knowledge, TMemory memory,
TContext context) throws EaterException, EaterExceptionLocated {
final Deque<TValue> stack = new ArrayDeque<TValue>();
if (trace)
@ -64,12 +71,14 @@ public class ReversePolishInterpretor {
stack.addFirst(TValue.fromNumber(token));
} else if (token.getTokenType() == TokenType.QUOTED_STRING) {
stack.addFirst(TValue.fromString(token));
} else if (token.getTokenType() == TokenType.JSON_DATA) {
stack.addFirst(TValue.fromJson(token.getJson()));
} else if (token.getTokenType() == TokenType.OPERATOR) {
final TValue v2 = stack.removeFirst();
final TValue v1 = stack.removeFirst();
final TokenOperator op = token.getTokenOperator();
if (op == null) {
throw new EaterException("bad op");
throw EaterException.unlocated("bad op");
}
final TValue tmp = op.operate(v1, v2);
stack.addFirst(tmp);
@ -77,7 +86,7 @@ public class ReversePolishInterpretor {
final int nb = Integer.parseInt(token.getSurface());
final Token token2 = it.nextToken();
if (token2.getTokenType() != TokenType.FUNCTION_NAME) {
throw new EaterException("rpn43");
throw EaterException.unlocated("rpn43");
}
if (trace)
System.err.println("token2=" + token2);
@ -85,10 +94,11 @@ public class ReversePolishInterpretor {
if (trace)
System.err.println("function=" + function);
if (function == null) {
throw new EaterException("Unknow built-in function " + token2.getSurface());
throw EaterException.unlocated("Unknow built-in function " + token2.getSurface());
}
if (function.canCover(nb) == false) {
throw new EaterException("Bad number of arguments for " + function.getSignature().getFunctionName());
throw EaterException
.unlocated("Bad number of arguments for " + function.getSignature().getFunctionName());
}
final List<TValue> args = new ArrayList<TValue>();
for (int i = 0; i < nb; i++) {
@ -96,12 +106,15 @@ public class ReversePolishInterpretor {
}
if (trace)
System.err.println("args=" + args);
final TValue r = function.executeReturn(context, memory, args);
if (location == null) {
throw EaterException.unlocated("rpn44");
}
final TValue r = function.executeReturn(context, memory, location, args);
if (trace)
System.err.println("r=" + r);
stack.addFirst(r);
} else {
throw new EaterException("rpn41");
throw EaterException.unlocated("rpn41");
}
}
result = stack.removeFirst();

View File

@ -37,9 +37,6 @@ package net.sourceforge.plantuml.tim.expression;
import java.util.ArrayDeque;
import java.util.Deque;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TVariable;
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
// https://en.cppreference.com/w/c/language/operator_precedence
public class ShuntingYard {
@ -58,7 +55,7 @@ public class ShuntingYard {
System.err.println("");
}
public ShuntingYard(TokenIterator it, Knowledge knowledge) throws EaterException {
public ShuntingYard(TokenIterator it, Knowledge knowledge) {
while (it.hasMoreTokens()) {
final Token token = it.nextToken();
@ -71,15 +68,16 @@ public class ShuntingYard {
operatorStack.addFirst(token);
} else if (token.getTokenType() == TokenType.PLAIN_TEXT) {
final String name = token.getSurface();
final TVariable variable = knowledge.getVariable(name);
final TValue variable = knowledge.getVariable(name);
if (variable == null) {
throw new EaterException("Unknown variable " + name);
ouputQueue.add(new Token("undefined", TokenType.QUOTED_STRING, null));
} else {
ouputQueue.add(variable.toToken());
}
ouputQueue.add(variable.getValue().toToken());
} else if (token.getTokenType() == TokenType.OPERATOR) {
while ((thereIsAFunctionAtTheTopOfTheOperatorStack(token) //
|| thereIsAnOperatorAtTheTopOfTheOperatorStackWithGreaterPrecedence(token) //
|| theOperatorAtTheTopOfTheOperatorStackHasEqualPrecedenceAndIsLeftAssociative(token)) //
|| theOperatorAtTheTopOfTheOperatorStackHasEqualPrecedenceAndIsLeftAssociative(token)) //
&& theOperatorAtTheTopOfTheOperatorStackIsNotALeftParenthesis(token)) {
ouputQueue.add(operatorStack.removeFirst());
}

View File

@ -142,9 +142,12 @@ public class TValue {
public Token toToken() {
if (isNumber()) {
return new Token(toString(), TokenType.NUMBER);
return new Token(toString(), TokenType.NUMBER, null);
}
return new Token(toString(), TokenType.QUOTED_STRING);
if (isJson()) {
return new Token(toString(), TokenType.JSON_DATA, jsonValue);
}
return new Token(toString(), TokenType.QUOTED_STRING, null);
}
public TValue greaterThanOrEquals(TValue v2) {

View File

@ -34,9 +34,12 @@
*/
package net.sourceforge.plantuml.tim.expression;
import net.sourceforge.plantuml.json.JsonValue;
public class Token {
private final String surface;
private final JsonValue json;
private final TokenType tokenType;
@Override
@ -44,13 +47,14 @@ public class Token {
return tokenType + "{" + surface + "}";
}
public Token(char surface, TokenType tokenType) {
this("" + surface, tokenType);
public Token(char surface, TokenType tokenType, JsonValue json) {
this("" + surface, tokenType, json);
}
public Token(String surface, TokenType tokenType) {
public Token(String surface, TokenType tokenType, JsonValue json) {
this.surface = surface;
this.tokenType = tokenType;
this.json = json;
}
public TokenOperator getTokenOperator() {
@ -73,7 +77,14 @@ public class Token {
if (this.tokenType != TokenType.PLAIN_TEXT) {
throw new IllegalStateException();
}
return new Token(surface, TokenType.FUNCTION_NAME);
return new Token(surface, TokenType.FUNCTION_NAME, null);
}
public JsonValue getJson() {
if (this.tokenType != TokenType.JSON_DATA) {
throw new IllegalStateException();
}
return json;
}
}

View File

@ -42,7 +42,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.Eater;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TMemory;
@ -93,7 +95,7 @@ public class TokenStack {
eater.skipSpaces();
final char ch = eater.peekChar();
if (ch == 0) {
throw new EaterException("until001");
throw EaterException.unlocated("until001");
}
if (level == 0 && (ch == ',' || ch == ')')) {
return result;
@ -114,7 +116,7 @@ public class TokenStack {
while (true) {
final Token ch = it.peekToken();
if (ch == null) {
throw new EaterException("until002");
throw EaterException.unlocated("until002");
}
final TokenType typech = ch.getTokenType();
if (level == 0 && (typech == TokenType.COMMA || typech == TokenType.CLOSE_PAREN_MATH)
@ -147,10 +149,10 @@ public class TokenStack {
} else if (type == TokenType.COMMA) {
result++;
} else {
throw new EaterException("count13");
throw EaterException.unlocated("count13");
}
}
throw new EaterException("count12");
throw EaterException.unlocated("count12");
}
public void guessFunctions() throws EaterException {
@ -172,10 +174,10 @@ public class TokenStack {
assert tokens.get(iopen).getTokenType() == TokenType.OPEN_PAREN_MATH;
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));
tokens.set(iopen - 1, new Token(tokens.get(iopen - 1).getSurface(), TokenType.FUNCTION_NAME, null));
final int nbArg = countFunctionArg(subTokenStack(iopen + 1).tokenIterator());
tokens.set(iopen, new Token("" + nbArg, TokenType.OPEN_PAREN_FUNC));
tokens.set(iclose, new Token(")", TokenType.CLOSE_PAREN_FUNC));
tokens.set(iopen, new Token("" + nbArg, TokenType.OPEN_PAREN_FUNC, null));
tokens.set(iclose, new Token(")", TokenType.CLOSE_PAREN_FUNC, null));
}
}
// System.err.println("after=" + toString());
@ -206,14 +208,14 @@ public class TokenStack {
return new InternalIterator();
}
public TValue getResult(TContext context, TMemory memory) throws EaterException {
public TValue getResult(LineLocation location, TContext context, TMemory memory) throws EaterException, EaterExceptionLocated {
final Knowledge knowledge = context.asKnowledge(memory);
final TokenStack tmp = withoutSpace();
tmp.guessFunctions();
final TokenIterator it = tmp.tokenIterator();
final ShuntingYard shuntingYard = new ShuntingYard(it, knowledge);
final ReversePolishInterpretor rpn = new ReversePolishInterpretor(shuntingYard.getQueue(), knowledge, memory,
context);
final ReversePolishInterpretor rpn = new ReversePolishInterpretor(location, shuntingYard.getQueue(), knowledge,
memory, context);
return rpn.getResult();
}

View File

@ -39,7 +39,7 @@ import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TLineType;
public enum TokenType {
QUOTED_STRING, OPERATOR, OPEN_PAREN_MATH, COMMA, CLOSE_PAREN_MATH, NUMBER, PLAIN_TEXT, SPACES, FUNCTION_NAME, OPEN_PAREN_FUNC, CLOSE_PAREN_FUNC;
QUOTED_STRING, JSON_DATA, OPERATOR, OPEN_PAREN_MATH, COMMA, CLOSE_PAREN_MATH, NUMBER, PLAIN_TEXT, SPACES, FUNCTION_NAME, OPEN_PAREN_FUNC, CLOSE_PAREN_FUNC;
private boolean isSingleChar1() {
return this == OPEN_PAREN_MATH || this == COMMA || this == CLOSE_PAREN_MATH;
@ -83,24 +83,24 @@ public enum TokenType {
}
final TokenOperator tokenOperator = TokenOperator.getTokenOperator(ch, eater.peekCharN2());
if (TLineType.isQuote(ch)) {
return new Token(eater.eatAndGetQuotedString(), TokenType.QUOTED_STRING);
return new Token(eater.eatAndGetQuotedString(), TokenType.QUOTED_STRING, null);
} else if (tokenOperator != null) {
if (tokenOperator.getDisplay().length() == 1) {
return new Token(eater.eatOneChar(), TokenType.OPERATOR);
return new Token(eater.eatOneChar(), TokenType.OPERATOR, null);
}
return new Token("" + eater.eatOneChar() + eater.eatOneChar(), TokenType.OPERATOR);
return new Token("" + eater.eatOneChar() + eater.eatOneChar(), TokenType.OPERATOR, null);
} else if (ch == '(') {
return new Token(eater.eatOneChar(), TokenType.OPEN_PAREN_MATH);
return new Token(eater.eatOneChar(), TokenType.OPEN_PAREN_MATH, null);
} else if (ch == ')') {
return new Token(eater.eatOneChar(), TokenType.CLOSE_PAREN_MATH);
return new Token(eater.eatOneChar(), TokenType.CLOSE_PAREN_MATH, null);
} else if (ch == ',') {
return new Token(eater.eatOneChar(), TokenType.COMMA);
return new Token(eater.eatOneChar(), TokenType.COMMA, null);
} else if (TLineType.isLatinDigit(ch)) {
return new Token(eater.eatAndGetNumber(), TokenType.NUMBER);
return new Token(eater.eatAndGetNumber(), TokenType.NUMBER, null);
} else if (TLineType.isSpaceChar(ch)) {
return new Token(eater.eatAndGetSpaces(), TokenType.SPACES);
return new Token(eater.eatAndGetSpaces(), TokenType.SPACES, null);
}
return new Token(eatAndGetTokenPlainText(eater), TokenType.PLAIN_TEXT);
return new Token(eatAndGetTokenPlainText(eater), TokenType.PLAIN_TEXT, null);
}
static private String eatAndGetTokenPlainText(Eater eater) throws EaterException {

View File

@ -0,0 +1,61 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
public abstract class AbstractCodeIterator implements CodeIterator {
protected final CodeIterator source;
public AbstractCodeIterator(CodeIterator source) {
this.source = source;
}
public void next() throws EaterException, EaterExceptionLocated {
source.next();
}
final public CodePosition getCodePosition() {
return source.getCodePosition();
}
final public void jumpToCodePosition(CodePosition newPosition) throws EaterException {
source.jumpToCodePosition(newPosition);
}
}

View File

@ -0,0 +1,51 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
public interface CodeIterator {
public StringLocated peek() throws EaterException, EaterExceptionLocated;
public void next() throws EaterException, EaterExceptionLocated;
public CodePosition getCodePosition();
public void jumpToCodePosition(CodePosition newPosition) throws EaterException;
}

View File

@ -0,0 +1,98 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.json.ParseException;
import net.sourceforge.plantuml.tim.EaterAffectation;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
public class CodeIteratorAffectation extends AbstractCodeIterator {
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorAffectation(CodeIterator source, TContext context, TMemory memory, List<StringLocated> log) {
super(source);
this.context = context;
this.memory = memory;
this.logs = log;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
if (result.getType() == TLineType.AFFECTATION) {
logs.add(result);
doAffectation(result);
next();
continue;
}
return result;
}
}
private void doAffectation(StringLocated result) throws EaterException, EaterExceptionLocated {
int lastLocation = -1;
for (int i = 0; i < 100; i++)
try {
this.executeAffectation(context, memory, result);
return;
} catch (ParseException e) {
if (e.getColumn() <= lastLocation) {
throw EaterException.located("Error in JSON format", result);
}
lastLocation = e.getColumn();
next();
final StringLocated forward = source.peek();
result = result.append(forward.getString());
}
}
private void executeAffectation(TContext context, TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
new EaterAffectation(s).analyze(context, memory);
}
}

View File

@ -0,0 +1,131 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.json.JsonValue;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterForeach;
import net.sourceforge.plantuml.tim.ExecutionContextForeach;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.TVariableScope;
import net.sourceforge.plantuml.tim.expression.TValue;
public class CodeIteratorForeach extends AbstractCodeIterator {
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorForeach(CodeIterator source, TContext context, TMemory memory, List<StringLocated> logs) {
super(source);
this.context = context;
this.memory = memory;
this.logs = logs;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
int level = 0;
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
final ExecutionContextForeach foreach = memory.peekForeach();
if (foreach != null && foreach.isSkipMe()) {
if (result.getType() == TLineType.FOREACH) {
level++;
} else if (result.getType() == TLineType.ENDFOREACH) {
level--;
if (level == -1) {
memory.pollForeach();
level = 0;
}
}
next();
continue;
}
if (result.getType() == TLineType.FOREACH) {
logs.add(result);
executeForeach(memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.ENDFOREACH) {
logs.add(result);
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());
}
next();
continue;
}
return result;
}
}
private void executeForeach(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterForeach condition = new EaterForeach(s);
condition.analyze(context, memory);
final ExecutionContextForeach foreach = ExecutionContextForeach.fromValue(condition.getVarname(),
condition.getJsonArray(), source.getCodePosition());
if (condition.isSkip()) {
foreach.skipMeNow();
} 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);
}
}

View File

@ -0,0 +1,93 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.FunctionsSet;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
public class CodeIteratorFunction extends AbstractCodeIterator {
private final FunctionsSet functionsSet;
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorFunction(CodeIterator source, TContext context, TMemory memory, FunctionsSet functionsSet,
List<StringLocated> logs) {
super(source);
this.context = context;
this.functionsSet = functionsSet;
this.logs = logs;
this.memory = memory;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
if (functionsSet.pendingFunction() != null) {
logs.add(result);
if (result.getType() == TLineType.END_FUNCTION) {
functionsSet.executeEndfunction();
} else {
functionsSet.pendingFunction().addBody(result);
}
next();
continue;
}
if (result.getType() == TLineType.DECLARE_FUNCTION) {
logs.add(result);
functionsSet.executeDeclareFunction(context, memory, result);
next();
continue;
}
return result;
}
}
}

View File

@ -0,0 +1,163 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterElseIf;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterIf;
import net.sourceforge.plantuml.tim.EaterIfdef;
import net.sourceforge.plantuml.tim.EaterIfndef;
import net.sourceforge.plantuml.tim.ExecutionContextIf;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
public class CodeIteratorIf extends AbstractCodeIterator {
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorIf(CodeIterator source, TContext context, TMemory memory, List<StringLocated> logs) {
super(source);
this.context = context;
this.memory = memory;
this.logs = logs;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
if (result.getType() == TLineType.IF) {
logs.add(result);
executeIf(context, memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.IFDEF) {
logs.add(result);
executeIfdef(context, memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.IFNDEF) {
logs.add(result);
executeIfndef(context, memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.ELSE) {
logs.add(result);
executeElse(context, memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.ELSEIF) {
logs.add(result);
executeElseIf(context, memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.ENDIF) {
logs.add(result);
executeEndif(context, memory, result.getTrimmed());
next();
continue;
} else if (memory.peekIf() != null && (memory.areAllIfOk(context, memory) == false)) {
logs.add(result);
next();
continue;
}
return result;
}
}
private void executeIf(TContext context, TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterIf condition = new EaterIf(s);
condition.analyze(context, memory);
final boolean isTrue = condition.isTrue();
memory.addIf(ExecutionContextIf.fromValue(isTrue));
}
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", s);
}
poll.enteringElseIf();
if (poll.hasBeenBurn() == false) {
final EaterElseIf condition = new EaterElseIf(s);
condition.analyze(context, memory);
final boolean isTrue = condition.isTrue();
if (isTrue) {
poll.nowInSomeElseIf();
}
}
}
private void executeIfdef(TContext context, TMemory memory, StringLocated s) throws EaterException {
final EaterIfdef condition = new EaterIfdef(s);
condition.analyze(context, memory);
final boolean isTrue = condition.isTrue(context, memory);
memory.addIf(ExecutionContextIf.fromValue(isTrue));
}
private void executeIfndef(TContext context, TMemory memory, StringLocated s) throws EaterException {
final EaterIfndef condition = new EaterIfndef(s);
condition.analyze(context, memory);
final boolean isTrue = condition.isTrue(context, memory);
memory.addIf(ExecutionContextIf.fromValue(isTrue));
}
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", 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", s);
}
}
}

View File

@ -0,0 +1,98 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterException;
public class CodeIteratorImpl implements CodeIterator {
private final List<StringLocated> list;
private int current = 0;
private int countJump = 0;
static class Position implements CodePosition {
final int pos;
Position(int pos) {
this.pos = pos;
}
// @Override
// public String toString() {
// return "-->" + list.get(pos);
// }
}
public CodeIteratorImpl(List<StringLocated> list) {
this.list = list;
}
public StringLocated peek() {
if (current == list.size()) {
return null;
}
if (current > list.size()) {
throw new IllegalStateException();
}
return list.get(current);
}
public void next() {
if (current >= list.size()) {
throw new IllegalStateException();
}
assert current < list.size();
current++;
assert current <= list.size();
}
public CodePosition getCodePosition() {
return new Position(current);
}
public void jumpToCodePosition(CodePosition newPosition) throws EaterException {
this.countJump++;
if (this.countJump > 999) {
throw EaterException.unlocated("Infinite loop?");
}
final Position pos = (Position) newPosition;
this.current = pos.pos;
}
}

View File

@ -0,0 +1,55 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
public class CodeIteratorInnerComment extends AbstractCodeIterator {
public CodeIteratorInnerComment(CodeIterator source) {
super(source);
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
return result.removeInnerComment();
}
}

View File

@ -0,0 +1,85 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.FunctionsSet;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
public class CodeIteratorLegacyDefine extends AbstractCodeIterator {
private final FunctionsSet functionsSet;
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorLegacyDefine(CodeIterator source, TContext context, TMemory memory, FunctionsSet functionsSet,
List<StringLocated> logs) {
super(source);
this.context = context;
this.functionsSet = functionsSet;
this.logs = logs;
this.memory = memory;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
if (result.getType() == TLineType.LEGACY_DEFINE) {
logs.add(result);
functionsSet.executeLegacyDefine(context, memory, result);
next();
continue;
} else if (result.getType() == TLineType.LEGACY_DEFINELONG) {
logs.add(result);
functionsSet.executeLegacyDefineLong(context, memory, result);
next();
continue;
}
return result;
}
}
}

View File

@ -0,0 +1,75 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TLineType;
public class CodeIteratorLongComment extends AbstractCodeIterator {
private final List<StringLocated> logs;
public CodeIteratorLongComment(CodeIterator source, List<StringLocated> logs) {
super(source);
this.logs = logs;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
if (source.peek() == null) {
return null;
}
if (source.peek().getType() != TLineType.COMMENT_LONG_START) {
return source.peek();
}
StringLocated s = null;
while ((s = source.peek()) != null && s.getTrimmed().getString().endsWith("'/") == false) {
logs.add(s);
source.next();
}
assert source.peek() == null || s.getTrimmed().getString().endsWith("'/");
if (source.peek() != null) {
assert s.getTrimmed().getString().endsWith("'/");
logs.add(source.peek());
source.next();
}
}
}
}

View File

@ -0,0 +1,68 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TLineType;
public class CodeIteratorShortComment extends AbstractCodeIterator {
private final List<StringLocated> logs;
public CodeIteratorShortComment(CodeIterator source, List<StringLocated> logs) {
super(source);
this.logs = logs;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
if (result.getType() == TLineType.COMMENT_SIMPLE) {
logs.add(result);
next();
continue;
}
assert result != null && result.getType() != TLineType.COMMENT_SIMPLE;
return result;
}
}
}

View File

@ -0,0 +1,112 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.Collections;
import java.util.Map;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.preproc.Sub;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterStartsub;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
public class CodeIteratorSub extends AbstractCodeIterator {
private final Map<String, Sub> subs;
private CodeIterator readingInProgress;
private final TMemory memory;
private final TContext context;
public CodeIteratorSub(CodeIterator source, Map<String, Sub> subs, TContext context, TMemory memory) {
super(source);
this.context = context;
this.memory = memory;
this.subs = subs;
}
public Map<String, Sub> getSubs() {
return Collections.unmodifiableMap(subs);
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
StringLocated result = source.peek();
if (result == null) {
return null;
}
if (result.getType() == TLineType.STARTSUB) {
final EaterStartsub eater = new EaterStartsub(result.getTrimmed());
eater.analyze(context, memory);
final Sub created = new Sub(eater.getSubname());
this.subs.put(eater.getSubname(), created);
source.next();
StringLocated s = null;
while ((s = source.peek()) != null) {
if (s.getType() == TLineType.STARTSUB) {
throw EaterException.located("Cannot nest sub", s);
} else if (s.getType() == TLineType.ENDSUB) {
source.next();
readingInProgress = new CodeIteratorImpl(created.lines());
break;
} else {
created.add(s);
source.next();
}
}
}
if (readingInProgress != null) {
return readingInProgress.peek();
}
return result;
}
@Override
public void next() throws EaterException, EaterExceptionLocated {
if (readingInProgress == null) {
source.next();
return;
}
readingInProgress.next();
if (readingInProgress.peek() == null) {
readingInProgress = null;
}
}
}

View File

@ -0,0 +1,123 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim.iterator;
import java.util.List;
import net.sourceforge.plantuml.StringLocated;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.EaterWhile;
import net.sourceforge.plantuml.tim.ExecutionContextWhile;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TLineType;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.expression.TValue;
import net.sourceforge.plantuml.tim.expression.TokenStack;
public class CodeIteratorWhile extends AbstractCodeIterator {
private final TContext context;
private final TMemory memory;
private final List<StringLocated> logs;
public CodeIteratorWhile(CodeIterator source, TContext context, TMemory memory, List<StringLocated> logs) {
super(source);
this.context = context;
this.memory = memory;
this.logs = logs;
}
public StringLocated peek() throws EaterException, EaterExceptionLocated {
int level = 0;
while (true) {
final StringLocated result = source.peek();
if (result == null) {
return null;
}
final ExecutionContextWhile currentWhile = memory.peekWhile();
if (currentWhile != null && currentWhile.isSkipMe()) {
if (result.getType() == TLineType.WHILE) {
level++;
} else if (result.getType() == TLineType.ENDWHILE) {
level--;
if (level == -1) {
memory.pollWhile();
level = 0;
}
}
next();
continue;
}
if (result.getType() == TLineType.WHILE) {
logs.add(result);
executeWhile(memory, result.getTrimmed());
next();
continue;
} else if (result.getType() == TLineType.ENDWHILE) {
logs.add(result);
if (currentWhile == null) {
throw EaterException.located("No while related to this endwhile", result);
}
final TValue value = currentWhile.conditionValue(result.getLocation(), context, memory);
if (value.toBoolean()) {
source.jumpToCodePosition(currentWhile.getStartWhile());
} else {
memory.pollWhile();
}
next();
continue;
}
return result;
}
}
private void executeWhile(TMemory memory, StringLocated s) throws EaterException, EaterExceptionLocated {
final EaterWhile condition = new EaterWhile(s);
condition.analyze(context, memory);
final TokenStack whileExpression = condition.getWhileExpression();
final ExecutionContextWhile theWhile = ExecutionContextWhile.fromValue(whileExpression,
source.getCodePosition());
final TValue value = theWhile.conditionValue(s.getLocation(), context, memory);
if (value.toBoolean() == false) {
theWhile.skipMe();
}
memory.addWhile(theWhile);
}
}

View File

@ -32,28 +32,8 @@
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.tim;
package net.sourceforge.plantuml.tim.iterator;
import net.sourceforge.plantuml.tim.expression.TValue;
public class TVariable {
private final TValue value;
public TVariable(TValue value) {
if (value == null) {
throw new IllegalArgumentException();
}
this.value = value;
}
@Override
public String toString() {
return super.toString() + " " + value.toString();
}
public TValue getValue() {
return value;
}
public interface CodePosition {
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
@ -52,7 +53,7 @@ public class AlwaysFalse extends SimpleReturnFunction {
return nbArg == 0;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
return TValue.fromBoolean(false);
}
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
@ -52,7 +53,7 @@ public class AlwaysTrue extends SimpleReturnFunction {
return nbArg == 0;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
return TValue.fromBoolean(true);
}
}

View File

@ -36,6 +36,8 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterExceptionLocated;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunction;
@ -53,15 +55,15 @@ public class CallUserFunction extends SimpleReturnFunction {
return nbArg > 0;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> values) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> values) throws EaterException, EaterExceptionLocated {
final String fname = values.get(0).toString();
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 new EaterException("Cannot find void function " + fname);
throw EaterException.unlocated("Cannot find void function " + fname);
}
return func.executeReturn(context, memory, args);
return func.executeReturn(context, memory, location, args);
}
}

View File

@ -38,6 +38,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
@ -54,7 +55,7 @@ public class DateFunction extends SimpleReturnFunction {
return nbArg == 0 || nbArg == 1;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
if (args.size() == 0) {
return TValue.fromString(new Date().toString());
}
@ -62,7 +63,7 @@ public class DateFunction extends SimpleReturnFunction {
try {
return TValue.fromString(new SimpleDateFormat(format).format(new Date()));
} catch (Exception e) {
throw new EaterException("Bad date pattern");
throw EaterException.unlocated("Bad date pattern");
}
}
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.preproc.Defines;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
@ -59,7 +60,7 @@ public class Dirpath extends SimpleReturnFunction {
return nbArg == 0;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
if (value == null) {
return TValue.fromString("");
}

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.io.File;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
@ -54,7 +55,7 @@ public class FileExists extends SimpleReturnFunction {
return nbArg == 1;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
if (OptionFlags.ALLOW_INCLUDE == false) {
return TValue.fromBoolean(false);
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.preproc.Defines;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
@ -59,7 +60,7 @@ public class Filename extends SimpleReturnFunction {
return nbArg == 0;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
if (value == null) {
return TValue.fromString("");
}

View File

@ -36,6 +36,7 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
@ -52,7 +53,7 @@ public class FunctionExists extends SimpleReturnFunction {
return nbArg == 1;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
final String name = args.get(0).toString();
return TValue.fromBoolean(context.doesFunctionExist(name));
}

View File

@ -36,11 +36,11 @@ package net.sourceforge.plantuml.tim.stdlib;
import java.util.List;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.tim.EaterException;
import net.sourceforge.plantuml.tim.TContext;
import net.sourceforge.plantuml.tim.TFunctionSignature;
import net.sourceforge.plantuml.tim.TMemory;
import net.sourceforge.plantuml.tim.TVariable;
import net.sourceforge.plantuml.tim.expression.TValue;
public class GetVariableValue extends SimpleReturnFunction {
@ -53,13 +53,13 @@ public class GetVariableValue extends SimpleReturnFunction {
return nbArg == 1;
}
public TValue executeReturn(TContext context, TMemory memory, List<TValue> args) throws EaterException {
public TValue executeReturn(TContext context, TMemory memory, LineLocation location, List<TValue> args) throws EaterException {
final String name = args.get(0).toString();
final TVariable variable = memory.getVariable(name);
final TValue variable = memory.getVariable(name);
if (variable == null) {
return TValue.fromString("");
}
return variable.getValue();
return variable;
}
}

Some files were not shown because too many files have changed in this diff Show More