Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 625f32b

Browse files
committed
converted lexer from function to closure
1 parent 9632c99 commit 625f32b

File tree

2 files changed

+124
-154
lines changed

2 files changed

+124
-154
lines changed

src/Parser.js

Lines changed: 112 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
function Lexer(text, parsStrings){
2-
this.text = text;
3-
// UTC dates have 20 characters, we send them through parser
4-
this.dateParseLength = parsStrings ? 20 : -1;
5-
this.tokens = [];
6-
this.index = 0;
7-
}
8-
91
OPERATORS = {
102
'null':function(self){return _null;},
113
'true':function(self){return true;},
@@ -33,143 +25,133 @@ OPERATORS = {
3325
};
3426
ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
3527

36-
Lexer.prototype = {
37-
peek: function() {
38-
if (this.index + 1 < this.text.length) {
39-
return this.text.charAt(this.index + 1);
28+
function lex(text, parseStrings){
29+
var dateParseLength = parseStrings ? 20 : -1,
30+
tokens = [],
31+
index = 0,
32+
canStartRegExp = true;
33+
34+
while (index < text.length) {
35+
var ch = text.charAt(index);
36+
if (ch == '"' || ch == "'") {
37+
readString(ch);
38+
canStartRegExp = true;
39+
} else if (ch == '(' || ch == '[') {
40+
tokens.push({index:index, text:ch});
41+
index++;
42+
} else if (ch == '{' ) {
43+
var peekCh = peek();
44+
if (peekCh == ':' || peekCh == '(') {
45+
tokens.push({index:index, text:ch + peekCh});
46+
index++;
47+
} else {
48+
tokens.push({index:index, text:ch});
49+
}
50+
index++;
51+
canStartRegExp = true;
52+
} else if (ch == ')' || ch == ']' || ch == '}' ) {
53+
tokens.push({index:index, text:ch});
54+
index++;
55+
canStartRegExp = false;
56+
} else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
57+
tokens.push({index:index, text:ch});
58+
index++;
59+
canStartRegExp = true;
60+
} else if ( canStartRegExp && ch == '/' ) {
61+
readRegexp();
62+
canStartRegExp = false;
63+
} else if ( isNumber(ch) ) {
64+
readNumber();
65+
canStartRegExp = false;
66+
} else if (isIdent(ch)) {
67+
readIdent();
68+
canStartRegExp = false;
69+
} else if (isWhitespace(ch)) {
70+
index++;
4071
} else {
41-
return false;
42-
}
43-
},
44-
45-
parse: function() {
46-
var tokens = this.tokens;
47-
var canStartRegExp = true;
48-
while (this.index < this.text.length) {
49-
var ch = this.text.charAt(this.index);
50-
if (ch == '"' || ch == "'") {
51-
this.readString(ch);
52-
canStartRegExp = true;
53-
} else if (ch == '(' || ch == '[') {
54-
tokens.push({index:this.index, text:ch});
55-
this.index++;
56-
} else if (ch == '{' ) {
57-
var peekCh = this.peek();
58-
if (peekCh == ':' || peekCh == '(') {
59-
tokens.push({index:this.index, text:ch + peekCh});
60-
this.index++;
61-
} else {
62-
tokens.push({index:this.index, text:ch});
63-
}
64-
this.index++;
65-
canStartRegExp = true;
66-
} else if (ch == ')' || ch == ']' || ch == '}' ) {
67-
tokens.push({index:this.index, text:ch});
68-
this.index++;
69-
canStartRegExp = false;
70-
} else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
71-
tokens.push({index:this.index, text:ch});
72-
this.index++;
73-
canStartRegExp = true;
74-
} else if ( canStartRegExp && ch == '/' ) {
75-
this.readRegexp();
76-
canStartRegExp = false;
77-
} else if ( this.isNumber(ch) ) {
78-
this.readNumber();
79-
canStartRegExp = false;
80-
} else if (this.isIdent(ch)) {
81-
this.readIdent();
82-
canStartRegExp = false;
83-
} else if (this.isWhitespace(ch)) {
84-
this.index++;
72+
var ch2 = ch + peek(),
73+
fn = OPERATORS[ch],
74+
fn2 = OPERATORS[ch2];
75+
if (fn2) {
76+
tokens.push({index:index, text:ch2, fn:fn2});
77+
index += 2;
78+
} else if (fn) {
79+
tokens.push({index:index, text:ch, fn:fn});
80+
index += 1;
8581
} else {
86-
var ch2 = ch + this.peek();
87-
var fn = OPERATORS[ch];
88-
var fn2 = OPERATORS[ch2];
89-
if (fn2) {
90-
tokens.push({index:this.index, text:ch2, fn:fn2});
91-
this.index += 2;
92-
} else if (fn) {
93-
tokens.push({index:this.index, text:ch, fn:fn});
94-
this.index += 1;
95-
} else {
96-
throw "Lexer Error: Unexpected next character [" +
97-
this.text.substring(this.index) +
98-
"] in expression '" + this.text +
99-
"' at column '" + (this.index+1) + "'.";
100-
}
101-
canStartRegExp = true;
82+
throw "Lexer Error: Unexpected next character [" +
83+
text.substring(index) +
84+
"] in expression '" + text +
85+
"' at column '" + (index+1) + "'.";
10286
}
87+
canStartRegExp = true;
10388
}
104-
return tokens;
105-
},
89+
}
90+
return tokens;
10691

107-
isNumber: function(ch) {
92+
function peek() {
93+
return index + 1 < text.length ? text.charAt(index + 1) : false;
94+
}
95+
function isNumber(ch) {
10896
return '0' <= ch && ch <= '9';
109-
},
110-
111-
isWhitespace: function(ch) {
97+
}
98+
function isWhitespace(ch) {
11299
return ch == ' ' || ch == '\r' || ch == '\t' ||
113100
ch == '\n' || ch == '\v';
114-
},
115-
116-
isIdent: function(ch) {
101+
}
102+
function isIdent(ch) {
117103
return 'a' <= ch && ch <= 'z' ||
118104
'A' <= ch && ch <= 'Z' ||
119105
'_' == ch || ch == '$';
120-
},
121-
122-
readNumber: function() {
106+
}
107+
function readNumber() {
123108
var number = "";
124-
var start = this.index;
125-
while (this.index < this.text.length) {
126-
var ch = this.text.charAt(this.index);
127-
if (ch == '.' || this.isNumber(ch)) {
109+
var start = index;
110+
while (index < text.length) {
111+
var ch = text.charAt(index);
112+
if (ch == '.' || isNumber(ch)) {
128113
number += ch;
129114
} else {
130115
break;
131116
}
132-
this.index++;
117+
index++;
133118
}
134119
number = 1 * number;
135-
this.tokens.push({index:start, text:number,
120+
tokens.push({index:start, text:number,
136121
fn:function(){return number;}});
137-
},
138-
139-
readIdent: function() {
122+
}
123+
function readIdent() {
140124
var ident = "";
141-
var start = this.index;
142-
while (this.index < this.text.length) {
143-
var ch = this.text.charAt(this.index);
144-
if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
125+
var start = index;
126+
while (index < text.length) {
127+
var ch = text.charAt(index);
128+
if (ch == '.' || isIdent(ch) || isNumber(ch)) {
145129
ident += ch;
146130
} else {
147131
break;
148132
}
149-
this.index++;
133+
index++;
150134
}
151135
var fn = OPERATORS[ident];
152136
if (!fn) {
153137
fn = getterFn(ident);
154138
fn.isAssignable = ident;
155139
}
156-
this.tokens.push({index:start, text:ident, fn:fn});
157-
},
158-
159-
readString: function(quote) {
160-
var start = this.index;
161-
var dateParseLength = this.dateParseLength;
162-
this.index++;
140+
tokens.push({index:start, text:ident, fn:fn});
141+
}
142+
function readString(quote) {
143+
var start = index;
144+
index++;
163145
var string = "";
164146
var rawString = quote;
165147
var escape = false;
166-
while (this.index < this.text.length) {
167-
var ch = this.text.charAt(this.index);
148+
while (index < text.length) {
149+
var ch = text.charAt(index);
168150
rawString += ch;
169151
if (escape) {
170152
if (ch == 'u') {
171-
var hex = this.text.substring(this.index + 1, this.index + 5);
172-
this.index += 4;
153+
var hex = text.substring(index + 1, index + 5);
154+
index += 4;
173155
string += String.fromCharCode(parseInt(hex, 16));
174156
} else {
175157
var rep = ESCAPE[ch];
@@ -183,8 +165,8 @@ Lexer.prototype = {
183165
} else if (ch == '\\') {
184166
escape = true;
185167
} else if (ch == quote) {
186-
this.index++;
187-
this.tokens.push({index:start, text:rawString, string:string,
168+
index++;
169+
tokens.push({index:start, text:rawString, string:string,
188170
fn:function(){
189171
return (string.length == dateParseLength) ?
190172
angular['String']['toDate'](string) : string;
@@ -193,53 +175,52 @@ Lexer.prototype = {
193175
} else {
194176
string += ch;
195177
}
196-
this.index++;
178+
index++;
197179
}
198180
throw "Lexer Error: Unterminated quote [" +
199-
this.text.substring(start) + "] starting at column '" +
200-
(start+1) + "' in expression '" + this.text + "'.";
201-
},
202-
203-
readRegexp: function(quote) {
204-
var start = this.index;
205-
this.index++;
181+
text.substring(start) + "] starting at column '" +
182+
(start+1) + "' in expression '" + text + "'.";
183+
}
184+
function readRegexp(quote) {
185+
var start = index;
186+
index++;
206187
var regexp = "";
207188
var escape = false;
208-
while (this.index < this.text.length) {
209-
var ch = this.text.charAt(this.index);
189+
while (index < text.length) {
190+
var ch = text.charAt(index);
210191
if (escape) {
211192
regexp += ch;
212193
escape = false;
213194
} else if (ch === '\\') {
214195
regexp += ch;
215196
escape = true;
216197
} else if (ch === '/') {
217-
this.index++;
198+
index++;
218199
var flags = "";
219-
if (this.isIdent(this.text.charAt(this.index))) {
220-
this.readIdent();
221-
flags = this.tokens.pop().text;
200+
if (isIdent(text.charAt(index))) {
201+
readIdent();
202+
flags = tokens.pop().text;
222203
}
223204
var compiledRegexp = new RegExp(regexp, flags);
224-
this.tokens.push({index:start, text:regexp, flags:flags,
205+
tokens.push({index:start, text:regexp, flags:flags,
225206
fn:function(){return compiledRegexp;}});
226207
return;
227208
} else {
228209
regexp += ch;
229210
}
230-
this.index++;
211+
index++;
231212
}
232213
throw "Lexer Error: Unterminated RegExp [" +
233-
this.text.substring(start) + "] starting at column '" +
234-
(start+1) + "' in expression '" + this.text + "'.";
214+
text.substring(start) + "] starting at column '" +
215+
(start+1) + "' in expression '" + text + "'.";
235216
}
236-
};
217+
}
237218

238219
/////////////////////////////////////////
239220

240221
function Parser(text, parseStrings){
241222
this.text = text;
242-
this.tokens = new Lexer(text, parseStrings).parse();
223+
this.tokens = lex(text, parseStrings);
243224
this.index = 0;
244225
}
245226

0 commit comments

Comments
 (0)