TemplateCompiler.ts
104 lines
| 2.8 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r59 | import { format } from "./StringFormat"; | ||
| import { TraceSource, DebugLevel } from "../log/TraceSource"; | ||||
| import { ITemplateParser, TokenType } from "./TemplateParser"; | ||||
| import m = require("module"); | ||||
| const trace = TraceSource.get(m.id); | ||||
| type TemplateFn = (obj: object) => string; | ||||
| export class TemplateCompiler { | ||||
| _data: string[]; | ||||
| _code: string[]; | ||||
| _wrapWith = true; | ||||
| constructor() { | ||||
| this._code = []; | ||||
| this._data = []; | ||||
| } | ||||
| compile(parser: ITemplateParser): TemplateFn { | ||||
| this.preamble(); | ||||
| this.visitTemplate(parser); | ||||
| this.postamble(); | ||||
| const text = this._code.join("\n"); | ||||
| try { | ||||
| // tslint:disable-next-line:function-constructor | ||||
| const compiled = new Function("obj, format, $data", text); | ||||
| /** | ||||
| * Функция форматирования по шаблону | ||||
| * | ||||
| * @type{Function} | ||||
| * @param{Object} obj объект с параметрами для подстановки | ||||
| */ | ||||
| return (obj: object) => compiled(obj || {}, format, this._data); | ||||
| } catch (e) { | ||||
| trace.traceEvent(DebugLevel, [e, text, this._data]); | ||||
| throw e; | ||||
| } | ||||
| } | ||||
| preamble() { | ||||
| this._code.push( | ||||
| "var $p = [];", | ||||
| "var print = function(){", | ||||
| " $p.push(format.apply(null,arguments));", | ||||
| "};" | ||||
| ); | ||||
| if (this._wrapWith) | ||||
| this._code.push("with(obj){"); | ||||
| } | ||||
| postamble() { | ||||
| if (this._wrapWith) | ||||
| this._code.push("}"); | ||||
| this._code.push("return $p.join('');"); | ||||
| } | ||||
| visitTemplate(parser: ITemplateParser) { | ||||
| while (parser.next()) { | ||||
| switch (parser.token()) { | ||||
| case TokenType.OpenBlock: | ||||
| this.visitCode(parser); | ||||
| break; | ||||
| case TokenType.OpenInlineBlock: | ||||
| this.visitInline(parser); | ||||
| break; | ||||
| default: | ||||
| this.visitTextFragment(parser); | ||||
| break; | ||||
| } | ||||
| } | ||||
| } | ||||
| visitInline(parser: ITemplateParser) { | ||||
| const code = ["$p.push("]; | ||||
| while (parser.next()) { | ||||
| if (parser.token() === TokenType.CloseBlock) | ||||
| break; | ||||
| code.push(parser.value()); | ||||
| } | ||||
| code.push(");"); | ||||
| this._code.push(code.join("")); | ||||
| } | ||||
| visitCode(parser: ITemplateParser) { | ||||
| const code = []; | ||||
| while (parser.next()) { | ||||
| if (parser.token() === TokenType.CloseBlock) | ||||
| break; | ||||
| code.push(parser.value()); | ||||
| } | ||||
| this._code.push(code.join("")); | ||||
| } | ||||
| visitTextFragment(parser: ITemplateParser) { | ||||
| const i = this._data.push(parser.value()); | ||||
| this._code.push("$p.push($data[" + i + "]);"); | ||||
| } | ||||
| } | ||||
