diff --git a/src/main/ts/text/FormatCompiler.ts b/src/main/ts/text/FormatCompiler.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/text/FormatCompiler.ts @@ -0,0 +1,61 @@ +import { FormatScanner, TokeType } from "./FormatScanner"; + +export class FormatCompiler { + + visitText(scanner: FormatScanner) { + while (scanner.next()) { + if (scanner.getTokenType() === TokeType.CurlOpen) + this.visitCurlOpen(scanner); + } + } + + visitCurlOpen(scanner: FormatScanner) { + if (scanner.next()) { + if (scanner.getTokenType() === TokeType.CurlOpen) + this.pushText("{"); + else + this.visitTemplateSubst(scanner); + + } + } + + visitTemplateSubst(scanner: FormatScanner) { + if (scanner.getTokenType() !== TokeType.Text) + this.dieUnexpectedToken(scanner); + + const fieldName = scanner.getTokenValue(); + let filedFormat: string; + if (this.readColon(scanner)) { + filedFormat = this.readFieldFormat(scanner); + } else { + if (scanner.getTokenType() !== TokeType.CurlClose) + this.dieUnexpectedToken(scanner); + } + + this.pushSubst(fieldName, filedFormat); + } + pushSubst(fieldName: string, filedFormat: string) { + throw new Error("Method not implemented."); + } + readFieldFormat(scanner: FormatScanner): string { + throw new Error("Method not implemented."); + } + readColon(scanner: FormatScanner) { + if (!scanner.next()) + this.dieUnexpectedEnd(); + if (scanner.getTokenType() !== TokeType.Colon) + return false; + } + + pushText(text: string) { + + } + + dieUnexpectedToken(scanner: FormatScanner) { + throw new Error(`Unexpected token ${scanner.getTokenValue()}`); + } + + dieUnexpectedEnd() { + throw new Error("Unexpected end of string"); + } +} diff --git a/src/main/ts/text/FormatScanner.ts b/src/main/ts/text/FormatScanner.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/text/FormatScanner.ts @@ -0,0 +1,48 @@ +import { argumentNotEmptyString } from "../safe"; +import { MapOf } from "../interfaces"; + +export const enum TokeType { + CurlOpen, + CurlClose, + Colon, + Text +} + +const typeMap = { + "{": TokeType.CurlOpen, + "}": TokeType.CurlClose, + ":": TokeType.Colon +} as MapOf; + +export class FormatScanner { + private _text: string; + private _pos: number; + private _tokenType: TokeType; + private _tokenValue: string; + private _rx = /[^{}:]+|(.)/g; + + constructor(text: string) { + argumentNotEmptyString(text, text); + this._text = text; + } + + next() { + if (this._rx.lastIndex >= this._text.length) + return false; + this._pos = this._rx.lastIndex; + + const match = this._rx.exec(this._text); + this._tokenType = typeMap[match[1]] || TokeType.Text; + this._tokenValue = match[0]; + + return true; + } + + getTokenValue() { + return this._tokenValue; + } + + getTokenType() { + return this._tokenType; + } +} diff --git a/src/main/ts/text/StringBuilder.ts b/src/main/ts/text/StringBuilder.ts new file mode 100644 --- /dev/null +++ b/src/main/ts/text/StringBuilder.ts @@ -0,0 +1,18 @@ +export class StringBuilder { + private _data: string[]; + private _newLine = "\n"; + + Write(obj: any); + Write(format: string, ...args: any[]) { + + } + + WriteLine(obj: any); + WriteLine(format: string, ...args: any[]) { + + } + + WriteValue(value: any, spec?: string) { + + } +}