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                 // 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);