Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 import 'package:analyzer/src/summary/idl.dart'; | |
| 2 import 'package:front_end/src/base/library_info.dart'; | |
| 3 | |
| 4 /// Decodes the contents of the SDK's "libraries.dart" file. | |
| 5 /// | |
| 6 /// Caller should pass in the unlinked summary of the libraries.dart file. This | |
| 7 /// function will materialize the "libraries" constant based on information in | |
| 8 /// the summary. | |
| 9 /// | |
| 10 /// Note that this code is not intended to be fully general; it makes some | |
| 11 /// assumptions about the structure of the "libraries.dart" file (such as what | |
| 12 /// declarations are expected to be present in it, and the types of those | |
| 13 /// declarations). | |
| 14 Map<String, LibraryInfo> readLibraries(UnlinkedUnit librariesUnit) { | |
|
Siggi Cherem (dart-lang)
2016/12/14 20:48:43
cool to see that we can use summaries for this - b
Paul Berry
2016/12/14 23:17:25
That's wonderful to hear (see my other comment)!
| |
| 15 var constContext = new _ConstContext(librariesUnit.references); | |
| 16 for (var variable in librariesUnit.variables) { | |
| 17 if (!variable.isConst) continue; | |
| 18 constContext.topLevelConstants[variable.name] = | |
| 19 new _ConstVariable(variable.initializer.bodyExpr, constContext); | |
| 20 } | |
| 21 for (var cls in librariesUnit.classes) { | |
| 22 if (cls.name == 'Maturity') { | |
| 23 for (var field in cls.fields) { | |
| 24 if (!field.isConst) continue; | |
| 25 constContext.maturityConstants[field.name] = | |
| 26 new _ConstVariable(field.initializer.bodyExpr, constContext); | |
| 27 } | |
| 28 } | |
| 29 } | |
| 30 return constContext.topLevelConstants['libraries'].value; | |
| 31 } | |
| 32 | |
| 33 /// Function type used to invoke a constructor based on dynamic information. | |
| 34 /// | |
| 35 /// Caller supplies two callbacks ([positional] and [named]) which can be used | |
| 36 /// to query the arguments passed to the constructor. These callbacks will | |
| 37 /// return the requested argument if it was provided; otherwise they will return | |
| 38 /// the supplied default value. | |
| 39 typedef dynamic _Constructor(dynamic positional(int i, [dynamic defaultValue]), | |
| 40 dynamic named(String name, [dynamic defaultValue])); | |
| 41 | |
| 42 /// Contextual information used to evaluate constants in the "libraries.dart" | |
| 43 /// file. | |
| 44 class _ConstContext { | |
| 45 /// Top level constants in the "libraries.dart" file. | |
| 46 final topLevelConstants = <String, _ConstVariable>{}; | |
| 47 | |
| 48 /// Static constants in "libraries.dart"'s "Maturity" class. | |
| 49 final maturityConstants = <String, _ConstVariable>{}; | |
| 50 | |
| 51 /// References from the unlinked summary of the "libraries.dart" file. | |
| 52 final List<UnlinkedReference> references; | |
| 53 | |
| 54 _ConstContext(this.references); | |
| 55 } | |
| 56 | |
| 57 /// Information necessary to evaluate a single constant from the | |
| 58 /// "libraries.dart" file. | |
| 59 class _ConstVariable { | |
| 60 /// The constant expression from the unlinked summary. | |
| 61 final UnlinkedExpr expr; | |
| 62 | |
| 63 /// Contextual information necessary to evaluate the constant. | |
| 64 final _ConstContext context; | |
| 65 | |
| 66 /// The evaluated value. | |
| 67 dynamic _value; | |
| 68 | |
| 69 /// Indicates whether the value has been evaluated yet. | |
| 70 bool isMaterialized = false; | |
|
Siggi Cherem (dart-lang)
2016/12/14 20:48:43
minor nit: do we expect to have `null` values? If
Paul Berry
2016/12/14 23:17:25
Fair enough. Following your suggestion below gets
| |
| 71 | |
| 72 _ConstVariable(this.expr, this.context); | |
| 73 | |
| 74 /// Evaluate the constant (if necessary) and return it. | |
| 75 dynamic get value { | |
|
Siggi Cherem (dart-lang)
2016/12/14 20:48:43
similarly, if `null` is not a valid value, then:
Paul Berry
2016/12/14 23:17:25
Done.
| |
| 76 if (!isMaterialized) _materialize(); | |
| 77 return _value; | |
| 78 } | |
| 79 | |
| 80 /// Find the constructor referred to by [entityRef] and return a function | |
| 81 /// which may be used to invoke it. | |
| 82 _Constructor _findConstructor(EntityRef entityRef) { | |
| 83 // This method is not fully general; we only support the constructor | |
| 84 // invocations that we expect to find in LibraryInfo. | |
| 85 assert(entityRef.implicitFunctionTypeIndices.isEmpty); | |
| 86 assert(entityRef.paramReference == 0); | |
| 87 assert(entityRef.syntheticParams.isEmpty); | |
| 88 assert(entityRef.syntheticReturnType == null); | |
| 89 assert(entityRef.typeArguments.isEmpty); | |
| 90 var reference = context.references[entityRef.reference]; | |
| 91 assert(reference.prefixReference == 0); | |
| 92 switch (reference.name) { | |
| 93 case 'LibraryInfo': | |
| 94 return (dynamic positional(int i, [dynamic defaultValue]), | |
| 95 dynamic named(String name, [dynamic defaultValue])) => | |
| 96 new LibraryInfo(positional(0), | |
| 97 categories: named('categories', ''), | |
| 98 dart2jsPath: named('dart2jsPath'), | |
| 99 dart2jsPatchPath: named('dart2jsPatchPath'), | |
| 100 implementation: named('implementation', false), | |
| 101 documented: named('documented', true), | |
| 102 maturity: named('maturity', Maturity.UNSPECIFIED), | |
| 103 platforms: named('platforms', DART2JS_PLATFORM | VM_PLATFORM)); | |
| 104 case 'Maturity': | |
| 105 return (dynamic positional(int i, [dynamic defaultValue]), | |
| 106 dynamic named(String name, [dynamic defaultValue])) => | |
| 107 new Maturity(positional(0), positional(1), positional(2)); | |
| 108 default: | |
| 109 throw new UnimplementedError( | |
| 110 'Unexpected constructor reference: ${reference.name}'); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 /// Compute the value referred to by [entityRef]. | |
| 115 dynamic _findReference(EntityRef entityRef) { | |
| 116 // This method is not fully general; we only support the references that we | |
| 117 // expect to find in LibraryInfo. | |
| 118 assert(entityRef.implicitFunctionTypeIndices.isEmpty); | |
| 119 assert(entityRef.paramReference == 0); | |
| 120 assert(entityRef.syntheticParams.isEmpty); | |
| 121 assert(entityRef.syntheticReturnType == null); | |
| 122 assert(entityRef.typeArguments.isEmpty); | |
| 123 var reference = context.references[entityRef.reference]; | |
| 124 if (reference.prefixReference == 0) { | |
| 125 return context.topLevelConstants[reference.name].value; | |
| 126 } else { | |
| 127 assert(reference.prefixReference != 0); | |
| 128 var prefixReference = context.references[reference.prefixReference]; | |
| 129 assert(prefixReference.name == 'Maturity'); | |
| 130 assert(prefixReference.prefixReference == 0); | |
| 131 return context.maturityConstants[reference.name].value; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 /// Compute the value of the constant and store it in [_value]. | |
| 136 void _materialize() { | |
| 137 var stack = []; | |
| 138 var stringIndex = 0; | |
| 139 var intIndex = 0; | |
| 140 var referenceIndex = 0; | |
| 141 List popItems(int count) { | |
| 142 var items = stack.sublist(stack.length - count, stack.length); | |
| 143 stack.length -= count; | |
| 144 return items; | |
| 145 } | |
| 146 | |
| 147 for (var operation in expr.operations) { | |
| 148 switch (operation) { | |
| 149 case UnlinkedExprOperation.pushString: | |
| 150 stack.add(expr.strings[stringIndex++]); | |
| 151 break; | |
| 152 case UnlinkedExprOperation.invokeConstructor: | |
| 153 var namedArgumentList = popItems(expr.ints[intIndex++]); | |
| 154 var namedArguments = <String, dynamic>{}; | |
| 155 for (var namedArgument in namedArgumentList) { | |
| 156 namedArguments[expr.strings[stringIndex++]] = namedArgument; | |
| 157 } | |
| 158 var positionalArguments = popItems(expr.ints[intIndex++]); | |
| 159 stack.add(_findConstructor(expr.references[referenceIndex++])( | |
| 160 (i, [defaultValue]) => i < positionalArguments.length | |
| 161 ? positionalArguments[i] | |
| 162 : defaultValue, | |
| 163 (name, [defaultValue]) => namedArguments.containsKey(name) | |
| 164 ? namedArguments[name] | |
| 165 : defaultValue)); | |
| 166 break; | |
| 167 case UnlinkedExprOperation.makeUntypedMap: | |
| 168 var map = {}; | |
| 169 var numKeyValuePairs = expr.ints[intIndex++]; | |
| 170 var keyValueList = popItems(numKeyValuePairs * 2); | |
| 171 for (var i = 0; i < numKeyValuePairs; i++) { | |
| 172 map[keyValueList[2 * i]] = keyValueList[2 * i + 1]; | |
| 173 } | |
| 174 stack.add(map); | |
| 175 break; | |
| 176 case UnlinkedExprOperation.pushReference: | |
| 177 stack.add(_findReference(expr.references[referenceIndex++])); | |
| 178 break; | |
| 179 case UnlinkedExprOperation.pushInt: | |
| 180 stack.add(expr.ints[intIndex++]); | |
| 181 break; | |
| 182 case UnlinkedExprOperation.pushFalse: | |
| 183 stack.add(false); | |
| 184 break; | |
| 185 case UnlinkedExprOperation.pushTrue: | |
| 186 stack.add(true); | |
| 187 break; | |
| 188 case UnlinkedExprOperation.bitOr: | |
| 189 var y = stack.removeLast(); | |
| 190 var x = stack.removeLast(); | |
| 191 stack.add(x | y); | |
| 192 break; | |
| 193 default: | |
| 194 throw new UnimplementedError( | |
| 195 'Unexpected expression in libraries.dart: $operation'); | |
| 196 } | |
| 197 } | |
| 198 assert(stringIndex == expr.strings.length); | |
| 199 assert(intIndex == expr.ints.length); | |
| 200 assert(referenceIndex == expr.references.length); | |
| 201 assert(stack.length == 1); | |
| 202 _value = stack[0]; | |
| 203 isMaterialized = true; | |
| 204 } | |
| 205 } | |
| OLD | NEW |