Tiny在上周上线TinyUiEnterprise的http://www.tinygroup.org/组件,经过反馈测试发现模板引擎的性能一直有问题,请查看jprofile
当然很多性能问题,我们正在完善中,诸如:非递归DFS、大对象生命周期、异步调用......
但是放在我面前的却是把原先ClassLoader加载后,进行调用执行的方式变更为使用anltr的解释性语言去执行。
通过一周左右的攻克,总算把最难啃的骨头给啃掉了,这离不开beetl的贡献,这里有些运用了其中核心代码,通过bytewrite的方式进行调用
本文不在过多论述anltr到底是什么玩意,我感觉这类文章在网上搜索一大堆,推荐去阅读http://blog.csdn.net/dc_726/article/details/45399371
核心代码
}
//语法分析
BeetlLexer lexer = new BeetlLexer(input);
lexer.removeErrorListeners();
lexer.addErrorListener(syntaxError);
//token就是语法树上节点,递归下降解析器
CommonTokenStream tokens = new CommonTokenStream(lexer);
//语法树
BeetlParser parser = new BeetlParser(tokens);
// 测试代码
ProgContext tree = parser.prog();
// begin parsing at init rule
AntlrProgramBuilder pb = new AntlrProgramBuilder(gt);
ProgramMetaData data = pb.build(tree);
判断ASTNode的节点类型
if (node instanceof TinyTemplateParser.BlockContext) {
TinyTemplateParser.BlockContext bc = (TinyTemplateParser.BlockContext) node;
int count = bc.getChildCount();
for (int i = 0; i < count; i++) {
String str = bc.getChild(i).getText();
int position = 0;
if (!this.gt.getConf().directByteOutput) {
StaticTextASTNode textNode = new StaticTextASTNode(
position, null);
return textNode;
} else {
StaticTextByteASTNode textNode = new StaticTextByteASTNode(
position, null);
return textNode;
}
}
Statement block = parseBlock(bc.value(), node);
return block;
}
本案例中采用最简单的模板,里面就是读取变量,没有用到自定义宏
那么如何不通过classloader,而是直接write出来呢?
ctx.byteWriter.write((char[]) ctx.staticTextArray[textIndex]);
/*
注意:此文档初始版本来自jetbrick-template,后经过修改成为Tiny模板引擎词法文件
* jetbrick-template
* http://subchen.github.io/jetbrick-template/
*
* Copyright 2010-2013 Guoqiang Chen. All rights reserved.
* Email: subchen@gmail.com
*/
lexer grammar TinyTemplateLexer;
/*
@header {
package jetbrick.template.parser.grammer;
}
*/
// *******************************************************************
// ------- DEFAULT mode for Plain Text -------------------------------
COMMENT_LINE : '##' ~[\r\n]* NEWLINE ;
COMMENT_BLOCK2 : '#*' .*? '*#' ;
COMMENT_BLOCK1 : '#--' .*? '--#' ;
fragment NEWLINE : ('\r'? '\n' | EOF) ;
TEXT_PLAIN : ~('$'|'#'|'\\')+ ;
TEXT_CDATA : '#[[' .*? ']]#' ;
TEXT_ESCAPED_CHAR : ('\\#'|'\\$'|'\\\\') ;
TEXT_SINGLE_CHAR : ('#'|'$'|'\\') ;
PARA_SPLITER :[ \t]* (',')?[ \t]* ;
I18N_OPEN : '$${' -> pushMode(INSIDE) ;
//VALUE_COMPACT_OPEN : '$' ;
VALUE_OPEN : '${' -> pushMode(INSIDE) ;
VALUE_ESCAPED_OPEN : '$!{' -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_SET : ('#set'|'#!set' ) ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_IF : '#if' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_ELSEIF : '#elseif' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_FOR : ('#for'|'#foreach') ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_BREAK : '#break' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_CONTINUE : '#continue' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_STOP : '#stop' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_INCLUDE : '#include' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_CALL : '#call' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_CALL : '#@call' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_LAYOUT_IMPL : '#@layout' ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_MACRO : '#macro' [ \t]+ ID ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_LAYOUT : '#layout' ARGUMENT_START -> pushMode(INSIDE) ;
fragment ID : [_a-zA-Z$][_a-zA-Z$0-9]* ;
fragment ARGUMENT_START : [ \t]* '(' ;
DIRECTIVE_SET : '#set'|'#!set' ;
DIRECTIVE_IF : '#if' ;
DIRECTIVE_ELSEIF : '#elseif' ;
DIRECTIVE_FOR : '#for' ;
DIRECTIVE_INCLUDE : '#include' ;
DIRECTIVE_BREAK : '#break' ;
DIRECTIVE_CONTINUE : '#continue' ;
DIRECTIVE_STOP : '#stop' ;
DIRECTIVE_MACRO : '#macro' ;
DIRECTIVE_ELSE : '#else'|'#{else}' ;
DIRECTIVE_END : '#end'|'#{end}' ;
DIRECTIVE_BLANK : '#b'|'#{b}' ;
DIRECTIVE_END_OF_LINE : '#eol'|'#{eol}' ;
DIRECTIVE_TABS : '#t'|'#{t}' ;
DIRECTIVE_TABS_INDENT : '#]'|'#{]}' ;
DIRECTIVE_TABS_DENT : '#['|'#{[}' ;
DIRECTIVE_BODYCONTENT : '#bodyContent'|'#{bodyContent}' ;
DIRECTIVE_IMPORT : '#import' ARGUMENT_START -> pushMode(INSIDE) ;
//DIRECTIVE_CALL : '#' ID ;
DIRECTIVE_MACRO_INVOKE : '#' ID ARGUMENT_START -> pushMode(INSIDE) ;
DIRECTIVE_OPEN_MACRO_INVOKE : '#@' ID ARGUMENT_START -> pushMode(INSIDE) ;
// It is a text which like a directive.
// It must be put after directive defination to avoid confliction.
TEXT_DIRECTIVE_LIKE : '#' [a-zA-Z0-9]+ ;
// *******************************************************************
// -------- INSIDE mode for directive --------------------------------
mode INSIDE;
WHITESPACE : [ \t\r\n]+ -> skip ;
LEFT_PARENTHESE : '(' -> pushMode(INSIDE) ;
RIGHT_PARENTHESE : ')' -> popMode ;
LEFT_BRACKET : '[' ;
RIGHT_BRACKET : ']' ;
LEFT_BRACE : '{' -> pushMode(INSIDE) ;
RIGHT_BRACE : '}' -> popMode ;
IN : 'in' ;
OP_ASSIGNMENT : '=' ;
OP_DOT_DOT : '..' ;
OP_DOT_INVOCATION : '.' ;
OP_DOT_INVOCATION_SAFE : '?.' ;
OP_EQUALITY_EQ : '==' ;
OP_EQUALITY_NE : '!=' ;
OP_RELATIONAL_GT : '>' ;
OP_RELATIONAL_LT : '<' ;
OP_RELATIONAL_GE : '>=' ;
OP_RELATIONAL_LE : '<=' ;
OP_CONDITIONAL_AND : '&&' ;
OP_CONDITIONAL_OR : '||' ;
OP_CONDITIONAL_NOT : '!' ;
OP_MATH_PLUS : '+' ;
OP_MATH_MINUS : '-' ;
OP_MATH_MULTIPLICATION : '*' ;
OP_MATH_DIVISION : '/' ;
OP_MATH_REMAINDER : '%' ;
OP_MATH_INCREMENT : '++' ;
OP_MATH_DECREMENT : '--' ;
OP_BITWISE_AND : '&' ;
OP_BITWISE_OR : '|' ;
OP_BITWISE_NOT : '~' ;
OP_BITWISE_XOR : '^' ;
OP_BITWISE_SHL : '<<' ;
OP_BITWISE_SHR : '>>' ;
OP_BITWISE_SHR_2 : '>>>' ;
OP_CONDITIONAL_TERNARY : '?' ;
OP_SIMPLE_CONDITION_TERNARY : '?:' ;
COMMA : ',' ;
COLON : ':' ;
AT : '@' ;
KEYWORD_TRUE : 'true' ;
KEYWORD_FALSE : 'false' ;
KEYWORD_NULL : 'null' ;
IDENTIFIER : [_a-zA-Z][_a-zA-Z0-9]* ;
INTEGER : INT [lLfFdD]? ;
INTEGER_HEX : '0x' HEX+ [lL]? ;
FLOATING_POINT : INT ('.' FRAC)? EXP? [fFdD]? ;
fragment INT : '0' | [1-9] [0-9]* ;
fragment FRAC : [0-9]+ ;
fragment EXP : [Ee] [+\-]? INT ;
STRING_DOUBLE : '"' (ESC|.)*? '"' ;
STRING_SINGLE : '\'' (ESC|.)*? '\'' ;
fragment ESC : '\\' ([btnfr"'\\]|UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;
/*
注意:此文档初始版本来自jetbrick-template,后经过修改成为Tiny模板引擎语法文件
* jetbrick-template
* http://subchen.github.io/jetbrick-template/
*
* Copyright 2010-2013 Guoqiang Chen. All rights reserved.
* Email: subchen@gmail.com
*/
parser grammar TinyTemplateParser;
options {
tokenVocab = TinyTemplateLexer; // use tokens from JetTemplateLexer.g4
}
/*
@header {
package jetbrick.template.parser.grammer;
}
*/
// -------- rule ---------------------------------------
template : block
;
block : (comment | directive | text | value)*
;
text : TEXT_PLAIN
| TEXT_CDATA
| TEXT_SINGLE_CHAR
| COMMENT_LINE
| COMMENT_BLOCK1
| COMMENT_BLOCK2
| TEXT_ESCAPED_CHAR
| TEXT_DIRECTIVE_LIKE
;
comment : COMMENT_LINE
| COMMENT_BLOCK1
| COMMENT_BLOCK2
;
value : //VALUE_COMPACT_OPEN identify_list
VALUE_OPEN expression '}'
| VALUE_ESCAPED_OPEN expression '}'
| I18N_OPEN identify_list '}'
;
directive : set_directive
| if_directive
| for_directive
| break_directive
| import_directive
| continue_directive
| stop_directive
| include_directive
| macro_directive
| call_block_directive
| layout_directive
| layout_impl_directive
| call_directive
| endofline_directive
| blank_directive
| tabs_directive
| indent_directive
| dent_directive
| call_macro_directive
| call_macro_block_directive
| bodycontent_directive
| invalid_directive
;
identify_list
:IDENTIFIER ('.' IDENTIFIER)*
;
define_expression_list
: define_expression (','? define_expression)*
;
para_expression_list
: para_expression (','? para_expression)*
;
para_expression
: IDENTIFIER '=' expression
| expression
;
define_expression
: IDENTIFIER ('=' expression)?
;
set_directive
: DIRECTIVE_OPEN_SET set_expression (','? set_expression)* ')'
;
set_expression
: IDENTIFIER '=' expression
;
endofline_directive
: DIRECTIVE_END_OF_LINE
;
tabs_directive
: DIRECTIVE_TABS
;
blank_directive
: DIRECTIVE_BLANK
;
indent_directive
: DIRECTIVE_TABS_INDENT
;
dent_directive
: DIRECTIVE_TABS_DENT
;
if_directive
: DIRECTIVE_OPEN_IF expression ')' block elseif_directive* else_directive? DIRECTIVE_END
;
elseif_directive
: DIRECTIVE_OPEN_ELSEIF expression ')' block
;
else_directive
: DIRECTIVE_ELSE block
;
for_directive
: DIRECTIVE_OPEN_FOR for_expression ')' block else_directive? DIRECTIVE_END
;
for_expression
: IDENTIFIER (':'|'in') expression
;
break_directive
: DIRECTIVE_OPEN_BREAK expression?')'
| DIRECTIVE_BREAK
;
import_directive
: DIRECTIVE_IMPORT expression ')'
;
continue_directive
: DIRECTIVE_OPEN_CONTINUE expression? ')'
| DIRECTIVE_CONTINUE
;
stop_directive
: DIRECTIVE_OPEN_STOP expression? ')'
| DIRECTIVE_STOP
;
include_directive
: DIRECTIVE_OPEN_INCLUDE expression (','? '{' hash_map_entry_list? '}')? ')'
;
macro_directive
: DIRECTIVE_OPEN_MACRO define_expression_list? ')' block DIRECTIVE_END
;
layout_directive
: DIRECTIVE_OPEN_LAYOUT IDENTIFIER ')' block DIRECTIVE_END
;
call_block_directive
: DIRECTIVE_OPEN_CALL expression (','? para_expression_list )? ')' block DIRECTIVE_END
;
layout_impl_directive
: DIRECTIVE_OPEN_LAYOUT_IMPL IDENTIFIER ')' block DIRECTIVE_END
;
call_directive
: DIRECTIVE_CALL expression ( ','? para_expression_list )? ')'
;
call_macro_block_directive
: DIRECTIVE_OPEN_MACRO_INVOKE para_expression_list? ')' block DIRECTIVE_END
;
bodycontent_directive
:DIRECTIVE_BODYCONTENT
;
call_macro_directive
: DIRECTIVE_MACRO_INVOKE para_expression_list? ')'
;
invalid_directive
: DIRECTIVE_SET
// | DIRECTIVE_PUT
| DIRECTIVE_IF
| DIRECTIVE_ELSEIF
| DIRECTIVE_FOR
| DIRECTIVE_INCLUDE
// | DIRECTIVE_OPEN_CALL_MACRO
// | DIRECTIVE_BODY_CALL
| DIRECTIVE_MACRO
;
expression : '(' expression ')' # expr_group
| constant # expr_constant
| IDENTIFIER # expr_identifier
| '[' (expression_list |expression_range)? ']' # expr_array_list
| '{' hash_map_entry_list? '}' # expr_hash_map
| expression ('.'|'?.') IDENTIFIER '(' expression_list? ')' # expr_member_function_call
| expression ('.'|'?.') IDENTIFIER # expr_field_access
| IDENTIFIER '(' expression_list? ')' # expr_function_call
| expression ('?')? '[' expression ']' # expr_array_get
| expression ('++'|'--') # expr_single_right
| ('+' <assoc=right> |'-' <assoc=right>) expression # expr_math_unary_prefix
| ('++'|'--') expression # expr_single_left
| '~' <assoc=right> expression # expr_math_unary_prefix
| '!' <assoc=right> expression # expr_math_unary_prefix
| expression ('*'|'/'|'%') expression # expr_math_binary_basic
| expression ('+'|'-') expression # expr_math_binary_basic
| expression ('<<'|'>>'|'>>>') expression # expr_math_binary_shift
| expression ('>='|'<='|'>'|'<') expression # expr_compare_relational
| expression ('=='|'!=') expression # expr_compare_equality
| expression '&' expression # expr_math_binary_bitwise
| expression '^' <assoc=right> expression # expr_math_binary_bitwise
| expression '|' expression # expr_math_binary_bitwise
| expression '&&' expression # expr_compare_condition
| expression '||' expression # expr_compare_condition
| expression '?' <assoc=right> expression ':' expression # expr_conditional_ternary
| expression '?:' expression # expr_simple_condition_ternary
;
constant : STRING_DOUBLE
| STRING_SINGLE
| INTEGER
| INTEGER_HEX
| FLOATING_POINT
| KEYWORD_TRUE
| KEYWORD_FALSE
| KEYWORD_NULL
;
expression_list
: expression (',' expression)*
;
hash_map_entry_list
: expression ':' expression (',' expression ':' expression)*
;
expression_range
: expression '..' expression
;