| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class LibraryImport { | 5 class LibraryImport { |
| 6 String prefix; | 6 String prefix; |
| 7 Library library; | 7 Library library; |
| 8 LibraryImport(this.library, [this.prefix = null]); | 8 LibraryImport(this.library, [this.prefix = null]); |
| 9 } | 9 } |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 if (filename.startsWith('dart:')) return filename; | 56 if (filename.startsWith('dart:')) return filename; |
| 57 // TODO(jmesserly): replace with node.js path.resolve | 57 // TODO(jmesserly): replace with node.js path.resolve |
| 58 if (filename.startsWith('/')) return filename; | 58 if (filename.startsWith('/')) return filename; |
| 59 if (filename.startsWith('file:///')) return filename; | 59 if (filename.startsWith('file:///')) return filename; |
| 60 if (filename.startsWith('http://')) return filename; | 60 if (filename.startsWith('http://')) return filename; |
| 61 return joinPaths(sourceDir, filename); | 61 return joinPaths(sourceDir, filename); |
| 62 } | 62 } |
| 63 | 63 |
| 64 /** Adds an import to the library. */ | 64 /** Adds an import to the library. */ |
| 65 addImport(String fullname, String prefix) { | 65 addImport(String fullname, String prefix) { |
| 66 // TODO(jimhug): Check for duplicates. | 66 var newLib = world.getOrAddLibrary(fullname); |
| 67 imports.add(new LibraryImport(world.getOrAddLibrary(fullname), prefix)); | 67 imports.add(new LibraryImport(newLib, prefix)); |
| 68 return newLib; |
| 68 } | 69 } |
| 69 | 70 |
| 70 addNative(String fullname) { | 71 addNative(String fullname) { |
| 71 natives.add(world.reader.readFile(fullname)); | 72 natives.add(world.reader.readFile(fullname)); |
| 72 } | 73 } |
| 73 | 74 |
| 74 MemberSet _findMembers(String name) { | 75 MemberSet _findMembers(String name) { |
| 75 if (name.startsWith('_')) { | 76 if (name.startsWith('_')) { |
| 76 return _privateMembers[name]; | 77 return _privateMembers[name]; |
| 77 } else { | 78 } else { |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 index = name.indexOf('.', 0); | 236 index = name.indexOf('.', 0); |
| 236 if (index > 0) { | 237 if (index > 0) { |
| 237 name = name.substring(0, index); | 238 name = name.substring(0, index); |
| 238 } | 239 } |
| 239 } | 240 } |
| 240 for (var type in types.getValues()) { | 241 for (var type in types.getValues()) { |
| 241 type.resolve(); | 242 type.resolve(); |
| 242 } | 243 } |
| 243 } | 244 } |
| 244 | 245 |
| 246 visitSources() { |
| 247 var visitor = new _LibraryVisitor(this); |
| 248 visitor.addSource(baseSource); |
| 249 } |
| 250 |
| 245 toString() => baseSource.filename; | 251 toString() => baseSource.filename; |
| 246 } | 252 } |
| 247 | 253 |
| 248 | 254 |
| 249 class LibraryVisitor implements TreeVisitor { | 255 class _LibraryVisitor implements TreeVisitor { |
| 250 final Library library; | 256 final Library library; |
| 251 Type currentType; | 257 Type currentType; |
| 252 List<SourceFile> sources; | 258 List<SourceFile> sources; |
| 253 | 259 |
| 254 LibraryVisitor(this.library) { | 260 bool seenImport = false; |
| 261 bool seenSource = false; |
| 262 bool seenResource = false; |
| 263 bool isTop = true; |
| 264 |
| 265 _LibraryVisitor(this.library) { |
| 255 currentType = library.topType; | 266 currentType = library.topType; |
| 256 sources = []; | 267 sources = []; |
| 257 addSource(library.baseSource); | |
| 258 } | 268 } |
| 259 | 269 |
| 260 addSourceFromName(String name) { | 270 addSourceFromName(String name, SourceSpan span) { |
| 271 var filename = library.makeFullPath(name); |
| 272 if (filename == library.baseSource.filename) { |
| 273 world.error('library can not source itself', span); |
| 274 return; |
| 275 } else if (sources.some((s) => s.filename == filename)) { |
| 276 world.error('file "$filename" has already been sourced', span); |
| 277 return; |
| 278 } |
| 279 |
| 261 var source = world.readFile(library.makeFullPath(name)); | 280 var source = world.readFile(library.makeFullPath(name)); |
| 262 sources.add(source); | 281 sources.add(source); |
| 263 } | 282 } |
| 264 | 283 |
| 265 addSource(SourceFile source) { | 284 addSource(SourceFile source) { |
| 285 if (library.sources.some((s) => s.filename == source.filename)) { |
| 286 // TODO(jimhug): good error location. |
| 287 world.error('duplicate source file "${source.filename}"', null); |
| 288 return; |
| 289 } |
| 266 library.sources.add(source); | 290 library.sources.add(source); |
| 267 final parser = new Parser(source, /*diet:*/options.dietParse); | 291 final parser = new Parser(source, /*diet:*/options.dietParse); |
| 268 final unit = parser.compilationUnit(); | 292 final unit = parser.compilationUnit(); |
| 269 | 293 |
| 270 for (final def in unit) { | 294 unit.forEach((def) => def.visit(this)); |
| 271 def.visit(this); | |
| 272 } | |
| 273 | 295 |
| 274 // TODO(jimhug): Enforce restrictions on source and import directives. | 296 assert(sources.length == 0 || isTop); |
| 297 isTop = false; |
| 275 var newSources = sources; | 298 var newSources = sources; |
| 276 sources = []; | 299 sources = []; |
| 277 for (var source in newSources) { | 300 for (var source in newSources) { |
| 278 addSource(source); | 301 addSource(source); |
| 279 } | 302 } |
| 280 } | 303 } |
| 281 | 304 |
| 282 void visitDirectiveDefinition(DirectiveDefinition node) { | 305 void visitDirectiveDefinition(DirectiveDefinition node) { |
| 306 if (!isTop) { |
| 307 world.error('directives not allowed in sourced file', node.span); |
| 308 return; |
| 309 } |
| 310 |
| 283 var name; | 311 var name; |
| 284 switch (node.name.name) { | 312 switch (node.name.name) { |
| 285 case "library": | 313 case "library": |
| 286 name = getSingleStringArg(node); | 314 name = getSingleStringArg(node); |
| 287 if (library.name == null) { | 315 if (library.name == null) { |
| 288 library.name = name; | 316 library.name = name; |
| 289 // TODO(jimhug): Hack to get native fields for io and dom - generalize
. | 317 // TODO(jimhug): Hack to get native fields for io and dom - generalize
. |
| 290 if (name == 'node' || name == 'dom') { | 318 if (name == 'node' || name == 'dom') { |
| 291 library.topType.isNativeType = true; | 319 library.topType.isNativeType = true; |
| 292 } | 320 } |
| 321 if (seenImport || seenSource || seenResource) { |
| 322 world.error('#library must be first directive in file', node.span); |
| 323 } |
| 293 } else { | 324 } else { |
| 294 world.error('already specified library name', node.span); | 325 world.error('already specified library name', node.span); |
| 295 } | 326 } |
| 296 break; | 327 break; |
| 297 | 328 |
| 298 case "import": | 329 case "import": |
| 330 seenImport = true; |
| 299 name = getFirstStringArg(node); | 331 name = getFirstStringArg(node); |
| 300 var prefix = tryGetNamedStringArg(node, 'prefix'); | 332 var prefix = tryGetNamedStringArg(node, 'prefix'); |
| 301 if (node.arguments.length > 2 || | 333 if (node.arguments.length > 2 || |
| 302 node.arguments.length == 2 && prefix == null) { | 334 node.arguments.length == 2 && prefix == null) { |
| 303 world.error( | 335 world.error( |
| 304 'expected at most one "name" argument and one optional "prefix"' | 336 'expected at most one "name" argument and one optional "prefix"' |
| 305 + ' but found ${node.arguments.length}', node.span); | 337 + ' but found ${node.arguments.length}', node.span); |
| 306 } else if (prefix != null && prefix.indexOf('.', 0) >= 0) { | 338 } else if (prefix != null && prefix.indexOf('.', 0) >= 0) { |
| 307 world.error('library prefix canot contain "."', node.span); | 339 world.error('library prefix canot contain "."', node.span); |
| 340 } else if (seenSource || seenResource) { |
| 341 world.error('#imports must come before any #source or #resource', |
| 342 node.span); |
| 308 } | 343 } |
| 309 | 344 |
| 310 // Empty prefix and no prefix are equivalent | 345 // Empty prefix and no prefix are equivalent |
| 311 if (prefix == '') prefix = null; | 346 if (prefix == '') prefix = null; |
| 312 | 347 |
| 313 library.addImport(library.makeFullPath(name), prefix); | 348 var filename = library.makeFullPath(name); |
| 349 |
| 350 if (library.imports.some((li) => li.library.baseSource == filename)) { |
| 351 // TODO(jimhug): Can you import a lib twice with different prefixes? |
| 352 world.error('duplicate import of "$name"', node.span); |
| 353 return; |
| 354 } |
| 355 |
| 356 var newLib = library.addImport(filename, prefix); |
| 357 if (newLib.name == null && !filename.startsWith('dart:')) { |
| 358 world.info('imported library "$name" has no #library directive', |
| 359 node.span); |
| 360 } |
| 314 break; | 361 break; |
| 315 | 362 |
| 316 case "source": | 363 case "source": |
| 364 seenSource = true; |
| 317 name = getSingleStringArg(node); | 365 name = getSingleStringArg(node); |
| 318 addSourceFromName(name); | 366 addSourceFromName(name, node.span); |
| 367 if (seenResource) { |
| 368 world.error('#sources must come before any #resource', node.span); |
| 369 } |
| 319 break; | 370 break; |
| 320 | 371 |
| 321 case "native": | 372 case "native": |
| 373 // TODO(jimhug): Fit this into spec? |
| 322 name = getSingleStringArg(node); | 374 name = getSingleStringArg(node); |
| 323 library.addNative(library.makeFullPath(name)); | 375 library.addNative(library.makeFullPath(name)); |
| 324 break; | 376 break; |
| 325 | 377 |
| 326 case "resource": | 378 case "resource": |
| 327 // TODO(jmesserly): should we do anything else here? | 379 // TODO(jmesserly): should we do anything else here? |
| 380 seenResource = true; |
| 328 getFirstStringArg(node); | 381 getFirstStringArg(node); |
| 329 break; | 382 break; |
| 330 | 383 |
| 331 default: | 384 default: |
| 332 world.error('unknown directive: ${node.name.name}', node.span); | 385 world.error('unknown directive: ${node.name.name}', node.span); |
| 333 } | 386 } |
| 334 } | 387 } |
| 335 | 388 |
| 336 String getSingleStringArg(DirectiveDefinition node) { | 389 String getSingleStringArg(DirectiveDefinition node) { |
| 337 if (node.arguments.length != 1) { | 390 if (node.arguments.length != 1) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 | 449 |
| 397 void visitFunctionDefinition(FunctionDefinition node) { | 450 void visitFunctionDefinition(FunctionDefinition node) { |
| 398 currentType.addMethod(node.name.name, node); | 451 currentType.addMethod(node.name.name, node); |
| 399 } | 452 } |
| 400 | 453 |
| 401 void visitFunctionTypeDefinition(FunctionTypeDefinition node) { | 454 void visitFunctionTypeDefinition(FunctionTypeDefinition node) { |
| 402 var type = library.addType(node.func.name.name, node, false); | 455 var type = library.addType(node.func.name.name, node, false); |
| 403 type.addMethod('\$call', node.func); | 456 type.addMethod('\$call', node.func); |
| 404 } | 457 } |
| 405 } | 458 } |
| OLD | NEW |