| Index: frog/analyze_frame.dart
|
| diff --git a/frog/analyze_frame.dart b/frog/analyze_frame.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0f88ef3654876d02bcae0ad4b0e68a5535eb31d2
|
| --- /dev/null
|
| +++ b/frog/analyze_frame.dart
|
| @@ -0,0 +1,169 @@
|
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +class CallFrame implements CallingContext {
|
| + CallFrame enclosingFrame;
|
| +
|
| + MethodAnalyzer analyzer;
|
| +
|
| + MemberSet findMembers(String name) => library._findMembers(name);
|
| + CounterLog get counters() => world.counters;
|
| + Library get library() => method.library;
|
| + MethodMember method;
|
| +
|
| + bool get needsCode() => false;
|
| + bool get showWarnings() => true;
|
| +
|
| + // TODO(jimhug): Shouldn't need these 5 methods below.
|
| + String _makeThisCode() => null;
|
| +
|
| + Value getTemp(Value value) => null;
|
| + VariableValue forceTemp(Value value) => null;
|
| + Value assignTemp(Value tmp, Value v) => null;
|
| + void freeTemp(VariableValue value) => null;
|
| +
|
| + bool get isStatic() =>
|
| + enclosingFrame != null ? enclosingFrame.isStatic : method.isStatic;
|
| +
|
| + Value thisValue;
|
| + Arguments args;
|
| +
|
| + List<VariableSlot> _slots;
|
| + VariableSlot _returnSlot;
|
| +
|
| + AnalyzeScope _scope;
|
| +
|
| +
|
| + CallFrame(this.analyzer, this.method, this.thisValue, this.args,
|
| + this.enclosingFrame) {
|
| + _slots = [];
|
| + _scope = new AnalyzeScope(null, this, analyzer.body);
|
| +
|
| + _returnSlot = new VariableSlot(_scope, 'return', method.returnType,
|
| + analyzer.body, false);
|
| +
|
| + }
|
| +
|
| + void pushBlock(Node node) {
|
| + _scope = new AnalyzeScope(_scope, this, node);
|
| + }
|
| +
|
| + void popBlock(Node node) {
|
| + if (_scope.node != node) {
|
| + world.internalError('incorrect pop', node.span, _scope.node.span);
|
| + }
|
| + _scope = _scope.parent;
|
| + }
|
| +
|
| + Value getReturnValue() {
|
| + return _returnSlot.get();
|
| + }
|
| +
|
| + void returns(Value value) {
|
| + _returnSlot.set(value);
|
| + }
|
| +
|
| + VariableSlot lookup(String name) {
|
| + var slot = _scope._lookup(name);
|
| + if (slot == null && enclosingFrame != null) {
|
| + return enclosingFrame.lookup(name);
|
| + }
|
| + return slot;
|
| + }
|
| +
|
| + VariableSlot create(String name, Type staticType, Node node, bool isFinal,
|
| + Value value) {
|
| + // TODO(jimhug): Save mapping from node -> Slot.
|
| +
|
| + final slot = new VariableSlot(_scope, name, staticType, node, isFinal,
|
| + value);
|
| + final existingSlot = _scope._lookup(name);
|
| + if (existingSlot !== null) {
|
| + if (existingSlot.scope == this) {
|
| + world.error('duplicate name "$name"', node.span);
|
| + } else {
|
| + // TODO(jimhug): Confirm that we can enable this useful warning.
|
| + //world.warning('"$name" shadows variable from enclosing scope',
|
| + // node.span);
|
| + }
|
| + }
|
| + _slots.add(slot);
|
| + _scope._slots.add(slot);
|
| + }
|
| +
|
| + VariableSlot declareParameter(Parameter p, Value value) {
|
| + return create(p.name, p.type, p.definition, false, value);
|
| + }
|
| +
|
| + _makeValue(Type type, Node node) {
|
| + return new PureStaticValue(type, node == null ? null : node.span);
|
| + }
|
| +
|
| +
|
| + Value makeSuperValue(Node node) {
|
| + return _makeValue(thisValue.type.parent, node);
|
| + }
|
| +
|
| + Value makeThisValue(Node node) {
|
| + return _makeValue(thisValue.type, node);
|
| + }
|
| +
|
| +
|
| + void dump() {
|
| + print('**********${method.declaringType.name}.${method.name}***********');
|
| + for (var slot in _slots) {
|
| + print(slot);
|
| + }
|
| + print(_returnSlot);
|
| + }
|
| +}
|
| +
|
| +class VariableSlot {
|
| + AnalyzeScope scope;
|
| + final String name;
|
| + Type staticType;
|
| + Node node;
|
| + bool isFinal;
|
| + Value value;
|
| +
|
| + VariableSlot(this.scope, this.name, this.staticType, this.node,
|
| + this.isFinal, [this.value]);
|
| +
|
| + Value get() {
|
| + return scope.frame._makeValue(staticType, null);
|
| + }
|
| +
|
| + void set(Value newValue) {
|
| + if (value == null) value = newValue;
|
| + else value = Value.union(value, newValue);
|
| + // TODO(jimhug): Add type checks.
|
| + }
|
| +
|
| + String toString() {
|
| + var valueString = value !== null ? ' = ${value.type.name}' : '';
|
| + return '${this.staticType.name} ${this.name}${valueString}';
|
| + }
|
| +}
|
| +
|
| +class AnalyzeScope {
|
| + CallFrame frame;
|
| + AnalyzeScope parent;
|
| +
|
| + /** Tracks the node that this scope is associated with, for debugging */
|
| + Node node;
|
| +
|
| + List<VariableSlot> _slots;
|
| +
|
| + AnalyzeScope(this.parent, this.frame, this.node): _slots = [];
|
| +
|
| + VariableSlot _lookup(String name) {
|
| + for (var s = this; s != null; s = s.parent) {
|
| + for (int i = 0; i < s._slots.length; i++) {
|
| + final ret = s._slots[i];
|
| + if (ret.name == name) return ret;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +}
|
|
|