protected void insertCompilationUnitMessages(boolean insertErrors, IList otherMessages) { org.rascalmpl.value.type.Type args = TF.tupleType(TF.stringType(), TF.sourceLocationType()); IValueList result = new IValueList(values); if (otherMessages != null) { for (IValue message : otherMessages) { result.add(message); } } if (insertErrors) { int i; IProblem[] problems = compilUnit.getProblems(); for (i = 0; i < problems.length; i++) { int offset = problems[i].getSourceStart(); int length = problems[i].getSourceEnd() - offset + 1; int sl = problems[i].getSourceLineNumber(); ISourceLocation pos = values.sourceLocation(loc, offset, length, sl, sl, 0, 0); org.rascalmpl.value.type.Type constr; if (problems[i].isError()) { constr = typeStore.lookupConstructor( this.typeStore.lookupAbstractDataType("Message"), "error", args); } else { constr = typeStore.lookupConstructor( this.typeStore.lookupAbstractDataType("Message"), "warning", args); } result.add(values.constructor(constr, values.string(problems[i].getMessage()), pos)); } } setAnnotation("messages", result.asList()); }
@Override public Type getKeywordArgumentTypes(Environment scope) { ArrayList<String> labels = new ArrayList<>(); ArrayList<Type> types = new ArrayList<>(); // TODO: I am not sure this is what we want. Double names will end up twice in the tuple type... for (AbstractFunction c : primaryCandidates) { Type args = c.getKeywordArgumentTypes(scope); if (args != null && args.hasFieldNames()) { for (String label : args.getFieldNames()) { labels.add(label); types.add(args.getFieldType(label)); } } } for (AbstractFunction c : defaultCandidates) { Type args = c.getKeywordArgumentTypes(scope); if (args != null && args.hasFieldNames()) { for (String label : args.getFieldNames()) { labels.add(label); types.add(args.getFieldType(label)); } } } return TF.tupleType( types.toArray(new Type[types.size()]), labels.toArray(new String[labels.size()])); }
public static IList compose(IList rel1, IList rel2) { Type otherTupleType = rel2.getType().getFieldTypes(); if (rel1.getElementType() == voidType) return rel1; if (otherTupleType == voidType) return rel2; if (rel1.getElementType().getArity() != 2 || otherTupleType.getArity() != 2) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType); // Relaxed type constraint: if (!rel1.getElementType().getFieldType(1).comparable(otherTupleType.getFieldType(0))) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType); Type[] newTupleFieldTypes = new Type[] {rel1.getElementType().getFieldType(0), otherTupleType.getFieldType(1)}; Type tupleType = typeFactory.tupleType(newTupleFieldTypes); IListWriter w = new ListWriter(tupleType); for (IValue v1 : rel1) { ITuple tuple1 = (ITuple) v1; for (IValue t2 : rel2) { ITuple tuple2 = (ITuple) t2; if (tuple1.get(1).isEqual(tuple2.get(0))) { w.append(Tuple.newTuple(tuple1.get(0), tuple2.get(1))); } } } return w.done(); }
private static Type lub(List<AbstractFunction> candidates) { Set<FunctionType> alternatives = new HashSet<FunctionType>(); Iterator<AbstractFunction> iter = candidates.iterator(); if (!iter.hasNext()) { return TF.voidType(); } FunctionType first = iter.next().getFunctionType(); Type returnType = first.getReturnType(); alternatives.add(first); AbstractFunction l = null; while (iter.hasNext()) { l = iter.next(); if (l.getFunctionType().getReturnType() == returnType) { alternatives.add(l.getFunctionType()); } else { return TF.valueType(); } } return RascalTypeFactory.getInstance().overloadedFunctionType(alternatives); }
private static String computeMessage( String name, List<AbstractFunction> candidates, Type[] argTypes) { StringBuilder b = new StringBuilder(); b.append("The called signature: " + name); b.append('('); argumentTypes(TypeFactory.getInstance().tupleType(argTypes), b); b.append(')'); if (candidates.size() == 1) { b.append(",\ndoes not match the declared signature:"); } else { b.append(",\ndoes not match any of the declared (overloaded) signature patterns:\n"); } for (AbstractFunction c : candidates) { b.append('\t'); b.append(c.toString()); b.append('\n'); } return b.toString(); }
public ITree filterAmbiguity(ITree ambCluster, Object environment) { ISet alts = (ISet) ambCluster.get("alternatives"); if (alts.size() == 0) { return null; } Environment env = (Environment) environment; Result<IValue> var = env.getFrameVariable("amb"); if (var != null && var instanceof ICallableValue) { Type type = RascalTypeFactory.getInstance().nonTerminalType(ambCluster); ICallableValue func = (ICallableValue) var; try { Result<IValue> result = func.call(new Type[] {TF.setType(type)}, new IValue[] {alts}, null); if (result.getType().isBottom()) { return ambCluster; } ITree r = (ITree) result.getValue(); if (TreeAdapter.isAmb(r)) { ISet returnedAlts = TreeAdapter.getAlternatives(r); if (returnedAlts.size() == 1) { return (ITree) returnedAlts.iterator().next(); } else if (returnedAlts.size() == 0) { return null; } else { return r; } } return (ITree) result.getValue(); } catch (ArgumentMismatch e) { return ambCluster; } } return ambCluster; }
public ISourceLocation resolveSourceLocation(ISourceLocation loc) { String scheme = loc.getScheme(); int pos; ICallableValue resolver = sourceResolvers.get(scheme); if (resolver == null) { for (char sep : new char[] {'+', ':'}) { pos = scheme.indexOf(sep); if (pos != -1) { scheme = scheme.substring(0, pos); } } resolver = sourceResolvers.get(scheme); if (resolver == null) { return loc; } } Type[] argTypes = new Type[] {TypeFactory.getInstance().sourceLocationType()}; IValue[] argValues = new IValue[] {loc}; return (ISourceLocation) resolver.call(argTypes, argValues, null).getValue(); }
/** * This is the way of executing actions for Rascal syntax definitions. Each function that returns a * non-terminal type and is named one of the constructor names of one of the alternatives and has * the same argument types as the syntax production will be called when a certain production is * constructed, e.g: * * <p>Stat if(Exp e, Stat thenPart, Stat elsePart); * * <p>Also, on ambiguity clusters functions named 'amb' are called with a set[&T] argument for the * alternatives, e.g. Stat amb(set[Stat] alternatives); * * <p>Also, on entering a production the 'enter' function is called with a reifed type argument for * the production type that is entered: void enter(type[Stat.If] prod); * * <p>Also on exiting a production the 'exit' function is called, similarly: void exit(type[Stat.If] * prod); * * <p>Note that RascalFunctionActionExecutors use functions visible from the call site of the parse * function. */ public class RascalFunctionActionExecutor implements IActionExecutor<ITree> { private static final TypeFactory TF = TypeFactory.getInstance(); private final IEvaluatorContext ctx; public RascalFunctionActionExecutor(IEvaluatorContext ctx) { this.ctx = ctx; } public void completed(Object environment, boolean filtered) {} public Object createRootEnvironment() { return ctx.getCurrentEnvt(); } public Object enteringListNode(Object production, int index, Object environment) { return environment; } public Object enteringListProduction(Object production, Object env) { return env; } public Object enteringNode(Object production, int index, Object environment) { return environment; } public Object enteringProduction(Object production, Object env) { return env; } public void exitedListProduction(Object production, boolean filtered, Object environment) {} public void exitedProduction(Object production, boolean filtered, Object environment) {} public ITree filterAmbiguity(ITree ambCluster, Object environment) { ISet alts = (ISet) ambCluster.get("alternatives"); if (alts.size() == 0) { return null; } Environment env = (Environment) environment; Result<IValue> var = env.getFrameVariable("amb"); if (var != null && var instanceof ICallableValue) { Type type = RascalTypeFactory.getInstance().nonTerminalType(ambCluster); ICallableValue func = (ICallableValue) var; try { Result<IValue> result = func.call(new Type[] {TF.setType(type)}, new IValue[] {alts}, null); if (result.getType().isBottom()) { return ambCluster; } ITree r = (ITree) result.getValue(); if (TreeAdapter.isAmb(r)) { ISet returnedAlts = TreeAdapter.getAlternatives(r); if (returnedAlts.size() == 1) { return (ITree) returnedAlts.iterator().next(); } else if (returnedAlts.size() == 0) { return null; } else { return r; } } return (ITree) result.getValue(); } catch (ArgumentMismatch e) { return ambCluster; } } return ambCluster; } @Override public ITree filterCycle(ITree cycle, Object environment) { return cycle; } @Override public ITree filterListAmbiguity(ITree ambCluster, Object environment) { return filterAmbiguity(ambCluster, environment); } @Override public ITree filterListCycle(ITree cycle, Object environment) { return cycle; } @Override public ITree filterListProduction(ITree tree, Object environment) { return tree; } @Override public ITree filterProduction(ITree tree, Object environment) { String cons = TreeAdapter.getConstructorName(tree); if (cons != null) { Environment env = (Environment) environment; Result<IValue> var = env.getFrameVariable(cons); if (var != null && var instanceof ICallableValue) { ICallableValue function = (ICallableValue) var; try { Result<IValue> result = null; if (TreeAdapter.isContextFree(tree)) { // For context free trees, try it without layout and literal arguments first. result = call(function, TreeAdapter.getASTArgs(tree)); } if (result == null) { result = call(function, TreeAdapter.getArgs(tree)); } if (result == null) { return tree; } if (result.getType().isBottom()) { return tree; } if (!(result.getType() instanceof NonTerminalType && SymbolAdapter.isEqual( ((NonTerminalType) result.getType()).getSymbol(), TreeAdapter.getType(tree)))) { // do not call the function if it does not return the right type return tree; } return (ITree) result.getValue(); } catch (Filtered f) { return null; } } } return tree; } private static Result<IValue> call(ICallableValue function, IList args) { try { int nrOfArgs = args.length(); Type[] types = new Type[nrOfArgs]; IValue[] actuals = new IValue[nrOfArgs]; for (int i = nrOfArgs - 1; i >= 0; --i) { IValue arg = args.get(i); types[i] = RascalTypeFactory.getInstance().nonTerminalType((IConstructor) arg); actuals[i] = arg; } return function.call(types, actuals, null); } catch (MatchFailed e) { return null; } catch (Failure f) { return null; } } public boolean isImpure(Object rhs) { return true; } }
protected IValue constructTypeNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_TYPE_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); }
public abstract class JavaToRascalConverter extends ASTVisitor { protected static final IValueFactory values = ValueFactoryFactory.getValueFactory(); protected static final TypeFactory TF = TypeFactory.getInstance(); protected final TypeStore typeStore; protected IValue ownValue; private static final String DATATYPE_RASCAL_AST_TYPE_NODE = "Type"; private static final String DATATYPE_RASCAL_AST_MODIFIER_NODE = "Modifier"; private static final String DATATYPE_RASCAL_AST_DECLARATION_NODE = "Declaration"; private static final String DATATYPE_RASCAL_AST_EXPRESSION_NODE = "Expression"; private static final String DATATYPE_RASCAL_AST_STATEMENT_NODE = "Statement"; private static final String DATATYPE_RASCAL_MESSAGE = "Message"; private static final String DATATYPE_RASCAL_MESSAGE_ERROR = "error"; private final org.rascalmpl.value.type.Type DATATYPE_RASCAL_AST_DECLARATION_NODE_TYPE; private final org.rascalmpl.value.type.Type DATATYPE_RASCAL_AST_EXPRESSION_NODE_TYPE; private final org.rascalmpl.value.type.Type DATATYPE_RASCAL_AST_STATEMENT_NODE_TYPE; protected static org.rascalmpl.value.type.Type DATATYPE_RASCAL_AST_TYPE_NODE_TYPE; protected static org.rascalmpl.value.type.Type DATATYPE_RASCAL_AST_MODIFIER_NODE_TYPE; protected static org.rascalmpl.value.type.Type DATATYPE_RASCAL_MESSAGE_DATA_TYPE; protected static org.rascalmpl.value.type.Type DATATYPE_RASCAL_MESSAGE_ERROR_NODE_TYPE; protected CompilationUnit compilUnit; protected ISourceLocation loc; protected final BindingsResolver bindingsResolver; protected final boolean collectBindings; protected IListWriter messages; protected final Map<String, ISourceLocation> locationCache; JavaToRascalConverter( final TypeStore typeStore, Map<String, ISourceLocation> cache, boolean collectBindings) { super(true); this.typeStore = typeStore; this.bindingsResolver = new BindingsResolver(typeStore, cache, collectBindings); this.collectBindings = collectBindings; DATATYPE_RASCAL_AST_TYPE_NODE_TYPE = this.typeStore.lookupAbstractDataType(DATATYPE_RASCAL_AST_TYPE_NODE); DATATYPE_RASCAL_AST_MODIFIER_NODE_TYPE = this.typeStore.lookupAbstractDataType(DATATYPE_RASCAL_AST_MODIFIER_NODE); this.DATATYPE_RASCAL_AST_DECLARATION_NODE_TYPE = typeStore.lookupAbstractDataType(DATATYPE_RASCAL_AST_DECLARATION_NODE); this.DATATYPE_RASCAL_AST_EXPRESSION_NODE_TYPE = typeStore.lookupAbstractDataType(DATATYPE_RASCAL_AST_EXPRESSION_NODE); this.DATATYPE_RASCAL_AST_STATEMENT_NODE_TYPE = typeStore.lookupAbstractDataType(DATATYPE_RASCAL_AST_STATEMENT_NODE); JavaToRascalConverter.DATATYPE_RASCAL_MESSAGE_DATA_TYPE = typeStore.lookupAbstractDataType(DATATYPE_RASCAL_MESSAGE); JavaToRascalConverter.DATATYPE_RASCAL_MESSAGE_ERROR_NODE_TYPE = typeStore .lookupConstructor(DATATYPE_RASCAL_MESSAGE_DATA_TYPE, DATATYPE_RASCAL_MESSAGE_ERROR) .iterator() .next(); this.locationCache = cache; messages = values.listWriter(); } protected ISourceLocation resolveBinding(String packageComponent) { ISourceLocation packageBinding = new BindingsResolver(typeStore, locationCache, this.collectBindings) { public ISourceLocation resolveBinding(String packageC) { try { if (collectBindings) { if (locationCache.containsKey(packageC)) { return locationCache.get(packageC); } return values.sourceLocation("java+package", null, packageC); } return values.sourceLocation("unknown", null, null); } catch (URISyntaxException e) { throw new RuntimeException("Should not happen", e); } } }.resolveBinding(packageComponent); locationCache.put(packageComponent, packageBinding); return packageBinding; } protected ISourceLocation resolveBinding(CompilationUnit node) { ISourceLocation compilationUnit = new BindingsResolver(typeStore, locationCache, true) { public ISourceLocation resolveBinding(CompilationUnit node) { return makeBinding("java+compilationUnit", null, loc.getPath()); } }.resolveBinding(node); return compilationUnit; } protected ISourceLocation resolveBinding(IBinding binding) { ISourceLocation resolvedBinding = bindingsResolver.resolveBinding(binding); if (binding != null) locationCache.put(binding.getKey(), resolvedBinding); return resolvedBinding; } protected ISourceLocation resolveDeclaringClass(IBinding binding) { ISourceLocation resolvedBinding; if (binding instanceof ITypeBinding) { resolvedBinding = bindingsResolver.resolveBinding(((ITypeBinding) binding).getDeclaringClass()); } else if (binding instanceof IMethodBinding) { resolvedBinding = bindingsResolver.resolveBinding(((IMethodBinding) binding).getDeclaringClass()); } else if (binding instanceof IVariableBinding) { resolvedBinding = bindingsResolver.resolveBinding(((IVariableBinding) binding).getDeclaringClass()); } else { binding = null; resolvedBinding = bindingsResolver.resolveBinding(binding); } return resolvedBinding; } protected ISourceLocation resolveBinding(ASTNode node) { if (node instanceof CompilationUnit) { return resolveBinding((CompilationUnit) node); } return bindingsResolver.resolveBinding(node); } protected ISourceLocation getSourceLocation(ASTNode node) { try { int nodeLength = compilUnit.getExtendedLength(node); if (nodeLength > 0) { int start = compilUnit.getExtendedStartPosition(node); int end = start + nodeLength - 1; if (end < start && ((node.getFlags() & 9) > 0)) { insert( messages, values.constructor( DATATYPE_RASCAL_MESSAGE_ERROR_NODE_TYPE, values.string("Recovered/Malformed node, guessing the length"), values.sourceLocation(loc, 0, 0))); nodeLength = node.toString().length(); end = start + nodeLength - 1; } return values.sourceLocation( loc, start, nodeLength, compilUnit.getLineNumber(start), compilUnit.getLineNumber(end), // TODO: only adding 1 at the end seems to work, need to test. compilUnit.getColumnNumber(start), compilUnit.getColumnNumber(end) + 1); } } catch (IllegalArgumentException e) { insert( messages, values.constructor( DATATYPE_RASCAL_MESSAGE_ERROR_NODE_TYPE, values.string("Most probably missing dependency"), values.sourceLocation(loc, 0, 0))); } return values.sourceLocation(loc, 0, 0, 0, 0, 0, 0); } protected IValue[] removeNulls(IValue... withNulls) { List<IValue> withOutNulls = new ArrayList<IValue>(); for (IValue child : withNulls) { if (!(child == null)) { withOutNulls.add(child); } } return withOutNulls.toArray(new IValue[withOutNulls.size()]); } protected IValueList parseModifiers(int modifiers) { IValueList extendedModifierList = new IValueList(values); for (String constructor : java.lang.reflect.Modifier.toString(modifiers).split(" ")) { Set<org.rascalmpl.value.type.Type> exConstr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_MODIFIER_NODE_TYPE, constructor); for (org.rascalmpl.value.type.Type con : exConstr) { extendedModifierList.add(values.constructor(con)); } } return extendedModifierList; } @SuppressWarnings({"rawtypes"}) protected IValueList parseExtendedModifiers(List ext) { IValueList extendedModifierList = new IValueList(values); for (Iterator it = ext.iterator(); it.hasNext(); ) { ASTNode p = (ASTNode) it.next(); IValue val = visitChild(p); if (p instanceof Annotation) { val = constructModifierNode("annotation", val); } extendedModifierList.add(val); } return extendedModifierList; } @SuppressWarnings("deprecation") protected IValueList parseExtendedModifiers(BodyDeclaration node) { if (node.getAST().apiLevel() == AST.JLS2) { return parseModifiers(node.getModifiers()); } else { return parseExtendedModifiers(node.modifiers()); } } protected IValue visitChild(ASTNode node) { node.accept(this); return this.getValue(); } public IValue getValue() { return this.ownValue; } protected IConstructor constructModifierNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_MODIFIER_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); } protected void setAnnotation(String annoName, IValue annoValue) { if (this.ownValue == null) { return; } if (annoValue != null && ownValue.getType().declaresAnnotation(this.typeStore, annoName)) { ownValue = ((IConstructor) ownValue).asAnnotatable().setAnnotation(annoName, annoValue); } } protected void setAnnotation(String annoName, IValueList annoList) { IList annos = (IList) annoList.asList(); if (this.ownValue == null) { return; } if (annoList != null && this.ownValue.getType().declaresAnnotation(this.typeStore, annoName) && !annos.isEmpty()) { this.ownValue = ((IConstructor) this.ownValue).asAnnotatable().setAnnotation(annoName, annos); } } protected IValue constructDeclarationNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_DECLARATION_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); } protected IValue constructExpressionNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_EXPRESSION_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); } protected IValue constructStatementNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_STATEMENT_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); } protected IValue constructTypeNode(String constructor, IValue... children) { org.rascalmpl.value.type.Type args = TF.tupleType(removeNulls(children)); org.rascalmpl.value.type.Type constr = typeStore.lookupConstructor(DATATYPE_RASCAL_AST_TYPE_NODE_TYPE, constructor, args); return values.constructor(constr, removeNulls(children)); } protected void insertCompilationUnitMessages(boolean insertErrors, IList otherMessages) { org.rascalmpl.value.type.Type args = TF.tupleType(TF.stringType(), TF.sourceLocationType()); IValueList result = new IValueList(values); if (otherMessages != null) { for (IValue message : otherMessages) { result.add(message); } } if (insertErrors) { int i; IProblem[] problems = compilUnit.getProblems(); for (i = 0; i < problems.length; i++) { int offset = problems[i].getSourceStart(); int length = problems[i].getSourceEnd() - offset + 1; int sl = problems[i].getSourceLineNumber(); ISourceLocation pos = values.sourceLocation(loc, offset, length, sl, sl, 0, 0); org.rascalmpl.value.type.Type constr; if (problems[i].isError()) { constr = typeStore.lookupConstructor( this.typeStore.lookupAbstractDataType("Message"), "error", args); } else { constr = typeStore.lookupConstructor( this.typeStore.lookupAbstractDataType("Message"), "warning", args); } result.add(values.constructor(constr, values.string(problems[i].getMessage()), pos)); } } setAnnotation("messages", result.asList()); } public void insert(IListWriter listW, IValue message) { if (message.getType().isConstructor() && message.getType().getAbstractDataType().getName().equals("Message")) { listW.insert(message); } } public void convert(CompilationUnit root, ASTNode node, ISourceLocation loc) { this.compilUnit = root; this.loc = loc; node.accept(this); } }
public class OverloadedFunction extends Result<IValue> implements IExternalValue, ICallableValue { private static final TypeFactory TF = TypeFactory.getInstance(); private final List<AbstractFunction> primaryCandidates; // it should be a list to allow proper shadowing private final List<AbstractFunction> defaultCandidates; // it should be a list to allow proper shadowing private final String name; private final boolean isStatic; public OverloadedFunction( String name, Type type, List<AbstractFunction> candidates, List<AbstractFunction> defaults, IEvaluatorContext ctx) { super(type, null, ctx); if (candidates.size() + defaults.size() <= 0) { throw new ImplementationError("at least need one function"); } this.name = name; this.primaryCandidates = new ArrayList<AbstractFunction>(candidates.size()); this.defaultCandidates = new ArrayList<AbstractFunction>(candidates.size()); addAll(primaryCandidates, candidates, true); addAll(defaultCandidates, defaults, false); isStatic = checkStatic(primaryCandidates) && checkStatic(defaultCandidates); } @Override public IConstructor encodeAsConstructor() { TypeReifier tr = new TypeReifier(getValueFactory()); return tr.overloadedToProduction(this, ctx); } public List<AbstractFunction> getPrimaryCandidates() { return primaryCandidates; } public List<AbstractFunction> getDefaultCandidates() { return defaultCandidates; } @Override public Type getKeywordArgumentTypes(Environment scope) { ArrayList<String> labels = new ArrayList<>(); ArrayList<Type> types = new ArrayList<>(); // TODO: I am not sure this is what we want. Double names will end up twice in the tuple type... for (AbstractFunction c : primaryCandidates) { Type args = c.getKeywordArgumentTypes(scope); if (args != null && args.hasFieldNames()) { for (String label : args.getFieldNames()) { labels.add(label); types.add(args.getFieldType(label)); } } } for (AbstractFunction c : defaultCandidates) { Type args = c.getKeywordArgumentTypes(scope); if (args != null && args.hasFieldNames()) { for (String label : args.getFieldNames()) { labels.add(label); types.add(args.getFieldType(label)); } } } return TF.tupleType( types.toArray(new Type[types.size()]), labels.toArray(new String[labels.size()])); } public OverloadedFunction(AbstractFunction function) { super(function.getType(), null, function.getEval()); this.name = function.getName(); this.primaryCandidates = new ArrayList<AbstractFunction>(1); this.defaultCandidates = new ArrayList<AbstractFunction>(1); if (function.isDefault()) { defaultCandidates.add(function); } else { primaryCandidates.add(function); } this.isStatic = function.isStatic(); } public OverloadedFunction(String name, List<AbstractFunction> funcs) { super(lub(funcs), null, funcs.iterator().next().getEval()); this.name = name; this.primaryCandidates = new ArrayList<AbstractFunction>(1); this.defaultCandidates = new ArrayList<AbstractFunction>(1); addAll(primaryCandidates, funcs, true); addAll(defaultCandidates, funcs, false); this.isStatic = checkStatic(funcs); } private OverloadedFunction( String name, Type type, List<AbstractFunction> candidates, List<AbstractFunction> defaults, boolean isStatic, IEvaluatorContext ctx) { super(type, null, ctx); this.name = name; this.primaryCandidates = candidates; this.defaultCandidates = defaults; this.isStatic = isStatic; } @Override public OverloadedFunction cloneInto(Environment env) { List<AbstractFunction> newCandidates = new ArrayList<>(); for (AbstractFunction f : primaryCandidates) { newCandidates.add((AbstractFunction) f.cloneInto(env)); } List<AbstractFunction> newDefaultCandidates = new ArrayList<>(); for (AbstractFunction f : defaultCandidates) { newDefaultCandidates.add((AbstractFunction) f.cloneInto(env)); } OverloadedFunction of = new OverloadedFunction(name, getType(), newCandidates, newDefaultCandidates, isStatic, ctx); of.setPublic(isPublic()); return of; } /** * This function groups occurrences of pattern dispatched functions as one "PatternFunction" that * has a hash table to look up based on outermost function symbol. A group is a bunch of functions * that have an ADT as a first parameter type and a call or tree pattern with a fixed name as the * first parameter pattern, or it is a singleton other case. The addAll function retains the order * of the functions from the candidates list, in order to preserve shadowing rules! */ private void addAll( List<AbstractFunction> container, List<AbstractFunction> candidates, boolean nonDefault) { @SuppressWarnings("unchecked") Map<String, List<AbstractFunction>>[] constructors = new Map[10]; @SuppressWarnings("unchecked") Map<IConstructor, List<AbstractFunction>>[] productions = new Map[10]; List<AbstractFunction> other = new LinkedList<AbstractFunction>(); for (AbstractFunction func : candidates) { if (nonDefault && func.isDefault()) { continue; } if (!nonDefault && !func.isDefault()) { continue; } String label = null; IConstructor prod = null; if (func.isPatternDispatched()) { // this one is already hashed, but we might find more to add to that map in the next round Map<String, List<AbstractFunction>> funcMap = ((AbstractPatternDispatchedFunction) func).getMap(); int pos = func.getIndexedArgumentPosition(); for (String key : funcMap.keySet()) { addFuncsToMap(pos, constructors, funcMap.get(key), key); } } else if (func.isConcretePatternDispatched()) { // this one is already hashed, but we might find more to add to that map in the next round Map<IConstructor, List<AbstractFunction>> funcMap = ((ConcretePatternDispatchedFunction) func).getMap(); int pos = func.getIndexedArgumentPosition(); for (IConstructor key : funcMap.keySet()) { addProdsToMap(pos, productions, funcMap.get(key), key); } } else { // a new function definition, that may be hashable int pos = func.getIndexedArgumentPosition(); label = func.getIndexedLabel(); prod = func.getIndexedProduction(); if (label != null) { // we found another one to hash addFuncToMap(pos, constructors, func, label); } else if (prod != null) { addProdToMap(pos, productions, func, prod); } else { other.add(func); } } } for (int i = 0; i < constructors.length; i++) { if (constructors[i] != null && !constructors[i].isEmpty()) { container.add( new AbstractPatternDispatchedFunction( ctx.getEvaluator(), i, name, type, constructors[i])); } } for (int i = 0; i < productions.length; i++) { if (productions[i] != null && !productions[i].isEmpty()) { container.add( new ConcretePatternDispatchedFunction( ctx.getEvaluator(), i, name, type, productions[i])); } } container.addAll(other); } private void addFuncToMap( int pos, Map<String, List<AbstractFunction>>[] map, AbstractFunction func, String label) { if (map[pos] == null) { map[pos] = new HashMap<>(); } List<AbstractFunction> l = map[pos].get(label); if (l == null) { l = new LinkedList<AbstractFunction>(); map[pos].put(label, l); } l.add(func); } private void addProdToMap( int pos, Map<IConstructor, List<AbstractFunction>>[] map, AbstractFunction func, IConstructor label) { if (map[pos] == null) { map[pos] = new HashMap<>(); } List<AbstractFunction> l = map[pos].get(label); if (l == null) { l = new LinkedList<AbstractFunction>(); map[pos].put(label, l); } l.add(func); } private void addFuncsToMap( int pos, Map<String, List<AbstractFunction>>[] map, List<AbstractFunction> funcs, String label) { if (map[pos] == null) { map[pos] = new HashMap<>(); } List<AbstractFunction> l = map[pos].get(label); if (l == null) { l = new LinkedList<AbstractFunction>(); map[pos].put(label, l); } l.addAll(funcs); } private void addProdsToMap( int pos, Map<IConstructor, List<AbstractFunction>>[] map, List<AbstractFunction> funcs, IConstructor label) { if (map[pos] == null) { map[pos] = new HashMap<>(); } List<AbstractFunction> l = map[pos].get(label); if (l == null) { l = new LinkedList<AbstractFunction>(); map[pos].put(label, l); } l.addAll(funcs); } @Override public int getArity() { throw new UnsupportedOperationException(); } @Override public boolean hasVarArgs() { throw new UnsupportedOperationException(); } @Override public boolean hasKeywordArguments() { throw new UnsupportedOperationException(); } @Override public boolean isStatic() { return isStatic; } private static boolean checkStatic(List<AbstractFunction> l) { for (ICallableValue f : l) { if (!f.isStatic()) { return false; } } return true; } @Override public IValue getValue() { return this; } private static Type lub(List<AbstractFunction> candidates) { Set<FunctionType> alternatives = new HashSet<FunctionType>(); Iterator<AbstractFunction> iter = candidates.iterator(); if (!iter.hasNext()) { return TF.voidType(); } FunctionType first = iter.next().getFunctionType(); Type returnType = first.getReturnType(); alternatives.add(first); AbstractFunction l = null; while (iter.hasNext()) { l = iter.next(); if (l.getFunctionType().getReturnType() == returnType) { alternatives.add(l.getFunctionType()); } else { return TF.valueType(); } } return RascalTypeFactory.getInstance().overloadedFunctionType(alternatives); } @Override public Result<IValue> call( IRascalMonitor monitor, Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) { IRascalMonitor old = ctx.getEvaluator().setMonitor(monitor); try { return call(argTypes, argValues, keyArgValues); } finally { ctx.getEvaluator().setMonitor(old); } } @Override public Result<IValue> call( Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues) { Result<IValue> result = callWith( primaryCandidates, argTypes, argValues, keyArgValues, defaultCandidates.size() <= 0); if (result == null && defaultCandidates.size() > 0) { result = callWith(defaultCandidates, argTypes, argValues, keyArgValues, true); } if (result == null) { throw new MatchFailed(); } return result; } private static Result<IValue> callWith( List<AbstractFunction> candidates, Type[] argTypes, IValue[] argValues, Map<String, IValue> keyArgValues, boolean mustSucceed) { AbstractFunction failed = null; Failure failure = null; for (AbstractFunction candidate : candidates) { if ((candidate.hasVarArgs() && argValues.length >= candidate.getArity() - 1) || candidate.getArity() == argValues.length || candidate.hasKeywordArguments()) { try { return candidate.call(argTypes, argValues, keyArgValues); } catch (MatchFailed m) { // could happen if pattern dispatched } catch (Failure e) { failed = candidate; failure = e; // could happen if function body throws fail } } } if (failed != null && mustSucceed) { throw new UnguardedFail(failed.ast, failure); } return null; } public OverloadedFunction join(OverloadedFunction other) { if (other == null) { return this; } List<AbstractFunction> joined = new ArrayList<AbstractFunction>(other.primaryCandidates.size() + primaryCandidates.size()); List<AbstractFunction> defJoined = new ArrayList<AbstractFunction>(other.defaultCandidates.size() + defaultCandidates.size()); joined.addAll(primaryCandidates); defJoined.addAll(defaultCandidates); for (AbstractFunction cand : other.primaryCandidates) { if (!joined.contains(cand)) { joined.add(cand); } } for (AbstractFunction cand : other.defaultCandidates) { if (!defJoined.contains(cand)) { defJoined.add(cand); } } return new OverloadedFunction( "(" + name + "+" + other.getName() + ")", lub(joined).lub(lub(defJoined)), joined, defJoined, ctx); } public OverloadedFunction add(AbstractFunction candidate) { List<AbstractFunction> joined = new ArrayList<AbstractFunction>(primaryCandidates.size() + 1); joined.addAll(primaryCandidates); List<AbstractFunction> defJoined = new ArrayList<AbstractFunction>(defaultCandidates.size() + 1); defJoined.addAll(defaultCandidates); if (candidate.isDefault() && !defJoined.contains(candidate)) { defJoined.add(candidate); } else if (!candidate.isDefault() && !joined.contains(candidate)) { joined.add(candidate); } return new OverloadedFunction( "(" + name + "+" + candidate.getName() + ")", lub(joined).lub(lub(defJoined)), joined, defJoined, ctx); } @Override public boolean equals(Object obj) { if (obj instanceof OverloadedFunction) { OverloadedFunction other = (OverloadedFunction) obj; return primaryCandidates.containsAll(other.primaryCandidates) && other.primaryCandidates.containsAll(primaryCandidates) && defaultCandidates.containsAll(other.defaultCandidates) && other.defaultCandidates.containsAll(defaultCandidates); } return false; } @Override public String toString() { StringBuilder b = new StringBuilder(); for (AbstractFunction l : primaryCandidates) { b.append(l.toString()); b.append(' '); } for (AbstractFunction l : defaultCandidates) { b.append(l.toString()); b.append(' '); } return b.toString(); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitExternal(this); } @Override public boolean isEqual(IValue other) { if (other instanceof OverloadedFunction) { return primaryCandidates.equals(((OverloadedFunction) other).primaryCandidates); } return false; } @Override public <V extends IValue> Result<IBool> equals(Result<V> that) { return that.equalToOverloadedFunction(this); } @Override public Result<IBool> equalToOverloadedFunction(OverloadedFunction that) { return ResultFactory.bool( primaryCandidates.equals(that.primaryCandidates) && defaultCandidates.equals(that.defaultCandidates), ctx); } @Override public <U extends IValue, V extends IValue> Result<U> add(Result<V> that) { return that.addFunctionNonDeterministic(this); } @Override public OverloadedFunction addFunctionNonDeterministic(AbstractFunction that) { return this.add(that); } @Override public OverloadedFunction addFunctionNonDeterministic(OverloadedFunction that) { return this.join(that); } @Override public ComposedFunctionResult addFunctionNonDeterministic(ComposedFunctionResult that) { return new ComposedFunctionResult.NonDeterministic(that, this, ctx); } @Override public <U extends IValue, V extends IValue> Result<U> compose(Result<V> right) { return right.composeFunction(this); } @Override public ComposedFunctionResult composeFunction(AbstractFunction that) { return new ComposedFunctionResult(that, this, ctx); } @Override public ComposedFunctionResult composeFunction(OverloadedFunction that) { return new ComposedFunctionResult(that, this, ctx); } @Override public ComposedFunctionResult composeFunction(ComposedFunctionResult that) { return new ComposedFunctionResult(that, this, ctx); } public List<AbstractFunction> getFunctions() { List<AbstractFunction> result = new LinkedList<AbstractFunction>(); for (AbstractFunction f : primaryCandidates) { result.add(f); } for (AbstractFunction f : defaultCandidates) { result.add(f); } return result; } public List<AbstractFunction> getTests() { List<AbstractFunction> result = new LinkedList<AbstractFunction>(); for (AbstractFunction f : getFunctions()) { if (f.isTest()) { result.add(f); } } return result; } public String getName() { return name; } @Override public Evaluator getEval() { return (Evaluator) ctx; } @Override public boolean isAnnotatable() { return false; } @Override public IAnnotatable<? extends IValue> asAnnotatable() { throw new IllegalOperationException("Cannot be viewed as annotatable.", getType()); } @Override public boolean mayHaveKeywordParameters() { return false; } @Override public IWithKeywordParameters<? extends IValue> asWithKeywordParameters() { throw new IllegalOperationException("Cannot be viewed as with keyword parameters", getType()); } }
public class RelationalFunctionsOnList { protected static final TypeFactory typeFactory = TypeFactory.getInstance(); protected static final Type voidType = typeFactory.voidType(); public static int arity(IList rel) { return rel.getElementType().getArity(); } public static IList carrier(IList rel1) { Type newType = rel1.getType().carrier(); IListWriter w = List.createListWriter(newType.getElementType()); HashSet<IValue> cache = new HashSet<>(); for (IValue v : rel1) { ITuple t = (ITuple) v; for (IValue e : t) { if (!cache.contains(e)) { cache.add(e); w.append(e); } } } return w.done(); } public static IList domain(IList rel1) { Type lrelType = rel1.getType(); IListWriter w = List.createListWriter(lrelType.getFieldType(0)); HashSet<IValue> cache = new HashSet<>(); for (IValue elem : rel1) { ITuple tuple = (ITuple) elem; IValue e = tuple.get(0); if (!cache.contains(e)) { cache.add(e); w.append(e); } } return w.done(); } public static IList range(IList rel1) { Type lrelType = rel1.getType(); int last = lrelType.getArity() - 1; IListWriter w = List.createListWriter(lrelType.getFieldType(last)); HashSet<IValue> cache = new HashSet<>(); for (IValue elem : rel1) { ITuple tuple = (ITuple) elem; IValue e = tuple.get(last); if (!cache.contains(e)) { cache.add(e); w.append(e); } } return w.done(); } public static IList compose(IList rel1, IList rel2) { Type otherTupleType = rel2.getType().getFieldTypes(); if (rel1.getElementType() == voidType) return rel1; if (otherTupleType == voidType) return rel2; if (rel1.getElementType().getArity() != 2 || otherTupleType.getArity() != 2) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType); // Relaxed type constraint: if (!rel1.getElementType().getFieldType(1).comparable(otherTupleType.getFieldType(0))) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType); Type[] newTupleFieldTypes = new Type[] {rel1.getElementType().getFieldType(0), otherTupleType.getFieldType(1)}; Type tupleType = typeFactory.tupleType(newTupleFieldTypes); IListWriter w = new ListWriter(tupleType); for (IValue v1 : rel1) { ITuple tuple1 = (ITuple) v1; for (IValue t2 : rel2) { ITuple tuple2 = (ITuple) t2; if (tuple1.get(1).isEqual(tuple2.get(0))) { w.append(Tuple.newTuple(tuple1.get(0), tuple2.get(1))); } } } return w.done(); } public static IList closure(IList rel1) { Type resultType = rel1.getType().closure(); // will throw exception if not binary and reflexive IList tmp = rel1; int prevCount = 0; ShareableValuesHashSet addedTuples = new ShareableValuesHashSet(); while (prevCount != tmp.length()) { prevCount = tmp.length(); IList tcomp = compose(tmp, tmp); IListWriter w = List.createListWriter(resultType.getElementType()); for (IValue t1 : tcomp) { if (!tmp.contains(t1)) { if (!addedTuples.contains(t1)) { addedTuples.add(t1); w.append(t1); } } } tmp = tmp.concat(w.done()); addedTuples.clear(); } return tmp; } public static IList closureStar(IList rel1) { Type resultType = rel1.getType().closure(); // an exception will have been thrown if the type is not acceptable IListWriter reflex = List.createListWriter(resultType.getElementType()); for (IValue e : carrier(rel1)) { reflex.insert(Tuple.newTuple(new IValue[] {e, e})); } return closure(rel1).concat(reflex.done()); } public static IList project(IList rel1, int... fields) { IListWriter w = ValueFactory.getInstance().listWriter(); for (IValue v : rel1) { w.append(((ITuple) v).select(fields)); } return w.done(); } public static IList projectByFieldNames(IList rel1, String... fields) { int[] indexes = new int[fields.length]; int i = 0; if (rel1.getType().getFieldTypes().hasFieldNames()) { for (String field : fields) { indexes[i++] = rel1.getType().getFieldTypes().getFieldIndex(field); } return project(rel1, indexes); } throw new IllegalOperationException("select with field names", rel1.getType()); } }