diff --git a/src/main/ts/interfaces.ts b/src/main/ts/interfaces.ts --- a/src/main/ts/interfaces.ts +++ b/src/main/ts/interfaces.ts @@ -1,5 +1,5 @@ export interface Constructor { - new (...args: any[]): T; + new(...args: any[]): T; prototype: T; } @@ -101,6 +101,11 @@ export interface IObserver { } export interface TextWriter { - formatter; - Write(data, format?: string); + Write(obj: any): void; + Write(format: string, ...args: any[]): void; + + WriteLine(obj: any): void; + WriteLine(format: string, ...args: any[]): void; + + WriteValue(value: any, spec?: string): void; } diff --git a/src/main/ts/text/FormatCompiler.ts b/src/main/ts/text/FormatCompiler.ts --- a/src/main/ts/text/FormatCompiler.ts +++ b/src/main/ts/text/FormatCompiler.ts @@ -1,53 +1,86 @@ import { FormatScanner, TokeType } from "./FormatScanner"; +import { isNullOrEmptyString } from "../safe"; +import { TextWriter } from "../interfaces"; export class FormatCompiler { + _scanner: FormatScanner; - visitText(scanner: FormatScanner) { - while (scanner.next()) { - if (scanner.getTokenType() === TokeType.CurlOpen) - this.visitCurlOpen(scanner); + _parts: []; + + compile() { + return (writer: TextWriter, args: any) => { + this._parts.forEach(x => writer.WriteValue(x)) + }; + } + + visitText() { + while (this._scanner.next()) { + switch (this._scanner.getTokenType()) { + case TokeType.CurlOpen: + this.visitCurlOpen(); + break; + case TokeType.CurlClose: + this.visitCurlClose(); + break; + default: + this.pushText(this._scanner.getTokenValue()); + } + if (this._scanner.getTokenType() === TokeType.CurlOpen) + this.visitCurlOpen(); } } - visitCurlOpen(scanner: FormatScanner) { - if (scanner.next()) { - if (scanner.getTokenType() === TokeType.CurlOpen) + visitCurlClose() { + if (!this._scanner.next()) + this.dieUnexpectedEnd("}"); + if (this._scanner.getTokenType() !== TokeType.CurlClose) + this.dieUnexpectedToken("}"); + this.pushText("}"); + } + + visitCurlOpen() { + if (this._scanner.next()) { + if (this._scanner.getTokenType() === TokeType.CurlOpen) this.pushText("{"); else - this.visitTemplateSubst(scanner); - + this.visitTemplateSubst(); } } - visitTemplateSubst(scanner: FormatScanner) { - if (scanner.getTokenType() !== TokeType.Text) - this.dieUnexpectedToken(scanner); + visitTemplateSubst() { + if (this._scanner.getTokenType() !== TokeType.Text) + this.dieUnexpectedToken("TEXT"); - const fieldName = scanner.getTokenValue(); - let filedFormat: string; - if (this.readColon(scanner)) { - filedFormat = this.readFieldFormat(scanner); - } else { - if (scanner.getTokenType() !== TokeType.CurlClose) - this.dieUnexpectedToken(scanner); - } + const fieldName = this._scanner.getTokenValue(); + const filedFormat = this.readColon() && this.readFieldFormat(); this.pushSubst(fieldName, filedFormat); } - pushSubst(fieldName: string, filedFormat: string) { - throw new Error("Method not implemented."); + readFieldFormat() { + const parts = new Array(); + while (this._scanner.next()) { + if (this._scanner.getTokenType() === TokeType.CurlClose) { + return parts.join(""); + } else { + parts.push(this._scanner.getTokenValue()); + } + } + + this.dieUnexpectedEnd("}"); } - readFieldFormat(scanner: FormatScanner): string { - throw new Error("Method not implemented."); + readColon() { + if (!this._scanner.next()) + this.dieUnexpectedEnd(); + if (this._scanner.getTokenType() !== TokeType.Colon) + return false; + if (!this._scanner.next()) + this.dieUnexpectedEnd(); + return true; } - readColon(scanner: FormatScanner) { - if (!scanner.next()) - this.dieUnexpectedEnd(); - if (scanner.getTokenType() !== TokeType.Colon) - return false; + pushSubst(fieldName: string, filedFormat: string) { } @@ -55,11 +88,14 @@ export class FormatCompiler { } - dieUnexpectedToken(scanner: FormatScanner) { - throw new Error(`Unexpected token ${scanner.getTokenValue()}`); + dieUnexpectedToken(expected?: string) { + throw new Error(isNullOrEmptyString(expected) ? + `Unexpected token ${this._scanner.getTokenValue()}` : + `Unexpected token ${this._scanner.getTokenValue()}, expected ${expected}` + ); } - dieUnexpectedEnd() { - throw new Error("Unexpected end of string"); + dieUnexpectedEnd(expected?: string) { + throw new Error(isNullOrEmptyString(expected) ? "Unexpected end of the string" : `Unexpected end of the string, expected ${expected}`); } } diff --git a/src/main/ts/text/StringBuilder.ts b/src/main/ts/text/StringBuilder.ts --- a/src/main/ts/text/StringBuilder.ts +++ b/src/main/ts/text/StringBuilder.ts @@ -9,7 +9,7 @@ export class StringBuilder { WriteLine(obj: any); WriteLine(format: string, ...args: any[]) { - + } WriteValue(value: any, spec?: string) {