/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.jena.atlas.json.io.parser;
import static org.apache.jena.riot.tokens.TokenType.COLON ;
import static org.apache.jena.riot.tokens.TokenType.COMMA ;
import static org.apache.jena.riot.tokens.TokenType.KEYWORD ;
import static org.apache.jena.riot.tokens.TokenType.LBRACE ;
import static org.apache.jena.riot.tokens.TokenType.RBRACE ;
import static org.apache.jena.riot.tokens.TokenType.RBRACKET ;
import org.apache.jena.atlas.json.io.JSONHandler ;
/** Json (extended) parser
* Extensions:
* Use of ', """ and ''' for strings
* Bare words for strings in maps (JSON objects)
* Hex numbers
* Objects with duplicate keys are a warning (keeps last)
*/
public class JSONP extends JSONParserBase
{
private JSONHandler handler ;
public JSONP(TokenizerJSON tokens, JSONHandler handler)
{
super(tokens) ;
this.handler = handler ;
}
public void parse()
{
if ( ! peekToken().hasType(LBRACE) )
exception("Not a JSON object START: "+peekToken()) ;
parseObject() ;
}
private void parseObject()
{
// JSON Object
nextToken() ;
handler.startObject(currLine, currCol) ;
if ( lookingAt(RBRACE) )
{
nextToken() ;
handler.finishObject(currLine, currCol) ;
return ;
}
// ** Read pairs until the cows come home. Or a } occurs.
for(;;)
{
handler.startPair(currLine, currCol) ;
if ( ! lookingAt(KEYWORD) && ! lookingAtString() )
exception("Not a key for a JSON object: "+peekToken()) ;
String key = peekToken().getImage() ;
nextToken() ;
handler.valueString(key, currLine, currCol) ;
if ( ! lookingAt(COLON) )
exception("Not a colon: "+peekToken()) ;
nextToken() ;
handler.keyPair(currLine, currCol) ;
// One parse.
parseAny() ;
handler.finishPair(currLine, currCol) ;
if ( ! lookingAt(COMMA) )
break ;
nextToken() ;
}
if ( ! lookingAt(RBRACE) )
exception("Illegal: "+peekToken()) ;
nextToken() ;
handler.finishObject(currLine, currCol) ;
}
/** Parse one element into the JSONhandler (includes nesting) */
public void parseAny()
{
switch(peekToken().getType())
{
case LBRACE: { parseObject() ; return ; }
case LBRACKET: { parseArray() ; return ; }
// Number
case INTEGER: { handler.valueInteger(peekToken().getImage(), currLine, currCol) ; nextToken() ; return ; }
case DECIMAL: { handler.valueDecimal(peekToken().getImage(), currLine, currCol) ; nextToken() ; return ; }
case DOUBLE: { handler.valueDouble(peekToken().getImage(), currLine, currCol) ; nextToken() ; return ; }
// String - liberal
case STRING1:
case STRING2:
case LONG_STRING1:
case LONG_STRING2:
{
handler.valueString(peekToken().getImage(), currLine, currCol) ;
nextToken() ;
return ;
}
case KEYWORD:
{
String image = peekToken().getImage() ;
if ( image.equalsIgnoreCase("true") ) { handler.valueBoolean(true, currLine, currCol) ; nextToken() ; return ; }
if ( image.equalsIgnoreCase("false") ) { handler.valueBoolean(false, currLine, currCol) ; nextToken() ; return ; }
if ( image.equalsIgnoreCase("null") ) { handler.valueNull(currLine, currCol) ; nextToken() ; return ; }
//exception("Unrecognized keyword: "+token()) ;
// Very liberal
handler.valueString(image, currLine, currCol) ;
break ;
}
default:
exception("Unrecognized token: "+peekToken()) ;
}
}
private void parseArray()
{
handler.startArray(currLine, currCol) ;
nextToken() ;
if ( lookingAt(RBRACKET) )
{
nextToken() ;
handler.finishArray(currLine, currCol) ;
return ;
}
for(;;)
{
parseAny() ;
handler.element(currLine, currCol) ;
if ( ! lookingAt(COMMA) )
break ;
nextToken() ;
}
if ( ! lookingAt(RBRACKET) )
exception("Illegal: "+peekToken()) ;
nextToken() ;
handler.finishArray(currLine, currCol) ;
}
}