OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } | |
OLD | NEW |