/*
* Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
* All rights reserved.
*
* This file is part of the Abacus Formula Compiler (AFC).
*
* For commercial licensing, please contact sales(at)formulacompiler.com.
*
* AFC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AFC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AFC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.formulacompiler.compiler.internal.expressions.parser;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.internal.expressions.ExpressionNode;
import org.formulacompiler.runtime.New;
/**
* Provides a node stack for the recursive descent expression parser generated by JavaCC. Also adds
* override points for implementing spreadsheet-specific elements like cells and ranges. Those are
* not implemented here so the basic parser does not depend on
* {@link org.formulacompiler.spreadsheet}. Nevertheless, it does "parse" the cell constructs
* because it seems impossible to add them in derivations (JavaCC does not support inheritance and
* it would be hard for it to do so, too).
*
* @author peo
*/
abstract class ExpressionParserBase
{
/**
* Use a List instead of a Deque here so {@link #popNodes(int)} does not have to reverse
* elements.
*/
private final List<ExpressionNode> nodes = New.list();
protected final void pushNode( ExpressionNode _node )
{
this.nodes.add( _node );
}
protected final ExpressionNode popNode()
{
return this.nodes.remove( this.nodes.size() - 1 );
}
/**
* Returns the top <i>n</i> nodes <em>in the order they were pushed</em> (FIFO). Popping the
* nodes individually would reverse this order (LIFO).
*/
protected final List<ExpressionNode> popNodes( int _howMany )
{
final int have = this.nodes.size();
if (_howMany > have) {
throw new IllegalArgumentException( "_howMany > have" );
}
else {
final List<ExpressionNode> result = New.list( _howMany );
for (int i = have - _howMany; i < have; i++) {
result.add( this.nodes.get( i ) );
}
for (int i = 1; i <= _howMany; i++) {
this.nodes.remove( have - i );
}
return result;
}
}
private final Stack<Integer> marks = new Stack<Integer>();
/**
* Remembers the current node stack pointer for {@code popMarkedNodes()}. Calls are nestable.
*/
protected final void mark()
{
this.marks.push( this.nodes.size() );
}
/**
* Returns the top <i>n</i> nodes since the last {@code mark()}
* <em>in the order they were pushed</em> (FIFO).
*/
protected final List<ExpressionNode> popMarkedNodes()
{
final int mark = this.marks.pop();
return popNodes( this.nodes.size() - mark );
}
/**
* Pops the top node and adds it as the last child to the then top node.
*/
protected final void popNodeAndMergeIntoTopNode()
{
final ExpressionNode popped = popNode();
final ExpressionNode top = peekNode();
top.addArgument( popped );
}
protected final ExpressionNode peekNode()
{
return this.nodes.get( this.nodes.size() - 1 );
}
protected final Number parseInt( String _text )
{
return Double.parseDouble( _text ); // LATER return proper data type
}
protected final Number parseDouble( String _text )
{
return Double.parseDouble( _text ); // LATER return proper data type
}
protected final String parseQuotedString( String _text )
{
return _text.substring( 1, _text.length() - 1 ).replaceAll( "\"\"", "\"" );
}
protected final void unsupportedFunction( Token _name )
{
throw new InnerParserException( new CompilerException.UnsupportedExpression( "Unsupported function "
+ _name.image + " encountered" ) );
}
protected abstract CellRefFormat getCellRefFormat();
protected abstract Object makeCell( Token _cell, Object _baseCell );
protected abstract boolean isRangeName( Token _name );
protected abstract ExpressionNode makeNamedRangeRef( Token _name );
protected abstract Object makeCellRange( Object _from, Object _to );
protected abstract Object makeCellRange( Token _range );
protected abstract void convertRangesToCells( boolean _allowRanges );
protected abstract ExpressionNode makeNodeForReference( Object _reference );
protected abstract ExpressionNode makeRangeIntersection( Collection<ExpressionNode> _firstTwoElements );
protected abstract ExpressionNode makeRangeUnion( Collection<ExpressionNode> _firstTwoElements );
protected abstract ExpressionNode makeShapedRange( ExpressionNode _range );
protected void makeNewRuleDef( Token _name )
{
throw new IllegalStateException();
}
protected void finalizeLastRuleDef()
{
throw new IllegalStateException();
}
protected void makeNewFoldDef( Token _name )
{
throw new IllegalStateException();
}
protected void finalizeLastFoldDef()
{
throw new IllegalStateException();
}
protected void makeNewParam( Token _name, char _suffix )
{
throw new IllegalStateException();
}
protected void let( Token... _name )
{
throw new IllegalStateException();
}
protected void unlet( Token... _name )
{
throw new IllegalStateException();
}
protected void letParams()
{
throw new IllegalStateException();
}
protected void unletParams()
{
throw new IllegalStateException();
}
protected void makeBody()
{
throw new IllegalStateException();
}
protected void initFold()
{
throw new IllegalStateException();
}
protected void addFoldAccuInit( Token _name, ExpressionNode _init )
{
throw new IllegalStateException();
}
protected void addFoldEltName( Token _name )
{
throw new IllegalStateException();
}
protected void setFoldIdxName( Token _name )
{
throw new IllegalStateException();
}
protected void letFoldAccus()
{
throw new IllegalStateException();
}
protected void unletFoldAccus()
{
throw new IllegalStateException();
}
protected void letFoldElts()
{
throw new IllegalStateException();
}
protected void unletFoldElts()
{
throw new IllegalStateException();
}
protected void letFoldCount()
{
throw new IllegalStateException();
}
protected void unletFoldCount()
{
throw new IllegalStateException();
}
protected void addFoldStep( Token _name, ExpressionNode _step )
{
throw new IllegalStateException();
}
protected void setFoldCountName( Token _name )
{
throw new IllegalStateException();
}
protected void setFoldInto( ExpressionNode _node )
{
throw new IllegalStateException();
}
protected void setFoldWhenEmpty( ExpressionNode _node )
{
throw new IllegalStateException();
}
protected void pushFold( boolean _mayRearrange, boolean _mayReduce )
{
throw new IllegalStateException();
}
protected void pushApplyList( Token _def, Token _elts )
{
throw new IllegalStateException();
}
protected void pushApplyVectors( Token _def, Collection<Token> _vecs )
{
throw new IllegalStateException();
}
protected void setExprType( final Token _type )
{
throw new IllegalStateException();
}
protected static final class InnerParserException extends RuntimeException
{
public InnerParserException( Throwable _cause )
{
super( _cause );
}
}
}