Chromium Code Reviews| Index: pkg/kernel/lib/interpreter/interpreter.dart |
| diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
| index c9eb916983451c8313a3bde8a5855781eb984f69..76ddc324089f5a8d4af74f5d83d289e633b7ec13 100644 |
| --- a/pkg/kernel/lib/interpreter/interpreter.dart |
| +++ b/pkg/kernel/lib/interpreter/interpreter.dart |
| @@ -86,6 +86,15 @@ class Evaluator |
| Configuration eval(Expression expr, ExpressionConfiguration config) => |
| expr.accept1(this, config); |
| + Configuration evalArgs(List<ArgumentExpression> args, Environment env, |
| + ApplicationContinuation cont) { |
| + if (args.isNotEmpty) { |
| + return new ExpressionConfiguration(args.first.expression, env, |
| + new ActualArgumentsContinuation(args.first, args.skip(1), env, cont)); |
| + } |
| + return new ArgumentContinuationConfiguration(cont, <ArgumentValue>[]); |
| + } |
| + |
| Configuration defaultExpression( |
| Expression node, ExpressionConfiguration config) { |
| throw new NotImplemented('Evaluation for expressions of type ' |
| @@ -138,9 +147,12 @@ class Evaluator |
| node.arguments.positional.first, config.environment, cont); |
| } else { |
| log.info('static-invocation-${node.target.name.toString()}\n'); |
| - var cont = new ActualArgumentsContinuation(node.arguments, |
| - node.target.function, config.environment, config.continuation); |
| - return cont.createCurrentConfiguration(); |
| + |
| + List<ArgumentExpression> args = |
| + _createArgumentExpressionList(node.arguments, node.target.function); |
| + ApplicationContinuation cont = new StaticInvocationApplication( |
| + node.target.function, config.continuation); |
| + return new ArgumentsConfiguration(args, config.environment, cont); |
| } |
| } |
| @@ -328,7 +340,17 @@ class ContinuationConfiguration extends Configuration { |
| ContinuationConfiguration(this.continuation, this.value); |
| - Configuration step(StatementExecuter executer) => continuation(value); |
| + Configuration step(StatementExecuter _) => continuation(value); |
| +} |
| + |
| +/// Represents the configuration for applying an [ApplicationContinuation]. |
| +class ArgumentContinuationConfiguration extends Configuration { |
| + final ApplicationContinuation continuation; |
| + final List<ArgumentValue> argumentValues; |
| + |
| + ArgumentContinuationConfiguration(this.continuation, this.argumentValues); |
| + |
| + Configuration step(StatementExecuter _) => continuation(argumentValues); |
| } |
| /// Represents the configuration for evaluating an [Expression]. |
| @@ -339,7 +361,7 @@ class ExpressionConfiguration extends Configuration { |
| final Environment environment; |
| /// Next continuation to be applied. |
| - final ExpressionContinuation continuation; |
| + final Continuation continuation; |
| ExpressionConfiguration(this.expression, this.environment, this.continuation); |
| @@ -347,8 +369,123 @@ class ExpressionConfiguration extends Configuration { |
| executer.eval(expression, this); |
| } |
| +/// Represents the configuration for evaluating a list of argument expressions. |
| +class ArgumentsConfiguration extends Configuration { |
| + final List<ArgumentExpression> arguments; |
| + final Environment environment; |
| + final Continuation continuation; |
| + |
| + ArgumentsConfiguration(this.arguments, this.environment, this.continuation); |
| + |
| + Configuration step(StatementExecuter executer) => |
| + executer.evalArgs(arguments, environment, continuation); |
| +} |
| + |
| +abstract class ArgumentExpression { |
| + Expression get expression; |
| +} |
| + |
| +class PositionalArgumentExpression extends ArgumentExpression { |
| + final Expression expression; |
| + |
| + PositionalArgumentExpression(this.expression); |
| +} |
| + |
| +class NamedArgumentExpression extends ArgumentExpression { |
| + final String name; |
| + final Expression expression; |
| + |
| + NamedArgumentExpression(this.name, this.expression); |
| +} |
| + |
| +abstract class ArgumentValue { |
| + Value get value; |
| +} |
| + |
| +class PositionalArgumentValue extends ArgumentValue { |
| + final Value value; |
| + |
| + PositionalArgumentValue(this.value); |
| +} |
| + |
| +class NamedArgumentValue extends ArgumentValue { |
| + final String name; |
| + final Value value; |
| + |
| + NamedArgumentValue(this.name, this.value); |
| +} |
| + |
| +abstract class Continuation {} |
| + |
| +/// Represents the continuation called after the evaluation of argument |
| +/// expressions. |
| +abstract class ApplicationContinuation extends Continuation { |
| + Configuration call(List<ArgumentValue> args); |
| + |
| + /// Creates an environment binding actual argument values to formal parameters |
| + /// of the function in a new environment, which is used to execute the |
| + /// body od the function. |
| + static Environment createEnvironment( |
| + FunctionNode function, List<ArgumentValue> args) { |
| + Environment newEnv = new Environment.empty(); |
| + List<PositionalArgumentValue> positional = args.reversed |
| + .where((ArgumentValue av) => av is PositionalArgumentValue) |
| + .toList(); |
| + |
| + // Add positional parameters. |
| + for (int i = 0; i < positional.length; ++i) { |
| + newEnv.expand(function.positionalParameters[i], positional[i].value); |
| + } |
| + |
| + Map<String, Value> named = new Map.fromIterable( |
| + args.where((ArgumentValue av) => av is NamedArgumentValue), |
| + key: (NamedArgumentValue av) => av.name, |
| + value: (NamedArgumentValue av) => av.value); |
| + |
| + // Add named parameters. |
| + for (VariableDeclaration v in function.namedParameters) { |
| + newEnv.expand(v, named[v.name.toString()]); |
| + } |
| + |
| + return newEnv; |
| + } |
| +} |
| + |
| +/// Represents the application continuation for static invocation. |
| +class StaticInvocationApplication extends ApplicationContinuation { |
| + final FunctionNode function; |
| + final ExpressionContinuation continuation; |
| + |
| + StaticInvocationApplication(this.function, this.continuation); |
| + |
| + Configuration call(List<ArgumentValue> args) { |
| + Environment functionEnv = |
| + ApplicationContinuation.createEnvironment(function, args); |
| + |
| + State bodyState = new State.initial() |
| + .withExpressionContinuation(continuation) |
| + .withConfiguration(new ExitConfiguration(continuation)) |
| + .withEnvironment(functionEnv); |
| + return new StatementConfiguration(function.body, bodyState); |
| + } |
| +} |
| + |
| +/// Represents the application continuation called after the evaluation of all |
| +/// argument expressions for an invocation. |
| +class ArgumentValueApplication extends ApplicationContinuation { |
| + final ArgumentValue value; |
| + final ApplicationContinuation applicationContinuation; |
| + |
| + ArgumentValueApplication(this.value, this.applicationContinuation); |
| + |
| + Configuration call(List<ArgumentValue> args) { |
| + args.add(value); |
| + return new ArgumentContinuationConfiguration(applicationContinuation, args); |
| + } |
| +} |
| + |
| /// Represents an expression continuation. |
| -abstract class ExpressionContinuation { |
| +abstract class ExpressionContinuation extends Continuation { |
| Configuration call(Value v); |
| } |
| @@ -422,137 +559,26 @@ class SetterContinuation extends ExpressionContinuation { |
| /// argument for function invocation. |
| /// TODO: Add checks for validation of arguments according to spec. |
| class ActualArgumentsContinuation extends ExpressionContinuation { |
| - final Arguments arguments; |
| - final FunctionNode functionNode; |
| + final ArgumentExpression currentArgument; |
| + final List<ArgumentExpression> arguments; |
| final Environment environment; |
| - final ExpressionContinuation continuation; |
| - |
| - final List<Value> _positional = <Value>[]; |
| - int _currentPositional = 0; |
| - final Map<String, Value> _named = <String, Value>{}; |
| - int _currentNamed = 0; |
| + final ApplicationContinuation applicationContinuation; |
| - ActualArgumentsContinuation( |
| - this.arguments, this.functionNode, this.environment, this.continuation); |
| + ActualArgumentsContinuation(this.currentArgument, this.arguments, |
| + this.environment, this.applicationContinuation); |
| Configuration call(Value v) { |
| - if (_currentPositional < arguments.positional.length) { |
| - _positional.add(v); |
| - _currentPositional++; |
| + ArgumentValue argumentValue; |
| + if (currentArgument is NamedArgumentExpression) { |
| + argumentValue = new NamedArgumentValue( |
| + (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
|
| } else { |
| - assert(_currentNamed < arguments.named.length); |
| - String name = arguments.named[_currentNamed].name; |
| - _named[name] = v; |
| - _currentNamed++; |
| - } |
| - |
| - return createCurrentConfiguration(); |
| - } |
| - |
| - Configuration createCurrentConfiguration() { |
| - // Next argument to evaluate is a provided positional argument. |
| - if (_currentPositional < arguments.positional.length) { |
| - return new ExpressionConfiguration( |
| - arguments.positional[_currentPositional], environment, this); |
| - } |
| - // Next argument to evaluate is a provided named argument. |
| - if (_currentNamed < arguments.named.length) { |
| - return new ExpressionConfiguration( |
| - arguments.named[_currentNamed].value, environment, this); |
| + assert(currentArgument is PositionalArgumentExpression); |
| + argumentValue = new PositionalArgumentValue(v); |
| } |
| - // TODO: check if the number of actual arguments is larger then the number |
| - // of required arguments and smaller then the number of formal arguments. |
| - |
| - return new OptionalArgumentsContinuation( |
| - _positional, _named, functionNode, environment, continuation) |
| - .createCurrentConfiguration(); |
| - } |
| -} |
| - |
| -class OptionalArgumentsContinuation extends ExpressionContinuation { |
| - final List<Value> positional; |
| - final Map<String, Value> named; |
| - final FunctionNode functionNode; |
| - final Environment environment; |
| - final ExpressionContinuation continuation; |
| - |
| - final Map<String, VariableDeclaration> _missingFormalNamed = |
| - <String, VariableDeclaration>{}; |
| - |
| - int _currentPositional; |
| - String _currentNamed; |
| - |
| - OptionalArgumentsContinuation(this.positional, this.named, this.functionNode, |
| - this.environment, this.continuation) { |
| - _currentPositional = positional.length; |
| - assert(_currentPositional >= functionNode.requiredParameterCount); |
| - |
| - for (VariableDeclaration vd in functionNode.namedParameters) { |
| - if (named[vd.name] == null) { |
| - _missingFormalNamed[vd.name] = vd; |
| - } |
| - } |
| - } |
| - |
| - Configuration call(Value v) { |
| - if (_currentPositional < functionNode.positionalParameters.length) { |
| - // Value is a optional positional argument |
| - positional.add(v); |
| - _currentPositional++; |
| - } else { |
| - // Value is a optional named argument. |
| - assert(named[_currentNamed] == null); |
| - named[_currentNamed] = v; |
| - } |
| - |
| - return createCurrentConfiguration(); |
| - } |
| - |
| - /// Creates the current configuration for the evaluation of invocation a |
| - /// function. |
| - Configuration createCurrentConfiguration() { |
| - if (_currentPositional < functionNode.positionalParameters.length) { |
| - // Next argument to evaluate is a missing positional argument. |
| - // Evaluate its initializer. |
| - return new ExpressionConfiguration( |
| - functionNode.positionalParameters[_currentPositional].initializer, |
| - environment, |
| - this); |
| - } |
| - if (named.length < functionNode.namedParameters.length) { |
| - // Next argument to evaluate is a missing named argument. |
| - // Evaluate its initializer. |
| - _currentNamed = _missingFormalNamed.keys.first; |
| - Expression initializer = _missingFormalNamed[_currentNamed].initializer; |
| - _missingFormalNamed.remove(_currentNamed); |
| - return new ExpressionConfiguration(initializer, environment, this); |
| - } |
| - |
| - Environment newEnv = _createEnvironment(); |
| - State bodyState = new State.initial() |
| - .withExpressionContinuation(continuation) |
| - .withConfiguration(new ExitConfiguration(continuation)) |
| - .withEnvironment(newEnv); |
| - |
| - return new StatementConfiguration(functionNode.body, bodyState); |
| - } |
| - |
| - /// Creates an environment binding actual argument values to formal parameters |
| - /// of the function in a new environment, which is used to execute the |
| - /// body od the function. |
| - Environment _createEnvironment() { |
| - Environment newEnv = new Environment.empty(); |
| - // Add positional parameters. |
| - for (int i = 0; i < positional.length; ++i) { |
| - newEnv.expand(functionNode.positionalParameters[i], positional[i]); |
| - } |
| - // Add named parameters. |
| - for (VariableDeclaration v in functionNode.namedParameters) { |
| - newEnv.expand(v, named[v.name.toString()]); |
| - } |
| - |
| - return newEnv; |
| + return new ArgumentsConfiguration(arguments, environment, |
| + new ArgumentValueApplication(argumentValue, applicationContinuation)); |
| } |
| } |
| @@ -788,6 +814,9 @@ class StatementExecuter extends StatementVisitor1<Configuration, State> { |
| statement.accept1(this, state); |
| Configuration eval(Expression expression, ExpressionConfiguration config) => |
| evaluator.eval(expression, config); |
| + Configuration evalArgs( |
| + List<ArgumentExpression> args, Environment env, Continuation cont) => |
| + evaluator.evalArgs(args, env, cont); |
| Configuration defaultStatement(Statement node, State state) { |
| throw notImplemented( |
| @@ -1110,3 +1139,43 @@ class NullValue extends LiteralValue { |
| notImplemented({String m, Object obj}) { |
| throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| } |
| + |
| +// ------------------------------------------------------------------------ |
| +// INTERNAL FUNCTIONS |
| +// ------------------------------------------------------------------------ |
| +/// Creates a list of all argument expressions to be evaluated for the |
| +/// invocation of the provided [FunctionNode] containing the actual arguments |
| +/// and the optional argument initializers. |
| +List<ArgumentExpression> _createArgumentExpressionList( |
| + Arguments providedArgs, FunctionNode fun) { |
| + List<ArgumentExpression> args = <ArgumentExpression>[]; |
| + // Add positional arguments expressions. |
| + args.addAll(providedArgs.positional |
| + .map((Expression e) => new PositionalArgumentExpression(e))); |
| + |
| + // Add optional positional argument initializers. |
| + for (int i = providedArgs.positional.length; |
| + i < fun.positionalParameters.length; |
| + i++) { |
| + args.add(new PositionalArgumentExpression( |
| + fun.positionalParameters[i].initializer)); |
| + } |
| + |
| + Map<String, NamedArgumentExpression> namedFormals = new Map.fromIterable( |
| + fun.namedParameters, |
| + key: (VariableDeclaration vd) => vd.name, |
| + value: (VariableDeclaration vd) => |
| + new NamedArgumentExpression(vd.name, vd.initializer)); |
| + |
| + // Add named expressions. |
| + for (int i = 0; i < providedArgs.named.length; i++) { |
| + var current = providedArgs.named[i]; |
| + args.add(new NamedArgumentExpression(current.name, current.value)); |
| + namedFormals.remove(current.name); |
| + } |
| + |
| + // Add missing optional named initializers. |
| + args.addAll(namedFormals.values); |
| + |
| + return args; |
| +} |