|
|
@@ -18,6 +18,7 @@ package com.jfinal.template.stat;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
+import com.jfinal.template.EngineConfig;
|
|
|
|
|
|
/**
|
|
|
* DKFF(Dynamic Key Feature Forward) Lexer
|
|
|
@@ -27,6 +28,8 @@ class Lexer {
|
|
|
static final char EOF = (char)-1;
|
|
|
static final int TEXT_STATE_DIAGRAM = 999;
|
|
|
|
|
|
+ EngineConfig config;
|
|
|
+
|
|
|
char[] buf;
|
|
|
int state = 0;
|
|
|
int lexemeBegin = 0;
|
|
|
@@ -38,7 +41,9 @@ class Lexer {
|
|
|
List<Token> tokens = new ArrayList<Token>();
|
|
|
String fileName;
|
|
|
|
|
|
- public Lexer(StringBuilder content, String fileName) {
|
|
|
+ public Lexer(EngineConfig config, StringBuilder content, String fileName) {
|
|
|
+ this.config = config;
|
|
|
+
|
|
|
int len = content.length();
|
|
|
buf = new char[len + 1];
|
|
|
content.getChars(0, content.length(), buf, 0);
|
|
|
@@ -110,7 +115,7 @@ class Lexer {
|
|
|
para = scanPara("");
|
|
|
idToken = new Token(Symbol.OUTPUT, beginRow);
|
|
|
paraToken = new ParaToken(para, beginRow);
|
|
|
- return addOutputToken(idToken, paraToken);
|
|
|
+ return addIdParaToken(idToken, paraToken);
|
|
|
}
|
|
|
if (CharTable.isLetter(peek())) { // # id
|
|
|
state = 10;
|
|
|
@@ -472,31 +477,6 @@ class Lexer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 输出指令不对前后空白与换行进行任何处理,直接调用 tokens.add(...)
|
|
|
- boolean addOutputToken(Token idToken, Token paraToken) {
|
|
|
- tokens.add(idToken);
|
|
|
- tokens.add(paraToken);
|
|
|
- previousTextToken = null;
|
|
|
- return prepareNextScan(0);
|
|
|
- }
|
|
|
-
|
|
|
- // 向前看后续是否跟随的是空白 + 换行或者是空白 + EOF,是则表示当前指令后续没有其它有用内容
|
|
|
- boolean lookForwardLineFeedAndEof() {
|
|
|
- int forwardBak = forward;
|
|
|
- int forwardRowBak = forwardRow;
|
|
|
- for (char c=peek(); true; c=next()) {
|
|
|
- if (CharTable.isBlank(c)) {
|
|
|
- continue ;
|
|
|
- }
|
|
|
- if (c == '\n' || c == EOF) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- forward = forwardBak;
|
|
|
- forwardRow = forwardRowBak;
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 带参指令处于独立行时删除前后空白字符,并且再删除一个后续的换行符
|
|
|
* 处于独立行是指:向前看无有用内容,在前面情况成立的基础之上
|
|
|
@@ -509,32 +489,58 @@ class Lexer {
|
|
|
tokens.add(idToken);
|
|
|
tokens.add(paraToken);
|
|
|
|
|
|
+ // 保留指令所在行空白字符
|
|
|
+ if (config.isKeepLineBlank(idToken.value())) {
|
|
|
+ prepareNextScan(0);
|
|
|
+ } else {
|
|
|
+ trimLineBlank();
|
|
|
+ }
|
|
|
+
|
|
|
+ previousTextToken = null;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // #set 这类指令,处在独立一行时,需要删除当前行的前后空白字符以及行尾字符 '\n'
|
|
|
+ void trimLineBlank() {
|
|
|
// if (lookForwardLineFeed() && (deletePreviousTextTokenBlankTails() || lexemeBegin == 0)) {
|
|
|
if (lookForwardLineFeedAndEof() && deletePreviousTextTokenBlankTails()) {
|
|
|
prepareNextScan(peek() != EOF ? 1 : 0);
|
|
|
} else {
|
|
|
prepareNextScan(0);
|
|
|
}
|
|
|
- previousTextToken = null;
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
// 处理前后空白的逻辑与 addIdParaToken() 基本一样,仅仅多了一个对于紧随空白的 next() 操作
|
|
|
boolean addNoParaToken(Token noParaToken) {
|
|
|
tokens.add(noParaToken);
|
|
|
+
|
|
|
if (CharTable.isBlank(peek())) {
|
|
|
next(); // 无参指令之后紧随的一个空白字符仅为分隔符,不参与后续扫描
|
|
|
}
|
|
|
|
|
|
- if (lookForwardLineFeedAndEof() && deletePreviousTextTokenBlankTails()) {
|
|
|
- prepareNextScan(peek() != EOF ? 1 : 0);
|
|
|
- } else {
|
|
|
- prepareNextScan(0);
|
|
|
- }
|
|
|
+ trimLineBlank();
|
|
|
+
|
|
|
previousTextToken = null;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ // 向前看后续是否跟随的是空白 + 换行或者是空白 + EOF,是则表示当前指令后续没有其它有用内容
|
|
|
+ boolean lookForwardLineFeedAndEof() {
|
|
|
+ int forwardBak = forward;
|
|
|
+ int forwardRowBak = forwardRow;
|
|
|
+ for (char c=peek(); true; c=next()) {
|
|
|
+ if (CharTable.isBlank(c)) {
|
|
|
+ continue ;
|
|
|
+ }
|
|
|
+ if (c == '\n' || c == EOF) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ forward = forwardBak;
|
|
|
+ forwardRow = forwardRowBak;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 1:当前指令前方仍然是指令 (previousTextToken 为 null),直接返回 true
|
|
|
* 2:当前指令前方为 TextToken 时的处理逻辑与返回值完全依赖于 TextToken.deleteBlankTails()
|