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

Unified Diff: pkg/kernel/lib/interpreter/interpreter.dart

Issue 2740433006: Implement support for variables and evaluation of logic expressions (Closed)
Patch Set: Refactor Created 3 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/kernel/lib/interpreter/interpreter.dart
diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart
index f4f87794487782fad8e299b6762d142050ce8dcd..c0e7038b2f7954690fa3a2ac17196b41a0a42240 100644
--- a/pkg/kernel/lib/interpreter/interpreter.dart
+++ b/pkg/kernel/lib/interpreter/interpreter.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
library kernerl.interpreter;
-import 'dart:collection';
import '../ast.dart';
class NotImplemented {
@@ -23,17 +22,25 @@ class Interpreter {
assert(program.libraries.isEmpty);
Procedure mainMethod = program.mainMethod;
Statement statementBlock = mainMethod.function.body;
- // Evaluate only statement with one expression, ExpressionStatement, which
- // is StaticInvocation of the method print.
+ // Evaluates only ExpressionStatements and VariableDeclarations in the top
Kevin Millikin (Google) 2017/03/15 10:01:23 Evaluates ==> Executes.
zhivkag 2017/03/15 11:48:53 Done.
+ // BlockStatement.
if (statementBlock is Block) {
- Statement statement = statementBlock.statements.first;
- if (statement is ExpressionStatement) {
- statement.expression.accept1(new ExpressionEval1(),
- new ExpressionState(new HashMap<String, Object>()));
+ var exprEval = new ExpressionEval();
Kevin Millikin (Google) 2017/03/15 10:01:24 So far ExpressionEval doesn't have any state, so I
zhivkag 2017/03/15 11:48:53 Done.
+ var env = new Environment.empty();
+
+ for (Statement s in statementBlock.statements) {
+ if (s is ExpressionStatement) {
+ s.expression.accept1(exprEval, env);
Kevin Millikin (Google) 2017/03/15 10:01:23 It reads more nicely to have a method Value eval(
zhivkag 2017/03/15 11:48:52 Done.
+ } else if (s is VariableDeclaration) {
+ env.expand(s, s.initializer.accept1(exprEval, env));
+ } else {
+ throw new NotImplemented('Evaluation for statement type '
+ '${s.runtimeType} is not implemented.');
+ }
}
} else {
throw new NotImplemented('Evaluation for statement type '
- '${statementBlock.runtimeType} is not implemented');
+ '${statementBlock.runtimeType} is not implemented.');
}
}
}
@@ -43,41 +50,180 @@ class InvalidExpressionError {
InvalidExpressionError(this.expression);
- String toString() => 'Invalid expression at '
- '${expression.location.toString()}';
+ String toString() =>
+ 'Invalid expression at ${expression.location.toString()}';
}
-class ExpressionState {
- Map<String, Object> environment;
+class Binding {
Kevin Millikin (Google) 2017/03/15 10:01:24 Ultimately we should have really detailed comments
zhivkag 2017/03/15 11:48:53 Acknowledged.
+ final VariableDeclaration variable;
+ Value value;
- ExpressionState(this.environment);
+ Binding(this.variable, this.value);
}
-class ExpressionEval1 extends ExpressionVisitor1<Object> {
- @override
- Object defaultExpression(Expression node, arg) {
+class Environment {
+ final List<Binding> bindings = <Binding>[];
+ Environment parent;
Kevin Millikin (Google) 2017/03/15 10:01:24 final Environment parent;
zhivkag 2017/03/15 11:48:52 Done.
+
+ Environment.empty();
+ Environment(this.parent);
+
+ Binding lookupBinding(VariableDeclaration variable) {
Kevin Millikin (Google) 2017/03/15 10:01:23 I'd make this the recursive function (and never re
zhivkag 2017/03/15 11:48:52 Done.
+ for (Binding b in bindings) {
+ if (b.variable == variable) return b;
+ }
+ return null;
+ }
+
+ Value lookup(VariableDeclaration variable) {
Kevin Millikin (Google) 2017/03/15 10:01:23 Then this is: return lookupBinding(variable).valu
zhivkag 2017/03/15 11:48:52 Done.
+ return lookupBinding(variable)?.value ??
+ parent?.lookup(variable) ??
+ error(variable);
+ }
+
+ void assign(VariableDeclaration variable, Value value) {
Kevin Millikin (Google) 2017/03/15 10:01:23 And this is: lookupBinding(variable).value = valu
zhivkag 2017/03/15 11:48:53 Done.
+ var b = lookupBinding(variable);
+ if (b != null) {
+ b.value = value;
+ } else if (parent != null) {
+ parent.assign(variable, value);
+ } else {
+ error(variable);
+ }
+ }
+
+ void expand(VariableDeclaration variable, Value value) {
+ if (lookupBinding(variable) != null) {
Kevin Millikin (Google) 2017/03/15 10:01:23 Variable declarations should be unique. We could
zhivkag 2017/03/15 11:48:52 Done.
+ error(variable);
+ }
+ bindings.add(new Binding(variable, value));
+ }
+}
+
+class ExpressionEval extends ExpressionVisitor1<Value> {
Kevin Millikin (Google) 2017/03/15 10:01:24 class Evaluator?
zhivkag 2017/03/15 11:48:52 Done.
+ Value defaultExpression(Expression node, arg) {
throw new NotImplemented('Evaluation for expressions of type '
'${node.runtimeType} is not implemented.');
}
- Object visitInvalidExpression1(InvalidExpression node, arg) =>
- throw new InvalidExpressionError(node);
+ Value visitInvalidExpression1(InvalidExpression node, arg) {
+ throw new InvalidExpressionError(node);
+ }
+
+ Value visitVariableGet(VariableGet node, arg) {
Kevin Millikin (Google) 2017/03/15 10:01:24 arg ==> env.
zhivkag 2017/03/15 11:48:53 Done.
+ return arg.lookup(node.variable);
+ }
- Object visitStaticInvocation(StaticInvocation node, arg) {
+ Value visitVariableSet(VariableSet node, arg) {
+ return arg.assign(node.variable, node.value.accept1(this, arg));
+ }
+
+ Value visitStaticInvocation(StaticInvocation node, arg) {
if ('print' == node.name.toString()) {
// Special evaluation of print.
var res = node.arguments.positional[0].accept1(this, arg);
- print(res);
+ print(res.value);
+ return null;
Kevin Millikin (Google) 2017/03/15 10:01:23 Not null, but new NullValue(). We should make can
zhivkag 2017/03/15 11:48:52 Acknowledged.
} else {
throw new NotImplemented('Support for statement type '
'${node.runtimeType} is not implemented');
}
}
+ Value visitNot(Not node, arg) {
+ return new BoolValue(!node.operand.accept1(this, arg).asBool);
Kevin Millikin (Google) 2017/03/15 10:01:23 I think I'd do the boolean conversion a little dif
zhivkag 2017/03/15 11:48:53 Acknowledged.
+ }
+
+ Value visitLogicalExpression(LogicalExpression node, arg) {
+ bool left = node.left.accept1(this, arg).asBool;
+
+ if ('||' == node.operator) {
Kevin Millikin (Google) 2017/03/15 10:01:24 We might want a more literal interpretation of the
zhivkag 2017/03/15 11:48:52 Acknowledged.
+ return left
+ ? new BoolValue(true)
+ : new BoolValue(node.right.accept1(this, arg).asBool);
+ } else {
+ assert('&&' == node.operator);
+ return !left
+ ? new BoolValue(false)
+ : new BoolValue(node.right.accept1(this, arg).asBool);
+ }
+ }
+
+ Value visitConditionalExpression(ConditionalExpression node, arg) {
+ if (node.condition.accept1(this, arg).asBool) {
+ return node.then.accept1(this, arg);
+ } else {
+ return node.otherwise.accept1(this, arg);
+ }
+ }
+
+ Value visitStringConcatenation(StringConcatenation node, arg) {
+ StringBuffer res = new StringBuffer();
+ for (Expression e in node.expressions) {
+ res.write(e.accept1(this, arg).value);
+ }
+ return new StringValue(res.toString());
+ }
+
// Evaluation of BasicLiterals.
- Object visitStringLiteral(StringLiteral node, arg) => node.value;
- Object visitIntLiteral(IntLiteral node, arg) => node.value;
- Object visitDoubleLiteral(DoubleLiteral node, arg) => node.value;
- Object visitBoolLiteral(BoolLiteral node, arg) => node.value;
- Object visitNullLiteral(NullLiteral node, arg) => node.value;
+ Value visitStringLiteral(StringLiteral node, arg) =>
+ new StringValue(node.value);
+ Value visitIntLiteral(IntLiteral node, arg) => new IntValue(node.value);
+ Value visitDoubleLiteral(DoubleLiteral node, arg) =>
+ new DoubleValue(node.value);
+ Value visitBoolLiteral(BoolLiteral node, arg) => new BoolValue(node.value);
+ Value visitNullLiteral(NullLiteral node, arg) => new NullValue();
+
+ Value visitLet(Let node, arg) {
+ var letEnv = new Environment(arg);
Kevin Millikin (Google) 2017/03/15 10:01:23 It might be more clear to name the value instead o
zhivkag 2017/03/15 11:48:52 Acknowledged.
+ letEnv.expand(node.variable, node.variable.initializer.accept1(this, arg));
+ return node.body.accept1(this, letEnv);
+ }
+}
+
+abstract class Value {
+ Object get value;
+ bool get asBool;
+}
+
+class StringValue extends Value {
+ String value;
+
+ bool get asBool => false;
+
+ StringValue(this.value);
+}
+
+class IntValue extends Value {
+ int value;
+
+ bool get asBool => false;
+
+ IntValue(this.value);
+}
+
+class DoubleValue extends Value {
+ double value;
+
+ bool get asBool => false;
+
+ DoubleValue(this.value);
+}
+
+class BoolValue extends Value {
+ bool value;
+
+ bool get asBool => value;
+
+ BoolValue(this.value);
+}
+
+class NullValue extends Value {
+ Object get value => null;
+ bool get asBool => false;
+}
+
+Object error(obj) {
+ // TODO: Implement accordingly with support for error handling.
+ throw new ArgumentError(obj);
}
« 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