enjoy 3.3 release ^_^
This commit is contained in:
@@ -95,7 +95,7 @@ class Lexer {
|
||||
StringBuilder para = null;
|
||||
Token idToken = null;
|
||||
Token paraToken = null;
|
||||
while(true) {
|
||||
while (true) {
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (peek() == '#') { // #
|
||||
@@ -141,6 +141,14 @@ class Lexer {
|
||||
continue ;
|
||||
}
|
||||
|
||||
// 在支持 #seleif 的基础上,支持 #else if
|
||||
if (symbol == Symbol.ELSE) {
|
||||
if (foundFollowingIf()) {
|
||||
id = "else if";
|
||||
symbol = Symbol.ELSEIF;
|
||||
}
|
||||
}
|
||||
|
||||
// 无参关键字指令
|
||||
if (symbol.noPara()) {
|
||||
return addNoParaToken(new Token(symbol, id, beginRow));
|
||||
@@ -199,6 +207,22 @@ class Lexer {
|
||||
}
|
||||
}
|
||||
|
||||
boolean foundFollowingIf() {
|
||||
int p = forward;
|
||||
while (CharTable.isBlank(buf[p])) {p++;}
|
||||
if (buf[p++] == 'i') {
|
||||
if (buf[p++] == 'f') {
|
||||
while (CharTable.isBlank(buf[p])) {p++;}
|
||||
// 要求出现 '(' 才认定解析成功,为了支持这种场景: #else if you ...
|
||||
if (buf[p] == '(') {
|
||||
forward = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用者已确定以字母或下划线开头,故一定可以获取到 id值
|
||||
*/
|
||||
@@ -405,7 +429,7 @@ class Lexer {
|
||||
}
|
||||
|
||||
void skipBlanks() {
|
||||
while(CharTable.isBlank(buf[forward])) {
|
||||
while (CharTable.isBlank(buf[forward])) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package com.jfinal.template.stat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.jfinal.template.Directive;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ExprParser;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
@@ -84,10 +85,10 @@ public class Parser {
|
||||
throw new ParseException("Can not match the #end of directive #" + name.value(), getLocation(name.row));
|
||||
}
|
||||
|
||||
public Stat parse() {
|
||||
public StatList parse() {
|
||||
tokenList = new Lexer(content, fileName).scan();
|
||||
tokenList.add(EOF);
|
||||
Stat statList = statList();
|
||||
StatList statList = statList();
|
||||
if (peek() != EOF) {
|
||||
throw new ParseException("Syntax error: can not match " + peek().value(), getLocation(peek().row));
|
||||
}
|
||||
@@ -122,7 +123,7 @@ public class Parser {
|
||||
switch (name.symbol) {
|
||||
case TEXT:
|
||||
move();
|
||||
return new Text(((TextToken)name).getContent()).setLocation(getLocation(name.row));
|
||||
return new Text(((TextToken)name).getContent(), env.getEngineConfig().getEncoding()).setLocation(getLocation(name.row));
|
||||
case OUTPUT:
|
||||
move();
|
||||
Token para = matchPara(name);
|
||||
@@ -171,9 +172,9 @@ public class Parser {
|
||||
String functionName = name.value();
|
||||
move();
|
||||
para = matchPara(name);
|
||||
Stat stat = statList();
|
||||
statList = statList();
|
||||
matchEnd(name);
|
||||
return new Define(functionName, parseExprList(para), stat, getLocation(name.row));
|
||||
return new Define(functionName, parseExprList(para), statList, getLocation(name.row));
|
||||
case CALL:
|
||||
functionName = name.value();
|
||||
move();
|
||||
@@ -206,7 +207,7 @@ public class Parser {
|
||||
move();
|
||||
return Return.me;
|
||||
case ID:
|
||||
Stat dire = env.getEngineConfig().getDirective(name.value());
|
||||
Class<? extends Directive> dire = env.getEngineConfig().getDirective(name.value());
|
||||
if (dire == null) {
|
||||
throw new ParseException("Directive not found: #" + name.value(), getLocation(name.row));
|
||||
}
|
||||
@@ -215,9 +216,9 @@ public class Parser {
|
||||
para = matchPara(name);
|
||||
ret.setExprList(parseExprList(para));
|
||||
|
||||
if (dire.hasEnd()) {
|
||||
if (ret.hasEnd()) {
|
||||
statList = statList();
|
||||
ret.setStat(statList);
|
||||
ret.setStat(statList.getActualStat());
|
||||
matchEnd(name);
|
||||
}
|
||||
return ret;
|
||||
@@ -236,9 +237,9 @@ public class Parser {
|
||||
return new Location(fileName, row);
|
||||
}
|
||||
|
||||
private Stat createDirective(Stat dire, Token name) {
|
||||
private Stat createDirective(Class<? extends Directive> dire, Token name) {
|
||||
try {
|
||||
return dire.getClass().newInstance();
|
||||
return dire.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ParseException(e.getMessage(), getLocation(name.row), e);
|
||||
}
|
||||
|
@@ -90,8 +90,19 @@ public class Scope {
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
for (Scope cur=this; cur!=null; cur=cur.parent) {
|
||||
if (cur.data != null && cur.data.containsKey(key)) {
|
||||
return cur.data.get(key);
|
||||
// if (cur.data != null && cur.data.containsKey(key)) {
|
||||
// return cur.data.get(key);
|
||||
// }
|
||||
|
||||
if (cur.data != null) {
|
||||
Object ret = cur.data.get(key);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cur.data.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return null;
|
||||
@@ -229,6 +240,18 @@ public class Scope {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自内向外在作用域栈中查找变量是否存在
|
||||
*/
|
||||
public boolean exists(Object key) {
|
||||
for (Scope cur=this; cur!=null; cur=cur.parent) {
|
||||
if (cur.data != null && cur.data.containsKey(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
|
@@ -16,10 +16,10 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
|
@@ -16,7 +16,6 @@
|
||||
|
||||
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;
|
||||
@@ -25,6 +24,7 @@ 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;
|
||||
import com.jfinal.template.io.Writer;
|
||||
|
||||
/**
|
||||
* Define 定义模板函数:
|
||||
@@ -50,10 +50,10 @@ public class Define extends Stat {
|
||||
private String[] parameterNames;
|
||||
private Stat stat;
|
||||
|
||||
public Define(String functionName, ExprList exprList, Stat stat, Location location) {
|
||||
public Define(String functionName, ExprList exprList, StatList statList, Location location) {
|
||||
setLocation(location);
|
||||
this.functionName = functionName;
|
||||
this.stat = stat;
|
||||
this.stat = statList.getActualStat();
|
||||
|
||||
Expr[] exprArray = exprList.getExprArray();
|
||||
if (exprArray.length == 0) {
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
@@ -27,8 +27,8 @@ public class Else extends Stat {
|
||||
|
||||
private Stat stat;
|
||||
|
||||
public Else(Stat stat) {
|
||||
this.stat = stat;
|
||||
public Else(StatList statList) {
|
||||
this.stat = statList.getActualStat();
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
|
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.expr.ast.Logic;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
@@ -29,16 +30,16 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class ElseIf extends Stat {
|
||||
|
||||
private ExprList cond;
|
||||
private Expr cond;
|
||||
private Stat stat;
|
||||
private Stat elseIfOrElse;
|
||||
|
||||
public ElseIf(ExprList cond, Stat stat, Location location) {
|
||||
public ElseIf(ExprList cond, StatList statList, Location location) {
|
||||
if (cond.length() == 0) {
|
||||
throw new ParseException("The condition expression of #elseif statement can not be blank", location);
|
||||
throw new ParseException("The condition expression of #else if statement can not be blank", location);
|
||||
}
|
||||
this.cond = cond;
|
||||
this.stat = stat;
|
||||
this.cond = cond.getActualExpr();
|
||||
this.stat = statList.getActualStat();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,12 +16,12 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
@@ -38,12 +38,12 @@ import com.jfinal.template.stat.Scope;
|
||||
public class For extends Stat {
|
||||
|
||||
private ForCtrl forCtrl;
|
||||
private StatList statList;
|
||||
private Stat stat;
|
||||
private Stat _else;
|
||||
|
||||
public For(ForCtrl forCtrl, StatList statList, Stat _else) {
|
||||
this.forCtrl = forCtrl;
|
||||
this.statList = statList;
|
||||
this.stat = statList.getActualStat();
|
||||
this._else = _else;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class For extends Stat {
|
||||
String itemName = forCtrl.getId();
|
||||
while(it.hasNext()) {
|
||||
scope.setLocal(itemName, it.next());
|
||||
statList.exec(env, scope, writer);
|
||||
stat.exec(env, scope, writer);
|
||||
forIteratorStatus.nextState();
|
||||
|
||||
if (ctrl.isJump()) {
|
||||
@@ -108,7 +108,7 @@ public class For extends Stat {
|
||||
ctrl.setLocalAssignment();
|
||||
for (init.eval(scope); cond == null || Logic.isTrue(cond.eval(scope)); update.eval(scope)) {
|
||||
ctrl.setWisdomAssignment();
|
||||
statList.exec(env, scope, writer);
|
||||
stat.exec(env, scope, writer);
|
||||
ctrl.setLocalAssignment();
|
||||
forLoopStatus.nextState();
|
||||
|
||||
|
@@ -25,7 +25,7 @@ public class ForEntry implements Entry<Object, Object> {
|
||||
|
||||
private Entry<Object, Object> entry;
|
||||
|
||||
public ForEntry(Entry<Object, Object> entry) {
|
||||
public void init(Entry<Object, Object> entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
|
@@ -60,11 +60,6 @@ public class ForIteratorStatus {
|
||||
|
||||
@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();
|
||||
@@ -75,6 +70,11 @@ public class ForIteratorStatus {
|
||||
iterator = new MapIterator(((Map<Object, Object>)target).entrySet().iterator());
|
||||
return ;
|
||||
}
|
||||
if (target == null) { // 必须放在 target.getClass() 之前,避免空指针异常
|
||||
size = 0;
|
||||
iterator = NullIterator.me;
|
||||
return ;
|
||||
}
|
||||
if (target.getClass().isArray()) {
|
||||
size = Array.getLength(target);
|
||||
iterator = new ArrayIterator(target, size);
|
||||
@@ -148,6 +148,7 @@ public class ForIteratorStatus {
|
||||
class MapIterator implements Iterator<Entry<Object, Object>> {
|
||||
|
||||
private Iterator<Entry<Object, Object>> iterator;
|
||||
private ForEntry forEntry = new ForEntry();
|
||||
|
||||
public MapIterator(Iterator<Entry<Object, Object>> iterator) {
|
||||
this.iterator = iterator;
|
||||
@@ -158,7 +159,8 @@ class MapIterator implements Iterator<Entry<Object, Object>> {
|
||||
}
|
||||
|
||||
public Entry<Object, Object> next() {
|
||||
return new ForEntry((Entry<Object, Object>)iterator.next());
|
||||
forEntry.init(iterator.next());
|
||||
return forEntry;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
|
@@ -16,10 +16,11 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.expr.ast.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.expr.ast.Logic;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
@@ -29,16 +30,16 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class If extends Stat {
|
||||
|
||||
private ExprList cond;
|
||||
private Expr cond;
|
||||
private Stat stat;
|
||||
private Stat elseIfOrElse;
|
||||
|
||||
public If(ExprList cond, Stat stat, Location location) {
|
||||
public If(ExprList cond, StatList statList, 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;
|
||||
this.cond = cond.getActualExpr();
|
||||
this.stat = statList.getActualStat();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,13 +16,13 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.source.ISource;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
@@ -94,7 +94,7 @@ public class Include extends Stat {
|
||||
if (config.isDevMode()) {
|
||||
env.addSource(fileSource);
|
||||
}
|
||||
this.stat = parser.parse();
|
||||
this.stat = parser.parse().getActualStat();
|
||||
} catch (Exception e) {
|
||||
// 文件路径不正确抛出异常时添加 location 信息
|
||||
throw new ParseException(e.getMessage(), location, e);
|
||||
|
40
src/main/java/com/jfinal/template/stat/ast/NullStat.java
Normal file
40
src/main/java/com/jfinal/template/stat/ast/NullStat.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 com.jfinal.template.Env;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* NullStat
|
||||
*/
|
||||
public class NullStat extends Stat {
|
||||
|
||||
public static final NullStat me = new NullStat();
|
||||
|
||||
private NullStat() {}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -16,10 +16,11 @@
|
||||
|
||||
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.Expr;
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
@@ -34,21 +35,41 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class Output extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
private Expr expr;
|
||||
|
||||
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;
|
||||
this.expr = exprList.getActualExpr();
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
try {
|
||||
Object value = exprList.eval(scope);
|
||||
if (value != null) {
|
||||
String str = value.toString();
|
||||
Object value = expr.eval(scope);
|
||||
|
||||
if (value instanceof String) {
|
||||
String str = (String)value;
|
||||
writer.write(str, 0, str.length());
|
||||
} else if (value instanceof Number) {
|
||||
Class<?> c = value.getClass();
|
||||
if (c == Integer.class) {
|
||||
writer.write((Integer)value);
|
||||
} else if (c == Long.class) {
|
||||
writer.write((Long)value);
|
||||
} else if (c == Double.class) {
|
||||
writer.write((Double)value);
|
||||
} else if (c == Float.class) {
|
||||
writer.write((Float)value);
|
||||
} else if (c == Short.class) {
|
||||
writer.write((Short)value);
|
||||
} else {
|
||||
writer.write(value.toString());
|
||||
}
|
||||
} else if (value instanceof Boolean) {
|
||||
writer.write((Boolean)value);
|
||||
} else if (value != null) {
|
||||
writer.write(value.toString());
|
||||
}
|
||||
} catch(TemplateException e) {
|
||||
throw e;
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.Writer;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
@@ -36,7 +36,7 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class Set extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
private Expr expr;
|
||||
|
||||
public Set(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
@@ -48,12 +48,12 @@ public class Set extends Stat {
|
||||
throw new ParseException("#set directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
this.expr = exprList.getActualExpr();
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
scope.getCtrl().setWisdomAssignment();
|
||||
exprList.eval(scope);
|
||||
expr.eval(scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
@@ -33,7 +33,7 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class SetGlobal extends Stat {
|
||||
|
||||
private ExprList exprList;
|
||||
private Expr expr;
|
||||
|
||||
public SetGlobal(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
@@ -45,14 +45,14 @@ public class SetGlobal extends Stat {
|
||||
throw new ParseException("#setGlobal directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
this.expr = exprList.getActualExpr();
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
try {
|
||||
ctrl.setGlobalAssignment();
|
||||
exprList.eval(scope);
|
||||
expr.eval(scope);
|
||||
} finally {
|
||||
ctrl.setWisdomAssignment();
|
||||
}
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ParseException;
|
||||
@@ -34,7 +34,7 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class SetLocal extends Stat {
|
||||
|
||||
final ExprList exprList;
|
||||
final Expr expr;
|
||||
|
||||
public SetLocal(ExprList exprList, Location location) {
|
||||
if (exprList.length() == 0) {
|
||||
@@ -46,14 +46,14 @@ public class SetLocal extends Stat {
|
||||
throw new ParseException("#setLocal directive only supports assignment expressions", location);
|
||||
}
|
||||
}
|
||||
this.exprList = exprList;
|
||||
this.expr = exprList.getActualExpr();
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
try {
|
||||
ctrl.setLocalAssignment();
|
||||
exprList.eval(scope);
|
||||
expr.eval(scope);
|
||||
} finally {
|
||||
ctrl.setWisdomAssignment();
|
||||
}
|
||||
|
@@ -17,10 +17,10 @@
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
@@ -59,19 +59,6 @@ public abstract class Stat {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -16,10 +16,10 @@
|
||||
|
||||
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.io.Writer;
|
||||
import com.jfinal.template.stat.Ctrl;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
@@ -28,24 +28,44 @@ import com.jfinal.template.stat.Scope;
|
||||
*/
|
||||
public class StatList extends Stat {
|
||||
|
||||
public static final Stat[] NULL_STATS = new Stat[0];
|
||||
public static final Stat NULL_STAT = NullStat.me;
|
||||
public static final Stat[] NULL_STAT_ARRAY = 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;
|
||||
this.statArray = NULL_STAT_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 持有 StatList 的指令可以通过此方法提升 AST 执行性能
|
||||
* 1:当 statArray.length > 1 时返回 StatList 自身
|
||||
* 2:当 statArray.length == 1 时返回 statArray[0]
|
||||
* 3:其它情况返回 NullStat
|
||||
*
|
||||
* 意义在于,当满足前面两个条件时,避免掉了 StatList.exec(...) 方法中的判断与循环
|
||||
*/
|
||||
public Stat getActualStat() {
|
||||
if (statArray.length > 1) {
|
||||
return this;
|
||||
} else if (statArray.length == 1) {
|
||||
return statArray[0];
|
||||
} else {
|
||||
return NULL_STAT;
|
||||
}
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
Ctrl ctrl = scope.getCtrl();
|
||||
for (Stat stat : statArray) {
|
||||
for (int i=0; i<statArray.length; i++) {
|
||||
if (ctrl.isJump()) {
|
||||
break ;
|
||||
}
|
||||
stat.exec(env, scope, writer);
|
||||
statArray[i].exec(env, scope, writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,41 +17,98 @@
|
||||
package com.jfinal.template.stat.ast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import com.jfinal.template.Env;
|
||||
import com.jfinal.template.TemplateException;
|
||||
import com.jfinal.template.io.IWritable;
|
||||
import com.jfinal.template.io.Writer;
|
||||
import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Text 输出纯文本块以及使用 "#[[" 与 "]]#" 指定的非解析块
|
||||
*/
|
||||
public class Text extends Stat {
|
||||
public class Text extends Stat implements IWritable {
|
||||
|
||||
private char[] text;
|
||||
// content、bytes、chars 三者必有一者不为 null
|
||||
// 在 OutputStream、Writer 混合模式下 bytes、chars 同时不为null
|
||||
private StringBuilder content;
|
||||
private Charset charset;
|
||||
private byte[] bytes;
|
||||
private char[] chars;
|
||||
|
||||
public Text(StringBuilder content) {
|
||||
this.text = new char[content.length()];
|
||||
content.getChars(0, content.length(), this.text, 0);
|
||||
// content 初始值在 Lexer 中已确保不为 null
|
||||
public Text(StringBuilder content, String encoding) {
|
||||
this.content = content;
|
||||
this.charset = Charset.forName(encoding);
|
||||
this.bytes = null;
|
||||
this.chars = null;
|
||||
}
|
||||
|
||||
public void exec(Env env, Scope scope, Writer writer) {
|
||||
try {
|
||||
writer.write(text, 0, text.length);
|
||||
writer.write(this);
|
||||
} catch (IOException e) {
|
||||
throw new TemplateException(e.getMessage(), location, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return text.length == 0;
|
||||
public byte[] getBytes() {
|
||||
if (bytes != null) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
bytes = content.toString().getBytes(charset);
|
||||
content = null;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bytes = new String(chars).getBytes(charset);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return text != null ? new String(text) : null;
|
||||
public char[] getChars() {
|
||||
if (chars != null) {
|
||||
return chars;
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
char[] charsTemp = new char[content.length()];
|
||||
content.getChars(0, content.length(), charsTemp, 0);
|
||||
chars = charsTemp;
|
||||
content = null;
|
||||
return chars;
|
||||
}
|
||||
|
||||
String strTemp = new String(bytes, charset);
|
||||
char[] charsTemp = new char[strTemp.length()];
|
||||
strTemp.getChars(0, strTemp.length(), charsTemp, 0);
|
||||
chars = charsTemp;
|
||||
return chars;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
if (content != null) {
|
||||
return content.length() == 0;
|
||||
} else if (bytes != null) {
|
||||
return bytes.length == 0;
|
||||
} else {
|
||||
return chars.length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// public String getContent() {
|
||||
// return text != null ? new String(text) : null;
|
||||
// }
|
||||
|
||||
public String toString() {
|
||||
return text != null ? new String(text) : "";
|
||||
if (bytes != null) {
|
||||
return new String(bytes, charset);
|
||||
} else if (chars != null) {
|
||||
return new String(chars);
|
||||
} else {
|
||||
return content.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user