Beispiel #1
0
/**
 * Parse JSON string and fill tokens.
 */
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
               jsmntok_t *tokens, unsigned int num_tokens) {
    int r;
    int i;
    jsmntok_t *token;
    int count = 0;

    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
        char c;
        jsmntype_t type;

        c = js[parser->pos];
        switch (c) {
        case '{':
        case '[':
            count++;
            if (tokens == NULL) {
                break;
            }
            token = jsmn_alloc_token(parser, tokens, num_tokens);
            if (token == NULL)
                return JSMN_ERROR_NOMEM;
            if (parser->toksuper != -1) {
                tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
                token->parent = parser->toksuper;
#endif
            }
            token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
            token->start = parser->pos;
            parser->toksuper = parser->toknext - 1;
            break;
        case '}':
        case ']':
            if (tokens == NULL)
                break;
            type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
            if (parser->toknext < 1) {
                return JSMN_ERROR_INVAL;
            }
            token = &tokens[parser->toknext - 1];
            for (;;) {
                if (token->start != -1 && token->end == -1) {
                    if (token->type != type) {
                        return JSMN_ERROR_INVAL;
                    }
                    token->end = parser->pos + 1;
                    parser->toksuper = token->parent;
                    break;
                }
                if (token->parent == -1) {
                    break;
                }
                token = &tokens[token->parent];
            }
#else
            for (i = parser->toknext - 1; i >= 0; i--) {
                token = &tokens[i];
                if (token->start != -1 && token->end == -1) {
                    if (token->type != type) {
                        return JSMN_ERROR_INVAL;
                    }
                    parser->toksuper = -1;
                    token->end = parser->pos + 1;
                    break;
                }
            }
            /* Error if unmatched closing bracket */
            if (i == -1) return JSMN_ERROR_INVAL;
            for (; i >= 0; i--) {
                token = &tokens[i];
                if (token->start != -1 && token->end == -1) {
                    parser->toksuper = i;
                    break;
                }
            }
#endif
            break;
        case '\"':
            r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
            if (r < 0) return r;
            count++;
            if (parser->toksuper != -1 && tokens != NULL)
                tokens[parser->toksuper].size++;
            break;
        case '\t' :
        case '\r' :
        case '\n' :
        case ' ':
            break;
        case ':':
            parser->toksuper = parser->toknext - 1;
            break;
        case ',':
            if (tokens != NULL &&
                    tokens[parser->toksuper].type != JSMN_ARRAY &&
                    tokens[parser->toksuper].type != JSMN_OBJECT) {
#ifdef JSMN_PARENT_LINKS
                parser->toksuper = tokens[parser->toksuper].parent;
#else
                for (i = parser->toknext - 1; i >= 0; i--) {
                    if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
                        if (tokens[i].start != -1 && tokens[i].end == -1) {
                            parser->toksuper = i;
                            break;
                        }
                    }
                }
#endif
            }
            break;
#ifdef JSMN_STRICT
        /* In strict mode primitives are: numbers and booleans */
        case '-':
        case '0':
        case '1' :
        case '2':
        case '3' :
        case '4':
        case '5':
        case '6':
        case '7' :
        case '8':
        case '9':
        case 't':
        case 'f':
        case 'n' :
            /* And they must not be keys of the object */
            if (tokens != NULL) {
                jsmntok_t *t = &tokens[parser->toksuper];
                if (t->type == JSMN_OBJECT ||
                        (t->type == JSMN_STRING && t->size != 0)) {
                    return JSMN_ERROR_INVAL;
                }
            }
#else
        /* In non-strict mode every unquoted value is a primitive */
        default:
#endif
            r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
            if (r < 0) return r;
            count++;
            if (parser->toksuper != -1 && tokens != NULL)
                tokens[parser->toksuper].size++;
            break;

#ifdef JSMN_STRICT
        /* Unexpected char in strict mode */
        default:
            return JSMN_ERROR_INVAL;
#endif
        }
    }

    for (i = parser->toknext - 1; i >= 0; i--) {
        /* Unmatched opened object or array */
        if (tokens[i].start != -1 && tokens[i].end == -1) {
            return JSMN_ERROR_PART;
        }
    }

    return count;
}
Beispiel #2
0
/**
 * Parse JSON string and fill tokens.
 */
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, 
		unsigned int num_tokens) {
	int r;
	int i;
	jsmntok_t *token;

	/* initialize the rest of tokens (they could be reallocated) */
	for (i = parser->toknext; i < num_tokens; i++) {
		jsmn_fill_token(&tokens[i], JSMN_PRIMITIVE, -1, -1);
	}

	for (; js[parser->pos] != '\0'; parser->pos++) {
		char c;
		jsmntype_t type;

		c = js[parser->pos];
		switch (c) {
			case '{': case '[':
				token = jsmn_alloc_token(parser, tokens, num_tokens);
				if (token == NULL)
					return JSMN_ERROR_NOMEM;
				if (parser->toksuper != -1)
					tokens[parser->toksuper].size++;
				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
				token->start = parser->pos;
				parser->toksuper = parser->toknext - 1;
				break;
			case '}': case ']':
				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
				for (i = parser->toknext - 1; i >= 0; i--) {
					token = &tokens[i];
					if (token->start != -1 && token->end == -1) {
						if (token->type != type) {
							return JSMN_ERROR_INVAL;
						}
						parser->toksuper = -1;
						token->end = parser->pos + 1;
						break;
					}
				}
				/* Error if unmatched closing bracket */
				if (i == -1) return JSMN_ERROR_INVAL;
				for (; i >= 0; i--) {
					token = &tokens[i];
					if (token->start != -1 && token->end == -1) {
						parser->toksuper = i;
						break;
					}
				}
				break;
			case '\"':
				r = jsmn_parse_string(parser, js, tokens, num_tokens);
				if (r < 0) return jsmnerr_t(r);
				if (parser->toksuper != -1)
					tokens[parser->toksuper].size++;
				break;
			case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': 
				break;
#ifdef JSMN_STRICT
			/* In strict mode primitives are: numbers and booleans */
			case '-': case '0': case '1' : case '2': case '3' : case '4':
			case '5': case '6': case '7' : case '8': case '9':
			case 't': case 'f': case 'n' :
#else
			/* In non-strict mode every unquoted value is a primitive */
			default:
#endif
				r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
				if (r < 0) return jsmnerr_t(r);
				if (parser->toksuper != -1)
					tokens[parser->toksuper].size++;
				break;

#ifdef JSMN_STRICT
			/* Unexpected char in strict mode */
			default:
				return JSMN_ERROR_INVAL;
#endif

		}
	}

	for (i = parser->toknext - 1; i >= 0; i--) {
		/* Unmatched opened object or array */
		if (tokens[i].start != -1 && tokens[i].end == -1) {
			return JSMN_ERROR_PART;
		}
	}

	return JSMN_SUCCESS;
}
Beispiel #3
0
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, unsigned int num_tokens)
#endif

