private Object expandVar()

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;
    }