/** * Copyright 2010 Bing Ran<bing_ran@hotmail.com> * * 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 cn.bran.japid.compiler; import java.util.regex.Matcher; import java.util.regex.Pattern; import cn.bran.japid.classmeta.AbstractTemplateClassMetaData; import cn.bran.japid.classmeta.TemplateClassMetaData; import cn.bran.japid.compiler.Tag.TagSet; import cn.bran.japid.template.ActionRunner; import cn.bran.japid.template.RenderResult; /** * specifically for callable templates * * tags does not extends (why not?) some decisions: flow control is not treated * as tags, assume ~{ if (xxx) { }~ ~{}}~ #{tags} with body will be compiled to * inner classes /anonymous class#{tags sdfs df /} don't create inner class * * -- extends can take parnt.html or a java class directly. * @author Bing Ran<bing_ran@hotmail.com> * @author Play! framework original authors */ public class JapidTemplateCompiler extends JapidAbstractCompiler { private static final String DO_BODY = "doBody"; // StringBuilder mainRenderBodySource = new StringBuilder(); TemplateClassMetaData tcmd = new TemplateClassMetaData(); @Override protected void startTag(Tag tag) { if (tag.tagName.equals(DO_BODY)) { String[] argPartsAndVar = JavaSyntaxTool.breakArgParts(tag.args); if (argPartsAndVar.length == 1){ tcmd.doBody(tag.args); print("if (body != null){ body.setBuffer(getOut()); body.render(" + tag.args + "); body.resetBuffer();}"); } else { String args = argPartsAndVar[0]; tcmd.doBody(args); String localVar = argPartsAndVar[1]; print("String " + localVar + " = renderBody(" + args + ");"); } // print to the root space before move one stack up } else if ("set".equals(tag.tagName)) { if (SET_ARG_PATTERN_ONELINER.matcher(tag.args).matches()) { if (tag.hasBody) { throw new JapidCompilationException(template, parser.getLineNumber(), "set tag cannot have value both in tag and in body: " + tag + " " + tag.args); } else { int i = 0; if (SET_ARG_PATTERN_ONELINER_COLON.matcher(tag.args).matches()) { i = tag.args.indexOf(":"); } else { i = tag.args.indexOf("="); } String key = tag.args.substring(0, i).trim().replace("\"", "").replace("'", ""); String value = tag.args.substring(i + 1); if (JavaSyntaxTool.isValidExpr(value)) this.tcmd.addSetTag(key, "p(" + value + ");", (TagSet) tag); else throw new JapidCompilationException(template, parser.getLineNumber(), "The value part in the set tag is not a valid expression: " + value + ". " + "The grammar is: set var_name = java_expression."); } } else { Matcher matcher = setPattern.matcher(tag.args); if (matcher.matches()) { tag.hasBody = false; String key = matcher.group(1); String value = matcher.group(2); this.tcmd.addSetTag(key, "p(" + value + ");", (TagSet) tag); } } } else if (tag.tagName.equals("def")) { def(tag); } else { regularTagInvoke(tag); } pushToStack(tag); markLine(); println(); skipLineBreak = true; } static Pattern setPattern = Pattern.compile("(\\w+)\\s+(.*)"); static Pattern SET_ARG_PATTERN_ONELINER_COLON = Pattern.compile("\\w+\\s*:.*"); static Pattern SET_ARG_PATTERN_ONELINER_EQUAL = Pattern.compile("\\w+\\s*=.*"); static Pattern SET_ARG_PATTERN_ONELINER = Pattern.compile("\\w+\\s*[:=].*"); @Override protected AbstractTemplateClassMetaData getTemplateClassMetaData() { return tcmd; } @Override protected void scriptline(String token) { String line = token;//.trim(); don't trim `a `t is sensitive to the space if (JapidAbstractCompiler.startsWithIgnoreSpace(line.trim(), DO_BODY) || line.trim().equals(DO_BODY)) { String args = line.trim().substring(DO_BODY.length()).trim(); String[] argPartsAndVar = JavaSyntaxTool.breakArgParts(args); if (argPartsAndVar.length == 1){ tcmd.doBody(args); printLine("if (body != null){ body.setBuffer(getOut()); body.render(" + args + "); body.resetBuffer();}"); } else { args = argPartsAndVar[0]; tcmd.doBody(args); String localVar = argPartsAndVar[1]; printLine("String " + localVar + " = renderBody(" + args + ");"); } skipLineBreak = true; } else { super.scriptline(token); } } @Override void endSet(TagSet tag) { if (tag.hasBody) { String key = tag.args.replace("\"", "").replace("'", ""); this.tcmd.addSetTag(key, tag.getBodyText(), tag); } } }