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;
}
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);
}
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);
}
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);
}
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);
}
Aggregations