-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtokenizer.ts
89 lines (79 loc) · 2.75 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
export interface Token {
value: string;
type: TokenType;
}
export enum TokenType {
Number,
String,
Identifier,
Equals,
BinaryOperator,
VariableDeclaration,
Const,
OpenParen,
CloseParen,
Semicolon,
EOF,
}
const keywordToTokenType = new Map<string, TokenType>([
["let", TokenType.VariableDeclaration],
["const", TokenType.Const],
]);
function createToken(value = "", type: TokenType): Token {
return { value, type };
}
function isNumber(value: string): boolean {
return !isNaN(parseFloat(value));
}
function isAlphabetic(value: string): boolean {
return /^[a-zA-Z]+$/.test(value);
}
function isWhitespace(value: string): boolean {
return value === " " || value === "\n" || value === "\t";
}
export function tokenize(input: string): Token[] {
const tokens = new Array<Token>();
const currentInput = input.split("");
while (currentInput.length > 0) {
if (currentInput[0] === "(") {
tokens.push(createToken(currentInput.shift(), TokenType.OpenParen));
} else if (currentInput[0] === ")") {
tokens.push(createToken(currentInput.shift(), TokenType.CloseParen));
} else if (
currentInput[0] === "+" ||
currentInput[0] === "-" ||
currentInput[0] === "*" ||
currentInput[0] === "/" ||
currentInput[0] === "%"
) {
tokens.push(createToken(currentInput.shift(), TokenType.BinaryOperator));
} else if (isNumber(currentInput[0])) {
let number = "";
while (currentInput.length > 0 && isNumber(currentInput[0])) {
number += currentInput.shift();
}
tokens.push(createToken(number, TokenType.Number));
} else if (currentInput[0] == "=") {
tokens.push(createToken(currentInput.shift(), TokenType.Equals));
} else if (currentInput[0] == ";") {
tokens.push(createToken(currentInput.shift(), TokenType.Semicolon));
} else if (isAlphabetic(currentInput[0])) {
let identifier = "";
while (currentInput.length > 0 && isAlphabetic(currentInput[0])) {
identifier += currentInput.shift();
}
const keywordType = keywordToTokenType.get(identifier);
if (typeof keywordType == "number") {
tokens.push(createToken(identifier, keywordType));
} else {
tokens.push(createToken(identifier, TokenType.Identifier));
}
} else if (isWhitespace(currentInput[0])) {
currentInput.shift();
} else {
throw new Error(`Unexpected character: ${currentInput[0]}`);
}
}
tokens.push(createToken("", TokenType.EOF));
return tokens;
}