/****************************************************************************** * Copyright (c) 2016 Oracle * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance ******************************************************************************/ package org.eclipse.sapphire.modeling.el; import java.util.List; import org.eclipse.sapphire.LocalizableText; import org.eclipse.sapphire.Text; import org.eclipse.sapphire.util.ListFactory; /** * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public abstract class Function { @Text( "Function {0} missing operand {1}." ) private static LocalizableText missingOperandMessage; static { LocalizableText.init( Function.class ); } private Object origin; private boolean originInitialized; private List<Class<?>> signature; private List<Function> operands = ListFactory.empty(); public final void initSignature( final List<Class<?>> signature ) { this.signature = signature; } public final void init( final Function... operands ) { this.operands = ListFactory.unmodifiable( operands ); } public final void init( final List<Function> operands ) { this.operands = ListFactory.unmodifiable( operands ); } public final void initOrigin( final Object origin, final boolean applyToOperands ) { if( this.originInitialized ) { throw new IllegalStateException(); } this.origin = origin; if( applyToOperands ) { for( Function operand : this.operands ) { operand.initOrigin( origin, true ); } } } public final Object origin() { return this.origin; } public abstract String name(); public boolean operator() { return false; } public int precedence() { return 1; } public final List<Class<?>> signature() { return this.signature; } public final List<Function> operands() { return this.operands; } public final Function operand( final int position ) { if( position < this.operands.size() ) { return this.operands.get( position ); } else { throw new FunctionException( missingOperandMessage.format( getClass().getName(), String.valueOf( position ) ) ); } } public abstract FunctionResult evaluate( FunctionContext context ); @Override public final String toString() { final StringBuilder buf = new StringBuilder(); if( this instanceof Literal || this instanceof ConcatFunction ) { toString( buf, true ); } else { buf.append( "${ " ); toString( buf, false ); buf.append( " }" ); } return buf.toString(); } public void toString( final StringBuilder buf, final boolean topLevel ) { final String name = name(); if( operator() ) { final int precedence = precedence(); boolean first = true; boolean addOperatorBeforeNext = ( this.operands.size() == 1 ); for( Function operand : this.operands ) { if( addOperatorBeforeNext ) { if( first ) { first = false; } else { buf.append( ' ' ); } buf.append( name ); buf.append( ' ' ); } else { addOperatorBeforeNext = true; first = false; } final boolean parens = ( precedence < operand.precedence() ); if( parens ) { buf.append( "( " ); } operand.toString( buf, false ); if( parens ) { buf.append( " )" ); } } } else { buf.append( name ); buf.append( '(' ); if( ! this.operands.isEmpty() ) { boolean first = true; for( Function operand : this.operands ) { if( first ) { buf.append( ',' ); } else { first = false; } buf.append( ' ' ); operand.toString( buf, false ); } buf.append( ' ' ); } buf.append( ')' ); } } }