ParseUtil.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.aadl2.parsesupport;
import java.util.HashMap;
import java.util.Map;
public class ParseUtil {
private static final char UNDERLINE = '_';
private static final char HASHMARK = '#';
private static final char EXPONENT = 'E';
private static final char PLUS = '+';
private static final char MINUS = '-';
private static Map<String, String> annexNS = new HashMap<String, String>();
/**
* Trick to get rid of an additional dependency to annexsupport
* @param annexName
* @param annexNSName
*/
public static void setAnnexNS(String annexName, String annexNSName) {
if ((annexName != null) && (annexNSName != null)) {
// OsateDebug.osateDebug("called setAnnexNSURI with " + annexName + annexNSName);
annexName = annexName.toLowerCase();
if (annexNS.get(annexName) == null) {
annexNS.put(annexName, annexNSName);
}
}
}
public static String getAnnexNS(String annexName) {
String ns;
annexName = annexName.toLowerCase();
ns = annexNS.get(annexName);
// if ((annexName!=null) && (ns != null))
// {
// OsateDebug.osateDebug("called getAnnexNSURI with " + annexName + ns);
// }
return ns;
}
/**
* Parse a string representation of an aadlinteger.
* @param stringValue The string to parse.
* @return An array of length 2: the first element is the base
* and the second element is the value.
* @exception IllegalArgumentException thrown if there is some kind of
* parsing error.
*/
public static long[] parseAadlInteger(final String stringValue) {
/*
* First remove '_', convert to upper case, get as char[]. We assume
* the result still has at least one 1 character in it. (Should have
* at least one digit in it and have no '.' in it; otherwise the
* parser/lexer failed us).
*/
final char[] valueAsChars = normalizeValue(stringValue).toCharArray();
// Get the sign
int currentIdx = 0;
final boolean isNegative;
if (valueAsChars[0] == PLUS) {
isNegative = false;
currentIdx = 1;
} else if (valueAsChars[0] == MINUS) {
isNegative = true;
currentIdx = 1;
} else {
isNegative = false;
}
// Process as base 10 until we hit end of string, 'E' or '#'
long value = 0L;
for (; currentIdx < valueAsChars.length; currentIdx++) {
final char c = valueAsChars[currentIdx];
if (c == EXPONENT || c == HASHMARK) {
break;
} else if ('0' <= c && c <= '9') {
value = (value * 10) + Character.digit(c, 10);
if (value < 0) {
throw new IllegalArgumentException("Integer value is not representable");
}
} else {
throw new IllegalArgumentException("Unexpected character '" + c + "' at string index " + currentIdx);
}
}
final int base;
if (currentIdx == valueAsChars.length) {
// Hit end of string, it's a simple decimal integer
base = 10;
} else {
if (valueAsChars[currentIdx] == EXPONENT) {
// Decimal integer with exponent
base = 10;
} else {
// based_integer
base = (int) value;
if (base < 2 || base > 16) { // base is bad
throw new IllegalArgumentException("Base not between 2 and 16: " + base);
} else { // base is good
value = 0L;
char c = valueAsChars[++currentIdx];
while (c != HASHMARK) {
final int digit = Character.digit(c, base);
if (digit == -1) {
throw new IllegalArgumentException("'" + c + "' at string index " + currentIdx
+ " is not an extended digit in base " + base);
} else {
value = (value * base) + digit;
if (value < 0) {
throw new IllegalArgumentException("Integer value is not representable");
}
}
c = valueAsChars[++currentIdx];
}
// eat hashmark
currentIdx += 1;
}
}
// eat the 'e'; based integers don't have to have an exponent
if (++currentIdx < valueAsChars.length) {
// deal with sign
char c = valueAsChars[currentIdx];
if (c == MINUS) {
throw new IllegalArgumentException("Integers cannot have a negative exponent");
} else if (c == PLUS) {
currentIdx += 1;
}
int exponent = 0;
while (currentIdx < valueAsChars.length) {
c = valueAsChars[currentIdx++];
if ('0' <= c && c <= '9') {
exponent = (exponent * 10) + Character.digit(c, 10);
if (exponent < 0) {
throw new IllegalArgumentException(
"Integer value is not representable: cannot represent exponent");
}
} else {
throw new IllegalArgumentException(
"Unexpected character '" + c + "' at string index " + currentIdx);
}
}
for (int i = 0; i < exponent; i++) {
value *= base;
if (value < 0) {
throw new IllegalArgumentException("Integer value is not representable");
}
}
}
}
if (isNegative) {
value = -value;
}
return new long[] { base, value };
}
/**
* Parse a string representation of an aadlreal.
*
* @param stringValue
* The real value to resolve.
* @return The value
* @exception IllegalArgumentException Thrown if the value is not
* parsable into an aadlreal value.
*/
public static double parseAadlReal(final String stringValue) {
try {
return Double.parseDouble(normalizeValue(stringValue));
} catch (final NumberFormatException e) {
throw new IllegalArgumentException("Couldn't resolve literal: " + e.getMessage());
}
}
/**
* Remove the underlines, “ <code>_</code>,” from the numeric
* literal and forces letters to be uppercase.
*
* @param value
* The string to process
* @return The provided string with all the underlines removed.
*/
private static String normalizeValue(final String value) {
int nextUnderlineLoc = value.indexOf(UNDERLINE);
if (nextUnderlineLoc == -1) {
return value.toUpperCase();
} else {
// size of the new string <= size of value
final StringBuffer working = new StringBuffer(value.length());
int lastUnderlineLoc = 0;
// already found the first underscore...
do {
working.append(value.substring(lastUnderlineLoc, nextUnderlineLoc).toUpperCase());
lastUnderlineLoc = nextUnderlineLoc + 1;
nextUnderlineLoc = value.indexOf(UNDERLINE, lastUnderlineLoc);
} while (nextUnderlineLoc != -1);
// append the last portion of the string
working.append(value.substring(lastUnderlineLoc));
return working.toString();
}
}
}