cdc.applic.expressions.literals.LiteralUtils Maven / Gradle / Ivy
Show all versions of cdc-applic-expressions Show documentation
package cdc.applic.expressions.literals;
/**
* Utilities related to recognition of certain literals.
*
* @author Damien Carbonne
*/
public final class LiteralUtils {
private LiteralUtils() {
}
public static final char ESCAPE_CHAR = '"';
public static final char PATH_SEPARATOR = '.';
/**
* Returns {@code true} when a character is a digit.
*
* @param c The character
* @return {@code true} when {@code c} is a digit.
*/
public static boolean isDigit(char c) {
return c >= '0' && c <= '9';
}
/**
* Returns {@code true} when a character is either '+' or '-'.
*
* @param c The character
* @return {@code true} when {@code c} is either '+' or '-'.
*/
public static boolean isPlusMinus(char c) {
return c == '+' || c == '-';
}
public static boolean isOneOf(char c,
char c1,
char c2) {
return c == c1 || c == c2;
}
/**
* Returns {@code true} when a text represents a literal.
*
* It must be a non-{@code null}, non-empty text.
* It must not contain illegal characters ('~' and '|').
* WARNING: {@code text} must NOT be escaped.
*
* @param text The text.
* @return {@code true} when {@code text} represents a literal.
*/
public static boolean isLiteral(String text) {
return EscapingUtils.isLegalLiteral(text);
}
/**
* Returns {@code true} when a text literal is a boolean literal.
*
* WARNING: {@code text} must NOT be escaped.
*
* Pattern: {@code [Tt][Rr][Uu][Ee])|([Ff][Aa][Ll][Ss][Ee]}
*
* @param text The text.
* @return {@code true} when {@code text} is a boolean literal.
*/
public static boolean isBooleanLiteral(String text) {
if (text == null) {
return false;
} else {
return "true".equalsIgnoreCase(text) || "false".equalsIgnoreCase(text);
}
}
/**
* Returns {@code true} when a text represents an integer value literal.
*
* An Integer value literal contains at least one digit and only digits.
* It may start with '-' or '+'.
* WARNING: {@code text} must NOT be escaped.
*
* Pattern: {@code [+-]?[0-9]+}
*
* @param text The text.
* @return {@code true} when {@code text} represents an integer literal.
*/
public static boolean isIntegerLiteral(String text) {
if (text == null || text.isEmpty()) {
return false;
} else {
for (int index = 0; index < text.length(); index++) {
final char c = text.charAt(index);
if (index == 0) {
if (isPlusMinus(c)) {
if (text.length() == 1) {
return false;
}
} else if (!isDigit(c)) {
return false;
}
} else {
if (!isDigit(c)) {
return false;
}
}
}
return true;
}
}
/**
* Returns {@code true} when a text represents a real value literal.
*
* Pattern: {@code [+-]?[0-9]+[.][0-9]+([eE][+-]?[0-9]+)?}
*
* @param text The text.
* @return {@code true} when {@code text} represents a real literal.
*/
public static boolean isRealLiteral(String text) {
if (text == null || text.isEmpty()) {
return false;
} else {
final int length = text.length();
int pos = 0;
if (isPlusMinus(text.charAt(pos))) {
pos++;
}
final int begin0 = pos;
while (pos < length && isDigit(text.charAt(pos))) {
pos++;
}
if (pos == begin0) {
return false;
}
if (pos >= length || text.charAt(pos) != '.') {
return false;
} else {
pos++;
}
final int begin1 = pos;
while (pos < length && isDigit(text.charAt(pos))) {
pos++;
}
if (pos == begin1) {
return false;
}
if (pos >= length) {
return true;
}
if (text.charAt(pos) == 'e' || text.charAt(pos) == 'E') {
pos++;
}
if (pos >= length) {
return false;
}
if (isPlusMinus(text.charAt(pos))) {
pos++;
}
if (pos >= length) {
return false;
}
final int begin2 = pos;
while (pos < length && isDigit(text.charAt(pos))) {
pos++;
}
if (pos == begin2) {
return false;
}
return true;
}
}
/**
* Returns {@code true} when a text starts as a number.
*
* Pattern: {@code [+-]?[0-9].*}
*
* @param text The text.
* @return {@code true} when {@code text} starts as a number.
*/
public static boolean startsAsNumber(String text) {
if (text == null || text.isEmpty()) {
return false;
} else {
final int length = text.length();
int pos = 0;
if (isPlusMinus(text.charAt(pos))) {
pos++;
}
return pos < length && isDigit(text.charAt(pos));
}
}
/**
* Returns {@code true} when a text represents a special string literal (or, and, not, in, ...).
*
* Pattern:
* {@code ([iI][nN]) | ([oO][rR]) | ([tT][oO]) | ([nN][oO][tT]) | ([ii][fF][fF]) | ([aA][nN][dD]) | ([iI][mM][pP]) | ([xX][oO][rR])}
*
* WARNING: "not in" is not handled.
*
* @param text The text.
*
* @return {@code true} when {@code text} is a special string literal.
*/
public static boolean isSpecialStringLiteral(String text) {
if (text == null || text.isEmpty()) {
return false;
} else {
if (text.length() == 2) {
// in, or, to
final char c0 = text.charAt(0);
final char c1 = text.charAt(1);
return isOneOf(c0, 'i', 'I') && isOneOf(c1, 'n', 'N')
|| isOneOf(c0, 'o', 'O') && isOneOf(c1, 'r', 'R')
|| isOneOf(c0, 't', 'T') && isOneOf(c1, 'o', 'O');
} else if (text.length() == 3) {
// not, iff, and, imp
final char c0 = text.charAt(0);
final char c1 = text.charAt(1);
final char c2 = text.charAt(2);
return isOneOf(c0, 'n', 'N') && isOneOf(c1, 'o', 'O') && isOneOf(c2, 't', 'T')
|| isOneOf(c0, 'i', 'I') && isOneOf(c1, 'f', 'F') && isOneOf(c2, 'f', 'F')
|| isOneOf(c0, 'a', 'A') && isOneOf(c1, 'n', 'N') && isOneOf(c2, 'd', 'D')
|| isOneOf(c0, 'i', 'I') && isOneOf(c1, 'm', 'M') && isOneOf(c2, 'p', 'P')
|| isOneOf(c0, 'x', 'X') && isOneOf(c1, 'o', 'O') && isOneOf(c2, 'r', 'R');
} else {
return false;
}
}
}
/**
* Returns {@code true} when a text represents a restricted String value literal.
*
* It is neither a boolean, integer nor real.
* WARNING: literal must NOT be escaped.
*
* @param text The text.
* @return {@code true} when {@code text} represents a String value.
*/
public static boolean isRestrictedStringLiteral(String text) {
return isLiteral(text)
&& !isBooleanLiteral(text)
&& !isIntegerLiteral(text)
&& !isRealLiteral(text);
}
/**
* Returns the kind of a literal.
*
* WARNING: literal must NOT be escaped.
*
* @param text The text.
* @return The kind of {@code text}.
*/
public static LiteralKind getKind(String text) {
if (isBooleanLiteral(text)) {
return LiteralKind.BOOLEAN;
} else if (isIntegerLiteral(text)) {
return LiteralKind.INTEGER;
} else if (isRealLiteral(text)) {
return LiteralKind.REAL;
} else if (isLiteral(text)) {
return LiteralKind.RESTRICTED_STRING;
} else {
return LiteralKind.NONE;
}
}
}