public Interpreter()

in gateway-util-common/src/main/java/org/apache/knox/gateway/plang/Interpreter.java [48:118]


    public Interpreter() {
        addSpecialForm(Arity.min(1), "or", args -> args.stream().anyMatch(each -> (boolean)eval(each)));
        addSpecialForm(Arity.min(1), "and", args -> args.stream().allMatch(each -> (boolean)eval(each)));
        addSpecialForm(Arity.between(2, 3), "if", args -> {
            if ((boolean)eval(args.get(0))) {
                return eval(args.get(1));
            } else if (args.size() == 3) {
                return eval(args.get(2));
            }
            return null;
        });
        addFunction("not", Arity.UNARY, args -> !(boolean)args.get(0));
        addFunction("=", Arity.BINARY, args -> equalTo(args.get(0), args.get(1)));
        addFunction("!=", Arity.BINARY, args -> !equalTo(args.get(0), args.get(1)));
        // The comparisons are floating point based, we might need proper integer-integer comparison in the future
        addFunction("<", Arity.BINARY, args ->  ((Number)args.get(0)).doubleValue() < ((Number)args.get(1)).doubleValue());
        addFunction("<=", Arity.BINARY, args ->  ((Number)args.get(0)).doubleValue() <= ((Number)args.get(1)).doubleValue());
        addFunction(">", Arity.BINARY, args ->  ((Number)args.get(0)).doubleValue() > ((Number)args.get(1)).doubleValue());
        addFunction(">=", Arity.BINARY, args ->  ((Number)args.get(0)).doubleValue() >= ((Number)args.get(1)).doubleValue());
        addFunction("+", Arity.BINARY, args -> add((Number)args.get(0), (Number)args.get(1)));
        addFunction("-", Arity.BINARY, args -> sub((Number)args.get(0), (Number)args.get(1)));
        addFunction("*", Arity.BINARY, args -> mul((Number)args.get(0), (Number)args.get(1)));
        addFunction("/", Arity.BINARY, args -> div((Number)args.get(0), (Number)args.get(1)));
        addFunction("match", Arity.BINARY, args ->
            args.get(0) instanceof String
                ? Pattern.matches((String)args.get(1), (String)args.get(0))
                : ((List<String>)(args.get(0))).stream().anyMatch(each -> Pattern.matches((String)args.get(1), each))
        );
        addFunction("size", Arity.UNARY, args -> ((Collection<?>) args.get(0)).size());
        addFunction("empty", Arity.UNARY, args -> ((Collection<?>) args.get(0)).isEmpty());
        addFunction("username", Arity.UNARY, args -> constants.get("username").equals(args.get(0)));
        addFunction("member", Arity.UNARY, args -> ((Collection<String>)constants.get("groups")).contains((String)args.get(0)));
        addFunction("lowercase", Arity.UNARY, args -> ((String)args.get(0)).toLowerCase(Locale.getDefault()));
        addFunction("uppercase", Arity.UNARY, args -> ((String)args.get(0)).toUpperCase(Locale.getDefault()));
        addFunction("concat", Arity.min(1), args -> args.stream().map(Object::toString).collect(Collectors.joining()));
        addFunction("substr", Arity.min(2), args ->
                args.size() == 2
                    ? ((String)args.get(0)).substring(((Number)args.get(1)).intValue())
                    : ((String)args.get(0)).substring(((Number)args.get(1)).intValue(), ((Number)args.get(2)).intValue())
        );
        addFunction("strlen", Arity.UNARY, args -> ((String)args.get(0)).length());
        addFunction("starts-with", Arity.BINARY, args -> ((String)args.get(0)).startsWith((String)args.get(1)));
        addFunction("ends-with", Arity.BINARY, args -> ((String)args.get(0)).endsWith((String)args.get(1)));
        addFunction("contains", Arity.BINARY, args -> ((String)args.get(1)).contains((String)args.get(0)));
        addFunction("index-of", Arity.BINARY, args -> ((String)args.get(1)).indexOf((String)args.get(0)));
        addFunction("regex-template", Arity.between(3, 5), args -> {
            String str = (String) args.get(0);
            String regex = (String) args.get(1);
            String template = (String) args.get(2);
            if (args.size() == 3) {
                return new RegexTemplate(regex, template, null, false).apply(str);
            } else {
                boolean useOriginalOnLookupFailure = args.size() >= 5 && (boolean) args.get(4);
                return new RegexTemplate(regex, template, (Map)args.get(3), useOriginalOnLookupFailure).apply(str);
            }
        });
        addFunction("print", Arity.min(1), args -> { // for debugging
            args.forEach(arg -> LOG.info(arg == null ? "null" : arg.toString()));
            return false;
        });
        addFunction("hash", Arity.even(), args -> { // create a hashmap, number of arguments must be an even number, this is needed for the RegExp lookup table
            Map<Object,Object> map = new HashMap<>();
            for (int i = 0; i < args.size() -1; i+=2) {
                map.put(args.get(i), args.get(i +1));
            }
            return map;
        });
        addFunction("at", Arity.BINARY, args -> ((Map<Object,Object>)args.get(1)).get(args.get(0)));
        constants.put("true", true);
        constants.put("false", false);
    }