content: /*
   * Copyright 1999-2101 Alibaba Group.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.alibaba.fastjson.parser;
  
  import static com.alibaba.fastjson.parser.JSONScanner.EOI;
  import static com.alibaba.fastjson.parser.JSONToken.EOF;
  import static com.alibaba.fastjson.parser.JSONToken.ERROR;
  import static com.alibaba.fastjson.parser.JSONToken.FALSE;
  import static com.alibaba.fastjson.parser.JSONToken.LBRACE;
  import static com.alibaba.fastjson.parser.JSONToken.LBRACKET;
  import static com.alibaba.fastjson.parser.JSONToken.LITERAL_FLOAT;
  import static com.alibaba.fastjson.parser.JSONToken.LITERAL_INT;
  import static com.alibaba.fastjson.parser.JSONToken.LITERAL_STRING;
  import static com.alibaba.fastjson.parser.JSONToken.NEW;
  import static com.alibaba.fastjson.parser.JSONToken.NULL;
  import static com.alibaba.fastjson.parser.JSONToken.RBRACKET;
  import static com.alibaba.fastjson.parser.JSONToken.SET;
  import static com.alibaba.fastjson.parser.JSONToken.TREE_SET;
  import static com.alibaba.fastjson.parser.JSONToken.TRUE;
  
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.lang.reflect.TypeVariable;
  import java.lang.reflect.WildcardType;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.TreeSet;
  
  import com.alibaba.fastjson.JSON;
  import com.alibaba.fastjson.JSONArray;
  import com.alibaba.fastjson.JSONException;
  import com.alibaba.fastjson.JSONObject;
  import com.alibaba.fastjson.parser.deserializer.DefaultObjectDeserializer;
  import com.alibaba.fastjson.parser.deserializer.FieldDeserializer;
  import com.alibaba.fastjson.parser.deserializer.IntegerDeserializer;
  import com.alibaba.fastjson.parser.deserializer.ListResolveFieldDeserializer;
  import com.alibaba.fastjson.parser.deserializer.MapResolveFieldDeserializer;
  import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
  import com.alibaba.fastjson.parser.deserializer.StringDeserializer;
  import com.alibaba.fastjson.util.TypeUtils;
  
  /**
   * @author wenshao<szujobs@hotmail.com>
   */
  public class DefaultJSONParser extends AbstractJSONParser {
  
      protected final Object             input;
      protected final SymbolTable        symbolTable;
      protected ParserConfig             config;
  
      private DefaultObjectDeserializer  derializer        = new DefaultObjectDeserializer();
  
      private final static Set<Class<?>> primitiveClasses  = new HashSet<Class<?>>();
  
      private String                     dateFormatPattern = JSON.DEFFAULT_DATE_FORMAT;
      private DateFormat                 dateFormat;
  
      protected final JSONLexer          lexer;
  
      protected ParseContext             context;
  
      private ParseContext[]             contextArray      = new ParseContext[8];
      private int                        contextArrayIndex = 0;
  
      private final List<ResolveTask>    resolveTaskList   = new ArrayList<ResolveTask>();
  
      public final static int            NONE              = 0;
      public final static int            NeedToResolve     = 1;
      public final static int            TypeNameRedirect  = 2;
  
      private int                        resolveStatus     = NONE;
  
      static {
          primitiveClasses.add(boolean.class);
          primitiveClasses.add(byte.class);
          primitiveClasses.add(short.class);
          primitiveClasses.add(int.class);
          primitiveClasses.add(long.class);
          primitiveClasses.add(float.class);
          primitiveClasses.add(double.class);
  
          primitiveClasses.add(Boolean.class);
          primitiveClasses.add(Byte.class);
          primitiveClasses.add(Short.class);
          primitiveClasses.add(Integer.class);
          primitiveClasses.add(Long.class);
          primitiveClasses.add(Float.class);
          primitiveClasses.add(Double.class);
  
          primitiveClasses.add(BigInteger.class);
          primitiveClasses.add(BigDecimal.class);
          primitiveClasses.add(String.class);
      }
  
      public String getDateFomartPattern() {
          return dateFormatPattern;
      }
  
      public DateFormat getDateFormat() {
          if (dateFormat == null) {
              dateFormat = new SimpleDateFormat(dateFormatPattern);
          }
          return dateFormat;
      }
  
      public void setDateFormat(String dateFormat) {
          this.dateFormatPattern = dateFormat;
          this.dateFormat = null;
      }
  
      public void setDateFomrat(DateFormat dateFormat) {
          this.dateFormat = dateFormat;
      }
  
      public DefaultJSONParser(String input){
          this(input, ParserConfig.getGlobalInstance(), JSON.DEFAULT_PARSER_FEATURE);
      }
  
      public DefaultJSONParser(final String input, final ParserConfig config){
          this(input, new JSONScanner(input, JSON.DEFAULT_PARSER_FEATURE), config);
      }
  
      public DefaultJSONParser(final String input, final ParserConfig config, int features){
          this(input, new JSONScanner(input, features), config);
      }
  
      public DefaultJSONParser(final char[] input, int length, final ParserConfig config, int features){
          this(input, new JSONScanner(input, length, features), config);
      }
  
      public DefaultJSONParser(final Object input, final JSONLexer lexer, final ParserConfig config){
          this.lexer = lexer;
          this.input = input;
          this.config = config;
          this.symbolTable = config.getSymbolTable();
  
          lexer.nextToken(JSONToken.LBRACE); // prime the pump
      }
  
      public SymbolTable getSymbolTable() {
          return symbolTable;
      }
  
      public String getInput() {
          if (input instanceof char[]) {
              return new String((char[]) input);
          }
          return input.toString();
      }
  
      @SuppressWarnings({ "unchecked", "rawtypes" })
      public final Object parseObject(final Map object, Object fieldName) {
          JSONScanner lexer = (JSONScanner) this.lexer;
  
          if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
              throw new JSONException("syntax error, expect {, actual " + lexer.tokenName());
          }
  
          ParseContext context = this.getContext();
          try {
              boolean setContextFlag = false;
              for (;;) {
                  lexer.skipWhitespace();
                  char ch = lexer.getCurrent();
                  if (isEnabled(Feature.AllowArbitraryCommas)) {
                      while (ch == ',') {
                          lexer.incrementBufferPosition();
                          lexer.skipWhitespace();
                          ch = lexer.getCurrent();
                      }
                  }
  
                  boolean isObjectKey = false;
                  Object key;
                  if (ch == '"') {
                      key = lexer.scanSymbol(symbolTable, '"');
                      lexer.skipWhitespace();
                      ch = lexer.getCurrent();
                      if (ch != ':') {
                          throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
                      }
                  } else if (ch == '}') {
                      lexer.incrementBufferPosition();
                      lexer.resetStringPosition();
                      lexer.nextToken();
                      return object;
                  } else if (ch == '\'') {
                      if (!isEnabled(Feature.AllowSingleQuotes)) {
                          throw new JSONException("syntax error");
                      }
  
                      key = lexer.scanSymbol(symbolTable, '\'');
                      lexer.skipWhitespace();
                      ch = lexer.getCurrent();
                      if (ch != ':') {
                          throw new JSONException("expect ':' at " + lexer.pos());
                      }
                  } else if (ch == EOI) {
                      throw new JSONException("syntax error");
                  } else if (ch == ',') {
                      throw new JSONException("syntax error");
                  } else if ((ch >= '0' && ch <= '9') || ch == '-') {
                      lexer.resetStringPosition();
                      lexer.scanNumber();
                      if (lexer.token() == JSONToken.LITERAL_INT) {
                          key = lexer.integerValue();
                      } else {
                          key = lexer.decimalValue(true);
                      }
                      ch = lexer.getCurrent();
                      if (ch != ':') {
                          throw new JSONException("expect ':' at " + lexer.pos() + ", name " + key);
                      }
                  } else if (ch == '{' || ch == '[') {
                      lexer.nextToken();
                      key = parse();
                      isObjectKey = true;
                  } else {
                      if (!isEnabled(Feature.AllowUnQuotedFieldNames)) {
                          throw new JSONException("syntax error");
                      }
  
                      key = lexer.scanSymbolUnQuoted(symbolTable);
                      lexer.skipWhitespace();
                      ch = lexer.getCurrent();
                      if (ch != ':') {
                          throw new JSONException("expect ':' at " + lexer.pos() + ", actual " + ch);
                      }
                  }
  
                  if (!isObjectKey) {
                      lexer.incrementBufferPosition();
                      lexer.skipWhitespace();
                  }
  
                  ch = lexer.getCurrent();
  
                  lexer.resetStringPosition();
  
                  if (key == "@type") {
                      String typeName = lexer.scanSymbol(symbolTable, '"');
                      Class<?> clazz = TypeUtils.loadClass(typeName);
  
                      if (clazz == null) {
                          object.put("@type", typeName);
                          continue;
                      }
  
                      lexer.nextToken(JSONToken.COMMA);
                      if (lexer.token() == JSONToken.RBRACE) {
                          lexer.nextToken(JSONToken.COMMA);
                          try {
                              return clazz.newInstance();
                          } catch (Exception e) {
                              throw new JSONException("create instance error", e);
                          }
                      }
  
                      this.setResolveStatus(TypeNameRedirect);
  
                      if (this.context != null && !(fieldName instanceof Integer)) {
                          this.popContext();
                      }
  
                      ObjectDeserializer deserializer = config.getDeserializer(clazz);
                      return deserializer.deserialze(this, clazz, fieldName);
                  }
                  
                  if (key == "$ref") {
                      lexer.nextToken(JSONToken.LITERAL_STRING);
                      if (lexer.token() == JSONToken.LITERAL_STRING) {
                          String ref = lexer.stringVal();
                          lexer.nextToken(JSONToken.RBRACE);
  
                          Object refValue = null;
                          if ("@".equals(ref)) {
                              if (this.getContext() != null) {
                                  refValue = this.getContext().getObject();
                              }
                          } else if ("..".equals(ref)) {
                              ParseContext parentContext = context.getParentContext();
                              if (parentContext.getObject() != null) {
                                  refValue = this.getContext().getObject();
                              } else {
                                  addResolveTask(new ResolveTask(parentContext, ref));
                                  setResolveStatus(DefaultJSONParser.NeedToResolve);
                              }
                          } else if ("$".equals(ref)) {
                              ParseContext rootContext = context;
                              while (rootContext.getParentContext() != null) {
                                  rootContext = rootContext.getParentContext();
                              }
  
                              if (rootContext.getObject() != null) {
                                  refValue = rootContext.getObject();
                              } else {
                                  addResolveTask(new ResolveTask(rootContext, ref));
                                  setResolveStatus(DefaultJSONParser.NeedToResolve);
                              }
                          } else {
                              addResolveTask(new ResolveTask(context, ref));
                              setResolveStatus(DefaultJSONParser.NeedToResolve);
                          }
  
                          if (lexer.token() != JSONToken.RBRACE) {
                              throw new JSONException("syntax error");
                          }
                          lexer.nextToken(JSONToken.COMMA);
  
                          return refValue;
                      } else {
                          throw new JSONException("illegal ref, " + JSONToken.name(lexer.token()));
                      }
                  }
                  
                  if (!setContextFlag) {
                      setContext(object, fieldName);
                      setContextFlag = true;
                  }
  
                  Object value;
                  if (ch == '"') {
                      lexer.scanString();
                      String strValue = lexer.stringVal();
                      value = strValue;
  
                      if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
                          JSONScanner iso8601Lexer = new JSONScanner(strValue);
                          if (iso8601Lexer.scanISO8601DateIfMatch()) {
                              value = iso8601Lexer.getCalendar().getTime();
                          }
                      }
  
                      if (object.getClass() == JSONObject.class) {
                          object.put(key.toString(), value);
                      } else {
                          object.put(key, value);
                      }
                  } else if (ch >= '0' && ch <= '9' || ch == '-') {
                      lexer.scanNumber();
                      if (lexer.token() == JSONToken.LITERAL_INT) {
                          value = lexer.integerValue();
                      } else {
                          value = lexer.decimalValue();
                      }
  
                      object.put(key, value);
                  } else if (ch == '[') { // 减少潜套，兼容android
                      lexer.nextToken();
                      JSONArray list = new JSONArray();
                      this.parseArray(list, key);
                      value = list;
                      object.put(key, value);
  
                      if (lexer.token() == JSONToken.RBRACE) {
                          lexer.nextToken();
                          return object;
                      } else if (lexer.token() == JSONToken.COMMA) {
                          continue;
                      } else {
                          throw new JSONException("syntax error");
                      }
                  } else if (ch == '{') { // 减少潜套，兼容android
                      lexer.nextToken();
                      Object obj = this.parseObject(new JSONObject(), key);
                      checkMapResolve(object, key.toString());
  
                      if (object.getClass() == JSONObject.class) {
                          object.put(key.toString(), obj);
                      } else {
                          object.put(key, obj);
                      }
  
                      setContext(context, obj, key);
  
                      if (lexer.token() == JSONToken.RBRACE) {
                          lexer.nextToken();
  
                          setContext(context);
                          return object;
                      } else if (lexer.token() == JSONToken.COMMA) {
                          continue;
                      } else {
                          throw new JSONException("syntax error, " + lexer.tokenName());
                      }
                  } else {
                      lexer.nextToken();
                      value = parse();
                      object.put(key, value);
  
                      if (lexer.token() == JSONToken.RBRACE) {
                          lexer.nextToken();
                          return object;
                      } else if (lexer.token() == JSONToken.COMMA) {
                          continue;
                      } else {
                          throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
                      }
                  }
  
                  lexer.skipWhitespace();
                  ch = lexer.getCurrent();
                  if (ch == ',') {
                      lexer.incrementBufferPosition();
                      continue;
                  } else if (ch == '}') {
                      lexer.incrementBufferPosition();
                      lexer.resetStringPosition();
                      lexer.nextToken();
  
                      this.setContext(object, fieldName);
  
                      return object;
                  } else {
                      throw new JSONException("syntax error, position at " + lexer.pos() + ", name " + key);
                  }
  
              }
          } finally {
              this.setContext(context);
          }
  
      }
  
      public ParserConfig getConfig() {
          return config;
      }
  
      public void setConfig(ParserConfig config) {
          this.config = config;
      }
  
      // compatible
      @SuppressWarnings("unchecked")
      public <T> T parseObject(Class<T> clazz) {
          return (T) parseObject((Type) clazz);
      }
  
      @SuppressWarnings("unchecked")
      public <T> T parseObject(Type type) {
          if (lexer.token() == JSONToken.NULL) {
              lexer.nextToken();
              return null;
          }
  
          ObjectDeserializer derializer = config.getDeserializer(type);
  
          try {
              return (T) derializer.deserialze(this, type, null);
          } catch (JSONException e) {
              throw e;
          } catch (Throwable e) {
              throw new JSONException(e.getMessage(), e);
          }
      }
  
      public <T> List<T> parseArray(Class<T> clazz) {
          List<T> array = new ArrayList<T>();
          parseArray(clazz, array);
          return array;
      }
  
      public void parseArray(Class<?> clazz, @SuppressWarnings("rawtypes") Collection array) {
          parseArray((Type) clazz, array);
      }
  
      @SuppressWarnings("rawtypes")
      public void parseArray(Type type, Collection array) {
          parseArray(type, array, null);
      }
  
      @SuppressWarnings({ "unchecked", "rawtypes" })
      public void parseArray(Type type, Collection array, Object fieldName) {
          if (lexer.token() == JSONToken.SET || lexer.token() == JSONToken.TREE_SET) {
              lexer.nextToken();
          }
  
          if (lexer.token() != JSONToken.LBRACKET) {
              throw new JSONException("exepct '[', but " + JSONToken.name(lexer.token()));
          }
  
          ObjectDeserializer deserializer = null;
          if (int.class == type) {
              deserializer = IntegerDeserializer.instance;
              lexer.nextToken(JSONToken.LITERAL_INT);
          } else if (String.class == type) {
              deserializer = StringDeserializer.instance;
              lexer.nextToken(JSONToken.LITERAL_STRING);
          } else {
              deserializer = config.getDeserializer(type);
              lexer.nextToken(deserializer.getFastMatchToken());
          }
  
          ParseContext context = this.getContext();
          this.setContext(array, fieldName);
          try {
              for (int i = 0;; ++i) {
                  if (isEnabled(Feature.AllowArbitraryCommas)) {
                      while (lexer.token() == JSONToken.COMMA) {
                          lexer.nextToken();
                          continue;
                      }
                  }
  
                  if (lexer.token() == JSONToken.RBRACKET) {
                      break;
                  }
  
                  if (int.class == type) {
                      Object val = IntegerDeserializer.deserialze(this);
                      array.add(val);
                  } else if (String.class == type) {
                      String value;
                      if (lexer.token() == JSONToken.LITERAL_STRING) {
                          value = lexer.stringVal();
                          lexer.nextToken(JSONToken.COMMA);
                      } else {
                          Object obj = this.parse();
                          if (obj == null) {
                              value = null;
                          } else {
                              value = obj.toString();
                          }
                      }
  
                      array.add(value);
                  } else {
                      Object val;
                      if (lexer.token() == JSONToken.NULL) {
                          lexer.nextToken();
                          val = null;
                      } else {
                          val = deserializer.deserialze(this, type, i);
                      }
                      array.add(val);
                      checkListResolve(array);
                  }
  
                  if (lexer.token() == JSONToken.COMMA) {
                      lexer.nextToken(deserializer.getFastMatchToken());
                      continue;
                  }
              }
          } finally {
              this.setContext(context);
          }
  
          lexer.nextToken(JSONToken.COMMA);
      }
  
      public Object[] parseArray(Type[] types) {
          if (lexer.token() == JSONToken.NULL) {
              lexer.nextToken(JSONToken.COMMA);
              return null;
          }
  
          if (lexer.token() != JSONToken.LBRACKET) {
              throw new JSONException("syntax error : " + lexer.tokenName());
          }
  
          Object[] list = new Object[types.length];
          if (types.length == 0) {
              lexer.nextToken(JSONToken.RBRACKET);
  
              if (lexer.token() != JSONToken.RBRACKET) {
                  throw new JSONException("syntax error");
              }
  
              lexer.nextToken(JSONToken.COMMA);
              return new Object[0];
          }
  
          lexer.nextToken(JSONToken.LITERAL_INT);
  
          for (int i = 0; i < types.length; ++i) {
              Object value;
  
              if (lexer.token() == JSONToken.NULL) {
                  value = null;
                  lexer.nextToken(JSONToken.COMMA);
              } else {
                  Type type = types[i];
                  if (type == int.class || type == Integer.class) {
                      if (lexer.token() == JSONToken.LITERAL_INT) {
                          value = Integer.valueOf(lexer.intValue());
                          lexer.nextToken(JSONToken.COMMA);
                      } else {
                          value = this.parse();
                          value = TypeUtils.cast(value, type, config);
                      }
                  } else if (type == String.class) {
                      if (lexer.token() == JSONToken.LITERAL_STRING) {
                          value = lexer.stringVal();
                          lexer.nextToken(JSONToken.COMMA);
                      } else {
                          value = this.parse();
                          value = TypeUtils.cast(value, type, config);
                      }
                  } else {
                      boolean isArray = false;
                      Class<?> componentType = null;
                      if (i == types.length - 1) {
                          if (type instanceof Class) {
                              Class<?> clazz = (Class<?>) type;
                              isArray = clazz.isArray();
                              componentType = clazz.getComponentType();
                          }
                      }
  
                      // support varArgs
                      if (isArray && lexer.token() != JSONToken.LBRACKET) {
                          List<Object> varList = new ArrayList<Object>();
  
                          ObjectDeserializer derializer = config.getDeserializer(componentType);
                          int fastMatch = derializer.getFastMatchToken();
  
                          if (lexer.token() != JSONToken.RBRACKET) {
                              for (;;) {
                                  Object item = derializer.deserialze(this, type, null);
                                  varList.add(item);
  
                                  if (lexer.token() == JSONToken.COMMA) {
                                      lexer.nextToken(fastMatch);
                                  } else if (lexer.token() == JSONToken.RBRACKET) {
                                      break;
                                  } else {
                                      throw new JSONException("syntax error :" + JSONToken.name(lexer.token()));
                                  }
                              }
                          }
  
                          value = TypeUtils.cast(varList, type, config);
                      } else {
                          ObjectDeserializer derializer = config.getDeserializer(type);
                          value = derializer.deserialze(this, type, null);
                      }
                  }
              }
              list[i] = value;
  
              if (lexer.token() == JSONToken.RBRACKET) {
                  break;
              }
  
              if (lexer.token() != JSONToken.COMMA) {
                  throw new JSONException("syntax error :" + JSONToken.name(lexer.token()));
              }
  
              if (i == types.length - 1) {
                  lexer.nextToken(JSONToken.RBRACKET);
              } else {
                  lexer.nextToken(JSONToken.LITERAL_INT);
              }
          }
  
          if (lexer.token() != JSONToken.RBRACKET) {
              throw new JSONException("syntax error");
          }
  
          lexer.nextToken(JSONToken.COMMA);
  
          return list;
      }
  
      public void parseObject(Object object) {
          derializer.parseObject(this, object);
      }
  
      public Object parseArrayWithType(Type collectionType) {
          if (lexer.token() == JSONToken.NULL) {
              lexer.nextToken();
              return null;
          }
  
          Type[] actualTypes = ((ParameterizedType) collectionType).getActualTypeArguments();
  
          if (actualTypes.length != 1) {
              throw new JSONException("not support type " + collectionType);
          }
  
          Type actualTypeArgument = actualTypes[0];
  
          if (actualTypeArgument instanceof Class) {
              List<Object> array = new ArrayList<Object>();
              this.parseArray((Class<?>) actualTypeArgument, array);
              return array;
          }
  
          if (actualTypeArgument instanceof WildcardType) {
              WildcardType wildcardType = (WildcardType) actualTypeArgument;
  
              // assert wildcardType.getUpperBounds().length == 1;
              Type upperBoundType = wildcardType.getUpperBounds()[0];
  
              // assert upperBoundType instanceof Class;
              if (Object.class.equals(upperBoundType)) {
                  if (wildcardType.getLowerBounds().length == 0) {
                      // Collection<?>
                      return parse();
                  } else {
                      throw new JSONException("not support type : " + collectionType);
                  }
              }
  
              List<Object> array = new ArrayList<Object>();
              this.parseArray((Class<?>) upperBoundType, array);
              return array;
  
              // throw new JSONException("not support type : " +
              // collectionType);return parse();
          }
  
          if (actualTypeArgument instanceof TypeVariable) {
              TypeVariable<?> typeVariable = (TypeVariable<?>) actualTypeArgument;
              Type[] bounds = typeVariable.getBounds();
  
              if (bounds.length != 1) {
                  throw new JSONException("not support : " + typeVariable);
              }
  
              Type boundType = bounds[0];
              if (boundType instanceof Class) {
                  List<Object> array = new ArrayList<Object>();
                  this.parseArray((Class<?>) boundType, array);
                  return array;
              }
          }
  
          if (actualTypeArgument instanceof ParameterizedType) {
              ParameterizedType parameterizedType = (ParameterizedType) actualTypeArgument;
  
              List<Object> array = new ArrayList<Object>();
              this.parseArray(parameterizedType, array);
              return array;
          }
  
          throw new JSONException("TODO : " + collectionType);
      }
  
      public void acceptType(String typeName) {
          JSONScanner lexer = (JSONScanner) this.lexer;
  
          lexer.nextTokenWithColon();
  
          if (lexer.token() != JSONToken.LITERAL_STRING) {
              throw new JSONException("type not match error");
          }
  
          if (typeName.equals(lexer.stringVal())) {
              lexer.nextToken();
              if (lexer.token() == JSONToken.COMMA) {
                  lexer.nextToken();
              }
          } else {
              throw new JSONException("type not match error");
          }
      }
  
      public int getResolveStatus() {
          return resolveStatus;
      }
  
      public void setResolveStatus(int resolveStatus) {
          this.resolveStatus = resolveStatus;
      }
  
      public Object getObject(String path) {
          for (int i = 0; i < contextArrayIndex; ++i) {
              if (path.equals(contextArray[i].getPath())) {
                  return contextArray[i].getObject();
              }
          }
  
          return null;
      }
  
      @SuppressWarnings("rawtypes")
      public void checkListResolve(Collection array) {
          if (resolveStatus == NeedToResolve) {
              final int index = array.size() - 1;
              final List list = (List) array;
              ResolveTask task = getLastResolveTask();
              task.setFieldDeserializer(new ListResolveFieldDeserializer(this, list, index));
              task.setOwnerContext(context);
              setResolveStatus(DefaultJSONParser.NONE);
          }
      }
  
      @SuppressWarnings("rawtypes")
      public void checkMapResolve(Map object, String fieldName) {
          if (resolveStatus == NeedToResolve) {
              MapResolveFieldDeserializer fieldResolver = new MapResolveFieldDeserializer(object, fieldName);
              ResolveTask task = getLastResolveTask();
              task.setFieldDeserializer(fieldResolver);
              task.setOwnerContext(context);
              setResolveStatus(DefaultJSONParser.NONE);
          }
      }
  
      @SuppressWarnings("rawtypes")
      public Object parseObject(final Map object) {
          return parseObject(object, null);
      }
  
      public JSONObject parseObject() {
          JSONObject object = new JSONObject();
          parseObject(object);
          return object;
      }
  
      @SuppressWarnings("rawtypes")
      public final void parseArray(final Collection array) {
          parseArray(array, null);
      }
  
      @SuppressWarnings({ "unchecked", "rawtypes" })
      public final void parseArray(final Collection array, Object fieldName) {
          final JSONLexer lexer = getLexer();
  
          if (lexer.token() == JSONToken.SET || lexer.token() == JSONToken.TREE_SET) {
              lexer.nextToken();
          }
  
          if (lexer.token() != JSONToken.LBRACKET) {
              throw new JSONException("syntax error, expect [, actual " + JSONToken.name(lexer.token()) + ", pos " + lexer.pos());
          }
  
          lexer.nextToken(JSONToken.LITERAL_STRING);
  
          ParseContext context = this.getContext();
          this.setContext(array, fieldName);
          try {
              for (int i = 0;; ++i) {
                  if (isEnabled(Feature.AllowArbitraryCommas)) {
                      while (lexer.token() == JSONToken.COMMA) {
                          lexer.nextToken();
                          continue;
                      }
                  }
  
                  Object value;
                  switch (lexer.token()) {
                      case LITERAL_INT:
                          value = lexer.integerValue();
                          lexer.nextToken(JSONToken.COMMA);
                          break;
                      case LITERAL_FLOAT:
                          if (lexer.isEnabled(Feature.UseBigDecimal)) {
                              value = lexer.decimalValue(true);
                          } else {
                              value = lexer.decimalValue(false);
                          }
                          lexer.nextToken(JSONToken.COMMA);
                          break;
                      case LITERAL_STRING:
                          String stringLiteral = lexer.stringVal();
                          lexer.nextToken(JSONToken.COMMA);
  
                          if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
                              JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
                              if (iso8601Lexer.scanISO8601DateIfMatch()) {
                                  value = iso8601Lexer.getCalendar().getTime();
                              } else {
                                  value = stringLiteral;
                              }
                          } else {
                              value = stringLiteral;
                          }
  
                          break;
                      case TRUE:
                          value = Boolean.TRUE;
                          lexer.nextToken(JSONToken.COMMA);
                          break;
                      case FALSE:
                          value = Boolean.FALSE;
                          lexer.nextToken(JSONToken.COMMA);
                          break;
                      case LBRACE:
                          JSONObject object = new JSONObject();
                          value = parseObject(object, i);
                          break;
                      case LBRACKET:
                          Collection items = new JSONArray();
                          parseArray(items, i);
                          value = items;
                          break;
                      case NULL:
                          value = null;
                          lexer.nextToken(JSONToken.LITERAL_STRING);
                          break;
                      case RBRACKET:
                          lexer.nextToken(JSONToken.COMMA);
                          return;
                      default:
                          value = parse();
                          break;
                  }
  
                  array.add(value);
                  checkListResolve(array);
  
                  if (lexer.token() == JSONToken.COMMA) {
                      lexer.nextToken(JSONToken.LITERAL_STRING);
                      continue;
                  }
              }
          } finally {
              this.setContext(context);
          }
      }
  
      public ParseContext getContext() {
          return context;
      }
  
      public List<ResolveTask> getResolveTaskList() {
          return resolveTaskList;
      }
  
      public void addResolveTask(ResolveTask task) {
          resolveTaskList.add(task);
      }
  
      public ResolveTask getLastResolveTask() {
          return resolveTaskList.get(resolveTaskList.size() - 1);
      }
  
      public void setContext(ParseContext context) {
          if (isEnabled(Feature.DisableCircularReferenceDetect)) {
              return;
          }
          this.context = context;
      }
  
      public void popContext() {
          if (isEnabled(Feature.DisableCircularReferenceDetect)) {
              return;
          }
  
          this.context = this.context.getParentContext();
          contextArray[contextArrayIndex - 1] = null;
          contextArrayIndex--;
      }
  
      public ParseContext setContext(Object object, Object fieldName) {
          if (isEnabled(Feature.DisableCircularReferenceDetect)) {
              return null;
          }
  
          return setContext(this.context, object, fieldName);
      }
  
      public ParseContext setContext(ParseContext parent, Object object, Object fieldName) {
          if (isEnabled(Feature.DisableCircularReferenceDetect)) {
              return null;
          }
          
          this.context = new ParseContext(parent, object, fieldName);
          addContext(this.context);
  
          return this.context;
      }
      
      public int getContextLength() {
          return contextArrayIndex;
      }
      
      public void clearContext(ParseContext context, int start) {
          for (int i = start; i < contextArrayIndex; ++i) {
              contextArray[i] = null;
          }
          contextArrayIndex = start;
          this.context = context;
      }
  
      private void addContext(ParseContext context) {
          int i = contextArrayIndex++;
          if (i >= contextArray.length) {
              int newLen = (contextArray.length * 3) / 2;
              ParseContext[] newArray = new ParseContext[newLen];
              System.arraycopy(contextArray, 0, newArray, 0, contextArray.length);
              contextArray = newArray;
          }
          contextArray[i] = context;
      }
  
      public Object parse() {
          return parse(null);
      }
  
      public Object parse(Object fieldName) {
          final JSONLexer lexer = getLexer();
          switch (lexer.token()) {
              case SET:
                  lexer.nextToken();
                  HashSet<Object> set = new HashSet<Object>();
                  parseArray(set, fieldName);
                  return set;
              case TREE_SET:
                  lexer.nextToken();
                  TreeSet<Object> treeSet = new TreeSet<Object>();
                  parseArray(treeSet, fieldName);
                  return treeSet;
              case LBRACKET:
                  JSONArray array = new JSONArray();
                  parseArray(array, fieldName);
                  return array;
              case LBRACE:
                  JSONObject object = new JSONObject();
                  return parseObject(object, fieldName);
              case LITERAL_INT:
                  Number intValue = lexer.integerValue();
                  lexer.nextToken();
                  return intValue;
              case LITERAL_FLOAT:
                  Object value = lexer.decimalValue(isEnabled(Feature.UseBigDecimal));
                  lexer.nextToken();
                  return value;
              case LITERAL_STRING:
                  String stringLiteral = lexer.stringVal();
                  lexer.nextToken(JSONToken.COMMA);
  
                  if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {
                      JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);
                      if (iso8601Lexer.scanISO8601DateIfMatch()) {
                          return iso8601Lexer.getCalendar().getTime();
                      }
                  }
  
                  return stringLiteral;
              case NULL:
                  lexer.nextToken();
                  return null;
              case TRUE:
                  lexer.nextToken();
                  return Boolean.TRUE;
              case FALSE:
                  lexer.nextToken();
                  return Boolean.FALSE;
              case NEW:
                  lexer.nextToken(JSONToken.IDENTIFIER);
  
                  if (lexer.token() != JSONToken.IDENTIFIER) {
                      throw new JSONException("syntax error");
                  }
                  lexer.nextToken(JSONToken.LPAREN);
  
                  accept(JSONToken.LPAREN);
                  long time = ((Number) lexer.integerValue()).longValue();
                  accept(JSONToken.LITERAL_INT);
  
                  accept(JSONToken.RPAREN);
  
                  return new Date(time);
              case EOF:
                  if (lexer.isBlankInput()) {
                      return null;
                  }
                  throw new JSONException("unterminated json string, pos " + lexer.getBufferPosition());
              case ERROR:
              default:
                  throw new JSONException("syntax error, pos " + lexer.getBufferPosition());
          }
      }
  
      public void config(Feature feature, boolean state) {
          getLexer().config(feature, state);
      }
  
      public boolean isEnabled(Feature feature) {
          return getLexer().isEnabled(feature);
      }
  
      public JSONLexer getLexer() {
          return lexer;
      }
  
      public final void accept(final int token) {
          final JSONLexer lexer = getLexer();
          if (lexer.token() == token) {
              lexer.nextToken();
          } else {
              throw new JSONException("syntax error, expect " + JSONToken.name(token) + ", actual "
                                      + JSONToken.name(lexer.token()));
          }
      }
  
      public void close() {
          final JSONLexer lexer = getLexer();
  
          try {
              if (isEnabled(Feature.AutoCloseSource)) {
                  if (!lexer.isEOF()) {
                      throw new JSONException("not close json text, token : " + JSONToken.name(lexer.token()));
                  }
              }
          } finally {
              lexer.close();
          }
      }
  
      public static class ResolveTask {
  
          private final ParseContext context;
          private final String       referenceValue;
          private FieldDeserializer  fieldDeserializer;
          private ParseContext       ownerContext;
  
          public ResolveTask(ParseContext context, String referenceValue){
              this.context = context;
              this.referenceValue = referenceValue;
          }
  
          public ParseContext getContext() {
              return context;
          }
  
          public String getReferenceValue() {
              return referenceValue;
          }
  
          public FieldDeserializer getFieldDeserializer() {
              return fieldDeserializer;
          }
  
          public void setFieldDeserializer(FieldDeserializer fieldDeserializer) {
              this.fieldDeserializer = fieldDeserializer;
          }
  
          public ParseContext getOwnerContext() {
              return ownerContext;
          }
  
          public void setOwnerContext(ParseContext ownerContext) {
              this.ownerContext = ownerContext;
          }
  
      }
  
  }
  