@@ -132,21 +132,34 @@ private static Object tryParam(String n, Object i) {
132132 * Returns: list of values after simtime
133133 * Includes max retry limit to avoid infinite blocking (matches Python behavior).
134134 */
135- private static Object read (int port , String name , String initstr ) {
135+ private static List <Object > read (int port , String name , String initstr ) {
136+ // Parse default value upfront for consistent return type
137+ List <Object > defaultVal = new ArrayList <>();
138+ try {
139+ List <?> parsed = (List <?>) literalEval (initstr );
140+ if (parsed .size () > 1 ) {
141+ defaultVal = new ArrayList <>(parsed .subList (1 , parsed .size ()));
142+ }
143+ } catch (Exception e ) {
144+ // initstr not parseable as list; defaultVal stays empty
145+ }
146+
136147 String filePath = inpath + port + "/" + name ;
137148 try {
138149 Thread .sleep (delay );
139150 } catch (InterruptedException e ) {
140151 Thread .currentThread ().interrupt ();
141- return initstr ;
152+ s += initstr ;
153+ return defaultVal ;
142154 }
143155
144156 String ins ;
145157 try {
146158 ins = new String (Files .readAllBytes (Paths .get (filePath )));
147159 } catch (IOException e ) {
148160 System .out .println ("File " + filePath + " not found, using default value." );
149- return initstr ;
161+ s += initstr ;
162+ return defaultVal ;
150163 }
151164
152165 int attempts = 0 ;
@@ -155,7 +168,8 @@ private static Object read(int port, String name, String initstr) {
155168 Thread .sleep (delay );
156169 } catch (InterruptedException e ) {
157170 Thread .currentThread ().interrupt ();
158- return initstr ;
171+ s += initstr ;
172+ return defaultVal ;
159173 }
160174 try {
161175 ins = new String (Files .readAllBytes (Paths .get (filePath )));
@@ -168,23 +182,43 @@ private static Object read(int port, String name, String initstr) {
168182
169183 if (ins .length () == 0 ) {
170184 System .out .println ("Max retries reached for " + filePath + ", using default value." );
171- return initstr ;
185+ s += initstr ;
186+ return defaultVal ;
172187 }
173188
174189 s += ins ;
175190 try {
176191 List <?> inval = (List <?>) literalEval (ins );
177192 if (!inval .isEmpty ()) {
178- // First element is simtime (preserve as double for fractional values)
179193 double firstSimtime = ((Number ) inval .get (0 )).doubleValue ();
180194 simtime = Math .max (simtime , firstSimtime );
181- // Return remaining elements (values after simtime)
182- return inval .subList (1 , inval .size ());
195+ return new ArrayList <>(inval .subList (1 , inval .size ()));
183196 }
184197 } catch (Exception e ) {
185198 System .out .println ("Error parsing " + ins + ": " + e .getMessage ());
186199 }
187- return initstr ;
200+ s += initstr ;
201+ return defaultVal ;
202+ }
203+
204+ /**
205+ * Escapes a Java string so it can be safely used as a single-quoted Python string literal.
206+ * At minimum, escapes backslash, single quote, newline, carriage return, and tab.
207+ */
208+ private static String escapePythonString (String s ) {
209+ StringBuilder sb = new StringBuilder (s .length ());
210+ for (int i = 0 ; i < s .length (); i ++) {
211+ char c = s .charAt (i );
212+ switch (c ) {
213+ case '\\' : sb .append ("\\ \\ " ); break ;
214+ case '\'' : sb .append ("\\ '" ); break ;
215+ case '\n' : sb .append ("\\ n" ); break ;
216+ case '\r' : sb .append ("\\ r" ); break ;
217+ case '\t' : sb .append ("\\ t" ); break ;
218+ default : sb .append (c ); break ;
219+ }
220+ }
221+ return sb .toString ();
188222 }
189223
190224 /**
@@ -194,7 +228,7 @@ private static Object read(int port, String name, String initstr) {
194228 private static String toPythonLiteral (Object obj ) {
195229 if (obj == null ) return "None" ;
196230 if (obj instanceof Boolean ) return ((Boolean ) obj ) ? "True" : "False" ;
197- if (obj instanceof String ) return "'" + obj + "'" ;
231+ if (obj instanceof String ) return "'" + escapePythonString (( String ) obj ) + "'" ;
198232 if (obj instanceof Number ) return obj .toString ();
199233 if (obj instanceof List ) {
200234 List <?> list = (List <?>) obj ;
@@ -259,9 +293,11 @@ private static void write(int port, String name, Object val, int delta) {
259293 return ;
260294 }
261295 Files .write (Paths .get (path ), content .toString ().getBytes ());
262- } catch (IOException | InterruptedException e ) {
296+ } catch (InterruptedException e ) {
263297 Thread .currentThread ().interrupt ();
264298 System .out .println ("skipping " + outpath + port + "/" + name );
299+ } catch (IOException e ) {
300+ System .out .println ("skipping " + outpath + port + "/" + name );
265301 }
266302 }
267303
@@ -370,7 +406,9 @@ Map<String, Object> parseDict() {
370406 Object value = parseExpression ();
371407 map .put (key .toString (), value );
372408 skipWhitespace ();
373- if (pos >= input .length ()) break ;
409+ if (pos >= input .length ()) {
410+ throw new IllegalArgumentException ("Unterminated dict: missing '}'" );
411+ }
374412 if (input .charAt (pos ) == '}' ) {
375413 pos ++;
376414 break ;
@@ -402,7 +440,9 @@ List<Object> parseList() {
402440 skipWhitespace ();
403441 list .add (parseExpression ());
404442 skipWhitespace ();
405- if (pos >= input .length ()) break ;
443+ if (pos >= input .length ()) {
444+ throw new IllegalArgumentException ("Unterminated list: missing ']'" );
445+ }
406446 if (input .charAt (pos ) == ']' ) {
407447 pos ++;
408448 break ;
@@ -434,7 +474,9 @@ List<Object> parseTuple() {
434474 skipWhitespace ();
435475 list .add (parseExpression ());
436476 skipWhitespace ();
437- if (pos >= input .length ()) break ;
477+ if (pos >= input .length ()) {
478+ throw new IllegalArgumentException ("Unterminated tuple: missing ')'" );
479+ }
438480 if (input .charAt (pos ) == ')' ) {
439481 pos ++;
440482 break ;
0 commit comments