All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.simpleEL.dialect.tiny.TinyELPreprocessor Maven / Gradle / Ivy

The newest version!
package com.alibaba.simpleEL.dialect.tiny;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.simpleEL.ELException;
import com.alibaba.simpleEL.JavaSource;
import com.alibaba.simpleEL.TypeUtils;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELBinaryOpExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELBinaryOperator;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELIdentifierExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELLiteralExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELMethodInvokeExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELPropertyExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELStringExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyELVariantRefExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.TinyUnaryOpExpr;
import com.alibaba.simpleEL.dialect.tiny.ast.stmt.TinyELForEachStatement;
import com.alibaba.simpleEL.dialect.tiny.ast.stmt.TinyELForStatement;
import com.alibaba.simpleEL.dialect.tiny.ast.stmt.TinyELStatement;
import com.alibaba.simpleEL.dialect.tiny.ast.stmt.TinyLocalVarDeclareStatement;
import com.alibaba.simpleEL.dialect.tiny.parser.TinyELExprParser;
import com.alibaba.simpleEL.dialect.tiny.parser.TinyStatementParser;
import com.alibaba.simpleEL.dialect.tiny.visitor.TinyELOutputVisitor;
import com.alibaba.simpleEL.preprocess.TemplatePreProcessor;

public class TinyELPreprocessor extends TemplatePreProcessor {

    public final static String        DEFAULT_PACKAGE_NAME = "com.alibaba.simpleEL.dialect.tiny.gen";

    private final Map functions            = new HashMap();

    public TinyELPreprocessor(){
        this.packageName = DEFAULT_PACKAGE_NAME;
    }

    public Map getFunctions() {
        return this.functions;
    }

    @Override
    public JavaSource handle(Map context, String text) {
        if (variantResolver == null) {
            throw new IllegalStateException("variantResolver is null");
        }

        String resolvedResult;
        if (!allowMultiStatement) {
            TinyELExprParser parser = new TinyELExprParser(text);
            TinyELExpr expr = parser.expr();

            StringWriter out = new StringWriter();
            TinyELOutputVisitor visitor = createVisitor(out);
            expr.accept(visitor);

            resolvedResult = out.toString();
        } else {
            TinyStatementParser parser = new TinyStatementParser(text);
            List statements = parser.statementList();

            StringWriter out = new StringWriter();
            TinyELOutputVisitor visitor = createVisitor(out);

            visitor.incrementIndent();
            for (TinyELStatement statement : statements) {
                visitor.println();
                statement.accept(visitor);
            }
            visitor.decrementIndent();

            resolvedResult = out.toString();
        }

        // System.out.println(resolvedResult);

        if (!allowMultiStatement) {
            resolvedResult = "return " + resolvedResult + ";";
        }

        final String className = "GenClass_" + digits();

        String source = template.replace("$packageName", packageName)//
        .replace("$className", className)//
        .replace("$expression", resolvedResult);

        JavaSource javaSource = new JavaSource(packageName, className, source);

        return javaSource;
    }

    protected TinyELOutputVisitor createVisitor(StringWriter out) {
        JavaSourceGenVisitor visitor = new JavaSourceGenVisitor(new PrintWriter(out));
        return visitor;
    }

    public class JavaSourceGenVisitor extends TinyELOutputVisitor {

        protected Map localVariants = new HashMap();

        public JavaSourceGenVisitor(PrintWriter out){
            super(out);
        }

        @Override
        public boolean visit(TinyELIdentifierExpr x) {
            String ident = x.getName();

            if (localVariants.containsKey(ident)) {
                out.print(ident);
                return false;
            }

            {
                String fullName = "java.lang." + ident;
                if (isClassName(fullName)) {
                    out.print(ident);
                    return false;
                }
            }
            {
                String fullName = "java.util." + ident;
                if (isClassName(fullName)) {
                    out.print(fullName);
                    return false;
                }
            }

            String result = variantResolver.resolve(ident);
            out.print(result);
            return false;
        }

        @Override
        public boolean visit(TinyELVariantRefExpr x) {
            String ident = x.getName();
            String result = variantResolver.resolve(ident);
            out.print(result);
            return false;
        }

        public boolean isClassName(String fullName) {
            try {
                Class clazz = Thread.currentThread().getContextClassLoader().loadClass(fullName);

                if (clazz != null) {
                    return true;
                }
            } catch (ClassNotFoundException e) {
                return false;
            }

            return false;
        }

