OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dart 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 import 'package:analyzer/dart/element/element.dart' | |
6 show CompilationUnitElement, LibraryElement; | |
7 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | |
8 import 'package:path/path.dart' as path; | |
9 | |
10 import '../compiler.dart' show AbstractCompiler; | |
11 import '../info.dart'; | |
12 import '../utils.dart' show canonicalLibraryName; | |
13 import '../options.dart' show CodegenOptions; | |
14 | |
15 abstract class CodeGenerator { | |
16 final AbstractCompiler compiler; | |
17 final AnalysisContext context; | |
18 final CodegenOptions options; | |
19 | |
20 CodeGenerator(AbstractCompiler compiler) | |
21 : compiler = compiler, | |
22 context = compiler.context, | |
23 options = compiler.options.codegenOptions; | |
24 | |
25 /// Return a hash, if any, that can be used for caching purposes. When two | |
26 /// invocations to this function return the same hash, the underlying | |
27 /// code-generator generated the same code. | |
28 String generateLibrary(LibraryUnit unit); | |
29 | |
30 static List<String> _searchPaths = () { | |
31 // TODO(vsm): Can we remove redundancy with multi_package_resolver logic? | |
32 var packagePaths = | |
33 new String.fromEnvironment('package_paths', defaultValue: null); | |
34 if (packagePaths == null) return null; | |
35 var list = packagePaths.split(','); | |
36 // Normalize the paths. | |
37 list = new List<String>.from(list.map(_dirToPrefix)); | |
38 // The current directory is implicitly in the search path. | |
39 list.add(_dirToPrefix(path.current)); | |
40 // Sort by reverse length to prefer longer prefixes. | |
41 // This ensures that we get the minimum valid suffix. E.g., if we have: | |
42 // - root/ | |
43 // - root/generated/ | |
44 // in our search path, and the path "root/generated/foo/bar.dart", we'll | |
45 // compute "foo/bar.dart" instead of "generated/foo/bar.dart" in the search | |
46 // below. | |
47 list.sort((s1, s2) => s2.length - s1.length); | |
48 return list; | |
49 }() as List<String>; | |
50 | |
51 static String _dirToPrefix(String dir) { | |
52 dir = path.absolute(dir); | |
53 dir = path.normalize(dir); | |
54 if (!dir.endsWith(path.separator)) { | |
55 dir = dir + path.separator; | |
56 } | |
57 return dir; | |
58 } | |
59 | |
60 static String _convertIfPackage(String dir) { | |
61 assert(path.isRelative(dir)); | |
62 var parts = path.split(dir); | |
63 var index = parts.indexOf('lib'); | |
64 if (index < 0) { | |
65 // Not a package. | |
66 return dir; | |
67 } | |
68 // This is a package. | |
69 // Convert: foo/bar/lib/baz/hi | |
70 // to: packages/foo.bar/baz/hi | |
71 var packageName = parts.sublist(0, index).join('.'); | |
72 var prefix = path.join('packages', packageName); | |
73 var suffix = path.joinAll(parts.sublist(index + 1)); | |
74 return path.join(prefix, suffix); | |
75 } | |
76 | |
77 static String _getOutputDirectory( | |
78 String name, CompilationUnitElement unitElement) { | |
79 var uri = unitElement.source.uri.toString(); | |
80 String suffix; | |
81 if (uri.startsWith('dart:') || _searchPaths == null) { | |
82 // Use the library name as the directory. | |
83 suffix = name; | |
84 } else if (uri.startsWith('package:')) { | |
85 suffix = uri.replaceFirst('package:', 'packages/'); | |
86 suffix = path.dirname(suffix); | |
87 } else { | |
88 // Recover the original search path and use the relative path | |
89 // from there as the directory. | |
90 // TODO(vsm): Is there a better way to get the resolved path? | |
91 var resolvedPath = unitElement.toString(); | |
92 var resolvedDir = path.dirname(resolvedPath); | |
93 for (var prefix in _searchPaths) { | |
94 if (resolvedDir.startsWith(prefix)) { | |
95 suffix = resolvedDir.substring(prefix.length); | |
96 break; | |
97 } | |
98 } | |
99 } | |
100 assert(suffix != null); | |
101 assert(path.isRelative(suffix)); | |
102 return _convertIfPackage(suffix); | |
103 } | |
104 | |
105 static Uri uriFor(LibraryElement lib) { | |
106 var unitElement = lib.definingCompilationUnit; | |
107 var uri = unitElement.source.uri; | |
108 if (uri.scheme == 'dart') return uri; | |
109 if (uri.scheme == 'package') return uri; | |
110 var suffix = _getOutputDirectory(canonicalLibraryName(lib), unitElement); | |
111 suffix = path.join(suffix, uri.pathSegments.last); | |
112 var parts = path.split(suffix); | |
113 var index = parts.indexOf('packages'); | |
114 if (index < 0) { | |
115 // Not a package. | |
116 // TODO(leafp) These may need to be adjusted | |
117 // relative to the import location | |
118 return new Uri(path: suffix); | |
119 } | |
120 assert(index == 0); | |
121 return new Uri( | |
122 scheme: 'package', path: path.joinAll(parts.sublist(index + 1))); | |
123 } | |
124 } | |
OLD | NEW |