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: [email protected] */ 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: [email protected] */ 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 ;