        @Override
        public boolean visit(TinyELPropertyExpr x) {
            if (x.getOwner() instanceof TinyELBinaryOpExpr) {
                out.print('(');
                x.getOwner().accept(this);
                out.print(')');
                out.print(".");
                out.print(x.getName());

                return false;
            }

            String fullName = x.toString();
            if (isClassName(fullName)) {
                out.print(fullName);
                return false;
            }

            x.getOwner().accept(this);

            out.print(".");
            out.print(x.getName());
            return false;
        }

        private Class getType(TinyELExpr expr) {
            if (expr instanceof TinyELIdentifierExpr) {
                TinyELIdentifierExpr ident = (TinyELIdentifierExpr) expr;
                String name = ident.getName();

                Class type = variantResolver.getType(name);
                if (type != null) {
                    return type;
                }

            }
            
            if (expr instanceof TinyELVariantRefExpr) {
                TinyELVariantRefExpr ident = (TinyELVariantRefExpr) expr;
                String name = ident.getName();

                Class type = variantResolver.getType(name);
                if (type != null) {
                    return type;
                }

            }
            
            if (expr instanceof TinyELBinaryOpExpr) {
                TinyELBinaryOpExpr binaryExpr = (TinyELBinaryOpExpr) expr;
                Class leftType = getType(binaryExpr.getLeft());
                Class rightType = getType(binaryExpr.getRight());
                
                if (leftType != null && leftType.equals(rightType)) {
                    return leftType;
                }
            }
            
            return null;
        }

        @Override
        public boolean visit(TinyELMethodInvokeExpr x) {
            if (x.getOwner() == null) {
                String methodName = x.getMethodName();
                Method method = functions.get(methodName);

                if (method == null) {
                    return super.visit(x);
                }

                Class[] types = method.getParameterTypes();
                if (!method.isVarArgs()) {
                    if (types.length != x.getParameters().size()) {
                        return super.visit(x);
                    }

                    String className = method.getDeclaringClass().getName();
                    className = className.replaceAll("\\$", "."); // inner class
                    out.print(className);
                    out.print(".");
                    out.print(method.getName());

                    out.print("(");
                    for (int i = 0, size = x.getParameters().size(); i < size; ++i) {
                        if (i != 0) {
                            out.print(",");
                        }

                        TinyELExpr param = x.getParameters().get(i);
                        if (types[i] == getType(param)) {
                            param.accept(this);
                        } else {
                            visitMethodParameter(types[i], param);
                        }
                    }

                    out.print(")");
                    return false;
                } else {
                    if (types.length > x.getParameters().size()) {
                        return super.visit(x);
                    }

                    String className = method.getDeclaringClass().getName();
                    className = className.replaceAll("\\$", "."); // inner class
                    out.print(className);
                    out.print(".");
                    out.print(method.getName());

                    out.print("(");
                    for (int i = 0, size = x.getParameters().size(); i < size; ++i) {
                        if (i != 0) {
                            out.print(",");
                        }

                        Class type;
                        if (i >= types.length - 1) {
                            type = types[types.length - 1];
                            type = type.getComponentType();
                        } else {
                            type = types[i];
                        }
                        visitMethodParameter(type, x.getParameters().get(i));
                    }

                    out.print(")");
                    return false;
                }
            }

            if (x.getOwner() instanceof TinyELIdentifierExpr && x.getMethodName().equals("equals")
                && x.getParameters().size() == 1) {
                TinyELIdentifierExpr leftIdent = (TinyELIdentifierExpr) x.getOwner();
                String varName = leftIdent.getName();

                TinyELExpr param = x.getParameters().get(0);
                Class type = variantResolver.getType(varName);
                if (type == Date.class && param instanceof TinyELStringExpr) {
                    x.getOwner().accept(this);
                    print(".equals(_date(");
                    param.accept(this);
                    print("))");
                    return false;
                }
            }

            return super.visit(x);
        }

