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

Side by Side 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 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 kernerl.interpreter; 4 library kernerl.interpreter;
5 5
6 import 'dart:collection';
7 import '../ast.dart'; 6 import '../ast.dart';
8 7
9 class NotImplemented { 8 class NotImplemented {
10 String message; 9 String message;
11 10
12 NotImplemented(this.message); 11 NotImplemented(this.message);
13 12
14 String toString() => message; 13 String toString() => message;
15 } 14 }
16 15
17 class Interpreter { 16 class Interpreter {
18 Program program; 17 Program program;
19 18
20 Interpreter(this.program); 19 Interpreter(this.program);
21 20
22 void evalProgram() { 21 void evalProgram() {
Kevin Millikin (Google) 2017/03/15 10:01:23 Program's don't produce values, and maybe we shoul
zhivkag 2017/03/15 11:48:52 Done.
23 assert(program.libraries.isEmpty); 22 assert(program.libraries.isEmpty);
24 Procedure mainMethod = program.mainMethod; 23 Procedure mainMethod = program.mainMethod;
25 Statement statementBlock = mainMethod.function.body; 24 Statement statementBlock = mainMethod.function.body;
26 // Evaluate only statement with one expression, ExpressionStatement, which 25 // 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.
27 // is StaticInvocation of the method print. 26 // BlockStatement.
28 if (statementBlock is Block) { 27 if (statementBlock is Block) {
29 Statement statement = statementBlock.statements.first; 28 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.
30 if (statement is ExpressionStatement) { 29 var env = new Environment.empty();
31 statement.expression.accept1(new ExpressionEval1(), 30
32 new ExpressionState(new HashMap<String, Object>())); 31 for (Statement s in statementBlock.statements) {
32 if (s is ExpressionStatement) {
33 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.
34 } else if (s is VariableDeclaration) {
35 env.expand(s, s.initializer.accept1(exprEval, env));
36 } else {
37 throw new NotImplemented('Evaluation for statement type '
38 '${s.runtimeType} is not implemented.');
39 }
33 } 40 }
34 } else { 41 } else {
35 throw new NotImplemented('Evaluation for statement type ' 42 throw new NotImplemented('Evaluation for statement type '
36 '${statementBlock.runtimeType} is not implemented'); 43 '${statementBlock.runtimeType} is not implemented.');
37 } 44 }
38 } 45 }
39 } 46 }
40 47
41 class InvalidExpressionError { 48 class InvalidExpressionError {
42 InvalidExpression expression; 49 InvalidExpression expression;
43 50
44 InvalidExpressionError(this.expression); 51 InvalidExpressionError(this.expression);
45 52
46 String toString() => 'Invalid expression at ' 53 String toString() =>
47 '${expression.location.toString()}'; 54 'Invalid expression at ${expression.location.toString()}';
48 } 55 }
49 56
50 class ExpressionState { 57 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.
51 Map<String, Object> environment; 58 final VariableDeclaration variable;
59 Value value;
52 60
53 ExpressionState(this.environment); 61 Binding(this.variable, this.value);
54 } 62 }
55 63
56 class ExpressionEval1 extends ExpressionVisitor1<Object> { 64 class Environment {
57 @override 65 final List<Binding> bindings = <Binding>[];
58 Object defaultExpression(Expression node, arg) { 66 Environment parent;
Kevin Millikin (Google) 2017/03/15 10:01:24 final Environment parent;
zhivkag 2017/03/15 11:48:52 Done.
67
68 Environment.empty();
69 Environment(this.parent);
70
71 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.
72 for (Binding b in bindings) {
73 if (b.variable == variable) return b;
74 }
75 return null;
76 }
77
78 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.
79 return lookupBinding(variable)?.value ??
80 parent?.lookup(variable) ??
81 error(variable);
82 }
83
84 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.
85 var b = lookupBinding(variable);
86 if (b != null) {
87 b.value = value;
88 } else if (parent != null) {
89 parent.assign(variable, value);
90 } else {
91 error(variable);
92 }
93 }
94
95 void expand(VariableDeclaration variable, Value value) {
96 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.
97 error(variable);
98 }
99 bindings.add(new Binding(variable, value));
100 }
101 }
102
103 class ExpressionEval extends ExpressionVisitor1<Value> {
Kevin Millikin (Google) 2017/03/15 10:01:24 class Evaluator?
zhivkag 2017/03/15 11:48:52 Done.
104 Value defaultExpression(Expression node, arg) {
59 throw new NotImplemented('Evaluation for expressions of type ' 105 throw new NotImplemented('Evaluation for expressions of type '
60 '${node.runtimeType} is not implemented.'); 106 '${node.runtimeType} is not implemented.');
61 } 107 }
62 108
63 Object visitInvalidExpression1(InvalidExpression node, arg) => 109 Value visitInvalidExpression1(InvalidExpression node, arg) {
64 throw new InvalidExpressionError(node); 110 throw new InvalidExpressionError(node);
111 }
65 112
66 Object visitStaticInvocation(StaticInvocation node, arg) { 113 Value visitVariableGet(VariableGet node, arg) {
Kevin Millikin (Google) 2017/03/15 10:01:24 arg ==> env.
zhivkag 2017/03/15 11:48:53 Done.
114 return arg.lookup(node.variable);
115 }
116
117 Value visitVariableSet(VariableSet node, arg) {
118 return arg.assign(node.variable, node.value.accept1(this, arg));
119 }
120
121 Value visitStaticInvocation(StaticInvocation node, arg) {
67 if ('print' == node.name.toString()) { 122 if ('print' == node.name.toString()) {
68 // Special evaluation of print. 123 // Special evaluation of print.
69 var res = node.arguments.positional[0].accept1(this, arg); 124 var res = node.arguments.positional[0].accept1(this, arg);
70 print(res); 125 print(res.value);
126 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.
71 } else { 127 } else {
72 throw new NotImplemented('Support for statement type ' 128 throw new NotImplemented('Support for statement type '
73 '${node.runtimeType} is not implemented'); 129 '${node.runtimeType} is not implemented');
74 } 130 }
75 } 131 }
76 132
133 Value visitNot(Not node, arg) {
134 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.
135 }
136
137 Value visitLogicalExpression(LogicalExpression node, arg) {
138 bool left = node.left.accept1(this, arg).asBool;
139
140 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.
141 return left
142 ? new BoolValue(true)
143 : new BoolValue(node.right.accept1(this, arg).asBool);
144 } else {
145 assert('&&' == node.operator);
146 return !left
147 ? new BoolValue(false)
148 : new BoolValue(node.right.accept1(this, arg).asBool);
149 }
150 }
151
152 Value visitConditionalExpression(ConditionalExpression node, arg) {
153 if (node.condition.accept1(this, arg).asBool) {
154 return node.then.accept1(this, arg);
155 } else {
156 return node.otherwise.accept1(this, arg);
157 }
158 }
159
160 Value visitStringConcatenation(StringConcatenation node, arg) {
161 StringBuffer res = new StringBuffer();
162 for (Expression e in node.expressions) {
163 res.write(e.accept1(this, arg).value);
164 }
165 return new StringValue(res.toString());
166 }
167
77 // Evaluation of BasicLiterals. 168 // Evaluation of BasicLiterals.
78 Object visitStringLiteral(StringLiteral node, arg) => node.value; 169 Value visitStringLiteral(StringLiteral node, arg) =>
79 Object visitIntLiteral(IntLiteral node, arg) => node.value; 170 new StringValue(node.value);
80 Object visitDoubleLiteral(DoubleLiteral node, arg) => node.value; 171 Value visitIntLiteral(IntLiteral node, arg) => new IntValue(node.value);
81 Object visitBoolLiteral(BoolLiteral node, arg) => node.value; 172 Value visitDoubleLiteral(DoubleLiteral node, arg) =>
82 Object visitNullLiteral(NullLiteral node, arg) => node.value; 173 new DoubleValue(node.value);
174 Value visitBoolLiteral(BoolLiteral node, arg) => new BoolValue(node.value);
175 Value visitNullLiteral(NullLiteral node, arg) => new NullValue();
176
177 Value visitLet(Let node, arg) {
178 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.
179 letEnv.expand(node.variable, node.variable.initializer.accept1(this, arg));
180 return node.body.accept1(this, letEnv);
181 }
83 } 182 }
183
184 abstract class Value {
185 Object get value;
186 bool get asBool;
187 }
188
189 class StringValue extends Value {
190 String value;
191
192 bool get asBool => false;
193
194 StringValue(this.value);
195 }
196
197 class IntValue extends Value {
198 int value;
199
200 bool get asBool => false;
201
202 IntValue(this.value);
203 }
204
205 class DoubleValue extends Value {
206 double value;
207
208 bool get asBool => false;
209
210 DoubleValue(this.value);
211 }
212
213 class BoolValue extends Value {
214 bool value;
215
216 bool get asBool => value;
217
218 BoolValue(this.value);
219 }
220
221 class NullValue extends Value {
222 Object get value => null;
223 bool get asBool => false;
224 }
225
226 Object error(obj) {
227 // TODO: Implement accordingly with support for error handling.
228 throw new ArgumentError(obj);
229 }
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