@@ -281,6 +281,60 @@ private static String toPythonLiteral(Object obj) {
281281 return obj .toString ();
282282 }
283283
284+ /**
285+ * Escapes a Java string so it can be safely embedded in a JSON double-quoted string.
286+ * Escapes backslash, double quote, newline, carriage return, and tab.
287+ */
288+ private static String escapeJsonString (String s ) {
289+ StringBuilder sb = new StringBuilder (s .length ());
290+ for (int i = 0 ; i < s .length (); i ++) {
291+ char c = s .charAt (i );
292+ switch (c ) {
293+ case '\\' : sb .append ("\\ \\ " ); break ;
294+ case '"' : sb .append ("\\ \" " ); break ;
295+ case '\n' : sb .append ("\\ n" ); break ;
296+ case '\r' : sb .append ("\\ r" ); break ;
297+ case '\t' : sb .append ("\\ t" ); break ;
298+ default : sb .append (c ); break ;
299+ }
300+ }
301+ return sb .toString ();
302+ }
303+
304+ /**
305+ * Converts a Java object to its JSON string representation.
306+ * true/false/null instead of True/False/None; strings double-quoted.
307+ */
308+ private static String toJsonLiteral (Object obj ) {
309+ if (obj == null ) return "null" ;
310+ if (obj instanceof Boolean ) return ((Boolean ) obj ) ? "true" : "false" ;
311+ if (obj instanceof String ) return "\" " + escapeJsonString ((String ) obj ) + "\" " ;
312+ if (obj instanceof Number ) return obj .toString ();
313+ if (obj instanceof List ) {
314+ List <?> list = (List <?>) obj ;
315+ StringBuilder sb = new StringBuilder ("[" );
316+ for (int i = 0 ; i < list .size (); i ++) {
317+ if (i > 0 ) sb .append (", " );
318+ sb .append (toJsonLiteral (list .get (i )));
319+ }
320+ sb .append ("]" );
321+ return sb .toString ();
322+ }
323+ if (obj instanceof Map ) {
324+ Map <?, ?> map = (Map <?, ?>) obj ;
325+ StringBuilder sb = new StringBuilder ("{" );
326+ boolean first = true ;
327+ for (Map .Entry <?, ?> entry : map .entrySet ()) {
328+ if (!first ) sb .append (", " );
329+ sb .append (toJsonLiteral (entry .getKey ())).append (": " ).append (toJsonLiteral (entry .getValue ()));
330+ first = false ;
331+ }
332+ sb .append ("}" );
333+ return sb .toString ();
334+ }
335+ return obj .toString ();
336+ }
337+
284338 /**
285339 * Writes data to a port file.
286340 * Prepends simtime+delta to the value list, then serializes to Python-literal format.
@@ -437,10 +491,10 @@ public static void write(String portName, String name, Object val, int delta) {
437491 if (val instanceof List ) {
438492 List <?> listVal = (List <?>) val ;
439493 StringBuilder sb = new StringBuilder ("[" );
440- sb .append (toPythonLiteral (simtime + delta ));
494+ sb .append (toJsonLiteral (simtime + delta ));
441495 for (Object o : listVal ) {
442496 sb .append (", " );
443- sb .append (toPythonLiteral (o ));
497+ sb .append (toJsonLiteral (o ));
444498 }
445499 sb .append ("]" );
446500 payload = sb .toString ();
@@ -750,9 +804,9 @@ Object parseKeyword() {
750804 }
751805 String word = input .substring (start , pos );
752806 switch (word ) {
753- case "True" : return Boolean .TRUE ;
754- case "False" : return Boolean .FALSE ;
755- case "None" : return null ;
807+ case "True" : case "true" : return Boolean .TRUE ;
808+ case "False" : case "false" : return Boolean .FALSE ;
809+ case "None" : case "null" : return null ;
756810 default : throw new IllegalArgumentException ("Unknown keyword: '" + word + "' at position " + start );
757811 }
758812 }
0 commit comments