        public void visitMethodParameter(Class type, TinyELExpr expr) {
            if (type == String.class && expr instanceof TinyELStringExpr) {
                expr.accept(this);
                return;
            }

            if (Boolean.class == type || boolean.class == type) {
                out.print("_bool(");
                expr.accept(this);
                out.print(")");
            } else if (String.class == type) {
                out.print("_string(");
                expr.accept(this);
                out.print(")");
            } else if (Byte.class == type || byte.class == type) {
                out.print("_byte(");
                expr.accept(this);
                out.print(")");
            } else if (Short.class == type || short.class == type) {
                out.print("_short(");
                expr.accept(this);
                out.print(")");
            } else if (Integer.class == type || int.class == type) {
                out.print("_int(");
                expr.accept(this);
                out.print(")");
            } else if (Long.class == type || long.class == type) {
                out.print("_long(");
                expr.accept(this);
                out.print(")");
            } else if (Float.class == type || float.class == type) {
                out.print("_float(");
                expr.accept(this);
                out.print(")");
            } else if (Double.class == type || double.class == type) {
                out.print("_double(");
                expr.accept(this);
                out.print(")");
            } else if (BigInteger.class == type) {
                out.print("_bigInt(");
                expr.accept(this);
                out.print(")");
            } else if (BigDecimal.class == type) {
                out.print("_decimal(");
                expr.accept(this);
                out.print(")");
            } else if (java.util.Date.class == type) {
                out.print("_date(");
                expr.accept(this);
                out.print(")");
            } else if (Object.class == type) {
                expr.accept(this);
            } else {
                String className = TypeUtils.getClassName(type);

                out.print("(" + className + ")");
                expr.accept(this);
            }

        }

