Name.java
package Hoot.Runtime.Names;
import java.util.*;
import static Hoot.Runtime.Names.Keyword.Java;
import static Hoot.Runtime.Faces.Logging.*;
import static Hoot.Runtime.Functions.Utils.*;
/**
* Maps between Hoot Smalltalk selectors and Java method names.
*
* @author nik <nikboyd@sonic.net>
* @see "Copyright 2010,2021 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public class Name {
static final char DOT = '.';
static final String Dot = Operator.Dot;
static final String Escape = "\\";
static final char COLON = ':';
static final String Colon = ":";
static final char UNDER = '_';
static final String Under = "_";
static final char DOLLAR = '$';
static final String Dollar = "$";
public static final String Public = "public";
public static final String Protected = "protected";
public static final String Private = "private";
public static final String Transient = "transient";
public static final String Static = "static";
public static final String Abstract = "abstract";
public static final String Wrapped = "wrapped";
/**
* Internal meta member names.
*/
public static final String Metatype = "Metatype";
public static final String Metaclass = "Metaclass";
public static final String MetaMember = "$class";
static final List<String> ReservedWords = emptyList(String.class);
public static final Properties BinaryOperators = new Properties();
public static final char[] Vowels = { 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U' };
/**
* Initializes (reservedWords), (binaryOperators), (controlClasses).
*/
static {
ReservedWords.add("package");
ReservedWords.add("import");
ReservedWords.add("class");
ReservedWords.add("interface");
ReservedWords.add("if");
ReservedWords.add("else");
ReservedWords.add("while");
ReservedWords.add("new");
ReservedWords.add("return");
ReservedWords.add("do");
ReservedWords.add("case");
ReservedWords.add("continue");
ReservedWords.add("switch");
ReservedWords.add(Public);
ReservedWords.add(Private);
ReservedWords.add(Protected);
ReservedWords.add("synchronized");
ReservedWords.add("native");
ReservedWords.add("volatile");
ReservedWords.add(Static);
ReservedWords.add("null");
ReservedWords.add("byte");
ReservedWords.add("char");
ReservedWords.add("short");
ReservedWords.add("int");
ReservedWords.add("long");
ReservedWords.add("float");
ReservedWords.add("double");
BinaryOperators.put(":=", " = ");
BinaryOperators.put("^", "return");
BinaryOperators.put("@", "$at");
BinaryOperators.put(",", "$append");
BinaryOperators.put("&", "$and");
BinaryOperators.put("|", "$or");
BinaryOperators.put("+", "$plus");
BinaryOperators.put("-", "$minus");
BinaryOperators.put("+=", "$incremented");
BinaryOperators.put("-=", "$decremented");
BinaryOperators.put("*", "$times");
BinaryOperators.put("*=", "$magnified");
BinaryOperators.put("/", "$dividedBy");
BinaryOperators.put("/=", "$divided");
BinaryOperators.put("//", "$idiv");
BinaryOperators.put("\\", "$into");
BinaryOperators.put("\\\\", "$imod");
BinaryOperators.put("**", "$raised");
BinaryOperators.put("%", "$modulus");
BinaryOperators.put("<", "$lessThan");
BinaryOperators.put("<=", "$lessEqual");
BinaryOperators.put(">", "$moreThan");
BinaryOperators.put(">=", "$moreEqual");
BinaryOperators.put("=", "$equal");
BinaryOperators.put("~=", "$notEqual");
BinaryOperators.put("==", "$is");
BinaryOperators.put("~~", "$isnt");
BinaryOperators.put(">>", "$associateWith");
BinaryOperators.put("$at", "@");
BinaryOperators.put("$append", ",");
BinaryOperators.put("$and", "&");
BinaryOperators.put("$or", "|");
BinaryOperators.put("$plus", "+");
BinaryOperators.put("$minus", "-");
BinaryOperators.put("$incremented", "+=");
BinaryOperators.put("$decremented", "-=");
BinaryOperators.put("$times", "*");
BinaryOperators.put("$magnified", "*=");
BinaryOperators.put("$dividedBy", "/");
BinaryOperators.put("$divided", "/=");
BinaryOperators.put("$idiv", "//");
BinaryOperators.put("$into", "\\");
BinaryOperators.put("$imod", "\\\\");
BinaryOperators.put("$raised", "**");
BinaryOperators.put("$modulus", "%");
BinaryOperators.put("$lessThan", "<");
BinaryOperators.put("$lessEqual", "<=");
BinaryOperators.put("$moreThan", ">");
BinaryOperators.put("$moreEqual", ">=");
BinaryOperators.put("$equal", "=");
BinaryOperators.put("$notEqual", "~=");
BinaryOperators.put("$is", "==");
BinaryOperators.put("$isnt", "~~");
BinaryOperators.put("$associateWith", ">>");
}
/**
* @return a primitive String
* @param selector a Hoot selector
*/
public static String from(String selector) {
String op = BinaryOperators.getProperty(selector);
if (op != null) {
return op;
}
int tail = selector.length() - 1;
while (tail > 0 && selector.charAt(tail) == COLON) {
tail--;
}
selector = selector.substring(0, tail + 1);
selector = selector.replace(COLON, UNDER);
if (ReservedWords.contains(selector)) {
selector = Dollar + selector;
}
return selector;
}
/**
* @return a selector
* @param methodName the name of a Java method.
* @param argumentCount the number of method arguments.
*/
public static String from(String methodName, int argumentCount) {
String op = BinaryOperators.getProperty(methodName);
if (op != null) {
return op;
}
if (methodName.startsWith(Dollar)) {
methodName = methodName.substring(1);
}
methodName = methodName.replace(UNDER, COLON);
if (argumentCount > 0) {
methodName = methodName + Colon;
}
return methodName;
}
/**
* Returns the root package name from a (fully qualified) name.
* @param fullName a (fully qualified) name
* @return a root name if present, or empty
*/
public static String rootPackage(String fullName) {
String packageName = packageName(fullName);
if (!packageName.contains(Dot)) return packageName;
String[] parts = packageName.split(Escape + Dot);
return parts[0];
}
/**
* Returns the package name from a (fully qualified) name.
* @param fullName a (fully qualified) name
* @return a package name if present, or empty
*/
public static String packageName(String fullName) {
if (isEmpty(fullName)) return Empty;
fullName = Name.asMetaMember(fullName.trim());
if (!fullName.contains(Dot)) return Empty;
String[] parts = fullName.split(Escape + Dot);
String lastPart = parts[parts.length - 1];
if (Character.isLowerCase(lastPart.charAt(0)) &&
!Primitive.isPrimitiveType(lastPart)) return fullName;
int headLength = fullName.length() - lastPart.length();
return fullName.substring(0, headLength - 1);
}
/**
* Returns the full type name from a (fully qualified) name.
* @param fullName a (fully qualified) name
* @return a type name if present, or empty
*/
public static String typeName(String fullName) {
if (isEmpty(fullName)) return Empty;
fullName = Name.asMetaMember(fullName.trim());
if (!fullName.contains(Dot)) return fullName;
String[] parts = fullName.split(Escape + Dot);
String lastPart = parts[parts.length - 1];
if (Character.isLowerCase(lastPart.charAt(0)) &&
!Primitive.isPrimitiveType(lastPart)) return Empty;
return lastPart;
}
// public static boolean isSimple(String name) {
// if (isEmpty(name)) return false;
// if (isProper(name)) return false;
// return packageName(name).isEmpty();
// }
public static boolean isProper(String name) {
if (isEmpty(name)) return false;
return Character.isUpperCase(name.charAt(0));
}
public static boolean isQualified(String name) {
if (isEmpty(name)) return false;
return !packageName(name).isEmpty();
}
public static boolean isMetaNamed(String name) { return isMetaclassNamed(name) || isMetatypeNamed(name); }
public static boolean isMetaclassNamed(String name) { return !isEmpty(name) && name.endsWith(Metaclass); }
public static boolean isMetatypeNamed(String name) { return !isEmpty(name) && name.endsWith(Metatype); }
public static String asMetaMember(String name) {
if (isMetaclassNamed(name)) return name.replace(Dot + Metaclass, Dollar + Metaclass);
if (isMetatypeNamed(name)) return name.replace(Dot + Metatype, Dollar + Metatype);
return name; // not really a meta-member
}
public static String withoutMeta(String name) {
if (isMetaclassNamed(name)) return removeTail(name, Metaclass);
if (isMetatypeNamed(name)) return removeTail(name, Metatype);
return name; // not really a meta-member
}
public static String formType(String... names) {
return formType(wrap(names));
}
public static String formType(List<String> names) {
if (names.isEmpty()) return Empty;
String tailMost = names.get(names.size() - 1);
if (names.size() == 1) {
return Primitive.isPrimitiveType(tailMost) ?
tailMost.toLowerCase() : tailMost;
}
List<String> heads = names.subList(0, names.size() - 1);
String joinedHeads = joinWith(Dot, heads);
String joinedLowers = joinedHeads.toLowerCase();
String headMost = names.get(0);
String fullName = joinWith(Dot, names);
if (headMost.startsWith(Java)) {
String[] fullerNames = { joinedLowers, tailMost };
return joinWith(Dot, wrap(fullerNames));
}
return fullName;
}
public static String removeTail(String name, String tail) {
if (!name.endsWith(tail)) return name;
String result = name.substring(0, name.length() - tail.length());
if (result.endsWith(Dot)) result = result.substring(0, result.length() - 1);
if (result.endsWith(Dollar)) result = result.substring(0, result.length() - 1);
return result.trim(); // no tailing blank(s) either
}
} // Name