{
	jsmnerr_t r;
	int i;
	jsmntok_t *token;


#ifdef JSMN_OPTIMIZE
	for (; js[parser->pos] != '\0' && parser->pos < js_len; parser->pos++)
#else
	for (; js[parser->pos] != '\0'; parser->pos++)
#endif
	 {

		char c;
		jsmntype_t type;

		c = js[parser->pos];
		switch (c) {



			case '{': case '[':
				token = jsmn_alloc_token(parser, tokens, num_tokens);
				if (token == NULL)
					return JSMN_ERROR_NOMEM;
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
					token->parent = parser->toksuper;
#endif
				}
				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
				token->start = parser->pos;
				parser->toksuper = parser->toknext - 1;	//上一层 改为 上一个token
				break;




			case '}': case ']':
				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
				if (parser->toknext < 1) {
					return JSMN_ERROR_INVAL;
				}
				token = &tokens[parser->toknext - 1];	//当前token(尾部的token)

				for (;;) {
					if (token->start != -1 && token->end == -1) {
						if (token->type != type) {
							return JSMN_ERROR_INVAL;
						}
						token->end = parser->pos + 1;
						parser->toksuper = token->parent;
						break;
					}
					if (token->parent == -1) {
						break;
					}
					token = &tokens[token->parent];
				}
#else

				for (i = parser->toknext - 1; i >= 0; i--) {	//回溯
					token = &tokens[i];
					if (token->start != -1 && token->end == -1) {		//找到还没有结尾的token 就是 { [ 的tk
						if (token->type != type) {
							return JSMN_ERROR_INVAL;
						}
						parser->toksuper = -1;
						token->end = parser->pos + 1;		//结尾之
						break;
					}
				}

				/* Error if unmatched closing bracket */
				if (i == -1) return JSMN_ERROR_INVAL;	//找到头也没有

				for (; i >= 0; i--) {				//接着回溯
					token = &tokens[i];
					if (token->start != -1 && token->end == -1) {		//找到再上一级的对象tk
						parser->toksuper = i;
						break;
					}
				}
#endif
				break;





			case '\"':
#ifdef JSMN_OPTIMIZE
				r = jsmn_parse_string(parser, js, js_len, tokens, num_tokens);
#else
				r = jsmn_parse_string(parser, js, tokens, num_tokens);
#endif
				if (r < 0) return r;

				if (parser->toksuper != -1)		//如果有上一层 那么为其添加数量
					tokens[parser->toksuper].size++;
				break;






			case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': 	//越过空白字符
				break;


#ifdef JSMN_STRICT
			/* In strict mode primitives are: numbers and booleans */
			case '-': case '0': case '1' : case '2': case '3' : case '4':
			case '5': case '6': case '7' : case '8': case '9':
			case 't': case 'f': case 'n' :
#else
			/* In non-strict mode every unquoted value is a primitive */
			default:
#endif

#ifdef JSMN_OPTIMIZE
				r = jsmn_parse_primitive(parser, js, js_len, tokens, num_tokens);
#else
				r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
#endif

				if (r < 0) return r;
				if (parser->toksuper != -1)
					tokens[parser->toksuper].size++;
				break;

#ifdef JSMN_STRICT
			/* Unexpected char in strict mode */
			default:
				return JSMN_ERROR_INVAL;
#endif

		}
	}

	for (i = parser->toknext - 1; i >= 0; i--) {	//回溯
		/* Unmatched opened object or array */
		if (tokens[i].start != -1 && tokens[i].end == -1) {		//若是还能找到未圆满的tk
			return JSMN_ERROR_PART;
		}
	}

	return JSMN_SUCCESS;
}
Beispiel #4
0
/**
 * Parse JSON string and fill tokens.
 */
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
					 jsmntok_t *tokens, unsigned int num_tokens) {
	jsmnerr_t r;
	int i;
	jsmntok_t *token;

	for (; js[parser->pos] != '\0'; parser->pos++) {
		char c;
		jsmntype_t type;

		c = js[parser->pos];
		switch (c) {
			case '{': case '[':
				token = jsmn_alloc_token(parser, tokens, num_tokens);
				if (token == NULL) {
					return JSMN_ERROR_NOMEM;
				}
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
					#ifdef JSMN_PARENT_LINKS
						token->parent = parser->toksuper;
					#endif
				}
				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
				token->start = parser->pos;
				parser->toksuper = parser->toknext - 1;
				break;
			case '}': case ']':
				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
				#ifdef JSMN_PARENT_LINKS
					if (parser->toknext < 1) {
						return JSMN_ERROR_INVAL;
					}
					token = &tokens[parser->toknext - 1];
					for (;;) {
						if (token->start != -1 && token->end == -1) {
							if (token->type != type) {
								return JSMN_ERROR_INVAL;
							}
							token->end = parser->pos + 1;
							parser->toksuper = token->parent;
							break;
						}
						if (token->parent == -1) {
							break;
						}
						token = &tokens[token->parent];
				}
				#else
					for (i = parser->toknext - 1; i >= 0; i--) {
						token = &tokens[i];
						if (token->start != -1 && token->end == -1) {
							if (token->type != type) {
								return JSMN_ERROR_INVAL;
							}
							parser->toksuper = -1;
							token->end = parser->pos + 1;
							break;
						}
					}
					/* Error if unmatched closing bracket */
					if (i == -1) {
						return JSMN_ERROR_INVAL;
					}
					for (; i >= 0; i--) {
						token = &tokens[i];
						if (token->start != -1 && token->end == -1) {
							parser->toksuper = i;
							break;
						}
					}
				#endif
				break;
			case '\"':
				r = jsmn_parse_string(parser, js, tokens, num_tokens);
				if (r < 0) {
					return r;
				}
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
				}
				break;
			case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': 
				break;
			#ifdef JSMN_STRICT
				/* Strict mode:
				    Primitives are numbers and booleans */
				case '-': case '0': case '1' : case '2': case '3' : case '4':
				case '5': case '6': case '7' : case '8': case '9':
				case 't': case 'f': case 'n' :
			#else
				/* Non-strict mode:
				    Every unquoted value is a primitive */
				default:
			#endif
					r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
					if (r < 0) {
						return r;
					}
					if (parser->toksuper != -1) {
						tokens[parser->toksuper].size++;
					}
					break;

			#ifdef JSMN_STRICT
				/* Unexpected char in strict mode */
				default:
					return JSMN_ERROR_INVAL;
			#endif

		}
	}

	for (i = parser->toknext - 1; i >= 0; i--) {
		/* Unmatched opened object or array */
		if (tokens[i].start != -1 && tokens[i].end == -1) {
			return JSMN_ERROR_PART;
		}
	}

	return JSMN_SUCCESS;
}
Beispiel #5
0
/**
 * Parse JSON string and fill tokens.
 */
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
		jsmntok_t *tokens, unsigned int num_tokens) {
	int r;
	int i;
	jsmntok_priv_t *token;
	int depth = 0;
	int count = parser->toknext;

	if (tokens == NULL) {
		return JSMN_ERROR_NOMEM;
	}

	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
		char c;
		jsmntype_t type;

		c = js[parser->pos];
		switch (c) {
			case '{': case '[':
				/* check previous token is valid */
				if (parser->toknext >= 1) {
					token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
					depth = token->_depth;
					switch (token->_lasttype) {
						case _JSMN_SEPARATOR_COMMA:
						case _JSMN_SEPARATOR_COLON:
						case JSMN_ARRAY:
							break;
						default:
							return JSMN_ERROR_INVAL;
					}
				}
				/* check parent token is valid */
				if (parser->toksuper != -1) {
					token = (jsmntok_priv_t *)&tokens[parser->toksuper];
					if (token->type == JSMN_OBJECT) {
						return JSMN_ERROR_INVAL;
					}
				}
				count++;
				token = (jsmntok_priv_t *)jsmn_alloc_token(parser, tokens, num_tokens);
				if (token == NULL) return JSMN_ERROR_NOMEM;
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
					token->parent = parser->toksuper;
					jsmn_percolate_skip_counts(tokens, parser->toksuper);
				}
				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
				token->_lasttype = token->type;
				token->_depth = depth+1;
				token->start = parser->pos;
				parser->toksuper = parser->toknext - 1;
				break;
			case '}': case ']':
				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
				if (parser->toksuper == -1) {
					return JSMN_ERROR_INVAL;
				}
				if (parser->toknext < 1) {
					return JSMN_ERROR_INVAL;
				}
				token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
				switch (token->_lasttype) {
					case JSMN_PRIMITIVE:
					case JSMN_STRING:
					case JSMN_OBJECT:
					case JSMN_ARRAY:
					case _JSMN_OBJECT_END:
					case _JSMN_ARRAY_END:
						break;
					default:
						return JSMN_ERROR_INVAL;
				}
				for (;;) {
					if (token->start != -1 && token->end == -1) {
						if (token->type != type) {
							return JSMN_ERROR_INVAL;
						}
						token->end = parser->pos + 1;
						parser->toksuper = token->parent;
						token->_depth--;
						break;
					}
					if (token->parent == -1) {
						break;
					}
					token = (jsmntok_priv_t *)&tokens[token->parent];
				}
				token->_lasttype = token->type == JSMN_OBJECT ? _JSMN_OBJECT_END : _JSMN_ARRAY_END;
				break;
			case '\"':
				if (parser->toknext >= 1) {
					token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
					depth = token->_depth;
					switch (token->_lasttype) {
						case JSMN_OBJECT:
						case JSMN_ARRAY:
						case _JSMN_SEPARATOR_COLON:
						case _JSMN_SEPARATOR_COMMA:
							break;
						default:
							return JSMN_ERROR_INVAL;
					}
				}
				r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
				if (r < 0) return r;
				count++;
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
					jsmn_percolate_skip_counts(tokens, parser->toksuper);
					token = (jsmntok_priv_t *)&tokens[parser->toksuper];
					type = token->_lasttype == JSMN_OBJECT ? _JSMN_STRING_KEY : JSMN_STRING;
				} else {
				    type = JSMN_STRING;
				}
				token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
				token->_lasttype = type;
				token->_depth = depth;
				break;
			case '\t' : case '\r' : case '\n' : case ' ':
				break;
			case ':':
				if (parser->toksuper == -1) {
					return JSMN_ERROR_INVAL;
				}
				assert(parser->toknext >= 1);
				token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
				switch (token->_lasttype) {
					case _JSMN_STRING_KEY:
						break;
					default:
						return JSMN_ERROR_INVAL;
				}
				parser->toksuper = parser->toknext - 1;
				token->_lasttype = _JSMN_SEPARATOR_COLON;
				break;
			case ',':
				if (parser->toksuper == -1) {
					return JSMN_ERROR_INVAL;
				}
				assert(parser->toknext >= 1);
				token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
				switch (token->_lasttype) {
					case JSMN_PRIMITIVE:
					case JSMN_STRING:
					case _JSMN_OBJECT_END:
					case _JSMN_ARRAY_END:
						break;
					default:
						return JSMN_ERROR_INVAL;
				}
				if (
						tokens[parser->toksuper].type != JSMN_ARRAY &&
						tokens[parser->toksuper].type != JSMN_OBJECT) {
					parser->toksuper = tokens[parser->toksuper].parent;
				}
				token->_lasttype = _JSMN_SEPARATOR_COMMA;
				break;
			/* In strict mode primitives are: numbers and booleans */
			case '-': case '0': case '1' : case '2': case '3' : case '4':
			case '5': case '6': case '7' : case '8': case '9':
			case 't': case 'f': case 'n' :
				/* And they must not be keys of the object */
				if (parser->toksuper != -1) {
					token = (jsmntok_priv_t *)&tokens[parser->toksuper];
					if (token->type == JSMN_OBJECT ||
							(token->type == JSMN_STRING && token->size != 0)) {
						return JSMN_ERROR_INVAL;
					}
					depth = token->_depth;
				}
				if (parser->toknext >= 1) {
					token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
					switch (token->_lasttype) {
						case JSMN_ARRAY:
						case _JSMN_SEPARATOR_COLON:
						case _JSMN_SEPARATOR_COMMA:
							break;
						default:
							return JSMN_ERROR_INVAL;
					}
				}
				r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
				if (r < 0) return r;
				count++;
				if (parser->toksuper != -1) {
					tokens[parser->toksuper].size++;
					jsmn_percolate_skip_counts(tokens, parser->toksuper);
				}
				token = (jsmntok_priv_t *)&tokens[parser->toknext - 1];
				token->_lasttype = JSMN_PRIMITIVE;
				token->_depth = depth;
				break;

			/* Unexpected char in strict mode */
			default:
				return JSMN_ERROR_INVAL;
		}
	}

	if (tokens[0].type == JSMN_OBJECT || tokens[0].type == JSMN_ARRAY) {
		/* Unmatched opened object or array */
		if (((jsmntok_priv_t *)(&tokens[0]))->_depth != 0) {
				return JSMN_ERROR_INVAL;
		}
	}

