OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, 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 part of mirror_renamer; | |
6 | |
7 class MirrorRenamerImpl implements MirrorRenamer { | |
8 static const String MIRROR_HELPER_GET_NAME_FUNCTION = 'helperGetName'; | |
9 static final Uri DART_MIRROR_HELPER = | |
10 new Uri(scheme: 'dart', path: '_mirror_helper'); | |
11 static const String MIRROR_HELPER_SYMBOLS_MAP_NAME = '_SYMBOLS'; | |
12 | |
13 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary | |
14 /// field is set. | |
15 final LibraryElement helperLibrary; | |
16 | |
17 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary | |
18 /// field is set. | |
19 final FunctionElement getNameFunction; | |
20 | |
21 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary | |
22 /// field is set. | |
23 final FieldElement symbolsMapVariable; | |
24 | |
25 /// Maps mangled name to original name. | |
26 Map<String, String> symbols = new Map<String, String>(); | |
27 | |
28 /// Contains all occurrencs of MirrorSystem.getName() calls in the user code. | |
29 List<Node> mirrorSystemGetNameNodes = <Node>[]; | |
30 | |
31 /** | |
32 * Initialized when the placeholderCollector collects the FunctionElement | |
33 * backend.mirrorHelperGetNameFunction which represents the helperGetName | |
34 * function in _mirror_helper. | |
35 */ | |
36 FunctionExpression get getNameFunctionNode => getNameFunction.node; | |
37 VariableDefinitions get symbolsMapNode => symbolsMapVariable.node; | |
38 Compiler compiler; | |
39 DartBackend backend; | |
40 | |
41 MirrorRenamerImpl(this.compiler, this.backend, LibraryElement library) | |
42 : this.helperLibrary = library, | |
43 getNameFunction = library.find( | |
44 MirrorRenamerImpl.MIRROR_HELPER_GET_NAME_FUNCTION), | |
45 symbolsMapVariable = library.find( | |
46 MirrorRenamerImpl.MIRROR_HELPER_SYMBOLS_MAP_NAME); | |
47 | |
48 bool isMirrorHelperLibrary(LibraryElement element) { | |
49 return element == helperLibrary; | |
50 } | |
51 | |
52 void registerStaticSend(Element currentElement, Element target, Send node) { | |
53 if (target == compiler.mirrorSystemGetNameFunction && | |
54 currentElement.library != helperLibrary) { | |
55 // Access to `MirrorSystem.getName` that needs to be redirected to the | |
56 // [getNameFunction]. | |
57 mirrorSystemGetNameNodes.add(node); | |
58 } | |
59 } | |
60 | |
61 /** | |
62 * Adds a toplevel node to the output containing a map from the mangled | |
63 * to the unmangled names and replaces calls to MirrorSystem.getName() | |
64 * with calls to the corresponding wrapper from _mirror_helper which has | |
65 * been added during resolution. [renames] is assumed to map nodes in user | |
66 * code to mangled names appearing in output code, and [topLevelNodes] should | |
67 * contain all the toplevel ast nodes that will be emitted in the output. | |
68 */ | |
69 void addRenames(Map<Node, String> renames, List<Node> topLevelNodes, | |
70 PlaceholderCollector placeholderCollector) { | |
71 // Right now we only support instances of MirrorSystem.getName, | |
72 // hence if there are no occurence of these we don't do anything. | |
73 if (mirrorSystemGetNameNodes.isEmpty) { | |
74 return; | |
75 } | |
76 | |
77 Node parse(String text) { | |
78 Token tokens = compiler.scanner.tokenize(text); | |
79 return compiler.parser.parseCompilationUnit(tokens); | |
80 } | |
81 | |
82 // Add toplevel map containing all renames of members. | |
83 symbols = new Map<String, String>(); | |
84 for (Set<Identifier> s in placeholderCollector.memberPlaceholders.values) { | |
85 // All members in a set have the same name so we only need to look at one. | |
86 Identifier sampleNode = s.first; | |
87 symbols.putIfAbsent(renames[sampleNode], () => sampleNode.source); | |
88 } | |
89 | |
90 Identifier symbolsMapIdentifier = | |
91 symbolsMapNode.definitions.nodes.head.asSend().selector; | |
92 assert(symbolsMapIdentifier != null); | |
93 topLevelNodes.remove(symbolsMapNode); | |
94 | |
95 StringBuffer sb = new StringBuffer( | |
96 'const ${renames[symbolsMapIdentifier]} = const<String,String>{'); | |
97 bool first = true; | |
98 for (String mangledName in symbols.keys) { | |
99 if (!first) { | |
100 sb.write(','); | |
101 } else { | |
102 first = false; | |
103 } | |
104 sb.write("'$mangledName' : '"); | |
105 sb.write(symbols[mangledName]); | |
106 sb.write("'"); | |
107 } | |
108 sb.write('};'); | |
109 sb.writeCharCode(0); // Terminate the string with '0', see [StringScanner]. | |
110 topLevelNodes.add(parse(sb.toString())); | |
111 | |
112 // Replace calls to Mirrorsystem.getName with calls to helper function. | |
113 mirrorSystemGetNameNodes.forEach((node) { | |
114 renames[node.selector] = renames[getNameFunctionNode.name]; | |
115 renames[node.receiver] = ''; | |
116 }); | |
117 } | |
118 } | |
OLD | NEW |