Mercurial Hosting > luan
comparison 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 |
comparison
equal
deleted
inserted
replaced
1552:46d4baaad64d | 1553:26c51acf00f3 |
---|---|
1 package luan.modules.parsers; | 1 package luan.modules.parsers; |
2 | 2 |
3 import java.util.List; | 3 import java.util.List; |
4 import java.util.Map; | 4 import java.util.Map; |
5 import java.util.Set; | 5 import java.util.Set; |
6 import java.util.HashSet; | |
6 import java.util.Collections; | 7 import java.util.Collections; |
7 import luan.Luan; | 8 import luan.Luan; |
8 import luan.LuanTable; | 9 import luan.LuanTable; |
9 import luan.LuanException; | 10 import luan.LuanException; |
10 import luan.LuanRuntimeException; | 11 import luan.LuanRuntimeException; |
11 | 12 |
12 | 13 |
13 public final class LuanToString { | 14 public final class LuanToString { |
14 public boolean strict = false; | 15 public static class Settings implements Cloneable { |
15 public boolean numberTypes = false; | 16 public boolean strict = false; |
16 public boolean compressed = false; | 17 public boolean numberTypes = false; |
17 public boolean useLongStrings = false; | 18 public boolean compressed = false; |
18 public Set longStringKeys = Collections.emptySet(); | 19 public boolean longStrings = false; |
20 public boolean inline = false; | |
21 | |
22 void applyOptions(LuanTable options) throws LuanException { | |
23 Boolean b; | |
24 b = (Boolean)options.get("strict"); | |
25 if( b != null ) | |
26 strict = b; | |
27 b = (Boolean)options.get("number_types"); | |
28 if( b != null ) | |
29 numberTypes = b; | |
30 b = (Boolean)options.get("compressed"); | |
31 if( b != null ) | |
32 compressed = b; | |
33 b = (Boolean)options.get("long_strings"); | |
34 if( b != null ) | |
35 longStrings = b; | |
36 b = (Boolean)options.get("inline"); | |
37 if( b != null ) | |
38 inline = b; | |
39 } | |
40 | |
41 public Settings cloneSettings() { | |
42 try { | |
43 return (Settings)clone(); | |
44 } catch(CloneNotSupportedException e) { | |
45 throw new RuntimeException(e); | |
46 } | |
47 } | |
48 } | |
49 private static final Settings keySettings = new Settings(); | |
50 private static final Set<String> settingsKeys = new HashSet<String>(); | |
51 static { | |
52 Collections.addAll(settingsKeys,"strict","number_types","compressed","long_strings","inline"); | |
53 } | |
54 | |
55 private static void checkOptions(LuanTable options) throws LuanException { | |
56 for( Map.Entry entry : options.iterable() ) { | |
57 if( !settingsKeys.contains(entry.getKey()) ) | |
58 throw new LuanException("invalid option: "+entry.getKey()); | |
59 if( !(entry.getValue() instanceof Boolean) ) | |
60 throw new LuanException("options values must be boolean"); | |
61 } | |
62 } | |
63 | |
64 public final Settings settingsInit = new Settings(); | |
65 private final LuanTable subOptions; | |
66 | |
67 public LuanToString(LuanTable options,LuanTable subOptions) throws LuanException { | |
68 this.subOptions = subOptions; | |
69 if( options != null ) { | |
70 checkOptions(options); | |
71 settingsInit.applyOptions(options); | |
72 } | |
73 if( subOptions != null ) { | |
74 for( Map.Entry entry : subOptions.iterable() ) { | |
75 /* | |
76 if( !(entry.getKey() instanceof String) ) | |
77 throw new LuanException("sub_options keys must be strings"); | |
78 */ | |
79 if( !(entry.getValue() instanceof LuanTable) ) | |
80 throw new LuanException("sub_options keys must be tables"); | |
81 LuanTable tbl = (LuanTable)entry.getValue(); | |
82 checkOptions(tbl); | |
83 } | |
84 } | |
85 } | |
19 | 86 |
20 public String toString(Object obj) throws LuanException { | 87 public String toString(Object obj) throws LuanException { |
21 StringBuilder sb = new StringBuilder(); | 88 StringBuilder sb = new StringBuilder(); |
22 toString(obj,sb,0,useLongStrings); | 89 toString(obj,sb,0,settingsInit); |
23 return sb.toString(); | 90 return sb.toString(); |
24 } | 91 } |
25 | 92 |
26 private void toString(Object obj,StringBuilder sb,int indented,boolean longStrings) throws LuanException { | 93 private void toString(Object obj,StringBuilder sb,int indented,Settings settings) throws LuanException { |
27 if( obj == null ) { | 94 if( obj == null ) { |
28 sb.append( "nil" ); | 95 sb.append( "nil" ); |
29 return; | 96 return; |
30 } | 97 } |
31 if( obj instanceof Boolean ) { | 98 if( obj instanceof Boolean ) { |
32 sb.append( obj ); | 99 sb.append( obj ); |
33 return; | 100 return; |
34 } | 101 } |
35 if( obj instanceof Number ) { | 102 if( obj instanceof Number ) { |
36 toString((Number)obj,sb); | 103 toString((Number)obj,sb,settings); |
37 return; | 104 return; |
38 } | 105 } |
39 if( obj instanceof String ) { | 106 if( obj instanceof String ) { |
40 toString((String)obj,sb,longStrings); | 107 toString((String)obj,sb,settings); |
41 return; | 108 return; |
42 } | 109 } |
43 if( obj instanceof LuanTable ) { | 110 if( obj instanceof LuanTable ) { |
44 toString((LuanTable)obj,sb,indented,longStrings); | 111 toString((LuanTable)obj,sb,indented,settings); |
45 return; | 112 return; |
46 } | 113 } |
47 if( strict ) | 114 if( settings.strict ) |
48 throw new LuanException("can't handle type "+Luan.type(obj)); | 115 throw new LuanException("can't handle type "+Luan.type(obj)); |
49 sb.append( '<' ); | 116 sb.append( '<' ); |
50 sb.append( obj ); | 117 sb.append( obj ); |
51 sb.append( '>' ); | 118 sb.append( '>' ); |
52 } | 119 } |
53 | 120 |
54 private void toString(LuanTable tbl,StringBuilder sb,int indented,boolean longStrings) throws LuanException { | 121 private void toString(LuanTable tbl,StringBuilder sb,int indented,Settings settings) throws LuanException { |
55 List list = tbl.asList(); | 122 List list = tbl.asList(); |
56 Map map = tbl.rawMap(); | 123 Map map = tbl.rawMap(); |
57 sb.append( '{' ); | 124 sb.append( '{' ); |
58 boolean first = true; | 125 boolean first = true; |
59 for( Object obj : list ) { | 126 for( Object obj : list ) { |
60 if( !compressed ) | 127 if( settings.compressed ) { |
128 if( first ) | |
129 first = false; | |
130 else | |
131 sb.append( ',' ); | |
132 } else if( settings.inline ) { | |
133 if( first ) { | |
134 first = false; | |
135 sb.append( ' ' ); | |
136 } else | |
137 sb.append( ", " ); | |
138 } else { | |
61 indent(sb,indented+1); | 139 indent(sb,indented+1); |
62 else if( first ) | 140 } |
63 first = false; | 141 toString(obj,sb,indented+1,settings); |
64 else | |
65 sb.append( ',' ); | |
66 toString(obj,sb,indented+1,longStrings); | |
67 } | 142 } |
68 for( Object obj : map.entrySet() ) { | 143 for( Object obj : map.entrySet() ) { |
69 Map.Entry entry = (Map.Entry)obj; | 144 Map.Entry entry = (Map.Entry)obj; |
70 if( !compressed ) | 145 if( settings.compressed ) { |
146 if( first ) | |
147 first = false; | |
148 else | |
149 sb.append( ',' ); | |
150 } else if( settings.inline ) { | |
151 if( first ) { | |
152 first = false; | |
153 sb.append( ' ' ); | |
154 } else | |
155 sb.append( ", " ); | |
156 } else { | |
71 indent(sb,indented+1); | 157 indent(sb,indented+1); |
72 else if( first ) | 158 } |
73 first = false; | 159 toString(entry,sb,indented+1,settings); |
74 else | 160 } |
75 sb.append( ',' ); | 161 if( !list.isEmpty() || !map.isEmpty() ) { |
76 toString(entry,sb,indented+1); | 162 if( settings.compressed ) { |
77 } | 163 } else if( settings.inline ) { |
78 if( !compressed && (!list.isEmpty() || !map.isEmpty()) ) | 164 sb.append( ' ' ); |
79 indent(sb,indented); | 165 } else { |
166 indent(sb,indented); | |
167 } | |
168 } | |
80 sb.append( '}' ); | 169 sb.append( '}' ); |
81 return; | 170 return; |
82 } | 171 } |
83 | 172 |
84 private void toString(Map.Entry entry,StringBuilder sb,int indented) throws LuanException { | 173 private void toString(Map.Entry entry,StringBuilder sb,int indented,Settings settings) throws LuanException { |
85 Object key = entry.getKey(); | 174 Object key = entry.getKey(); |
86 if( key instanceof String && ((String)key).matches("[a-zA-Z_][a-zA-Z_0-9]*") ) { | 175 if( key instanceof String && ((String)key).matches("[a-zA-Z_][a-zA-Z_0-9]*") ) { |
87 sb.append( (String)key ); | 176 sb.append( (String)key ); |
88 } else { | 177 } else { |
89 sb.append( '[' ); | 178 sb.append( '[' ); |
90 toString( key, sb, indented, false ); | 179 toString( key, sb, indented, keySettings ); |
91 sb.append( ']' ); | 180 sb.append( ']' ); |
92 } | 181 } |
93 sb.append( compressed ? "=" : " = " ); | 182 sb.append( settings.compressed ? "=" : " = " ); |
94 toString( entry.getValue(), sb, indented, longStringKeys.contains(key) ); | 183 LuanTable options = (LuanTable)subOptions.get(key); |
184 if( options != null ) { | |
185 settings = settings.cloneSettings(); | |
186 settings.applyOptions(options); | |
187 } | |
188 toString( entry.getValue(), sb, indented, settings ); | |
95 } | 189 } |
96 | 190 |
97 private void indent(StringBuilder sb,int indented) { | 191 private void indent(StringBuilder sb,int indented) { |
98 sb.append( '\n' ); | 192 sb.append( '\n' ); |
99 for( int i=0; i<indented; i++ ) { | 193 for( int i=0; i<indented; i++ ) { |
100 sb.append( '\t' ); | 194 sb.append( '\t' ); |
101 } | 195 } |
102 } | 196 } |
103 | 197 |
104 private void toString(Number n,StringBuilder sb) throws LuanException { | 198 private void toString(Number n,StringBuilder sb,Settings settings) throws LuanException { |
105 if( numberTypes ) { | 199 if( settings.numberTypes ) { |
106 sb.append( n.getClass().getSimpleName().toLowerCase() ); | 200 sb.append( n.getClass().getSimpleName().toLowerCase() ); |
107 sb.append( '(' ); | 201 sb.append( '(' ); |
108 } | 202 } |
109 sb.append( Luan.toString(n) ); | 203 sb.append( Luan.toString(n) ); |
110 if( numberTypes ) | 204 if( settings.numberTypes ) |
111 sb.append( ')' ); | 205 sb.append( ')' ); |
112 } | 206 } |
113 | 207 |
114 public static void addNumberTypes(LuanTable env) { | 208 public static void addNumberTypes(LuanTable env) { |
115 try { | 209 try { |
121 } catch(LuanException e) { | 215 } catch(LuanException e) { |
122 throw new LuanRuntimeException(e); | 216 throw new LuanRuntimeException(e); |
123 } | 217 } |
124 } | 218 } |
125 | 219 |
126 private void toString(String s,StringBuilder sb,boolean longStrings) { | 220 private void toString(String s,StringBuilder sb,Settings settings) { |
127 if( longStrings ) { | 221 if( settings.longStrings ) { |
128 StringBuilder start = new StringBuilder("[["); | 222 StringBuilder start = new StringBuilder("[["); |
129 if( s.indexOf('\n') != -1 ) | 223 if( s.indexOf('\n') != -1 ) |
130 start.append('\n'); | 224 start.append('\n'); |
131 StringBuilder end = new StringBuilder("]]"); | 225 StringBuilder end = new StringBuilder("]]"); |
132 while( s.contains(end) ) { | 226 while( s.contains(end) ) { |