import { FormatScanner, TokeType } from "./FormatScanner"; import { isNullOrEmptyString, isPrimitive, get } from "../safe"; import { TextWriter, MapOf } from "../interfaces"; type CompiledPattern = (writer: TextWriter, args: any) => void; export class FormatCompiler { _scanner: FormatScanner; _cache: MapOf = {}; _parts: Array; compile(pattern: string) { let compiledPattern = this._cache && this._cache[pattern]; if (!compiledPattern) { this._scanner = new FormatScanner(pattern); this._parts = []; this.visitText(); const parts = this._parts; compiledPattern = (writer: TextWriter, args: any) => { parts.forEach(x => { if (isPrimitive(x)) writer.writeValue(x); else writer.writeValue(get(x.name, args), x.format); }); }; if (this._cache) this._cache[pattern] = compiledPattern; } return compiledPattern; } visitText() { while (this._scanner.next()) { // console.log(this._scanner.getTokenType(), this._scanner.getTokenValue()); switch (this._scanner.getTokenType()) { case TokeType.CurlOpen: this.visitCurlOpen(); break; case TokeType.CurlClose: this.visitCurlClose(); break; default: this.pushText(this._scanner.getTokenValue()); } } } visitCurlClose() { if (!this._scanner.next()) this.dieUnexpectedEnd("}"); if (this._scanner.getTokenType() !== TokeType.CurlClose) this.dieUnexpectedToken("}"); this.pushText("}"); } visitCurlOpen() { if (!this._scanner.next()) this.dieUnexpectedEnd("{ | TEXT"); if (this._scanner.getTokenType() === TokeType.CurlOpen) this.pushText("{"); else this.visitTemplateSubst(); } visitTemplateSubst() { if (this._scanner.getTokenType() !== TokeType.Text) this.dieUnexpectedToken("TEXT"); const fieldName = this._scanner.getTokenValue(); const filedFormat = this.readColon() ? this.readFieldFormat() : null; if (this._scanner.getTokenType() !== TokeType.CurlClose) this.dieUnexpectedToken("}"); this.pushSubst(fieldName, filedFormat); } readFieldFormat() { const parts = new Array(); do { if (this._scanner.getTokenType() === TokeType.CurlClose) { return parts.join(""); } else { parts.push(this._scanner.getTokenValue()); } } while (this._scanner.next()); this.dieUnexpectedEnd("}"); } readColon() { if (!this._scanner.next()) this.dieUnexpectedEnd(); if (this._scanner.getTokenType() !== TokeType.Colon) return false; if (!this._scanner.next()) this.dieUnexpectedEnd(); return true; } pushSubst(fieldName: string, filedFormat: string) { // console.log("pushSubst ", fieldName, filedFormat); this._parts.push({ name: fieldName, format: filedFormat }); } pushText(text: string) { this._parts.push(text); } dieUnexpectedToken(expected?: string) { throw new Error(isNullOrEmptyString(expected) ? `Unexpected token ${this._scanner.getTokenValue()}` : `Unexpected token ${this._scanner.getTokenValue()}, expected ${expected}` ); } dieUnexpectedEnd(expected?: string) { throw new Error(isNullOrEmptyString(expected) ? "Unexpected end of the string" : `Unexpected end of the string, expected ${expected}`); } }