/*
 * 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
 *
 *     https://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.avro.io.parsing;

import java.io.IOException;
import java.util.Arrays;

import org.apache.avro.AvroTypeException;

Parser is the class that maintains the stack for parsing. This class is used by encoders, which are not required to skip.
/** * Parser is the class that maintains the stack for parsing. This class is used * by encoders, which are not required to skip. */
public class Parser {
The parser knows how to handle the terminal and non-terminal symbols. But it needs help from outside to handle implicit and explicit actions. The clients implement this interface to provide this help.
/** * The parser knows how to handle the terminal and non-terminal symbols. But it * needs help from outside to handle implicit and explicit actions. The clients * implement this interface to provide this help. */
public interface ActionHandler {
Handle the action symbol top when the input is sought to be taken off the stack.
Params:
  • input – The input symbol from the caller of advance
  • top – The symbol at the top the stack.
Throws:
Returns:null if advance() is to continue processing the stack. If not null the return value will be returned by advance().
/** * Handle the action symbol <tt>top</tt> when the <tt>input</tt> is sought to be * taken off the stack. * * @param input The input symbol from the caller of advance * @param top The symbol at the top the stack. * @return <tt>null</tt> if advance() is to continue processing the stack. If * not <tt>null</tt> the return value will be returned by advance(). * @throws IOException */
Symbol doAction(Symbol input, Symbol top) throws IOException; } protected final ActionHandler symbolHandler; protected Symbol[] stack; protected int pos; public Parser(Symbol root, ActionHandler symbolHandler) throws IOException { this.symbolHandler = symbolHandler; this.stack = new Symbol[5]; // Start small to make sure expansion code works this.stack[0] = root; this.pos = 1; }
If there is no sufficient room in the stack, use this expand it.
/** * If there is no sufficient room in the stack, use this expand it. */
private void expandStack() { stack = Arrays.copyOf(stack, stack.length + Math.max(stack.length, 1024)); }
Recursively replaces the symbol at the top of the stack with its production, until the top is a terminal. Then checks if the top symbol matches the terminal symbol suppled terminal.
Params:
  • input – The symbol to match against the terminal at the top of the stack.
Returns:The terminal symbol at the top of the stack unless an implicit action resulted in another symbol, in which case that symbol is returned.
/** * Recursively replaces the symbol at the top of the stack with its production, * until the top is a terminal. Then checks if the top symbol matches the * terminal symbol suppled <tt>terminal</tt>. * * @param input The symbol to match against the terminal at the top of the * stack. * @return The terminal symbol at the top of the stack unless an implicit action * resulted in another symbol, in which case that symbol is returned. */
public final Symbol advance(Symbol input) throws IOException { for (;;) { Symbol top = stack[--pos]; if (top == input) { return top; // A common case } Symbol.Kind k = top.kind; if (k == Symbol.Kind.IMPLICIT_ACTION) { Symbol result = symbolHandler.doAction(input, top); if (result != null) { return result; } } else if (k == Symbol.Kind.TERMINAL) { throw new AvroTypeException("Attempt to process a " + input + " when a " + top + " was expected."); } else if (k == Symbol.Kind.REPEATER && input == ((Symbol.Repeater) top).end) { return input; } else { pushProduction(top); } } }
Performs any implicit actions at the top the stack, expanding any production (other than the root) that may be encountered. This method will fail if there are any repeaters on the stack.
Throws:
  • IOException –
/** * Performs any implicit actions at the top the stack, expanding any production * (other than the root) that may be encountered. This method will fail if there * are any repeaters on the stack. * * @throws IOException */
public final void processImplicitActions() throws IOException { while (pos > 1) { Symbol top = stack[pos - 1]; if (top.kind == Symbol.Kind.IMPLICIT_ACTION) { pos--; symbolHandler.doAction(null, top); } else if (top.kind != Symbol.Kind.TERMINAL) { pos--; pushProduction(top); } else { break; } } }
Performs any "trailing" implicit actions at the top the stack.
/** * Performs any "trailing" implicit actions at the top the stack. */
public final void processTrailingImplicitActions() throws IOException { while (pos >= 1) { Symbol top = stack[pos - 1]; if (top.kind == Symbol.Kind.IMPLICIT_ACTION && ((Symbol.ImplicitAction) top).isTrailing) { pos--; symbolHandler.doAction(null, top); } else { break; } } }
Pushes the production for the given symbol sym. If sym is a repeater and input is either Symbol.ARRAY_END or Symbol.MAP_END pushes nothing.
Params:
  • sym –
/** * Pushes the production for the given symbol <tt>sym</tt>. If <tt>sym</tt> is a * repeater and <tt>input</tt> is either {@link Symbol#ARRAY_END} or * {@link Symbol#MAP_END} pushes nothing. * * @param sym */
public final void pushProduction(Symbol sym) { Symbol[] p = sym.production; while (pos + p.length > stack.length) { expandStack(); } System.arraycopy(p, 0, stack, pos, p.length); pos += p.length; }
Pops and returns the top symbol from the stack.
/** * Pops and returns the top symbol from the stack. */
public Symbol popSymbol() { return stack[--pos]; }
Returns the top symbol from the stack.
/** * Returns the top symbol from the stack. */
public Symbol topSymbol() { return stack[pos - 1]; }
Pushes sym on to the stack.
/** * Pushes <tt>sym</tt> on to the stack. */
public void pushSymbol(Symbol sym) { if (pos == stack.length) { expandStack(); } stack[pos++] = sym; }
Returns the depth of the stack.
/** * Returns the depth of the stack. */
public int depth() { return pos; } public void reset() { pos = 1; } }