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

Unified Diff: frog/value.dart

Issue 9146001: continued cleanup of initialization and Value (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: touchups to comments Created 8 years, 11 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
Index: frog/value.dart
diff --git a/frog/value.dart b/frog/value.dart
index 9f8a46217c14d062d2a9a2148d15a3b2f95f2285..d557b8e596efbdef17e58376431896f1cacce570 100644
--- a/frog/value.dart
+++ b/frog/value.dart
@@ -56,12 +56,24 @@ class Value {
if (_type == null) world.internalError('type passed as null', span);
}
+ Value union(Value other) {
+ // TODO(jimhug): What the hell is right here?
+ if (this == other) return this;
+ world.internalError('not yet ready for union');
+ }
+
/** Is this value a constant expression? */
bool get isConst() => false;
/** If [isConst], the [EvaluatedValue] that defines this value. */
EvaluatedValue get constValue() => null;
+ // TODO(jimhug): remove once type system works better.
+ setField(Member field, Value value, [bool duringInit = false]) { }
+
+ // Nothing to do in general?
+ validateInitialized(SourceSpan span) { }
+
// TODO(jimhug): Fix these names once get/set are truly pseudo-keywords.
// See issue #379.
Value get_(MethodGenerator context, String name, Node node) {
@@ -85,6 +97,23 @@ class Value {
}
}
+ Value unop(int kind, MethodGenerator context, var node) {
+ switch (kind) {
+ case TokenKind.NOT:
+ // TODO(jimhug): Issue #359 seeks to clarify this behavior.
+ var newVal = convertTo(context, world.nonNullBool);
+ return new Value(newVal.type, '!${newVal.code}', node.span);
+ case TokenKind.ADD:
+ world.error('no unary add operator in dart', node.span);
+ break;
+ case TokenKind.SUB:
+ return invoke(context, ':negate', node, Arguments.EMPTY);
+ case TokenKind.BIT_NOT:
+ return invoke(context, ':bit_not', node, Arguments.EMPTY);
+ }
+ world.internalError('unimplemented: ${node.op}', node.span);
+ }
+
Value binop(int kind, Value other, MethodGenerator context, var node) {
switch (kind) {
case TokenKind.AND:
@@ -544,7 +573,7 @@ function \$assert_${toType.name}(x) {
}
-// rename to PrimitiveValue
+// TODO(jimhug): rename to PrimitiveValue and refactor further
class EvaluatedValue extends Value implements Hashable {
/** Is this value treated as const by dart language? */
bool isConst;
@@ -556,7 +585,7 @@ class EvaluatedValue extends Value implements Hashable {
EvaluatedValue get constValue() => this;
- // TODO(jimhug): Using computed code here with caching is major perf fear.
+ // TODO(jimhug): Using computed code here without caching is major fear.
int hashCode() => code.hashCode();
bool operator ==(var other) {
@@ -565,6 +594,7 @@ class EvaluatedValue extends Value implements Hashable {
}
}
+
class NullValue extends EvaluatedValue {
NullValue(bool isConst, SourceSpan span):
super(isConst, world.varType, span);
@@ -574,19 +604,19 @@ class NullValue extends EvaluatedValue {
String get code() => 'null';
Value binop(int kind, var other, MethodGenerator context, var node) {
- // TODO(jimhug): Support int/double better
- if (other is! ListValue) return super.binop(kind, other, context, node);
+ if (other is! NullValue) return super.binop(kind, other, context, node);
+ final c = isConst && other.isConst;
+ final s = node.span;
switch (kind) {
case TokenKind.EQ_STRICT:
- return new BoolValue(type == other.type && code == other.code,
- isConst && other.isConst, node.span);
+ case TokenKind.EQ:
+ return new BoolValue(true, c, s);
case TokenKind.NE_STRICT:
- return new BoolValue(type != other.type || code != other.code,
- isConst && other.isConst, node.span);
+ case TokenKind.NE:
+ return new BoolValue(false, c, s);
}
- // TODO(jimhug): Will flesh out ops here!
return super.binop(kind, other, context, node);
}
}
@@ -599,25 +629,33 @@ class BoolValue extends EvaluatedValue {
String get code() => actualValue ? 'true' : 'false';
+ Value unop(int kind, MethodGenerator context, var node) {
+ switch (kind) {
+ case TokenKind.NOT:
+ return new BoolValue(!actualValue, isConst, node.span);
+ }
+ return super.unop(kind, context, node);
+ }
+
Value binop(int kind, var other, MethodGenerator context, var node) {
if (other is! BoolValue) return super.binop(kind, other, context, node);
+ final c = isConst && other.isConst;
+ final s = node.span;
+ bool x = actualValue, y = other.actualValue;
switch (kind) {
- case TokenKind.AND:
- return new BoolValue(actualValue && other.actualValue,
- isConst && other.isConst, node.span);
- case TokenKind.OR:
- return new BoolValue(actualValue || other.actualValue,
- isConst && other.isConst, node.span);
case TokenKind.EQ_STRICT:
- return new BoolValue(actualValue == other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
case TokenKind.NE_STRICT:
- return new BoolValue(actualValue != other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+ case TokenKind.AND:
+ return new BoolValue(x && y, c, s);
+ case TokenKind.OR:
+ return new BoolValue(x || y, c, s);
}
- // TODO(jimhug): Could handle more ops here, but does it matter?
return super.binop(kind, other, context, node);
}
}
@@ -631,20 +669,102 @@ class IntValue extends EvaluatedValue {
// TODO(jimhug): Only add parens when needed.
String get code() => '(${actualValue})';
- Value binop(int kind, var other, MethodGenerator context, var node) {
- // TODO(jimhug): Support int/double better
- if (other is! IntValue) return super.binop(kind, other, context, node);
-
+ Value unop(int kind, MethodGenerator context, var node) {
switch (kind) {
- case TokenKind.EQ_STRICT:
- return new BoolValue(actualValue == other.actualValue,
- isConst && other.isConst, node.span);
- case TokenKind.NE_STRICT:
- return new BoolValue(actualValue != other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.ADD:
+ // This is allowed on numeric constants only
+ return new IntValue(actualValue, isConst, span);
+ case TokenKind.SUB:
+ return new IntValue(-actualValue, isConst, span);
+ case TokenKind.BIT_NOT:
+ return new IntValue(~actualValue, isConst, span);
+ }
+ return super.unop(kind, context, node);
+ }
+
+
+ Value binop(int kind, var other, MethodGenerator context, var node) {
+ final c = isConst && other.isConst;
+ final s = node.span;
+ if (other is IntValue) {
+ int x = actualValue;
+ int y = other.actualValue;
+ switch (kind) {
+ case TokenKind.EQ_STRICT:
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
+ case TokenKind.NE_STRICT:
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+
+ case TokenKind.BIT_OR:
+ return new IntValue(x | y, c, s);
+ case TokenKind.BIT_XOR:
+ return new IntValue(x ^ y, c, s);
+ case TokenKind.BIT_AND:
+ return new IntValue(x & y, c, s);
+ case TokenKind.SHL:
+ return new IntValue(x << y, c, s);
+ case TokenKind.SAR:
+ return new IntValue(x >> y, c, s);
+ case TokenKind.SHR:
+ return new IntValue(x >>> y, c, s);
+ case TokenKind.ADD:
+ return new IntValue(x + y, c, s);
+ case TokenKind.SUB:
+ return new IntValue(x - y, c, s);
+ case TokenKind.MUL:
+ return new IntValue(x * y, c, s);
+ case TokenKind.DIV:
+ return new DoubleValue(x / y, c, s);
+ case TokenKind.TRUNCDIV:
+ return new IntValue(x ~/ y, c, s);
+ case TokenKind.MOD:
+ return new IntValue(x % y, c, s);
+ case TokenKind.LT:
+ return new BoolValue(x < y, c, s);
+ case TokenKind.GT:
+ return new BoolValue(x > y, c, s);
+ case TokenKind.LTE:
+ return new BoolValue(x <= y, c, s);
+ case TokenKind.GTE:
+ return new BoolValue(x >= y, c, s);
+ }
+ } else if (other is DoubleValue) {
+ int x = actualValue;
+ double y = other.actualValue;
+ switch (kind) {
+ case TokenKind.EQ_STRICT:
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
+ case TokenKind.NE_STRICT:
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+
+ case TokenKind.ADD:
+ return new DoubleValue(x + y, c, s);
+ case TokenKind.SUB:
+ return new DoubleValue(x - y, c, s);
+ case TokenKind.MUL:
+ return new DoubleValue(x * y, c, s);
+ case TokenKind.DIV:
+ return new DoubleValue(x / y, c, s);
+ case TokenKind.TRUNCDIV:
+ // TODO(jimhug): I expected int, but corelib says double here...
+ return new DoubleValue(x ~/ y, c, s);
+ case TokenKind.MOD:
+ return new DoubleValue(x % y, c, s);
+ case TokenKind.LT:
+ return new BoolValue(x < y, c, s);
+ case TokenKind.GT:
+ return new BoolValue(x > y, c, s);
+ case TokenKind.LTE:
+ return new BoolValue(x <= y, c, s);
+ case TokenKind.GTE:
+ return new BoolValue(x >= y, c, s);
+ }
}
- // TODO(jimhug): Will flesh out ops here!
return super.binop(kind, other, context, node);
}
}
@@ -657,20 +777,88 @@ class DoubleValue extends EvaluatedValue {
String get code() => '(${actualValue})';
- Value binop(int kind, var other, MethodGenerator context, var node) {
- // TODO(jimhug): Support int/double better
- if (other is! DoubleValue) return super.binop(kind, other, context, node);
-
+ Value unop(int kind, MethodGenerator context, var node) {
switch (kind) {
- case TokenKind.EQ_STRICT:
- return new BoolValue(actualValue == other.actualValue,
- isConst && other.isConst, node.span);
- case TokenKind.NE_STRICT:
- return new BoolValue(actualValue != other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.ADD:
+ // This is allowed on numeric constants only
+ return new DoubleValue(actualValue, isConst, span);
+ case TokenKind.SUB:
+ return new DoubleValue(-actualValue, isConst, span);
+ }
+ return super.unop(kind, context, node);
+ }
+
+ Value binop(int kind, var other, MethodGenerator context, var node) {
+ final c = isConst && other.isConst;
+ final s = node.span;
+ if (other is DoubleValue) {
+ double x = actualValue;
+ double y = other.actualValue;
+ switch (kind) {
+ case TokenKind.EQ_STRICT:
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
+ case TokenKind.NE_STRICT:
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+
+ case TokenKind.ADD:
+ return new DoubleValue(x + y, c, s);
+ case TokenKind.SUB:
+ return new DoubleValue(x - y, c, s);
+ case TokenKind.MUL:
+ return new DoubleValue(x * y, c, s);
+ case TokenKind.DIV:
+ return new DoubleValue(x / y, c, s);
+ case TokenKind.TRUNCDIV:
+ // TODO(jimhug): I expected int, but corelib says double here...
+ return new DoubleValue(x ~/ y, c, s);
+ case TokenKind.MOD:
+ return new DoubleValue(x % y, c, s);
+ case TokenKind.LT:
+ return new BoolValue(x < y, c, s);
+ case TokenKind.GT:
+ return new BoolValue(x > y, c, s);
+ case TokenKind.LTE:
+ return new BoolValue(x <= y, c, s);
+ case TokenKind.GTE:
+ return new BoolValue(x >= y, c, s);
+ }
+ } else if (other is IntValue) {
+ double x = actualValue;
+ int y = other.actualValue;
+ switch (kind) {
+ case TokenKind.EQ_STRICT:
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
+ case TokenKind.NE_STRICT:
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+
+ case TokenKind.ADD:
+ return new DoubleValue(x + y, c, s);
+ case TokenKind.SUB:
+ return new DoubleValue(x - y, c, s);
+ case TokenKind.MUL:
+ return new DoubleValue(x * y, c, s);
+ case TokenKind.DIV:
+ return new DoubleValue(x / y, c, s);
+ case TokenKind.TRUNCDIV:
+ // TODO(jimhug): I expected int, but corelib says double here...
+ return new DoubleValue(x ~/ y, c, s);
+ case TokenKind.MOD:
+ return new DoubleValue(x % y, c, s);
+ case TokenKind.LT:
+ return new BoolValue(x < y, c, s);
+ case TokenKind.GT:
+ return new BoolValue(x > y, c, s);
+ case TokenKind.LTE:
+ return new BoolValue(x <= y, c, s);
+ case TokenKind.GTE:
+ return new BoolValue(x >= y, c, s);
+ }
}
- // TODO(jimhug): Will flesh out ops here!
return super.binop(kind, other, context, node);
}
}
@@ -682,19 +870,22 @@ class StringValue extends EvaluatedValue {
super(isConst, world.stringType, span);
Value binop(int kind, var other, MethodGenerator context, var node) {
- // TODO(jimhug): Support int/double better
if (other is! StringValue) return super.binop(kind, other, context, node);
+ final c = isConst && other.isConst;
+ final s = node.span;
+ String x = actualValue, y = other.actualValue;
switch (kind) {
case TokenKind.EQ_STRICT:
- return new BoolValue(actualValue == other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.EQ:
+ return new BoolValue(x == y, c, s);
case TokenKind.NE_STRICT:
- return new BoolValue(actualValue != other.actualValue,
- isConst && other.isConst, node.span);
+ case TokenKind.NE:
+ return new BoolValue(x != y, c, s);
+ case TokenKind.ADD:
+ return new StringValue(x + y, c, s);
}
- // TODO(jimhug): Will flesh out ops here!
return super.binop(kind, other, context, node);
}
@@ -827,24 +1018,84 @@ class MapValue extends EvaluatedValue {
class ObjectValue extends EvaluatedValue {
- Map<String, Value> fields;
+ Map<FieldMember, Value> fields;
+ bool seenNativeInitializer = false;
+
String _code;
- ObjectValue(this.fields, bool isConst, Type type, this._code, SourceSpan span):
- super(isConst, type, span);
+ ObjectValue(bool isConst, Type type, SourceSpan span):
+ fields = {}, super(isConst, type, span);
String get code() {
+ if (_code === null) validateInitialized(null);
return _code;
}
+ initFields() {
+ var allMembers = world.gen._orderValues(type.getAllMembers());
+ for (var f in allMembers) {
+ if (f.isField && !f.isStatic && f.declaringType.isClass) {
+ fields[f] = f.computeValue();
+ }
+ }
+ }
+
+ setField(Member field, Value value, [bool duringInit = false]) {
+ var currentValue = fields[field];
+ if (isConst && !value.isConst) {
+ world.error('used of non-const value in const intializer', value.span);
+ }
+
+ if (currentValue === null) {
+ fields[field] = value;
+ if (field.isFinal && !duringInit) {
+ world.error('can not initialize final fields outside of initializer',
+ value.span);
+ }
+ } else {
+ // TODO(jimhug): Clarify spec on reinitializing fields with defaults.
+ if (field.isFinal && field.computeValue() === null) {
+ world.error('reassignment of field not allowed', value.span,
+ field.span);
+ } else {
+ fields[field] = value; //currentValue.union(value);
+ }
+ }
+ }
+
+ validateInitialized(SourceSpan span) {
+ var buf = new StringBuffer();
+ buf.add('Object.create(');
+ buf.add('${type.jsname}.prototype, ');
+
+ buf.add('{');
+ for (var field in fields.getKeys()) {
+ buf.add(field.name);
+ buf.add(': ');
+ buf.add('{"value": ');
+ if (fields[field] === null) {
+ world.error('Required field "${field.name}" was not initialized',
+ span, field.span);
+ buf.add('null');
+ } else {
+ buf.add(fields[field].code);
+ }
+ buf.add(', writeable: false}, ');
+ }
+ buf.add('})');
+ _code = buf.toString();
+ }
+
Value binop(int kind, var other, MethodGenerator context, var node) {
if (other is! ObjectValue) return super.binop(kind, other, context, node);
switch (kind) {
case TokenKind.EQ_STRICT:
+ case TokenKind.EQ:
return new BoolValue(type == other.type && code == other.code,
isConst && other.isConst, node.span);
case TokenKind.NE_STRICT:
+ case TokenKind.NE:
return new BoolValue(type != other.type || code != other.code,
isConst && other.isConst, node.span);
}
@@ -855,34 +1106,6 @@ class ObjectValue extends EvaluatedValue {
}
-/** An evaluated constant object expression. */
-/*
-class ConstObjectValue extends EvaluatedValue {
- Map<String, EvaluatedValue> fields;
-
- factory ConstObjectValue(
- Type type, Map<String, EvaluatedValue> fields,
- String canonicalCode, SourceSpan span) {
- // compute a unique-string form used to index this value in the global const
- // map. This is used to ensure that multiple const object values are
- // equivalent if they have the same type name and values on each field.
- final fieldValues = [];
- for (var f in fields.getKeys()) {
- fieldValues.add('$f = ${fields[f].actualValue}');
- }
- fieldValues.sort((a, b) => a.compareTo(b));
- final actualValue = 'const ${type.jsname} ['
- + Strings.join(fieldValues, ',') + ']';
- return new ConstObjectValue._internal(type, fields, actualValue,
- canonicalCode, span, codeWithComments(canonicalCode, span));
- }
-
- ConstObjectValue._internal(type, this.fields,
- actualValue, canonicalCode, span, code) :
- super._internal(type, actualValue, canonicalCode, span, code);
-}
-*/
-
/**
* A global value in the generated code, which corresponds to either a static
* field or a memoized const expressions.
@@ -900,9 +1123,8 @@ class GlobalValue extends Value implements Comparable {
/** The value of the field or constant expression to declare. */
Value exp;
-
/** True for either cont expressions or a final static field. */
- bool get isConst() => exp.isConst && (field == null || field.isFinal);
+ bool isConst;
/** The actual constant value, when [isConst] is true. */
get actualValue() => exp.dynamic.actualValue;
@@ -916,7 +1138,8 @@ class GlobalValue extends Value implements Comparable {
GlobalValue(Type type, String code, bool isConst,
this.field, this.name, this.exp,
SourceSpan span, List<Value> _dependencies)
- : super(type, code, span, !isConst), dependencies = [] {
+ : super(type, code, span, !isConst),
+ dependencies = [], isConst = isConst {
// store transitive-dependencies so sorting algorithm works correctly.
for (var dep in _dependencies) {
if (dep is GlobalValue) {
« frog/member.dart ('K') | « frog/minfrog ('k') | tests/corelib/corelib.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698