/******************************************************************************* * 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: * * Mark Hills - Mark.Hills@cwi.nl (CWI) * * Arnold Lankamp - Arnold.Lankamp@cwi.nl *******************************************************************************/ package org.rascalmpl.interpreter; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.rascalmpl.interpreter.types.ReifiedType; import org.rascalmpl.library.Prelude; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IMap; import org.rascalmpl.value.IMapWriter; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISetWriter; 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.value.type.TypeStore; import org.rascalmpl.values.uptr.IRascalValueFactory; import org.rascalmpl.values.uptr.RascalValueFactory; /** * TypeReifier maps types to values that represent these types and their definitions. These values have * very specific types, namely 'type[&T]' where &T is bound to the type the value represents. <pre> data type[&T] = type(Symbol symbol, map[Symbol, Production] definitions); </pre> */ public class TypeReifier { private final IValueFactory vf; public TypeReifier(IValueFactory valueFactory) { this.vf = valueFactory; } public IConstructor typeToValue(Type t, TypeStore store, IMap syntax) { // after this definitions contains a relation from adt to constructors ISetWriter definitions = vf.setWriter(); IConstructor symbol = reify(t, definitions, store, syntax); // now we hash the relation on adt, resulting in a map from adt to set of constructors IMap index = new Prelude(vf).index(definitions.done()); // TODO: bring index functionality to rascal-value library IMapWriter grammar = vf.mapWriter(); // and here we wrap the set of constructors in a choice operator for (IValue sym : index) { ISet alts = (ISet) index.get(sym); grammar.put(sym, vf.constructor(RascalValueFactory.Production_Choice, sym, alts)); } return IRascalValueFactory.getInstance().reifiedType(symbol, grammar.done()); } public Type valueToType(IConstructor typeValue) { return valueToType(typeValue, new TypeStore()); } /** * Reconstruct a type from a reified type value and declare all types used. * @param typeValue the type value to restore * @param store a possibly empty store that will be filled with the relevant type declarations. * @return the type corresponding to the reified type value */ public Type valueToType(IConstructor typeValue, TypeStore store) { if (typeValue.getType() instanceof ReifiedType) { /* Although the type of this value contains already a type, it may be more general * then the type represented by the symbol. So, we do have to map the symbol to * a type recursively. * * We also need to construct a TypeStore from the declarations, such that the * appropriate definitions for ADT's and aliases can be found. */ IMap definitions = (IMap) typeValue.get("definitions"); return TypeFactory.getInstance().fromSymbol((IConstructor) typeValue.get("symbol"), store, x -> getAlternatives(definitions, x)); } throw new IllegalArgumentException(typeValue + " is not a reified type."); } /** * Converts a production a constructor type, * all side-effects in typestores are discarded. * @param prod value which represents a constructor definition as produced by typeToValue or the compiler * @return a constructor type as if production by @{link TypeFactory} */ public Type productionToConstructorType(IConstructor prod) { if (prod.getConstructorType() == RascalValueFactory.Symbol_Prod) { return productionToConstructorType(convertSymbolProdToProduction(prod)); } // TODO remove check after bootstrap suc6 IConstructor adt = (IConstructor) (prod.has("adt") ? prod.get("adt") : prod.get("def")); return TypeFactory.getInstance().fromSymbol(prod, new TypeStore(), x -> x == adt ? Collections.singleton(prod) : Collections.emptySet()); } /** * The type checker uses a production representation of type Symbol internally, * which we convert here to a production representation of type Production for further processing */ private IConstructor convertSymbolProdToProduction(IConstructor prod) { IValue sort = prod.get("sort"); IValue parameters = prod.get("parameters"); IValue attributes = prod.get("attributes"); return vf.constructor(RascalValueFactory.Production_Default, sort, parameters, attributes); } private Set<IConstructor> getAlternatives(IMap definitions, IConstructor x) { IConstructor choice = (IConstructor) definitions.get(x); if (choice == null || choice.getConstructorType() != RascalValueFactory.Production_Choice) { return Collections.emptySet(); } Set<IConstructor> result = new HashSet<>(); for (IValue alt : ((ISet) choice.get("alternatives"))) { result.add((IConstructor) alt); } return result; } /** * Reconstruct a type from a reified type value; without declaration side-effect. * If you need a TypeStore reconstructed see the other overload of symbolToType. * @param typeValue the type value to restore * @param definitions the definition */ public Type symbolToType(IConstructor symbol) { return TypeFactory.getInstance().fromSymbol(symbol, new TypeStore(), x -> Collections.emptySet()); } /** * Reconstruct a type from a reified type value, and declare all types used first using the given definitions * @param typeValue the type value to restore * @param definitions the definition */ public Type symbolToType(IConstructor symbol, IMap definitions) { return TypeFactory.getInstance().fromSymbol(symbol, new TypeStore(), x -> getAlternatives(definitions, x)); } private IConstructor reify(Type t, ISetWriter definitions, final TypeStore store, IMap syntax) { return t.asSymbol(vf, new TypeStoreWithSyntax(vf, store, syntax), definitions, new HashSet<>()); } public static class TypeStoreWithSyntax extends TypeStore { private final IMap grammar; private final IValueFactory vf; public TypeStoreWithSyntax(IValueFactory vf, TypeStore parent, IMap grammar) { this.grammar = grammar; this.vf = vf; extendStore(parent); } public ISet getRules(IConstructor nt) { IConstructor choice = (IConstructor) grammar.get(nt); return choice != null ? (ISet) choice.get("alternatives") : vf.setWriter().done(); } } }