src/jdk/nashorn/internal/parser/JSONParser.java

Print this page




  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                 // If number begins with 0x.
 165                 if (digit == 0 && (ch1 == 'x' || ch1 == 'X') && convertDigit(ch2, 16) != -1) {
 166                     // Skip over 0xN.
 167                     skip(3);
 168                     // Skip over remaining digits.
 169                     while (convertDigit(ch0, 16) != -1) {
 170                         skip(1);
 171                     }
 172                     error(Lexer.message("json.no.hexadecimal.number"), STRING, position, limit);
 173                     type = TokenType.HEXADECIMAL;
 174                 } else {
 175                     // Check for possible octal constant.
 176                     boolean octal = digit == 0;
 177                     // Skip first digit if not leading '.'.
 178                     if (digit != -1) {
 179                         skip(1);
 180                     }
 181 
 182                     // Skip remaining digits.
 183                     while (convertDigit(ch0, 10) != -1) {
 184                         // Skip digit.
 185                         skip(1);
 186                     }
 187 
 188                     if (octal && position - start > 1) {
 189                         error(Lexer.message("json.no.octal.number"), STRING, position, limit);
 190                         type = TokenType.OCTAL;
 191                     } else if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') {
 192                         // Must be a double.
 193                         if (ch0 == '.') {
 194                             // Skip period.
 195                             skip(1);
 196                             boolean mantissa = false;
 197                             // Skip mantissa.
 198                             while (convertDigit(ch0, 10) != -1) {
 199                                 skip(1);
 200                                 mantissa = true;
 201                             }
 202 
 203                             if (! mantissa) {
 204                                 // no digit after "."
 205                                 error(Lexer.message("json.invalid.number"), STRING, position, limit);
 206                             }
 207                         }
 208 
 209                         // Detect exponent.
 210                         if (ch0 == 'E' || ch0 == 'e') {
 211                             // Skip E.
 212                             skip(1);
 213                             // Detect and skip exponent sign.
 214                             if (ch0 == '+' || ch0 == '-') {
 215                                 skip(1);
 216                             }
 217                             boolean exponent = false;
 218                             // Skip exponent.
 219                             while (convertDigit(ch0, 10) != -1) {
 220                                 exponent = true;
 221                                 skip(1);
 222                             }
 223 
 224                             if (! exponent) {
 225                                 // no digit after "E"
 226                                 error(Lexer.message("json.invalid.number"), STRING, position, limit);
 227                             }
 228                         }
 229 
 230                         type = TokenType.FLOATING;
 231                     }
 232                 }
 233 
 234                 // Add number token.
 235                 add(type, start);
 236             }
 237 
 238             // ECMA 15.12.1.1 The JSON Lexical Grammar - JSONEscapeCharacter
 239             @Override
 240             protected boolean isEscapeCharacter(final char ch) {
 241                 switch (ch) {
 242                     case '"':
 243                     case '/':
 244                     case '\\':
 245                     case 'b':
 246                     case 'f':
 247                     case 'n':
 248                     case 'r':
 249                     case 't':
 250                     // could be unicode escape
 251                     case 'u':
 252                         return true;
 253                     default:
 254                         return false;
 255                 }
 256             }
 257         };
 258 
 259         k = -1;
 260 
 261         next();
 262 
 263         final Node resultNode = jsonLiteral();
 264         expect(EOF);
 265 
 266         return resultNode;
 267     }
 268 
 269     @SuppressWarnings("fallthrough")
 270     private LiteralNode<?> getStringLiteral() {
 271         final LiteralNode<?> literal = getLiteral();
 272         final String         str     = (String)literal.getValue();
 273 
 274         for (int i = 0; i < str.length(); i++) {
 275             final char ch = str.charAt(i);