/**
* Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de>
*
* Licensed 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 de.codesourcery.jasm16.ast;
import org.apache.commons.lang.ObjectUtils;
import de.codesourcery.jasm16.compiler.ICompilationContext;
import de.codesourcery.jasm16.compiler.ISymbolTable;
import de.codesourcery.jasm16.exceptions.ParseException;
import de.codesourcery.jasm16.lexer.IToken;
import de.codesourcery.jasm16.lexer.TokenType;
import de.codesourcery.jasm16.parser.IParseContext;
import de.codesourcery.jasm16.parser.Operator;
import de.codesourcery.jasm16.utils.ITextRegion;
/**
* AST node that represents an operator along with it's operands.
*
* @author tobias.gierke@code-sourcery.de
*/
public class OperatorNode extends TermNode
{
private Operator operator;
public OperatorNode() {
}
public OperatorNode(Operator op,ASTNode term1,IParseContext context)
{
if ( op == null ) {
throw new IllegalArgumentException("op must not be NULL.");
}
if ( term1 == null ) {
throw new IllegalArgumentException("term1 must not be NULL.");
}
if ( op.isInfixOperator() ) {
throw new IllegalArgumentException("Cannot use infix operator "+op+" with only one term");
}
this.operator = op;
addChild( term1 , context );
}
@Override
public boolean equals(Object obj)
{
if ( obj == this ) {
return true;
}
if ( obj instanceof OperatorNode) {
return ObjectUtils.equals( operator , ((OperatorNode) obj).operator ) ;
}
return false;
}
public OperatorNode(Operator operator, ASTNode term1,ASTNode term2,ITextRegion foldedTextRegion)
{
super( foldedTextRegion );
if ( operator == null ) {
throw new IllegalArgumentException("operator must not be NULL");
}
this.operator = operator;
addChild( term1 , null );
addChild( term2 , null );
}
public boolean hasAllRequiredArguments() {
return getTermCount() == this.operator.getRequiredOperandCount();
}
@Override
protected ASTNode parseInternal(IParseContext context) throws ParseException
{
final IToken tok = context.read("expected an operator",TokenType.OPERATOR);
mergeWithAllTokensTextRegion( tok );
if ( ! Operator.isValidOperator( tok.getContents() ) )
{
throw new ParseException("Invalid operator '"+tok.getContents()+"'", tok );
}
this.operator = Operator.fromString( tok.getContents() );
return this;
}
public Operator getOperator() {
return operator;
}
public boolean isNumberTerm(int termIndex) {
return getTerm( termIndex ) instanceof NumberNode;
}
public boolean isRegisterReference(int termIndex)
{
return getTerm( termIndex ) instanceof RegisterReferenceNode;
}
public int getTermCount()
{
int count = 0;
for ( ASTNode child : getChildren() ) {
if ( ExpressionNode.isTermNode( child ) ) {
count++;
}
}
return count;
}
public TermNode getTerm1()
{
return getTerm(0);
}
public TermNode getTerm2()
{
return getTerm(1);
}
public TermNode getTerm(int index) throws RuntimeException
{
int count = 0;
for ( ASTNode child : getChildren() ) {
if ( ExpressionNode.isTermNode( child ) ) {
if ( count == index ) {
return (TermNode) child;
}
count++;
}
}
return null;
}
@Override
public String toString()
{
if ( getOperator() == null ) {
return "?? NULL operator ??";
}
return getOperator().getLiteral();
// if ( ! hasChildren() ) {
// return getOperator().getLiteral()+" ( no children )";
// }
// if ( getOperator().isPrefixOperator() )
// {
// if ( getOperator() == Operator.PARENS ) {
// return "( "+child(0)+" )";
// }
// return getOperator()+""+child(0);
// } else if ( getOperator().isPostfixOperator() ) {
// return child(0)+""+getOperator().getLiteral();
// }
// if ( getChildCount() < 2 ) {
// return child(0)+" "+getOperator().getLiteral()+" <missing operand>";
// }
// return child(0)+" "+getOperator().getLiteral()+" "+child(1);
}
@Override
public TermNode reduce(ICompilationContext context)
{
return operator.fold( context , this );
}
@Override
protected OperatorNode copySingleNode()
{
final OperatorNode result = new OperatorNode();
result.operator = operator;
return result;
}
@Override
public boolean supportsChildNodes() {
return true;
}
@Override
public Long calculate(ISymbolTable symbolTable) {
return operator.calculate( symbolTable, this );
}
}