From ec37ee18ec313a7c9d9cb107ddeaa61a92b8a7b5 Mon Sep 17 00:00:00 2001 From: Peter Verhas Date: Wed, 11 Dec 2024 13:24:38 +0100 Subject: [PATCH] added segments to the input to contain the built-in macro nesting path in errors --- README.jrf | 2 +- .../java/javax0/jamal/api/BadSyntaxAt.java | 10 +----- .../src/main/java/javax0/jamal/api/Input.java | 3 +- .../main/java/javax0/jamal/api/Position.java | 31 +++++++++++++++++- .../main/java/javax0/jamal/cmd/JamalMain.java | 2 +- .../java/javax0/jamal/engine/Processor.java | 13 ++++++-- .../com/javax0/jamal/maven/JamalLogger.java | 2 +- jamal-snippet/README.adoc | 2 +- jamal-sql/demodb.mv.db | Bin 24576 -> 24576 bytes .../javax0/jamal/testsupport/TestThat.java | 2 +- .../main/java/javax0/jamal/tools/Input.java | 6 ++-- .../src/test/resources/demoConverted.docx | Bin 12792 -> 12792 bytes .../test/resources/includetestConverted.docx | Bin 34572 -> 34572 bytes .../src/test/resources/pictureConverted.docx | Bin 21869 -> 21869 bytes .../src/test/resources/sampleConverted.docx | Bin 40810 -> 40813 bytes 15 files changed, 51 insertions(+), 22 deletions(-) diff --git a/README.jrf b/README.jrf index 972bcd4e7..7ec47b8d8 100644 --- a/README.jrf +++ b/README.jrf @@ -1,5 +1,5 @@ # This is a Jamal reference file containing serialized base64 encoded macros -# Created: 2024-12-10 17:58:05 +0100 +# Created: 2024-12-11 13:19:58 +0100 # id|openStr|closeStr|verbatim|tailParameter|pure|content|parameters # TOC VE9D|eyU=|JX0=|0|0|0|Ci4gPDxJbnN0YWxsYXRpb24+PgouIDw8R1M+PgouIDw8Q29uZmlndXJhdGlvbj4+Ci4gPDxGZWF0dXJlcz4+Ci4gPDxDb250cmlidXRpbmc+PgouIDw8RG9jdW1lbnRhdGlvbj4+Ci4gPDxMaWNlbnNlPj4KLiA8PENoYW5nZWxvZz4+Ci4gPDxSb2FkbWFwPj4KLiA8PFN1cHBvcnQ+PgouIDw8RkFRPj4KLiA8PE1haW50ZW5hbmNlPj4=| diff --git a/jamal-api/src/main/java/javax0/jamal/api/BadSyntaxAt.java b/jamal-api/src/main/java/javax0/jamal/api/BadSyntaxAt.java index c50387509..9ad55ec9c 100644 --- a/jamal-api/src/main/java/javax0/jamal/api/BadSyntaxAt.java +++ b/jamal-api/src/main/java/javax0/jamal/api/BadSyntaxAt.java @@ -58,20 +58,12 @@ public BadSyntaxAt(String message, Position pos, Throwable cause) { this.pos = pos; } - public static String posFormat(Position pos) { - if (pos == null) { - return ""; - } else { - return pos.file + "/" + pos.line + ":" + pos.column; - } - } - @Override public String getMessage() { if (pos == null) { return super.getMessage(); } else { - return super.getMessage() + " at " + posFormat(pos); + return super.getMessage() + " at " + pos.posFormat(); } } diff --git a/jamal-api/src/main/java/javax0/jamal/api/Input.java b/jamal-api/src/main/java/javax0/jamal/api/Input.java index c0ff827e7..5ce31e5d2 100644 --- a/jamal-api/src/main/java/javax0/jamal/api/Input.java +++ b/jamal-api/src/main/java/javax0/jamal/api/Input.java @@ -20,7 +20,7 @@ public interface Input extends CharSequence { *
  • either perform the operation as described here to support the default implementations, or *
  • implement the methods in a way that they do not use this method. * - * + *

    * Get the {@link StringBuilder} that contains the characters of the input. The processing many times works directly * on the {@link StringBuilder} deleting characters from the start of it as the processing progresses, thus * essentially modifying/mutating the {@code Input} object. @@ -38,7 +38,6 @@ public interface Input extends CharSequence { */ Position getPosition(); - /** * @return the reference file name that the input was read from */ diff --git a/jamal-api/src/main/java/javax0/jamal/api/Position.java b/jamal-api/src/main/java/javax0/jamal/api/Position.java index 7556dfc0c..d8772e13a 100644 --- a/jamal-api/src/main/java/javax0/jamal/api/Position.java +++ b/jamal-api/src/main/java/javax0/jamal/api/Position.java @@ -1,5 +1,7 @@ package javax0.jamal.api; +import java.util.ArrayList; + /** * The {@code Position} contains the name of a file, a line number and the column number. This serves as a parameter * when an error happens. The exception {@link BadSyntaxAt} gets an object of this type as a parameter, and later it is @@ -10,19 +12,30 @@ */ public class Position { public final String file; + public final ArrayList segment = new ArrayList<>(); public int line; public int column; public int charpos = 0; public final Position parent; + /** + * This is the position that this position is a clone of. This is needed when segments are to be added to or + * removed from a position. The method {@link Input#getPosition()} returns a clone of the position but in the case + * when we want to add a segment we need the original position as we want to modify it. + */ + public final Position cloneOf; + public Position(String file, int line, int column, Position parent) { this.file = file; this.line = line; this.column = column; this.parent = parent; + this.cloneOf = this; } + public Position(Position clone) { + cloneOf = clone; if (clone == null) { file = null; line = 1; @@ -60,6 +73,14 @@ public Position clone() { return new Position(this); } + public void pushSegment(String segment) { + this.segment.add(segment); + } + + public void popSegment() { + this.segment.remove(this.segment.size() - 1); + } + /** * @return return the position, which is the same as the position of the input, but references the position of the * input as parent. This means that we will have two positions, with the same file/line:column information, but @@ -83,12 +104,20 @@ public Position fork() { */ public Position top() { var top = this; - while ( top.parent != null) { + while (top.parent != null) { top = top.parent; } return top; } + public String posFormat() { + if (segment.isEmpty()) { + return file + "/" + line + ":" + column; + } else { + return file + "[" + String.join(">", segment) + "]" + line + ":" + column; + } + } + @Override public String toString() { return file + ":" + line + ":" + column; diff --git a/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java b/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java index 1db44c907..5039059c8 100644 --- a/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java +++ b/jamal-cmd/src/main/java/javax0/jamal/cmd/JamalMain.java @@ -137,7 +137,7 @@ public static void main(String[] args) { private static final System.Logger LOGGER = System.getLogger("JAMAL"); private static void log(final System.Logger.Level level, final Position pos, final String format, final String... params) { - final var msg = String.format(format, (Object[]) params) + (pos == null ? "" : " at ") + BadSyntaxAt.posFormat(pos); + final var msg = String.format(format, (Object[]) params) + (pos == null ? "" : " at " + pos.posFormat()); LOGGER.log(level, msg); } diff --git a/jamal-engine/src/main/java/javax0/jamal/engine/Processor.java b/jamal-engine/src/main/java/javax0/jamal/engine/Processor.java index fcbd5be03..7efe41ca8 100644 --- a/jamal-engine/src/main/java/javax0/jamal/engine/Processor.java +++ b/jamal-engine/src/main/java/javax0/jamal/engine/Processor.java @@ -200,7 +200,7 @@ public String process(final Input input) throws BadSyntax { skipWhiteSpaces(input); try { processMacro(input, output); - }catch(LinkageError le){ + } catch (LinkageError le) { throw new BadSyntax("Linkage error", le); } } else { @@ -215,7 +215,7 @@ public String process(final Input input) throws BadSyntax { } processingException = badSyntax; throw badSyntax; - }finally { + } finally { closeProcessWithExceptionHandling(output, processingException); } traceRecordFactory.dump(null); @@ -511,7 +511,14 @@ private void pushBadSyntax(BadSyntax bs, final Position ref) throws BadSyntaxAt private String evaluateBuiltinMacro(final Input input, final Position ref, final MacroQualifier qualifier) throws BadSyntaxAt { try { lastInvokedBuiltInMacro = qualifier.macroId; - return qualifier.macro.evaluate(input, this); + input.getPosition().cloneOf.pushSegment(qualifier.macro.getId()); + final String s; + try { + s = qualifier.macro.evaluate(input, this); + } finally { + input.getPosition().cloneOf.popSegment(); + } + return s; } catch (BadSyntax bs) { pushBadSyntax(bs, ref); return ""; diff --git a/jamal-maven-plugin/src/main/java/com/javax0/jamal/maven/JamalLogger.java b/jamal-maven-plugin/src/main/java/com/javax0/jamal/maven/JamalLogger.java index bd62ee81f..4680a65dc 100644 --- a/jamal-maven-plugin/src/main/java/com/javax0/jamal/maven/JamalLogger.java +++ b/jamal-maven-plugin/src/main/java/com/javax0/jamal/maven/JamalLogger.java @@ -7,7 +7,7 @@ public class JamalLogger { public static void log(final System.Logger.Level level, final Position pos, final String format, final String... params) { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("jamal"); - final var msg = String.format(format, (Object[]) params) + (pos == null ? "" : " at ") + BadSyntaxAt.posFormat(pos); + final var msg = String.format(format, (Object[]) params) + (pos == null ? "" : " at " + pos.posFormat()); switch (level) { case DEBUG: log.debug(msg); diff --git a/jamal-snippet/README.adoc b/jamal-snippet/README.adoc index b16a677c9..ba7f8cef8 100644 --- a/jamal-snippet/README.adoc +++ b/jamal-snippet/README.adoc @@ -3816,7 +3816,7 @@ will result in the output .output [source] ---- -2024-12-10 17:58:06 +2024-12-11 13:19:58 ---- diff --git a/jamal-sql/demodb.mv.db b/jamal-sql/demodb.mv.db index 5e88ffeeb20644dd0b41e12fe59289e11ab38216..46535c89864c0321927abcf31c086489d4d87513 100644 GIT binary patch literal 24576 zcmeHPO>f)C877@LX1sM4ShR<|w2W*gF`yO5AvydwMYgqTZDl!-nIsDL2cH)nXvq?Gz!r@ReoR<%W zGtc`zFR~G!YSb%|rB9Cr&jQnlT~wugMh1adr6WehEDB67wj(z* z41%liaI{axfmJIvJDR$pMpX-V8p~sdq7cUVEG- z#;}OLkmO}7eM%_2sgvcY#_-}g!>{sJmbbb&n=T2{t;cYu+Um)e)kh<8lJ~mEi@pXU zXKo}$USx3D=FQAReQI*?>Czewo?K?8psAa{3~dd=E=*q7CpO8!(rSMgc38|tY(Uvk zGPyswNS94ECcL$xs4sT5)!A7^ow)%s{jPp*r`zc1Yn?{D*VtX%ZnoBSgzSo5SwQJU zeY@M}=*>^{_Et}C>@>T*u3o9=-FmC1-@mVK)Vmu=Szq65wik7M;W+EIR$tp_tn0n{ zYOA4F9&N9-nroF><@5Sxy|uozw!PVC_v*doR=e_GKH04*&Gm}jZ1)^D9gG-Gxpz^rKF56Mocx+W1l! zIlHfWozMM-~K|G`OCl5+v%ITHK*NH?l#A;>zfr`phaF-OT4g`dEwmS1-{P< z_W>`w6<+v?GPAS&;)eP|Wfpix4e_JJj}AX#Ex8VS1m!1wenNNymmfWT^luHwKCA8i zfEO@NlZpR9UV+J5oWlhE5x+h>V1wR>3=Uy^hFr$OwCk9JeO5EXiuECHKW6&}@IAo2 z?(q82AR4xYPikhlint}gE*~VA9^_uqHOL03K4T|AzU5bsNk7P0$TDvRj{&2dZk2O^ zK)9KeC2VFJP?DMH(9>OWE>q!Mi$^%!8N1~skQmAnLWTQdcO^BT0OpMGGB#B_5Wvq{ z<-~?RcFvtLfA5$*;*2_B($50|j5@it z3Fl{UYhrV5jjYHhachHBj|NAFka;^H+v$b+SOh;RQE;DgZ{j-DA*DwLWI#^>BNojL zGqb&t+3*lkW@E?)ewEoYG25WXFS`VYUd8N?o9%>_XtpJq9c5n7;R6@^f5cZSA3l57ZxjEY7XE+wttTIQ`K!U9xcI>Rxc~3*ufnyBe8}%ug8x6W z^Yh;;m!Sw@P7$c22uZl$S}8(&K1GP%E{YH)6oD$rO}w+ID)Sej2m)PT!g>7vM;)xG zb>khO4nWO>6hVW%=X~qql%SbRu-?cB zTDGadNS7vP4}qZlCM6yJ0HP-UBmxoviGV~vA|Mfv2)r7B)Bd;M|AP-*`2QBcz7J~f zcXXepx(oh4a5RAs+eNhUwEzE-7^UlqT+uaCGUss81u@8}k*``!_5Y8g{x9|aw==Kd z8l-ip|I3V)D`fM$L;C;cQvZJ^_5Yu|cKu)d&*P78D05;ERtT`V#uWmrdF-sL&5E(J zRGSrJXF^Qs0(p;RZ5D{o8NnzZa{{$HJCqg+AwOuJ{>Mx&53rhrNRx;BtV;?u=h_KY zBq2Z0Z^WP(N>$CNpc$RWsfmo4Rtr@#t)8c9g1WQ#?W-xX{8b_#5s(PH7YI!J|J?r; zHVN>d3;*B7*eB*S`v2wKG1dQ*w4coXXN4$3dH(alQ-!A<>O7wpQ%;V3$_@`P<5iC*9iO%nu?>7w< za_ufaLsRygal&#;V~#Y)Z6;&LV{wf-~_qG9Pw*>hRv7ZWm5!CXwp z6a;gcM=x{spV8M-nVByk`(<;@JP0b1XfGqt>2jJY&zB+54+Z5pQ=s3AO;J9CL_i`S j5s(N-1SA3yf%h1JiT|Jb-(?@V@c$hI{=fCw{r~>~c7iLm literal 24576 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 E06_m8j{pDw diff --git a/jamal-testsupport/src/main/java/javax0/jamal/testsupport/TestThat.java b/jamal-testsupport/src/main/java/javax0/jamal/testsupport/TestThat.java index 5e077bfd4..f6bf6b4a1 100644 --- a/jamal-testsupport/src/main/java/javax0/jamal/testsupport/TestThat.java +++ b/jamal-testsupport/src/main/java/javax0/jamal/testsupport/TestThat.java @@ -69,7 +69,7 @@ private TestThat(Class klass) { private final List logItems = new ArrayList<>(); private void log(final System.Logger.Level level, final Position pos, final String format, final String... params) { - logItems.add("[" + level.getName() + "] " + String.format(format, (Object[]) params) + (pos == null ? "" : " at ") + BadSyntaxAt.posFormat(pos)); + logItems.add("[" + level.getName() + "] " + String.format(format, (Object[]) params) + (pos == null ? "" : " at " + pos.posFormat())); } public List getLogs() { diff --git a/jamal-tools/src/main/java/javax0/jamal/tools/Input.java b/jamal-tools/src/main/java/javax0/jamal/tools/Input.java index 665d60f7a..fd28a156d 100644 --- a/jamal-tools/src/main/java/javax0/jamal/tools/Input.java +++ b/jamal-tools/src/main/java/javax0/jamal/tools/Input.java @@ -7,8 +7,11 @@ */ public class Input implements javax0.jamal.api.Input { private final StringBuilder input; - private final Position pos; + private Position pos; + Position getPos() { + return pos; + } /** * Create an empty input, which may also serve as an output where the characters are collected. @@ -147,7 +150,6 @@ public void stepColumn() { pos.charpos++; } - @Override public StringBuilder getSB() { return input; diff --git a/jamal-word/src/test/resources/demoConverted.docx b/jamal-word/src/test/resources/demoConverted.docx index b281023a4b9efa17829de66b05658157f269af4f..98f89ff6ce806063c211c9fb6caf68ec6853d71a 100644 GIT binary patch delta 216 zcmey7{3Dq+z?+#xgn@&DgJE`7_eS15jLblK^BG2E2;&n|JA_fgG6~F>EXZ~OtmF=x z2{)J_EMy8%;w?N4!gwOGlo>45BLOwfTk1G3SVUCgCL4$``J@fMy2VLTC8$_$q3k${@#Ep?n1EF!9LlMTd}{87&iOdIK&f$400YcRc1 o-v&&-(1*xt8bJ6N2JT?-O$N4L`V*8kGK9z%8d`zH*BN>N0J|?wRR910 diff --git a/jamal-word/src/test/resources/includetestConverted.docx b/jamal-word/src/test/resources/includetestConverted.docx index 53f0a886e2976be482ead8230f6237676fc9c7c7..723905c404754949cea80140a5a7d122556b0c14 100644 GIT binary patch delta 221 zcmeC_W9sQ+;tlX-W)WfF;NW1Goz=aOcLpOfklwt4Q4+#9!t@Qo*vnD~VHmPSae~$K z@q0i-ZVIR{fkZY5Uk(A$lMUI#Hor-K&jwa@FK-tQm@&KhIz*(jsROKWQi~l}xnqkN wn67HE2GcuQY{2w)C~em24(2zs+Jfl=t&U)tr46Faxy=e9-{t_O54U*&0G+5;d;kCd delta 221 zcmeC_W9sQ+;tlX-W)WfF;NW0L?(f>jJA;uKNN--jC<$R4VfqGP>}4s0FbvtEIKgWA z_&p#ZHw9FfKq8xjFNc8W$%brVo8P3rX9Fv{m$!=t%$Qw$9U@ZN)B)Bwsl^Vg+_A+B vOjos7gXtYDHemWYls0R12lE?RZNc<`R!1<+(gsoI+-3!lZ*u_Chub^>*@0D@ diff --git a/jamal-word/src/test/resources/pictureConverted.docx b/jamal-word/src/test/resources/pictureConverted.docx index aa73805c3e97631c64405e01b18ddcc20c8cb8b3..ad5d1ede04699d4b4a06eb8f5310309fc44bd1d6 100644 GIT binary patch delta 304 zcmaF6it+6#M&1B#W)=|!4h{~6*;(BidCxO41L@888T}y)L*~Cw25Sj~v4SlT!rXfkIe7!fEkBfu0urTdK*HtU-aRE zFz)$QLl`ms9bm@f=K*#gO_MbO&A@bGpf#ADA7}%n?*&5S<%1ynxFC11_=+G~F#RIP o5lrg@L-;wt5Ou4AtswHj4q#e4#2ZXkhJ=CXOCkPXS|!vI0LiI!#{d8T delta 304 zcmaF6it+6#M&1B#W)=|!4h{~6RWyyqF2f%NA4jQ$XYA@g4-gS7<0SizPEVeoLY zaDWw076^feyb_$k1Qux&5tINkrs}w|f*E%Wnb^RLN9OlLE#*C8Tvy$vDSFZysn z825auA&eOR4lrZ#^8h=LrpX$CW?(uo&>Bq753~W(_W~jE@<9-OT#!3hd_|Bgn0^uD o2&Q#{A^eOV diff --git a/jamal-word/src/test/resources/sampleConverted.docx b/jamal-word/src/test/resources/sampleConverted.docx index a9d117f257955da0c00dd6b5e9323347fbabaac2..902cf96ba9ea40d1a1593381785d909c61f03ef3 100644 GIT binary patch delta 2336 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