| 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 |