| 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.errors; | |
| 6 | |
| 7 import 'package:compiler/src/tokens/token.dart' show | |
| 8 Token; | |
| 9 | |
| 10 import 'package:compiler/src/util/characters.dart' show | |
| 11 $LF; | |
| 12 | |
| 13 import 'dart:io' show | |
| 14 File; | |
| 15 | |
| 16 import 'node.dart' show | |
| 17 FunctionNode, | |
| 18 FormalNode, | |
| 19 IdentifierNode, | |
| 20 ListType, | |
| 21 FieldNode, | |
| 22 MemberNode, | |
| 23 Node, | |
| 24 NodeVisitor, | |
| 25 ServiceNode, | |
| 26 StructNode, | |
| 27 TopLevelNode, | |
| 28 TypeNode, | |
| 29 UnionNode; | |
| 30 | |
| 31 enum ErrorTag { | |
| 32 badField, | |
| 33 badFieldType, | |
| 34 badFormal, | |
| 35 badFunction, | |
| 36 badListType, | |
| 37 badPointerType, | |
| 38 badReturnType, | |
| 39 badServiceDefinition, | |
| 40 badSingleFormal, | |
| 41 badStructDefinition, | |
| 42 badTopLevel, | |
| 43 badTypeParameter, | |
| 44 badUnion, | |
| 45 cyclicStruct, | |
| 46 expectedPrimitiveFormal, | |
| 47 multipleDefinitions, | |
| 48 multipleUnions, | |
| 49 serviceStructNameClash, | |
| 50 undefinedService | |
| 51 } | |
| 52 | |
| 53 // A reverse map from error names to errors. | |
| 54 final Map<String, ErrorTag> compilerErrorTypes = | |
| 55 new Map<String, ErrorTag>.fromIterables( | |
| 56 ErrorTag.values.map((value) => value.toString()), | |
| 57 ErrorTag.values | |
| 58 ); | |
| 59 | |
| 60 // Error nodes. | |
| 61 class ServiceErrorNode extends ServiceNode with ErrorNode { | |
| 62 ServiceErrorNode(IdentifierNode identifier, | |
| 63 List<FunctionNode> functions, | |
| 64 Token begin) | |
| 65 : super(identifier, functions) { | |
| 66 this.begin = begin; | |
| 67 tag = ErrorTag.badServiceDefinition; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 class StructErrorNode extends StructNode with ErrorNode { | |
| 72 StructErrorNode(IdentifierNode identifier, | |
| 73 List<MemberNode> members, | |
| 74 Token begin) | |
| 75 : super(identifier, members) { | |
| 76 this.begin = begin; | |
| 77 tag = ErrorTag.badStructDefinition; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 class TopLevelErrorNode extends TopLevelNode with ErrorNode { | |
| 82 TopLevelErrorNode(Token begin) | |
| 83 : super(null) { | |
| 84 this.begin = begin; | |
| 85 tag = ErrorTag.badTopLevel; | |
| 86 } | |
| 87 | |
| 88 void accept(NodeVisitor visitor) { | |
| 89 visitor.visitError(this); | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 class FunctionErrorNode extends FunctionNode | |
| 94 with ErrorNode { | |
| 95 FunctionErrorNode(TypeNode type, | |
| 96 IdentifierNode identifier, | |
| 97 List<FormalNode> formals, | |
| 98 Token begin) | |
| 99 : super(type, identifier, formals) { | |
| 100 this.begin = begin; | |
| 101 tag = ErrorTag.badFunction; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 class UnionErrorNode extends UnionNode with ErrorNode { | |
| 106 UnionErrorNode(List<FieldNode> fields, Token begin) | |
| 107 : super(fields) { | |
| 108 this.begin = begin; | |
| 109 tag = ErrorTag.badUnion; | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 class FieldErrorNode extends FieldNode with ErrorNode { | |
| 114 FieldErrorNode(TypeNode type, IdentifierNode identifier, Token begin) | |
| 115 : super(type, identifier) { | |
| 116 this.begin = begin; | |
| 117 tag = ErrorTag.badField; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 class FormalErrorNode extends FormalNode with ErrorNode { | |
| 122 FormalErrorNode(TypeNode type, IdentifierNode identifier, Token begin) | |
| 123 : super(type, identifier) { | |
| 124 this.begin = begin; | |
| 125 tag = ErrorTag.badFormal; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 class ListTypeError extends ListType with ErrorNode { | |
| 130 ListTypeError(IdentifierNode identifier, TypeNode typeParameter, Token begin) | |
| 131 : super(identifier, typeParameter) { | |
| 132 this.begin = begin; | |
| 133 tag = ErrorTag.badListType; | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 class ErrorNode { | |
| 138 Token begin; | |
| 139 ErrorTag tag; | |
| 140 } | |
| 141 | |
| 142 class InternalCompilerError extends Error { | |
| 143 String message; | |
| 144 InternalCompilerError(this.message); | |
| 145 | |
| 146 String toString() => "InternalCompilerError: $message"; | |
| 147 } | |
| 148 | |
| 149 // Error reporter. | |
| 150 class ErrorReporter { | |
| 151 String absolutePath; | |
| 152 String relativePath; | |
| 153 String fileContents; | |
| 154 | |
| 155 List<int> lineStarts; | |
| 156 | |
| 157 ErrorReporter(this.absolutePath, this.relativePath) { | |
| 158 fileContents = new File(absolutePath).readAsStringSync(); | |
| 159 | |
| 160 lineStarts = <int>[-1]; | |
| 161 | |
| 162 for (int i = 0; i < fileContents.length; ++i) { | |
| 163 if ($LF == fileContents.codeUnitAt(i)) { | |
| 164 lineStarts.add(i); | |
| 165 } | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 void report(List<CompilationError> errors) { | |
| 170 print("Number of errors: ${errors.length}"); | |
| 171 for (CompilationError error in errors) { | |
| 172 error.report(this); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 void _reportMessage(String message, Token token, String type) { | |
| 177 if (null != token) { | |
| 178 int lineNumber = getLineNumber(token); | |
| 179 int lineOffset = getLineOffset(token, lineNumber); | |
| 180 print("$relativePath:$lineNumber:$lineOffset: $type: $message"); | |
| 181 int end = lineNumber < lineStarts.length ? lineStarts[lineNumber] | |
| 182 : fileContents.length; | |
| 183 print(fileContents.substring(lineStarts[lineNumber - 1] + 1, end)); | |
| 184 print(" " * (lineOffset - 1) + "^"); | |
| 185 } else { | |
| 186 print("$relativePath: $type: $message"); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 void reportError(String message, [Token token]) { | |
| 191 _reportMessage(message, token, "error"); | |
| 192 } | |
| 193 | |
| 194 void reportWarning(String message, [Token token]) { | |
| 195 _reportMessage(message, token, "warning"); | |
| 196 } | |
| 197 | |
| 198 void reportInfo(String message, [Token token]) { | |
| 199 _reportMessage(message, token, "info"); | |
| 200 } | |
| 201 | |
| 202 int getLineNumber(Token token) { | |
| 203 for (int i = 1; i < lineStarts.length; ++i) { | |
| 204 if (lineStarts[i] >= token.charOffset) { | |
| 205 return i; | |
| 206 } | |
| 207 } | |
| 208 return lineStarts.length; | |
| 209 } | |
| 210 | |
| 211 int getLineOffset(Token token, int currentLine) { | |
| 212 return token.charOffset - lineStarts[currentLine - 1]; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 // Compilation errors. | |
| 217 abstract class CompilationError { | |
| 218 ErrorTag get tag; | |
| 219 void report(ErrorReporter reporter); | |
| 220 } | |
| 221 | |
| 222 class UndefinedServiceError extends CompilationError { | |
| 223 ErrorTag get tag => ErrorTag.undefinedService; | |
| 224 void report(ErrorReporter reporter) { | |
| 225 reporter.reportError("There should be at least one service per " + | |
| 226 "compilation unit."); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 class SyntaxError extends CompilationError { | |
| 231 ErrorNode node; | |
| 232 ErrorTag get tag => node.tag; | |
| 233 | |
| 234 SyntaxError(this.node); | |
| 235 | |
| 236 Map<ErrorTag, String> errorMessages = { | |
| 237 ErrorTag.badField: "Unfinished field declaration.", | |
| 238 ErrorTag.badFormal: "Unfinished formal argument declaration.", | |
| 239 ErrorTag.badFunction: "Unfinished function declaration.", | |
| 240 ErrorTag.badListType: "Unexpected token while parsing type parameter.", | |
| 241 ErrorTag.badServiceDefinition: "Unfinished service definition.", | |
| 242 ErrorTag.badStructDefinition: "Unfinished struct definition.", | |
| 243 ErrorTag.badTopLevel: "Unexpected token while parsing top-level " + | |
| 244 "definition." | |
| 245 }; | |
| 246 | |
| 247 Map<ErrorTag, String> infoMessages = { | |
| 248 ErrorTag.badField: null, | |
| 249 ErrorTag.badFormal: null, | |
| 250 ErrorTag.badFunction: null, | |
| 251 ErrorTag.badListType: "Expected a primitive type, a string, or a " + | |
| 252 "structure as the List type parameter", | |
| 253 ErrorTag.badServiceDefinition: null, | |
| 254 ErrorTag.badStructDefinition: null, | |
| 255 ErrorTag.badTopLevel: "Top-level defintions start with `service` or " + | |
| 256 "`struct`." | |
| 257 }; | |
| 258 | |
| 259 void report(ErrorReporter reporter) { | |
| 260 reporter.reportError(errorMessages[node.tag], node.begin); | |
| 261 if (null != infoMessages[node.tag]) { | |
| 262 reporter.reportInfo(infoMessages[node.tag], node.begin); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 } | |
| 267 | |
| 268 class CyclicStructError extends CompilationError { | |
| 269 Iterable<StructNode> chain; | |
| 270 ErrorTag get tag => ErrorTag.cyclicStruct; | |
| 271 | |
| 272 CyclicStructError(this.chain); | |
| 273 | |
| 274 void report(ErrorReporter reporter) { | |
| 275 String message; | |
| 276 StructNode struct = chain.first; | |
| 277 if (chain.length == 1) { | |
| 278 message = "Struct ${struct.identifier.value} references itself."; | |
| 279 } else { | |
| 280 message = "Struct ${struct.identifier.value} has a cyclic reference;"; | |
| 281 } | |
| 282 reporter.reportError(message, struct.identifier.token); | |
| 283 for (StructNode struct in chain) { | |
| 284 if (struct == chain.first) continue; | |
| 285 message = "references ${struct.identifier.value}"; | |
| 286 if (struct == chain.last) { | |
| 287 message += "."; | |
| 288 } else { | |
| 289 message += " which in turn"; | |
| 290 } | |
| 291 reporter.reportInfo(message, struct.identifier.token); | |
| 292 } | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 class MultipleUnionsError extends CompilationError { | |
| 297 StructNode struct; | |
| 298 ErrorTag get tag => ErrorTag.multipleUnions; | |
| 299 | |
| 300 MultipleUnionsError(this.struct); | |
| 301 | |
| 302 void report(ErrorReporter reporter) { | |
| 303 reporter.reportError( | |
| 304 "Struct ${struct.identifier.value} contains multiple unions.", | |
| 305 struct.identifier.token); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 class NotPrimitiveFormalError extends CompilationError { | |
| 310 FormalNode formal; | |
| 311 ErrorTag get tag => ErrorTag.expectedPrimitiveFormal; | |
| 312 | |
| 313 NotPrimitiveFormalError(this.formal); | |
| 314 | |
| 315 void report(ErrorReporter reporter) { | |
| 316 reporter.reportError( | |
| 317 "Unexpected type of formal argument '${formal.identifier.value}'.", | |
| 318 formal.type.identifier.token); | |
| 319 reporter.reportInfo( | |
| 320 "All formal arguments should have primitive types when the function " + | |
| 321 "has more than one formal argument.", | |
| 322 formal.type.identifier.token); | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 class MultipleDefinitionsError extends CompilationError { | |
| 327 IdentifierNode original; | |
| 328 IdentifierNode redefined; | |
| 329 ErrorTag get tag => ErrorTag.multipleDefinitions; | |
| 330 | |
| 331 MultipleDefinitionsError(this.original, this.redefined); | |
| 332 | |
| 333 void report(ErrorReporter reporter) { | |
| 334 reporter.reportError("Redefined symbol ${redefined.value};", | |
| 335 redefined.token); | |
| 336 reporter.reportInfo("Original definition found here.", original.token); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 class ServiceStructNameClashError extends CompilationError { | |
| 341 IdentifierNode original; | |
| 342 IdentifierNode redefined; | |
| 343 ErrorTag get tag => ErrorTag.serviceStructNameClash; | |
| 344 | |
| 345 ServiceStructNameClashError(this.original, this.redefined); | |
| 346 | |
| 347 void report(ErrorReporter reporter) { | |
| 348 reporter.reportError("Identifier ${redefined.value} used both as a " + | |
| 349 "service name and as a struct name;", | |
| 350 redefined.token); | |
| 351 reporter.reportInfo("Original definition found here.", original.token); | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 abstract class BadTypeError extends CompilationError { | |
| 356 TypeNode type; | |
| 357 String get errorMessage; | |
| 358 String get infoMessage; | |
| 359 | |
| 360 BadTypeError(this.type); | |
| 361 | |
| 362 void report(ErrorReporter reporter) { | |
| 363 reporter.reportError(errorMessage, type.identifier.token); | |
| 364 reporter.reportInfo(infoMessage, type.identifier.token); | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 class BadReturnTypeError extends BadTypeError { | |
| 369 ErrorTag get tag => ErrorTag.badReturnType; | |
| 370 String get errorMessage => "Unexpected return type."; | |
| 371 String get infoMessage => "Expected a pointer type or a primitive type as " + | |
| 372 "the return type of a function."; | |
| 373 | |
| 374 BadReturnTypeError(TypeNode type) | |
| 375 : super(type); | |
| 376 } | |
| 377 | |
| 378 class BadSingleFormalError extends BadTypeError { | |
| 379 ErrorTag get tag => ErrorTag.badSingleFormal; | |
| 380 String get errorMessage => "Unexpected type of formal argument."; | |
| 381 String get infoMessage => "Expected a primitive type or a pointer type for " + | |
| 382 "a function with just one formal argument."; | |
| 383 | |
| 384 BadSingleFormalError(TypeNode type) | |
| 385 : super(type); | |
| 386 } | |
| 387 | |
| 388 class BadFieldTypeError extends BadTypeError { | |
| 389 ErrorTag get tag => ErrorTag.badFieldType; | |
| 390 String get errorMessage => "Unexpected field type."; | |
| 391 String get infoMessage => | |
| 392 "A field type should be one of the following:\n" + | |
| 393 " * a primitive type, e.g. int32;\n" + | |
| 394 " * a String;\n" + | |
| 395 " * a struct type, e.g. Foo.\n" + | |
| 396 " * a pointer to a struct, e.g. Foo*;\n" + | |
| 397 " * a list of structs, e.g. List<Foo>."; | |
| 398 | |
| 399 BadFieldTypeError(TypeNode type) | |
| 400 : super(type); | |
| 401 } | |
| 402 | |
| 403 class BadPointerTypeError extends BadTypeError { | |
| 404 ErrorTag get tag => ErrorTag.badPointerType; | |
| 405 String get errorMessage => "Undefined struct '${type.identifier.value}'."; | |
| 406 String get infoMessage => "Expected a pointer to a known struct type."; | |
| 407 | |
| 408 BadPointerTypeError(TypeNode type) | |
| 409 : super(type); | |
| 410 } | |
| 411 | |
| 412 class BadListTypeError extends BadTypeError { | |
| 413 ErrorTag get tag => ErrorTag.badListType; | |
| 414 String get errorMessage => | |
| 415 "Unexpected generic type '${type.identifier.value}'."; | |
| 416 String get infoMessage => "'List' is the only supported generic type."; | |
| 417 | |
| 418 BadListTypeError(TypeNode type) | |
| 419 : super(type); | |
| 420 } | |
| 421 | |
| 422 class BadTypeParameterError extends BadTypeError { | |
| 423 ErrorTag get tag => ErrorTag.badTypeParameter; | |
| 424 String get errorMessage => "Unexpected type parameter."; | |
| 425 String get infoMessage => "Expected a primitive type or a structure as " + | |
| 426 "the List type parameter."; | |
| 427 | |
| 428 BadTypeParameterError(TypeNode type) | |
| 429 : super(type); | |
| 430 } | |
| OLD | NEW |