/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* 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.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.ml.prg.extension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.encog.EncogError;
import org.encog.ml.ea.exception.EACompileError;
import org.encog.ml.prg.EncogProgramContext;
import org.encog.ml.prg.ProgramNode;
import org.encog.ml.prg.expvalue.ValueType;
import org.encog.util.SimpleParser;
/**
* A basic template.
*/
public abstract class BasicTemplate implements ProgramExtensionTemplate {
/**
* The serial id.
*/
private static final long serialVersionUID = 1L;
/**
* The name of this opcode.
*/
private final String name;
/**
* True if this opcode has a variable value, other than variance of its
* child nodes.
*/
private final boolean varValue;
/**
* The amount of data that is stored with this node.
*/
private final int dataSize;
/**
* The node type.
*/
private final NodeType nodeType;
/**
* The precedence.
*/
private final int precedence;
/**
* The opcode signature.
*/
private final String signature;
/**
* The parameters.
*/
private final List<ParamTemplate> params = new ArrayList<ParamTemplate>();
/**
* The return value.
*/
private final ParamTemplate returnValue;
/**
* Construct a basic template object.
*
* @param thePrecedence
* The precedence.
* @param theSignature
* The opcode signature.
* @param theType
* The opcode type.
* @param isVariable
* True, if this opcode is a variable.
* @param theDataSize
* The data size kept for this opcode.
*/
public BasicTemplate(final int thePrecedence, final String theSignature,
final NodeType theType, final boolean isVariable,
final int theDataSize) {
this.precedence = thePrecedence;
this.signature = theSignature;
this.varValue = isVariable;
this.dataSize = theDataSize;
this.nodeType = theType;
if (theSignature.trim().equals("(")) {
// special case, we add a left-paren for the shunting yard alg.
this.name = theSignature;
this.returnValue = null;
} else {
// non-special case, find the name of the function/operator
final SimpleParser parser = new SimpleParser(theSignature);
boolean pass = false;
parser.eatWhiteSpace();
this.name = parser.readToChars("(").trim();
parser.advance();
boolean done = false;
while (!done) {
if (parser.peek() == ')') {
parser.advance();
done = true;
} else if (parser.peek() == ':') {
parser.advance();
pass = true;
} else if (parser.peek() == '{') {
final ParamTemplate temp = readParam(parser);
temp.setPassThrough(pass);
pass = false;
this.params.add(temp);
} else {
parser.advance();
if( parser.eol() ) {
throw new EncogError("Invalid opcode template.");
}
}
}
// get the return type
parser.eatWhiteSpace();
if (!parser.lookAhead(":")) {
throw new EACompileError("Return type not specified.");
}
parser.advance();
parser.eatWhiteSpace();
this.returnValue = readParam(parser);
}
}
/**
* Construct a function based on the provided signature.
*
* @param theSignature
* The signature.
*/
public BasicTemplate(final String theSignature) {
this(0, theSignature, NodeType.Function, false, 0);
}
/**
* {@inheritDoc}
*/
@Override
public int getChildNodeCount() {
return this.params.size();
}
/**
* {@inheritDoc}
*/
@Override
public int getDataSize() {
return this.dataSize;
}
/**
* {@inheritDoc}
*/
@Override
public String getName() {
return this.name;
}
/**
* {@inheritDoc}
*/
@Override
public NodeType getNodeType() {
return this.nodeType;
}
/**
* {@inheritDoc}
*/
@Override
public List<ParamTemplate> getParams() {
return this.params;
}
/**
* {@inheritDoc}
*/
@Override
public int getPrecedence() {
return this.precedence;
}
/**
* {@inheritDoc}
*/
@Override
public ParamTemplate getReturnValue() {
return this.returnValue;
}
/**
* @return the signature
*/
public String getSignature() {
return this.signature;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isPossibleReturnType(final EncogProgramContext context,
final ValueType rtn) {
return this.returnValue.getPossibleTypes().contains(rtn);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isVariable() {
return this.varValue;
}
/**
* {@inheritDoc}
*/
@Override
public void randomize(final Random rnd, final List<ValueType> desiredTypes,
final ProgramNode actual, final double minValue,
final double maxValue) {
}
/**
* Read the specified parameter.
*
* @param parser
* The parser to use.
* @return The parsed parameter.
*/
private ParamTemplate readParam(final SimpleParser parser) {
final ParamTemplate result = new ParamTemplate();
if (!parser.lookAhead("{")) {
throw new EACompileError("Expected {");
}
parser.advance();
boolean done = false;
final StringBuilder buffer = new StringBuilder();
while (!done) {
if (parser.peek() == '}') {
done = true;
parser.advance();
} else if (parser.peek() == '{') {
throw new EACompileError("Unexpected {");
} else if (parser.peek() == '{') {
done = true;
parser.advance();
} else if (parser.peek() == ',') {
result.addType(buffer.toString().trim().toLowerCase());
parser.advance();
buffer.setLength(0);
} else {
buffer.append(parser.readChar());
}
}
final String s = buffer.toString().trim();
if (s.length() > 0) {
result.addType(s);
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
result.append("[BasicTemplate:");
result.append(this.signature);
result.append(",type=");
result.append(this.nodeType.toString());
result.append(",argCount=");
result.append(getChildNodeCount());
result.append("]");
return result.toString();
}
}