/******************************************************************************* * Copyright (c) 2009-2013 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Anya Helene Bagge - anya@ii.uib.no (Univ. Bergen) *******************************************************************************/ package org.rascalmpl.library.util.tasks; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.rascalmpl.debug.IRascalMonitor; import org.rascalmpl.interpreter.IEvaluatorContext; import org.rascalmpl.interpreter.TypeReifier; import org.rascalmpl.interpreter.asserts.ImplementationError; import org.rascalmpl.interpreter.result.ICallableValue; import org.rascalmpl.interpreter.result.Result; import org.rascalmpl.interpreter.staticErrors.UnexpectedType; import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory; import org.rascalmpl.tasks.IIValueTask; import org.rascalmpl.tasks.ITaskRegistry; import org.rascalmpl.tasks.ITransaction; import org.rascalmpl.tasks.PDBValueTaskRegistry; import org.rascalmpl.tasks.Transaction; import org.rascalmpl.value.IBool; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.values.ValueFactoryFactory; public class Manager { private Transaction base = null; private final ITaskRegistry<Type, IValue, IValue> registry; private final IValueFactory vf; private final TypeReifier typeReifier; private final Map<IValueWrapper,ProducerWrapper> producers = new HashMap<IValueWrapper,ProducerWrapper>(); public Manager() { this(ValueFactoryFactory.getValueFactory()); } public Manager(IValueFactory vf) { this.vf = vf; this.typeReifier = new TypeReifier(vf); this.registry = PDBValueTaskRegistry.getRegistry(); } public void lockProducerRegistry() { registry.lock(); } public void unlockProducerRegistry() { registry.unlock(); } public IValue startTransaction(IEvaluatorContext ctx) { if(base == null) base = new Transaction(ctx.getStdErr()); return new Transaction(base, ctx.getStdErr()); } public IValue startTransaction(IValue tr, IEvaluatorContext ctx) { return new Transaction(transaction(tr), ctx.getStdErr()); } public void endTransaction(IValue tr) { transaction(tr).commit(); } public void abandonTransaction(IValue tr) { transaction(tr).abandon(); } public IValue getFact(IValue tr, IValue key, IValue name, IEvaluatorContext ctx) { if(!(key instanceof IConstructor)) throw RuntimeExceptionFactory.illegalArgument(key, ctx.getCurrentAST(), ctx.getStackTrace(), "key is not a reified type"); IValue fact = transaction(tr).getFact(ctx, typeReifier.valueToType((IConstructor) key), name); if(fact == null) fact = null; // <- put breakpoint here! return check(fact, (IConstructor) key, name, ctx); } private IValue check(IValue fact, IValue key, IValue name, IEvaluatorContext ctx) { if(!(key instanceof IConstructor)) throw RuntimeExceptionFactory.illegalArgument(key, ctx.getCurrentAST(), ctx.getStackTrace(), "key is not a reified type"); if(fact == null) throw RuntimeExceptionFactory.noSuchKey(vf.string(typeReifier.valueToType((IConstructor) key).toString() + ":" + name.toString()), ctx.getCurrentAST(), ctx.getStackTrace()); else if(!fact.getType().isSubtypeOf(typeReifier.valueToType((IConstructor) key))) throw new UnexpectedType(typeReifier.valueToType((IConstructor) key), fact.getType(), ctx.getCurrentAST()); else return fact; } public IValue queryFact(IValue tr, IValue key, IValue name, IEvaluatorContext ctx) { if(!(key instanceof IConstructor)) throw RuntimeExceptionFactory.illegalArgument(key, ctx.getCurrentAST(), ctx.getStackTrace(), "key is not a reified type"); return check(transaction(tr).queryFact(typeReifier.valueToType((IConstructor) key), name), key, name, ctx); } public void removeFact(IValue tr, IValue key, IValue name, IEvaluatorContext ctx) { if(!(key instanceof IConstructor)) throw RuntimeExceptionFactory.illegalArgument(key, ctx.getCurrentAST(), ctx.getStackTrace(), "key is not a reified type"); transaction(tr).removeFact(typeReifier.valueToType((IConstructor) key), name); } public void setFact(IValue tr, IValue key, IValue name, IValue value, IEvaluatorContext ctx) { if(!(key instanceof IConstructor)) throw RuntimeExceptionFactory.illegalArgument(key, ctx.getCurrentAST(), ctx.getStackTrace(), "key is not a reified type"); Type keyType = typeReifier.valueToType((IConstructor) key); if(!value.getType().isSubtypeOf(keyType)) throw new UnexpectedType(keyType, value.getType(), ctx.getCurrentAST()); else transaction(tr).setFact(keyType, name, value); } public void registerProducer(IValue producer, ISet keys, IEvaluatorContext ctx) { ProducerWrapper wrapper = new ProducerWrapper(ctx, (ICallableValue)producer, keys); producers.put(new IValueWrapper(producer), wrapper); registry.registerProducer(wrapper); } public void unregisterProducer(IValue producer) { IValueWrapper prod = new IValueWrapper(producer); if(producers.containsKey(prod)) { ProducerWrapper wrapper = producers.get(prod); registry.unregisterProducer(wrapper); producers.remove(prod); } } public ITuple getDependencyGraph(IValue tr) { return transaction(tr).getGraph(); } protected IConstructor reify(IEvaluatorContext ctx, Type type) { return typeReifier.typeToValue(type, ctx.getCurrentEnvt().getStore(), vf.mapWriter().done()); } /** * Cast an IValue to ITransaction */ protected static Transaction transaction(IValue tr) { if(tr instanceof Transaction) return (Transaction)tr; else throw new ImplementationError("Not a transaction: " + tr); } class ProducerWrapper implements IIValueTask { private ICallableValue fun; private IEvaluatorContext ctx; private Collection<Type> keys = new ArrayList<Type>(); ProducerWrapper(IEvaluatorContext ctx, ICallableValue fun, ISet keys) { this.ctx = ctx; this.fun = fun; for(IValue v : keys) { if(v instanceof ITuple) { IValue keyType = ((ITuple)v).get(0); IValue nameType = ((ITuple)v).get(1); this.keys.add(TypeFactory.getInstance().tupleType( typeReifier.valueToType((IConstructor)keyType), typeReifier.valueToType((IConstructor)nameType))); } else { this.keys.add(TypeFactory.getInstance().tupleType( typeReifier.valueToType((IConstructor)v), TypeFactory.getInstance().valueType())); } } } public boolean produce(IRascalMonitor monitor, ITransaction<Type, IValue, IValue> tr, Type key, IValue name) { Transaction t = (Transaction)tr; IValue reifiedKey = reify(ctx, key); Result<IValue> result = fun.call(monitor, new Type[] {t.getType(), reifiedKey.getType(), name.getType()}, new IValue[] {t, reifiedKey, name}, null); if(result.getValue() instanceof IBool) return ((IBool)result.getValue()).getValue(); else throw new UnexpectedType(TypeFactory.getInstance().boolType(), result.getType(), ctx.getCurrentAST()); } public Collection<Type> getKeys() { return keys; } } } class IValueWrapper { private final IValue value; IValueWrapper(IValue value) { this.value = value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; IValueWrapper other = (IValueWrapper) obj; if (value == null) { if (other.value != null) return false; } else if (!value.isEqual(other.value)) return false; return true; } }