/** * jetbrick-template * http://subchen.github.io/jetbrick-template/ * * Copyright 2010-2014 Guoqiang Chen. All rights reserved. * Email: [email protected] * * 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 jetbrick.template.parser; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.lang.model.SourceVersion; import jetbrick.template.JetContext; import jetbrick.template.JetEngine; import jetbrick.template.JetSecurityManager; import jetbrick.template.parser.code.BlockCode; import jetbrick.template.parser.code.Code; import jetbrick.template.parser.code.DefineExpressionCode; import jetbrick.template.parser.code.ForExpressionCode; import jetbrick.template.parser.code.MacroCode; import jetbrick.template.parser.code.ScopeCode; import jetbrick.template.parser.code.SegmentCode; import jetbrick.template.parser.code.SegmentListCode; import jetbrick.template.parser.code.TagCode; import jetbrick.template.parser.code.TemplateClassCode; import jetbrick.template.parser.code.TextCode; import jetbrick.template.parser.grammer.JetTemplateParser; import jetbrick.template.parser.grammer.JetTemplateParser.BlockContext; import jetbrick.template.parser.grammer.JetTemplateParser.Break_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.ConstantContext; import jetbrick.template.parser.grammer.JetTemplateParser.Continue_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Define_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Define_expressionContext; import jetbrick.template.parser.grammer.JetTemplateParser.Define_expression_listContext; import jetbrick.template.parser.grammer.JetTemplateParser.DirectiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Else_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Elseif_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_array_getContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_array_listContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_class_castContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_compare_conditionContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_compare_equalityContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_compare_notContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_compare_relationalContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_conditional_ternaryContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_constantContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_field_accessContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_function_callContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_groupContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_hash_mapContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_identifierContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_instanceofContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_math_binary_basicContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_math_binary_bitwiseContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_math_binary_shiftContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_math_unary_prefixContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_math_unary_suffixContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_method_invocationContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_new_arrayContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_new_objectContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_static_field_accessContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expr_static_method_invocationContext; import jetbrick.template.parser.grammer.JetTemplateParser.ExpressionContext; import jetbrick.template.parser.grammer.JetTemplateParser.Expression_listContext; import jetbrick.template.parser.grammer.JetTemplateParser.For_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.For_expressionContext; import jetbrick.template.parser.grammer.JetTemplateParser.Hash_map_entry_listContext; import jetbrick.template.parser.grammer.JetTemplateParser.If_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Include_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Invalid_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Macro_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Put_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Set_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Set_expressionContext; import jetbrick.template.parser.grammer.JetTemplateParser.Static_type_nameContext; import jetbrick.template.parser.grammer.JetTemplateParser.Stop_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.Tag_directiveContext; import jetbrick.template.parser.grammer.JetTemplateParser.TemplateContext; import jetbrick.template.parser.grammer.JetTemplateParser.TextContext; import jetbrick.template.parser.grammer.JetTemplateParser.TypeContext; import jetbrick.template.parser.grammer.JetTemplateParser.Type_argumentsContext; import jetbrick.template.parser.grammer.JetTemplateParser.Type_array_suffixContext; import jetbrick.template.parser.grammer.JetTemplateParser.Type_listContext; import jetbrick.template.parser.grammer.JetTemplateParser.Type_nameContext; import jetbrick.template.parser.grammer.JetTemplateParser.ValueContext; import jetbrick.template.parser.grammer.JetTemplateParserVisitor; import jetbrick.template.parser.support.ClassUtils; import jetbrick.template.parser.support.NumberClassUtils; import jetbrick.template.parser.support.PromotionUtils; import jetbrick.template.parser.support.TypedKlass; import jetbrick.template.parser.support.TypedKlassUtils; import jetbrick.template.resource.Resource; import jetbrick.template.runtime.JetTagContext; import jetbrick.template.utils.PathUtils; import jetbrick.template.utils.StringEscapeUtils; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; // Visitor 模式访问器,用来生成 Java 代码 public class JetTemplateCodeVisitor extends AbstractParseTreeVisitor<Code> implements JetTemplateParserVisitor<Code> { private final JetEngine engine; private final Resource resource; private final JetTemplateParser parser; private final VariableResolver resolver; private final JetSecurityManager securityManager; private final boolean globalSafeCall; private final boolean trimDirectiveLine; private final boolean trimDirectiveComments; private final String commentsPrefix; private final String commentsSuffix; private TemplateClassCode tcc; // private ScopeCode scopeCode; // 当前作用域对应的 Code private Map<String, MacroCode> macroMap; // 宏定义 private Map<String, TextCode> textCache; // 文本内容缓存(可以减少冗余 Text) private Deque<String> forStack; // 维护嵌套 #for 的堆栈,可以识别是否在嵌入在 #for 里面, 内部存储当前 for 的真实变量名 private int uuid = 1; // 计数器 public JetTemplateCodeVisitor(JetEngine engine, VariableResolver resolver, JetSecurityManager securityManager, JetTemplateParser parser, Resource resource) { this.engine = engine; this.parser = parser; this.resolver = resolver; this.securityManager = securityManager; this.resource = resource; this.globalSafeCall = engine.getConfig().isSyntaxSafecall(); this.trimDirectiveLine = engine.getConfig().isTrimDirectiveLine(); this.trimDirectiveComments = engine.getConfig().isTrimDirectiveComments(); this.commentsPrefix = engine.getConfig().getTrimDirectiveCommentsPrefix(); this.commentsSuffix = engine.getConfig().getTrimDirectiveCommentsSuffix(); this.textCache = new HashMap<String, TextCode>(32); this.forStack = new ArrayDeque<String>(8); // 专门处理是否存在未完成的解析 (1.2.8 在 parser.g4 中添加 EOF,此处代码已经无用) //Token token = parser.getCurrentToken(); //if (token.getType() != Token.EOF) { // throw reportError("Invalid " + token.getText() + " directive in here.", token); //} } @Override public Code visitTemplate(TemplateContext ctx) { tcc = new TemplateClassCode(); tcc.setPackageName(resource.getPackageName()); tcc.setClassName(resource.getClassName()); tcc.setTemplateName(resource.getName()); tcc.setEncoding(engine.getConfig().getOutputEncoding()); scopeCode = tcc.getMethodCode(); scopeCode.define(Code.CONTEXT_NAME, TypedKlass.JetContext); scopeCode.setBodyCode(ctx.block().accept(this)); return tcc; } @Override public Code visitBlock(BlockContext ctx) { int size = ctx.getChildCount(); BlockCode code = scopeCode.createBlockCode(size); if (size == 0) return code; for (int i = 0; i < size; i++) { ParseTree node = ctx.children.get(i); Code c = node.accept(this); if (node instanceof TextContext) { // 文本节点 TextCode textCode = (TextCode) c; if (trimDirectiveLine || trimDirectiveComments) { ParseTree prev = (i > 0) ? ctx.children.get(i - 1) : null; ParseTree next = (i < size - 1) ? ctx.children.get(i + 1) : null; boolean trimLeft; boolean keepLeftNewLine = false; if (prev == null) { trimLeft = !(ctx.getParent() instanceof TemplateContext); } else { trimLeft = prev instanceof DirectiveContext; if (trimLeft) { // inline directive, 对于一个内联的 #if, #for 指令,后面有要求保留一个 NewLine // @see https://github.com/subchen/jetbrick-template/issues/25 ParserRuleContext directive = (ParserRuleContext) ((DirectiveContext) prev).getChild(0); if (directive instanceof If_directiveContext || directive instanceof For_directiveContext) { if (directive.getStart().getLine() == directive.getStop().getLine()) { keepLeftNewLine = true; // 保留一个 NewLine } } } } boolean trimRight; if (next == null) { trimRight = !(ctx.getParent() instanceof TemplateContext); } else { trimRight = (next instanceof DirectiveContext); } // trim 指令两边的注释 if (trimDirectiveComments) { textCode.trimComments(trimLeft, trimRight, commentsPrefix, commentsSuffix); } // trim 指令两边的空白内容 if (trimDirectiveLine) { textCode.trimEmptyLine(trimLeft, trimRight, keepLeftNewLine); } // trim 掉 #tag 和 #macro 指令最后一个多余的 '\n' if (next == null) { if (ctx.getParent() instanceof Tag_directiveContext || ctx.getParent() instanceof Macro_directiveContext) { textCode.trimLastNewLine(); } } } if (!textCode.isEmpty()) { // 如果有相同内容的Text,则从缓存中读取 TextCode old = textCache.get(textCode.getText()); if (old == null) { old = textCode; textCache.put(textCode.getText(), textCode); // add text into field tcc.addField(textCode.getId(), textCode.getText()); } code.addLine(old.toString()); } } else { code.addChild(c); } } return code; } @Override public Code visitText(TextContext ctx) { Token token = ((TerminalNode) ctx.getChild(0)).getSymbol(); String text = token.getText(); switch (token.getType()) { case JetTemplateParser.TEXT_CDATA: text = text.substring(3, text.length() - 3); break; case JetTemplateParser.TEXT_ESCAPED_CHAR: text = text.substring(1); break; } String id = getUid("txt"); return new TextCode(id, text); } @Override public Code visitValue(ValueContext ctx) { Code code = ctx.expression().accept(this); String source = code.toString(); // 如果返回值是 void,那么不需要 print 语句。 if (code instanceof SegmentCode) { Class<?> klass = ((SegmentCode) code).getKlass(); if (Void.TYPE.equals(klass)) { return scopeCode.createLineCode(source + "; // line: " + ctx.getStart().getLine()); } } Token token = ((TerminalNode) ctx.getChild(0)).getSymbol(); if (token.getType() == JetTemplateParser.VALUE_ESCAPED_OPEN) { source = "JetUtils.asEscapeHtml(" + source + ")"; } if ("null".equals(source)) { // 防止编译出错 (也可以生成一个空行) source = "(Object)null"; } return scopeCode.createLineCode("$out.print(" + source + "); // line: " + ctx.getStart().getLine()); } @Override public Code visitDirective(DirectiveContext ctx) { return ctx.getChild(0).accept(this); } @Override public Code visitDefine_directive(Define_directiveContext ctx) { SegmentListCode define_expression_list = (SegmentListCode) ctx.define_expression_list().accept(this); BlockCode code = scopeCode.createBlockCode(define_expression_list.size()); for (SegmentCode node : define_expression_list.getChildren()) { DefineExpressionCode c = (DefineExpressionCode) node; String name = c.getName(); if (!scopeCode.define(name, c.getTypedKlass())) { throw reportError("Duplicate local variable " + name, c.getNode()); } String typeName = c.getTypedKlass().asBoxedTypedKlass().toString(); code.addLine(typeName + " " + name + " = (" + typeName + ") " + Code.CONTEXT_NAME + ".get(\"" + name + "\"); // line: " + c.getNode().getStart().getLine()); } return code; } @Override public Code visitDefine_expression_list(Define_expression_listContext ctx) { List<Define_expressionContext> define_expression_list = ctx.define_expression(); SegmentListCode code = new SegmentListCode(define_expression_list.size()); for (Define_expressionContext define_expression : define_expression_list) { code.addChild((SegmentCode) define_expression.accept(this)); } return code; } @Override public Code visitDefine_expression(Define_expressionContext ctx) { SegmentCode code = (SegmentCode) ctx.type().accept(this); String name = assert_java_identifier(ctx.IDENTIFIER(), true); return new DefineExpressionCode(code.getTypedKlass(), name, ctx); } @Override public Code visitSet_directive(Set_directiveContext ctx) { List<Set_expressionContext> set_expression_list = ctx.set_expression(); BlockCode code = scopeCode.createBlockCode(set_expression_list.size()); for (Set_expressionContext node : set_expression_list) { Code c = node.accept(this); if (c != null) { code.addChild(c); } } return code; } @Override public Code visitSet_expression(Set_expressionContext ctx) { String name = assert_java_identifier(ctx.IDENTIFIER(), true); SegmentCode code = (SegmentCode) ctx.expression().accept(this); boolean defining = false; // 是否同时定义一个变量 TypedKlass lhs = null; // 变量类型 TypeContext type = ctx.type(); if (type != null) { defining = true; // 定义一个变量 SegmentCode c = (SegmentCode) type.accept(this); lhs = c.getTypedKlass(); if (!scopeCode.define(name, lhs)) { throw reportError("Duplicate local variable " + name, ctx.IDENTIFIER()); } } else { // 直接赋值,如果变量没有定义,则先定义 lhs = scopeCode.resolve(name, false); defining = (lhs == null); if (defining) { lhs = code.getTypedKlass(); scopeCode.define(name, lhs); } } // 进行赋值语句类型检查 if (!ClassUtils.isAssignable(lhs.getKlass(), code.getKlass())) { // 是否支持正常赋值 if (!ClassUtils.isAssignable(code.getKlass(), lhs.getKlass())) { // 是否支持强制类型转换 throw reportError("Type mismatch: cannot convert from " + code.getTypedKlass().toString() + " to " + lhs.toString(), ctx); } } BlockCode c = scopeCode.createBlockCode(2); String source = name + " = (" + lhs.getSource() + ") " + code.toString() + "; // line: " + ctx.getStart().getLine(); if (defining) { source = lhs.getSource() + " " + source; } c.addLine(source); c.addLine(Code.CONTEXT_NAME + ".put(\"" + name + "\", " + name + ");"); return c; } @Override public Code visitPut_directive(Put_directiveContext ctx) { List<ExpressionContext> expression_list = ctx.expression(); int size = expression_list.size(); if (size == 0 || size % 2 == 1) { throw reportError("Mismatched arguments count for #put directive", ctx); } BlockCode code = scopeCode.createBlockCode(size / 2); for (int i = 0; i < size; i += 2) { SegmentCode name = (SegmentCode) expression_list.get(i).accept(this); SegmentCode value = (SegmentCode) expression_list.get(i + 1).accept(this); if (!String.class.equals(name.getKlass())) { throw reportError("The argument type can't cast to String.class for #put directive", name.getNode()); } assert_not_void_expression(value); code.addLine(Code.CONTEXT_NAME + ".putAsParents(" + name.toString() + ", " + value.toString() + "); // line: " + ctx.getStart().getLine()); } return code; } @Override public Code visitIf_directive(If_directiveContext ctx) { BlockCode code = scopeCode.createBlockCode(16); SegmentCode expr_code = (SegmentCode) ctx.expression().accept(this); code.addLine("if (" + get_if_expression_source(expr_code) + ") { // line: " + ctx.getStart().getLine()); scopeCode = scopeCode.push(); code.addChild(ctx.block().accept(this)); scopeCode = scopeCode.pop(); code.addLine("}"); // elseif ... List<Elseif_directiveContext> elseif_directive_list = ctx.elseif_directive(); for (Elseif_directiveContext elseif_directive : elseif_directive_list) { code.addChild(elseif_directive.accept(this)); } // else ... Else_directiveContext else_directive = ctx.else_directive(); if (else_directive != null) { code.addChild(else_directive.accept(this)); } return code; } @Override public Code visitElseif_directive(Elseif_directiveContext ctx) { BlockCode code = scopeCode.createBlockCode(16); SegmentCode expr_code = (SegmentCode) ctx.expression().accept(this); code.addLine("else if (" + get_if_expression_source(expr_code) + ") { // line: " + ctx.getStart().getLine()); scopeCode = scopeCode.push(); code.addChild(ctx.block().accept(this)); scopeCode = scopeCode.pop(); code.addLine("}"); return code; } @Override public Code visitElse_directive(Else_directiveContext ctx) { BlockCode code = scopeCode.createBlockCode(16); if (ctx.getParent() instanceof If_directiveContext) { code.addLine("else { // line: " + ctx.getStart().getLine()); } scopeCode = scopeCode.push(); code.addChild(ctx.block().accept(this)); scopeCode = scopeCode.pop(); if (ctx.getParent() instanceof If_directiveContext) { code.addLine("}"); } return code; } @Override public Code visitFor_directive(For_directiveContext ctx) { BlockCode code = scopeCode.createBlockCode(16); String id_for = getUid("for"); scopeCode = scopeCode.push(); // 注意:for循环变量的作用域要放在 for 内部, 防止出现变量重定义错误 ForExpressionCode for_expr_code = (ForExpressionCode) ctx.for_expression().accept(this); // for block forStack.push(id_for); Code for_block_code = ctx.block().accept(this); forStack.pop(); scopeCode = scopeCode.pop(); // for-else Else_directiveContext else_directive = ctx.else_directive(); Code for_else_block = (else_directive == null) ? null : else_directive.accept(this); // 生成代码 String id_foritem = getUid("foritem"); String typeName = for_expr_code.getKlassName(); String itemName = for_expr_code.getName(); code.addLine("Object " + id_foritem + " = context.get(\"" + itemName + "\"); // save it"); code.addLine("JetForIterator " + id_for + " = new JetForIterator(" + for_expr_code.toString() + ");"); code.addLine("while (" + id_for + ".hasNext()) { // line: " + ctx.getStart().getLine()); // class item = (class) it.next() ... code.addLine(" " + typeName + " " + itemName + " = (" + typeName + ") " + id_for + ".next();"); code.addLine(" context.put(\"" + itemName + "\", " + itemName + ");"); code.addChild(for_block_code); code.addLine("}"); code.addLine("context.put(\"" + itemName + "\", " + id_foritem + "); // reset it"); // for else ... if (for_else_block != null) { code.addLine("if (" + id_for + ".empty()) { // line: " + ctx.getStart().getLine()); code.addChild(for_else_block); code.addLine("}"); } return code; } @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); } @Override public Code visitBreak_directive(Break_directiveContext ctx) { assert_inside_of_for_directive(ctx, "#break"); 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 + ") break; // line: " + ctx.getStart().getLine(); return scopeCode.createLineCode(source); } @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); } @Override public Code visitStop_directive(Stop_directiveContext ctx) { 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 + ") return; // line: " + ctx.getStart().getLine(); return scopeCode.createLineCode(source); } @Override public Code visitInclude_directive(Include_directiveContext ctx) { Expression_listContext expression_list = ctx.expression_list(); SegmentListCode childrenCode = (SegmentListCode) expression_list.accept(this); if (childrenCode.size() > 2) { throw reportError("Arguments mismatch for #include directive.", ctx); } // argument 1: file SegmentCode fileCode = childrenCode.getChild(0); ExpressionContext fileExpression = expression_list.expression(0); if (!String.class.equals(fileCode.getKlass())) { throw reportError("Type mismatch: the first argument cannot convert from " + fileCode.getKlassName() + " to String", fileExpression); } // argument 2: parameters SegmentCode parametersCode = null; if (childrenCode.size() > 1) { parametersCode = childrenCode.getChild(1); if (!(Map.class.equals(parametersCode.getKlass()))) { throw reportError("Type mismatch: the second argument cannot convert from " + parametersCode.getKlassName() + " to Map", expression_list.expression(1)); } } // 如果 file 是常量,那么进行 file.exists() 校验 if (fileExpression instanceof Expr_constantContext) { String file = fileCode.toString(); file = file.substring(1, file.length() - 1); file = StringEscapeUtils.unescapeJava(file); file = PathUtils.getAbsolutionName(resource.getName(), file); if (!engine.lookupResource(file)) { throw reportError("FileNotFoundException: " + file, fileExpression); } } // 生成代码 StringBuilder source = new StringBuilder(); source.append("JetUtils.asInclude($ctx, "); source.append(fileCode.toString()); source.append(", (Map<String, Object>)"); source.append((parametersCode != null) ? parametersCode.toString() : "null"); source.append("); // line: "); source.append(ctx.getStart().getLine()); return scopeCode.createLineCode(source.toString()); } @Override public Code visitTag_directive(Tag_directiveContext ctx) { String text = ctx.getChild(0).getText(); String name = text.substring(5, text.length() - 1).trim(); TagCode tagCode = scopeCode.createTagCode(); tagCode.setTagId(getUid("tag")); scopeCode = tagCode.getMethodCode(); scopeCode.define(Code.CONTEXT_NAME, TypedKlass.JetContext); scopeCode.setBodyCode(ctx.block().accept(this)); // add body content scopeCode = scopeCode.pop(); // finding tag function Expression_listContext expression_list = ctx.expression_list(); SegmentListCode segmentListCode = (expression_list == null) ? SegmentListCode.EMPTY : (SegmentListCode) expression_list.accept(this); Class<?>[] parameterTypes = segmentListCode.getParameterTypes(JetTagContext.class); Method method = resolver.resolveTagMethod(name, parameterTypes); if (method == null) { throw reportError("Undefined tag definition: " + getMethodSignature(name, parameterTypes), ctx); } tagCode.setMethod(method); tagCode.setExpressionListCode(segmentListCode); return tagCode; } @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 scopeCode.setBodyCode(ctx.block().accept(this)); // add body content scopeCode = scopeCode.pop(); return Code.EMPTY; } @Override public Code visitInvalid_directive(Invalid_directiveContext ctx) { throw reportError("Missing arguments for " + ctx.getText() + " directive.", ctx); } @Override public Code visitExpr_group(Expr_groupContext ctx) { SegmentCode code = (SegmentCode) ctx.expression().accept(this); String source = "(" + code.toString() + ")"; return new SegmentCode(code.getTypedKlass(), source, ctx); } @Override public Code visitExpr_constant(Expr_constantContext ctx) { return ctx.getChild(0).accept(this); } @Override public Code visitExpr_array_list(Expr_array_listContext ctx) { String source = "Collections.EMPTY_LIST"; Expression_listContext expression_list = ctx.expression_list(); if (expression_list != null) { Code code = expression_list.accept(this); source = "Arrays.asList(" + code.toString() + ")"; } return new SegmentCode(List.class, source, ctx); } @Override public Code visitExpr_hash_map(Expr_hash_mapContext ctx) { String source = "Collections.EMPTY_MAP"; Hash_map_entry_listContext hash_map_entry_list = ctx.hash_map_entry_list(); if (hash_map_entry_list != null) { Code code = hash_map_entry_list.accept(this); source = "JetUtils.asMap(" + code.toString() + ")"; } return new SegmentCode(Map.class, source, ctx); } @Override public Code visitHash_map_entry_list(Hash_map_entry_listContext ctx) { List<ExpressionContext> expression_list = ctx.expression(); SegmentListCode code = new SegmentListCode(expression_list.size()); for (ExpressionContext expression : expression_list) { code.addChild((SegmentCode) expression.accept(this)); } return code; } @Override public Code visitExpr_identifier(Expr_identifierContext ctx) { String name = assert_java_identifier(ctx.IDENTIFIER(), false); // 特殊处理 for 变量 if ("for".equals(name)) { assert_inside_of_for_directive(ctx, "Local variable \"for\""); // 强制映射成 JetForStatus $for String forStatus = forStack.peek(); // 取出 forStatus 的实际变量名 return new SegmentCode(TypedKlass.JetForStatus, forStatus, ctx); } // 找到变量的类型 TypedKlass resultKlass = scopeCode.resolve(name, false); if (resultKlass == null) { // 没有定义过,继续向上深度查找 resultKlass = scopeCode.resolve(name, true); // 没有定义过,则查找全局定义 if (resultKlass == null) { resultKlass = resolver.resolveVariable(name); } if (scopeCode.define(name, resultKlass, true)) { if (resultKlass == TypedKlass.Object) { //removed unsed warning in 1.2.0 //log.warn("line " + ctx.getStart().getLine() + ": Implicit definition for context variable: " + resultKlass.toString() + " " + name); } } } return new SegmentCode(resultKlass, name, ctx); } @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); } @Override public Code visitExpr_method_invocation(Expr_method_invocationContext ctx) { // 处理参数 Expression_listContext expression_list = ctx.expression_list(); SegmentListCode segmentListCode = (expression_list == null) ? SegmentListCode.EMPTY : (SegmentListCode) expression_list.accept(this); Class<?>[] parameterTypes = segmentListCode.getParameterTypes(); // 查找方法 SegmentCode code = (SegmentCode) ctx.expression().accept(this); assert_not_null_constantContext(code.getNode()); code = code.asBoxedSegmentCode(); Class<?> beanClass = code.getKlass(); String name = ctx.IDENTIFIER().getText(); Method bean_method = resolver.resolveMethod(beanClass, name, parameterTypes); Method tool_method = (bean_method != null) ? null : resolver.resolveToolMethod(beanClass, name, parameterTypes); boolean tool_advanced = false; if (bean_method == null && tool_method == null) { tool_method = resolver.resolveToolMethod_advanced(beanClass, name, parameterTypes); tool_advanced = true; } if (bean_method == null && tool_method == null) { // reportError StringBuilder err = new StringBuilder(128); err.append("The method ").append(getMethodSignature(name, parameterTypes)); 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()); // 得到方法的返回类型 Method method = (bean_method == null) ? tool_method : bean_method; if (securityManager != null) { securityManager.checkMemberAccess(method); } TypedKlass resultKlass = TypedKlassUtils.getMethodReturnTypedKlass(method); boolean boxWhenSafeCall = resultKlass.isPrimitive(); if (isSafeCall) { resultKlass = resultKlass.asBoxedTypedKlass(); } // 生成code StringBuilder sb = new StringBuilder(64); if (tool_method != null) { // tool method if (isSafeCall) { // 安全调用,防止 NullPointException 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(ClassUtils.getShortClassName(tool_method.getDeclaringClass())); sb.append('.'); sb.append(name); sb.append('('); sb.append(code.toString()); if (tool_advanced) { sb.append(",$ctx"); } if (segmentListCode.size() > 0) { sb.append(','); } } else { if (isSafeCall) { // 安全调用,防止 NullPointException 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); sb.append('('); } if (segmentListCode.size() > 0) { sb.append(segmentListCode.toString()); } sb.append(')'); if (isSafeCall) { // 为了安全起见,用()包起来 if (boxWhenSafeCall) { sb.append(')'); } sb.insert(0, '(').append(')'); } return new SegmentCode(resultKlass, sb.toString(), ctx); } @Override public Code visitExpr_function_call(Expr_function_callContext ctx) { // 处理参数 Expression_listContext expression_list = ctx.expression_list(); SegmentListCode segmentListCode = (expression_list == null) ? SegmentListCode.EMPTY : (SegmentListCode) expression_list.accept(this); Class<?>[] parameterTypes = segmentListCode.getParameterTypes(); // 查找方法 String name = ctx.IDENTIFIER().getText(); // 优先查找 macro MacroCode macroCode = null; if (macroMap != null) { macroCode = macroMap.get(name); if (macroCode != null) { // macro 参数匹配 SegmentListCode defineListCode = macroCode.getDefineListCode(); int size = (defineListCode == null) ? 0 : defineListCode.size(); if (parameterTypes.length != size) { throw reportError("Arguments mismatch for #macro " + getMethodSignature(name, parameterTypes) + ".", ctx.IDENTIFIER()); } for (int i = 0; i < parameterTypes.length; i++) { if (!ClassUtils.isAssignable(parameterTypes[i], defineListCode.getChild(i).getKlass())) { throw reportError("Arguments mismatch for #macro " + getMethodSignature(name, parameterTypes) + ".", ctx.IDENTIFIER()); } } // 生成 macro 调用 code StringBuilder sb = new StringBuilder(64); sb.append("$macro_").append(name); sb.append("($ctx"); if (segmentListCode.size() > 0) { sb.append(',').append(segmentListCode.toString()); } sb.append(')'); return new SegmentCode(TypedKlass.VOID, sb.toString(), ctx); } } // 查找扩展方法 boolean advanced = false; Method method = resolver.resolveFunction(name, parameterTypes); if (method == null) { method = resolver.resolveFunction_advanced(name, parameterTypes); advanced = true; } if (method == null) { throw reportError("Undefined function or arguments mismatch: " + getMethodSignature(name, parameterTypes) + ".", ctx.IDENTIFIER()); } if (securityManager != null) { securityManager.checkMemberAccess(method); } // 生成code StringBuilder sb = new StringBuilder(64); sb.append(ClassUtils.getShortClassName(method.getDeclaringClass())); sb.append('.'); sb.append(name); sb.append('('); if (advanced) { sb.append("$ctx"); } if (segmentListCode.size() > 0) { if (advanced) sb.append(','); sb.append(segmentListCode.toString()); } sb.append(')'); TypedKlass typedKlass = TypedKlassUtils.getMethodReturnTypedKlass(method); return new SegmentCode(typedKlass, sb.toString(), ctx); } @Override public Code visitExpr_static_field_access(Expr_static_field_accessContext ctx) { SegmentCode static_type_name_code = (SegmentCode) ctx.static_type_name().accept(this); String typeName = static_type_name_code.toString(); String name = ctx.IDENTIFIER().getText(); Class<?> beanClass = resolver.resolveClass(typeName); if (beanClass == null) { throw reportError("java.lang.ClassNotFoundException: " + typeName, static_type_name_code.getNode()); } Field field = resolver.resolveStaticField(beanClass, name); if (field == null) { throw reportError(name + " is not a static field for type " + beanClass.getName(), ctx.IDENTIFIER()); } if (securityManager != null) { securityManager.checkMemberAccess(field); } String source = ClassUtils.getShortClassName(field.getDeclaringClass()) + '.' + name; TypedKlass resultKlass = TypedKlassUtils.getFieldTypedKlass(field); return new SegmentCode(resultKlass, source, ctx); } @Override public Code visitExpr_static_method_invocation(Expr_static_method_invocationContext ctx) { SegmentCode static_type_name_code = (SegmentCode) ctx.static_type_name().accept(this); String typeName = static_type_name_code.toString(); String name = ctx.IDENTIFIER().getText(); // 获取静态 Class Class<?> beanClass = resolver.resolveClass(typeName); if (beanClass == null) { throw reportError("java.lang.ClassNotFoundException: " + typeName, static_type_name_code.getNode()); } // 处理参数 Expression_listContext expression_list = ctx.expression_list(); SegmentListCode segmentListCode = (expression_list == null) ? SegmentListCode.EMPTY : (SegmentListCode) expression_list.accept(this); Class<?>[] parameterTypes = segmentListCode.getParameterTypes(); Method method = resolver.resolveStaticMethod(beanClass, name, parameterTypes); if (method == null) { throw reportError("The static method " + getMethodSignature(name, parameterTypes) + " is undefined for the type " + beanClass.getName(), ctx.IDENTIFIER()); } if (securityManager != null) { securityManager.checkMemberAccess(method); } // 生成代码 StringBuilder sb = new StringBuilder(); sb.append(ClassUtils.getShortClassName(method.getDeclaringClass())); sb.append('.'); sb.append(name); sb.append('('); sb.append(segmentListCode.toString()); sb.append(')'); TypedKlass resultKlass = TypedKlassUtils.getMethodReturnTypedKlass(method); return new SegmentCode(resultKlass, sb.toString(), ctx); } @Override public Code visitStatic_type_name(Static_type_nameContext ctx) { List<TerminalNode> name_list = ctx.IDENTIFIER(); StringBuilder sb = new StringBuilder(); for (TerminalNode node : name_list) { if (sb.length() > 0) { sb.append('.'); } sb.append(node.getText()); } return new SegmentCode(TypedKlass.NULL, sb.toString(), ctx); } @Override public Code visitExpr_array_get(Expr_array_getContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this); assert_not_null_constantContext(lhs.getNode()); assert_not_null_constantContext(rhs.getNode()); boolean isSafeCall = globalSafeCall || "?".equals(ctx.getChild(1).getText()); Class<?> lhsKlass = lhs.getKlass(); if (lhsKlass.isArray()) { if (!ClassUtils.isAssignable(Integer.TYPE, rhs.getKlass())) { throw reportError("Type mismatch: cannot convert from " + rhs.getKlassName() + " to int.", lhs.getNode()); } TypedKlass resultKlass = TypedKlass.create(lhsKlass.getComponentType(), lhs.getTypeArgs()); boolean boxWhenSafeCall = resultKlass.isPrimitive(); if (isSafeCall) { resultKlass = resultKlass.asBoxedTypedKlass(); } StringBuilder sb = new StringBuilder(); if (isSafeCall) { sb.append('('); sb.append(lhs.toString()); sb.append("==null?("); sb.append(resultKlass.getSource()); sb.append(")null:"); if (boxWhenSafeCall) { sb.append(resultKlass.getSource()).append(".valueOf("); } sb.append(lhs.toString()); sb.append('['); sb.append(rhs.toString()); sb.append(']'); if (boxWhenSafeCall) { sb.append(')'); } sb.append(')'); } else { sb.append(lhs.toString()); sb.append('['); sb.append(rhs.toString()); sb.append(']'); } return new SegmentCode(resultKlass, sb.toString(), ctx); } else { TypedKlass resultKlass = null; // try to List.get(index) or Map.get(name) or JetContext.get(name) if (List.class.isAssignableFrom(lhsKlass)) { if (!ClassUtils.isAssignable(Integer.TYPE, rhs.getKlass())) { throw reportError("The method get(int) in the type List is not applicable for the arguments (" + rhs.getKlassName() + ")", rhs.getNode()); } // 取出可能的List泛型 if (lhs.getTypeArgs() != null && lhs.getTypeArgs().length == 1) { resultKlass = lhs.getTypeArgs()[0]; } } else if (Map.class.isAssignableFrom(lhsKlass)) { // 取出可能的Map泛型 if (lhs.getTypeArgs() != null && lhs.getTypeArgs().length == 2) { resultKlass = lhs.getTypeArgs()[1]; // value 对应的泛型 } } else if (JetContext.class.isAssignableFrom(lhsKlass)) { if (!String.class.equals(rhs.getKlass())) { throw reportError("The method get(String) in the type JetContext is not applicable for the arguments (" + rhs.getKlassName() + ")", rhs.getNode()); } resultKlass = TypedKlass.Object; } else { throw reportError("Operator [] is not applicable for the object (" + lhs.getKlassName() + ").", ctx); } if (resultKlass == null) { resultKlass = TypedKlass.Object; } boolean boxWhenSafeCall = resultKlass.isPrimitive(); if (isSafeCall) { resultKlass = resultKlass.asBoxedTypedKlass(); } StringBuilder sb = new StringBuilder(); if (isSafeCall) { sb.append('('); sb.append(lhs.toString()); sb.append("==null?("); sb.append(resultKlass.getSource()); sb.append(")null:"); if (boxWhenSafeCall) { sb.append(resultKlass.getSource()).append(".valueOf("); } sb.append(lhs.toString()); sb.append(".get("); sb.append(rhs.toString()); sb.append(')'); if (boxWhenSafeCall) { sb.append(')'); } sb.append(')'); } else { sb.append(lhs.toString()); sb.append(".get("); sb.append(rhs.toString()); sb.append(')'); } return new SegmentCode(resultKlass, sb.toString(), ctx); } } @Override public Code visitExpr_new_object(Expr_new_objectContext ctx) { SegmentCode code = (SegmentCode) ctx.type().accept(this); Expression_listContext expression_list = ctx.expression_list(); SegmentListCode segmentListCode = (expression_list == null) ? SegmentListCode.EMPTY : (SegmentListCode) expression_list.accept(this); Class<?>[] parameterTypes = segmentListCode.getParameterTypes(); // 查找对应的构造函数 Class<?> beanClass = code.getKlass(); Constructor<?> constructor = resolver.resolveConstructor(beanClass, parameterTypes); if (constructor == null) { // reportError StringBuilder err = new StringBuilder(128); err.append("The constructor "); err.append(getMethodSignature(beanClass.getSimpleName(), parameterTypes)); err.append(" is undefined for the type "); err.append(beanClass.getName()); err.append('.'); throw reportError(err.toString(), ctx.type()); } // 生成代码 StringBuilder source = new StringBuilder(32); source.append("(new ").append(code.toString()).append('('); if (segmentListCode.size() > 0) { source.append(segmentListCode.toString()); } source.append("))"); return new SegmentCode(code.getTypedKlass(), source.toString(), ctx); } @Override public Code visitExpr_new_array(Expr_new_arrayContext ctx) { SegmentCode code = (SegmentCode) ctx.type().accept(this); if (code.getKlass().isArray()) { throw reportError("Cannot specify an array dimension after an empty dimension", ctx.type()); } StringBuilder typeSource = new StringBuilder(code.toString()); // 生成代码 StringBuilder source = new StringBuilder(32); source.append("(new ").append(code.toString()); for (ExpressionContext expression : ctx.expression()) { SegmentCode c = (SegmentCode) expression.accept(this); if (!ClassUtils.isAssignable(Integer.TYPE, c.getKlass())) { throw reportError("Type mismatch: cannot convert from " + c.getKlassName() + " to int.", expression); } source.append('[').append(c.toString()).append(']'); typeSource.append("[]"); } source.append(')'); TypedKlass resultKlass = resolver.resolveTypedKlass(typeSource.toString()); return new SegmentCode(resultKlass, source.toString(), ctx); } @Override public Code visitExpr_class_cast(Expr_class_castContext ctx) { SegmentCode code = (SegmentCode) ctx.type().accept(this); Code expr_code = ctx.expression().accept(this); String source = "((" + code.toString() + ")" + expr_code.toString() + ")"; return new SegmentCode(code.getTypedKlass(), source, ctx); } @Override public Code visitExpr_instanceof(Expr_instanceofContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression().accept(this); SegmentCode rhs = (SegmentCode) ctx.type().accept(this); if (!ClassUtils.isAssignable(lhs.getKlass(), rhs.getKlass()) && !ClassUtils.isAssignable(lhs.getKlass(), rhs.getKlass())) { throw reportError("Incompatible conditional operand types " + lhs.getKlassName() + " and " + rhs.getKlassName(), ctx.getChild(1)); } String source = "(" + lhs.toString() + " instanceof " + rhs.toString() + ")"; return new SegmentCode(Boolean.TYPE, source, ctx); } @Override public Code visitExpr_math_unary_suffix(Expr_math_unary_suffixContext ctx) { ExpressionContext expression = ctx.expression(); SegmentCode code = (SegmentCode) expression.accept(this); String op = ctx.getChild(1).getText(); assert_not_null_constantContext(expression); // ++, -- if (expression.getChildCount() == 1 && expression.getChild(0) instanceof ConstantContext) { throw reportError("Invalid argument to operation " + op + ", required: variable, found Value", expression); } // 类型检查 Class<?> resultKlass = PromotionUtils.get_unary_inc_dec(code.getKlass(), op); if (resultKlass == null) { throw reportError("The UnaryOperator \"" + op + "\" is not applicable for the operand " + code.getKlassName(), ctx.getChild(1)); } String source = "(" + code.toString() + op + ")"; return new SegmentCode(code.getTypedKlass(), source, ctx); } @Override public Code visitExpr_math_unary_prefix(Expr_math_unary_prefixContext ctx) { ExpressionContext expression = ctx.expression(); SegmentCode code = (SegmentCode) expression.accept(this); String op = ctx.getChild(0).getText(); assert_not_null_constantContext(expression); // 类型检查 Class<?> resultKlass; if (op.length() == 1) { // +, -, ~ resultKlass = PromotionUtils.get_unary_basic(code.getKlass(), op); } else { // ++, -- if (expression.getChildCount() == 1 && expression.getChild(0) instanceof ConstantContext) { throw reportError("Invalid argument to operation " + op + ", required: variable, found Value", expression); } resultKlass = PromotionUtils.get_unary_inc_dec(code.getKlass(), op); } if (resultKlass == null) { throw reportError("The UnaryOperator \"" + op + "\" is not applicable for the operand " + code.getKlassName(), ctx.getChild(0)); } String source = "(" + op + code.toString() + ")"; return new SegmentCode(code.getTypedKlass(), source, ctx); } @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); } @Override public Code visitExpr_math_binary_shift(Expr_math_binary_shiftContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this); // Combined '>' '>' => '>>' String op = ""; for (int i = 1; i < ctx.getChildCount() - 1; i++) { ParseTree node = ctx.getChild(i); if (node instanceof TerminalNode) { op = op + node.getText(); } } // 类型检查 Class<?> resultKlass = PromotionUtils.get_binary_shift(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); } @Override public Code visitExpr_math_binary_bitwise(Expr_math_binary_bitwiseContext 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_bitwise(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); } String source = "(" + lhs.toString() + op + rhs.toString() + ")"; return new SegmentCode(resultKlass, source, ctx); } @Override public Code visitExpr_compare_not(Expr_compare_notContext ctx) { SegmentCode code = (SegmentCode) ctx.expression().accept(this); String source = "(!" + get_if_expression_source(code) + ")"; return new SegmentCode(Boolean.TYPE, source, ctx); } @Override public Code visitExpr_compare_equality(Expr_compare_equalityContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this); TerminalNode op = (TerminalNode) ctx.getChild(1); assert_not_void_expression(lhs); assert_not_void_expression(rhs); StringBuilder source = new StringBuilder(32); source.append("==".equals(op.getText()) ? "JetUtils.asEquals(" : "JetUtils.asNotEquals("); source.append(lhs.toString()); source.append(','); source.append(rhs.toString()); source.append(')'); return new SegmentCode(Boolean.TYPE, source.toString(), ctx); } @Override public Code visitExpr_compare_relational(Expr_compare_relationalContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this); TerminalNode op = (TerminalNode) ctx.getChild(1); assert_not_void_expression(lhs); assert_not_void_expression(rhs); assert_not_null_constantContext(lhs.getNode()); assert_not_null_constantContext(rhs.getNode()); Class<?> c1 = lhs.getKlass(); Class<?> c2 = rhs.getKlass(); // 类型校验 boolean pass = true; if (NumberClassUtils.isNumbericClass(c1)) { pass = NumberClassUtils.isNumbericClass(c2); } else if (NumberClassUtils.isNumbericClass(c2)) { pass = false; } else { pass = c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1); } if (pass == false) { throw reportError("The operator " + op.getText() + " is undefined for the argument type(s) " + lhs.getKlassName() + ", " + rhs.getKlassName(), op); } String suffix = ""; switch (op.getSymbol().getType()) { case JetTemplateParser.OP_RELATIONAL_GT: suffix = ">0"; break; case JetTemplateParser.OP_RELATIONAL_LT: suffix = "<0"; break; case JetTemplateParser.OP_RELATIONAL_GE: suffix = ">=0"; break; case JetTemplateParser.OP_RELATIONAL_LE: suffix = "<=0"; break; default: throw reportError("Unexpected operator :" + op.getText(), ctx); } StringBuilder source = new StringBuilder(32); source.append("(JetUtils.asCompareWith("); source.append(lhs.toString()); source.append(','); source.append(rhs.toString()); source.append(')'); source.append(suffix); source.append(')'); return new SegmentCode(Boolean.TYPE, source.toString(), ctx); } @Override public Code visitExpr_compare_condition(Expr_compare_conditionContext ctx) { SegmentCode lhs = (SegmentCode) ctx.expression(0).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(1).accept(this); String op = ctx.getChild(1).getText(); assert_not_void_expression(lhs); assert_not_void_expression(rhs); String source = "(" + get_if_expression_source(lhs) + op + get_if_expression_source(rhs) + ")"; return new SegmentCode(Boolean.TYPE, source, ctx); } @Override public Code visitExpr_conditional_ternary(Expr_conditional_ternaryContext ctx) { SegmentCode condition = (SegmentCode) ctx.expression(0).accept(this); SegmentCode lhs = (SegmentCode) ctx.expression(1).accept(this); SegmentCode rhs = (SegmentCode) ctx.expression(2).accept(this); String source = "(" + get_if_expression_source(condition) + "?" + lhs.toString() + ":" + rhs.toString() + ")"; TypedKlass klass = PromotionUtils.getResultClassForConditionalOperator(lhs.getTypedKlass(), rhs.getTypedKlass()); return new SegmentCode(klass, source, ctx); } @Override public Code visitConstant(ConstantContext ctx) { Token token = ((TerminalNode) ctx.getChild(0)).getSymbol(); String text = token.getText(); switch (token.getType()) { case JetTemplateParser.STRING_DOUBLE: return new SegmentCode(String.class, text, ctx); case JetTemplateParser.STRING_SINGLE: text = StringEscapeUtils.asCanonicalJavaString(text); return new SegmentCode(String.class, text, ctx); case JetTemplateParser.INTEGER: case JetTemplateParser.INTEGER_HEX: case JetTemplateParser.FLOATING_POINT: Class<?> klass; if (text.endsWith("l") || text.endsWith("L")) { klass = Long.TYPE; } else if (text.endsWith("f") || text.endsWith("F")) { klass = Float.TYPE; } else if (text.endsWith("d") || text.endsWith("D")) { klass = Double.TYPE; } else if (token.getType() == JetTemplateParser.FLOATING_POINT) { klass = Double.TYPE; // 浮点数默认是double } else { klass = Integer.TYPE; } return new SegmentCode(klass, text, ctx); case JetTemplateParser.KEYWORD_TRUE: return new SegmentCode(Boolean.TYPE, text, ctx); case JetTemplateParser.KEYWORD_FALSE: return new SegmentCode(Boolean.TYPE, text, ctx); case JetTemplateParser.KEYWORD_NULL: return new SegmentCode(TypedKlass.NULL, text, ctx); default: throw reportError("Unexpected token type :" + token.getType(), ctx); } } @Override public Code visitExpression_list(Expression_listContext ctx) { List<ExpressionContext> expression_list = ctx.expression(); SegmentListCode code = new SegmentListCode(expression_list.size()); for (ExpressionContext expression : expression_list) { SegmentCode c = (SegmentCode) expression.accept(this); assert_not_void_expression(c); code.addChild(c); } return code; } @Override public Code visitType(TypeContext ctx) { StringBuilder name = new StringBuilder(); for (TerminalNode node : ctx.IDENTIFIER()) { if (name.length() > 0) { name.append('.'); } name.append(node.getText()); } // 查找 klass Class<?> klass = resolver.resolveClass(name.toString()); if (klass == null) { StringBuilder sb = new StringBuilder(128); sb.append("java.lang.ClassNotFoundException: ").append(name); sb.append("\n advise: Please define package in 'import.packages' or use full qualified class name."); throw reportError(sb.toString(), ctx); } if (securityManager != null) { securityManager.checkMemberAccess(klass); } // 查找泛型类型 typeArgs TypedKlass[] typeArgs = TypedKlass.EMPTY_TYPE_ARGS; Type_argumentsContext type_arguments = ctx.type_arguments(); if (type_arguments != null) { SegmentListCode c = (SegmentListCode) type_arguments.accept(this); typeArgs = new TypedKlass[c.size()]; for (int i = 0; i < typeArgs.length; i++) { typeArgs[i] = c.getChild(i).getTypedKlass(); } } // 如果是数组类型,则把 klass 转成数组 String array_suffix = ""; List<Type_array_suffixContext> type_array_suffix = ctx.type_array_suffix(); for (Type_array_suffixContext c : type_array_suffix) { Code code = c.accept(this); array_suffix = array_suffix + code.toString(); } if (array_suffix.length() > 0) { // 转换成 Array Class, 重新 resolve String klassName = name.toString() + array_suffix; klass = resolver.resolveClass(klassName); if (klass == null) { throw reportError("java.lang.ClassNotFoundException: " + klassName, ctx); } } // 返回带有的泛型信息的 Class TypedKlass typedKlass = TypedKlass.create(klass, typeArgs); return new SegmentCode(typedKlass, typedKlass.toString(), ctx); } @Override public Code visitType_array_suffix(Type_array_suffixContext ctx) { return new SegmentCode((TypedKlass) null, "[]", ctx); } @Override public Code visitType_arguments(Type_argumentsContext ctx) { return ctx.type_list().accept(this); } @Override public Code visitType_list(Type_listContext ctx) { List<Type_nameContext> type_name_list = ctx.type_name(); SegmentListCode code = new SegmentListCode(type_name_list.size()); for (Type_nameContext type_name : type_name_list) { Code c = type_name.accept(this); code.addChild((SegmentCode) c); } return code; } @Override public Code visitType_name(Type_nameContext ctx) { TypeContext type = ctx.type(); if (type != null) { return type.accept(this); } // List<?> return new SegmentCode(TypedKlass.WildcharTypedKlass, "?", ctx); } // ----------------------------------------------------------- // 变量必须是合法的 java 变量 private String assert_java_identifier(ParseTree node, boolean isDefining) { String name = node.getText(); if ("for".equals(name)) { if (isDefining) { throw reportError("Syntax error on token \"" + name + "\" is not a valid identifier.", node); } return name; } if (Code.CONTEXT_NAME.equals(name)) { if (isDefining) { throw reportError("Duplicate local variable \"" + name + "\" is a reserved identifier.", node); } return name; } if (SourceVersion.isKeyword(name)) { throw reportError("Syntax error on token \"" + name + "\", It is not a valid identifier in Java.", node); } if (name.startsWith("$")) { throw reportError("Local variable \"" + name + "\" can't start with '$', it is a reserved identifier.", node); } return name; } // 检验 ctx 必须在 #for 里面, 但不能在 for-else 里面 private void assert_inside_of_for_directive(ParserRuleContext ctx, String name) { // 还有一种方法,直接看 forStack 是否为空就可以了 ParserRuleContext p = ctx.getParent(); while (p != null) { if (p instanceof For_directiveContext) { return; } if (p instanceof Else_directiveContext) { // 跳过可能的 for-else 的情况, 继续向上查找 // 当然如果时候 if-else 的情况, 也可以跳过这个 #if,没有问题 p = p.getParent(); } p = p.getParent(); } throw reportError(name + " cannot be used outside of a #for directive", ctx); } // 检测 void 类型 private void assert_not_void_expression(SegmentCode code) { if (Void.TYPE.equals(code.getKlass()) || Void.class.equals(code.getKlass())) { throw reportError("Unexpected void type in here.", code.getNode()); } } // 检测非 null 常量 private void assert_not_null_constantContext(ParserRuleContext node) { if (node.getStart().getType() == JetTemplateParser.KEYWORD_NULL) { throw reportError("Unexpected token: invalid keyword null in here.", node); } } // 确保返回的代码类型必须是 boolean 类型的 private String get_if_expression_source(SegmentCode code) { if (Boolean.TYPE.equals(code.getKlass())) { return code.toString(); } else { assert_not_void_expression(code); return "JetUtils.asBoolean(" + code.toString() + ")"; } } // ----------------------------------------------------------- // 创建一个全局唯一的变量名称 private String getUid(String prefix) { return "$" + prefix + "_" + (uuid++); } private RuntimeException reportError(String message, Object node) { if (node instanceof ParserRuleContext) { parser.notifyErrorListeners(((ParserRuleContext) node).getStart(), message, null); } else if (node instanceof TerminalNode) { parser.notifyErrorListeners(((TerminalNode) node).getSymbol(), message, null); } else if (node instanceof Token) { parser.notifyErrorListeners((Token) node, message, null); } return new SyntaxErrorException(message); } // 等到一个方法描述字符串 private String getMethodSignature(String name, Class<?>[] parameterTypes) { StringBuilder sb = new StringBuilder(); sb.append(name).append('('); for (int i = 0; i < parameterTypes.length; i++) { if (i > 0) { sb.append(','); } Class<?> type = parameterTypes[i]; sb.append(type == null ? "<null>" : type.getSimpleName()); } sb.append(')'); return sb.toString(); } }