JAL-3026 adds org.json.simple to srcjars and jsonsimple-site.zip
[jalview.git] / srcjar / org / json / simple / parser / JSONParser.java
diff --git a/srcjar/org/json/simple/parser/JSONParser.java b/srcjar/org/json/simple/parser/JSONParser.java
new file mode 100644 (file)
index 0000000..59f8e31
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
+ * Created on 2006-4-15
+ */
+package org.json.simple.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+
+/**
+ * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
+ * 
+ * @author FangYidong<fangyidong@yahoo.com.cn>
+ */
+public class JSONParser {
+       public static final int S_INIT=0;
+       public static final int S_IN_FINISHED_VALUE=1;//string,number,boolean,null,object,array
+       public static final int S_IN_OBJECT=2;
+       public static final int S_IN_ARRAY=3;
+       public static final int S_PASSED_PAIR_KEY=4;
+       public static final int S_IN_PAIR_VALUE=5;
+       public static final int S_END=6;
+       public static final int S_IN_ERROR=-1;
+       
+       private LinkedList handlerStatusStack;
+       private Yylex lexer = new Yylex((Reader)null);
+       private Yytoken token = null;
+       private int status = S_INIT;
+       
+       private int peekStatus(LinkedList statusStack){
+               if(statusStack.size()==0)
+                       return -1;
+               Integer status=(Integer)statusStack.getFirst();
+               return status.intValue();
+       }
+       
+    /**
+     *  Reset the parser to the initial state without resetting the underlying reader.
+     *
+     */
+    public void reset(){
+        token = null;
+        status = S_INIT;
+        handlerStatusStack = null;
+    }
+    
+    /**
+     * Reset the parser to the initial state with a new character reader.
+     * 
+     * @param in - The new character reader.
+     * @throws IOException
+     * @throws ParseException
+     */
+       public void reset(Reader in){
+               lexer.yyreset(in);
+               reset();
+       }
+       
+       /**
+        * @return The position of the beginning of the current token.
+        */
+       public int getPosition(){
+               return lexer.getPosition();
+       }
+       
+       public Object parse(String s) throws ParseException{
+               return parse(s, (ContainerFactory)null);
+       }
+       
+       public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
+               StringReader in=new StringReader(s);
+               try{
+                       return parse(in, containerFactory);
+               }
+               catch(IOException ie){
+                       /*
+                        * Actually it will never happen.
+                        */
+                       throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
+               }
+       }
+       
+       public Object parse(Reader in) throws IOException, ParseException{
+               return parse(in, (ContainerFactory)null);
+       }
+       
+       /**
+        * Parse JSON text into java object from the input source.
+        *      
+        * @param in
+     * @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
+        * @return Instance of the following:
+        *  org.json.simple.JSONObject,
+        *      org.json.simple.JSONArray,
+        *      java.lang.String,
+        *      java.lang.Number,
+        *      java.lang.Boolean,
+        *      null
+        * 
+        * @throws IOException
+        * @throws ParseException
+        */
+       public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
+               reset(in);
+               LinkedList statusStack = new LinkedList();
+               LinkedList valueStack = new LinkedList();
+               
+               try{
+                       do{
+                               nextToken();
+                               switch(status){
+                               case S_INIT:
+                                       switch(token.type){
+                                       case Yytoken.TYPE_VALUE:
+                                               status=S_IN_FINISHED_VALUE;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(token.value);
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(createObjectContainer(containerFactory));
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(createArrayContainer(containerFactory));
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }//inner switch
+                                       break;
+                                       
+                               case S_IN_FINISHED_VALUE:
+                                       if(token.type==Yytoken.TYPE_EOF)
+                                               return valueStack.removeFirst();
+                                       else
+                                               throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                                       
+                               case S_IN_OBJECT:
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COMMA:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               if(token.value instanceof String){
+                                                       String key=(String)token.value;
+                                                       valueStack.addFirst(key);
+                                                       status=S_PASSED_PAIR_KEY;
+                                                       statusStack.addFirst(new Integer(status));
+                                               }
+                                               else{
+                                                       status=S_IN_ERROR;
+                                               }
+                                               break;
+                                       case Yytoken.TYPE_RIGHT_BRACE:
+                                               if(valueStack.size()>1){
+                                                       statusStack.removeFirst();
+                                                       valueStack.removeFirst();
+                                                       status=peekStatus(statusStack);
+                                               }
+                                               else{
+                                                       status=S_IN_FINISHED_VALUE;
+                                               }
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                               break;
+                                       }//inner switch
+                                       break;
+                                       
+                               case S_PASSED_PAIR_KEY:
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COLON:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               statusStack.removeFirst();
+                                               String key=(String)valueStack.removeFirst();
+                                               Map parent=(Map)valueStack.getFirst();
+                                               parent.put(key,token.value);
+                                               status=peekStatus(statusStack);
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               statusStack.removeFirst();
+                                               key=(String)valueStack.removeFirst();
+                                               parent=(Map)valueStack.getFirst();
+                                               List newArray=createArrayContainer(containerFactory);
+                                               parent.put(key,newArray);
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(newArray);
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               statusStack.removeFirst();
+                                               key=(String)valueStack.removeFirst();
+                                               parent=(Map)valueStack.getFirst();
+                                               Map newObject=createObjectContainer(containerFactory);
+                                               parent.put(key,newObject);
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(newObject);
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }
+                                       break;
+                                       
+                               case S_IN_ARRAY:
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COMMA:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               List val=(List)valueStack.getFirst();
+                                               val.add(token.value);
+                                               break;
+                                       case Yytoken.TYPE_RIGHT_SQUARE:
+                                               if(valueStack.size()>1){
+                                                       statusStack.removeFirst();
+                                                       valueStack.removeFirst();
+                                                       status=peekStatus(statusStack);
+                                               }
+                                               else{
+                                                       status=S_IN_FINISHED_VALUE;
+                                               }
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               val=(List)valueStack.getFirst();
+                                               Map newObject=createObjectContainer(containerFactory);
+                                               val.add(newObject);
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(newObject);
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               val=(List)valueStack.getFirst();
+                                               List newArray=createArrayContainer(containerFactory);
+                                               val.add(newArray);
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               valueStack.addFirst(newArray);
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }//inner switch
+                                       break;
+                               case S_IN_ERROR:
+                                       throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                               }//switch
+                               if(status==S_IN_ERROR){
+                                       throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                               }
+                       }while(token.type!=Yytoken.TYPE_EOF);
+               }
+               catch(IOException ie){
+                       throw ie;
+               }
+               
+               throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+       }
+       
+       private void nextToken() throws ParseException, IOException{
+               token = lexer.yylex();
+               if(token == null)
+                       token = new Yytoken(Yytoken.TYPE_EOF, null);
+       }
+       
+       private Map createObjectContainer(ContainerFactory containerFactory){
+               if(containerFactory == null)
+                       return new JSONObject();
+               Map m = containerFactory.createObjectContainer();
+               
+               if(m == null)
+                       return new JSONObject();
+               return m;
+       }
+       
+       private List createArrayContainer(ContainerFactory containerFactory){
+               if(containerFactory == null)
+                       return new JSONArray();
+               List l = containerFactory.creatArrayContainer();
+               
+               if(l == null)
+                       return new JSONArray();
+               return l;
+       }
+       
+       public void parse(String s, ContentHandler contentHandler) throws ParseException{
+               parse(s, contentHandler, false);
+       }
+       
+       public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
+               StringReader in=new StringReader(s);
+               try{
+                       parse(in, contentHandler, isResume);
+               }
+               catch(IOException ie){
+                       /*
+                        * Actually it will never happen.
+                        */
+                       throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
+               }
+       }
+       
+       public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
+               parse(in, contentHandler, false);
+       }
+       
+       /**
+        * Stream processing of JSON text.
+        * 
+        * @see ContentHandler
+        * 
+        * @param in
+        * @param contentHandler
+        * @param isResume - Indicates if it continues previous parsing operation.
+     *                   If set to true, resume parsing the old stream, and parameter 'in' will be ignored. 
+        *                   If this method is called for the first time in this instance, isResume will be ignored.
+        * 
+        * @throws IOException
+        * @throws ParseException
+        */
+       public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
+               if(!isResume){
+                       reset(in);
+                       handlerStatusStack = new LinkedList();
+               }
+               else{
+                       if(handlerStatusStack == null){
+                               isResume = false;
+                               reset(in);
+                               handlerStatusStack = new LinkedList();
+                       }
+               }
+               
+               LinkedList statusStack = handlerStatusStack;    
+               
+               try{
+                       do{
+                               switch(status){
+                               case S_INIT:
+                                       contentHandler.startJSON();
+                                       nextToken();
+                                       switch(token.type){
+                                       case Yytoken.TYPE_VALUE:
+                                               status=S_IN_FINISHED_VALUE;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.primitive(token.value))
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startObject())
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startArray())
+                                                       return;
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }//inner switch
+                                       break;
+                                       
+                               case S_IN_FINISHED_VALUE:
+                                       nextToken();
+                                       if(token.type==Yytoken.TYPE_EOF){
+                                               contentHandler.endJSON();
+                                               status = S_END;
+                                               return;
+                                       }
+                                       else{
+                                               status = S_IN_ERROR;
+                                               throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                                       }
+                       
+                               case S_IN_OBJECT:
+                                       nextToken();
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COMMA:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               if(token.value instanceof String){
+                                                       String key=(String)token.value;
+                                                       status=S_PASSED_PAIR_KEY;
+                                                       statusStack.addFirst(new Integer(status));
+                                                       if(!contentHandler.startObjectEntry(key))
+                                                               return;
+                                               }
+                                               else{
+                                                       status=S_IN_ERROR;
+                                               }
+                                               break;
+                                       case Yytoken.TYPE_RIGHT_BRACE:
+                                               if(statusStack.size()>1){
+                                                       statusStack.removeFirst();
+                                                       status=peekStatus(statusStack);
+                                               }
+                                               else{
+                                                       status=S_IN_FINISHED_VALUE;
+                                               }
+                                               if(!contentHandler.endObject())
+                                                       return;
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                               break;
+                                       }//inner switch
+                                       break;
+                                       
+                               case S_PASSED_PAIR_KEY:
+                                       nextToken();
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COLON:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               statusStack.removeFirst();
+                                               status=peekStatus(statusStack);
+                                               if(!contentHandler.primitive(token.value))
+                                                       return;
+                                               if(!contentHandler.endObjectEntry())
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               statusStack.removeFirst();
+                                               statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startArray())
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               statusStack.removeFirst();
+                                               statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startObject())
+                                                       return;
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }
+                                       break;
+                               
+                               case S_IN_PAIR_VALUE:
+                                       /*
+                                        * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
+                                        * therefore delay consuming token until next round.
+                                        */
+                                       statusStack.removeFirst();
+                                       status = peekStatus(statusStack);
+                                       if(!contentHandler.endObjectEntry())
+                                               return;
+                                       break;
+                                       
+                               case S_IN_ARRAY:
+                                       nextToken();
+                                       switch(token.type){
+                                       case Yytoken.TYPE_COMMA:
+                                               break;
+                                       case Yytoken.TYPE_VALUE:
+                                               if(!contentHandler.primitive(token.value))
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_RIGHT_SQUARE:
+                                               if(statusStack.size()>1){
+                                                       statusStack.removeFirst();
+                                                       status=peekStatus(statusStack);
+                                               }
+                                               else{
+                                                       status=S_IN_FINISHED_VALUE;
+                                               }
+                                               if(!contentHandler.endArray())
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_BRACE:
+                                               status=S_IN_OBJECT;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startObject())
+                                                       return;
+                                               break;
+                                       case Yytoken.TYPE_LEFT_SQUARE:
+                                               status=S_IN_ARRAY;
+                                               statusStack.addFirst(new Integer(status));
+                                               if(!contentHandler.startArray())
+                                                       return;
+                                               break;
+                                       default:
+                                               status=S_IN_ERROR;
+                                       }//inner switch
+                                       break;
+                                       
+                               case S_END:
+                                       return;
+                                       
+                               case S_IN_ERROR:
+                                       throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                               }//switch
+                               if(status==S_IN_ERROR){
+                                       throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+                               }
+                       }while(token.type!=Yytoken.TYPE_EOF);
+               }
+               catch(IOException ie){
+                       status = S_IN_ERROR;
+                       throw ie;
+               }
+               catch(ParseException pe){
+                       status = S_IN_ERROR;
+                       throw pe;
+               }
+               catch(RuntimeException re){
+                       status = S_IN_ERROR;
+                       throw re;
+               }
+               catch(Error e){
+                       status = S_IN_ERROR;
+                       throw e;
+               }
+               
+               status = S_IN_ERROR;
+               throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
+       }
+}