        @Override
        public boolean visit(TinyELBinaryOpExpr x) {
            x.getLeft().setParentExpr(x);
            x.getRight().setParentExpr(x);

            if (getType(x.getLeft()) == String.class || getType(x.getRight()) == String.class) {
                out.print("(");
                x.getLeft().accept(this);
                out.print(" ");
                out.print(x.getOperator().name);
                out.print(" ");
                x.getRight().accept(this);
                out.print(")");
                return false;
            }

            if (x.getLeft() instanceof TinyELIdentifierExpr) {
                TinyELIdentifierExpr leftIdent = (TinyELIdentifierExpr) x.getLeft();
                String varName = leftIdent.getName();
                if (!localVariants.containsKey(varName)) {
                    switch (x.getOperator()) {
                        case Assignment:
                            print("ctx.put(\"");
                            print(varName);
                            print("\", ");
                            x.getRight().accept(this);
                            print(")");
                            return false;
                        case AddAndAssignment:
                            print("ctx.put(\"");
                            print(varName);
                            print("\", ");
                            leftIdent.accept(this);
                            print(" ");
                            print(TinyELBinaryOperator.Add.name);
                            print(" ");
                            x.getRight().accept(this);
                            print(")");
                            return false;
                        default:
                            break;
                    }
                }

                Class type = variantResolver.getType(varName);
                if (type == BigDecimal.class) {
                    switch (x.getOperator()) {
                        case Add:
                            x.getLeft().accept(this);
                            print(".add(_decimal(");
                            x.getRight().accept(this);
                            print("))");
                            return false;
                        case Subtract:
                            x.getLeft().accept(this);
                            print(".subtract(_decimal(");
                            x.getRight().accept(this);
                            print("))");
                            return false;
                        case GreaterThan:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) > 0");
                            return false;
                        case GreaterThanOrEqual:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) >= 0");
                            return false;
                        case LessThan:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) < 0");
                            return false;
                        case LessThanOrEqual:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) <= 0");
                            return false;
                        default:
                            break;
                    }
                }
            }

            if (x.getLeft() instanceof TinyELVariantRefExpr) {
                TinyELVariantRefExpr var = (TinyELVariantRefExpr) x.getLeft();
                String varName = var.getName();
                if (!localVariants.containsKey(varName)) {
                    switch (x.getOperator()) {
                        case Assignment:
                            print("ctx.put(\"");
                            print(varName);
                            print("\", ");
                            x.getRight().accept(this);
                            print(")");
                            return false;
                        case AddAndAssignment:
                            print("ctx.put(\"");
                            print(varName);
                            print("\", ");
                            var.accept(this);
                            print(" ");
                            print(TinyELBinaryOperator.Add.name);
                            print(" ");
                            x.getRight().accept(this);
                            print(")");
                            return false;
                        default:
                            break;
                    }
                }

                Class type = variantResolver.getType(varName);
                if (type == BigDecimal.class) {
                    switch (x.getOperator()) {
                        case Add:
                            x.getLeft().accept(this);
                            print(".add(_decimal(");
                            x.getRight().accept(this);
                            print("))");
                            return false;
                        case GreaterThan:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) > 0");
                            return false;
                        case GreaterThanOrEqual:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) >= 0");
                            return false;
                        case LessThan:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) < 0");
                            return false;
                        case LessThanOrEqual:
                            x.getLeft().accept(this);
                            print(".compareTo(_decimal(");
                            x.getRight().accept(this);
                            print(")) <= 0");
                            return false;
                        default:
                            break;
                    }
                }

            }

            if (x.getOperator() == TinyELBinaryOperator.InstanceOf) {
                if (x.getLeft() instanceof TinyELIdentifierExpr) {
                    TinyELIdentifierExpr ident = (TinyELIdentifierExpr) x.getLeft();
                    String varName = ident.getName();
                    if (!localVariants.containsKey(varName)) {
                        print("ctx.get(\"");
                        print(varName);
                        print("\") instanceof ");
                    }
                    x.getRight().accept(this);
                    return false;
                }
            }
            return super.visit(x);
        }

        @Override
        public boolean visit(TinyLocalVarDeclareStatement x) {
            for (int i = 0, size = x.getVariants().size(); i < size; ++i) {
                String varName = x.getVariants().get(i).getName();
                localVariants.put(varName, x.getType());
            }

            return super.visit(x);
        }

        @Override
        public boolean visit(TinyELForStatement x) {
            for (int i = 0, size = x.getVariants().size(); i < size; ++i) {
                String varName = x.getVariants().get(i).getName();
                localVariants.put(varName, x.getType());
            }

            return super.visit(x);
        }

        @Override
        public boolean visit(TinyELForEachStatement x) {
            localVariants.put(x.getVariant(), x.getType());
            return super.visit(x);
        }

        @Override
        public boolean visit(TinyUnaryOpExpr x) {
            TinyELExpr expr = x.getExpr();

            if (expr instanceof TinyELLiteralExpr) {
                return super.visit(x);
            }

            Class type = getType(x.getExpr());

            if (type == BigDecimal.class) {
                switch (x.getOperator()) {
                    case Plus:
                        x.getExpr().accept(this);
                        return false;
                    case Minus:
                        if (type == BigDecimal.class) {
                            print("_decimal(");
                            x.getExpr().accept(this);
                            print(").negate()");
                        }
                        return false;
                    default:
                        break;
                }
            }

            if (expr instanceof TinyELIdentifierExpr) {
                TinyELIdentifierExpr identExpr = (TinyELIdentifierExpr) x.getExpr();
                String varName = identExpr.getName();

                if (localVariants.containsKey(varName)) {
                    return super.visit(x);
                }

                switch (x.getOperator()) {
                    case Plus:
                    case Minus:
                        return super.visit(x);
                    case PreIncrement:
                        print("putAndGet(ctx, \"");
                        print(varName);
                        print("\", _add(");
                        identExpr.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PostIncrement:
                        print("ctx.put(\"");
                        print(varName);
                        print("\", _add(");
                        identExpr.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PreDecrement:
                        print("putAndGet(ctx, \"");
                        print(varName);
                        print("\", _sub(");
                        identExpr.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PostDecrement:
                        print("ctx.put(\"");
                        print(varName);
                        print("\", _sub(");
                        identExpr.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    default:
                        throw new ELException("TOOD");
                }
            }

            if (x.getExpr() instanceof TinyELVariantRefExpr) {
                TinyELVariantRefExpr var = (TinyELVariantRefExpr) x.getExpr();
                String varName = var.getName();

                if (localVariants.containsKey(varName)) {
                    return super.visit(x);
                }

                switch (x.getOperator()) {
                    case Plus:
                    case Minus:
                        return super.visit(x);
                    case PreIncrement:
                        print("putAndGet(ctx, \"");
                        print(varName);
                        print("\", _add(");
                        var.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PostIncrement:
                        print("ctx.put(\"");
                        print(varName);
                        print("\", _add(");
                        var.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PreDecrement:
                        print("putAndGet(ctx, \"");
                        print(varName);
                        print("\", _sub(");
                        var.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    case PostDecrement:
                        print("ctx.put(\"");
                        print(varName);
                        print("\", _sub(");
                        var.accept(this);
                        print(", 1");
                        print("))");
                        return false;
                    default:
                        throw new ELException("TOOD");
                }
            }

            return super.visit(x);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy