Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: pkg/fasta/lib/src/kernel/kernel_procedure_builder.dart

Issue 2631693002: Fasta kernel builders. (Closed)
Patch Set: Address comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 library fasta.kernel_procedure_builder;
6
7 import 'package:kernel/ast.dart' show
8 Arguments,
9 AsyncMarker,
10 Constructor,
11 DartType,
12 DynamicType,
13 EmptyStatement,
14 Expression,
15 FunctionNode,
16 Initializer,
17 Library,
18 LocalInitializer,
19 Member,
20 Name,
21 NamedExpression,
22 Procedure,
23 ProcedureKind,
24 RedirectingInitializer,
25 Statement,
26 SuperInitializer,
27 TypeParameter,
28 VariableDeclaration,
29 VariableGet,
30 VoidType,
31 setParents;
32
33 import 'package:kernel/type_algebra.dart' show
34 containsTypeVariable,
35 substitute;
36
37 import '../errors.dart' show
38 internalError;
39
40 import '../modifier.dart' show
41 abstractMask;
42
43 import 'kernel_builder.dart' show
44 ClassBuilder,
45 ConstructorReferenceBuilder,
46 FormalParameterBuilder,
47 KernelFormalParameterBuilder,
48 KernelTypeBuilder,
49 KernelTypeVariableBuilder,
50 MetadataBuilder,
51 ProcedureBuilder,
52 TypeBuilder,
53 TypeVariableBuilder,
54 memberError;
55
56 abstract class KernelFunctionBuilder
57 extends ProcedureBuilder<KernelTypeBuilder> {
58 FunctionNode function;
59
60 Statement actualBody;
61
62 KernelFunctionBuilder(
63 List<MetadataBuilder> metadata,
64 int modifiers, KernelTypeBuilder returnType, String name,
65 List<TypeVariableBuilder> typeVariables,
66 List<FormalParameterBuilder> formals)
67 : super(metadata, modifiers, returnType, name, typeVariables, formals);
68
69 void set body(Statement newBody) {
70 if (isAbstract && newBody != null) {
71 return internalError("Attempting to set body on abstract method.");
72 }
73 actualBody = newBody;
74 if (function != null) {
75 function.body = newBody;
76 newBody?.parent = function;
77 }
78 }
79
80 Statement get body => actualBody ??= new EmptyStatement();
81
82 FunctionNode buildFunction() {
83 assert(function == null);
84 FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
85 if (typeVariables != null) {
86 for (KernelTypeVariableBuilder t in typeVariables) {
87 result.typeParameters.add(t.parameter);
88 }
89 setParents(result.typeParameters, result);
90 }
91 if (formals != null) {
92 for (KernelFormalParameterBuilder formal in formals) {
93 VariableDeclaration parameter = formal.build();
94 if (formal.isNamed) {
95 result.namedParameters.add(parameter);
96 } else {
97 result.positionalParameters.add(parameter);
98 }
99 parameter.parent = result;
100 if (formal.isRequired) {
101 result.requiredParameterCount++;
102 }
103 }
104 }
105 if (returnType != null) {
106 result.returnType = returnType.build();
107 }
108 if (!isConstructor && !isInstanceMember && parent is ClassBuilder) {
109 List<TypeParameter> typeParameters = parent.target.typeParameters;
110 if (typeParameters.isNotEmpty) {
111 Map<TypeParameter, DartType> substitution;
112 DartType removeTypeVariables(DartType type) {
113 if (substitution == null) {
114 substitution = <TypeParameter, DartType>{};
115 for (TypeParameter parameter in typeParameters) {
116 substitution[parameter] = const DynamicType();
117 }
118 }
119 print("Can only use type variables in instance methods.");
120 return substitute(type, substitution);
121 }
122 Set<TypeParameter> set = typeParameters.toSet();
123 for (VariableDeclaration parameter in result.positionalParameters) {
124 if (containsTypeVariable(parameter.type, set)) {
125 parameter.type = removeTypeVariables(parameter.type);
126 }
127 }
128 for (VariableDeclaration parameter in result.namedParameters) {
129 if (containsTypeVariable(parameter.type, set)) {
130 parameter.type = removeTypeVariables(parameter.type);
131 }
132 }
133 if (containsTypeVariable(result.returnType, set)) {
134 result.returnType = removeTypeVariables(result.returnType);
135 }
136 }
137 }
138 return function = result;
139 }
140
141 Member build(Library library);
142 }
143
144 class KernelProcedureBuilder extends KernelFunctionBuilder {
145 final Procedure procedure;
146
147 AsyncMarker actualAsyncModifier;
148
149 final ConstructorReferenceBuilder redirectionTarget;
150
151 KernelProcedureBuilder(
152 List<MetadataBuilder> metadata,
153 int modifiers, KernelTypeBuilder returnType, String name,
154 List<TypeVariableBuilder> typeVariables,
155 List<FormalParameterBuilder> formals, this.actualAsyncModifier,
156 ProcedureKind kind, [this.redirectionTarget])
157 : procedure = new Procedure(null, kind, null),
158 super(metadata, modifiers, returnType, name, typeVariables, formals);
159
160 ProcedureKind get kind => procedure.kind;
161
162 AsyncMarker get asyncModifier => actualAsyncModifier;
163
164 Statement get body {
165 if (actualBody == null && redirectionTarget == null && !isAbstract &&
166 !isExternal) {
167 actualBody = new EmptyStatement();
168 }
169 return actualBody;
170 }
171
172 void set asyncModifier(AsyncMarker newModifier) {
173 actualAsyncModifier = newModifier;
174 if (function != null) {
175 // No parent, it's an enum.
176 function.asyncMarker = actualAsyncModifier;
177 }
178 }
179
180 Procedure build(Library library) {
181 // TODO(ahe): I think we may call this twice on parts. Investigate.
182 if (procedure.name == null) {
183 procedure.function = buildFunction();
184 procedure.function.parent = procedure;
185 procedure.isAbstract = isAbstract;
186 procedure.isStatic = isStatic;
187 procedure.isExternal = isExternal;
188 procedure.isConst = isConst;
189 procedure.name = new Name(name, library);
190 }
191 return procedure;
192 }
193
194 KernelFunctionBuilder toConstructor(String name,
195 List<TypeVariableBuilder> classTypeVariables) {
196 assert(procedure.name == null);
197 assert(actualBody == null);
198 if (isFactory) {
199 if (this.typeVariables != null) {
200 return memberError(target, "Factories can't be generic.");
201 }
202 List<KernelTypeVariableBuilder> typeVariables;
203 KernelTypeBuilder returnType = this.returnType;
204 List<FormalParameterBuilder> formals;
205 if (classTypeVariables != null) {
206 typeVariables = <KernelTypeVariableBuilder>[];
207 for (KernelTypeVariableBuilder variable in classTypeVariables) {
208 typeVariables.add(new KernelTypeVariableBuilder(variable.name));
209 }
210 Map<TypeVariableBuilder, TypeBuilder> substitution =
211 <TypeVariableBuilder, TypeBuilder>{};
212 int i = 0;
213 for (KernelTypeVariableBuilder variable in classTypeVariables) {
214 substitution[variable] = typeVariables[i++].asTypeBuilder();
215 }
216 i = 0;
217 for (KernelTypeVariableBuilder variable in classTypeVariables) {
218 typeVariables[i++].bound = variable?.bound?.subst(substitution);
219 }
220 returnType = returnType?.subst(substitution);
221 i = 0;
222 if (this.formals != null) {
223 for (KernelFormalParameterBuilder formal in this.formals) {
224 KernelTypeBuilder type = formal.type?.subst(substitution);
225 if (type != formal.type) {
226 formals ??= this.formals.toList();
227 formals[i] = new KernelFormalParameterBuilder(formal.metadata,
228 formal.modifiers, type, formal.name, formal.hasThis);
229 }
230 i++;
231 }
232 }
233 }
234 formals ??= this.formals;
235 return new KernelProcedureBuilder(
236 metadata, modifiers, returnType, name, typeVariables, formals,
237 actualAsyncModifier, kind, redirectionTarget)
238 ..parent = parent;
239 } else {
240 return new KernelConstructorBuilder(metadata, modifiers & ~abstractMask,
241 returnType, name, typeVariables, formals)
242 ..parent = parent;
243 }
244 }
245
246 Procedure get target => procedure;
247 }
248
249 // TODO(ahe): Move this to own file?
250 class KernelConstructorBuilder extends KernelFunctionBuilder {
251 final Constructor constructor = new Constructor(null);
252
253 bool hasMovedSuperInitializer = false;
254
255 SuperInitializer superInitializer;
256
257 RedirectingInitializer redirectingInitializer;
258
259 KernelConstructorBuilder(
260 List<MetadataBuilder> metadata,
261 int modifiers, KernelTypeBuilder returnType, String name,
262 List<TypeVariableBuilder> typeVariables,
263 List<FormalParameterBuilder> formals)
264 : super(metadata, modifiers, returnType, name, typeVariables, formals);
265
266 bool get isInstanceMember => false;
267
268 bool get isConstructor => true;
269
270 AsyncMarker get asyncModifier => AsyncMarker.Sync;
271
272 ProcedureKind get kind => null;
273
274 Constructor build(Library library) {
275 if (constructor.name == null) {
276 constructor.function = buildFunction();
277 constructor.function.parent = constructor;
278 constructor.isConst = isConst;
279 constructor.isExternal = isExternal;
280 constructor.name = new Name(name, library);
281 }
282 return constructor;
283 }
284
285 FunctionNode buildFunction() {
286 // TODO(ahe): Should complain if another type is explicitly set.
287 return super.buildFunction()
288 ..returnType = const VoidType();
289 }
290
291 Constructor get target => constructor;
292
293 void checkSuperOrThisInitializer(Initializer initializer) {
294 if (superInitializer != null || redirectingInitializer != null) {
295 memberError(target,
296 "Can't have more than one 'super' or 'this' initializer.",
297 initializer.fileOffset);
298 }
299 }
300
301 void addInitializer(Initializer initializer) {
302 List<Initializer> initializers = constructor.initializers;
303 if (initializer is SuperInitializer) {
304 checkSuperOrThisInitializer(initializer);
305 superInitializer = initializer;
306 } else if (initializer is RedirectingInitializer) {
307 checkSuperOrThisInitializer(initializer);
308 redirectingInitializer = initializer;
309 if (constructor.initializers.isNotEmpty) {
310 memberError(target, "'this' initializer must be the only initializer.",
311 initializer.fileOffset);
312 }
313 } else if (redirectingInitializer != null) {
314 memberError(target, "'this' initializer must be the only initializer.",
315 initializer.fileOffset);
316 } else if (superInitializer != null) {
317 // If there is a super initializer ([initializer] isn't it), we need to
318 // insert [initializer] before the super initializer (thus ensuring that
319 // the super initializer is always last).
320 assert(superInitializer != initializer);
321 assert(initializers.last == superInitializer);
322 initializers.removeLast();
323 if (!hasMovedSuperInitializer) {
324 // To preserve correct evaluation order, the arguments to super call
325 // must be evaluated before [initializer]. Once the super initializer
326 // has been moved once, the arguments are evaluated in the correct
327 // order.
328 hasMovedSuperInitializer = true;
329 Arguments arguments = superInitializer.arguments;
330 List<Expression> positional = arguments.positional;
331 for (int i = 0; i < positional.length; i++) {
332 VariableDeclaration variable =
333 new VariableDeclaration.forValue(positional[i], isFinal: true);
334 initializers.add(
335 new LocalInitializer(variable)..parent = constructor);
336 positional[i] = new VariableGet(variable)..parent = arguments;
337 }
338 for (NamedExpression named in arguments.named) {
339 VariableDeclaration variable =
340 new VariableDeclaration.forValue(named.value, isFinal: true);
341 named.value = new VariableGet(variable)..parent = named;
342 initializers.add(
343 new LocalInitializer(variable)..parent = constructor);
344 }
345 }
346 initializers.add(initializer..parent = constructor);
347 initializers.add(superInitializer);
348 return;
349 }
350 initializers.add(initializer);
351 initializer.parent = constructor;
352 }
353 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698