Search in sources :

Example 36 with SegmentCode

use of jetbrick.template.parser.code.SegmentCode in project jetbrick-template-1x by subchen.

the class JetTemplateCodeVisitor method visitMacro_directive.

@Override
public Code visitMacro_directive(Macro_directiveContext ctx) {
    String text = ctx.getChild(0).getText();
    String name = text.substring(7, text.length() - 1).trim();
    MacroCode macroCode = scopeCode.createMacroCode();
    macroCode.setName(name);
    scopeCode = macroCode.getMethodCode();
    scopeCode.define(Code.CONTEXT_NAME, TypedKlass.JetContext);
    // 处理参数
    Define_expression_listContext define_expression_list = ctx.define_expression_list();
    if (define_expression_list != null) {
        SegmentListCode define_list_code = (SegmentListCode) define_expression_list.accept(this);
        macroCode.setDefineListCode(define_list_code);
        // 设置参数 Context
        for (SegmentCode node : define_list_code.getChildren()) {
            DefineExpressionCode c = (DefineExpressionCode) node;
            scopeCode.define(c.getName(), c.getTypedKlass());
        }
    }
    // 需要先定义 macro,这样可以支持 macro 的递归调用 (issue 102)
    if (macroMap == null) {
        macroMap = new HashMap<String, MacroCode>(8);
    }
    MacroCode old = macroMap.put(name, macroCode);
    if (old != null) {
        throw reportError("Duplicated macro defination " + name, ctx);
    }
    tcc.addMacro(macroCode);
    // 访问 macro body
    // add body content
    scopeCode.setBodyCode(ctx.block().accept(this));
    scopeCode = scopeCode.pop();
    return Code.EMPTY;
}
Also used : SegmentCode(jetbrick.template.parser.code.SegmentCode) DefineExpressionCode(jetbrick.template.parser.code.DefineExpressionCode) MacroCode(jetbrick.template.parser.code.MacroCode) SegmentListCode(jetbrick.template.parser.code.SegmentListCode) Define_expression_listContext(jetbrick.template.parser.grammer.JetTemplateParser.Define_expression_listContext)

Example 37 with SegmentCode

use of jetbrick.template.parser.code.SegmentCode in project jetbrick-template-1x by subchen.

the class JetTemplateCodeVisitor method visitExpr_math_binary_basic.

@Override
public Code visitExpr_math_binary_basic(Expr_math_binary_basicContext ctx) {
    SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this);
    SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this);
    String op = ctx.getChild(1).getText();
    // 类型检查
    Class<?> resultKlass = PromotionUtils.get_binary_basic(lhs.getKlass(), rhs.getKlass(), op);
    if (resultKlass == null) {
        throw reportError("The BinaryOperator \"" + op + "\" is not applicable for the operands " + lhs.getKlassName() + " and " + rhs.getKlassName(), ctx.getChild(1));
    }
    String source = "(" + lhs.toString() + op + rhs.toString() + ")";
    return new SegmentCode(resultKlass, source, ctx);
}
Also used : SegmentCode(jetbrick.template.parser.code.SegmentCode)

Example 38 with SegmentCode

use of jetbrick.template.parser.code.SegmentCode in project jetbrick-template-1x by subchen.

the class JetTemplateCodeVisitor method visitExpr_field_access.

