/* * Copyright 2003-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.newTypesystem.context; import gnu.trove.THashSet; import jetbrains.mps.errors.IErrorReporter; import jetbrains.mps.typesystem.inference.TypeSubstitution; import jetbrains.mps.newTypesystem.context.typechecking.BaseTypechecking; import jetbrains.mps.newTypesystem.context.typechecking.IncrementalTypechecking; import jetbrains.mps.newTypesystem.context.component.SimpleTypecheckingComponent; import jetbrains.mps.languageScope.LanguageScopeExecutor; import jetbrains.mps.newTypesystem.state.State; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.typesystem.TypeSystemReporter; import jetbrains.mps.typesystem.inference.EquationInfo; import jetbrains.mps.typesystem.inference.TypeChecker; import jetbrains.mps.util.Computable; import jetbrains.mps.util.Pair; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; /** * User: fyodor * Date: 11/6/12 */ public abstract class SimpleTypecheckingContext< STATE extends State, TCHECK extends BaseTypechecking<STATE, ? extends SimpleTypecheckingComponent<STATE>>> extends BaseTypecheckingContext { private TCHECK myTypechecking; private STATE myState; private boolean myCurrentlyChecking; public SimpleTypecheckingContext(SNode rootNode, TypeChecker typeChecker) { super(rootNode, typeChecker); myState = createState(); setTypechecking(createTypechecking()); } @SuppressWarnings("unchecked") protected abstract TCHECK createTypechecking(); @SuppressWarnings("unchecked") protected STATE createState() { return (STATE) new State(this); } @Override public STATE getState() { assert myState != null; return myState; } public TCHECK getTypechecking() { return myTypechecking; } @Override public boolean isSingleTypeComputation() { return true; } @Override public void addDependencyForCurrent(SNode node) { // do nothing } @Override public void reportMessage(SNode nodeWithError, IErrorReporter errorReporter) { // do nothing } @Override public boolean isIncrementalMode() { return false; } @Override public SNode getTypeOf_normalMode(SNode node) { throw new IllegalStateException("Invalid usage of SimpleTypecheckingContext"); } @Override public SNode getTypeOf_generationMode(final SNode node) { long start = System.nanoTime(); SNode result = LanguageScopeExecutor.execWithModelScope(node.getModel(), new Computable<SNode>() { @Override public SNode compute() { return getTypechecking().computeTypesForNodeDuringGeneration(node); } }); TypeSystemReporter.getInstance().reportTypeOf(node, (System.nanoTime() - start)); return result; } @Override public SNode getTypeOf_resolveMode(SNode node, TypeChecker typeChecker) { throw new IllegalStateException("Invalid usage of SimpleTypecheckingContext"); } @Override public SNode getTypeOf(SNode node, TypeChecker typeChecker) { if (node == null) return null; synchronized (TYPECHECKING_LOCK) { return getTypeOf_resolveMode(node, typeChecker); } } @Override public void setIsNonTypesystemComputation() { assert false; } @Override public void resetIsNonTypesystemComputation() { assert false; } @Override public boolean isNonTypesystemComputation() { return false; } protected void applyNonTypesystemRules() { // do nothing } @Override public void clear() { } @Override public IncrementalTypechecking getBaseNodeTypesComponent() { assert false; return null; } protected final void setTypechecking(TCHECK typechecking) { assert myTypechecking == null; assert typechecking != null; myTypechecking = typechecking; } @Override public SNode typeOf(SNode node) { return typeOf(node, null, null, true); } @Override public SNode typeOf(SNode node, String ruleModel, String ruleId, boolean addDependency) { EquationInfo info = new EquationInfo(node, "typeOf", ruleModel, ruleId); if (node == null) return null; BaseTypechecking currentTypesComponent = getTypechecking(); //first, in current component if (currentTypesComponent != null) { //--- for incremental algorithm: currentTypesComponent.addNodeToFrontier(node); processDependency(node, ruleModel, ruleId, addDependency); } return getState().typeOf(node, info); } @Override public SNode computeTypeInferenceMode(SNode node) { synchronized (TYPECHECKING_LOCK) { // myIsInferenceMode = true; try { return getTypechecking().computeTypesForNodeInferenceMode(node); } finally { // myIsInferenceMode = false; } } } @Override public SNode getTypeInGenerationMode(SNode node) { try { return getTypeOf_generationMode(node); } finally { // TODO [ts] move dispose -> trace tree getTypechecking().dispose(); } } @Override public boolean checkIfNotChecked(SNode node, boolean useNonTypesystemRules) { synchronized (TYPECHECKING_LOCK) { // recursion guard if (myCurrentlyChecking) return true; try { this.myCurrentlyChecking = true; if (!isCheckedRoot(useNonTypesystemRules)) { checkRoot(); if (useNonTypesystemRules) { applyNonTypesystemRules(); } } return true; } finally { this.myCurrentlyChecking = false; } } } @Override public void checkRoot() { checkRoot(false); } @Override public void checkRoot(final boolean refreshTypes) { synchronized (TYPECHECKING_LOCK) { LanguageScopeExecutor.execWithModelScope(myNode.getModel(), new Computable<Object>() { @Override public Object compute() { getTypechecking().computeTypes(refreshTypes); getTypechecking().setCheckedTypesystem(); return null; } }); } } @Override public Set<Pair<SNode, List<IErrorReporter>>> checkRootAndGetErrors(boolean refreshTypes) { synchronized (TYPECHECKING_LOCK) { // recursion guard if (myCurrentlyChecking) Collections.emptyList(); try { this.myCurrentlyChecking = true; checkRoot(refreshTypes); //non-typesystem checks applyNonTypesystemRules(); final Set<Pair<SNode, List<IErrorReporter>>> nodesWithErrors = getTypechecking().getNodesWithErrors(true); final THashSet<Pair<SNode, List<IErrorReporter>>> result = new THashSet<Pair<SNode, List<IErrorReporter>>>(nodesWithErrors); result.addAll(getTypechecking().getNodesWithErrors(false)); return result; } finally { this.myCurrentlyChecking = false; } } } @Override public Set<Pair<SNode, List<IErrorReporter>>> getNodesWithErrors(boolean typesystemErrors) { return getTypechecking().getNodesWithErrors(typesystemErrors); } @Override public boolean isCheckedRoot(boolean considerNonTypesystemRules) { return getTypechecking().isChecked(considerNonTypesystemRules); } @Override public List<IErrorReporter> getTypeMessagesDontCheck(SNode node) { return getTypechecking().getErrors(node); } @Override public IErrorReporter getTypeMessageDontCheck(SNode node) { List<IErrorReporter> messages = getTypeMessagesDontCheck(node); if (messages.isEmpty()) { return null; } Collections.sort(messages, new Comparator<IErrorReporter>() { @Override public int compare(IErrorReporter o1, IErrorReporter o2) { return o2.getMessageStatus().compareTo(o1.getMessageStatus()); } }); return messages.get(0); } @Override public TypeSubstitution getSubstitution(final SNode origNode) { return LanguageScopeExecutor.execWithLanguageScope(null, new Computable<TypeSubstitution>() { @Override public TypeSubstitution compute() { return myTypechecking.getTypecheckingComponent().lookupSubstitution(origNode, SimpleTypecheckingContext.this); } }); } protected void processDependency(SNode node, String ruleModel, String ruleId, boolean addDependency) { // do nothing } }