3ac13ad168
Was complaining "The name 'hash' cannot be referenced in the initializer of a variable with the same name", seems like an incorrect error message for this code (though it is arguably less confusing this way). TBR BUG= Review URL: https://codereview.chromium.org//23583021 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26892 260f80e4-7a28-3924-810f-c04153c831b5
252 lines
6.9 KiB
Dart
252 lines
6.9 KiB
Dart
// Copyright (c) 2013, 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.
|
|
|
|
library polymer_expressions.expression;
|
|
|
|
import 'visitor.dart';
|
|
|
|
// Helper functions for building expression trees programmatically
|
|
|
|
EmptyExpression empty() => new EmptyExpression();
|
|
Literal literal(v) => new Literal(v);
|
|
MapLiteral mapLiteral(List<MapLiteralEntry> entries) => new MapLiteral(entries);
|
|
MapLiteralEntry mapLiteralEntry(Literal key, Expression value) =>
|
|
new MapLiteralEntry(key, value);
|
|
Identifier ident(String v) => new Identifier(v);
|
|
ParenthesizedExpression paren(Expression e) => new ParenthesizedExpression(e);
|
|
UnaryOperator unary(String op, Expression e) => new UnaryOperator(op, e);
|
|
BinaryOperator binary(Expression l, String op, Expression r) =>
|
|
new BinaryOperator(l, op, r);
|
|
Invoke invoke(Expression e, String m, [List<Expression> a]) =>
|
|
new Invoke(e, m, a);
|
|
InExpression inExpr(Expression l, Expression r) => new InExpression(l, r);
|
|
|
|
|
|
class AstFactory {
|
|
EmptyExpression empty() => new EmptyExpression();
|
|
|
|
Literal literal(v) => new Literal(v);
|
|
|
|
MapLiteral mapLiteral(List<MapLiteralEntry> entries) =>
|
|
new MapLiteral(entries);
|
|
|
|
MapLiteralEntry mapLiteralEntry(Literal key, Expression value) =>
|
|
new MapLiteralEntry(key, value);
|
|
|
|
Identifier identifier(String v) => new Identifier(v);
|
|
|
|
ParenthesizedExpression parenthesized(Expression e) =>
|
|
new ParenthesizedExpression(e);
|
|
|
|
UnaryOperator unary(String op, Expression e) => new UnaryOperator(op, e);
|
|
|
|
BinaryOperator binary(Expression l, String op, Expression r) =>
|
|
new BinaryOperator(l, op, r);
|
|
|
|
Invoke invoke(Expression e, String m, [List<Expression> a]) =>
|
|
new Invoke(e, m, a);
|
|
|
|
InExpression inExpr(Expression l, Expression r) => new InExpression(l, r);
|
|
}
|
|
|
|
/// Base class for all expressions
|
|
abstract class Expression {
|
|
accept(Visitor v);
|
|
}
|
|
|
|
class EmptyExpression extends Expression {
|
|
accept(Visitor v) => v.visitEmptyExpression(this);
|
|
bool operator ==(o) => o is EmptyExpression;
|
|
}
|
|
|
|
class Literal<T> extends Expression {
|
|
final T value;
|
|
|
|
Literal(this.value);
|
|
|
|
accept(Visitor v) => v.visitLiteral(this);
|
|
|
|
String toString() => (value is String) ? '"$value"' : '$value';
|
|
|
|
bool operator ==(o) => o is Literal<T> && o.value == value;
|
|
|
|
int get hashCode => value.hashCode;
|
|
}
|
|
|
|
class MapLiteral extends Expression {
|
|
final List<MapLiteralEntry> entries;
|
|
|
|
MapLiteral(this.entries);
|
|
|
|
accept(Visitor v) => v.visitMapLiteral(this);
|
|
|
|
String toString() => "{$entries}";
|
|
|
|
bool operator ==(o) => o is MapLiteral && _listEquals(o.entries, entries);
|
|
|
|
int get hashCode => _hashList(entries);
|
|
}
|
|
|
|
class MapLiteralEntry extends Expression {
|
|
final Literal key;
|
|
final Expression entryValue;
|
|
|
|
MapLiteralEntry(this.key, this.entryValue);
|
|
|
|
accept(Visitor v) => v.visitMapLiteralEntry(this);
|
|
|
|
String toString() => "$key: $entryValue";
|
|
|
|
bool operator ==(o) => o is MapLiteralEntry && o.key == key
|
|
&& o.entryValue == entryValue;
|
|
|
|
int get hashCode => _JenkinsSmiHash.hash2(key.hashCode, entryValue.hashCode);
|
|
}
|
|
|
|
class ParenthesizedExpression extends Expression {
|
|
final Expression child;
|
|
|
|
ParenthesizedExpression(this.child);
|
|
|
|
accept(Visitor v) => v.visitParenthesizedExpression(this);
|
|
|
|
String toString() => '($child)';
|
|
|
|
bool operator ==(o) => o is ParenthesizedExpression && o.child == child;
|
|
|
|
int get hashCode => child.hashCode;
|
|
}
|
|
|
|
class Identifier extends Expression {
|
|
final String value;
|
|
|
|
Identifier(this.value);
|
|
|
|
accept(Visitor v) => v.visitIdentifier(this);
|
|
|
|
String toString() => value;
|
|
|
|
bool operator ==(o) => o is Identifier && o.value == value;
|
|
|
|
int get hashCode => value.hashCode;
|
|
}
|
|
|
|
class UnaryOperator extends Expression {
|
|
final String operator;
|
|
final Expression child;
|
|
|
|
UnaryOperator(this.operator, this.child);
|
|
|
|
accept(Visitor v) => v.visitUnaryOperator(this);
|
|
|
|
String toString() => '$operator $child';
|
|
|
|
bool operator ==(o) => o is UnaryOperator && o.operator == operator
|
|
&& o.child == child;
|
|
|
|
int get hashCode => _JenkinsSmiHash.hash2(operator.hashCode, child.hashCode);
|
|
}
|
|
|
|
class BinaryOperator extends Expression {
|
|
final String operator;
|
|
final Expression left;
|
|
final Expression right;
|
|
|
|
BinaryOperator(this.left, this.operator, this.right);
|
|
|
|
accept(Visitor v) => v.visitBinaryOperator(this);
|
|
|
|
String toString() => '($left $operator $right)';
|
|
|
|
bool operator ==(o) => o is BinaryOperator && o.operator == operator
|
|
&& o.left == left && o.right == right;
|
|
|
|
int get hashCode => _JenkinsSmiHash.hash3(operator.hashCode, left.hashCode,
|
|
right.hashCode);
|
|
}
|
|
|
|
class InExpression extends Expression {
|
|
final Expression left;
|
|
final Expression right;
|
|
|
|
InExpression(this.left, this.right);
|
|
|
|
accept(Visitor v) => v.visitInExpression(this);
|
|
|
|
String toString() => '($left in $right)';
|
|
|
|
bool operator ==(o) => o is InExpression && o.left == left
|
|
&& o.right == right;
|
|
|
|
int get hashCode => _JenkinsSmiHash.hash2(left.hashCode, right.hashCode);
|
|
}
|
|
|
|
/**
|
|
* Represents a function or method invocation. If [method] is null, then
|
|
* [receiver] is an expression that should evaluate to a function. If [method]
|
|
* is not null, then [receiver] is an expression that should evaluate to an
|
|
* object that has an appropriate method.
|
|
*/
|
|
class Invoke extends Expression {
|
|
final Expression receiver;
|
|
final String method;
|
|
final List<Expression> arguments;
|
|
|
|
Invoke(this.receiver, this.method, [this.arguments]);
|
|
|
|
accept(Visitor v) => v.visitInvoke(this);
|
|
|
|
bool get isGetter => arguments == null;
|
|
|
|
String toString() => '$receiver.$method($arguments)';
|
|
|
|
bool operator ==(o) =>
|
|
o is Invoke
|
|
&& o.receiver == receiver
|
|
&& o.method == method
|
|
&& _listEquals(o.arguments, arguments);
|
|
|
|
int get hashCode => _JenkinsSmiHash.hash3(receiver.hashCode, method.hashCode,
|
|
_hashList(arguments));
|
|
}
|
|
|
|
bool _listEquals(List a, List b) {
|
|
if (a == b) return true;
|
|
if (a == null || b == null) return false;
|
|
if (a.length != b.length) return false;
|
|
for (int i = 0; i < a.length; i++) {
|
|
if (a[i] != b[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int _hashList(List l) {
|
|
var hash = l.fold(0,
|
|
(h, item) => _JenkinsSmiHash.combine(h, item.hashCode));
|
|
return _JenkinsSmiHash.finish(hash);
|
|
}
|
|
|
|
class _JenkinsSmiHash {
|
|
// TODO: Bug 11617- This class should be optimized and standardized elsewhere.
|
|
|
|
static int combine(int hash, int value) {
|
|
hash = 0x1fffffff & (hash + value);
|
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
|
return hash ^ (hash >> 6);
|
|
}
|
|
|
|
static int finish(int hash) {
|
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
|
hash = hash ^ (hash >> 11);
|
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
|
}
|
|
|
|
static int hash2(a, b) => finish(combine(combine(0, a), b));
|
|
|
|
static int hash3(a, b, c) => finish(combine(combine(combine(0, a), b), c));
|
|
|
|
static int hash4(a, b, c, d) =>
|
|
finish(combine(combine(combine(combine(0, a), b), c), d));
|
|
}
|