@Override
public Code visitExpr_field_access(Expr_field_accessContext ctx) {
    SegmentCode code = (SegmentCode) ctx.expression().accept(this);
    String name = ctx.IDENTIFIER().getText();
    assert_not_null_constantContext(code.getNode());
    // 进行类型推导,找到方法的返回类型
    code = code.asBoxedSegmentCode();
    Class<?> beanClass = code.getKlass();
    Member member = null;
    if ((!beanClass.isArray()) || (!"length".equals(name))) {
        // not array.length
        member = resolver.resolveProperty(beanClass, name);
        if (member == null) {
            // reportError
            name = name.substring(0, 1).toUpperCase() + name.substring(1);
            StringBuilder err = new StringBuilder(128);
            err.append("The method ");
            err.append("get" + name);
            err.append("() or ");
            err.append("is" + name);
            err.append("() is undefined for the type ");
            err.append(beanClass.getName());
            err.append('.');
            if (Object.class.equals(beanClass)) {
                err.append("\n advise: ");
                if (code.getNode() instanceof Expr_identifierContext) {
                    err.append("Please use #define(type ");
                    err.append(code.getNode().getText());
                    err.append(") to define variable type.");
                } else {
                    err.append("Please use #set(type xxx = ");
                    err.append(code.getNode().getText());
                    err.append(") to define expression type.");
                }
            }
            throw reportError(err.toString(), ctx.IDENTIFIER());
        }
    }
    boolean isSafeCall = globalSafeCall || "?.".equals(ctx.getChild(1).getText());
    // 生成code
    StringBuilder sb = new StringBuilder(64);
    TypedKlass resultKlass = null;
    if (member instanceof Method) {
        Method method = (Method) member;
        if (securityManager != null) {
            securityManager.checkMemberAccess(method);
        }
        // special code for Map.get()
        // https://github.com/subchen/jetbrick-template/issues/100
        TypedKlass typedKlass = code.getTypedKlass();
        if ("get".equals(method.getName()) && member.getDeclaringClass() == Map.class) {
            if (typedKlass.getTypeArgs().length >= 2) {
                resultKlass = typedKlass.getTypeArgs()[1];
            }
        }
        if (resultKlass == null) {
            resultKlass = TypedKlassUtils.getMethodReturnTypedKlass(method);
        }
        if (method.getParameterTypes().length == 0) {
            // getXXX() or isXXX()
            if (isSafeCall) {
                // 安全调用,防止 NullPointException
                boolean boxWhenSafeCall = false;
                if (resultKlass.isPrimitive()) {
                    boxWhenSafeCall = true;
                    resultKlass = resultKlass.asBoxedTypedKlass();
                }
                sb.append("((");
                sb.append(code.toString());
                sb.append("==null)?(");
                sb.append(resultKlass.getSource());
                sb.append(")null:");
                if (boxWhenSafeCall) {
                    sb.append(resultKlass.getSource()).append(".valueOf(");
                }
                sb.append(code.toString());
                sb.append('.');
                sb.append(method.getName());
                sb.append("()");
                if (boxWhenSafeCall) {
                    sb.append(')');
                }
                sb.append(')');
            } else {
                sb.append(code.toString());
                sb.append('.');
                sb.append(method.getName());
                sb.append("()");
            }
        } else {
            // get(String)
            if (isSafeCall) {
                // 安全调用,防止 NullPointException
                boolean boxWhenSafeCall = false;
                if (resultKlass.isPrimitive()) {
                    boxWhenSafeCall = true;
                    resultKlass = resultKlass.asBoxedTypedKlass();
                }
                sb.append("((");
                sb.append(code.toString());
                sb.append("==null)?(");
                sb.append(resultKlass.getSource());
                sb.append(")null:");
                if (boxWhenSafeCall) {
                    sb.append(resultKlass.getSource()).append(".valueOf(");
                }
                sb.append(code.toString());
                sb.append(".get(\"");
                sb.append(name);
                sb.append("\")");
                if (boxWhenSafeCall) {
                    sb.append(')');
                }
                sb.append(')');
            } else {
                sb.append(code.toString());
                sb.append(".get(\"");
                sb.append(name);
                sb.append("\")");
            }
        }
    } else {
        if (member instanceof Field) {
            if (securityManager != null) {
                securityManager.checkMemberAccess((Field) member);
            }
            resultKlass = TypedKlassUtils.getFieldTypedKlass((Field) member);
        } else {
            // array.length
            resultKlass = TypedKlass.create(Integer.TYPE);
        }
        if (isSafeCall) {
            // 安全调用,防止 NullPointException
            boolean boxWhenSafeCall = false;
            if (resultKlass.isPrimitive()) {
                boxWhenSafeCall = true;
                resultKlass = resultKlass.asBoxedTypedKlass();
            }
            sb.append("((");
            sb.append(code.toString());
            sb.append("==null)?(");
            sb.append(resultKlass.getSource());
            sb.append(")null:");
            if (boxWhenSafeCall) {
                sb.append(resultKlass.getSource()).append(".valueOf(");
            }
            sb.append(code.toString());
            sb.append('.');
            sb.append(name);
            if (boxWhenSafeCall) {
                sb.append(')');
            }
            sb.append(')');
        } else {
            sb.append(code.toString());
            sb.append('.');
            sb.append(name);
        }
    }
    return new SegmentCode(resultKlass, sb.toString(), ctx);
}
Also used : Field(java.lang.reflect.Field) TypedKlass(jetbrick.template.parser.support.TypedKlass) SegmentCode(jetbrick.template.parser.code.SegmentCode) Method(java.lang.reflect.Method) Member(java.lang.reflect.Member) Map(java.util.Map) HashMap(java.util.HashMap) Expr_identifierContext(jetbrick.template.parser.grammer.JetTemplateParser.Expr_identifierContext)

