/*
* #%~
* The VDM Type Checker
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.typechecker;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.typechecker.NameScope;
import org.overture.ast.types.PType;
import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory;
public class TypeCheckInfo
{
public final ITypeCheckerAssistantFactory assistantFactory;
/*
* Added by RWL The Context allows us to resolve the following: (AnotherChecker,AnotherQuestion) ->
* (OvertureChecker,OvertureQuestion) -> (AnotherChecker, OvertureQuestion) Now the AnotherChecker is aware that
* only a OvertureQuestion is available here, however it may need its AnotherQuestion, right, to resolve that we
* have this context: (AnotherChecker,AnotherQuestion) -> Create Overture Question with AnotherQuestion in its
* context -> (OverutreChecker,OvertureQuestion) work as it should (AnotherChecker,OverTureQuestion) -> Get from the
* context the earlier AnotherQuestion. Other things can be added to the context and it may be used for any purpose.
* It is not used by Overture. (Remove this comment it is starts getting used by overture !)
*/
private static final Map<Class<?>, Object> context = new HashMap<Class<?>, Object>();
public static void clearContext()
{
context.clear();
}
@SuppressWarnings("unchecked")
private static <T> Stack<T> lookupListForType(Class<T> clz)
{
Object o = context.get(clz);
if (o instanceof List<?>)
{
List<?> list = List.class.cast(o);
if (list.size() > 0)
{
Object first = list.get(0);
if (first != null && clz.isInstance(first))
{
return (Stack<T>) list;
}
}
}
return null;
}
/**
* Returns the value associated with key. Implementation detail: Notice the map is shared between all instances.
*
* @param <T>
* @param key
* @return
*/
public <T> T contextGet(Class<T> key)
{
synchronized (TypeCheckInfo.class)
{
Stack<T> contextStack = lookupListForType(key);
if (contextStack != null)
{
return contextStack.peek();
}
}
return null;
}
/**
* Associates the given key with the given value.
*
* @param <T>
* @param key
* @param value
*/
public <T> void contextSet(Class<T> key, T value)
{
synchronized (TypeCheckInfo.class)
{
Stack<T> contextStack = lookupListForType(key);
if (contextStack == null)
{
contextStack = new Stack<T>();
context.put(key, contextStack);
}
contextStack.push(value);
}
}
/**
* Returns the value associated with key, and removes that binding from the context.
*
* @param <T>
* @param key
* @return value
*/
public <T> T contextRem(Class<T> key)
{
synchronized (TypeCheckInfo.class)
{
Stack<T> contextStack = lookupListForType(key);
if (contextStack != null)
{
return contextStack.pop();
}
}
return null;
}
public final Environment env;
public NameScope scope;
public LinkedList<PType> qualifiers;
public final PType constraint; // expressions
public final PType returnType; // statements
public TypeCheckInfo(ITypeCheckerAssistantFactory assistantFactory,
Environment env, NameScope scope, LinkedList<PType> qualifiers,
PType constraint, PType returnType)
{
this.assistantFactory = assistantFactory;
this.env = env;
this.scope = scope;
this.qualifiers = qualifiers;
this.constraint = constraint;
this.returnType = returnType;
}
public TypeCheckInfo(ITypeCheckerAssistantFactory assistantFactory,
Environment env, NameScope scope, LinkedList<PType> qualifiers)
{
this(assistantFactory, env, scope, qualifiers, null, null);
}
public TypeCheckInfo(ITypeCheckerAssistantFactory assistantFactory,
Environment env, NameScope scope)
{
this(assistantFactory, env, scope, null, null, null);
}
public TypeCheckInfo(ITypeCheckerAssistantFactory assistantFactory,
Environment env)
{
this(assistantFactory, env, null, null, null, null);
}
public TypeCheckInfo()
{
this(null, null, null, null, null, null);
}
@Override
public String toString()
{
return "Scope: " + scope + "\n" + env;
}
public TypeCheckInfo newConstraint(PType newConstraint)
{
TypeCheckInfo info = new TypeCheckInfo(assistantFactory, env, scope, qualifiers, newConstraint, returnType);
return info;
}
public TypeCheckInfo newScope(NameScope newScope)
{
TypeCheckInfo info = new TypeCheckInfo(assistantFactory, env, newScope, qualifiers, constraint, returnType);
return info;
}
public TypeCheckInfo newScope(List<PDefinition> definitions)
{
return newScope(definitions, scope);
}
public TypeCheckInfo newInfo(Environment newEnv)
{
TypeCheckInfo info = new TypeCheckInfo(assistantFactory, newEnv, scope, qualifiers, constraint, returnType);
return info;
}
public TypeCheckInfo newInfo(Environment newEnv, NameScope newScope)
{
TypeCheckInfo info = new TypeCheckInfo(assistantFactory, newEnv, newScope, qualifiers, constraint, returnType);
return info;
}
public TypeCheckInfo newScope(List<PDefinition> definitions,
NameScope newScope)
{
Environment newEnv = new FlatCheckedEnvironment(assistantFactory, definitions, env, newScope);
TypeCheckInfo info = new TypeCheckInfo(assistantFactory, newEnv, newScope);
return info;
}
}