Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Side by Side Diff: third_party/pkg/angular/lib/core/parser/lexer.dart

Issue 124053002: Adding Angular and dependent packages for testing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 part of angular.core.parser;
2
3 @NgInjectableService()
4 class Lexer {
5 List<Token> call(String text) {
6 Scanner scanner = new Scanner(text);
7 List<Token> tokens = [];
8 Token token = scanner.scanToken();
9 while (token != null) {
10 tokens.add(token);
11 token = scanner.scanToken();
12 }
13 return tokens;
14 }
15 }
16
17 class Scanner {
18 final String input;
19 final int length;
20
21 // TODO(kasperl): Get rid of this buffer. It is currently used for
22 // pushing back tokens for method calls found while scanning
23 // identifiers. We should be able to do this in the parser instead.
24 final List<Token> buffer = [];
25
26 int peek = 0;
27 int index = -1;
28
29 Scanner(String input) : this.input = input, this.length = input.length {
30 advance();
31 }
32
33 Token scanToken() {
34 // TODO(kasperl): The current handling of method calls is somewhat
35 // complicated. We should simplify it by dealing with it in the parser.
36 if (!buffer.isEmpty) return buffer.removeLast();
37
38 // Skip whitespace.
39 while (isWhitespace(peek)) advance();
40
41 // Handle identifiers and numbers.
42 if (isIdentifierStart(peek)) return scanIdentifier();
43 if (isDigit(peek)) return scanNumber(index);
44
45 int start = index;
46 switch (peek) {
47 case $EOF:
48 return null;
49 case $PERIOD:
50 advance();
51 return isDigit(peek) ? scanNumber(start) : new Token(start, '.');
52 case $LPAREN:
53 return scanCharacter(start, '(');
54 case $RPAREN:
55 return scanCharacter(start, ')');
56 case $LBRACE:
57 return scanCharacter(start, '{');
58 case $RBRACE:
59 return scanCharacter(start, '}');
60 case $LBRACKET:
61 return scanCharacter(start, '[');
62 case $RBRACKET:
63 return scanCharacter(start, ']');
64 case $COMMA:
65 return scanCharacter(start, ',');
66 case $COLON:
67 return scanCharacter(start, ':');
68 case $SEMICOLON:
69 return scanCharacter(start, ';');
70 case $SQ:
71 case $DQ:
72 return scanString();
73 case $PLUS:
74 return scanOperator(start, '+');
75 case $MINUS:
76 return scanOperator(start, '-');
77 case $STAR:
78 return scanOperator(start, '*');
79 case $SLASH:
80 return scanOperator(start, '/');
81 case $PERCENT:
82 return scanOperator(start, '%');
83 case $CARET:
84 return scanOperator(start, '^');
85 case $QUESTION:
86 return scanOperator(start, '?');
87 case $LT:
88 return scanComplexOperator(start, $EQ, '<', '<=');
89 case $GT:
90 return scanComplexOperator(start, $EQ, '>', '>=');
91 case $BANG:
92 return scanComplexOperator(start, $EQ, '!', '!=');
93 case $EQ:
94 return scanComplexOperator(start, $EQ, '=', '==');
95 case $AMPERSAND:
96 return scanComplexOperator(start, $AMPERSAND, '&', '&&');
97 case $BAR:
98 return scanComplexOperator(start, $BAR, '|', '||');
99 case $TILDE:
100 return scanComplexOperator(start, $SLASH, '~', '~/');
101 }
102
103 String character = new String.fromCharCode(peek);
104 error('Unexpected character [$character]');
105 }
106
107 Token scanCharacter(int start, String string) {
108 assert(peek == string.codeUnitAt(0));
109 advance();
110 return new Token(start, string);
111 }
112
113 Token scanOperator(int start, String string) {
114 assert(peek == string.codeUnitAt(0));
115 assert(OPERATORS.containsKey(string));
116 advance();
117 return new Token(start, string)..withOp(string);
118 }
119
120 Token scanComplexOperator(int start, int code, String one, String two) {
121 assert(peek == one.codeUnitAt(0));
122 advance();
123 String string = one;
124 if (peek == code) {
125 advance();
126 string = two;
127 }
128 assert(OPERATORS.containsKey(string));
129 return new Token(start, string)..withOp(string);
130 }
131
132 Token scanIdentifier() {
133 assert(isIdentifierStart(peek));
134 int start = index;
135 int dot = -1;
136 advance();
137 while (true) {
138 if (peek == $PERIOD) {
139 dot = index;
140 } else if (!isIdentifierPart(peek)) {
141 break;
142 }
143 advance();
144 }
145 if (dot == -1) {
146 String string = input.substring(start, index);
147 Token result = new Token(start, string);
148 // TODO(kasperl): Deal with null, undefined, true, and false in
149 // a cleaner and faster way.
150 if (OPERATORS.containsKey(string)) {
151 result.withOp(string);
152 } else {
153 result.withGetterSetter(string);
154 }
155 return result;
156 }
157
158 int end = index;
159 while (isWhitespace(peek)) advance();
160 if (peek == $LPAREN) {
161 buffer.add(new Token(dot + 1, input.substring(dot + 1, end)));
162 buffer.add(new Token(dot, '.'));
163 end = dot;
164 }
165 String string = input.substring(start, end);
166 return new Token(start, string)..withGetterSetter(string);
167 }
168
169 Token scanNumber(int start) {
170 assert(isDigit(peek));
171 bool simple = (index == start);
172 while (true) {
173 if (isDigit(peek)) {
174 // Do nothing.
175 } else if (peek == $PERIOD) {
176 simple = false;
177 } else if (isExponentStart(peek)) {
178 advance();
179 if (isExponentSign(peek)) advance();
180 if (!isDigit(peek)) error('Invalid exponent', -1);
181 simple = false;
182 } else {
183 break;
184 }
185 advance();
186 }
187 String string = input.substring(start, index);
188 num value = simple ? int.parse(string) : double.parse(string);
189 return new Token(start, string)..withValue(value);
190 }
191
192 Token scanString() {
193 assert(peek == $SQ || peek == $DQ);
194 int start = index;
195 int quote = peek;
196 advance(); // Skip initial quote.
197
198 StringBuffer buffer;
199 int marker = index;
200
201 while (peek != quote) {
202 if (peek == $BACKSLASH) {
203 if (buffer == null) buffer = new StringBuffer();
204 buffer.write(input.substring(marker, index));
205 advance();
206 int unescaped;
207 if (peek == $u) {
208 // TODO(kasperl): Check bounds? Make sure we have test
209 // coverage for this.
210 String hex = input.substring(index + 1, index + 5);
211 unescaped = int.parse(hex, radix: 16, onError: (ignore) {
212 error('Invalid unicode escape [\\u$hex]'); });
213 for (int i = 0; i < 5; i++) advance();
214 } else {
215 unescaped = unescape(peek);
216 advance();
217 }
218 buffer.writeCharCode(unescaped);
219 marker = index;
220 } else if (peek == $EOF) {
221 error('Unterminated quote');
222 } else {
223 advance();
224 }
225 }
226
227 String last = input.substring(marker, index);
228 advance(); // Skip terminating quote.
229 String string = input.substring(start, index);
230
231 // Compute the unescaped string value.
232 String unescaped = last;
233 if (buffer != null) {
234 buffer.write(last);
235 unescaped = buffer.toString();
236 }
237 return new Token(start, string)..withValue(unescaped);
238 }
239
240 void advance() {
241 if (++index >= length) peek = $EOF;
242 else peek = input.codeUnitAt(index);
243 }
244
245 void error(String message, [int offset = 0]) {
246 // TODO(kasperl): Try to get rid of the offset. It is only used to match
247 // the error expectations in the lexer tests for numbers with exponents.
248 int position = index + offset;
249 throw "Lexer Error: $message at column $position in expression [$input]";
250 }
251 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698