Created
December 17, 2021 20:25
-
-
Save vsajip/080d3681bd78bd68b3dc3e1b6ce032e6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Generated by: JavaCC 21 Parser Generator. JSONParser.java */ | |
package org.parsers.json; | |
import org.parsers.json.ast.*; | |
import java.util.*; | |
import java.util.concurrent.CancellationException; | |
import java.util.logging.*; | |
import java.io.*; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import static org.parsers.json.JSONConstants.TokenType.*; | |
@SuppressWarnings("unused") | |
public class JSONParser implements JSONConstants { | |
private static final java.util.logging.Logger LOGGER= Logger.getLogger(JSONConstants.class.getName()); | |
public static void setLogLevel(Level level) { | |
LOGGER.setLevel(level); | |
Logger.getGlobal().getParent().getHandlers()[0].setLevel(level); | |
} | |
static final int UNLIMITED= Integer.MAX_VALUE; | |
// The last token successfully "consumed" | |
Token lastConsumedToken= new Token(); | |
// We start with a dummy token. REVISIT | |
private TokenType nextTokenType; | |
private Token currentLookaheadToken; | |
private boolean scanToEnd; | |
private String currentlyParsedProduction, currentLookaheadProduction; | |
private EnumSet<TokenType> outerFollowSet; | |
private boolean cancelled; | |
public void cancel() { | |
cancelled= true; | |
} | |
public boolean isCancelled() { | |
return cancelled; | |
} | |
/** Generated Lexer. */ | |
public JSONLexer token_source; | |
public void setInputSource(String inputSource) { | |
token_source.setInputSource(inputSource); | |
} | |
String getInputSource() { | |
return token_source.getInputSource(); | |
} | |
//================================= | |
// Generated constructors | |
//================================= | |
public JSONParser(String inputSource, CharSequence content) { | |
this(new JSONLexer(inputSource, content)); | |
} | |
public JSONParser(CharSequence content) { | |
this("input", content); | |
} | |
public JSONParser(String inputSource, Path path) throws IOException { | |
this(inputSource, FileLineMap.stringFromBytes(Files.readAllBytes(path))); | |
} | |
public JSONParser(Path path) throws IOException { | |
this(path.toString(), path); | |
} | |
public JSONParser(java.io.InputStream stream) { | |
this(new InputStreamReader(stream)); | |
} | |
public JSONParser(Reader reader) { | |
this(new JSONLexer("input", reader)); | |
} | |
/** Constructor with user supplied Lexer. */ | |
public JSONParser(JSONLexer lexer) { | |
token_source= lexer; | |
lastConsumedToken.setInputSource(lexer.getInputSource()); | |
} | |
// If tok already has a next field set, it returns that | |
// Otherwise, it goes to the token_source, i.e. the Lexer. | |
final private Token nextToken(final Token tok) { | |
Token result= tok== null?null: | |
tok.getNext(); | |
Token previous= null; | |
while (result== null) { | |
nextTokenType= null; | |
Token next= token_source.getNextToken(); | |
previous= next; | |
if (!next.isUnparsed()) { | |
result= next; | |
} | |
else if (next instanceof InvalidToken) { | |
result= next.getNextToken(); | |
} | |
} | |
if (tok!=null) tok.setNext(result); | |
nextTokenType= null; | |
return result; | |
} | |
/** | |
* @return the next Token off the stream. This is the same as #getToken(1) | |
*/ | |
final public Token getNextToken() { | |
return getToken(1); | |
} | |
/** | |
* @param index how many tokens to look ahead | |
* @return the specific Token index ahead in the stream. | |
* If we are in a lookahead, it looks ahead from the currentLookaheadToken | |
* Otherwise, it is the lastConsumedToken | |
*/ | |
final public Token getToken(int index) { | |
Token t= currentLookaheadToken== null?lastConsumedToken: | |
currentLookaheadToken; | |
for (int i= 0; i<index; i++) { | |
t= nextToken(t); | |
} | |
return t; | |
} | |
private final TokenType nextTokenType() { | |
if (nextTokenType== null) { | |
nextTokenType= nextToken(lastConsumedToken).getType(); | |
} | |
return nextTokenType; | |
} | |
boolean activateTokenTypes(TokenType type, TokenType...types) { | |
boolean result= token_source.activeTokenTypes.add(type); | |
for (TokenType tt : types) { | |
result|=token_source.activeTokenTypes.add(tt); | |
} | |
if (result) { | |
token_source.reset(getToken(0)); | |
nextTokenType= null; | |
} | |
return result; | |
} | |
boolean deactivateTokenTypes(TokenType type, TokenType...types) { | |
boolean result= token_source.activeTokenTypes.remove(type); | |
for (TokenType tt : types) { | |
result|=token_source.activeTokenTypes.remove(tt); | |
} | |
if (result) { | |
token_source.reset(getToken(0)); | |
nextTokenType= null; | |
} | |
return result; | |
} | |
// JSON.javacc:65:1 | |
final public void Array() throws ParseException { | |
if (trace_enabled) LOGGER.info("Entering production defined on line 65 of JSON.javacc"); | |
if (cancelled) throw new CancellationException(); | |
String prevProduction= currentlyParsedProduction; | |
this.currentlyParsedProduction= "Array"; | |
Array Array1= null; | |
if (buildTree) { | |
Array1= new Array(); | |
Array1.setInputSource(getInputSource()); | |
openNodeScope(Array1); | |
} | |
ParseException parseException1= null; | |
int callStackSize2= parsingStack.size(); | |
try { | |
if (false) throw new ParseException("Never happens!"); | |
// Code for RegexpRef specified at: | |
// JSON.javacc:66:5 | |
consumeToken(OPEN_BRACKET); | |
// Code for ZeroOrOne specified at: | |
// JSON.javacc:67:5 | |
if (first_set$JSON_javacc$68$7.contains(nextTokenType())) { | |
// Code for NonTerminal specified at: | |
// JSON.javacc:68:7 | |
pushOntoCallStack("Array", "JSON.javacc", 68, 7); | |
outerFollowSet= follow_set$JSON_javacc$68$7$; | |
try { | |
Value(); | |
} | |
finally { | |
popCallStack(); | |
} | |
// Code for ZeroOrMore specified at: | |
// JSON.javacc:68:14 | |
while (true) { | |
if (!(nextTokenType()== COMMA)) break; | |
// Code for RegexpRef specified at: | |
// JSON.javacc:68:15 | |
consumeToken(COMMA); | |
// Code for NonTerminal specified at: | |
// JSON.javacc:68:23 | |
pushOntoCallStack("Array", "JSON.javacc", 68, 23); | |
outerFollowSet= follow_set$JSON_javacc$68$23; | |
try { | |
Value(); | |
} | |
finally { | |
popCallStack(); | |
} | |
} | |
} | |
// Code for RegexpRef specified at: | |
// JSON.javacc:70:5 | |
consumeToken(CLOSE_BRACKET); | |
} | |
catch(ParseException e) { | |
parseException1= e; | |
throw e; | |
} | |
finally { | |
restoreCallStack(callStackSize2); | |
if (Array1!=null) { | |
if (parseException1== null) { | |
closeNodeScope(Array1, nodeArity()> 1); | |
} | |
else { | |
if (trace_enabled) LOGGER.warning("ParseException: "+parseException1.getMessage()); | |
clearNodeScope(); | |
} | |
} | |
this.currentlyParsedProduction= prevProduction; | |
} | |
} | |
static private final EnumSet<TokenType> Value_FIRST_SET= EnumSet.of(OPEN_BRACKET, OPEN_BRACE, TRUE, FALSE, NULL, STRING_LITERAL, NUMBER); | |
// JSON.javacc:73:1 | |
final public void Value() throws ParseException { | |
if (trace_enabled) LOGGER.info("Entering production defined on line 73 of JSON.javacc"); | |
if (cancelled) throw new CancellationException(); | |
String prevProduction= currentlyParsedProduction; | |
this.currentlyParsedProduction= "Value"; | |
// Code for ExpansionChoice specified at: | |
// JSON.javacc:74:5 | |
Value Value2= null; | |
if (buildTree) { | |
Value2= new Value(); | |
Value2.setInputSource(getInputSource()); | |
openNodeScope(Value2); | |
} | |
ParseException parseException31= null; | |
int callStackSize32= parsingStack.size(); | |
try { | |
if (false) throw new ParseException("Never happens!"); | |
if (nextTokenType()== TRUE) { | |
// Code for RegexpRef specified at: | |
// JSON.javacc:74:5 | |
consumeToken(TRUE); | |
} | |
else if (nextTokenType()== FALSE) { | |
// Code for RegexpRef specified at: | |
// JSON.javacc:76:5 | |
consumeToken(FALSE); | |
} | |
else if (nextTokenType()== NULL) { | |
// Code for RegexpRef specified at: | |
// JSON.javacc:78:5 | |
consumeToken(NULL); | |
} | |
else if (nextTokenType()== STRING_LITERAL) { | |
// Code for RegexpRef specified at: | |
// JSON.javacc:80:5 | |
consumeToken(STRING_LITERAL); | |
} | |
else if (nextTokenType()== NUMBER) { | |
// Code for RegexpRef specified at: | |
// JSON.javacc:82:5 | |
consumeToken(NUMBER); | |
} | |
else if (nextTokenType()== OPEN_BRACKET) { | |
// Code for NonTerminal specified at: | |
// JSON.javacc:84:5 | |
pushOntoCallStack("Value", "JSON.javacc", 84, 5); | |
try { | |
Array(); | |
} | |
finally { | |
popCallStack(); | |
} | |
} | |
else if (nextTokenType()== OPEN_BRACE) { | |
// Code for NonTerminal specified at: | |
// JSON.javacc:86:5 | |
pushOntoCallStack("Value", "JSON.javacc", 86, 5); | |
try { | |
JSONObject(); | |
} | |
finally { | |
popCallStack(); | |
} | |
} | |
else { | |
pushOntoCallStack("Value", "JSON.javacc", 74, 5); | |
throw new ParseException(this, Value_FIRST_SET, parsingStack); | |
} | |
} | |
catch(ParseException e) { | |
parseException31= e; | |
throw e; | |
} | |
finally { | |
restoreCallStack(callStackSize32); | |
if (Value2!=null) { | |
if (parseException31== null) { | |
closeNodeScope(Value2, nodeArity()> 1); | |
} | |
else { | |
if (trace_enabled) LOGGER.warning("ParseException: "+parseException31.getMessage()); | |
clearNodeScope(); | |
} | |
} | |
this.currentlyParsedProduction= prevProduction; | |
} | |
} | |
// JSON.javacc:89:1 | |
final public void KeyValuePair() throws ParseException { | |
if (trace_enabled) LOGGER.info("Entering production defined on line 89 of JSON.javacc"); | |
if (cancelled) throw new CancellationException(); | |
String prevProduction= currentlyParsedProduction; | |
this.currentlyParsedProduction= "KeyValuePair"; | |
KeyValuePair KeyValuePair3= null; | |
if (buildTree) { | |
KeyValuePair3= new KeyValuePair(); | |
KeyValuePair3.setInputSource(getInputSource()); | |
openNodeScope(KeyValuePair3); | |
} | |
ParseException parseException76= null; | |
int callStackSize77= parsingStack.size(); | |
try { | |
if (false) throw new ParseException("Never happens!"); | |
// Code for RegexpRef specified at: | |
// JSON.javacc:89:16 | |
consumeToken(STRING_LITERAL); | |
// Code for RegexpRef specified at: | |
// JSON.javacc:89:33 | |
consumeToken(COLON); | |
// Code for NonTerminal specified at: | |
// JSON.javacc:89:41 | |
pushOntoCallStack("KeyValuePair", "JSON.javacc", 89, 41); | |
try { | |
Value(); | |
} | |
finally { | |
popCallStack(); | |
} | |
} | |
catch(ParseException e) { | |
parseException76= e; | |
throw e; | |
} | |
finally { | |
restoreCallStack(callStackSize77); | |
if (KeyValuePair3!=null) { | |
if (parseException76== null) { | |
closeNodeScope(KeyValuePair3, nodeArity()> 1); | |
} | |
else { | |
if (trace_enabled) LOGGER.warning("ParseException: "+parseException76.getMessage()); | |
clearNodeScope(); | |
} | |
} | |
this.currentlyParsedProduction= prevProduction; | |
} | |
} | |
// JSON.javacc:91:1 | |
final public void JSONObject() throws ParseException { | |
if (trace_enabled) LOGGER.info("Entering production defined on line 91 of JSON.javacc"); | |
if (cancelled) throw new CancellationException(); | |
String prevProduction= currentlyParsedProduction; | |
this.currentlyParsedProduction= "JSONObject"; | |
JSONObject JSONObject4= null; | |
if (buildTree) { | |
JSONObject4= new JSONObject(); | |
JSONObject4.setInputSource(getInputSource()); | |
openNodeScope(JSONObject4); | |
} | |
ParseException parseException88= null; | |
int callStackSize89= parsingStack.size(); | |
try { | |
if (false) throw new ParseException("Never happens!"); | |
// Code for RegexpRef specified at: | |
// JSON.javacc:92:5 | |
consumeToken(OPEN_BRACE); | |
// Code for ZeroOrOne specified at: | |
// JSON.javacc:93:5 | |
if (nextTokenType()== STRING_LITERAL) { | |
// Code for NonTerminal specified at: | |
// JSON.javacc:94:9 | |
pushOntoCallStack("JSONObject", "JSON.javacc", 94, 9); | |
outerFollowSet= follow_set$JSON_javacc$94$9; | |
try { | |
KeyValuePair(); | |
} | |
finally { | |
popCallStack(); | |
} | |
// Code for ZeroOrMore specified at: | |
// JSON.javacc:94:22 | |
while (true) { | |
if (!(nextTokenType()== COMMA)) break; | |
// Code for RegexpStringLiteral specified at: | |
// JSON.javacc:94:23 | |
consumeToken(COMMA); | |
// Code for NonTerminal specified at: | |
// JSON.javacc:94:27 | |
pushOntoCallStack("JSONObject", "JSON.javacc", 94, 27); | |
outerFollowSet= follow_set$JSON_javacc$94$27; | |
try { | |
KeyValuePair(); | |
} | |
finally { | |
popCallStack(); | |
} | |
} | |
} | |
// Code for RegexpRef specified at: | |
// JSON.javacc:96:5 | |
consumeToken(CLOSE_BRACE); | |
} | |
catch(ParseException e) { | |
parseException88= e; | |
throw e; | |
} | |
finally { | |
restoreCallStack(callStackSize89); | |
if (JSONObject4!=null) { | |
if (parseException88== null) { | |
closeNodeScope(JSONObject4, nodeArity()> 1); | |
} | |
else { | |
if (trace_enabled) LOGGER.warning("ParseException: "+parseException88.getMessage()); | |
clearNodeScope(); | |
} | |
} | |
this.currentlyParsedProduction= prevProduction; | |
} | |
} | |
// JSON.javacc:99:1 | |
final public void Root() throws ParseException { | |
if (trace_enabled) LOGGER.info("Entering production defined on line 99 of JSON.javacc"); | |
if (cancelled) throw new CancellationException(); | |
String prevProduction= currentlyParsedProduction; | |
this.currentlyParsedProduction= "Root"; | |
Root Root5= null; | |
if (buildTree) { | |
Root5= new Root(); | |
Root5.setInputSource(getInputSource()); | |
openNodeScope(Root5); | |
} | |
ParseException parseException118= null; | |
int callStackSize119= parsingStack.size(); | |
try { | |
if (false) throw new ParseException("Never happens!"); | |
// Code for NonTerminal specified at: | |
// JSON.javacc:99:8 | |
pushOntoCallStack("Root", "JSON.javacc", 99, 8); | |
outerFollowSet= follow_set$JSON_javacc$99$8; | |
try { | |
Value(); | |
} | |
finally { | |
popCallStack(); | |
} | |
// Code for EndOfFile specified at: | |
// JSON.javacc:99:15 | |
consumeToken(EOF); | |
} | |
catch(ParseException e) { | |
parseException118= e; | |
throw e; | |
} | |
finally { | |
restoreCallStack(callStackSize119); | |
if (Root5!=null) { | |
if (parseException118== null) { | |
closeNodeScope(Root5, nodeArity()> 1); | |
} | |
else { | |
if (trace_enabled) LOGGER.warning("ParseException: "+parseException118.getMessage()); | |
clearNodeScope(); | |
} | |
} | |
this.currentlyParsedProduction= prevProduction; | |
} | |
} | |
static private final EnumSet<TokenType> first_set$JSON_javacc$68$7= EnumSet.of(OPEN_BRACKET, OPEN_BRACE, TRUE, FALSE, NULL, STRING_LITERAL, NUMBER); | |
static private EnumSet<TokenType> follow_set$JSON_javacc$66$5_init() { | |
return EnumSet.of(OPEN_BRACKET, CLOSE_BRACKET, OPEN_BRACE, TRUE, FALSE, NULL, STRING_LITERAL, NUMBER); | |
} | |
static private final EnumSet<TokenType> follow_set$JSON_javacc$68$7$= EnumSet.of(COMMA, CLOSE_BRACKET); | |
static private final EnumSet<TokenType> follow_set$JSON_javacc$68$23= EnumSet.of(COMMA, CLOSE_BRACKET); | |
static private final EnumSet<TokenType> follow_set$JSON_javacc$94$9= EnumSet.of(COMMA, CLOSE_BRACE); | |
static private final EnumSet<TokenType> follow_set$JSON_javacc$94$27= EnumSet.of(COMMA, CLOSE_BRACE); | |
static private final EnumSet<TokenType> follow_set$JSON_javacc$99$8= EnumSet.of(EOF); | |
private boolean trace_enabled= false; | |
public void setTracingEnabled(boolean tracingEnabled) { | |
trace_enabled= tracingEnabled; | |
} | |
/** | |
* @deprecated Use #setTracingEnabled | |
*/ | |
@Deprecated public void enable_tracing() { | |
setTracingEnabled(true); | |
} | |
/** | |
* @deprecated Use #setTracingEnabled | |
*/ | |
@Deprecated public void disable_tracing() { | |
setTracingEnabled(false); | |
} | |
ArrayList<NonTerminalCall> parsingStack= new ArrayList<> (); | |
private ArrayList<NonTerminalCall> lookaheadStack= new ArrayList<> (); | |
/** | |
* Inner class that represents entering a grammar production | |
*/ | |
class NonTerminalCall { | |
final String sourceFile; | |
final String productionName; | |
final int line, column; | |
// We actually only use this when we're working with the LookaheadStack | |
final boolean scanToEnd; | |
final EnumSet<TokenType> followSet; | |
NonTerminalCall(String sourceFile, String productionName, int line, int column) { | |
this.sourceFile= sourceFile; | |
this.productionName= productionName; | |
this.line= line; | |
this.column= column; | |
this.scanToEnd= JSONParser.this.scanToEnd; | |
this.followSet= JSONParser.this.outerFollowSet; | |
} | |
StackTraceElement createStackTraceElement() { | |
return new StackTraceElement("JSONParser", productionName, sourceFile, line); | |
} | |
void dump(PrintStream ps) { | |
ps.println(productionName+":"+line+":"+column); | |
} | |
} | |
private final void pushOntoCallStack(String methodName, String fileName, int line, int column) { | |
parsingStack.add(new NonTerminalCall(fileName, methodName, line, column)); | |
} | |
private final void popCallStack() { | |
NonTerminalCall ntc= parsingStack.remove(parsingStack.size()-1); | |
this.currentlyParsedProduction= ntc.productionName; | |
this.outerFollowSet= ntc.followSet; | |
} | |
private final void restoreCallStack(int prevSize) { | |
while (parsingStack.size()> prevSize) { | |
popCallStack(); | |
} | |
} | |
void dumpLookaheadStack(PrintStream ps) { | |
ListIterator<NonTerminalCall> it= lookaheadStack.listIterator(lookaheadStack.size()); | |
while (it.hasPrevious()) { | |
it.previous().dump(ps); | |
} | |
} | |
void dumpCallStack(PrintStream ps) { | |
ListIterator<NonTerminalCall> it= parsingStack.listIterator(parsingStack.size()); | |
while (it.hasPrevious()) { | |
it.previous().dump(ps); | |
} | |
} | |
void dumpLookaheadCallStack(PrintStream ps) { | |
ps.println("Current Parser Production is: "+currentlyParsedProduction); | |
ps.println("Current Lookahead Production is: "+currentLookaheadProduction); | |
ps.println("---Lookahead Stack---"); | |
dumpLookaheadStack(ps); | |
ps.println("---Call Stack---"); | |
dumpCallStack(ps); | |
} | |
public boolean isParserTolerant() { | |
return false; | |
} | |
public void setParserTolerant(boolean tolerantParsing) { | |
if (tolerantParsing) { | |
throw new UnsupportedOperationException("This parser was not built with that feature!"); | |
} | |
} | |
private Token consumeToken(TokenType expectedType) throws ParseException { | |
Token oldToken= lastConsumedToken; | |
Token nextToken= nextToken(lastConsumedToken); | |
if (nextToken.getType()!=expectedType) { | |
nextToken= handleUnexpectedTokenType(expectedType, nextToken); | |
} | |
this.lastConsumedToken= nextToken; | |
this.nextTokenType= null; | |
if (buildTree&&tokensAreNodes) { | |
pushNode(lastConsumedToken); | |
} | |
if (trace_enabled) LOGGER.info("Consumed token of type "+lastConsumedToken.getType()+" from "+lastConsumedToken.getLocation()); | |
return lastConsumedToken; | |
} | |
private Token handleUnexpectedTokenType(TokenType expectedType, Token nextToken) throws ParseException { | |
throw new ParseException(nextToken, EnumSet.of(expectedType), parsingStack); | |
} | |
private class ParseState { | |
Token lastConsumed; | |
ArrayList<NonTerminalCall> parsingStack; | |
NodeScope nodeScope; | |
ParseState() { | |
this.lastConsumed= JSONParser.this.lastConsumedToken; | |
@SuppressWarnings("unchecked") | |
ArrayList<NonTerminalCall> parsingStack= (ArrayList<NonTerminalCall> ) JSONParser.this.parsingStack.clone(); | |
this.parsingStack= parsingStack; | |
this.nodeScope= (NodeScope) currentNodeScope.clone(); | |
} | |
} | |
private boolean buildTree= true; | |
private boolean tokensAreNodes= true; | |
private boolean unparsedTokensAreNodes= false; | |
public boolean isTreeBuildingEnabled() { | |
return buildTree; | |
} | |
public void setUnparsedTokensAreNodes(boolean unparsedTokensAreNodes) { | |
this.unparsedTokensAreNodes= unparsedTokensAreNodes; | |
} | |
public void setTokensAreNodes(boolean tokensAreNodes) { | |
this.tokensAreNodes= tokensAreNodes; | |
} | |
NodeScope currentNodeScope= new NodeScope(); | |
/** | |
* @return the root node of the AST. It only makes sense to call | |
* this after a successful parse. | |
*/ | |
public Node rootNode() { | |
return currentNodeScope.rootNode(); | |
} | |
/** | |
* push a node onto the top of the node stack | |
* @param n the node to push | |
*/ | |
public void pushNode(Node n) { | |
currentNodeScope.add(n); | |
} | |
/** | |
* @return the node on the top of the stack, and remove it from the | |
* stack. | |
*/ | |
public Node popNode() { | |
return currentNodeScope.pop(); | |
} | |
/** | |
* @return the node currently on the top of the tree-building stack. | |
*/ | |
public Node peekNode() { | |
return currentNodeScope.peek(); | |
} | |
/** | |
* Puts the node on the top of the stack. However, unlike pushNode() | |
* it replaces the node that is currently on the top of the stack. | |
* This is effectively equivalent to popNode() followed by pushNode(n) | |
* @param n the node to poke | |
*/ | |
public void pokeNode(Node n) { | |
currentNodeScope.poke(n); | |
} | |
/** | |
* @return the number of Nodes on the tree-building stack in the current node | |
* scope. | |
*/ | |
public int nodeArity() { | |
return currentNodeScope.size(); | |
} | |
private void clearNodeScope() { | |
currentNodeScope.clear(); | |
} | |
private void openNodeScope(Node n) { | |
new NodeScope(); | |
if (n!=null) { | |
Token next= nextToken(lastConsumedToken); | |
n.setBeginLine(next.getBeginLine()); | |
n.setBeginColumn(next.getBeginColumn()); | |
n.setInputSource(this.getInputSource()); | |
n.open(); | |
} | |
if (trace_enabled&&n!=null) LOGGER.info("Opened node scope for node of type: "+n.getClass().getName()); | |
if (trace_enabled) LOGGER.info("Scope nesting level is "+currentNodeScope.nestingLevel()); | |
} | |
/* A definite node is constructed from a specified number of | |
* children. That number of nodes are popped from the stack and | |
* made the children of the definite node. Then the definite node | |
* is pushed on to the stack. | |
*/ | |
private void closeNodeScope(Node n, int num) { | |
n.setEndLine(lastConsumedToken.getEndLine()); | |
n.setEndColumn(lastConsumedToken.getEndColumn()); | |
if (trace_enabled) LOGGER.info("Closing node scope for node of type: "+n.getClass().getName()+", popping "+num+" nodes off the stack."); | |
currentNodeScope.close(); | |
ArrayList<Node> nodes= new ArrayList<Node> (); | |
for (int i= 0; i<num; i++) { | |
nodes.add(popNode()); | |
} | |
Collections.reverse(nodes); | |
for (Node child : nodes) { | |
// FIXME deal with the UNPARSED_TOKENS_ARE_NODES case | |
n.addChild(child); | |
} | |
n.close(); | |
pushNode(n); | |
} | |
/** | |
* A conditional node is constructed if the condition is true. All | |
* the nodes that have been pushed since the node was opened are | |
* made children of the conditional node, which is then pushed | |
* on to the stack. If the condition is false the node is not | |
* constructed and they are left on the stack. | |
*/ | |
private void closeNodeScope(Node n, boolean condition) { | |
if (n!=null&&condition) { | |
n.setEndColumn(lastConsumedToken.getEndColumn()); | |
n.setEndLine(lastConsumedToken.getEndLine()); | |
if (trace_enabled) LOGGER.finer("Closing node scope for node of type: "+n.getClass().getName()+", popping "+nodeArity()+" nodes off the stack."); | |
int a= nodeArity(); | |
currentNodeScope.close(); | |
ArrayList<Node> nodes= new ArrayList<Node> (); | |
while (a--> 0) { | |
nodes.add(popNode()); | |
} | |
Collections.reverse(nodes); | |
for (Node child : nodes) { | |
if (unparsedTokensAreNodes&&child instanceof Token) { | |
Token tok= (Token) child; | |
while (tok.getPreviousToken()!=null&&tok.getPreviousToken().isUnparsed()) { | |
tok= tok.getPreviousToken(); | |
} | |
while (tok.isUnparsed()) { | |
n.addChild(tok); | |
tok= tok.getNextToken(); | |
} | |
} | |
n.addChild(child); | |
} | |
n.close(); | |
if (trace_enabled) { | |
LOGGER.info("Closing node scope for node of type: "+n.getClass().getName()+", leaving "+nodeArity()+" nodes on the stack."); | |
LOGGER.info("Nesting level is : "+currentNodeScope.nestingLevel()); | |
} | |
pushNode(n); | |
if (trace_enabled) { | |
LOGGER.info("Closed node scope for node of type: "+n.getClass().getName()+", there are now "+nodeArity()+" nodes on the stack."); | |
LOGGER.info("Nesting level is : "+currentNodeScope.nestingLevel()); | |
} | |
} | |
else { | |
currentNodeScope.close(); | |
if (trace_enabled&&n!=null) { | |
LOGGER.info("Closed node scope for node of type: "+n.getClass().getName()+", leaving "+nodeArity()+" nodes on the stack."); | |
LOGGER.info("Nesting level is : "+currentNodeScope.nestingLevel()); | |
} | |
} | |
} | |
public boolean getBuildTree() { | |
return buildTree; | |
} | |
public void setBuildTree(boolean buildTree) { | |
this.buildTree= buildTree; | |
} | |
/** | |
* Just a kludge so that existing jjtree-based code that uses | |
* parser.jjtree.foo can work without change. | |
*/ | |
JSONParser jjtree= this; | |
@SuppressWarnings("serial") | |
class NodeScope extends ArrayList<Node> { | |
NodeScope parentScope; | |
NodeScope() { | |
this.parentScope= JSONParser.this.currentNodeScope; | |
JSONParser.this.currentNodeScope= this; | |
} | |
boolean isRootScope() { | |
return parentScope== null; | |
} | |
Node rootNode() { | |
NodeScope ns= this; | |
while (ns.parentScope!=null) { | |
ns= ns.parentScope; | |
} | |
return ns.isEmpty()?null: | |
ns.get(0); | |
} | |
Node peek() { | |
return isEmpty()?parentScope.peek(): | |
get(size()-1); | |
} | |
Node pop() { | |
return isEmpty()?parentScope.pop(): | |
remove(size()-1); | |
} | |
void poke(Node n) { | |
if (isEmpty()) { | |
parentScope.poke(n); | |
} | |
else { | |
set(size()-1, n); | |
} | |
} | |
void close() { | |
parentScope.addAll(this); | |
JSONParser.this.currentNodeScope= parentScope; | |
} | |
int nestingLevel() { | |
int result= 0; | |
NodeScope parent= this; | |
while (parent.parentScope!=null) { | |
result++; | |
parent= parent.parentScope; | |
} | |
return result; | |
} | |
public NodeScope clone() { | |
NodeScope clone= (NodeScope) super.clone(); | |
if (parentScope!=null) { | |
clone.parentScope= (NodeScope) parentScope.clone(); | |
} | |
return clone; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment