-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.js
110 lines (87 loc) · 2.66 KB
/
parser.js
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
104
105
106
107
108
109
110
let TokenType = require('./token-type');
let Union = require('./nodes/union-node');
let Concat = require('./nodes/concat');
let Closure = require('./nodes/closure');
let Character = require('./nodes/character');
let Lexer = require('./lexer');
class Parser {
constructor(regex) {
this.lexer = new Lexer(regex);
this.currentToken = this.lexer.getNextToken();
}
parse() {
let expression = this.expression();
if(!this.checkTokenType(TokenType.EOF))
throw `End of file expected at column ${this.getTokenCol()}`;
return {
object: expression
}
}
expression() {
return this.union();
}
union() {
return this.unionPrime(this.concat());
}
unionPrime(leftValue) {
if(this.checkTokenType(TokenType.OP_UNION)) {
this.nextToken();
let rightValue = this.concat();
return this.unionPrime(new Union(leftValue, rightValue));
}
else return leftValue;
}
concat() {
return this.concatPrime(this.closure());
}
concatPrime(leftValue) {
if(this.checkTokenType(TokenType.OP_CONCAT)) {
this.nextToken();
let rightValue = this.closure();
return this.concatPrime(new Concat(leftValue, rightValue));
}
else return leftValue;
}
closure() {
return this.closurePrime(this.primaryExpression());
}
closurePrime(leftValue) {
if(this.checkTokenType(TokenType.OP_CLOSURE)) {
this.nextToken();
return new Closure(leftValue);
}
else return leftValue;
}
primaryExpression() {
if(this.checkTokenType(TokenType.CHARACTER)) {
let characterNode = new Character(this.getTokenLexeme());
this.nextToken();
return characterNode;
}
else if(this.checkTokenType(TokenType.PARENTHESIS_OPEN)) {
this.nextToken();
let expression = this.expression();
if(!this.checkTokenType(TokenType.PARENTHESIS_CLOSE)) {
throw `')' token expected at column ${this.getTokenCol()}`;
}
this.nextToken();
return expression;
}
else {
throw `character or '(' expected at column ${this.getTokenCol()}`;
}
}
getTokenLexeme() {
return this.currentToken.lexeme;
}
checkTokenType(tokenType) {
return this.currentToken.type === tokenType;
}
nextToken() {
this.currentToken = this.lexer.getNextToken();
}
getTokenCol() {
return this.currentToken.col;
}
}
module.exports = Parser;