Newer
Older
DesignCraft / src / main / java / models / algebra / Symbol.java
package models.algebra;

import java.util.List;

import models.algebra.Symbol.IImplGenerator;
import models.algebra.Symbol.Type;

public class Symbol {
	protected String name;
	protected int arity = 0;			// -1: variable number
	protected Type operatorType = Type.PREFIX;
	protected Symbol[] inverses = null;
	protected models.algebra.Type[] signature = null;
	protected ICalculator calculator = null;
	protected SymbolImpl symbolImpl = null;
	
	public Symbol(String name) {
		this.name = name;
		this.arity = 0;
		this.symbolImpl = new SymbolImpl(name);
	}
	
	public Symbol(String name, int arity) {
		this.name = name;
		this.arity = arity;
		this.symbolImpl = new SymbolImpl(name, arity);
	}
	
	public Symbol(String name, int arity, Type operatorType) {
		this.name = name;
		this.arity = arity;
		this.operatorType = operatorType;
		this.symbolImpl = new SymbolImpl(name, arity, operatorType);
	}
	
	public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType) {
		this.name = name;
		this.arity = arity;
		this.operatorType = operatorType;
		this.symbolImpl = new SymbolImpl(implName, arity, implOperatorType);
	}
	
	public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, int[] implParamOrder) {
		this(name, arity, operatorType, implName, implOperatorType);
		this.symbolImpl.setImplParamOrder(implParamOrder);
	}
	
	public Symbol(String name, int arity, Type operatorType, IImplGenerator generator) {
		this(name, arity, operatorType, name, Type.GENERATIVE);
		this.symbolImpl.setGenerator(generator);
	}
	
	public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, boolean bSideEffect) {
		this(name, arity, operatorType, name, Type.GENERATIVE);
		this.symbolImpl.setGenerator(generator);
		if (bSideEffect) {
			this.symbolImpl.setImplOperatorType(Type.GENERATIVE_WITH_SIDE_EFFECT);
		}
	}
	
	public Symbol(String name, int arity, ICalculator calculator) {
		this(name, arity);
		this.calculator = calculator;
	}
	
	public Symbol(String name, int arity, Type operatorType, ICalculator calculator) {
		this(name, arity, operatorType, name, operatorType);
		this.calculator = calculator;
	}
	
	public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, ICalculator calculator) {
		this(name, arity, operatorType, name, Type.GENERATIVE);
		this.calculator = calculator;
		this.symbolImpl.setGenerator(generator);
	}
	
	public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, ICalculator calculator) {
		this(name, arity, operatorType, implName, implOperatorType);
		this.calculator = calculator;
	}
	
	public void setArity(int arity) {
		this.arity = arity;
	}

	public int getArity() {
		return arity;
	}

	public String getName() {
		return name;
	}
	
	public void changeName(String name) {
		this.name = name;
		this.symbolImpl.setImplName(name);
	}

	public Type getOperatorType() {
		return operatorType;
	}
	
	public boolean isInfix() {
		return (operatorType == Type.INFIX);
	}
	
	public boolean isMethod() {
		return (operatorType == Type.METHOD || operatorType == Type.METHOD_WITH_SIDE_EFFECT);
	}
	
	public boolean isLambda() {
		return (operatorType == Type.LAMBDA);
	}

	public Symbol[] getInverses() {
		return inverses;
	}

	public void setInverses(Symbol[] inverses) {
		this.inverses = inverses;
	}

	public models.algebra.Type[] getSignature() {
		return signature;
	}

	public void setSignature(models.algebra.Type[] signature) {
		this.signature = signature;
	}

	public String getImplName() {
		return symbolImpl.getImplName();
	}

	public void setImplName(String implName) {
		this.symbolImpl.setImplName(implName);
	}

	public Type getImplOperatorType() {
		return symbolImpl.getImplOperatorType();
	}
	
	public boolean isImplInfix() {
		return (symbolImpl.getImplOperatorType() == Type.INFIX);
	}
	
	public boolean isImplMethod() {
		return (symbolImpl.getImplOperatorType() == Type.METHOD || symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT);
	}
	
	public boolean isImplLambda() {
		return (symbolImpl.getImplOperatorType() == Type.LAMBDA || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT);
	}
	
	public boolean isImplGenerative() {
		return (symbolImpl.getImplOperatorType() == Type.GENERATIVE || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT);
	}
	
	public boolean isImplWithSideEffect() {
		return (symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT 
				|| symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT 
				|| symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT);
	}

	public void setImplOperatorType(Type implOperatorType) {
		this.symbolImpl.setImplOperatorType(implOperatorType);
	}
	
	public int[] getImplParamOrder() {
		return symbolImpl.getImplParamOrder();
	}
	
	public void setGenerator(IImplGenerator generator) {
		this.symbolImpl.setGenerator(generator); 
	}
	
	/**
	 * Generate the implementation of this symbol
	 * @param type the type of this symbol
	 * @param childrenTypes 
	 * @param childrenImpl the implementations of the children
	 * @param childrenSideEffects (input) an array of the side effects of the children
	 * @param sideEffect (output) an array of the side effect of this symbol
	 * @return the implementation
	 */
	public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) {
		if (symbolImpl.getGenerator() != null) {
			return symbolImpl.getGenerator().generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect);
		}
		return null;
	}
	
	public boolean isCalculatable() {
		return (calculator != null);
	}
	
	public Expression calculate(List<Expression> args) {
		if (calculator != null) {
			return calculator.calculate(args);
		}
		return null;
	}

	public boolean equals(Object another) {
		if (!(another instanceof Symbol)) return false;
		return name.equals(((Symbol) another).name) && arity == ((Symbol) another).arity;
	}
	
	@Override
	public int hashCode() {
		return name.hashCode();
	}
	
	public String toString() {
		return name;
	}
	
	public String toImplementation() {
		return symbolImpl.getImplName();
	}
	
	public enum Type {
		PREFIX,
		INFIX,
		METHOD,
		METHOD_WITH_SIDE_EFFECT,
		LAMBDA,
		LAMBDA_WITH_SIDE_EFFECT,
		GENERATIVE,
		GENERATIVE_WITH_SIDE_EFFECT
	}
	
	public static class SymbolImpl {
		private String implName;
		protected int implArity = 0;			// -1: variable number
		private Type implOperatorType;
		private int[] implParamOrder;
		private IImplGenerator generator;
		
		public SymbolImpl(String implName) {
			this.implName = implName;
			this.implArity = 0;
		}
		
		public SymbolImpl(String implName, int implArity) {
			this.implName = implName;
			this.implArity = implArity;
		}
		
		public SymbolImpl(String implName, int implArity, Type implOperatorType) {
			this(implName, implArity);
			this.implOperatorType = implOperatorType;
		}

		public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder) {
			this(implName, implArity, implOperatorType);
			this.implParamOrder = implParamOrder;
		}

		public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder, IImplGenerator generator) {
			this(implName, implArity, implOperatorType, implParamOrder);
			this.generator = generator;
		}

		public String getImplName() {
			return implName;
		}

		public void setImplName(String implName) {
			this.implName = implName;
		}

		public Type getImplOperatorType() {
			return implOperatorType;
		}

		public void setImplOperatorType(Type implOperatorType) {
			this.implOperatorType = implOperatorType;
		}

		public int[] getImplParamOrder() {
			return implParamOrder;
		}

		public void setImplParamOrder(int[] implParamOrder) {
			this.implParamOrder = implParamOrder;
		}

		public IImplGenerator getGenerator() {
			return generator;
		}

		public void setGenerator(IImplGenerator generator) {
			this.generator = generator;
		}
	}
	
	public Memento createMemento() {
		return new Memento(symbolImpl.getImplName(), symbolImpl.getImplOperatorType());
	}
	
	public void setMemento(Memento memento) {
		this.symbolImpl.setImplName(memento.implName);
		this.symbolImpl.setImplOperatorType(memento.implOperatorType);
	}
	
	public static class Memento {
		private String implName;
		private Type implOperatorType = Type.PREFIX;
		
		public Memento(String implName, Type implOperatorType) {
			this.implName = implName;
			this.implOperatorType = implOperatorType;
		}
	}
	
	public interface IImplGenerator {
		/**
		 * Generate the implementation
		 * @param type the type of this expression
		 * @param childrenTypes 
		 * @param children the implementations of the children
		 * @param childrenSideEffects (input) an array of the side effects of the children
		 * @param sideEffect (output) an array of the side effect of this generator
		 * @return the generated implementation
		 */
		public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String children[], String[] childrenSideEffects, String[] sideEffect);
	}
	
	public interface ICalculator {
		public Expression calculate(List<Expression> args);
	}
}