-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtokenizer.ts
103 lines (98 loc) · 2.61 KB
/
tokenizer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
enum State {
Start,
Selector,
OpenBrace,
PropertyName,
Colon,
PropertyValue,
Semicolon,
CloseBrace,
Accept,
Reject,
}
export class CSSRuleParserStateMachine {
private state: State = State.Start;
private currentToken: string = "";
private selector: string = "";
private properties: { [key: string]: string } = {};
private currentProperty = "";
// parse each char of input and attempt to transition
// set state accordingly
parse(input: string): boolean {
for (const char of input) {
console.log(char);
this.transition(char);
if (this.state === State.Reject) {
console.log("rejecting", this.state);
return false;
}
}
console.log(`at end of parse ${this.state}`);
return this.state === State.Accept;
}
// state transition logic based on current state
// and given character
private transition(char: string): void {
switch (this.state) {
case State.Start:
if (char.trim() !== "") {
this.state = State.Selector;
this.currentToken += char;
}
break;
case State.Selector:
if (char === "{") {
this.selector = this.currentToken.trim();
this.currentToken = "";
this.state = State.OpenBrace;
} else {
this.currentToken += char;
}
break;
case State.OpenBrace:
if (char === ":") {
this.currentProperty = this.currentToken.trim();
this.currentToken = "";
this.state = State.Colon;
} else if (char === "}") {
this.state = State.CloseBrace;
} else {
this.currentToken += char;
}
break;
case State.Colon:
if (char.trim() !== "") {
this.state = State.PropertyValue;
this.currentToken += char;
}
break;
case State.PropertyValue:
if (char === ";") {
this.properties[this.currentProperty] = this.currentToken.trim();
this.currentToken = "";
this.state = State.Semicolon;
} else if (char === "}") {
this.properties[this.currentProperty] = this.currentToken.trim();
this.state = State.CloseBrace;
} else {
this.currentToken += char;
}
break;
case State.Semicolon:
this.state = State.Accept;
break;
default:
this.state = State.Reject;
}
}
// return typed object based off input
getParseResult(): {
selector: string;
properties: { [key: string]: string };
} {
return {
selector: this.selector,
properties: this.properties,
};
}
}