ArduinoAttrConstraints.java
/*******************************************************************************
* jArduino: Arduino C++ Code Generation From Java
* Copyright 2020 Tony Washer
*
* 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 net.sourceforge.jarduino.message;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;
/**
* Attribute constraints.
*/
public interface ArduinoAttrConstraints {
/**
* Check valid value.
* @param pValue the value.
* @return corrected value
* @throws ArduinoParserException on error
*/
Object checkValue(Object pValue) throws ArduinoParserException;
/**
* Value Constraints.
*/
class ArduinoAttrValueConstraints
implements ArduinoAttrConstraints {
/**
* The minimum value.
*/
private Number theMinimum;
/**
* The maximum value.
*/
private Number theMaximum;
/**
* Constructor.
* @param pMinimum the minimum
* @param pMaximum the maximum
*/
ArduinoAttrValueConstraints(final Number pMinimum,
final Number pMaximum) {
/* Store values */
theMinimum = pMinimum;
theMaximum = pMaximum;
}
/**
* Obtain the minimum.
* @return the minimum
*/
Number getMinimum() {
return theMinimum;
}
/**
* Obtain the maximum.
* @return the maximum
*/
Number getMaximum() {
return theMaximum;
}
@Override
public Object checkValue(final Object pValue) throws ArduinoParserException {
/* Must be a Number */
final Number myValue = (Number) pValue;
/* Check min and max values */
final boolean invalid = theMinimum instanceof Double
? myValue.doubleValue() < theMinimum.doubleValue()
|| myValue.doubleValue() > theMaximum.doubleValue()
: myValue.longValue() < theMinimum.longValue()
|| myValue.longValue() > theMaximum.longValue();
/* throw exception if not valid */
if (invalid) {
throw new ArduinoParserException("Attribute breaks constraints", myValue.toString());
}
/* Just return the value */
return pValue;
}
/**
* parse the constraints.
* @param pAttr the attribute
* @param pConstDef the constraints definition
* @return the parsed constraints (null if unbounded)
* @throws ArduinoParserException on error
*/
static ArduinoAttrValueConstraints parseConstraints(final ArduinoAttribute pAttr,
final String pConstDef) throws ArduinoParserException {
/* Minimum is first token, Maximum second */
final String myMinDef = ArduinoParser.nextToken(pConstDef);
final String myMaxDef = ArduinoParser.stripToken(pConstDef, myMinDef);
/* Parse the values */
Number myMin = ArduinoParser.parseNumber(myMinDef);
Number myMax = ArduinoParser.parseNumber(myMaxDef);
/* Make sure that if either value is double, both are */
if (myMin.getClass() != myMax.getClass()) {
/* Convert longs to doubles */
if (myMin instanceof Long) {
myMin = myMin.doubleValue();
}
if (myMax instanceof Long) {
myMax = myMax.doubleValue();
}
}
/* Return constraints */
return ArduinoSignalRange.isZero(myMin) && ArduinoSignalRange.isZero(myMax)
? null
: new ArduinoAttrValueConstraints(myMin, myMax);
}
}
/**
* Enum Constraints.
*/
class ArduinoAttrEnumConstraints
implements ArduinoAttrConstraints {
/**
* The list of enum values.
*/
private final List<String> theValues;
/**
* Constructor.
* @param pValues teh values
*/
ArduinoAttrEnumConstraints(final List<String> pValues) {
theValues = pValues;
}
/**
* Obtain the values.
* @return the values
*/
List<String> getValues() {
return theValues;
}
@Override
public Object checkValue(final Object pValue) throws ArduinoParserException {
/* If the value is a number */
if (pValue instanceof Long) {
final long myValue = (Long) pValue;
if (myValue < 0 || myValue >= theValues.size()) {
throw new ArduinoParserException("Attribute out of range for enum", pValue.toString());
}
return theValues.get((int) myValue);
}
/* Value must be a string */
final String myValue = (String) pValue;
/* Check that this is a valid enum */
if (!theValues.contains(myValue)) {
/* If the value is empty, try for the first enum */
if (myValue.length() == 0 && !theValues.isEmpty()) {
return theValues.get(0);
}
throw new ArduinoParserException("Attribute not valid enum", myValue);
}
/* Just return the value */
return pValue;
}
/**
* parse the constraints.
* @param pConstDef the constraints definition
* @return the parsed constraints
* @throws ArduinoParserException on error
*/
static ArduinoAttrConstraints parseConstraints(final String pConstDef) throws ArduinoParserException {
/* Create the value list */
final List<String> myEnums = new ArrayList<>();
/* Loop through the tokens */
String myValues = pConstDef;
while (myValues.length() > 0) {
/* Split on comma separator */
final int myIndex = myValues.indexOf(ArduinoChar.COMMA);
if (myIndex == -1) {
myEnums.add(ArduinoParser.nextQuotedToken(myValues));
return new ArduinoAttrEnumConstraints(myEnums);
}
final String myValue = myValues.substring(0, myIndex).trim();
myEnums.add(ArduinoParser.nextQuotedToken(myValue));
myValues = myValues.substring(myIndex + 1);
}
return new ArduinoAttrEnumConstraints(myEnums);
}
}
/**
* parse the constraints.
* @param pAttr the attribute
* @param pConstDef the constraints definition
* @return the parsed constraints (null if unbounded)
* @throws ArduinoParserException on error
*/
static ArduinoAttrConstraints parseConstraints(final ArduinoAttribute pAttr,
final String pConstDef) throws ArduinoParserException {
/* Switch on attribute type */
switch (pAttr.getAttrType()) {
case INT:
case HEX:
case FLOAT:
return ArduinoAttrValueConstraints.parseConstraints(pAttr, pConstDef);
case ENUM:
return ArduinoAttrEnumConstraints.parseConstraints(pConstDef);
default:
return null;
}
}
}