37 import java.util.List; 38 import jdk.nashorn.internal.ir.LiteralNode; 39 import jdk.nashorn.internal.ir.Node; 40 import jdk.nashorn.internal.ir.ObjectNode; 41 import jdk.nashorn.internal.ir.PropertyNode; 42 import jdk.nashorn.internal.ir.UnaryNode; 43 import jdk.nashorn.internal.runtime.ErrorManager; 44 import jdk.nashorn.internal.runtime.Source; 45 46 /** 47 * Parses JSON text and returns the corresponding IR node. This is derived from the objectLiteral production of the main parser. 48 * 49 * See: 15.12.1.2 The JSON Syntactic Grammar 50 */ 51 public class JSONParser extends AbstractParser { 52 53 /** 54 * Constructor 55 * @param source the source 56 * @param errors the error manager 57 * @param strict are we in strict mode 58 */ 59 public JSONParser(final Source source, final ErrorManager errors, final boolean strict) { 60 super(source, errors, strict); 61 } 62 63 /** 64 * Implementation of the Quote(value) operation as defined in the ECMA script spec 65 * It wraps a String value in double quotes and escapes characters within in 66 * 67 * @param value string to quote 68 * 69 * @return quoted and escaped string 70 */ 71 public static String quote(final String value) { 72 73 final StringBuilder product = new StringBuilder(); 74 75 product.append("\""); 76 77 for (final char ch : value.toCharArray()) { 78 // TODO: should use a table? 79 switch (ch) { 80 case '\\': 118 * Public parsed method - start lexing a new token stream for 119 * a JSON script 120 * 121 * @return the JSON literal 122 */ 123 public Node parse() { 124 stream = new TokenStream(); 125 126 lexer = new Lexer(source, stream) { 127 128 @Override 129 protected boolean skipComments() { 130 return false; 131 } 132 133 @Override 134 protected boolean isStringDelimiter(final char ch) { 135 return ch == '\"'; 136 } 137 138 @Override 139 protected boolean isWhitespace(final char ch) { 140 return Lexer.isJsonWhitespace(ch); 141 } 142 143 @Override 144 protected boolean isEOL(final char ch) { 145 return Lexer.isJsonEOL(ch); 146 } 147 }; 148 149 k = -1; 150 151 next(); 152 153 final Node resultNode = jsonLiteral(); 154 expect(EOF); 155 156 return resultNode; 157 } 158 159 @SuppressWarnings("fallthrough") 160 private LiteralNode<?> getStringLiteral() { 161 final LiteralNode<?> literal = getLiteral(); 162 final String str = (String)literal.getValue(); 163 164 for (int i = 0; i < str.length(); i++) { 165 final char ch = str.charAt(i); | 37 import java.util.List; 38 import jdk.nashorn.internal.ir.LiteralNode; 39 import jdk.nashorn.internal.ir.Node; 40 import jdk.nashorn.internal.ir.ObjectNode; 41 import jdk.nashorn.internal.ir.PropertyNode; 42 import jdk.nashorn.internal.ir.UnaryNode; 43 import jdk.nashorn.internal.runtime.ErrorManager; 44 import jdk.nashorn.internal.runtime.Source; 45 46 /** 47 * Parses JSON text and returns the corresponding IR node. This is derived from the objectLiteral production of the main parser. 48 * 49 * See: 15.12.1.2 The JSON Syntactic Grammar 50 */ 51 public class JSONParser extends AbstractParser { 52 53 /** 54 * Constructor 55 * @param source the source 56 * @param errors the error manager 57 */ 58 public JSONParser(final Source source, final ErrorManager errors) { 59 super(source, errors, false); 60 } 61 62 /** 63 * Implementation of the Quote(value) operation as defined in the ECMA script spec 64 * It wraps a String value in double quotes and escapes characters within in 65 * 66 * @param value string to quote 67 * 68 * @return quoted and escaped string 69 */ 70 public static String quote(final String value) { 71 72 final StringBuilder product = new StringBuilder(); 73 74 product.append("\""); 75 76 for (final char ch : value.toCharArray()) { 77 // TODO: should use a table? 78 switch (ch) { 79 case '\\': 117 * Public parsed method - start lexing a new token stream for 118 * a JSON script 119 * 120 * @return the JSON literal 121 */ 122 public Node parse() { 123 stream = new TokenStream(); 124 125 lexer = new Lexer(source, stream) { 126 127 @Override 128 protected boolean skipComments() { 129 return false; 130 } 131 132 @Override 133 protected boolean isStringDelimiter(final char ch) { 134 return ch == '\"'; 135 } 136 137 // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONWhiteSpace 138 @Override 139 protected boolean isWhitespace(final char ch) { 140 return Lexer.isJsonWhitespace(ch); 141 } 142 143 @Override 144 protected boolean isEOL(final char ch) { 145 return Lexer.isJsonEOL(ch); 146 } 147 148 // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONNumber 149 @Override 150 protected void scanNumber() { 151 // Record beginning of number. 152 final int start = position; 153 // Assume value is a decimal. 154 TokenType type = TokenType.DECIMAL; 155 156 // floating point can't start with a "." with no leading digit before 157 if (ch0 == '.') { 158 error(Lexer.message("json.invalid.number"), STRING, position, limit); 159 } 160 161 // First digit of number. 162 int digit = convertDigit(ch0, 10); 163 164 // skip first digit 165 skip(1); 166 167 if (digit != 0) { 168 // Skip over remaining digits. 169 while (convertDigit(ch0, 10) != -1) { 170 skip(1); 171 } 172 } 173 174 if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') { 175 // Must be a double. 176 if (ch0 == '.') { 177 // Skip period. 178 skip(1); 179 180 boolean mantissa = false; 181 // Skip mantissa. 182 while (convertDigit(ch0, 10) != -1) { 183 mantissa = true; 184 skip(1); 185 } 186 187 if (! mantissa) { 188 // no digit after "." 189 error(Lexer.message("json.invalid.number"), STRING, position, limit); 190 } 191 } 192 193 // Detect exponent. 194 if (ch0 == 'E' || ch0 == 'e') { 195 // Skip E. 196 skip(1); 197 // Detect and skip exponent sign. 198 if (ch0 == '+' || ch0 == '-') { 199 skip(1); 200 } 201 boolean exponent = false; 202 // Skip exponent. 203 while (convertDigit(ch0, 10) != -1) { 204 exponent = true; 205 skip(1); 206 } 207 208 if (! exponent) { 209 // no digit after "E" 210 error(Lexer.message("json.invalid.number"), STRING, position, limit); 211 } 212 } 213 214 type = TokenType.FLOATING; 215 } 216 217 // Add number token. 218 add(type, start); 219 } 220 221 // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONEscapeCharacter 222 @Override 223 protected boolean isEscapeCharacter(final char ch) { 224 switch (ch) { 225 case '"': 226 case '/': 227 case '\\': 228 case 'b': 229 case 'f': 230 case 'n': 231 case 'r': 232 case 't': 233 // could be unicode escape 234 case 'u': 235 return true; 236 default: 237 return false; 238 } 239 } 240 }; 241 242 k = -1; 243 244 next(); 245 246 final Node resultNode = jsonLiteral(); 247 expect(EOF); 248 249 return resultNode; 250 } 251 252 @SuppressWarnings("fallthrough") 253 private LiteralNode<?> getStringLiteral() { 254 final LiteralNode<?> literal = getLiteral(); 255 final String str = (String)literal.getValue(); 256 257 for (int i = 0; i < str.length(); i++) { 258 final char ch = str.charAt(i); |