srcjar changes for JSONParser - just 'c' |'c' workaround (not necessary
[jalview.git] / src / org / json / simple / parser / JSONParser.java
1 /*
2  * $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
3  * Created on 2006-4-15
4  */
5 package org.json.simple.parser;
6
7 import java.io.IOException;
8 import java.io.Reader;
9 import java.io.StringReader;
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.Map;
13
14 import org.json.simple.JSONArray;
15 import org.json.simple.JSONObject;
16
17 /**
18  * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
19  * 
20  * @author FangYidong<fangyidong@yahoo.com.cn>
21  */
22 public class JSONParser
23 {
24   public static final int S_INIT = 0;
25
26   public static final int S_IN_FINISHED_VALUE = 1;// string,number,boolean,null,object,array
27
28   public static final int S_IN_OBJECT = 2;
29
30   public static final int S_IN_ARRAY = 3;
31
32   public static final int S_PASSED_PAIR_KEY = 4;
33
34   public static final int S_IN_PAIR_VALUE = 5;
35
36   public static final int S_END = 6;
37
38   public static final int S_IN_ERROR = -1;
39
40   private LinkedList handlerStatusStack;
41
42   private Yylex lexer = new Yylex((Reader) null);
43
44   private Yytoken token = null;
45
46   private int status = S_INIT;
47
48   private int peekStatus(LinkedList statusStack)
49   {
50     if (statusStack.size() == 0)
51       return -1;
52     Integer status = (Integer) statusStack.getFirst();
53     return status.intValue();
54   }
55
56   /**
57    * Reset the parser to the initial state without resetting the underlying
58    * reader.
59    *
60    */
61   public void reset()
62   {
63     token = null;
64     status = S_INIT;
65     handlerStatusStack = null;
66   }
67
68   /**
69    * Reset the parser to the initial state with a new character reader.
70    * 
71    * @param in
72    *          - The new character reader.
73    * @throws IOException
74    * @throws ParseException
75    */
76   public void reset(Reader in)
77   {
78     lexer.yyreset(in);
79     reset();
80   }
81
82   /**
83    * @return The position of the beginning of the current token.
84    */
85   public int getPosition()
86   {
87     return lexer.getPosition();
88   }
89
90   public Object parse(String s) throws ParseException
91   {
92     return parse(s, (ContainerFactory) null);
93   }
94
95   public Object parse(String s, ContainerFactory containerFactory)
96           throws ParseException
97   {
98     StringReader in = new StringReader(s);
99     try
100     {
101       return parse(in, containerFactory);
102     } catch (IOException ie)
103     {
104       /*
105        * Actually it will never happen.
106        */
107       throw new ParseException(-1,
108               ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
109     }
110   }
111
112   public Object parse(Reader in) throws IOException, ParseException
113   {
114     return parse(in, (ContainerFactory) null);
115   }
116
117   /**
118    * Parse JSON text into java object from the input source.
119    * 
120    * @param in
121    * @param containerFactory
122    *          - Use this factory to createyour own JSON object and JSON array
123    *          containers.
124    * @return Instance of the following: org.json.simple.JSONObject,
125    *         org.json.simple.JSONArray, java.lang.String, java.lang.Number,
126    *         java.lang.Boolean, null
127    * 
128    * @throws IOException
129    * @throws ParseException
130    */
131   public Object parse(Reader in, ContainerFactory containerFactory)
132           throws IOException, ParseException
133   {
134     reset(in);
135     LinkedList statusStack = new LinkedList();
136     LinkedList valueStack = new LinkedList();
137
138     try
139     {
140       do
141       {
142         nextToken();
143         switch (status)
144         {
145         case S_INIT:
146           switch (token.type)
147           {
148           case Yytoken.TYPE_VALUE:
149             status = S_IN_FINISHED_VALUE;
150             statusStack.addFirst(new Integer(status));
151             valueStack.addFirst(token.value);
152             break;
153           case Yytoken.TYPE_LEFT_BRACE:
154             status = S_IN_OBJECT;
155             statusStack.addFirst(new Integer(status));
156             valueStack.addFirst(createObjectContainer(containerFactory));
157             break;
158           case Yytoken.TYPE_LEFT_SQUARE:
159             status = S_IN_ARRAY;
160             statusStack.addFirst(new Integer(status));
161             valueStack.addFirst(createArrayContainer(containerFactory));
162             break;
163           default:
164             status = S_IN_ERROR;
165           }// inner switch
166           break;
167
168         case S_IN_FINISHED_VALUE:
169           if (token.type == Yytoken.TYPE_EOF)
170             return valueStack.removeFirst();
171           else
172             throw new ParseException(getPosition(),
173                     ParseException.ERROR_UNEXPECTED_TOKEN, token);
174
175         case S_IN_OBJECT:
176           switch (token.type)
177           {
178           case Yytoken.TYPE_COMMA:
179             break;
180           case Yytoken.TYPE_VALUE:
181             if (token.value instanceof String)
182             {
183               String key = (String) token.value;
184               valueStack.addFirst(key);
185               status = S_PASSED_PAIR_KEY;
186               statusStack.addFirst(new Integer(status));
187             }
188             else
189             {
190               status = S_IN_ERROR;
191             }
192             break;
193           case Yytoken.TYPE_RIGHT_BRACE:
194             if (valueStack.size() > 1)
195             {
196               statusStack.removeFirst();
197               valueStack.removeFirst();
198               status = peekStatus(statusStack);
199             }
200             else
201             {
202               status = S_IN_FINISHED_VALUE;
203             }
204             break;
205           default:
206             status = S_IN_ERROR;
207             break;
208           }// inner switch
209           break;
210
211         case S_PASSED_PAIR_KEY:
212           switch (token.type)
213           {
214           case Yytoken.TYPE_COLON:
215             break;
216           case Yytoken.TYPE_VALUE:
217             statusStack.removeFirst();
218             String key = (String) valueStack.removeFirst();
219             Map parent = (Map) valueStack.getFirst();
220             parent.put(key, token.value);
221             status = peekStatus(statusStack);
222             break;
223           case Yytoken.TYPE_LEFT_SQUARE:
224             statusStack.removeFirst();
225             key = (String) valueStack.removeFirst();
226             parent = (Map) valueStack.getFirst();
227             List newArray = createArrayContainer(containerFactory);
228             parent.put(key, newArray);
229             status = S_IN_ARRAY;
230             statusStack.addFirst(new Integer(status));
231             valueStack.addFirst(newArray);
232             break;
233           case Yytoken.TYPE_LEFT_BRACE:
234             statusStack.removeFirst();
235             key = (String) valueStack.removeFirst();
236             parent = (Map) valueStack.getFirst();
237             Map newObject = createObjectContainer(containerFactory);
238             parent.put(key, newObject);
239             status = S_IN_OBJECT;
240             statusStack.addFirst(new Integer(status));
241             valueStack.addFirst(newObject);
242             break;
243           default:
244             status = S_IN_ERROR;
245           }
246           break;
247
248         case S_IN_ARRAY:
249           switch (token.type)
250           {
251           case Yytoken.TYPE_COMMA:
252             break;
253           case Yytoken.TYPE_VALUE:
254             List val = (List) valueStack.getFirst();
255             val.add(token.value);
256             break;
257           case Yytoken.TYPE_RIGHT_SQUARE:
258             if (valueStack.size() > 1)
259             {
260               statusStack.removeFirst();
261               valueStack.removeFirst();
262               status = peekStatus(statusStack);
263             }
264             else
265             {
266               status = S_IN_FINISHED_VALUE;
267             }
268             break;
269           case Yytoken.TYPE_LEFT_BRACE:
270             val = (List) valueStack.getFirst();
271             Map newObject = createObjectContainer(containerFactory);
272             val.add(newObject);
273             status = S_IN_OBJECT;
274             statusStack.addFirst(new Integer(status));
275             valueStack.addFirst(newObject);
276             break;
277           case Yytoken.TYPE_LEFT_SQUARE:
278             val = (List) valueStack.getFirst();
279             List newArray = createArrayContainer(containerFactory);
280             val.add(newArray);
281             status = S_IN_ARRAY;
282             statusStack.addFirst(new Integer(status));
283             valueStack.addFirst(newArray);
284             break;
285           default:
286             status = S_IN_ERROR;
287           }// inner switch
288           break;
289         case S_IN_ERROR:
290           throw new ParseException(getPosition(),
291                   ParseException.ERROR_UNEXPECTED_TOKEN, token);
292         }// switch
293         if (status == S_IN_ERROR)
294         {
295           throw new ParseException(getPosition(),
296                   ParseException.ERROR_UNEXPECTED_TOKEN, token);
297         }
298       } while (token.type != Yytoken.TYPE_EOF);
299     } catch (IOException ie)
300     {
301       throw ie;
302     }
303
304     throw new ParseException(getPosition(),
305             ParseException.ERROR_UNEXPECTED_TOKEN, token);
306   }
307
308   private void nextToken() throws ParseException, IOException
309   {
310     token = lexer.yylex();
311     if (token == null)
312       token = new Yytoken(Yytoken.TYPE_EOF, null);
313   }
314
315   private Map createObjectContainer(ContainerFactory containerFactory)
316   {
317     if (containerFactory == null)
318       return new JSONObject();
319     Map m = containerFactory.createObjectContainer();
320
321     if (m == null)
322       return new JSONObject();
323     return m;
324   }
325
326   private List createArrayContainer(ContainerFactory containerFactory)
327   {
328     if (containerFactory == null)
329       return new JSONArray();
330     List l = containerFactory.creatArrayContainer();
331
332     if (l == null)
333       return new JSONArray();
334     return l;
335   }
336
337   public void parse(String s, ContentHandler contentHandler)
338           throws ParseException
339   {
340     parse(s, contentHandler, false);
341   }
342
343   public void parse(String s, ContentHandler contentHandler,
344           boolean isResume) throws ParseException
345   {
346     StringReader in = new StringReader(s);
347     try
348     {
349       parse(in, contentHandler, isResume);
350     } catch (IOException ie)
351     {
352       /*
353        * Actually it will never happen.
354        */
355       throw new ParseException(-1,
356               ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
357     }
358   }
359
360   public void parse(Reader in, ContentHandler contentHandler)
361           throws IOException, ParseException
362   {
363     parse(in, contentHandler, false);
364   }
365
366   /**
367    * Stream processing of JSON text.
368    * 
369    * @see ContentHandler
370    * 
371    * @param in
372    * @param contentHandler
373    * @param isResume
374    *          - Indicates if it continues previous parsing operation. If set to
375    *          true, resume parsing the old stream, and parameter 'in' will be
376    *          ignored. If this method is called for the first time in this
377    *          instance, isResume will be ignored.
378    * 
379    * @throws IOException
380    * @throws ParseException
381    */
382   public void parse(Reader in, ContentHandler contentHandler,
383           boolean isResume) throws IOException, ParseException
384   {
385     if (!isResume)
386     {
387       reset(in);
388       handlerStatusStack = new LinkedList();
389     }
390     else
391     {
392       if (handlerStatusStack == null)
393       {
394         isResume = false;
395         reset(in);
396         handlerStatusStack = new LinkedList();
397       }
398     }
399
400     LinkedList statusStack = handlerStatusStack;
401
402     try
403     {
404       do
405       {
406         switch (status)
407         {
408         case S_INIT:
409           contentHandler.startJSON();
410           nextToken();
411           switch (token.type)
412           {
413           case Yytoken.TYPE_VALUE:
414             status = S_IN_FINISHED_VALUE;
415             statusStack.addFirst(new Integer(status));
416             if (!contentHandler.primitive(token.value))
417               return;
418             break;
419           case Yytoken.TYPE_LEFT_BRACE:
420             status = S_IN_OBJECT;
421             statusStack.addFirst(new Integer(status));
422             if (!contentHandler.startObject())
423               return;
424             break;
425           case Yytoken.TYPE_LEFT_SQUARE:
426             status = S_IN_ARRAY;
427             statusStack.addFirst(new Integer(status));
428             if (!contentHandler.startArray())
429               return;
430             break;
431           default:
432             status = S_IN_ERROR;
433           }// inner switch
434           break;
435
436         case S_IN_FINISHED_VALUE:
437           nextToken();
438           if (token.type == Yytoken.TYPE_EOF)
439           {
440             contentHandler.endJSON();
441             status = S_END;
442             return;
443           }
444           else
445           {
446             status = S_IN_ERROR;
447             throw new ParseException(getPosition(),
448                     ParseException.ERROR_UNEXPECTED_TOKEN, token);
449           }
450
451         case S_IN_OBJECT:
452           nextToken();
453           switch (token.type)
454           {
455           case Yytoken.TYPE_COMMA:
456             break;
457           case Yytoken.TYPE_VALUE:
458             if (token.value instanceof String)
459             {
460               String key = (String) token.value;
461               status = S_PASSED_PAIR_KEY;
462               statusStack.addFirst(new Integer(status));
463               if (!contentHandler.startObjectEntry(key))
464                 return;
465             }
466             else
467             {
468               status = S_IN_ERROR;
469             }
470             break;
471           case Yytoken.TYPE_RIGHT_BRACE:
472             if (statusStack.size() > 1)
473             {
474               statusStack.removeFirst();
475               status = peekStatus(statusStack);
476             }
477             else
478             {
479               status = S_IN_FINISHED_VALUE;
480             }
481             if (!contentHandler.endObject())
482               return;
483             break;
484           default:
485             status = S_IN_ERROR;
486             break;
487           }// inner switch
488           break;
489
490         case S_PASSED_PAIR_KEY:
491           nextToken();
492           switch (token.type)
493           {
494           case Yytoken.TYPE_COLON:
495             break;
496           case Yytoken.TYPE_VALUE:
497             statusStack.removeFirst();
498             status = peekStatus(statusStack);
499             if (!contentHandler.primitive(token.value))
500               return;
501             if (!contentHandler.endObjectEntry())
502               return;
503             break;
504           case Yytoken.TYPE_LEFT_SQUARE:
505             statusStack.removeFirst();
506             statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
507             status = S_IN_ARRAY;
508             statusStack.addFirst(new Integer(status));
509             if (!contentHandler.startArray())
510               return;
511             break;
512           case Yytoken.TYPE_LEFT_BRACE:
513             statusStack.removeFirst();
514             statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
515             status = S_IN_OBJECT;
516             statusStack.addFirst(new Integer(status));
517             if (!contentHandler.startObject())
518               return;
519             break;
520           default:
521             status = S_IN_ERROR;
522           }
523           break;
524
525         case S_IN_PAIR_VALUE:
526           /*
527            * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
528            * therefore delay consuming token until next round.
529            */
530           statusStack.removeFirst();
531           status = peekStatus(statusStack);
532           if (!contentHandler.endObjectEntry())
533             return;
534           break;
535
536         case S_IN_ARRAY:
537           nextToken();
538           switch (token.type)
539           {
540           case Yytoken.TYPE_COMMA:
541             break;
542           case Yytoken.TYPE_VALUE:
543             if (!contentHandler.primitive(token.value))
544               return;
545             break;
546           case Yytoken.TYPE_RIGHT_SQUARE:
547             if (statusStack.size() > 1)
548             {
549               statusStack.removeFirst();
550               status = peekStatus(statusStack);
551             }
552             else
553             {
554               status = S_IN_FINISHED_VALUE;
555             }
556             if (!contentHandler.endArray())
557               return;
558             break;
559           case Yytoken.TYPE_LEFT_BRACE:
560             status = S_IN_OBJECT;
561             statusStack.addFirst(new Integer(status));
562             if (!contentHandler.startObject())
563               return;
564             break;
565           case Yytoken.TYPE_LEFT_SQUARE:
566             status = S_IN_ARRAY;
567             statusStack.addFirst(new Integer(status));
568             if (!contentHandler.startArray())
569               return;
570             break;
571           default:
572             status = S_IN_ERROR;
573           }// inner switch
574           break;
575
576         case S_END:
577           return;
578
579         case S_IN_ERROR:
580           throw new ParseException(getPosition(),
581                   ParseException.ERROR_UNEXPECTED_TOKEN, token);
582         }// switch
583         if (status == S_IN_ERROR)
584         {
585           throw new ParseException(getPosition(),
586                   ParseException.ERROR_UNEXPECTED_TOKEN, token);
587         }
588       } while (token.type != Yytoken.TYPE_EOF);
589     } catch (IOException ie)
590     {
591       status = S_IN_ERROR;
592       throw ie;
593     } catch (ParseException pe)
594     {
595       status = S_IN_ERROR;
596       throw pe;
597     } catch (RuntimeException re)
598     {
599       status = S_IN_ERROR;
600       throw re;
601     } catch (Error e)
602     {
603       status = S_IN_ERROR;
604       throw e;
605     }
606
607     status = S_IN_ERROR;
608     throw new ParseException(getPosition(),
609             ParseException.ERROR_UNEXPECTED_TOKEN, token);
610   }
611 }