OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library servicec.parser; | |
6 | |
7 import 'package:compiler/src/tokens/token.dart' show | |
8 ErrorToken, | |
9 KeywordToken, | |
10 Token; | |
11 | |
12 import 'package:compiler/src/tokens/token_constants.dart' show | |
13 EOF_TOKEN, | |
14 IDENTIFIER_TOKEN, | |
15 KEYWORD_TOKEN; | |
16 | |
17 import 'listener.dart' show | |
18 Listener; | |
19 | |
20 import 'scanner.dart' show | |
21 LF_TOKEN; | |
22 | |
23 /// Parser for the Dart service IDL, reusing the dart2js tokens. | |
24 class Parser { | |
25 Listener listener; | |
26 Parser(this.listener); | |
27 | |
28 /// Entry point for the parser. The linked list [tokens] should be produced by | |
29 /// the dart2js [Scanner]. | |
30 /// | |
31 /// <unit> ::= <top-level-declaration>* | |
32 Token parseUnit(Token tokens) { | |
33 tokens = listener.beginCompilationUnit(tokens); | |
34 int count = 0; | |
35 while (valid(tokens)) { | |
36 tokens = parseTopLevel(tokens); | |
37 ++count; | |
38 } | |
39 tokens = listener.endCompilationUnit(tokens, count); | |
40 return tokens; | |
41 } | |
42 | |
43 /// A top-level declaration is a service or a struct. | |
44 /// | |
45 /// <top-level-declaration> ::= <service> | <struct> | |
46 Token parseTopLevel(Token tokens) { | |
47 tokens = listener.beginTopLevel(tokens); | |
48 if (optional('service', tokens)) { | |
49 tokens = parseService(tokens); | |
50 } else if (optional('struct', tokens)) { | |
51 tokens = parseStruct(tokens); | |
52 } else { | |
53 tokens = listener.expectedTopLevel(tokens); | |
54 } | |
55 tokens = listener.endTopLevel(tokens); | |
56 return tokens; | |
57 } | |
58 | |
59 /// A service contains the keyword, an identifier, and a body. The body is | |
60 /// enclosed in {} and contains zero or more function declarations. | |
61 /// | |
62 /// <service> ::= 'service' <identifier> '{' <func-decl>* '}' | |
63 Token parseService(Token tokens) { | |
64 tokens = listener.beginService(skipNewLines(tokens)); | |
65 tokens = parseIdentifier(next(tokens)); | |
66 tokens = expect('{', tokens); | |
67 int count = 0; | |
68 if (valid(tokens)) { | |
69 while (!optional('}', tokens)) { | |
70 tokens = parseFunction(tokens); | |
71 if (!valid(tokens)) break; // Don't count unsuccessful declarations | |
72 ++count; | |
73 } | |
74 } | |
75 tokens = expect('}', tokens); | |
76 tokens = listener.endService(tokens, count); | |
77 return tokens; | |
78 } | |
79 | |
80 /// A struct contains the keyword, an identifier, and a body. The body is | |
81 /// enclosed in {} and contains zero or more field declarations. | |
82 /// | |
83 /// <struct> ::= 'struct' <identifier> '{' <field-decl>* '}' | |
84 Token parseStruct(Token tokens) { | |
85 tokens = listener.beginStruct(skipNewLines(tokens)); | |
86 tokens = parseIdentifier(next(tokens)); | |
87 tokens = expect('{', tokens); | |
88 int count = 0; | |
89 if (valid(tokens)) { | |
90 while (!optional('}', tokens)) { | |
91 tokens = parseMember(tokens); | |
92 if (!valid(tokens)) break; // Don't count unsuccessful declarations | |
93 ++count; | |
94 } | |
95 } | |
96 tokens = expect('}', tokens); | |
97 tokens = listener.endStruct(tokens, count); | |
98 return tokens; | |
99 } | |
100 | |
101 Token parseIdentifier(Token tokens) { | |
102 Token trimmedTokens = skipNewLines(tokens); | |
103 if (isValidIdentifier(trimmedTokens)) { | |
104 tokens = listener.handleIdentifier(trimmedTokens); | |
105 } else { | |
106 tokens = listener.expectedIdentifier(tokens); | |
107 } | |
108 return tokens; | |
109 } | |
110 | |
111 /// A function declaration contains a type, an identifier, formal parameters, | |
112 /// and a semicolon. | |
113 /// | |
114 /// <func-decl> ::= <type> <identifier> <formal-params> ';' | |
115 Token parseFunction(Token tokens) { | |
116 tokens = listener.beginFunction(tokens); | |
117 tokens = parseType(tokens); | |
118 tokens = parseIdentifier(tokens); | |
119 tokens = expect('(', tokens); | |
120 int count = 0; | |
121 if (!optional(')', tokens)) { | |
122 tokens = parseFormal(tokens); | |
123 ++count; | |
124 while (optional(',', tokens)) { | |
125 tokens = next(tokens); | |
126 tokens = parseFormal(tokens); | |
127 ++count; | |
128 } | |
129 } | |
130 tokens = expect(')', tokens); | |
131 tokens = expect(';', tokens); | |
132 tokens = listener.endFunction(tokens, count); | |
133 return tokens; | |
134 } | |
135 | |
136 // Parse a struct member that can be either a field or a union. | |
137 Token parseMember(Token tokens) { | |
138 if (optional('union', tokens)) { | |
139 tokens = parseUnion(tokens); | |
140 } else { | |
141 tokens = parseField(tokens); | |
142 } | |
143 return tokens; | |
144 } | |
145 | |
146 /// A union contains the 'union' keyword and a list of fields, enclosed in | |
147 /// curly braces. | |
148 /// | |
149 /// <union> ::= 'union' '{' <field>* '}' | |
150 Token parseUnion(Token tokens) { | |
151 tokens = listener.beginUnion(tokens); | |
152 tokens = expect('{', next(tokens)); | |
153 int count = 0; | |
154 if (valid(tokens)) { | |
155 while (!optional('}', tokens)) { | |
156 tokens = parseField(tokens); | |
157 if (!valid(tokens)) break; // Don't count unsuccessful declarations | |
158 ++count; | |
159 } | |
160 } | |
161 tokens = expect('}', tokens); | |
162 tokens = listener.endUnion(tokens, count); | |
163 return tokens; | |
164 } | |
165 | |
166 /// A field contains a type, an identifier, and a semicolon. | |
167 /// | |
168 /// <field-decl> ::= <type> <identifier> ';' | |
169 Token parseField(Token tokens) { | |
170 tokens = listener.beginField(tokens); | |
171 tokens = parseType(tokens); | |
172 tokens = parseIdentifier(tokens); | |
173 tokens = expect(';', tokens); | |
174 tokens = listener.endField(tokens); | |
175 return tokens; | |
176 } | |
177 | |
178 Token parseType(Token tokens) { | |
179 tokens = listener.beginType(tokens); | |
180 tokens = parseIdentifier(tokens); | |
181 if (optional('*', tokens)) { | |
182 // Push a simple type on the stack. | |
183 tokens = listener.handleSimpleType(tokens); | |
184 tokens = next(tokens); | |
185 // Pop the simple type and push a pointer type. | |
186 tokens = listener.handlePointerType(tokens); | |
187 } else if (optional('<', tokens)) { | |
188 tokens = next(tokens); | |
189 tokens = parseType(tokens); | |
190 tokens = expect('>', tokens); | |
191 tokens = listener.handleListType(tokens); | |
192 } else { | |
193 tokens = listener.handleSimpleType(tokens); | |
194 } | |
195 tokens = listener.endType(tokens); | |
196 return tokens; | |
197 } | |
198 | |
199 /// A formal contains a type and an identifier. | |
200 /// | |
201 /// <param> ::= <type> <identifier> | |
202 Token parseFormal(Token tokens) { | |
203 tokens = listener.beginFormal(tokens); | |
204 tokens = parseType(tokens); | |
205 tokens = parseIdentifier(tokens); | |
206 tokens = listener.endFormal(tokens); | |
207 return tokens; | |
208 } | |
209 | |
210 bool isValidIdentifier(Token tokens) { | |
211 tokens = skipNewLines(tokens); | |
212 return tokens.kind == IDENTIFIER_TOKEN; | |
213 } | |
214 | |
215 Token skipNewLines(Token tokens) { | |
216 while (tokens.kind == LF_TOKEN) { | |
217 tokens = tokens.next; | |
218 } | |
219 return tokens; | |
220 } | |
221 | |
222 /// Returns true if the [tokens] is a SymbolToken or a KeywordToken with | |
223 /// stringValue [string]. | |
224 bool optional(String string, Token tokens) { | |
225 tokens = skipNewLines(tokens); | |
226 return string == tokens.stringValue; | |
227 } | |
228 | |
229 /// Checks that the [tokens] is a SymbolToken or a KeywordToken with | |
230 /// stringValue [value]. | |
231 Token expect(String string, Token tokens) { | |
232 tokens = skipNewLines(tokens); | |
233 if (string != tokens.stringValue) { | |
234 tokens = listener.expected(string, tokens); | |
235 } else { | |
236 tokens = next(tokens); | |
237 } | |
238 return tokens; | |
239 } | |
240 | |
241 bool valid(Token tokens) { | |
242 tokens = skipNewLines(tokens); | |
243 return tokens.kind != EOF_TOKEN && tokens is! ErrorToken; | |
244 } | |
245 | |
246 Token next(Token tokens) => skipNewLines(skipNewLines(tokens).next); | |
247 } | |
OLD | NEW |