Add StringLengthConstantExpression

... and make .fromEnvironment name a ConstantExpression.

BUG=
R=karlklose@google.com

Review URL: https://codereview.chromium.org//1166723002
This commit is contained in:
Johnni Winther 2015-06-02 10:52:50 +02:00
parent 411246ccc7
commit 3250c8fd91
6 changed files with 168 additions and 42 deletions

View file

@ -535,7 +535,8 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
StringConstantValue stringConstantValue = left.value;
DartString string = stringConstantValue.primitiveValue;
IntConstantValue length = constantSystem.createInt(string.length);
result = new VariableConstantExpression(length, element);
result =
new StringLengthConstantExpression(length, left.expression);
}
}
// Fall through to error handling.
@ -880,15 +881,20 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
AstConstant createEvaluatedConstant(ConstantValue value) {
ConstantExpression expression;
ConstantExpression name = concreteArguments[0].expression;
ConstantExpression defaultValue;
if (concreteArguments.length > 1) {
defaultValue = concreteArguments[1].expression;
}
if (constructor == compiler.intEnvironment) {
expression = new IntFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
value, name, defaultValue);
} else if (constructor == compiler.boolEnvironment) {
expression = new BoolFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
value, name, defaultValue);
} else if (constructor == compiler.stringEnvironment) {
expression = new StringFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
value, name, defaultValue);
}
return new AstConstant(context, node, expression);
}

View file

