enjoy 3.5
This commit is contained in:
parent
3e89651aa4
commit
1ce7068072
92
src/main/java/com/jfinal/kit/SyncWriteMap.java
Normal file
92
src/main/java/com/jfinal/kit/SyncWriteMap.java
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2019, 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.kit;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SyncWriteMap 同步写 HashMap
|
||||
* 创建原因是 HashMap扩容时,遇到并发修改可能造成 100% CPU 占用
|
||||
*
|
||||
* SyncWriteMap 拥有 HashMap 的性能,但不保障并发访问的线程安全
|
||||
* 只用于读多写少且不用保障线程安全的场景
|
||||
*
|
||||
* 例如 MethodKit 中用于缓存 MethodInfo 的 cache,被写入的数据
|
||||
* 不用保障是单例,读取之后会做 null 值判断
|
||||
*
|
||||
* ActionMapping 中的 HashMap 是系统启动时在独立线程内初始化的,
|
||||
* 不存在并发写,只存在并发读的情况,所以仍然可以使用 HashMap
|
||||
*/
|
||||
public class SyncWriteMap<K, V> extends HashMap<K, V> {
|
||||
|
||||
private static final long serialVersionUID = -7287230891751869148L;
|
||||
|
||||
public SyncWriteMap() {
|
||||
}
|
||||
|
||||
public SyncWriteMap(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
public SyncWriteMap(int initialCapacity, float loadFactor) {
|
||||
super(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
public SyncWriteMap(Map<? extends K, ? extends V> m) {
|
||||
super(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
synchronized (this) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
synchronized (this) {
|
||||
return super.putIfAbsent(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
synchronized (this) {
|
||||
super.putAll(m);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
synchronized (this) {
|
||||
return super.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
super.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -21,11 +21,13 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.jfinal.kit.HashKit;
|
||||
import com.jfinal.kit.StrKit;
|
||||
import com.jfinal.kit.SyncWriteMap;
|
||||
import com.jfinal.template.expr.ast.MethodKit;
|
||||
import com.jfinal.template.source.ClassPathSourceFactory;
|
||||
import com.jfinal.template.source.ISource;
|
||||
import com.jfinal.template.source.ISourceFactory;
|
||||
import com.jfinal.template.source.StringSource;
|
||||
import com.jfinal.template.stat.OutputDirectiveFactory;
|
||||
import com.jfinal.template.stat.Parser;
|
||||
import com.jfinal.template.stat.ast.Stat;
|
||||
|
||||
@ -41,7 +43,7 @@ public class Engine {
|
||||
public static final String MAIN_ENGINE_NAME = "main";
|
||||
|
||||
private static Engine MAIN_ENGINE;
|
||||
private static Map<String, Engine> engineMap = new HashMap<String, Engine>();
|
||||
private static Map<String, Engine> engineMap = new HashMap<String, Engine>(64, 0.5F);
|
||||
|
||||
// Create main engine
|
||||
static {
|
||||
@ -54,7 +56,7 @@ public class Engine {
|
||||
private EngineConfig config = new EngineConfig();
|
||||
private ISourceFactory sourceFactory = config.getSourceFactory();
|
||||
|
||||
private Map<String, Template> templateCache = new HashMap<String, Template>();
|
||||
private Map<String, Template> templateCache = new SyncWriteMap<String, Template>(2048, 0.5F);
|
||||
|
||||
/**
|
||||
* Create engine without management of JFinal
|
||||
@ -276,7 +278,7 @@ public class Engine {
|
||||
/**
|
||||
* Set output directive factory
|
||||
*/
|
||||
public Engine setOutputDirectiveFactory(IOutputDirectiveFactory outputDirectiveFactory) {
|
||||
public Engine setOutputDirectiveFactory(OutputDirectiveFactory outputDirectiveFactory) {
|
||||
config.setOutputDirectiveFactory(outputDirectiveFactory);
|
||||
return this;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import com.jfinal.template.source.ISource;
|
||||
import com.jfinal.template.source.ISourceFactory;
|
||||
import com.jfinal.template.source.StringSource;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.OutputDirectiveFactory;
|
||||
import com.jfinal.template.stat.Parser;
|
||||
import com.jfinal.template.stat.ast.Define;
|
||||
import com.jfinal.template.stat.ast.Output;
|
||||
@ -48,14 +49,14 @@ public class EngineConfig {
|
||||
|
||||
WriterBuffer writerBuffer = new WriterBuffer();
|
||||
|
||||
private Map<String, Define> sharedFunctionMap = new HashMap<String, Define>();
|
||||
private Map<String, Define> sharedFunctionMap = createSharedFunctionMap(); // new HashMap<String, Define>(512, 0.25F);
|
||||
private List<ISource> sharedFunctionSourceList = new ArrayList<ISource>(); // for devMode only
|
||||
|
||||
Map<String, Object> sharedObjectMap = null;
|
||||
|
||||
private IOutputDirectiveFactory outputDirectiveFactory = OutputDirectiveFactory.me;
|
||||
private OutputDirectiveFactory outputDirectiveFactory = OutputDirectiveFactory.me;
|
||||
private ISourceFactory sourceFactory = new FileSourceFactory();
|
||||
private Map<String, Class<? extends Directive>> directiveMap = new HashMap<String, Class<? extends Directive>>();
|
||||
private Map<String, Class<? extends Directive>> directiveMap = new HashMap<String, Class<? extends Directive>>(64, 0.5F);
|
||||
private SharedMethodKit sharedMethodKit = new SharedMethodKit();
|
||||
|
||||
private boolean devMode = false;
|
||||
@ -179,7 +180,7 @@ public class EngineConfig {
|
||||
* 开发者可直接使用模板注释功能将不需要的 function 直接注释掉
|
||||
*/
|
||||
private synchronized void reloadSharedFunctionSourceList() {
|
||||
Map<String, Define> newMap = new HashMap<String, Define>();
|
||||
Map<String, Define> newMap = createSharedFunctionMap();
|
||||
for (int i = 0, size = sharedFunctionSourceList.size(); i < size; i++) {
|
||||
ISource source = sharedFunctionSourceList.get(i);
|
||||
String fileName = source instanceof FileSource ? ((FileSource)source).getFileName() : null;
|
||||
@ -194,9 +195,13 @@ public class EngineConfig {
|
||||
this.sharedFunctionMap = newMap;
|
||||
}
|
||||
|
||||
private Map<String, Define> createSharedFunctionMap() {
|
||||
return new HashMap<String, Define>(512, 0.25F);
|
||||
}
|
||||
|
||||
public synchronized void addSharedObject(String name, Object object) {
|
||||
if (sharedObjectMap == null) {
|
||||
sharedObjectMap = new HashMap<String, Object>();
|
||||
sharedObjectMap = new HashMap<String, Object>(64, 0.25F);
|
||||
} else if (sharedObjectMap.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Shared object already exists: " + name);
|
||||
}
|
||||
@ -210,7 +215,7 @@ public class EngineConfig {
|
||||
/**
|
||||
* Set output directive factory
|
||||
*/
|
||||
public void setOutputDirectiveFactory(IOutputDirectiveFactory outputDirectiveFactory) {
|
||||
public void setOutputDirectiveFactory(OutputDirectiveFactory outputDirectiveFactory) {
|
||||
if (outputDirectiveFactory == null) {
|
||||
throw new IllegalArgumentException("outputDirectiveFactory can not be null");
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import com.jfinal.template.stat.ast.Define;
|
||||
public class Env {
|
||||
|
||||
protected EngineConfig engineConfig;
|
||||
protected Map<String, Define> functionMap = new HashMap<String, Define>();
|
||||
protected Map<String, Define> functionMap = new HashMap<String, Define>(16, 0.5F);
|
||||
|
||||
// 代替 Template 持有该属性,便于在 #include 指令中调用 Env.addSource()
|
||||
protected List<ISource> sourceList = null;
|
||||
|
@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2011-2019, 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;
|
||||
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ast.Output;
|
||||
|
||||
/**
|
||||
* OutputDirectiveFactory
|
||||
*/
|
||||
public class OutputDirectiveFactory implements IOutputDirectiveFactory {
|
||||
|
||||
public static final OutputDirectiveFactory me = new OutputDirectiveFactory();
|
||||
|
||||
public Output getOutputDirective(ExprList exprList, Location location) {
|
||||
return new Output(exprList, location);
|
||||
}
|
||||
}
|
||||
|
@ -18,13 +18,14 @@ package com.jfinal.template.expr.ast;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import com.jfinal.kit.SyncWriteMap;
|
||||
|
||||
/**
|
||||
* FieldKit
|
||||
*/
|
||||
public class FieldKit {
|
||||
|
||||
private static final HashMap<Long, Object> fieldCache = new HashMap<Long, Object>();
|
||||
private static final HashMap<Long, Object> fieldCache = new SyncWriteMap<Long, Object>(512, 0.5F);
|
||||
|
||||
public static Field getField(Long key, Class<?> targetClass, String fieldName) {
|
||||
Object field = fieldCache.get(key);
|
||||
|
@ -24,6 +24,17 @@ import com.jfinal.template.stat.Scope;
|
||||
|
||||
/**
|
||||
* Method : expr '.' ID '(' exprList? ')'
|
||||
*
|
||||
* 每次通过 MethodKit.getMethod(...) 取 MethodInfo 而不是用属性持有其对象
|
||||
* 是为了支持 target 对象的动态类型,MethodInfo 中的 Method 被调用 15 次以后
|
||||
* 会被 JDK 动态生成 GeneratedAccessorXXX 字节码,性能不是问题
|
||||
* 唯一的性能损耗是从 HashMap 中获取 MethodInfo 对象,可以忽略不计
|
||||
*
|
||||
* 如果在未来通过结合 #dynamic(boolean) 指令来优化,需要在 Ctrl 中引入一个
|
||||
* boolean dynamic = false 变量,而不能在 Env、Scope 引入该变量
|
||||
*
|
||||
* 还需要引入一个 NullMethodInfo 以及 isNull() 方法,此优化复杂度提高不少,
|
||||
* 暂时不做此优化
|
||||
*/
|
||||
public class Method extends Expr {
|
||||
|
||||
|
@ -23,6 +23,7 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import com.jfinal.kit.ReflectKit;
|
||||
import com.jfinal.kit.SyncWriteMap;
|
||||
import com.jfinal.template.ext.extensionmethod.ByteExt;
|
||||
import com.jfinal.template.ext.extensionmethod.DoubleExt;
|
||||
import com.jfinal.template.ext.extensionmethod.FloatExt;
|
||||
@ -37,10 +38,10 @@ import com.jfinal.template.ext.extensionmethod.StringExt;
|
||||
public class MethodKit {
|
||||
|
||||
private static final Class<?>[] NULL_ARG_TYPES = new Class<?>[0];
|
||||
private static final Set<String> forbiddenMethods = new HashSet<String>();
|
||||
private static final Set<Class<?>> forbiddenClasses = new HashSet<Class<?>>();
|
||||
private static final Map<Class<?>, Class<?>> primitiveMap = new HashMap<Class<?>, Class<?>>();
|
||||
private static final HashMap<Long, Object> methodCache = new HashMap<Long, Object>();
|
||||
private static final Set<String> forbiddenMethods = new HashSet<String>(64);
|
||||
private static final Set<Class<?>> forbiddenClasses = new HashSet<Class<?>>(64);
|
||||
private static final Map<Class<?>, Class<?>> primitiveMap = new HashMap<Class<?>, Class<?>>(64);
|
||||
private static final Map<Long, Object> methodCache = new SyncWriteMap<Long, Object>(2048, 0.25F);
|
||||
|
||||
// 初始化在模板中调用 method 时所在的被禁止使用类
|
||||
static {
|
||||
@ -307,7 +308,7 @@ public class MethodKit {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, Class<?>> primitiveToBoxedMap = new HashMap<Class<?>, Class<?>>();
|
||||
private static final Map<Class<?>, Class<?>> primitiveToBoxedMap = new HashMap<Class<?>, Class<?>>(64);
|
||||
|
||||
// 初始化 primitive type 到 boxed type 的映射
|
||||
static {
|
||||
|
@ -27,6 +27,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import com.jfinal.kit.HashKit;
|
||||
import com.jfinal.kit.ReflectKit;
|
||||
import com.jfinal.kit.SyncWriteMap;
|
||||
|
||||
/**
|
||||
* SharedMethodKit
|
||||
@ -44,7 +45,7 @@ public class SharedMethodKit {
|
||||
}
|
||||
|
||||
private final List<SharedMethodInfo> sharedMethodList = new ArrayList<SharedMethodInfo>();
|
||||
private final HashMap<Long, SharedMethodInfo> methodCache = new HashMap<Long, SharedMethodInfo>();
|
||||
private final HashMap<Long, SharedMethodInfo> methodCache = new SyncWriteMap<Long, SharedMethodInfo>(512, 0.25F);
|
||||
|
||||
public SharedMethodInfo getSharedMethodInfo(String methodName, Object[] argValues) {
|
||||
Class<?>[] argTypes = MethodKit.getArgTypes(argValues);
|
||||
|
@ -79,23 +79,25 @@ public class DateDirective extends Directive {
|
||||
|
||||
private void outputWithoutDatePattern(Env env, Scope scope, Writer writer) {
|
||||
Object value = valueExpr.eval(scope);
|
||||
if (value != null) {
|
||||
if (value instanceof Date) {
|
||||
write(writer, (Date)value, env.getEngineConfig().getDatePattern());
|
||||
} else if (value != null) {
|
||||
throw new TemplateException("The first parameter date of #date directive must be Date type", location);
|
||||
}
|
||||
}
|
||||
|
||||
private void outputWithDatePattern(Env env, Scope scope, Writer writer) {
|
||||
Object value = valueExpr.eval(scope);
|
||||
if (value == null) {
|
||||
return ;
|
||||
if (value instanceof Date) {
|
||||
Object datePattern = this.datePatternExpr.eval(scope);
|
||||
if (datePattern instanceof String) {
|
||||
write(writer, (Date)value, (String)datePattern);
|
||||
} else {
|
||||
throw new TemplateException("The sencond parameter datePattern of #date directive must be String", location);
|
||||
}
|
||||
} else if (value != null) {
|
||||
throw new TemplateException("The first parameter date of #date directive must be Date type", location);
|
||||
}
|
||||
|
||||
Object datePattern = this.datePatternExpr.eval(scope);
|
||||
if ( !(datePattern instanceof String) ) {
|
||||
throw new TemplateException("The sencond parameter datePattern of #date directive must be String", location);
|
||||
}
|
||||
|
||||
write(writer, (Date)value, (String)datePattern);
|
||||
}
|
||||
|
||||
private void write(Writer writer, Date date, String datePattern) {
|
||||
|
@ -52,11 +52,12 @@ public class EscapeDirective extends Directive {
|
||||
case '>':
|
||||
ret.append(">");
|
||||
break;
|
||||
case '\"':
|
||||
case '"':
|
||||
ret.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
ret.append("'"); // IE 不支持 ' 考虑 '
|
||||
// ret.append("'"); // IE 不支持 ' 考虑 '
|
||||
ret.append("'");
|
||||
break;
|
||||
case '&':
|
||||
ret.append("&");
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package com.jfinal.template.ext.directive;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.jfinal.kit.SyncWriteMap;
|
||||
import com.jfinal.template.Directive;
|
||||
import com.jfinal.template.EngineConfig;
|
||||
import com.jfinal.template.Env;
|
||||
@ -60,7 +60,7 @@ import com.jfinal.template.stat.ast.StatList;
|
||||
public class RenderDirective extends Directive {
|
||||
|
||||
private String parentFileName;
|
||||
private Map<String, StatInfo> statInfoCache = new HashMap<String,StatInfo>();
|
||||
private Map<String, StatInfo> statInfoCache = new SyncWriteMap<String,StatInfo>(16, 0.5F);
|
||||
|
||||
public void setExprList(ExprList exprList) {
|
||||
int len = exprList.length();
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.jfinal.template.ext.spring;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
@ -56,8 +57,20 @@ public class JFinalView extends AbstractTemplateView {
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream os = response.getOutputStream();
|
||||
JFinalViewResolver.engine.getTemplate(getUrl()).render(model, os);
|
||||
try {
|
||||
OutputStream os = response.getOutputStream();
|
||||
JFinalViewResolver.engine.getTemplate(getUrl()).render(model, os);
|
||||
} catch (Exception e) { // 捕获 ByteWriter.close() 抛出的 RuntimeException
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof IOException) { // ClientAbortException、EofException 直接或间接继承自 IOException
|
||||
String name = cause.getClass().getSimpleName();
|
||||
if ("ClientAbortException".equals(name) || "EofException".equals(name)) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
|
||||
|
@ -17,12 +17,11 @@
|
||||
package com.jfinal.template.source;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import com.jfinal.template.EngineConfig;
|
||||
|
||||
/**
|
||||
@ -72,17 +71,12 @@ public class ClassPathSource implements ISource {
|
||||
}
|
||||
|
||||
protected void processIsInJarAndlastModified() {
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
if ("jar".equals(url.getProtocol()) || conn instanceof JarURLConnection) {
|
||||
isInJar = true;
|
||||
lastModified = -1;
|
||||
} else {
|
||||
isInJar = false;
|
||||
lastModified = conn.getLastModified();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
if ("file".equalsIgnoreCase(url.getProtocol())) {
|
||||
isInJar = false;
|
||||
lastModified = new File(url.getFile()).lastModified();
|
||||
} else {
|
||||
isInJar = true;
|
||||
lastModified = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,12 +114,7 @@ public class ClassPathSource implements ISource {
|
||||
}
|
||||
|
||||
protected long getLastModified() {
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
return conn.getLastModified();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new File(url.getFile()).lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,14 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.jfinal.template;
|
||||
package com.jfinal.template.stat;
|
||||
|
||||
import com.jfinal.template.expr.ast.ExprList;
|
||||
import com.jfinal.template.stat.Location;
|
||||
import com.jfinal.template.stat.ast.Output;
|
||||
|
||||
/**
|
||||
* IOutputDirectiveFactory
|
||||
* OutputDirectiveFactory
|
||||
* 用于定制自定义输出指令,替换系统默认输出指令,满足个性化需求
|
||||
*
|
||||
* 用法:
|
||||
@ -32,12 +31,15 @@ import com.jfinal.template.stat.ast.Output;
|
||||
* }
|
||||
*
|
||||
* public void exec(Env env, Scope scope, Writer writer) {
|
||||
* write(writer, exprList.eval(scope));
|
||||
* Object value = exprList.eval(scope);
|
||||
* if (value != null) {
|
||||
* write(writer, value.toString());
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* 2:定义 MyOutputDirectiveFactory
|
||||
* public class MyOutputDirectiveFactory implements IOutputDirectiveFactory {
|
||||
* public class MyOutputDirectiveFactory extends OutputDirectiveFactory {
|
||||
* public Output getOutputDirective(ExprList exprList) {
|
||||
* return new MyOutput(exprList);
|
||||
* }
|
||||
@ -46,11 +48,13 @@ import com.jfinal.template.stat.ast.Output;
|
||||
* 3:配置
|
||||
* engine.setOutputDirectiveFactory(new MyOutputDirectiveFactory())
|
||||
*/
|
||||
public interface IOutputDirectiveFactory {
|
||||
public class OutputDirectiveFactory {
|
||||
|
||||
public Output getOutputDirective(ExprList exprList, Location location);
|
||||
public static final OutputDirectiveFactory me = new OutputDirectiveFactory();
|
||||
|
||||
public Output getOutputDirective(ExprList exprList, Location location) {
|
||||
return new Output(exprList, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ enum Symbol {
|
||||
* 扩展指令在得到 # id ( 序列以后才要求得到正确的后续 Token 序列,否则仅仅 return fail()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static final Map<String, Symbol> keywords = new HashMap<String, Symbol>() {{
|
||||
private static final Map<String, Symbol> keywords = new HashMap<String, Symbol>(64) {{
|
||||
put(Symbol.IF.getName(), IF);
|
||||
put(Symbol.ELSEIF.getName(), ELSEIF);
|
||||
put(Symbol.ELSE.getName(), ELSE);
|
||||
|
Loading…
Reference in New Issue
Block a user