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

Side by Side Diff: pkg/kernel/lib/interpreter/interpreter.dart

Issue 2871953002: Refactor argument evaluation for static invocation (Closed)
Patch Set: Remove name getter from ArgumentExpression Created 3 years, 7 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 library kernel.interpreter; 4 library kernel.interpreter;
5 5
6 import '../ast.dart'; 6 import '../ast.dart';
7 import '../ast.dart' as ast show Class; 7 import '../ast.dart' as ast show Class;
8 8
9 import '../log.dart'; 9 import '../log.dart';
10 export '../log.dart'; 10 export '../log.dart';
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 bindings.add(new Binding(variable, value)); 79 bindings.add(new Binding(variable, value));
80 } 80 }
81 } 81 }
82 82
83 /// Evaluate expressions. 83 /// Evaluate expressions.
84 class Evaluator 84 class Evaluator
85 extends ExpressionVisitor1<Configuration, ExpressionConfiguration> { 85 extends ExpressionVisitor1<Configuration, ExpressionConfiguration> {
86 Configuration eval(Expression expr, ExpressionConfiguration config) => 86 Configuration eval(Expression expr, ExpressionConfiguration config) =>
87 expr.accept1(this, config); 87 expr.accept1(this, config);
88 88
89 Configuration evalArgs(List<ArgumentExpression> args, Environment env,
90 ApplicationContinuation cont) {
91 if (args.isNotEmpty) {
92 return new ExpressionConfiguration(args.first.expression, env,
93 new ActualArgumentsContinuation(args.first, args.skip(1), env, cont));
94 }
95 return new ArgumentContinuationConfiguration(cont, <ArgumentValue>[]);
96 }
97
89 Configuration defaultExpression( 98 Configuration defaultExpression(
90 Expression node, ExpressionConfiguration config) { 99 Expression node, ExpressionConfiguration config) {
91 throw new NotImplemented('Evaluation for expressions of type ' 100 throw new NotImplemented('Evaluation for expressions of type '
92 '${node.runtimeType} is not implemented.'); 101 '${node.runtimeType} is not implemented.');
93 } 102 }
94 103
95 Configuration visitInvalidExpression1( 104 Configuration visitInvalidExpression1(
96 InvalidExpression node, ExpressionConfiguration config) { 105 InvalidExpression node, ExpressionConfiguration config) {
97 throw 'Invalid expression at ${node.location.toString()}'; 106 throw 'Invalid expression at ${node.location.toString()}';
98 } 107 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 defaultExpression(node, config); 140 defaultExpression(node, config);
132 141
133 Configuration visitStaticInvocation( 142 Configuration visitStaticInvocation(
134 StaticInvocation node, ExpressionConfiguration config) { 143 StaticInvocation node, ExpressionConfiguration config) {
135 if ('print' == node.name.toString()) { 144 if ('print' == node.name.toString()) {
136 var cont = new PrintContinuation(config.continuation); 145 var cont = new PrintContinuation(config.continuation);
137 return new ExpressionConfiguration( 146 return new ExpressionConfiguration(
138 node.arguments.positional.first, config.environment, cont); 147 node.arguments.positional.first, config.environment, cont);
139 } else { 148 } else {
140 log.info('static-invocation-${node.target.name.toString()}\n'); 149 log.info('static-invocation-${node.target.name.toString()}\n');
141 var cont = new ActualArgumentsContinuation(node.arguments, 150
142 node.target.function, config.environment, config.continuation); 151 List<ArgumentExpression> args =
143 return cont.createCurrentConfiguration(); 152 _createArgumentExpressionList(node.arguments, node.target.function);
153 ApplicationContinuation cont = new StaticInvocationApplication(
154 node.target.function, config.continuation);
155 return new ArgumentsConfiguration(args, config.environment, cont);
144 } 156 }
145 } 157 }
146 158
147 Configuration visitMethodInvocation( 159 Configuration visitMethodInvocation(
148 MethodInvocation node, ExpressionConfiguration config) { 160 MethodInvocation node, ExpressionConfiguration config) {
149 // Currently supports only method invocation with <2 arguments and is used 161 // Currently supports only method invocation with <2 arguments and is used
150 // to evaluate implemented operators for int, double and String values. 162 // to evaluate implemented operators for int, double and String values.
151 var cont = new MethodInvocationContinuation( 163 var cont = new MethodInvocationContinuation(
152 node.arguments, node.name, config.environment, config.continuation); 164 node.arguments, node.name, config.environment, config.continuation);
153 165
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 } 333 }
322 } 334 }
323 335
324 /// Represents the configuration for applying an [ExpressionContinuation]. 336 /// Represents the configuration for applying an [ExpressionContinuation].
325 class ContinuationConfiguration extends Configuration { 337 class ContinuationConfiguration extends Configuration {
326 final ExpressionContinuation continuation; 338 final ExpressionContinuation continuation;
327 final Value value; 339 final Value value;
328 340
329 ContinuationConfiguration(this.continuation, this.value); 341 ContinuationConfiguration(this.continuation, this.value);
330 342
331 Configuration step(StatementExecuter executer) => continuation(value); 343 Configuration step(StatementExecuter _) => continuation(value);
344 }
345
346 /// Represents the configuration for applying an [ApplicationContinuation].
347 class ArgumentContinuationConfiguration extends Configuration {
348 final ApplicationContinuation continuation;
349 final List<ArgumentValue> argumentValues;
350
351 ArgumentContinuationConfiguration(this.continuation, this.argumentValues);
352
353 Configuration step(StatementExecuter _) => continuation(argumentValues);
332 } 354 }
333 355
334 /// Represents the configuration for evaluating an [Expression]. 356 /// Represents the configuration for evaluating an [Expression].
335 class ExpressionConfiguration extends Configuration { 357 class ExpressionConfiguration extends Configuration {
336 final Expression expression; 358 final Expression expression;
337 359
338 /// Environment in which the expression is evaluated. 360 /// Environment in which the expression is evaluated.
339 final Environment environment; 361 final Environment environment;
340 362
341 /// Next continuation to be applied. 363 /// Next continuation to be applied.
342 final ExpressionContinuation continuation; 364 final Continuation continuation;
343 365
344 ExpressionConfiguration(this.expression, this.environment, this.continuation); 366 ExpressionConfiguration(this.expression, this.environment, this.continuation);
345 367
346 Configuration step(StatementExecuter executer) => 368 Configuration step(StatementExecuter executer) =>
347 executer.eval(expression, this); 369 executer.eval(expression, this);
348 } 370 }
349 371
372 /// Represents the configuration for evaluating a list of argument expressions.
373 class ArgumentsConfiguration extends Configuration {
374 final List<ArgumentExpression> arguments;
375 final Environment environment;
376 final Continuation continuation;
377
378 ArgumentsConfiguration(this.arguments, this.environment, this.continuation);
379
380 Configuration step(StatementExecuter executer) =>
381 executer.evalArgs(arguments, environment, continuation);
382 }
383
384 abstract class ArgumentExpression {
385 Expression get expression;
386 }
387
388 class PositionalArgumentExpression extends ArgumentExpression {
389 final Expression expression;
390
391 PositionalArgumentExpression(this.expression);
392 }
393
394 class NamedArgumentExpression extends ArgumentExpression {
395 final String name;
396 final Expression expression;
397
398 NamedArgumentExpression(this.name, this.expression);
399 }
400
401 abstract class ArgumentValue {
402 Value get value;
403 }
404
405 class PositionalArgumentValue extends ArgumentValue {
406 final Value value;
407
408 PositionalArgumentValue(this.value);
409 }
410
411 class NamedArgumentValue extends ArgumentValue {
412 final String name;
413 final Value value;
414
415 NamedArgumentValue(this.name, this.value);
416 }
417
418 abstract class Continuation {}
419
420 /// Represents the continuation called after the evaluation of argument
421 /// expressions.
422 abstract class ApplicationContinuation extends Continuation {
423 Configuration call(List<ArgumentValue> args);
424
425 /// Creates an environment binding actual argument values to formal parameters
426 /// of the function in a new environment, which is used to execute the
427 /// body od the function.
428 static Environment createEnvironment(
429 FunctionNode function, List<ArgumentValue> args) {
430 Environment newEnv = new Environment.empty();
431 List<PositionalArgumentValue> positional = args.reversed
432 .where((ArgumentValue av) => av is PositionalArgumentValue)
433 .toList();
434
435 // Add positional parameters.
436 for (int i = 0; i < positional.length; ++i) {
437 newEnv.expand(function.positionalParameters[i], positional[i].value);
438 }
439
440 Map<String, Value> named = new Map.fromIterable(
441 args.where((ArgumentValue av) => av is NamedArgumentValue),
442 key: (NamedArgumentValue av) => av.name,
443 value: (NamedArgumentValue av) => av.value);
444
445 // Add named parameters.
446 for (VariableDeclaration v in function.namedParameters) {
447 newEnv.expand(v, named[v.name.toString()]);
448 }
449
450 return newEnv;
451 }
452 }
453
454 /// Represents the application continuation for static invocation.
455 class StaticInvocationApplication extends ApplicationContinuation {
456 final FunctionNode function;
457 final ExpressionContinuation continuation;
458
459 StaticInvocationApplication(this.function, this.continuation);
460
461 Configuration call(List<ArgumentValue> args) {
462 Environment functionEnv =
463 ApplicationContinuation.createEnvironment(function, args);
464
465 State bodyState = new State.initial()
466 .withExpressionContinuation(continuation)
467 .withConfiguration(new ExitConfiguration(continuation))
468 .withEnvironment(functionEnv);
469 return new StatementConfiguration(function.body, bodyState);
470 }
471 }
472
473 /// Represents the application continuation called after the evaluation of all
474 /// argument expressions for an invocation.
475 class ArgumentValueApplication extends ApplicationContinuation {
476 final ArgumentValue value;
477 final ApplicationContinuation applicationContinuation;
478
479 ArgumentValueApplication(this.value, this.applicationContinuation);
480
481 Configuration call(List<ArgumentValue> args) {
482 args.add(value);
483 return new ArgumentContinuationConfiguration(applicationContinuation, args);
484 }
485 }
486
350 /// Represents an expression continuation. 487 /// Represents an expression continuation.
351 abstract class ExpressionContinuation { 488 abstract class ExpressionContinuation extends Continuation {
352 Configuration call(Value v); 489 Configuration call(Value v);
353 } 490 }
354 491
355 /// Represents a continuation that returns the next [StatementConfiguration] 492 /// Represents a continuation that returns the next [StatementConfiguration]
356 /// to be executed. 493 /// to be executed.
357 class ExpressionStatementContinuation extends ExpressionContinuation { 494 class ExpressionStatementContinuation extends ExpressionContinuation {
358 final StatementConfiguration configuration; 495 final StatementConfiguration configuration;
359 496
360 ExpressionStatementContinuation(this.configuration); 497 ExpressionStatementContinuation(this.configuration);
361 498
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 Setter setter = receiver.class_.lookupSetter(name); 552 Setter setter = receiver.class_.lookupSetter(name);
416 setter(receiver, v); 553 setter(receiver, v);
417 return new ContinuationConfiguration(continuation, v); 554 return new ContinuationConfiguration(continuation, v);
418 } 555 }
419 } 556 }
420 557
421 /// Represents a continuation to be called after the evaluation of an actual 558 /// Represents a continuation to be called after the evaluation of an actual
422 /// argument for function invocation. 559 /// argument for function invocation.
423 /// TODO: Add checks for validation of arguments according to spec. 560 /// TODO: Add checks for validation of arguments according to spec.
424 class ActualArgumentsContinuation extends ExpressionContinuation { 561 class ActualArgumentsContinuation extends ExpressionContinuation {
425 final Arguments arguments; 562 final ArgumentExpression currentArgument;
426 final FunctionNode functionNode; 563 final List<ArgumentExpression> arguments;
427 final Environment environment; 564 final Environment environment;
428 final ExpressionContinuation continuation; 565 final ApplicationContinuation applicationContinuation;
429 566
430 final List<Value> _positional = <Value>[]; 567 ActualArgumentsContinuation(this.currentArgument, this.arguments,
431 int _currentPositional = 0; 568 this.environment, this.applicationContinuation);
432 final Map<String, Value> _named = <String, Value>{};
433 int _currentNamed = 0;
434
435 ActualArgumentsContinuation(
436 this.arguments, this.functionNode, this.environment, this.continuation);
437 569
438 Configuration call(Value v) { 570 Configuration call(Value v) {
439 if (_currentPositional < arguments.positional.length) { 571 ArgumentValue argumentValue;
440 _positional.add(v); 572 if (currentArgument is NamedArgumentExpression) {
441 _currentPositional++; 573 argumentValue = new NamedArgumentValue(
574 (currentArgument as NamedArgumentExpression).name, v);
Dmitry Stefantsov 2017/05/10 08:41:45 Btw, we don't need the "as" cast here, because of
zhivkag 2017/05/10 09:11:07 Type promotion doesn't seem to be working in this
442 } else { 575 } else {
443 assert(_currentNamed < arguments.named.length); 576 assert(currentArgument is PositionalArgumentExpression);
444 String name = arguments.named[_currentNamed].name; 577 argumentValue = new PositionalArgumentValue(v);
445 _named[name] = v;
446 _currentNamed++;
447 } 578 }
448 579
449 return createCurrentConfiguration(); 580 return new ArgumentsConfiguration(arguments, environment,
450 } 581 new ArgumentValueApplication(argumentValue, applicationContinuation));
451
452 Configuration createCurrentConfiguration() {
453 // Next argument to evaluate is a provided positional argument.
454 if (_currentPositional < arguments.positional.length) {
455 return new ExpressionConfiguration(
456 arguments.positional[_currentPositional], environment, this);
457 }
458 // Next argument to evaluate is a provided named argument.
459 if (_currentNamed < arguments.named.length) {
460 return new ExpressionConfiguration(
461 arguments.named[_currentNamed].value, environment, this);
462 }
463
464 // TODO: check if the number of actual arguments is larger then the number
465 // of required arguments and smaller then the number of formal arguments.
466
467 return new OptionalArgumentsContinuation(
468 _positional, _named, functionNode, environment, continuation)
469 .createCurrentConfiguration();
470 } 582 }
471 } 583 }
472 584
473 class OptionalArgumentsContinuation extends ExpressionContinuation {
474 final List<Value> positional;
475 final Map<String, Value> named;
476 final FunctionNode functionNode;
477 final Environment environment;
478 final ExpressionContinuation continuation;
479
480 final Map<String, VariableDeclaration> _missingFormalNamed =
481 <String, VariableDeclaration>{};
482
483 int _currentPositional;
484 String _currentNamed;
485
486 OptionalArgumentsContinuation(this.positional, this.named, this.functionNode,
487 this.environment, this.continuation) {
488 _currentPositional = positional.length;
489 assert(_currentPositional >= functionNode.requiredParameterCount);
490
491 for (VariableDeclaration vd in functionNode.namedParameters) {
492 if (named[vd.name] == null) {
493 _missingFormalNamed[vd.name] = vd;
494 }
495 }
496 }
497
498 Configuration call(Value v) {
499 if (_currentPositional < functionNode.positionalParameters.length) {
500 // Value is a optional positional argument
501 positional.add(v);
502 _currentPositional++;
503 } else {
504 // Value is a optional named argument.
505 assert(named[_currentNamed] == null);
506 named[_currentNamed] = v;
507 }
508
509 return createCurrentConfiguration();
510 }
511
512 /// Creates the current configuration for the evaluation of invocation a
513 /// function.
514 Configuration createCurrentConfiguration() {
515 if (_currentPositional < functionNode.positionalParameters.length) {
516 // Next argument to evaluate is a missing positional argument.
517 // Evaluate its initializer.
518 return new ExpressionConfiguration(
519 functionNode.positionalParameters[_currentPositional].initializer,
520 environment,
521 this);
522 }
523 if (named.length < functionNode.namedParameters.length) {
524 // Next argument to evaluate is a missing named argument.
525 // Evaluate its initializer.
526 _currentNamed = _missingFormalNamed.keys.first;
527 Expression initializer = _missingFormalNamed[_currentNamed].initializer;
528 _missingFormalNamed.remove(_currentNamed);
529 return new ExpressionConfiguration(initializer, environment, this);
530 }
531
532 Environment newEnv = _createEnvironment();
533 State bodyState = new State.initial()
534 .withExpressionContinuation(continuation)
535 .withConfiguration(new ExitConfiguration(continuation))
536 .withEnvironment(newEnv);
537
538 return new StatementConfiguration(functionNode.body, bodyState);
539 }
540
541 /// Creates an environment binding actual argument values to formal parameters
542 /// of the function in a new environment, which is used to execute the
543 /// body od the function.
544 Environment _createEnvironment() {
545 Environment newEnv = new Environment.empty();
546 // Add positional parameters.
547 for (int i = 0; i < positional.length; ++i) {
548 newEnv.expand(functionNode.positionalParameters[i], positional[i]);
549 }
550 // Add named parameters.
551 for (VariableDeclaration v in functionNode.namedParameters) {
552 newEnv.expand(v, named[v.name.toString()]);
553 }
554
555 return newEnv;
556 }
557 }
558
559 class MethodInvocationContinuation extends ExpressionContinuation { 585 class MethodInvocationContinuation extends ExpressionContinuation {
560 final Arguments arguments; 586 final Arguments arguments;
561 final Name methodName; 587 final Name methodName;
562 final Environment environment; 588 final Environment environment;
563 final ExpressionContinuation continuation; 589 final ExpressionContinuation continuation;
564 590
565 MethodInvocationContinuation( 591 MethodInvocationContinuation(
566 this.arguments, this.methodName, this.environment, this.continuation); 592 this.arguments, this.methodName, this.environment, this.continuation);
567 593
568 Configuration call(Value receiver) { 594 Configuration call(Value receiver) {
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 void trampolinedExecution(Configuration configuration) { 807 void trampolinedExecution(Configuration configuration) {
782 while (configuration != null) { 808 while (configuration != null) {
783 configuration = configuration.step(this); 809 configuration = configuration.step(this);
784 } 810 }
785 } 811 }
786 812
787 Configuration exec(Statement statement, State state) => 813 Configuration exec(Statement statement, State state) =>
788 statement.accept1(this, state); 814 statement.accept1(this, state);
789 Configuration eval(Expression expression, ExpressionConfiguration config) => 815 Configuration eval(Expression expression, ExpressionConfiguration config) =>
790 evaluator.eval(expression, config); 816 evaluator.eval(expression, config);
817 Configuration evalArgs(
818 List<ArgumentExpression> args, Environment env, Continuation cont) =>
819 evaluator.evalArgs(args, env, cont);
791 820
792 Configuration defaultStatement(Statement node, State state) { 821 Configuration defaultStatement(Statement node, State state) {
793 throw notImplemented( 822 throw notImplemented(
794 m: "Execution is not implemented for statement:\n$node "); 823 m: "Execution is not implemented for statement:\n$node ");
795 } 824 }
796 825
797 Configuration visitInvalidStatement(InvalidStatement node, State state) { 826 Configuration visitInvalidStatement(InvalidStatement node, State state) {
798 throw "Invalid statement at ${node.location}"; 827 throw "Invalid statement at ${node.location}";
799 } 828 }
800 829
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
1103 1132
1104 class NullValue extends LiteralValue { 1133 class NullValue extends LiteralValue {
1105 Object get value => null; 1134 Object get value => null;
1106 1135
1107 const NullValue(); 1136 const NullValue();
1108 } 1137 }
1109 1138
1110 notImplemented({String m, Object obj}) { 1139 notImplemented({String m, Object obj}) {
1111 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); 1140 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented');
1112 } 1141 }
1142
1143 // ------------------------------------------------------------------------
1144 // INTERNAL FUNCTIONS
1145 // ------------------------------------------------------------------------
1146 /// Creates a list of all argument expressions to be evaluated for the
1147 /// invocation of the provided [FunctionNode] containing the actual arguments
1148 /// and the optional argument initializers.
1149 List<ArgumentExpression> _createArgumentExpressionList(
1150 Arguments providedArgs, FunctionNode fun) {
1151 List<ArgumentExpression> args = <ArgumentExpression>[];
1152 // Add positional arguments expressions.
1153 args.addAll(providedArgs.positional
1154 .map((Expression e) => new PositionalArgumentExpression(e)));
1155
1156 // Add optional positional argument initializers.
1157 for (int i = providedArgs.positional.length;
1158 i < fun.positionalParameters.length;
1159 i++) {
1160 args.add(new PositionalArgumentExpression(
1161 fun.positionalParameters[i].initializer));
1162 }
1163
1164 Map<String, NamedArgumentExpression> namedFormals = new Map.fromIterable(
1165 fun.namedParameters,
1166 key: (VariableDeclaration vd) => vd.name,
1167 value: (VariableDeclaration vd) =>
1168 new NamedArgumentExpression(vd.name, vd.initializer));
1169
1170 // Add named expressions.
1171 for (int i = 0; i < providedArgs.named.length; i++) {
1172 var current = providedArgs.named[i];
1173 args.add(new NamedArgumentExpression(current.name, current.value));
1174 namedFormals.remove(current.name);
1175 }
1176
1177 // Add missing optional named initializers.
1178 args.addAll(namedFormals.values);
1179
1180 return args;
1181 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698