diff src/luan/modules/parsers/LuanToString.java @ 1553:26c51acf00f3

improve stringify
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 06 Oct 2020 19:31:57 -0600
parents 46d4baaad64d
children 83249ce59d13
line wrap: on
line diff
--- a/src/luan/modules/parsers/LuanToString.java	Sun Oct 04 20:26:49 2020 -0600
+++ b/src/luan/modules/parsers/LuanToString.java	Tue Oct 06 19:31:57 2020 -0600
@@ -3,6 +3,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.HashSet;
 import java.util.Collections;
 import luan.Luan;
 import luan.LuanTable;
@@ -11,19 +12,85 @@
 
 
 public final class LuanToString {
-	public boolean strict = false;
-	public boolean numberTypes = false;
-	public boolean compressed = false;
-	public boolean useLongStrings = false;
-	public Set longStringKeys = Collections.emptySet();
+	public static class Settings implements Cloneable {
+		public boolean strict = false;
+		public boolean numberTypes = false;
+		public boolean compressed = false;
+		public boolean longStrings = false;
+		public boolean inline = false;
+
+		void applyOptions(LuanTable options) throws LuanException {
+			Boolean b;
+			b = (Boolean)options.get("strict");
+			if( b != null )
+				strict = b;
+			b = (Boolean)options.get("number_types");
+			if( b != null )
+				numberTypes = b;
+			b = (Boolean)options.get("compressed");
+			if( b != null )
+				compressed = b;
+			b = (Boolean)options.get("long_strings");
+			if( b != null )
+				longStrings = b;
+			b = (Boolean)options.get("inline");
+			if( b != null )
+				inline = b;
+		}
+
+		public Settings cloneSettings() {
+			try {
+				return (Settings)clone();
+			} catch(CloneNotSupportedException e) {
+				throw new RuntimeException(e);
+			}
+		}
+	}
+	private static final Settings keySettings = new Settings();
+	private static final Set<String> settingsKeys = new HashSet<String>();
+	static {
+		Collections.addAll(settingsKeys,"strict","number_types","compressed","long_strings","inline");
+	}
+
+	private static void checkOptions(LuanTable options) throws LuanException {
+		for( Map.Entry entry : options.iterable() ) {
+			if( !settingsKeys.contains(entry.getKey()) )
+				throw new LuanException("invalid option: "+entry.getKey());
+			if( !(entry.getValue() instanceof Boolean) )
+				throw new LuanException("options values must be boolean");
+		}
+	}
+
+	public final Settings settingsInit = new Settings();
+	private final LuanTable subOptions;
+
+	public LuanToString(LuanTable options,LuanTable subOptions) throws LuanException {
+		this.subOptions = subOptions;
+		if( options != null ) {
+			checkOptions(options);
+			settingsInit.applyOptions(options);
+		}
+		if( subOptions != null ) {
+			for( Map.Entry entry : subOptions.iterable() ) {
+/*
+				if( !(entry.getKey() instanceof String) )
+					throw new LuanException("sub_options keys must be strings");
+*/
+				if( !(entry.getValue() instanceof LuanTable) )
+					throw new LuanException("sub_options keys must be tables");
+				LuanTable tbl = (LuanTable)entry.getValue();
+				checkOptions(tbl);
+			}
+		}
+	}
 
 	public String toString(Object obj) throws LuanException {
 		StringBuilder sb = new StringBuilder();
-		toString(obj,sb,0,useLongStrings);
+		toString(obj,sb,0,settingsInit);
 		return sb.toString();
 	}
 
-	private void toString(Object obj,StringBuilder sb,int indented,boolean longStrings) throws LuanException {
+	private void toString(Object obj,StringBuilder sb,int indented,Settings settings) throws LuanException {
 		if( obj == null ) {
 			sb.append( "nil" );
 			return;
@@ -33,65 +100,92 @@
 			return;
 		}
 		if( obj instanceof Number ) {
-			toString((Number)obj,sb);
+			toString((Number)obj,sb,settings);
 			return;
 		}
 		if( obj instanceof String ) {
-			toString((String)obj,sb,longStrings);
+			toString((String)obj,sb,settings);
 			return;
 		}
 		if( obj instanceof LuanTable ) {
-			toString((LuanTable)obj,sb,indented,longStrings);
+			toString((LuanTable)obj,sb,indented,settings);
 			return;
 		}
-		if( strict )
+		if( settings.strict )
 			throw new LuanException("can't handle type "+Luan.type(obj));
 		sb.append( '<' );
 		sb.append( obj );
 		sb.append( '>' );
 	}
 
-	private void toString(LuanTable tbl,StringBuilder sb,int indented,boolean longStrings) throws LuanException {
+	private void toString(LuanTable tbl,StringBuilder sb,int indented,Settings settings) throws LuanException {
 		List list = tbl.asList();
 		Map map = tbl.rawMap();
 		sb.append( '{' );
 		boolean first = true;
 		for( Object obj : list ) {
-			if( !compressed )
+			if( settings.compressed ) {
+				if( first )
+					first = false;
+				else
+					sb.append( ',' );
+			} else if( settings.inline ) {
+				if( first ) {
+					first = false;
+					sb.append( ' ' );
+				} else
+					sb.append( ", " );
+			} else {
 				indent(sb,indented+1);
-			else if( first )
-				first = false;
-			else
-				sb.append( ',' );
-			toString(obj,sb,indented+1,longStrings);
+			}
+			toString(obj,sb,indented+1,settings);
 		}
 		for( Object obj : map.entrySet() ) {
 			Map.Entry entry = (Map.Entry)obj;
-			if( !compressed )
+			if( settings.compressed ) {
+				if( first )
+					first = false;
+				else
+					sb.append( ',' );
+			} else if( settings.inline ) {
+				if( first ) {
+					first = false;
+					sb.append( ' ' );
+				} else
+					sb.append( ", " );
+			} else {
 				indent(sb,indented+1);
-			else if( first )
-				first = false;
-			else
-				sb.append( ',' );
-			toString(entry,sb,indented+1);
+			}
+			toString(entry,sb,indented+1,settings);
 		}
-		if( !compressed && (!list.isEmpty() || !map.isEmpty()) )
-			indent(sb,indented);
+		if( !list.isEmpty() || !map.isEmpty() ) {
+			if( settings.compressed ) {
+			} else if( settings.inline ) {
+				sb.append( ' ' );
+			} else {
+				indent(sb,indented);
+			}
+		}
 		sb.append( '}' );
 		return;
 	}
 
-	private void toString(Map.Entry entry,StringBuilder sb,int indented) throws LuanException {
+	private void toString(Map.Entry entry,StringBuilder sb,int indented,Settings settings) throws LuanException {
 		Object key = entry.getKey();
 		if( key instanceof String && ((String)key).matches("[a-zA-Z_][a-zA-Z_0-9]*") ) {
 			sb.append( (String)key );
 		} else {
 			sb.append( '[' );
-			toString( key, sb, indented, false );
+			toString( key, sb, indented, keySettings );
 			sb.append( ']' );
 		}
-		sb.append( compressed ? "=" : " = " );
-		toString( entry.getValue(), sb, indented, longStringKeys.contains(key) );
+		sb.append( settings.compressed ? "=" : " = " );
+		LuanTable options = (LuanTable)subOptions.get(key);
+		if( options != null ) {
+			settings = settings.cloneSettings();
+			settings.applyOptions(options);
+		}
+		toString( entry.getValue(), sb, indented, settings );
 	}
 
 	private void indent(StringBuilder sb,int indented) {
@@ -101,13 +195,13 @@
 		}
 	}
 
-	private void toString(Number n,StringBuilder sb) throws LuanException {
-		if( numberTypes ) {
+	private void toString(Number n,StringBuilder sb,Settings settings) throws LuanException {
+		if( settings.numberTypes ) {
 			sb.append( n.getClass().getSimpleName().toLowerCase() );
 			sb.append( '(' );
 		}
 		sb.append( Luan.toString(n) );
-		if( numberTypes )
+		if( settings.numberTypes )
 			sb.append( ')' );
 	}
 
@@ -123,8 +217,8 @@
 		}
 	}
 
-	private void toString(String s,StringBuilder sb,boolean longStrings) {
-		if( longStrings ) {
+	private void toString(String s,StringBuilder sb,Settings settings) {
+		if( settings.longStrings ) {
 			StringBuilder start = new StringBuilder("[[");
 			if( s.indexOf('\n') != -1 )
 				start.append('\n');