| Index: compiler/java/com/google/dart/compiler/resolver/CompileTimeConstantResolver.java
|
| diff --git a/compiler/java/com/google/dart/compiler/resolver/CompileTimeConstantResolver.java b/compiler/java/com/google/dart/compiler/resolver/CompileTimeConstantResolver.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ffd895d8660700f14b36719992cf6eb5261d7aab
|
| --- /dev/null
|
| +++ b/compiler/java/com/google/dart/compiler/resolver/CompileTimeConstantResolver.java
|
| @@ -0,0 +1,199 @@
|
| +// Copyright (c) 2011, 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.
|
| +
|
| +package com.google.dart.compiler.resolver;
|
| +
|
| +import com.google.common.annotations.VisibleForTesting;
|
| +import com.google.dart.compiler.DartCompilerContext;
|
| +import com.google.dart.compiler.ast.DartClass;
|
| +import com.google.dart.compiler.ast.DartExpression;
|
| +import com.google.dart.compiler.ast.DartField;
|
| +import com.google.dart.compiler.ast.DartFunction;
|
| +import com.google.dart.compiler.ast.DartIdentifier;
|
| +import com.google.dart.compiler.ast.DartMethodDefinition;
|
| +import com.google.dart.compiler.ast.DartNewExpression;
|
| +import com.google.dart.compiler.ast.DartNode;
|
| +import com.google.dart.compiler.ast.DartNodeTraverser;
|
| +import com.google.dart.compiler.ast.DartParameter;
|
| +import com.google.dart.compiler.ast.DartPropertyAccess;
|
| +import com.google.dart.compiler.ast.DartUnit;
|
| +import com.google.dart.compiler.ast.DartVariable;
|
| +import com.google.dart.compiler.ast.DartVariableStatement;
|
| +import com.google.dart.compiler.ast.Modifiers;
|
| +
|
| +import java.util.List;
|
| +
|
| +
|
| +/**
|
| + * Compile-time constants need to infer types, not just in the current units to be resolved, but
|
| + * in all units. This pass resolves the right hand side of compile-time constants for the later
|
| + * type analysis and cycle detection done in {@link CompileTimeConstantAnalyzer}.
|
| + */
|
| +public class CompileTimeConstantResolver {
|
| +
|
| + private class ConstResolveVisitor extends ResolveVisitor {
|
| + private class ConstExpressionVisitor extends DartNodeTraverser<Void> {
|
| +
|
| + @Override
|
| + public Void visitPropertyAccess(DartPropertyAccess x) {
|
| + DartNode qualifierNode = x.getQualifier();
|
| + Element qualifier = null;
|
| + if (qualifierNode instanceof DartIdentifier) {
|
| + DartIdentifier qualifierIdent = (DartIdentifier) qualifierNode;
|
| + qualifier = getContext().getScope().findElement(libraryElement,
|
| + qualifierIdent
|
| + .getTargetName());
|
| + qualifierNode.setSymbol(qualifier);
|
| + }
|
| +
|
| + if (qualifier != null) {
|
| + Element element = null;
|
| +
|
| + switch (ElementKind.of(qualifier)) {
|
| + case CLASS:
|
| + // Must be a static field.
|
| + element = Elements.findElement(((ClassElement) qualifier), x
|
| + .getPropertyName());
|
| + break;
|
| +
|
| + case LIBRARY:
|
| + // Library prefix, lookup the element in the reference library.
|
| + Scope scope = ((LibraryElement) qualifier).getScope();
|
| + element = scope
|
| + .findElement(scope.getLibrary(), x.getPropertyName());
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| + if (element != null) {
|
| + recordElement(x, element);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Void visitIdentifier(DartIdentifier x) {
|
| + x.visitChildren(this);
|
| +
|
| + Element element = getContext().getScope()
|
| + .findElement(libraryElement, x.getTargetName());
|
| + if (element != null) {
|
| + recordElement(x, element);
|
| + }
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + private final LibraryElement libraryElement;
|
| + private EnclosingElement currentHolder;
|
| + private final ResolutionContext topLevelContext;
|
| + private ResolutionContext context;
|
| +
|
| + private ConstResolveVisitor(DartUnit unit,
|
| + DartCompilerContext compilerContext, Scope scope,
|
| + CoreTypeProvider typeProvider) {
|
| + super(typeProvider);
|
| + this.libraryElement = unit.getLibrary() == null ? null : unit
|
| + .getLibrary().getElement();
|
| + this.topLevelContext = this.context = new ResolutionContext(scope,
|
| + compilerContext, typeProvider);
|
| + this.currentHolder = libraryElement;
|
| + }
|
| +
|
| + private void beginClassContext(final DartClass node) {
|
| + assert !ElementKind.of(currentHolder).equals(ElementKind.CLASS) : "nested class?";
|
| + currentHolder = node.getSymbol();
|
| + context = context.extend((ClassElement) currentHolder);
|
| + }
|
| +
|
| + private void endClassContext() {
|
| + currentHolder = libraryElement;
|
| + context = topLevelContext;
|
| + }
|
| +
|
| + @Override
|
| + ResolutionContext getContext() {
|
| + return context;
|
| + }
|
| +
|
| + @Override
|
| + boolean isStaticContext() {
|
| + return true;
|
| + }
|
| +
|
| + private void resolveConstantExpression(DartExpression expression) {
|
| + if (expression != null) {
|
| + expression.accept(new ConstExpressionVisitor());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public Element visitClass(DartClass node) {
|
| + assert !ElementKind.of(currentHolder).equals(ElementKind.CLASS) : "nested class?";
|
| + beginClassContext(node);
|
| + this.visit(node.getMembers());
|
| + endClassContext();
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Element visitField(DartField node) {
|
| + resolveConstantExpression(node.getValue());
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Element visitMethodDefinition(DartMethodDefinition node) {
|
| + DartFunction functionNode = node.getFunction();
|
| + List<DartParameter> parameters = functionNode.getParams();
|
| + for (DartParameter parameter : parameters) {
|
| + // Then resolve the default values.
|
| + resolveConstantExpression(parameter.getDefaultExpr());
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Element visitNewExpression(DartNewExpression node) {
|
| + if (node.isConst()) {
|
| + for (DartExpression arg : node.getArgs()) {
|
| + resolveConstantExpression(arg);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Element visitParameter(DartParameter node) {
|
| + resolveConstantExpression(node.getDefaultExpr());
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public Element visitVariableStatement(DartVariableStatement node) {
|
| + for (DartVariable variable : node.getVariables()) {
|
| + Modifiers modifiers = node.getModifiers();
|
| + if (modifiers.isStatic() && modifiers.isFinal()
|
| + && variable.getValue() != null) {
|
| + resolveConstantExpression(variable.getValue());
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + public void exec(DartUnit unit,
|
| + DartCompilerContext compilerContext, CoreTypeProvider typeProvider) {
|
| + exec(unit, compilerContext, unit.getLibrary().getElement().getScope(), typeProvider);
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + public void exec(DartUnit unit, DartCompilerContext compilerContext,
|
| + Scope scope, CoreTypeProvider typeProvider) {
|
| + unit.accept(new ConstResolveVisitor(unit, compilerContext, scope,
|
| + typeProvider));
|
| + }
|
| +}
|
|
|