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

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

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

Powered by Google App Engine
This is Rietveld 408576698