Example 39 with SegmentCode

use of jetbrick.template.parser.code.SegmentCode in project jetbrick-template-1x by subchen.

the class JetTemplateCodeVisitor method visitFor_expression.

@Override
public Code visitFor_expression(For_expressionContext ctx) {
    String name = ctx.IDENTIFIER().getText();
    SegmentCode code = (SegmentCode) ctx.expression().accept(this);
    assert_not_void_expression(code);
    TypedKlass resultKlass = null;
    TypeContext type = ctx.type();
    if (type != null) {
        // 手动定义返回变量的类型
        SegmentCode c = (SegmentCode) type.accept(this);
        resultKlass = c.getTypedKlass();
    } else {
        // 根据 expression 来进行自动类型推导
        Class<?> rhsKlass = code.getKlass();
        if (rhsKlass.isArray()) {
            resultKlass = TypedKlass.create(rhsKlass.getComponentType(), code.getTypeArgs());
        } else if (Map.class.isAssignableFrom(rhsKlass)) {
            resultKlass = TypedKlass.create(Map.Entry.class, code.getTypeArgs());
        } else if (Collection.class.isAssignableFrom(rhsKlass)) {
            if (code.getTypeArgs() != null && code.getTypeArgs().length == 1) {
                resultKlass = code.getTypeArgs()[0];
            }
        }
    }
    if (resultKlass == null) {
        resultKlass = TypedKlass.Object;
    }
    // 必须是 Boxed 对象,因为需要强制类型转换 from iterator.next()
    resultKlass = resultKlass.asBoxedTypedKlass();
    if (!scopeCode.define(name, resultKlass)) {
        throw reportError("Duplicate local variable " + name, ctx.IDENTIFIER());
    }
    return new ForExpressionCode(resultKlass, name, code.toString(), ctx);
}
Also used : ForExpressionCode(jetbrick.template.parser.code.ForExpressionCode) TypedKlass(jetbrick.template.parser.support.TypedKlass) SegmentCode(jetbrick.template.parser.code.SegmentCode) TypeContext(jetbrick.template.parser.grammer.JetTemplateParser.TypeContext) Map(java.util.Map) HashMap(java.util.HashMap)

Example 40 with SegmentCode

use of jetbrick.template.parser.code.SegmentCode in project jetbrick-template-1x by subchen.

the class JetTemplateCodeVisitor method visitContinue_directive.

@Override
public Code visitContinue_directive(Continue_directiveContext ctx) {
    assert_inside_of_for_directive(ctx, "#continue");
    ExpressionContext expression = ctx.expression();
    String source;
    if (expression != null) {
        SegmentCode c = (SegmentCode) expression.accept(this);
        source = get_if_expression_source(c);
    } else {
        source = "true";
    }
    source = "if (" + source + ") continue; // line: " + ctx.getStart().getLine();
    return scopeCode.createLineCode(source);
}
Also used : ExpressionContext(jetbrick.template.parser.grammer.JetTemplateParser.ExpressionContext) SegmentCode(jetbrick.template.parser.code.SegmentCode)

Aggregations

SegmentCode (jetbrick.template.parser.code.SegmentCode)42 SegmentListCode (jetbrick.template.parser.code.SegmentListCode)14 TypedKlass (jetbrick.template.parser.support.TypedKlass)12 BlockCode (jetbrick.template.parser.code.BlockCode)11 DefineExpressionCode (jetbrick.template.parser.code.DefineExpressionCode)9 ExpressionContext (jetbrick.template.parser.grammer.JetTemplateParser.ExpressionContext)9 MacroCode (jetbrick.template.parser.code.MacroCode)8 ForExpressionCode (jetbrick.template.parser.code.ForExpressionCode)7 TerminalNode (org.antlr.v4.runtime.tree.TerminalNode)7 Code (jetbrick.template.parser.code.Code)6 ScopeCode (jetbrick.template.parser.code.ScopeCode)6 TagCode (jetbrick.template.parser.code.TagCode)6 TemplateClassCode (jetbrick.template.parser.code.TemplateClassCode)6 TextCode (jetbrick.template.parser.code.TextCode)6 Expression_listContext (jetbrick.template.parser.grammer.JetTemplateParser.Expression_listContext)6 Method (java.lang.reflect.Method)4 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Field (java.lang.reflect.Field)2 ConstantContext (jetbrick.template.parser.grammer.JetTemplateParser.ConstantContext)2