@ -38,6 +38,7 @@ enum ConstantExpressionKind {
NULL,
STRING,
STRING_FROM_ENVIRONMENT,
STRING_LENGTH,
SYMBOL,
TYPE,
UNARY,
@ -1002,6 +1003,50 @@ class UnaryConstantExpression extends ConstantExpression {
};
}
/// A string length constant expression like `a.length`.
class StringLengthConstantExpression extends ConstantExpression {
final ConstantValue value;
final ConstantExpression expression;
StringLengthConstantExpression(this.value, this.expression);
ConstantExpressionKind get kind => ConstantExpressionKind.STRING_LENGTH;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitStringLength(this, context);
}
@override
ConstantValue evaluate(Environment environment,
ConstantSystem constantSystem) {
ConstantValue value = expression.evaluate(environment, constantSystem);
if (value.isString) {
StringConstantValue stringValue = value;
return constantSystem.createInt(stringValue.primitiveValue.length);
}
return new NonConstantValue();
}
ConstantExpression apply(NormalizedArguments arguments) {
return new StringLengthConstantExpression(
value,
expression.apply(arguments));
}
int get precedence => 15;
@override
int _computeHashCode() {
return 23 * expression.hashCode;
}
@override
bool _equals(StringLengthConstantExpression other) {
return expression == other.expression;
}
}
/// A constant conditional expression like `a ? b : c`.
class ConditionalConstantExpression extends ConstantExpression {
final ConstantValue value;
@ -1135,7 +1180,7 @@ class NamedArgumentReference extends ConstantExpression {
abstract class FromEnvironmentConstantExpression extends ConstantExpression {
final ConstantValue value;
final String name;
final ConstantExpression name;
final ConstantExpression defaultValue;
FromEnvironmentConstantExpression(this.value, this.name, this.defaultValue);
@ -1159,7 +1204,7 @@ class BoolFromEnvironmentConstantExpression
BoolFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
@ -1174,19 +1219,35 @@ class BoolFromEnvironmentConstantExpression
@override
ConstantValue evaluate(Environment environment,
ConstantSystem constantSystem) {
String text = environment.readFromEnvironment(name);
ConstantValue nameConstantValue =
name.evaluate(environment, constantSystem);
ConstantValue defaultConstantValue;
if (defaultValue != null) {
defaultConstantValue =
defaultValue.evaluate(environment, constantSystem);
} else {
defaultConstantValue = constantSystem.createBool(false);
}
if (!nameConstantValue.isString) {
return new NonConstantValue();
}
StringConstantValue nameStringConstantValue = nameConstantValue;
String text = environment.readFromEnvironment(
nameStringConstantValue.primitiveValue.slowToString());
if (text == 'true') {
return constantSystem.createBool(true);
} else if (text == 'false') {
return constantSystem.createBool(false);
} else {
return defaultValue.evaluate(environment, constantSystem);
return defaultConstantValue;
}
}
ConstantExpression apply(NormalizedArguments arguments) {
return new BoolFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
null,
name.apply(arguments),
defaultValue != null ? defaultValue.apply(arguments) : null);
}
}
@ -1196,7 +1257,7 @@ class IntFromEnvironmentConstantExpression
IntFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
@ -1211,13 +1272,27 @@ class IntFromEnvironmentConstantExpression
@override
ConstantValue evaluate(Environment environment,
ConstantSystem constantSystem) {
ConstantValue nameConstantValue =
name.evaluate(environment, constantSystem);
ConstantValue defaultConstantValue;
if (defaultValue != null) {
defaultConstantValue =
defaultValue.evaluate(environment, constantSystem);
} else {
defaultConstantValue = constantSystem.createNull();
}
if (!nameConstantValue.isString) {
return new NonConstantValue();
}
StringConstantValue nameStringConstantValue = nameConstantValue;
String text = environment.readFromEnvironment(
nameStringConstantValue.primitiveValue.slowToString());
int value;
String text = environment.readFromEnvironment(name);
if (text != null) {
value = int.parse(text, onError: (_) => null);
}
if (value == null) {
return defaultValue.evaluate(environment, constantSystem);
return defaultConstantValue;
} else {
return constantSystem.createInt(value);
}
@ -1225,7 +1300,9 @@ class IntFromEnvironmentConstantExpression
ConstantExpression apply(NormalizedArguments arguments) {
return new IntFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
null,
name.apply(arguments),
defaultValue != null ? defaultValue.apply(arguments) : null);
}
}
@ -1235,7 +1312,7 @@ class StringFromEnvironmentConstantExpression
StringFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
@ -1250,9 +1327,23 @@ class StringFromEnvironmentConstantExpression
@override
ConstantValue evaluate(Environment environment,
ConstantSystem constantSystem) {
String text = environment.readFromEnvironment(name);
ConstantValue nameConstantValue =
name.evaluate(environment, constantSystem);
ConstantValue defaultConstantValue;
if (defaultValue != null) {
defaultConstantValue =
defaultValue.evaluate(environment, constantSystem);
} else {
defaultConstantValue = constantSystem.createNull();
}
if (!nameConstantValue.isString) {
return new NonConstantValue();
}
StringConstantValue nameStringConstantValue = nameConstantValue;
String text = environment.readFromEnvironment(
nameStringConstantValue.primitiveValue.slowToString());
if (text == null) {
return defaultValue.evaluate(environment, constantSystem);
return defaultConstantValue;
} else {
return constantSystem.createString(new DartString.literal(text));
}
@ -1260,7 +1351,9 @@ class StringFromEnvironmentConstantExpression
ConstantExpression apply(NormalizedArguments arguments) {
return new StringFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
null,
name.apply(arguments),
defaultValue != null ? defaultValue.apply(arguments) : null);
}
}
@ -1286,6 +1379,11 @@ class DeferredConstantExpression extends ConstantExpression {
return 13 * expression.hashCode;
}
ConstantExpression apply(NormalizedArguments arguments) {
return new DeferredConstantExpression(
value, expression.apply(arguments), prefix);
}
@override
bool _equals(DeferredConstantExpression other) {
return expression == other.expression;
@ -1320,6 +1418,7 @@ abstract class ConstantExpressionVisitor<R, A> {
R visitBinary(BinaryConstantExpression exp, A context);
R visitIdentical(IdenticalConstantExpression exp, A context);
R visitUnary(UnaryConstantExpression exp, A context);
R visitStringLength(StringLengthConstantExpression exp, A context);
R visitConditional(ConditionalConstantExpression exp, A context);
R visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
A context);
@ -1346,8 +1445,8 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
final StringBuffer sb = new StringBuffer();
void write(ConstantExpression parent,
ConstantExpression child,
{bool leftAssociative: true}) {
ConstantExpression child,
{bool leftAssociative: true}) {
if (child.precedence < parent.precedence ||
!leftAssociative && child.precedence == parent.precedence) {
sb.write('(');
@ -1443,11 +1542,11 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
void visitConstructed(ConstructedConstantExpression exp, [_]) {
sb.write('const ');
sb.write(exp.target.enclosingClass.name);
writeTypeArguments(exp.type);
if (exp.target.name != '') {
sb.write('.');
sb.write(exp.target.name);
}
writeTypeArguments(exp.type);
sb.write('(');
bool needsComma = false;
@ -1529,6 +1628,12 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
write(exp, exp.expression);
}
@override
void visitStringLength(StringLengthConstantExpression exp, [_]) {
write(exp, exp.expression, leftAssociative: false);
sb.write('.length');
}
@override
void visitConditional(ConditionalConstantExpression exp, [_]) {
write(exp, exp.condition, leftAssociative: false);
@ -1560,23 +1665,35 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
@override
void visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
[_]) {
sb.write('const bool.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write('const bool.fromEnvironment(');
visit(exp.name);
if (exp.defaultValue != null) {
sb.write(', defaultValue: ');
visit(exp.defaultValue);
}
sb.write(')');
}
@override
void visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp, [_]) {
sb.write('const int.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write('const int.fromEnvironment(');
visit(exp.name);
if (exp.defaultValue != null) {
sb.write(', defaultValue: ');
visit(exp.defaultValue);
}
sb.write(')');
}
@override
void visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp,
[_]) {
sb.write('const String.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write('const String.fromEnvironment(');
visit(exp.name);
if (exp.defaultValue != null) {
sb.write(', defaultValue: ');
visit(exp.defaultValue);
}
sb.write(')');
}

View file

@ -228,6 +228,12 @@ class AnnotationCreator
return null;
}
@override
Annotation visitStringLength(StringLengthConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitDeferred(DeferredConstantExpression exp,
AnnotationInfo context) {

View file

@ -38,7 +38,8 @@ class MemoryEnvironment implements Environment {
final Compiler compiler;
final Map<String, String> env;
MemoryEnvironment(this.compiler, [this.env = const <String, String>{}]);
MemoryEnvironment(this.compiler,
[this.env = const <String, String>{}]);
@override
String readFromEnvironment(String name) => env[name];
@ -54,6 +55,7 @@ const List<TestData> DATA = const [
const ConstantData('"foo"', const { const {} : 'StringConstant("foo")' }),
const ConstantData('1 + 2', const { const {} : 'IntConstant(3)' }),
const ConstantData('-(1)', const { const {} : 'IntConstant(-1)' }),
const ConstantData('"foo".length', const { const {} : 'IntConstant(3)' }),
const ConstantData('identical(0, 1)',
const { const {} : 'BoolConstant(false)' }),
const ConstantData('"a" "b"', const { const {} : 'StringConstant("ab")' }),
@ -144,9 +146,7 @@ class A<T> implements B {
}
class B<S> implements C {
const factory B({field1}) = A<B<S>>;
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const factory B.named() = A<S>;*/
const factory B.named() = A<S>;
}
class C<U> {
const factory C({field1}) = A<B<double>>;
@ -170,11 +170,9 @@ class C<U> {
const ConstantData('const C<int>(field1: 87)',
const { const {} :
'ConstructedConstant(A<B<double>>(field1=IntConstant(87)))' }),
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const ConstantData('const B<int>.named()',
const ConstantData('const B<int>.named()',
const { const {} :
'ConstructedConstant(A<int>(field1=IntConstant(42)))' }),*/
'ConstructedConstant(A<int>(field1=IntConstant(42)))' }),
]),
const TestData('''
const c = const int.fromEnvironment("foo", defaultValue: 5);

View file

@ -52,6 +52,7 @@ const List<TestData> DATA = const [
const ConstantData('"foo"', ConstantExpressionKind.STRING),
const ConstantData('1 + 2', ConstantExpressionKind.BINARY),
const ConstantData('-(1)', ConstantExpressionKind.UNARY, text: '-1'),
const ConstantData('"foo".length', ConstantExpressionKind.STRING_LENGTH),
const ConstantData('identical(0, 1)', ConstantExpressionKind.IDENTICAL),
const ConstantData('"a" "b"', ConstantExpressionKind.CONCATENATE,
text: '"ab"'),
@ -148,7 +149,7 @@ class B<S> implements C {
const factory B({field1}) = A<B<S>>;
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const factory B.named() = A<S>;*/
const factory B.named() = A<S>;
}
class C<U> {
const factory C({field1}) = A<B<double>>;
@ -183,14 +184,12 @@ class C<U> {
fields: const {
'field(A#field1)': '87',
}),
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const ConstantData('const B<int>.named()',
const ConstantData('const B<int>.named()',
ConstantExpressionKind.CONSTRUCTED,
type: 'A<int>',
fields: const {
'field(A#field1)': '42',
}),*/
}),
]),
];

View file

@ -3093,7 +3093,7 @@ const Map<String, List<Test>> SEND_TESTS = const {
''',
const Visit(VisitKind.VISIT_BOOL_FROM_ENVIRONMENT_CONSTRUCTOR_INVOKE,
constant:
'const bool.fromEnvironment("foo", defaultValue: false)')),
'const bool.fromEnvironment("foo")')),
const Test(
'''
m() => const bool.fromEnvironment('foo', defaultValue: true);
@ -3105,14 +3105,14 @@ const Map<String, List<Test>> SEND_TESTS = const {
m() => const int.fromEnvironment('foo');
''',
const Visit(VisitKind.VISIT_INT_FROM_ENVIRONMENT_CONSTRUCTOR_INVOKE,
constant: 'const int.fromEnvironment("foo", defaultValue: null)')),
constant: 'const int.fromEnvironment("foo")')),
const Test(
'''
m() => const String.fromEnvironment('foo');
''',
const Visit(VisitKind.VISIT_STRING_FROM_ENVIRONMENT_CONSTRUCTOR_INVOKE,
constant:
'const String.fromEnvironment("foo", defaultValue: null)')),
'const String.fromEnvironment("foo")')),
const Test(
'''
class Class {