#ifndef NDEBUG
	/* sanity checks */
	for (i = 0; i < parser->toknext; i++) {
		assert(tokens[i].start != -1);
		assert(tokens[i].end != -1);
		assert(((jsmntok_priv_t *)(&tokens[i]))->_depth != -1);
		assert(((jsmntok_priv_t *)(&tokens[i]))->_lasttype != JSMN_UNDEFINED);
	}
#endif

	return count;
}
Beispiel #6
0
/**
 * Parse JSON string and fill tokens.
 */
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, 
		unsigned int num_tokens) 
{
   jsmnerr_t r;
   int i;
   jsmntok_t *token;
   
   for (; js[parser->pos] != '\0'; parser->pos++) 
   {
      char c;
      jsmntype_t type;

      c = js[parser->pos];
      switch (c) 
      {
      case '{': case '[':
         token = jsmn_alloc_token(parser, tokens, num_tokens);
         if (token == NULL)
            return JSMN_ERROR_NOMEM;
         if (parser->toksuper != -1) {
            tokens[parser->toksuper].size++;
         }
         token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
         token->start = parser->pos;
         parser->toksuper = parser->toknext - 1;
         break;

      case '}': case ']':
         type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
         for (i = parser->toknext - 1; i >= 0; i--) {
            token = &tokens[i];
            if (token->start != -1 && token->end == -1) {
               if (token->type != type) {
                  return JSMN_ERROR_INVAL;
               }
               parser->toksuper = -1;
               token->end = parser->pos + 1;
               break;
            }
         }
         /* Error if unmatched closing bracket */
         if (i == -1) return JSMN_ERROR_INVAL;
         for (; i >= 0; i--) {
            token = &tokens[i];
            if (token->start != -1 && token->end == -1) {
               parser->toksuper = i;
               break;
            }
         }
         break;
      case '\"':
         r = jsmn_parse_string(parser, js, tokens, num_tokens);
         if (r < 0) return r;
         if (parser->toksuper != -1)
            tokens[parser->toksuper].size++;
         break;
      case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': 
         break;

      default:
         r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
         if (r < 0) return r;
         if (parser->toksuper != -1)
            tokens[parser->toksuper].size++;
         break;
         
      }
   }
   
   for (i = parser->toknext - 1; i >= 0; i--) {
      /* Unmatched opened object or array */
      if (tokens[i].start != -1 && tokens[i].end == -1) {
         return JSMN_ERROR_PART;
      }
   }

   // Append an "END" token
   if(parser->toknext < num_tokens)
   {
      tokens[parser->toknext].start = tokens[parser->toknext].end = -1;
   }
   return JSMN_SUCCESS;
}