Enjoy 3.2 release ^_^
This commit is contained in:
40
src/main/java/com/jfinal/template/stat/ast/Break.java
Normal file
40
src/main/java/com/jfinal/template/stat/ast/Break.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Break
|
||||
* java 中 break、continue 可出现在 for 中的最后一行,不一定要套在 if 中
|
||||
*/
|
||||
public class Break extends Stat {
|
||||
|
||||
public static final Break me = new Break();
|
||||
|
||||
private Break() {
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope.getCtrl().setBreak();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
57
src/main/java/com/jfinal/template/stat/ast/Call.java
Normal file
57
src/main/java/com/jfinal/template/stat/ast/Call.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Call 调用模板函数,两种用法:
|
||||
* 1:常规调用
|
||||
* #@funcName(p1, p2, ..., pn)
|
||||
* 2:安全调用,函数被定义才调用,否则跳过
|
||||
* #@funcName?(p1, p2, ..., pn)
|
||||
*
|
||||
* 注意:在函数名前面引入 '@' 字符是为了区分模板函数和指令
|
||||
*/
|
||||
public class Call extends Stat {
|
||||
|
||||
private String funcName;
|
||||
private ExprList exprList;
|
||||
private boolean callIfDefined;
|
||||
|
||||
public Call(String funcName, ExprList exprList, boolean callIfDefined) {
|
||||
this.funcName = funcName;
|
||||
this.exprList = exprList;
|
||||
this.callIfDefined = callIfDefined;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Define function = env.getFunction(funcName);
|
||||
if (function != null) {
|
||||
function.call(env, scope, exprList, writer);
|
||||
} else if (callIfDefined) {
|
||||
return ;
|
||||
} else {
|
||||
throw new TemplateException("Template function not defined: " + funcName, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
src/main/java/com/jfinal/template/stat/ast/Continue.java
Normal file
40
src/main/java/com/jfinal/template/stat/ast/Continue.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Continue
|
||||
*/
|
||||
public class Continue extends Stat {
|
||||
|
||||
public static final Continue me = new Continue();
|
||||
|
||||
private Continue() {
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope.getCtrl().setContinue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
141
src/main/java/com/jfinal/template/stat/ast/Define.java
Normal file
141
src/main/java/com/jfinal/template/stat/ast/Define.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.expr.ast.Id;
|
||||
|
||||
/**
|
||||
* Define 定义模板函数:
|
||||
* #define funcName(p1, p2, ..., pn)
|
||||
* body
|
||||
* #end
|
||||
*
|
||||
* 模板函数类型:
|
||||
* 1:全局共享的模板函数
|
||||
* 通过 engine.addSharedFunction(...) 添加,所有模板中可调用
|
||||
* 2:模板中定义的局部模板函数
|
||||
* 在模板中定义的模板函数,只在本模板中有效
|
||||
*
|
||||
* 高级用法:
|
||||
* 1:局部模板函数可以与全局共享模板函数同名,调用时优先调用模板内模板数
|
||||
* 2:模板内部不能定义同名的局部模板函数
|
||||
*/
|
||||
public class Define extends Stat {
|
||||
|
||||
private static final String[] NULL_PARAMETER_NAMES = new String[0];
|
||||
|
||||
private String functionName;
|
||||
private String[] parameterNames;
|
||||
private Stat stat;
|
||||
|
||||
public Define(String functionName, ExprList exprList, Stat stat, Location location) {
|
||||
setLocation(location);
|
||||
this.functionName = functionName;
|
||||
this.stat = stat;
|
||||
|
||||
Expr[] exprArray = exprList.getExprArray();
|
||||
if (exprArray.length == 0) {
|
||||
this.parameterNames = NULL_PARAMETER_NAMES;
|
||||
return ;
|
||||
}
|
||||
|
||||
parameterNames = new String[exprArray.length];
|
||||
for (int i=0; i<exprArray.length; i++) {
|
||||
if (exprArray[i] instanceof Id) {
|
||||
parameterNames[i] = ((Id)exprArray[i]).getId();
|
||||
} else {
|
||||
throw new ParseException("The parameter of template function definition must be identifier", location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
public String[] getParameterNames() {
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define 的继承类可以覆盖此方法实现一些 register 类的动作
|
||||
*/
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正调用模板函数
|
||||
*/
|
||||
public void call(Env env, Scope scope, ExprList exprList, Writer writer) {
|
||||
if (exprList.length() != parameterNames.length) {
|
||||
throw new TemplateException("Wrong number of argument to call the template function, right number is: " + parameterNames.length, location);
|
||||
}
|
||||
|
||||
scope = new Scope(scope);
|
||||
if (exprList.length() > 0) {
|
||||
Object[] parameterValues = exprList.evalExprList(scope);
|
||||
for (int i=0; i<parameterValues.length; i++) {
|
||||
scope.setLocal(parameterNames[i], parameterValues[i]); // 参数赋值
|
||||
}
|
||||
}
|
||||
|
||||
stat.exec(env, scope, writer);
|
||||
scope.getCtrl().setJumpNone(); // #define 中的 return、continue、break 全部在此消化
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.append("#define ").append(functionName).append("(");
|
||||
for (int i=0; i<parameterNames.length; i++) {
|
||||
if (i > 0) {
|
||||
ret.append(", ");
|
||||
}
|
||||
ret.append(parameterNames[i]);
|
||||
}
|
||||
return ret.append(")").toString();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* envForDevMode 属性性以及相关方法仅用于 devMode 判断当前 #define 指令所在资源是否被修改
|
||||
* 仅用于 EngineConfig 中处理 shared function 的逻辑
|
||||
*/
|
||||
private Env envForDevMode;
|
||||
|
||||
public void setEnvForDevMode(Env envForDevMode) {
|
||||
this.envForDevMode = envForDevMode;
|
||||
}
|
||||
|
||||
public boolean isSourceModifiedForDevMode() {
|
||||
if (envForDevMode == null) {
|
||||
throw new IllegalStateException("Check engine config: setDevMode(...) must be invoked before addSharedFunction(...)");
|
||||
}
|
||||
return envForDevMode.isSourceListModified();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
40
src/main/java/com/jfinal/template/stat/ast/Else.java
Normal file
40
src/main/java/com/jfinal/template/stat/ast/Else.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Else
|
||||
*/
|
||||
public class Else extends Stat {
|
||||
|
||||
private Stat stat;
|
||||
|
||||
public Else(Stat stat) {
|
||||
this.stat = stat;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
stat.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
63
src/main/java/com/jfinal/template/stat/ast/ElseIf.java
Normal file
63
src/main/java/com/jfinal/template/stat/ast/ElseIf.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.expr.ast.Logic;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* ElseIf
|
||||
*/
|
||||
public class ElseIf extends Stat {
|
||||
|
||||
private ExprList cond;
|
||||
private Stat stat;
|
||||
private Stat elseIfOrElse;
|
||||
|
||||
public ElseIf(ExprList cond, Stat stat, Location location) {
|
||||
if (cond.length() == 0) {
|
||||
throw new ParseException("The condition expression of #elseif statement can not be blank", location);
|
||||
}
|
||||
this.cond = cond;
|
||||
this.stat = stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* take over setStat(...) method of super class
|
||||
*/
|
||||
public void setStat(Stat elseIfOrElse) {
|
||||
this.elseIfOrElse = elseIfOrElse;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
if (Logic.isTrue(cond.eval(scope))) {
|
||||
stat.exec(env, scope, writer);
|
||||
} else if (elseIfOrElse != null) {
|
||||
elseIfOrElse.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
140
src/main/java/com/jfinal/template/stat/ast/For.java
Normal file
140
src/main/java/com/jfinal/template/stat/ast/For.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ForCtrl;
|
||||
import com.jfinal.template.expr.ast.Logic;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* For 循环控制,支持 List、Map、数组、Collection、Iterator、Iterable
|
||||
* Enumeration、null 以及任意单个对象的迭代,简单说是支持所有对象迭代
|
||||
*
|
||||
* 主要用法:
|
||||
* 1:#for(item : list) #(item) #end
|
||||
* 2:#for(item : list) #(item) #else content #end
|
||||
* 3:#for(i=0; i<9; i++) #(item) #end
|
||||
* 4:#for(i=0; i<9; i++) #(item) #else content #end
|
||||
*/
|
||||
public class For extends Stat {
|
||||
|
||||
private ForCtrl forCtrl;
|
||||
private StatList statList;
|
||||
private Stat _else;
|
||||
|
||||
public For(ForCtrl forCtrl, StatList statList, Stat _else) {
|
||||
this.forCtrl = forCtrl;
|
||||
this.statList = statList;
|
||||
this._else = _else;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope = new Scope(scope);
|
||||
if (forCtrl.isIterator()) {
|
||||
forIterator(env, scope, writer);
|
||||
} else {
|
||||
forLoop(env, scope, writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* #for( id : expr)
|
||||
*/
|
||||
private void forIterator(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
Object outer = scope.get("for");
|
||||
ctrl.setLocalAssignment();
|
||||
ForIteratorStatus forIteratorStatus = new ForIteratorStatus(outer, forCtrl.getExpr().eval(scope), location);
|
||||
ctrl.setWisdomAssignment();
|
||||
scope.setLocal("for", forIteratorStatus);
|
||||
|
||||
Iterator<?> it = forIteratorStatus.getIterator();
|
||||
String itemName = forCtrl.getId();
|
||||
while(it.hasNext()) {
|
||||
scope.setLocal(itemName, it.next());
|
||||
statList.exec(env, scope, writer);
|
||||
forIteratorStatus.nextState();
|
||||
|
||||
if (ctrl.isJump()) {
|
||||
if (ctrl.isBreak()) {
|
||||
ctrl.setJumpNone();
|
||||
break ;
|
||||
} else if (ctrl.isContinue()) {
|
||||
ctrl.setJumpNone();
|
||||
continue ;
|
||||
} else {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_else != null && forIteratorStatus.getIndex() == 0) {
|
||||
_else.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* #for(exprList; cond; update)
|
||||
*/
|
||||
private void forLoop(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
Object outer = scope.get("for");
|
||||
ForLoopStatus forLoopStatus = new ForLoopStatus(outer);
|
||||
scope.setLocal("for", forLoopStatus);
|
||||
|
||||
Expr init = forCtrl.getInit();
|
||||
Expr cond = forCtrl.getCond();
|
||||
Expr update = forCtrl.getUpdate();
|
||||
|
||||
ctrl.setLocalAssignment();
|
||||
for (init.eval(scope); cond == null || Logic.isTrue(cond.eval(scope)); update.eval(scope)) {
|
||||
ctrl.setWisdomAssignment();
|
||||
statList.exec(env, scope, writer);
|
||||
ctrl.setLocalAssignment();
|
||||
forLoopStatus.nextState();
|
||||
|
||||
if (ctrl.isJump()) {
|
||||
if (ctrl.isBreak()) {
|
||||
ctrl.setJumpNone();
|
||||
break ;
|
||||
} else if (ctrl.isContinue()) {
|
||||
ctrl.setJumpNone();
|
||||
continue ;
|
||||
} else {
|
||||
ctrl.setWisdomAssignment();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.setWisdomAssignment();
|
||||
if (_else != null && forLoopStatus.getIndex() == 0) {
|
||||
_else.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
46
src/main/java/com/jfinal/template/stat/ast/ForEntry.java
Normal file
46
src/main/java/com/jfinal/template/stat/ast/ForEntry.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* ForEntry 包装 HashMap、LinkedHashMap 等 Map 类型的 Entry 对象
|
||||
*/
|
||||
public class ForEntry implements Entry<Object, Object> {
|
||||
|
||||
private Entry<Object, Object> entry;
|
||||
|
||||
public ForEntry(Entry<Object, Object> entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return entry.getKey();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
public Object setValue(Object value) {
|
||||
return entry.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.stat.Location;
|
||||
|
||||
/**
|
||||
* ForIteratorStatus
|
||||
* 封装 #for( id : expr) 迭代语句状态,便于模板中获取
|
||||
*
|
||||
* 使用以下表达式可以模板中获取迭代状态:
|
||||
* for.size 被迭代集合元素数量,不支持 Iterator 与 Iterable
|
||||
* for.index 从 0 下始的下标
|
||||
* for.count 从 1 开始的计数器
|
||||
* for.first 是否第一个元素
|
||||
* for.last 是否最后一个元素
|
||||
* for.odd 是否第奇数个元素
|
||||
* for.even 是否第偶数个元素
|
||||
* for.outer 获取外层 for 对象,便于获取外层 for 循环状态
|
||||
* 例如: for.outer.index
|
||||
*/
|
||||
public class ForIteratorStatus {
|
||||
|
||||
private Object outer;
|
||||
private int index;
|
||||
private int size;
|
||||
private Iterator<?> iterator;
|
||||
private Location location;
|
||||
|
||||
public ForIteratorStatus(Object outer, Object target, Location location) {
|
||||
this.outer = outer;
|
||||
this.index = 0;
|
||||
this.location = location;
|
||||
init(target);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void init(Object target) {
|
||||
if (target == null) {
|
||||
size = 0;
|
||||
iterator = NullIterator.me;
|
||||
return ;
|
||||
}
|
||||
if (target instanceof Collection) {
|
||||
size = ((Collection<?>)target).size();
|
||||
iterator = ((Collection<?>)target).iterator();
|
||||
return ;
|
||||
}
|
||||
if (target instanceof Map<?, ?>) {
|
||||
size = ((Map<?, ?>)target).size();
|
||||
iterator = new MapIterator(((Map<Object, Object>)target).entrySet().iterator());
|
||||
return ;
|
||||
}
|
||||
if (target.getClass().isArray()) {
|
||||
size = Array.getLength(target);
|
||||
iterator = new ArrayIterator(target, size);
|
||||
return ;
|
||||
}
|
||||
if (target instanceof Iterator) {
|
||||
size = -1;
|
||||
iterator = (Iterator<?>)target;
|
||||
return ;
|
||||
}
|
||||
if (target instanceof Iterable) {
|
||||
size = -1;
|
||||
iterator = ((Iterable<?>)target).iterator();
|
||||
return ;
|
||||
}
|
||||
if (target instanceof Enumeration) {
|
||||
ArrayList<?> list = Collections.list((Enumeration<?>)target);
|
||||
size = list.size();
|
||||
iterator = list.iterator();
|
||||
return ;
|
||||
}
|
||||
|
||||
size = 1;
|
||||
iterator = new SingleObjectIterator(target);
|
||||
}
|
||||
|
||||
Iterator<?> getIterator() {
|
||||
return iterator;
|
||||
}
|
||||
|
||||
void nextState() {
|
||||
index++;
|
||||
}
|
||||
|
||||
public Object getOuter() {
|
||||
return outer;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
if (size >= 0) {
|
||||
return size;
|
||||
}
|
||||
throw new TemplateException("No such method getSize() of the iterator", location);
|
||||
}
|
||||
|
||||
public boolean getFirst() {
|
||||
return index == 0;
|
||||
}
|
||||
|
||||
public boolean getLast() {
|
||||
return !iterator.hasNext();
|
||||
}
|
||||
|
||||
public boolean getOdd() {
|
||||
return index % 2 == 0;
|
||||
}
|
||||
|
||||
public boolean getEven() {
|
||||
return index % 2 != 0;
|
||||
}
|
||||
}
|
||||
|
||||
class MapIterator implements Iterator<Entry<Object, Object>> {
|
||||
|
||||
private Iterator<Entry<Object, Object>> iterator;
|
||||
|
||||
public MapIterator(Iterator<Entry<Object, Object>> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public Entry<Object, Object> next() {
|
||||
return new ForEntry((Entry<Object, Object>)iterator.next());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayIterator implements Iterator<Object> {
|
||||
|
||||
private Object array;
|
||||
private int size;
|
||||
private int index;
|
||||
|
||||
ArrayIterator(Object array, int size) {
|
||||
this.array = array;
|
||||
this.size = size;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return index < size;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return Array.get(array, index++);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
class SingleObjectIterator implements Iterator<Object> {
|
||||
|
||||
private Object target;
|
||||
private boolean hasNext = true;
|
||||
|
||||
public SingleObjectIterator(Object target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (hasNext) {
|
||||
hasNext = false;
|
||||
return target;
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
class NullIterator implements Iterator<Object> {
|
||||
|
||||
static final Iterator<?> me = new NullIterator();
|
||||
|
||||
private NullIterator() {
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
/**
|
||||
* ForLoopStatus
|
||||
* 封装 #for( init; cond; update) 循环的状态,便于模板中获取
|
||||
*
|
||||
* 如下表达式可从模板中获取循环状态:
|
||||
* for.index 从 0 下始的下标
|
||||
* for.count 从 1 开始的计数器
|
||||
* for.first 是否第一个元素
|
||||
* for.odd 是否第奇数个元素
|
||||
* for.even 是否第偶数个元素
|
||||
* for.outer 获取外层 for 对象,便于获取外层 for 循环状态
|
||||
* 例如: for.outer.index
|
||||
*
|
||||
* 注意:比迭代型循环语句少支持两个状态取值表达式:for.size、for.last
|
||||
*/
|
||||
public class ForLoopStatus {
|
||||
|
||||
private Object outer;
|
||||
private int index;
|
||||
|
||||
public ForLoopStatus(Object outer) {
|
||||
this.outer = outer;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
void nextState() {
|
||||
index++;
|
||||
}
|
||||
|
||||
public Object getOuter() {
|
||||
return outer;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
public boolean getFirst() {
|
||||
return index == 0;
|
||||
}
|
||||
|
||||
public boolean getOdd() {
|
||||
return index % 2 == 0;
|
||||
}
|
||||
|
||||
public boolean getEven() {
|
||||
return index % 2 != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
61
src/main/java/com/jfinal/template/stat/ast/If.java
Normal file
61
src/main/java/com/jfinal/template/stat/ast/If.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.expr.ast.Logic;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* If
|
||||
*/
|
||||
public class If extends Stat {
|
||||
|
||||
private ExprList cond;
|
||||
private Stat stat;
|
||||
private Stat elseIfOrElse;
|
||||
|
||||
public If(ExprList cond, Stat stat, Location location) {
|
||||
if (cond.length() == 0) {
|
||||
throw new ParseException("The condition expression of #if statement can not be blank", location);
|
||||
}
|
||||
this.cond = cond;
|
||||
this.stat = stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* take over setStat(...) method of super class
|
||||
*/
|
||||
public void setStat(Stat elseIfOrElse) {
|
||||
this.elseIfOrElse = elseIfOrElse;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
if (Logic.isTrue(cond.eval(scope))) {
|
||||
stat.exec(env, scope, writer);
|
||||
} else if (elseIfOrElse != null) {
|
||||
elseIfOrElse.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
161
src/main/java/com/jfinal/template/stat/ast/Include.java
Normal file
161
src/main/java/com/jfinal/template/stat/ast/Include.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.EngineConfig;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Assign;
|
||||
import com.jfinal.template.expr.ast.Const;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.source.ISource;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Parser;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Include
|
||||
*
|
||||
* 1:父模板被缓存时,被 include 的模板会被间接缓存,无需关心缓存问题
|
||||
* 2:同一个模板文件被多个父模板 include,所处的背景环境不同,例如各父模板中定义的模板函数不同
|
||||
* 各父模板所处的相对路径不同,所以多个父模板不能共用一次 parse 出来的结果,而是在每个被include
|
||||
* 的地方重新 parse
|
||||
*
|
||||
* <pre>
|
||||
* 两种用法:
|
||||
* 1:只传入一个参数,参数必须是 String 常量,如果希望第一个参数是变量可以使用 #render 指令去实现
|
||||
* #include("_hot.html")
|
||||
*
|
||||
* 2:传入任意多个参数,除第一个参数以外的所有参数必须是赋值表达式,用于实现参数传递功能
|
||||
* #include("_hot.html", title = "热门新闻", list = newsList)
|
||||
*
|
||||
* 上例中传递了 title、list 两个参数,可以代替父模板中的 #set 指令传参方式
|
||||
* 并且此方式传入的参数只在子模板作用域有效,不会污染父模板作用域
|
||||
*
|
||||
* 这种传参方式有利于将子模板模块化,例如上例的调用改成如下的参数:
|
||||
* #include("_hot.html", title = "热门项目", list = projectList)
|
||||
* 通过这种传参方式在子模板 _hot.html 之中,完全不需要修改对于 title 与 list
|
||||
* 这两个变量的处理代码,就实现了对 “热门项目” 数据的渲染
|
||||
* </pre>
|
||||
*/
|
||||
public class Include extends Stat {
|
||||
|
||||
private Assign[] assignArray;
|
||||
private Stat stat;
|
||||
|
||||
public Include(Env env, ExprList exprList, String parentFileName, Location location) {
|
||||
int len = exprList.length();
|
||||
if (len == 0) {
|
||||
throw new ParseException("The parameter of #include directive can not be blank", location);
|
||||
}
|
||||
// 第一个参数必须为 String 类型
|
||||
Expr expr = exprList.getExpr(0);
|
||||
if (expr instanceof Const && ((Const)expr).isStr()) {
|
||||
} else {
|
||||
throw new ParseException("The first parameter of #include directive must be String", location);
|
||||
}
|
||||
// 其它参数必须为赋值表达式
|
||||
if (len > 1) {
|
||||
for (int i = 1; i < len; i++) {
|
||||
if (!(exprList.getExpr(i) instanceof Assign)) {
|
||||
throw new ParseException("The " + i + "th parameter of #include directive must be an assignment expression", location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseSubTemplate(env, ((Const)expr).getStr(), parentFileName, location);
|
||||
getAssignExpression(exprList);
|
||||
}
|
||||
|
||||
private void parseSubTemplate(Env env, String fileName, String parentFileName, Location location) {
|
||||
String subFileName = getSubFileName(fileName, parentFileName);
|
||||
EngineConfig config = env.getEngineConfig();
|
||||
// FileSource fileSource = new FileSource(config.getBaseTemplatePath(), subFileName, config.getEncoding());
|
||||
ISource fileSource = config.getSourceFactory().getSource(config.getBaseTemplatePath(), subFileName, config.getEncoding());
|
||||
try {
|
||||
Parser parser = new Parser(env, fileSource.getContent(), subFileName);
|
||||
if (config.isDevMode()) {
|
||||
env.addSource(fileSource);
|
||||
}
|
||||
this.stat = parser.parse();
|
||||
} catch (Exception e) {
|
||||
// 文件路径不正确抛出异常时添加 location 信息
|
||||
throw new ParseException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在父模板之下子模板的最终文件名,子模板目录相对于父模板文件目录来确定
|
||||
* 以 "/" 打头则以 baseTemplatePath 为根,否则以父文件所在路径为根
|
||||
*/
|
||||
public static String getSubFileName(String fileName, String parentFileName) {
|
||||
if (parentFileName == null) {
|
||||
return fileName;
|
||||
}
|
||||
if (fileName.startsWith("/")) {
|
||||
return fileName;
|
||||
}
|
||||
int index = parentFileName.lastIndexOf('/');
|
||||
if (index == -1) {
|
||||
return fileName;
|
||||
}
|
||||
return parentFileName.substring(0, index + 1) + fileName;
|
||||
}
|
||||
|
||||
private void getAssignExpression(ExprList exprList) {
|
||||
int len = exprList.length();
|
||||
if (len > 1) {
|
||||
assignArray = new Assign[len - 1];
|
||||
for (int i = 0; i < assignArray.length; i++) {
|
||||
assignArray[i] = (Assign)exprList.getExpr(i + 1);
|
||||
}
|
||||
} else {
|
||||
assignArray = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope = new Scope(scope);
|
||||
if (assignArray != null) {
|
||||
evalAssignExpression(scope);
|
||||
}
|
||||
stat.exec(env, scope, writer);
|
||||
scope.getCtrl().setJumpNone();
|
||||
}
|
||||
|
||||
private void evalAssignExpression(Scope scope) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
try {
|
||||
ctrl.setLocalAssignment();
|
||||
for (Assign assign : assignArray) {
|
||||
assign.eval(scope);
|
||||
}
|
||||
} finally {
|
||||
ctrl.setWisdomAssignment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
63
src/main/java/com/jfinal/template/stat/ast/Output.java
Normal file
63
src/main/java/com/jfinal/template/stat/ast/Output.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Output 输出指令
|
||||
*
|
||||
* 用法:
|
||||
* 1:#(value)
|
||||
* 2:#(x = 1, y = 2, x + y)
|
||||
* 3:#(seoTitle ?? 'JFinal 极速开发社区')
|
||||
*/
|
||||
public class Output extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
|
||||
public Output(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
throw new ParseException("The expression of output directive like #(expression) can not be blank", location);
|
||||
}
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
try {
|
||||
Object value = exprList.eval(scope);
|
||||
if (value != null) {
|
||||
String str = value.toString();
|
||||
writer.write(str, 0, str.length());
|
||||
}
|
||||
} catch(TemplateException e) {
|
||||
throw e;
|
||||
} catch(Exception e) {
|
||||
throw new TemplateException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
44
src/main/java/com/jfinal/template/stat/ast/Return.java
Normal file
44
src/main/java/com/jfinal/template/stat/ast/Return.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Return
|
||||
* 通常用于 #define 指令内部,不支持返回值
|
||||
*/
|
||||
public class Return extends Stat {
|
||||
|
||||
public static final Return me = new Return();
|
||||
|
||||
private Return() {
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope.getCtrl().setReturn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
59
src/main/java/com/jfinal/template/stat/ast/Set.java
Normal file
59
src/main/java/com/jfinal/template/stat/ast/Set.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Assign;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Set 赋值,从内向外作用域查找变量,找到则替换变量值,否则在顶层作用域赋值
|
||||
*
|
||||
* 用法:
|
||||
* 1:#set(k = v)
|
||||
* 2:#set(k1 = v1, k2 = v2, ..., kn = vn)
|
||||
* 3:#set(x = 1+2)
|
||||
* 4:#set(x = 1+2, y = 3>4, ..., z = c ? a : b)
|
||||
*/
|
||||
public class Set extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
|
||||
public Set(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
throw new ParseException("The parameter of #set directive can not be blank", location);
|
||||
}
|
||||
|
||||
for (Expr expr : exprList.getExprArray()) {
|
||||
if ( !(expr instanceof Assign) ) {
|
||||
throw new ParseException("#set directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope.getCtrl().setWisdomAssignment();
|
||||
exprList.eval(scope);
|
||||
}
|
||||
}
|
||||
|
65
src/main/java/com/jfinal/template/stat/ast/SetGlobal.java
Normal file
65
src/main/java/com/jfinal/template/stat/ast/SetGlobal.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Assign;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* SetLocal 设置全局变量,全局作用域是指本次请求的整个 template
|
||||
*
|
||||
* 适用于极少数的在内层作用域中希望直接操作顶层作用域的场景
|
||||
*/
|
||||
public class SetGlobal extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
|
||||
public SetGlobal(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
throw new ParseException("The parameter of #setGlobal directive can not be blank", location);
|
||||
}
|
||||
|
||||
for (Expr expr : exprList.getExprArray()) {
|
||||
if ( !(expr instanceof Assign) ) {
|
||||
throw new ParseException("#setGlobal directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
try {
|
||||
ctrl.setGlobalAssignment();
|
||||
exprList.eval(scope);
|
||||
} finally {
|
||||
ctrl.setWisdomAssignment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
66
src/main/java/com/jfinal/template/stat/ast/SetLocal.java
Normal file
66
src/main/java/com/jfinal/template/stat/ast/SetLocal.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Assign;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* SetLocal 设置局部变量
|
||||
*
|
||||
* 通常用于 #define #include 指令内部需要与外层作用域区分,以便于定义重用型模块的场景
|
||||
* 也常用于 #for 循环内部的临时变量
|
||||
*/
|
||||
public class SetLocal extends Stat {
|
||||
|
||||
final ExprList exprList;
|
||||
|
||||
public SetLocal(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
throw new ParseException("The parameter of #setLocal directive can not be blank", location);
|
||||
}
|
||||
|
||||
for (Expr expr : exprList.getExprArray()) {
|
||||
if ( !(expr instanceof Assign) ) {
|
||||
throw new ParseException("#setLocal directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
try {
|
||||
ctrl.setLocalAssignment();
|
||||
exprList.eval(scope);
|
||||
} finally {
|
||||
ctrl.setWisdomAssignment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
77
src/main/java/com/jfinal/template/stat/ast/Stat.java
Normal file
77
src/main/java/com/jfinal/template/stat/ast/Stat.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Stat
|
||||
*/
|
||||
public abstract class Stat {
|
||||
|
||||
protected Location location;
|
||||
|
||||
public Stat setLocation(Location location) {
|
||||
this.location = location;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setExprList(ExprList exprList) {
|
||||
}
|
||||
|
||||
public void setStat(Stat stat) {
|
||||
}
|
||||
|
||||
public abstract void exec(Env env, Scope scope, Writer writer);
|
||||
|
||||
public boolean hasEnd() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void write(Writer writer, String str) {
|
||||
try {
|
||||
writer.write(str, 0, str.length());
|
||||
} catch (IOException e) {
|
||||
throw new TemplateException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void write(Writer writer, char[] chars) {
|
||||
try {
|
||||
writer.write(chars, 0, chars.length);
|
||||
} catch (IOException e) {
|
||||
throw new TemplateException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
64
src/main/java/com/jfinal/template/stat/ast/StatList.java
Normal file
64
src/main/java/com/jfinal/template/stat/ast/StatList.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* StatList
|
||||
*/
|
||||
public class StatList extends Stat {
|
||||
|
||||
public static final Stat[] NULL_STATS = new Stat[0];
|
||||
private Stat[] statArray;
|
||||
|
||||
public StatList(List<Stat> statList) {
|
||||
if (statList.size() > 0) {
|
||||
this.statArray = statList.toArray(new Stat[statList.size()]);
|
||||
} else {
|
||||
this.statArray = NULL_STATS;
|
||||
}
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
for (Stat stat : statArray) {
|
||||
if (ctrl.isJump()) {
|
||||
break ;
|
||||
}
|
||||
stat.exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return statArray.length;
|
||||
}
|
||||
|
||||
public Stat getStat(int index) {
|
||||
if (index < 0 || index >= statArray.length) {
|
||||
throw new TemplateException("Index out of bounds: index = " + index + ", length = " + statArray.length, location);
|
||||
}
|
||||
return statArray[index];
|
||||
}
|
||||
}
|
||||
|
||||
|
59
src/main/java/com/jfinal/template/stat/ast/Text.java
Normal file
59
src/main/java/com/jfinal/template/stat/ast/Text.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.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 com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Text 输出纯文本块以及使用 "#[[" 与 "]]#" 指定的非解析块
|
||||
*/
|
||||
public class Text extends Stat {
|
||||
|
||||
private char[] text;
|
||||
|
||||
public Text(StringBuilder content) {
|
||||
this.text = new char[content.length()];
|
||||
content.getChars(0, content.length(), this.text, 0);
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
try {
|
||||
writer.write(text, 0, text.length);
|
||||
} catch (IOException e) {
|
||||
throw new TemplateException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return text.length == 0;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return text != null ? new String(text) : null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return text != null ? new String(text) : "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user