com.google.template.soy.pysrc.restricted.PyFunctionExprBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.google.template.soy.pysrc.restricted.PyFunctionExprBuilder.java

Source

/*
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.template.soy.pysrc.restricted;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 * A class for building code for a function call expression in Python.
 * It builds to a PyExpr so it could be used function call code recursively.
 *
 * <p> Sample Output:
 * {@code some_func_call(1, "str", foo='bar', foo=nested_call(42))}
 *
 *
 */
public final class PyFunctionExprBuilder {
    private static final Function<Map.Entry<String, PyExpr>, String> KEYWORD_ARG_MAPPER = new Function<Map.Entry<String, PyExpr>, String>() {
        @Override
        public String apply(Map.Entry<String, PyExpr> entry) {
            String key = entry.getKey();
            PyExpr value = entry.getValue();
            return key + "=" + value.getText();
        }
    };

    private static final Function<PyExpr, String> LIST_ARG_MAPPER = new Function<PyExpr, String>() {
        @Override
        public String apply(PyExpr arg) {
            return arg.getText();
        }
    };

    private final String funcName;
    private final Deque<PyExpr> argList;
    private final Map<String, PyExpr> kwargMap;
    private String unpackedKwargs = null;

    /**
     * @param funcName The name of the function.
     */
    public PyFunctionExprBuilder(String funcName) {
        this.funcName = funcName;
        this.argList = new ArrayDeque<>();
        this.kwargMap = new LinkedHashMap<>();
    }

    public PyFunctionExprBuilder addArg(PyExpr arg) {
        this.argList.add(arg);
        return this;
    }

    public PyFunctionExprBuilder addArg(String str) {
        this.argList.add(new PyStringExpr("'" + str + "'"));
        return this;
    }

    public PyFunctionExprBuilder addArg(boolean b) {
        this.argList.add(new PyExpr(b ? "True" : "False", Integer.MAX_VALUE));
        return this;
    }

    public PyFunctionExprBuilder addArg(int i) {
        this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    public PyFunctionExprBuilder addArg(double i) {
        this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    public PyFunctionExprBuilder addArg(long i) {
        this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    public String getFuncName() {
        return this.funcName;
    }

    public PyFunctionExprBuilder addKwarg(String key, PyExpr argValue) {
        kwargMap.put(key, argValue);
        return this;
    }

    public PyFunctionExprBuilder addKwarg(String key, String str) {
        kwargMap.put(key, new PyStringExpr("'" + str + "'"));
        return this;
    }

    public PyFunctionExprBuilder addKwarg(String key, int i) {
        kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    public PyFunctionExprBuilder addKwarg(String key, double i) {
        kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    public PyFunctionExprBuilder addKwarg(String key, long i) {
        kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE));
        return this;
    }

    /**
     * Unpacking keyword arguments will expand a dictionary into a series of keyword arguments.
     *
     * <p>NOTE: Keyword unpacking behavior is only guaranteed for mapping expressions. Non-mapping
     * expressions which attempt to unpack will result in Python runtime errors.
     *
     * @param mapping The mapping expression to unpack.
     * @return This PyFunctionExprBuilder instance.
     */
    public PyFunctionExprBuilder setUnpackedKwargs(PyExpr mapping) {
        if (unpackedKwargs != null) {
            throw new UnsupportedOperationException("Only one kwarg unpacking allowed per expression.");
        }
        StringBuilder expr = new StringBuilder("**");
        if (mapping.getPrecedence() < Integer.MAX_VALUE) {
            expr.append("(").append(mapping.getText()).append(")");
        } else {
            expr.append(mapping.getText());
        }
        unpackedKwargs = expr.toString();
        return this;
    }

    /**
     *  Returns a valid Python function call as a String.
     */
    public String build() {
        StringBuilder sb = new StringBuilder(funcName + "(");

        Joiner joiner = Joiner.on(", ").skipNulls();

        // Join args and kwargs into simple strings.
        String args = joiner.join(Iterables.transform(argList, LIST_ARG_MAPPER));
        String kwargs = joiner.join(Iterables.transform(kwargMap.entrySet(), KEYWORD_ARG_MAPPER));

        // Strip empty strings.
        args = Strings.emptyToNull(args);
        kwargs = Strings.emptyToNull(kwargs);

        // Join all pieces together.
        joiner.appendTo(sb, args, kwargs, unpackedKwargs);

        sb.append(")");
        return sb.toString();
    }

    /*
     * Use when the output function is unknown in Python runtime.
     *
     * @return A PyExpr represents the function code.
     */
    public PyExpr asPyExpr() {
        return new PyExpr(build(), Integer.MAX_VALUE);
    }

    /*
     * Use when the output function is known to be a String in Python runtime.
     *
     * @return A PyStringExpr represents the function code.
     */
    public PyStringExpr asPyStringExpr() {
        return new PyStringExpr(build());
    }
}