| @@ -1,5 +1,5 | |||
|
|
1 | 1 | export interface Constructor<T = {}> { |
|
|
2 |
new |
|
|
|
2 | new(...args: any[]): T; | |
|
|
3 | 3 | prototype: T; |
|
|
4 | 4 | } |
|
|
5 | 5 | |
| @@ -101,6 +101,11 export interface IObserver<T> { | |||
|
|
101 | 101 | } |
|
|
102 | 102 | |
|
|
103 | 103 | export interface TextWriter { |
|
|
104 | formatter; | |
|
|
105 |
Write( |
|
|
|
104 | Write(obj: any): void; | |
|
|
105 | Write(format: string, ...args: any[]): void; | |
|
|
106 | ||
|
|
107 | WriteLine(obj: any): void; | |
|
|
108 | WriteLine(format: string, ...args: any[]): void; | |
|
|
109 | ||
|
|
110 | WriteValue(value: any, spec?: string): void; | |
|
|
106 | 111 | } |
| @@ -1,53 +1,86 | |||
|
|
1 | 1 | import { FormatScanner, TokeType } from "./FormatScanner"; |
|
|
2 | import { isNullOrEmptyString } from "../safe"; | |
|
|
3 | import { TextWriter } from "../interfaces"; | |
|
|
2 | 4 | |
|
|
3 | 5 | export class FormatCompiler { |
|
|
6 | _scanner: FormatScanner; | |
|
|
4 | 7 | |
|
|
5 | visitText(scanner: FormatScanner) { | |
|
|
6 | while (scanner.next()) { | |
|
|
7 | if (scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
8 | this.visitCurlOpen(scanner); | |
|
|
8 | _parts: []; | |
|
|
9 | ||
|
|
10 | compile() { | |
|
|
11 | return (writer: TextWriter, args: any) => { | |
|
|
12 | this._parts.forEach(x => writer.WriteValue(x)) | |
|
|
13 | }; | |
|
|
14 | } | |
|
|
15 | ||
|
|
16 | visitText() { | |
|
|
17 | while (this._scanner.next()) { | |
|
|
18 | switch (this._scanner.getTokenType()) { | |
|
|
19 | case TokeType.CurlOpen: | |
|
|
20 | this.visitCurlOpen(); | |
|
|
21 | break; | |
|
|
22 | case TokeType.CurlClose: | |
|
|
23 | this.visitCurlClose(); | |
|
|
24 | break; | |
|
|
25 | default: | |
|
|
26 | this.pushText(this._scanner.getTokenValue()); | |
|
|
27 | } | |
|
|
28 | if (this._scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
29 | this.visitCurlOpen(); | |
|
|
9 | 30 | } |
|
|
10 | 31 | } |
|
|
11 | 32 | |
|
|
12 | visitCurlOpen(scanner: FormatScanner) { | |
|
|
13 |
if (scanner.next()) |
|
|
|
14 | if (scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
33 | visitCurlClose() { | |
|
|
34 | if (!this._scanner.next()) | |
|
|
35 | this.dieUnexpectedEnd("}"); | |
|
|
36 | if (this._scanner.getTokenType() !== TokeType.CurlClose) | |
|
|
37 | this.dieUnexpectedToken("}"); | |
|
|
38 | this.pushText("}"); | |
|
|
39 | } | |
|
|
40 | ||
|
|
41 | visitCurlOpen() { | |
|
|
42 | if (this._scanner.next()) { | |
|
|
43 | if (this._scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
15 | 44 | this.pushText("{"); |
|
|
16 | 45 | else |
|
|
17 |
this.visitTemplateSubst( |
|
|
|
18 | ||
|
|
46 | this.visitTemplateSubst(); | |
|
|
19 | 47 | } |
|
|
20 | 48 | } |
|
|
21 | 49 | |
|
|
22 |
visitTemplateSubst( |
|
|
|
23 | if (scanner.getTokenType() !== TokeType.Text) | |
|
|
24 |
this.dieUnexpectedToken( |
|
|
|
50 | visitTemplateSubst() { | |
|
|
51 | if (this._scanner.getTokenType() !== TokeType.Text) | |
|
|
52 | this.dieUnexpectedToken("TEXT"); | |
|
|
25 | 53 | |
|
|
26 | const fieldName = scanner.getTokenValue(); | |
|
|
27 | let filedFormat: string; | |
|
|
28 | if (this.readColon(scanner)) { | |
|
|
29 | filedFormat = this.readFieldFormat(scanner); | |
|
|
30 | } else { | |
|
|
31 | if (scanner.getTokenType() !== TokeType.CurlClose) | |
|
|
32 | this.dieUnexpectedToken(scanner); | |
|
|
33 | } | |
|
|
54 | const fieldName = this._scanner.getTokenValue(); | |
|
|
55 | const filedFormat = this.readColon() && this.readFieldFormat(); | |
|
|
34 | 56 | |
|
|
35 | 57 | this.pushSubst(fieldName, filedFormat); |
|
|
36 | 58 | } |
|
|
37 | 59 | |
|
|
38 | pushSubst(fieldName: string, filedFormat: string) { | |
|
|
39 | throw new Error("Method not implemented."); | |
|
|
60 | readFieldFormat() { | |
|
|
61 | const parts = new Array<string>(); | |
|
|
62 | while (this._scanner.next()) { | |
|
|
63 | if (this._scanner.getTokenType() === TokeType.CurlClose) { | |
|
|
64 | return parts.join(""); | |
|
|
65 | } else { | |
|
|
66 | parts.push(this._scanner.getTokenValue()); | |
|
|
67 | } | |
|
|
68 | } | |
|
|
69 | ||
|
|
70 | this.dieUnexpectedEnd("}"); | |
|
|
40 | 71 | } |
|
|
41 | 72 | |
|
|
42 | readFieldFormat(scanner: FormatScanner): string { | |
|
|
43 | throw new Error("Method not implemented."); | |
|
|
73 | readColon() { | |
|
|
74 | if (!this._scanner.next()) | |
|
|
75 | this.dieUnexpectedEnd(); | |
|
|
76 | if (this._scanner.getTokenType() !== TokeType.Colon) | |
|
|
77 | return false; | |
|
|
78 | if (!this._scanner.next()) | |
|
|
79 | this.dieUnexpectedEnd(); | |
|
|
80 | return true; | |
|
|
44 | 81 | } |
|
|
45 | 82 | |
|
|
46 | readColon(scanner: FormatScanner) { | |
|
|
47 | if (!scanner.next()) | |
|
|
48 | this.dieUnexpectedEnd(); | |
|
|
49 | if (scanner.getTokenType() !== TokeType.Colon) | |
|
|
50 | return false; | |
|
|
83 | pushSubst(fieldName: string, filedFormat: string) { | |
|
|
51 | 84 | |
|
|
52 | 85 | } |
|
|
53 | 86 | |
| @@ -55,11 +88,14 export class FormatCompiler { | |||
|
|
55 | 88 | |
|
|
56 | 89 | } |
|
|
57 | 90 | |
|
|
58 |
dieUnexpectedToken( |
|
|
|
59 | throw new Error(`Unexpected token ${scanner.getTokenValue()}`); | |
|
|
91 | dieUnexpectedToken(expected?: string) { | |
|
|
92 | throw new Error(isNullOrEmptyString(expected) ? | |
|
|
93 | `Unexpected token ${this._scanner.getTokenValue()}` : | |
|
|
94 | `Unexpected token ${this._scanner.getTokenValue()}, expected ${expected}` | |
|
|
95 | ); | |
|
|
60 | 96 | } |
|
|
61 | 97 | |
|
|
62 | dieUnexpectedEnd() { | |
|
|
63 | throw new Error("Unexpected end of string"); | |
|
|
98 | dieUnexpectedEnd(expected?: string) { | |
|
|
99 | throw new Error(isNullOrEmptyString(expected) ? "Unexpected end of the string" : `Unexpected end of the string, expected ${expected}`); | |
|
|
64 | 100 | } |
|
|
65 | 101 | } |
General Comments 0
You need to be logged in to leave comments.
Login now
