in gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java [1002:1854]
private Object expandVar(boolean rawVariable) throws Exception
{
assert '$' == ch;
Object val = null;
short sLine = line;
short sCol = column;
if (getch() != '{')
{
if ('(' == ch)
{ // support $(...) FELIX-2433
int start = index - 1;
find(')', '(');
Token p = text.subSequence(start, index);
val = evaluate.eval(new Parser(p).sequence());
getch();
}
else
{
int start = index - 1;
while (isName(ch))
{
getch();
}
if (index - 1 == start)
{
val = "$";
}
else
{
String name = text.subSequence(start, index - 1).toString();
val = evaluate.get(name);
this.rawVariable = rawVariable;
}
}
}
else
{
getch();
// unique flag
boolean flagu = false;
// sort flags
boolean flago = false;
boolean flagO = false;
boolean flaga = false;
boolean flagi = false;
boolean flagn = false;
// map flags
boolean flagk = false;
boolean flagv = false;
// param flags
boolean flagP = false;
// case transformation flags
boolean flagC = false;
boolean flagL = false;
boolean flagU = false;
// pattern flags
boolean flagG = false;
// expand flag
boolean flagExpand = false;
// visible chars
boolean flagV = false;
// codepoint
boolean flagSharp = false;
// quoting
int flagq = 0;
boolean flagQ = false;
// split / join
String flags = null;
String flagj = null;
// pattern
boolean flagPattern = false;
// length
boolean computeLength = false;
// Parse flags
if (ch == '(') {
getch();
boolean flagp = false;
while (ch != EOT && ch != ')')
{
switch (ch)
{
case 'u':
flagu = true;
break;
case 'p':
flagp = true;
break;
case 'f':
flags = "\n";
break;
case 'F':
flagj = "\n";
break;
case 's':
case 'j': {
char opt = ch;
char c = getch();
if (c == EOT)
{
throw new IllegalArgumentException("error in flags");
}
int start = index;
while (true)
{
char n = getch();
if (n == EOT)
{
throw new IllegalArgumentException("error in flags");
}
else if (n == c)
{
break;
}
}
String s = text.subSequence(start, index - 1).toString();
if (flagp)
{
s = ansiEscape(s).toString();
}
if (opt == 's')
{
flags = s;
}
else if (opt == 'j')
{
flagj = s;
}
else
{
throw new IllegalArgumentException("error in flags");
}
flagp = false;
break;
}
case 'q':
if (flagq != 0)
{
throw new IllegalArgumentException("error in flags");
}
flagq = 1;
if (peek() == '-')
{
flagq = -1;
getch();
}
else
{
while (peek() == 'q')
{
getch();
flagq++;
}
if (peek() == '-')
{
throw new IllegalArgumentException("error in flags");
}
}
break;
case 'Q':
flagQ = true;
break;
case '#':
flagSharp = true;
break;
case 'V':
flagV = true;
break;
case 'o':
flago = true;
break;
case 'O':
flagO = true;
break;
case 'a':
flaga = true;
break;
case 'i':
flagi = true;
break;
case 'n':
flagn = true;
break;
case 'P':
flagP = true;
break;
case '@':
flagExpand = true;
break;
case 'G':
flagG = true;
break;
case 'k':
flagk = true;
break;
case 'v':
flagv = true;
break;
case 'C':
flagC = true;
flagL = false;
flagU = false;
break;
case 'L':
flagC = false;
flagL = true;
flagU = false;
break;
case 'U':
flagC = false;
flagL = false;
flagU = true;
break;
default:
throw new SyntaxError(line, column, "unsupported flag: " + ch);
}
getch();
}
getch();
}
// Map to List conversion
final boolean _flagk = flagk;
final boolean _flagv = flagv;
final Function<Object, Object> toCollection = new Function<Object, Object>() {
@Override
public Object apply(Object v) {
return v instanceof Map
? toList(asMap(v), _flagk, _flagv)
: v != null && v.getClass().isArray()
? Arrays.asList((Object[]) v)
: v;
}
};
//
// String transformations
//
final BiFunction<Function<String, String>, Object, Object> stringApplyer = new BiFunction<Function<String, String>, Object, Object>() {
@Override
public Object apply(Function<String, String> func, Object v) {
v = toCollection.apply(v);
if (v instanceof Collection)
{
List<String> l = new ArrayList<>();
for (Object i : asCollection(v)) {
l.add(func.apply(String.valueOf(i)));
}
return l;
}
else if (v != null)
{
return func.apply(v.toString());
}
else {
return null;
}
}
};
if (ch == '+')
{
getch();
val = getAndEvaluateName();
}
else
{
while (true)
{
if (ch == '#')
{
computeLength = true;
getch();
}
else if (ch == '=')
{
if (flags == null) {
flags = "\\s";
}
getch();
}
else if (ch == '~')
{
flagPattern = true;
getch();
}
else
{
break;
}
}
Object val1 = getName('}');
if (ch == '}' || ch == '[')
{
val = val1 instanceof Token ? evaluate.get(expand((Token) val1).toString()) : val1;
}
else
{
int start = index - 1;
while (ch != EOT && ch != '}' && ":-+=?#%/".indexOf(ch) >= 0)
{
getch();
}
Token op = text.subSequence(start, index - 1);
if (Token.eq("-", op) || Token.eq(":-", op))
{
val1 = val1 instanceof Token ? evaluate.get(expand((Token) val1).toString()) : val1;
Object val2 = getValue();
val = val1 == null ? val2 : val1;
}
else if (Token.eq("+", op) || Token.eq(":+", op))
{
val1 = val1 instanceof Token ? evaluate.get(expand((Token) val1).toString()) : val1;
Object val2 = getValue();
val = val1 != null ? val2 : null;
}
else if (Token.eq("=", op) || Token.eq(":=", op) || Token.eq("::=", op))
{
if (!(val1 instanceof Token))
{
throw new SyntaxError(line, column, "not an identifier");
}
String name = expand((Token) val1).toString();
val1 = evaluate.get(name);
val = getValue();
if (Token.eq("::=", op) || val1 == null)
{
evaluate.put(name, val);
}
}
else if (Token.eq("?", op) || Token.eq(":?", op))
{
String name;
if (val1 instanceof Token)
{
name = expand((Token) val1).toString();
val = evaluate.get(name);
}
else
{
name = "";
val = val1;
}
if (val == null || val.toString().length() == 0)
{
throw new IllegalArgumentException(name + ": parameter not set");
}
}
else if (Token.eq("#", op) || Token.eq("##", op)
|| Token.eq("%", op) || Token.eq("%%", op)
|| Token.eq("/", op) || Token.eq("//", op))
{
val1 = val1 instanceof Token ? evaluate.get(expand((Token) val1).toString()) : val1;
String val2 = getPattern(op.charAt(0) == '/' ? "/}" : "}");
if (val2 != null)
{
String p = toRegexPattern(unquoteGlob(val2), op.length() == 1);
String r;
if (op.charAt(0) == '/')
{
if (ch == '/')
{
getch();
r = getValue().toString();
}
else
{
r = "";
}
}
else
{
r = "";
}
String m = op.charAt(0) == '#' ? "^" + p : op.charAt(0) == '%' ? p + "$" : p;
val1 = toCollection.apply(val1);
if (val1 instanceof Collection)
{
List<String> l = new ArrayList<>();
for (Object o : ((Collection<?>) val1))
{
if (flagG)
{
l.add(o.toString().replaceAll(m, r));
}
else
{
l.add(o.toString().replaceFirst(m, r));
}
}
val = l;
}
else if (val1 != null)
{
if (flagG)
{
val = val1.toString().replaceAll(m, r);
}
else
{
val = val1.toString().replaceFirst(m, r);
}
}
}
else
{
val = val1;
}
}
}
}
//
// Subscripts
//
while (ch == '[')
{
Object left;
boolean nLeft = false;
Object right;
boolean nRight = false;
getch();
if (ch == '*')
{
left = text.subSequence(index - 1, index);
getch();
}
else if (ch == '@')
{
left = text.subSequence(index - 1, index);
flagExpand = true;
getch();
}
else
{
if (ch == '-')
{
nLeft = true;
getch();
}
left = getName(']');
}
if (ch == ',')
{
getch();
if (ch == '-')
{
nRight = true;
getch();
}
right = getName(']');
}
else
{
right = null;
}
if (ch != ']')
{
throw new SyntaxError(line, column, "invalid subscript");
}
getch();
if (right == null)
{
left = left instanceof Token ? expand((Token) left) : left;
String sLeft = left.toString();
if (val instanceof Map)
{
if (sLeft.equals("@") || sLeft.equals("*"))
{
val = toList(asMap(val), flagk, flagv);
}
else
{
val = ((Map<?,?>) val).get(sLeft);
}
}
else if (val instanceof List)
{
if (sLeft.equals("@") || sLeft.equals("*"))
{
val = new ArgList((List<?>) val);
}
else
{
int iLeft = Integer.parseInt(sLeft);
List<?> list = (List<?>) val;
val = list.get(nLeft ? list.size() - 1 - iLeft : iLeft);
}
}
else if (val != null && val.getClass().isArray())
{
if (sLeft.equals("@") || sLeft.equals("*"))
{
final Object array = val;
List<Object> l = new AbstractList<Object>()
{
@Override
public Object get(int index)
{
return Array.get(array, index);
}
@Override
public int size()
{
return Array.getLength(array);
}
};
val = new ArgList(l);
}
else
{
int iLeft = Integer.parseInt(sLeft);
Object array = val;
val = Array.get(array, iLeft);
}
}
else if (val != null)
{
if (sLeft.equals("@") || sLeft.equals("*"))
{
val = val.toString();
}
else
{
int iLeft = Integer.parseInt(sLeft);
String str = val.toString();
val = str.charAt(nLeft ? str.length() - 1 - iLeft : iLeft);
}
}
}
else
{
if (val instanceof Map)
{
val = null;
}
else
{
left = left instanceof Token ? expand((Token) left) : left;
right = right instanceof Token ? expand((Token) right) : right;
int iLeft = Integer.parseInt(left.toString());
int iRight = Integer.parseInt(right.toString());
if (val instanceof List)
{
List<?> list = (List<?>) val;
val = list.subList(nLeft ? list.size() - iLeft : iLeft,
nRight ? list.size() - iRight : iRight);
}
else
{
String str = val.toString();
val = str.substring(nLeft ? str.length() - iLeft : iLeft,
nRight ? str.length() - iRight : iRight);
}
}
}
}
if (ch != '}')
{
throw new SyntaxError(sLine, sCol, "bad substitution");
}
// Parameter name replacement
if (flagP)
{
val = val != null ? evaluate.get(val.toString()) : null;
}
// Double quote joining
boolean joined = false;
if (inQuote && !computeLength && !flagExpand)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
String j = flagj != null ? flagj : " ";
StringBuilder sb = new StringBuilder();
for (Object i : asCollection(val)) {
if (sb.length() > 0) {
sb.append(j);
}
sb.append(String.valueOf(i));
}
val = sb.toString();
joined = true;
}
}
// Character evaluation
if (flagSharp)
{
val = stringApplyer.apply(new Function<String, String>() {
public String apply(String s) { return Expander.this.sharp(s); };
}, val);
}
// Length
if (computeLength)
{
if (val instanceof Collection)
{
val = ((Collection<?>) val).size();
}
else if (val instanceof Map)
{
val = ((Map<?,?>) val).size();
}
else if (val != null)
{
val = val.toString().length();
}
else
{
val = 0;
}
}
// Forced joining
if (flagj != null || flags != null && !joined)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
String j = flagj != null ? flagj : " ";
StringBuilder sb = new StringBuilder();
for (Object i : asCollection(val)) {
if (sb.length() > 0) {
sb.append(j);
}
sb.append(String.valueOf(i));
}
val = sb.toString();
}
}
// Simple word splitting
if (flags != null)
{
val = toCollection.apply(val);
if (!(val instanceof Collection))
{
val = Collections.singletonList(val);
}
List<String> l = new ArrayList<>();
for (Object i : asCollection(val)) {
Collections.addAll(l, String.valueOf(i).split(flags));
}
val = l;
}
Function<String, String> toLowerCase = new Function<String, String>() {
@Override
public String apply(String t) {
return t.toLowerCase();
}
};
Function<String, String> toUpperCase = new Function<String, String>() {
@Override
public String apply(String t) {
return t.toUpperCase();
}
};
// Case modification
if (flagC)
{
val = stringApplyer.apply(new Function<String, String>(){
@Override
public String apply(String t) {
return Expander.this.toCamelCase(t);
}}, val);
}
else if (flagL)
{
val = stringApplyer.apply(toLowerCase, val);
}
else if (flagU)
{
val = stringApplyer.apply(toUpperCase, val);
}
// Visibility enhancement
if (flagV)
{
val = stringApplyer.apply(new Function<String, String>() {
@Override
public String apply(String t) {
return visible(t);
}}, val);
}
// Quote
if (flagq != 0)
{
final int _flagq = flagq;
val = stringApplyer.apply(new Function<String, String>() {
@Override
public String apply(String s) {
return quote(s, _flagq);
}
}, val);
inQuote = true;
}
else if (flagQ) {
val = stringApplyer.apply(new Function<String,String>(){
@Override
public String apply(String t) {
return unquote(t);
}}, val);
}
// Uniqueness
if (flagu)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
val = new ArrayList<>(new LinkedHashSet<>(asCollection(val)));
}
}
// Ordering
if (flaga || flagi || flagn || flago || flagO)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
List<String> list;
if (flagn)
{
final boolean _flagi = flagi;
List<String> l = new ArrayList<>();
for (Object i : asCollection(val)) {
l.add(String.valueOf(i));
}
Collections.sort(l, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return numericCompare(s1, s2, _flagi);
}
});
list = l;
}
else if (flaga)
{
list = new ArrayList<String>((Collection<? extends String>)val);
}
else
{
//Comparator<String> comparator = flagi ? String.CASE_INSENSITIVE_ORDER : String::compareTo;
Comparator<String> comparator;
if (flagi) {
comparator = String.CASE_INSENSITIVE_ORDER;
}
else {
comparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}};
}
List<String> l = new ArrayList<>();
for (Object i : asCollection(val)) {
l.add(String.valueOf(i));
}
//l.sort(comparator);
Collections.sort(l, comparator);
list = l;
}
if (flagO)
{
Collections.reverse(list);
}
val = list;
}
}
// Semantic joining
if (semanticJoin)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
StringBuilder sb = new StringBuilder();
for (Object i : asCollection(val)) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(String.valueOf(i));
}
val = sb.toString();
}
}
// Empty argument removal
if (val instanceof Collection)
{
List<Object> l = new ArrayList<>();
for (Object o : asCollection(val)) {
if (!(o instanceof CharSequence) || ((CharSequence) o).length() > 0) {
l.add(o);
}
}
val = l;
}
if (asPattern && !inQuote && !flagPattern)
{
val = toCollection.apply(val);
List<String> patterns = new ArrayList<>();
for (Object o : toCollection(val)) {
patterns.add(quote(String.valueOf(o), 2));
}
val = patterns.size() == 1 ? patterns.get(0) : patterns;
}
if (inQuote)
{
val = toCollection.apply(val);
if (val instanceof Collection)
{
List<Object> l = new ArrayList<>(asCollection(val));
if (flagExpand)
{
val = new ArgList(l);
}
else
{
val = l;
}
}
}
else
{
if (flagExpand && val instanceof List)
{
val = new ArgList((List<?>) val);
}
}
getch();
}
return val;
}