1 /*
   2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.oracle.javafx.jmx.json.impl;
  27 
  28 import com.oracle.javafx.jmx.json.JSONException;
  29 import java.io.IOException;
  30 import java.util.HashMap;
  31 import java.util.Stack;
  32 
  33 
  34 /**
  35  * JSON syntax. Collection of symbols linked with grammar processor. Grammar
  36  * tree trversal generate events fed into JSONParserHandler instance.
  37  */
  38 enum JSONSymbol {
  39 
  40     X, O, O1, O3, OV, A, A1, A2, V, VA,
  41     CURLYOPEN, CURLYCLOSE, COLON, COMMA, SQUAREOPEN, SQUARECLOSE, KEYWORD, STRING, NUMBER, EOS,
  42     X_, O_, O1_, O3_, OV_, A_, A1_, A2_, V_, VA_;
  43 
  44     static final boolean DEBUG = false;
  45 
  46     static {
  47         final JSONSymbol[] epsilon = new JSONSymbol[0];
  48         X.transition(CURLYOPEN, new JSONSymbol[]{O});
  49         X.transition(SQUAREOPEN, new JSONSymbol[]{A});
  50         O.transition(CURLYOPEN, new JSONSymbol[]{CURLYOPEN, O1, CURLYCLOSE});
  51         O1.transition(CURLYCLOSE, epsilon);
  52         O1.transition(STRING, new JSONSymbol[]{OV, O3});
  53         O3.transition(CURLYCLOSE, epsilon);
  54         O3.transition(COMMA, new JSONSymbol[]{COMMA, OV, O3});
  55         OV.transition(STRING, new JSONSymbol[]{STRING, COLON, V});
  56         A.transition(SQUAREOPEN, new JSONSymbol[]{SQUAREOPEN, A1, SQUARECLOSE});
  57         A1.transition(CURLYOPEN, new JSONSymbol[]{VA, A2});
  58         A1.transition(SQUAREOPEN, new JSONSymbol[]{VA, A2});
  59         A1.transition(SQUARECLOSE, epsilon);
  60         A1.transition(KEYWORD, new JSONSymbol[]{VA, A2});
  61         A1.transition(STRING, new JSONSymbol[]{VA, A2});
  62         A1.transition(NUMBER, new JSONSymbol[]{VA, A2});
  63         A2.transition(COMMA, new JSONSymbol[]{COMMA, VA, A2});
  64         A2.transition(SQUARECLOSE, epsilon);
  65         VA.transition(CURLYOPEN, new JSONSymbol[]{V});
  66         VA.transition(SQUAREOPEN, new JSONSymbol[]{V});
  67         VA.transition(STRING, new JSONSymbol[]{V});
  68         VA.transition(NUMBER, new JSONSymbol[]{V});
  69         VA.transition(KEYWORD, new JSONSymbol[]{V});
  70         V.transition(CURLYOPEN, new JSONSymbol[]{O});
  71         V.transition(SQUAREOPEN, new JSONSymbol[]{A});
  72         V.transition(KEYWORD, new JSONSymbol[]{KEYWORD});
  73         V.transition(STRING, new JSONSymbol[]{STRING});
  74         V.transition(NUMBER, new JSONSymbol[]{NUMBER});
  75         X.marker(X_);
  76         O.marker(O_);
  77         O1.marker(O1_);
  78         O3.marker(O3_);
  79         OV.marker(OV_);
  80         A.marker(A_);
  81         A1.marker(A1_);
  82         A2.marker(A2_);
  83         VA.marker(VA_);
  84         V.marker(V_);
  85     }
  86 
  87     boolean isTerminal = true;
  88     boolean isMarker = false;
  89     HashMap<JSONSymbol, JSONSymbol[]> transitions;
  90     JSONSymbol markerSymbol;
  91 
  92     private void transition(JSONSymbol s, JSONSymbol[] sequence) {
  93         if (isTerminal) {
  94             isTerminal = false;
  95             transitions = new HashMap<JSONSymbol, JSONSymbol[]>();
  96         }
  97         transitions.put(s, sequence);
  98     }
  99 
 100     private void marker(JSONSymbol s) {
 101         this.markerSymbol = s;
 102         s.isMarker = true;
 103     }
 104 
 105     private static Stack<JSONSymbol> stack;
 106     private static JSONSymbol        terminal;
 107     private static JSONSymbol        current;
 108     private static JSONScanner       scanner;
 109     private static String            value;
 110 
 111     static void init(JSONScanner js) throws JSONException, IOException  {
 112         scanner = js;
 113         stack = new Stack<JSONSymbol>();
 114 
 115         stack.push(X);
 116         terminal = scanner.nextSymbol();
 117     }
 118 
 119     static JSONSymbol next() throws JSONException, IOException {
 120         current = stack.pop();
 121         if (DEBUG) {
 122             Object[] args = {current};
 123             System.out.println(JSONMessages.localize(args, "parser_current"));
 124         }
 125 
 126         if (current.isMarker) {
 127             if (current == X_) {
 128                 // reached bottom of processing stack
 129                 return current;
 130             }
 131         } else if (current.isTerminal) {
 132             if (current != terminal) {
 133                 Object[] args = {current, terminal};
 134                 throw new JSONException(JSONMessages.localize(args, "expected_but_found"), scanner.line(), scanner.column());
 135             }
 136             value = scanner.getValue();
 137             if (DEBUG) {
 138                 Object[] args = {current, value};
 139                 System.out.println(JSONMessages.localize(args, "parser_type"));
 140             }
 141             terminal = scanner.nextSymbol();
 142             if (DEBUG) {
 143                 Object[] args = {terminal, scanner.line(), scanner.column()};
 144                 System.out.println(JSONMessages.localize(args, "parser_next_terminal"));
 145             }
 146         } else {
 147             JSONSymbol[] target = current.transitions.get(terminal);
 148             if (target == null) {
 149                 Object[] args = {terminal, current};
 150                 throw new JSONException(JSONMessages.localize(args, "unexpected_terminal"), scanner.line(), scanner.column());
 151             }
 152 
 153             if (DEBUG) {
 154                 Object[] args = {current.markerSymbol};
 155                 System.out.print(JSONMessages.localize(args, "parser_target") + ", ");
 156             }
 157             stack.push(current.markerSymbol);
 158 
 159             for (int i = target.length; --i >= 0;) {
 160                 final JSONSymbol s = target[i];
 161 
 162                 if (DEBUG) {
 163                     System.out.print(s.toString() + (i > 0 ? ", " : "\n"));
 164                 }
 165 
 166                 stack.push(s);
 167             }
 168         }
 169         return current;
 170     }
 171 
 172     static String getValue() {
 173         return value;
 174     }
 175 }