package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.AbstractMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.rascalmpl.interpreter.types.RascalType; import org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.traverse.DescendantDescriptor; import org.rascalmpl.library.experiments.Compiler.RVM.Interpreter.traverse.DescendantMatchIterator; import org.rascalmpl.value.IBool; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IInteger; import org.rascalmpl.value.IList; import org.rascalmpl.value.IListWriter; import org.rascalmpl.value.IMap; import org.rascalmpl.value.INode; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISetWriter; import org.rascalmpl.value.IString; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.exceptions.FactTypeUseException; import org.rascalmpl.value.impl.AnnotatedConstructorFacade; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.values.ValueFactoryFactory; import org.rascalmpl.values.uptr.ITree; import org.rascalmpl.values.uptr.RascalValueFactory.AnnotatedAmbFacade; import org.rascalmpl.values.uptr.TreeAdapter; /** * MuPrimitive defines all primitives that are necessary for running muRascal programs. * This includes all operations with at least one operand that is not an IValue: * - mint (Java Integer) * - mstr (Java String) * - mset (Java HashSet<IValue>) * - mmap (Java HashMap of various types, e.g., HashMap<String, IValue> and HashMap<String, Entry<String, IValue>>) * - array (Java Object[]) * * All operations with only IValues as arguments are defined in RascalPrimitive * * Each MuPrimitive has an execute function with as arguments * - stack in the current stack frame * - stackpointer (sp) in that stack * - arity of the primitive * * and returns a new values for the stackpointer. * * TODO: Earlier we use Java booleans to represent booleans but we have switched to using IBool instead. * Some primitives using booleans now work on IValues only and should be moved to RascalPrimitives. */ /** * @author paulklint * */ public enum MuPrimitive { /** * mint3 = mint1 + mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ addition_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return (int) arg_2 + ((int) arg_1); }; }, /** * Assign to array element * [ ..., array, mint, Object ] => [ ..., Object ] * */ assign_subscript_array_mint { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; Object[] ar = (Object[]) stack[sp - 3]; int index = ((int) stack[sp - 2]); ar[index] = stack[sp - 1]; stack[sp - 3] = stack[sp - 1]; return sp - 2; }; }, /** * Check the type of an argument * [ ..., IValue arg, Type type ] => [ ..., bool ] * */ check_arg_type { @Override public Object execute2(final Object arg_2, final Object arg_1) { Type argType = ((IValue) arg_2).getType(); Type paramType = ((Type) arg_1); return vf.bool(argType.isSubtypeOf(paramType)); }; }, /** * mint3 = mint1 / mint2 * * [ ... mint1, mint2 ] => [ ..., mint3 ] * */ division_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((int) arg_2) / ((int) arg_1); }; }, /** * bool = (mint1 == mint2) * [ ..., mint1, mint2 ] => [ ..., bool ] * */ equal_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) == ((int) arg_1)); }; }, /** * Equality on IValues or Types: bool = (IValueOrType1 == IValueOrType2) * * [ ..., IValueOrType1, IValueOrType2 ] => [ ..., bool ] * */ equal { @Override public Object execute2(final Object arg_2, final Object arg_1) { if (arg_2 instanceof IValue && (arg_1 instanceof IValue)) { return vf.bool(((IValue) arg_2).isEqual(((IValue) arg_1))); } else if (arg_2 instanceof Type && (arg_1 instanceof Type)) { return vf.bool(((Type) arg_2) == ((Type) arg_1)); } else { throw new CompilerError("MuPrimitive equal -- not defined on " + arg_2.getClass() + " and " + arg_1.getClass()); } }; }, /** * Equality on ISet and mset: bool = (ISet == mset) * * [ ..., ISet, mset ] => [ ..., bool ] * */ equal_set_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { ISet set = (ISet) arg_2; HashSet<IValue> mset = (HashSet<IValue>) arg_1; if (set.size() != mset.size()) { return RascalPrimitive.Rascal_FALSE; } for (IValue v : set) { if (!mset.contains(v)) { return RascalPrimitive.Rascal_FALSE; } } return RascalPrimitive.Rascal_TRUE; }; }, /** * Get the positional arguments of node or constructor (any keyword parameters are ignored): * [ ..., iNode ] => [ ..., array ] */ get_children { @Override public Object execute1(final Object arg_1) { INode nd = (INode) arg_1; Object[] elems = new Object[nd.arity()]; for (int i = 0; i < nd.arity(); i++) { elems[i] = nd.get(i); } return elems; }; }, /** * Given a ParseTree of the form appl(Symbol, list[Tree]) get * its children without layout as well as its keyword map. * Also handles concrete lists with separators * [ ... IConstructor tree ] => [ ..., array ] * */ get_children_without_layout_or_separators_with_keyword_map { @Override public Object execute1(final Object arg_1) { IConstructor cons = (IConstructor) arg_1; // TODO use TreeAdapter.getNonLayoutArgs(cons); IConstructor prod = (IConstructor) cons.get(0); IList args = (IList) cons.get(1); IConstructor symbol = (IConstructor) prod.get(0); int step = RascalPrimitive.$getIterDelta(symbol); if(step < 0) step = 2; int non_lit_len = 0; for(int i = 0; i < args.length(); i += step){ if(!$is_literal(args.get(i))){ non_lit_len++; } } Object[] elems = new Object[non_lit_len + 1]; int j = 0; for(int i = 0; i < args.length(); i += step){ if(!$is_literal(args.get(i))){ elems[j++] = args.get(i); } } elems[non_lit_len] = RVMCore.emptyKeywordMap; return elems; } }, /** * Given a ParseTree of the form appl(Symbol, list[Tree]) get * its children without layout and without its keyword map. * Also handles concrete lists with separators * [ ... IConstructor tree ] => [ ..., array ] * */ get_children_without_layout_or_separators_without_keyword_map { @Override public Object execute1(final Object arg_1) { IConstructor cons = (IConstructor) arg_1; // TODO use TreeAdapter.getNonLayoutArgs(cons); IConstructor prod = (IConstructor) cons.get(0); IList args = (IList) cons.get(1); IConstructor symbol = (IConstructor) prod.get(0); int step = RascalPrimitive.$getIterDelta(symbol); if(step < 0) step = 2; int non_lit_len = 0; for(int i = 0; i < args.length(); i += step){ if(!$is_literal(args.get(i))){ non_lit_len++; } } Object[] elems = new Object[non_lit_len]; int j = 0; for(int i = 0; i < args.length(); i += step){ if(!$is_literal(args.get(i))){ elems[j++] = args.get(i); } } return elems; } }, /** * Get value associated with a key in mmap * * [ ..., mmap, String key ] => Object * */ get_mmap { @SuppressWarnings("unchecked") @Override public Object execute2(final Object arg_2, final Object arg_1) { Map<String,IValue> m = (Map<String,IValue>) arg_2; String key = (String) arg_1; return m.get(key); }; }, /** * Get the name of a node * * [ ..., node nd ] => [ ..., nodeName] */ get_name { @Override public Object execute1(final Object arg_1) { INode nd = (INode) arg_1; return vf.string(nd.getName()); }; }, /** * Given a constructor or node get an array consisting of * - node/constructor name * - positional arguments * * [ ..., node ] => [ ..., array ] */ get_name_and_children { @Override public Object execute1(final Object arg_1) { INode v = (INode) arg_1; int cons_arity = v.arity(); Object[] elems = new Object[cons_arity + 1]; elems[0] = vf.string(v.getName()); for (int i = 0; i < cons_arity; i++) { elems[i + 1] = v.get(i); } return elems; }; }, /** * Given a mmap, return its keys as array * * [ ..., mmap ] => [ ..., array ] */ get_keys_mmap { @Override public Object execute1(final Object arg_1) { @SuppressWarnings("unchecked") Map<String,IValue> mmap = (Map<String,IValue>) arg_1; int len = mmap.size(); String[] keys = new String[len]; int i = 0; for(String key : mmap.keySet()){ keys[i++] = key; } return keys; }; }, /** * Given * - an array of keywords (as string) * - an array of IValues * construct an mmap representing <keyword[i],value[i]> pairs * * [ ..., array of keys, array of IValues] => [ ..., mmap ] * */ make_keyword_mmap { @Override public Object execute2(final Object arg_2, final Object arg_1) { String[] keywords = (String[]) arg_2; Object[] values = (Object[]) arg_1; assert keywords.length == values.length; Map<String,IValue> mmap = new HashMap<String,IValue>(keywords.length); for(int i = 0; i< keywords.length; i++){ mmap.put(keywords[i], (IValue) values[i]); } return mmap; }; }, /** * Given a tuple, get an array consisting of its elements * * [ ..., ITuple ] => [ ..., array ] */ get_tuple_elements { @Override public Object execute1(final Object arg_1) { ITuple tup = (ITuple) arg_1; int nelem = tup.arity(); Object[] elems = new Object[nelem]; for (int i = 0; i < nelem; i++) { elems[i] = tup.get(i); } return elems; }; }, /** * bool = (mint1 >= mint2) * * [ ..., mint1, mint2 ] => [ ..., bool ] * */ greater_equal_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) >= ((int) arg_1)); }; }, /** * bool = mint1 > mint2 * * [ ..., mint1, mint2 ] => [ ..., bool ] * */ greater_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) > ((int) arg_1)); }; }, /** * Has a concrete term a given label? * * [ ..., IValue, IString label ] => [ ..., bool ] */ // TODO rename to more parse tree specific? has_label { @Override public Object execute2(final Object arg_2, final Object arg_1) { IValue v = (IValue) arg_2; Type vt = v.getType(); String label_name = ((IString) arg_1).getValue(); if (isNonTerminalType(vt)) { ITree cons = (ITree) v; if (TreeAdapter.isAppl(cons)) { String treeLabel = TreeAdapter.getConstructorName(cons); return (treeLabel != null && label_name.equals(treeLabel)) ? RascalPrimitive.Rascal_TRUE : RascalPrimitive.Rascal_FALSE; } } return RascalPrimitive.Rascal_FALSE; } }, /** * bool3 = (bool1 ==> bool2) * * [ ..., bool1, bool2 ] => [ ..., bool3 ] * */ // TODO: move to RascalPrimitive? implies_mbool_mbool { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((IBool) arg_2).implies((IBool) arg_1); }; }, /** * Check that a Reference refers to a non-null variable * * [ ..., Reference ] => [ ..., bool ] * */ is_defined { @Override public Object execute1(final Object arg_1) { return vf.bool(((Reference) arg_1).isDefined()); }; }, /** * Check that IValue is element of mset * * [ ..., IValue, mset ] => [ ..., bool ] * */ is_element_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((HashSet<IValue>) arg_1).contains((IValue) arg_2)); }; }, /** * Is IValue an IBool? * * [ ..., IValue ] => [ ..., bool ] * * Note: all is_* primitives are introduced by Implode and are only used in Library.mu * */ is_bool { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isBool()); }; }, /** * Is IValue a constructor? * * [ ..., IValue ] => [ ..., bool ] * */ is_constructor { @Override public Object execute1(final Object arg_1) { Type t = ((IValue) arg_1).getType(); // TODO: review if is_constructor still needs true on parse trees return vf.bool(t.isAbstractData() || isNonTerminalType(t)); } }, /** * Is IValue a IDateTime? * * [ ..., IValue ] => [ ..., bool ] * */ is_datetime { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isDateTime()); }; }, /** * Is IValue an IInteger? * * [ ..., IValue ] => [ ..., bool ] * */ is_int { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isInteger()); }; }, /** * Is IValue an IList? * * [ ..., IValue ] => [ ..., bool ] * */ is_list { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isList()); }; }, /** * Is IValue an IListRelation? * * [ ..., IValue ] => [ ..., bool ] * */ is_lrel { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isListRelation()); }; }, /** * Is IValue an ISourceLocation? * * [ ..., IValue ] => [ ..., bool ] * */ is_loc { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isSourceLocation()); }; }, /** * Is IValue an IMap? * * [ ..., IValue ] => [ ..., bool ] * */ is_map { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isMap()); }; }, /** * Is Object an mmap? * * [ ..., Object ] => [ ..., bool ] * */ is_mmap { @Override public Object execute1(final Object arg_1) { return vf.bool(arg_1 instanceof Map); }; }, /** * Is IValue an INode? * * [ ..., IValue ] => [ ..., bool ] * */ is_node { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isNode()); }; }, /** * Is IValue an INumber? * * [ ..., IValue ] => [ ..., bool ] * */ is_num { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isNumber()); }; }, /** * Is IValue an IReal? * * [ ..., IValue ] => [ ..., bool ] * */ is_real { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isReal()); }; }, /** * Is IValue an IRational? * * [ ..., IValue ] => [ ..., bool ] * */ is_rat { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isRational()); }; }, /** * Is IValue an IRelation? * * [ ..., IValue ] => [ ..., bool ] * */ is_rel { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isRelation()); }; }, /** * Is IValue an ISet? * * [ ..., IValue ] => [ ..., bool ] * */ is_set { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isSet()); }; }, /** * Is IValue an IString? * * [ ..., IValue ] => [ ..., bool ] * */ is_str { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isString()); }; }, /** * Is IValue an ITuple? * * [ ..., IValue ] => [ ..., bool ] * */ is_tuple { @Override public Object execute1(final Object arg_1) { return vf.bool(((IValue) arg_1).getType().isTuple()); }; }, /** * Given an IMap return an array containing its keys * * [ ..., IMap ] => [ ..., array ] * */ keys_map { @Override public Object execute1(final Object arg_1) { IMap map = ((IMap) arg_1); IListWriter writer = vf.listWriter(); for (IValue key : map) { writer.append(key); } return writer.done(); }; }, /** * Given an IMap return an array containing its values * * [ ..., IMap ] => [ ..., array ] * */ values_map { @Override public Object execute1(final Object arg_1) { IMap map = ((IMap) arg_1); IListWriter writer = vf.listWriter(); for (IValue key : map) { writer.append(map.get(key)); } return writer.done(); }; }, /** * bool= mint1 <= mint2 * * [ ..., mint1, mint2 ] => [ ..., bool ] * */ less_equal_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) <= ((int) arg_1)); }; }, /** * bool = mint1 < mint2 * * [ ..., mint1, mint2 ] => [ ..., bool ] * */ less_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) < ((int) arg_1)); }; }, make_iarray { // TODO replace by make_array? @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity >= 0; IValue[] ar = new IValue[arity]; for (int i = arity - 1; i >= 0; i--) { ar[i] = (IValue) stack[sp - arity + i]; } int sp1 = sp - arity + 1; stack[sp1 - 1] = ar; return sp1; }; }, make_iarray_of_size { @Override public Object execute1(final Object arg_1) { int len = ((int) arg_1); return new IValue[len]; }; }, /** * Make an array containing Object_1, Object_2, ..., Object_n: * * [ ..., Object_1, Object_2, ..., Object_n ] => [ ..., array ] * */ make_array { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity >= 0; Object[] ar = new Object[arity]; for (int i = arity - 1; i >= 0; i--) { ar[i] = stack[sp - arity + i]; } int sp1 = sp - arity + 1; stack[sp1 - 1] = ar; return sp1; }; }, /** * Make an array of given size * * [ ..., mint ] => [ ..., array ] * */ make_array_of_size { @Override public Object execute1(final Object arg_1) { int len = ((int) arg_1); return new Object[len]; }; }, /** * Make a new mset * * [ ... ] => [ ..., mset ] * */ make_mset { @Override public Object execute0() { HashSet<IValue> mset = new HashSet<IValue>(); return mset; }; }, /** * Create a new mmap from keyword name (String) to an MapEntry <Type, IValue> * * [ ... ] => [ ..., mmap ] */ make_mmap_str_entry { @Override public Object execute0() { return new HashMap<String, Map.Entry<Type, IValue>>(); }; }, /** * Create a MapEntry <type, default_value> * * [ ..., Type, IValue ] => [ ..., MapEntry ] * */ make_mentry_type_ivalue { @Override public Object execute2(final Object arg_2, final Object arg_1) { return new AbstractMap.SimpleEntry<Type, IValue>((Type) arg_2, (IValue) arg_1); }; }, /** * Given IString_1, IValue_1, ..., IString_n, IValue_n, create a keyword map with <String_i, IValue_i> as entries * * [ ..., IString_1, IValue_1, ..., IString_n, IValue_n ] => [ ..., mmap ] */ make_mmap { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity >= 0; if(arity == 0){ stack[sp] = new HashMap<String, IValue>(0); return sp + 1; } Map<String, IValue> writer = new HashMap<String, IValue>((arity+1)/2); for (int i = arity; i > 0; i -= 2) { writer.put(((IString) stack[sp - i]).getValue(), (IValue) stack[sp - i + 1]); } int sp1 = sp - arity + 1; stack[sp1 - 1] = writer; return sp1; } }, /** * Given defPos, IString_1, IValue_1, ..., IString_n, IValue_n, * copy the default map at stack[defPos] and insert the entries <String_i, IValue_i> in it * * [ ..., defPos, IString_1, IValue_1, ..., IString_n, IValue_n ] => [ ..., mmap ] * * Note: this implements downward keyword parameter propagation that is not (yet) supported by the interpreter */ copy_and_update_keyword_mmap { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity >= 1; int defPos = ((IInteger) stack[sp - arity]).intValue(); @SuppressWarnings("unchecked") HashMap<String, IValue> oldMap = (HashMap<String, IValue>) stack[defPos]; if(arity == 1){ stack[sp - 1] = oldMap; return sp; } @SuppressWarnings("unchecked") HashMap<String, IValue> writer = (HashMap<String, IValue>) oldMap.clone(); for (int i = arity - 1; i > 0; i -= 2) { writer.put(((IString) stack[sp - i]).getValue(), (IValue) stack[sp - i + 1]); } int sp1 = sp - arity + 1; stack[sp1 - 1] = writer; return sp1; } }, /** * Does a keyword map with <String, IValue> entries contain a given key (as String)? * * [ ..., mmap, String] => [ ..., bool ] * */ mmap_contains_key { @SuppressWarnings("unchecked") @Override public Object execute2(final Object arg_2, final Object arg_1) { Map<String,IValue> m = (Map<String,IValue>) arg_2; String key = ((String) arg_1); return vf.bool(m.containsKey(key)); }; }, make_iterator { @SuppressWarnings("unchecked") @Override public Object execute1(final Object arg_1) { Object iteratee = arg_1; if(iteratee instanceof Object[]){ return new ArrayIterator<Object>((Object[]) iteratee); } else if(iteratee instanceof AnnotatedAmbFacade){ return ((AnnotatedAmbFacade) iteratee).getAlternatives().iterator(); } else if(iteratee instanceof AnnotatedConstructorFacade){ return ((AnnotatedConstructorFacade) iteratee).getChildren().iterator(); } else { return ((Iterable<IValue>) iteratee).iterator(); } }; }, make_descendant_iterator{ @Override public Object execute2(final Object arg_2, final Object arg_1) { IValue iteratee = (IValue) arg_2; DescendantDescriptor descriptor = (DescendantDescriptor) arg_1; return new DescendantMatchIterator(iteratee, descriptor); }; }, iterator_hasNext { @SuppressWarnings("unchecked") @Override public Object execute1(final Object arg_1) { return vf.bool(((Iterator<IValue>) arg_1).hasNext()); }; }, iterator_next { @SuppressWarnings("unchecked") @Override public Object execute1(final Object arg_1) { return ((Iterator<IValue>) arg_1).next(); }; }, /** * mint3 = min(mint1, mint2) * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ min_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { int x = ((int) arg_2); int y = ((int) arg_1); return x < y ? x : y; }; }, /** * mint3 = max(mint1, mint2) * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ max_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { int x = ((int) arg_2); int y = ((int) arg_1); return x > y ? x : y; }; }, /** * Convert an IValue to a mint * * [ ..., IValue ] => [ ..., mint ] * */ mint { @Override public Object execute1(final Object arg_1) { if(arg_1 instanceof IInteger){ return ((IInteger) arg_1).intValue(); } return arg_1; }; }, /** * Convert an IString to mstr * * [ ..., IString ] => [ ..., mstr ] * */ mstr { @Override public Object execute1(final Object arg_1) { if(arg_1 instanceof IString){ return ((IString) arg_1).getValue(); } return arg_1; }; }, /** * mint3 = mint1 % mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ modulo_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((int) arg_2) % ((int) arg_1); }; }, /** * Convert an ISet to mset * * [ ..., ISet ] => [ ..., mset ] * */ mset { @Override public Object execute1(final Object arg_1) { ISet set = ((ISet) arg_1); int n = set.size(); HashSet<IValue> mset = n > 0 ? new HashSet<IValue>(n) : emptyMset; for (IValue v : set) { mset.add(v); } return mset; }; }, /** * mset = ISet1 - ISet2 * * [ [ ..., ISet1, ISet2 ] => [ ..., mset ] */ mset_set_subtract_set { @Override public Object execute2(final Object arg_2, final Object arg_1) { ISet set1 = ((ISet) arg_2); int n = set1.size(); ISet set2 = ((ISet) arg_1); HashSet<IValue> mset = n > 0 ? new HashSet<IValue>(n) : emptyMset; for (IValue v : set1) { if(!set2.contains(v)){ mset.add(v); } } return mset; }; }, /** * Make an empty mset * * [ ... ] => [ ..., mset ] * */ mset_empty() { @Override public Object execute0() { return emptyMset; }; }, /** * Convert an mset to an IList * * [ ..., mset ] => [ ..., IList ] * */ mset2list { @Override @SuppressWarnings("unchecked") public Object execute1(final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_1; IListWriter writer = vf.listWriter(); for (IValue elem : mset) { writer.append(elem); } return writer.done(); }; }, /** * Destructively add element to an mset * * [ ..., mset, elm ] => [ ..., mset ] * */ mset_destructive_add_elm { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_2; if(mset == emptyMset){ mset = (HashSet<IValue>) emptyMset.clone(); } IValue elm = ((IValue) arg_1); mset.add(elm); return mset; }; }, /** * Destructively add mset2 to mset1 * * [ ..., mset1, mset2 ] => [ ..., mset1 ] * */ mset_destructive_add_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> lhs = (HashSet<IValue>) arg_2; if(lhs == emptyMset){ lhs = (HashSet<IValue>) emptyMset.clone(); } // lhs = (HashSet<IValue>) lhs.clone(); HashSet<IValue> rhs = (HashSet<IValue>) arg_1; lhs.addAll(rhs); return lhs; }; }, /** * Add a <Tye, IValue> entry to an mmap * * [ ..., mmap, IString, MapEntry<Type,IValue> ] => [ ..., mmap ] */ mmap_str_entry_add_entry_type_ivalue { @Override @SuppressWarnings("unchecked") public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; /*stack[sp - 3] = */((Map<String, Map.Entry<Type, IValue>>) stack[sp - 3]) .put(((IString) stack[sp - 2]).getValue(), (Map.Entry<Type, IValue>) stack[sp - 1]); return sp - 2; }; }, /** * mint3 = mint1 * mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ multiplication_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((int) arg_2) * ((int) arg_1); }; }, /** * Destructively subtract mset from mset * * [ ..., mset1, mset2 ] => [ ..., mset1 ] * */ mset_destructive_subtract_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> lhs = (HashSet<IValue>) arg_2; // lhs = (HashSet<IValue>) lhs.clone(); HashSet<IValue> rhs = (HashSet<IValue>) arg_1; lhs.removeAll(rhs); return lhs; }; }, /** * Subtract mset from copied mset * * [ ..., mset1, mset2 ] => [ ..., mset3 ] * */ mset_subtract_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> lhs = (HashSet<IValue>) arg_2; lhs = (HashSet<IValue>) lhs.clone(); HashSet<IValue> rhs = (HashSet<IValue>) arg_1; lhs.removeAll(rhs); return lhs; }; }, /** * Destructively subtract ISet from an mset * * [ ..., mset, ISet ] => [ ..., mset ] * */ mset_destructive_subtract_set { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_2; mset = (HashSet<IValue>) mset.clone(); ISet set = ((ISet) arg_1); for (IValue v : set) { mset.remove(v); } return mset; }; }, /** * Subtract ISet from copied mset * * [ ..., mset1, ISet ] => [ ..., mset2 ] * */ mset_subtract_set { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_2; mset = (HashSet<IValue>) mset.clone(); ISet set = ((ISet) arg_1); for (IValue v : set) { mset.remove(v); } return mset; }; }, /** * Destructively subtract element from an mset * * [ ..., mset, IValue ] => [ ..., mset ] * */ mset_destructive_subtract_elm { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_2; IValue elm = ((IValue) arg_1); mset.remove(elm); return mset; }; }, /** * Subtract element from copied mset * * [ ..., mset1, IValue ] => [ ..., mset2 ] * */ mset_subtract_elm { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_2; mset = (HashSet<IValue>) mset.clone(); IValue elm = ((IValue) arg_1); mset.remove(elm); return mset; }; }, /** * bool = (mint1 != mint2) * * [ ..., mint1, mint2 ] => [ ..., bool ] * */ not_equal_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((int) arg_2) != ((int) arg_1)); }; }, /** * bool2 = !bool1 * * [ ..., bool1 ] => [ ..., bool2 ] * */ // TODO: move to RascalPrimitive? not_mbool { @Override public Object execute1(final Object arg_1) { return ((IBool) arg_1).not(); }; }, /** * bool = IList2 is a sublist of IList1 at start * * [ ..., IList1, IList2, start ] => [ ..., bool ] */ occurs_list_list_mint { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; IList sublist = ((IList) stack[sp - 3]); int nsub = sublist.length(); IList list = ((IList) stack[sp - 2]); int start = (int) stack[sp - 1]; int nlist = list.length(); stack[sp - 3] = RascalPrimitive.Rascal_FALSE; int newsp = sp - 2; if (start + nsub <= nlist) { for (int i = 0; i < nsub; i++) { if (!sublist.get(i).isEqual(list.get(start + i))) return newsp; } } else { return newsp; } stack[sp - 3] = RascalPrimitive.Rascal_TRUE; return newsp; }; }, one_dot_zero { @Override public Object execute1(final Object arg_1) { // Actually zero args, but muRascal does not permit that return vf.real("1.0"); }; }, /** * bool3 = (bool1 || bool2) * * [ ..., bool1, bool2 ] => [ ..., bool3 ] * */ // TODO: move to RascalPrimitive? or_mbool_mbool { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((IBool) arg_2).or((IBool) arg_1); }; }, /** * mint3 = mint1 ^ mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ power_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { int n1 = ((int) arg_2); int n2 = ((int) arg_1); int pow = 1; for (int i = 0; i < n2; i++) { pow *= n1; } return pow; }; }, /** * Convert mint to Rascal int (IInteger) * * [ ..., mint ] => [ ..., IInteger ] */ rint { @Override public Object execute1(final Object arg_1) { return vf.integer((int) arg_1); }; }, /** * Compile a RegExp Matcher given: * - IString, the regexp * - IValue, the subject string, either an IString or an arbitrary IValue (always a ParseTree). * * [ ..., IString regexp, IValue subject ] => [ ..., Matcher ] */ regexp_compile { @Override public Object execute2(final Object arg_2, final Object arg_1) { String RegExpAsString = ((IString) arg_2).getValue(); IValue isubject = (IValue) arg_1; String subject; if(isubject instanceof IString){ subject = ((IString) isubject).getValue(); } else { StringWriter w = new StringWriter(); IConstructor c = (IConstructor) isubject; try { TreeAdapter.unparse(c, w); } catch (FactTypeUseException | IOException e) { throw new RuntimeException(e); } subject = w.toString(); } //System.err.println("regexp_compile: \"" + RegExpAsString + "\" and \"" + subject + "\" len = " + subject.length()); try { Pattern pat = Pattern.compile(RegExpAsString, Pattern.UNICODE_CHARACTER_CLASS); return pat.matcher(subject); } catch (PatternSyntaxException e) { throw RascalRuntimeException.RegExpSyntaxError(RegExpAsString, null); } }; }, /** * Begin position of RegExp Match * * [ ..., Matcher ] => [ ..., begin position ] */ regexp_begin { @Override public Object execute1(final Object arg_1) { Matcher matcher = (Matcher) arg_1; return matcher.start(); //vf.integer(matcher.start()); }; }, /** * End position of RegExp Match * * [ ..., Matcher ] => [ ..., end position ] */ regexp_end { @Override public Object execute1(final Object arg_1) { Matcher matcher = (Matcher) arg_1; return matcher.end(); //vf.integer(matcher.end()); }; }, /** * Find next RegExp match * * [ ..., Matcher ] => [ ..., bool ] */ regexp_find { @Override public Object execute1(final Object arg_1) { Matcher matcher = (Matcher) arg_1; return vf.bool(matcher.find()); }; }, /** * Set the region for a RegExp Matcher * * [ ..., Matcher, mint1, mint2 ] => [ ..., Matcher ] * */ regexp_set_region { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; Matcher matcher = (Matcher) stack[sp - 3]; int start = ((int) stack[sp - 2]); int end = ((int) stack[sp - 1]); stack[sp - 3] = matcher.region(start, end); return sp - 2; }; }, /** * Get the match result for a specifc group mint in RegExp match * * [ ..., Matcher, mint ] => [ ..., IString ] */ regexp_group { @Override public Object execute2(final Object arg_2, final Object arg_1) { Matcher matcher = (Matcher) arg_2; int idx = (int) arg_1; return vf.string(matcher.group(idx)); }; }, /** * Convert mset to Rascal set (ISet) * * [ ..., mset ] => [ ..., ISet ] */ set { @Override @SuppressWarnings("unchecked") public Object execute1(final Object arg_1) { HashSet<IValue> mset = (HashSet<IValue>) arg_1; ISetWriter w = vf.setWriter(); for (IValue v : mset) { w.insert(v); } return w.done(); }; }, /** * Convert an ISet to an IList * * [ ..., ISet ] => [ ..., IList ] */ set2list { @Override public Object execute1(final Object arg_1) { ISet set = (ISet) arg_1; IListWriter writer = vf.listWriter(); for (IValue elem : set) { writer.append(elem); } return writer.done(); }; }, /** * bool = (ISet < mset) * * [ ..., ISet, mset ] => [ ..., bool ] */ set_is_subset_of_mset { @Override @SuppressWarnings("unchecked") public Object execute2(final Object arg_2, final Object arg_1) { ISet subset = ((ISet) arg_2); HashSet<IValue> mset = (HashSet<IValue>) arg_1; for (IValue v : subset) { if (!mset.contains(v)) { return RascalPrimitive.Rascal_FALSE; } } return RascalPrimitive.Rascal_TRUE; }; }, /** * Size of array * * [ ..., array ] => [ ..., mint ] */ size_array { @Override public Object execute1(final Object arg_1) { return ((Object[]) arg_1).length; }; }, /** * Size of IList * * [ ..., IList ] => [ ..., mint ] */ size_list { @Override public Object execute1(final Object arg_1) { return ((IList) arg_1).length(); }; }, /** * Size of ISet * * [ ..., ISet ] => [ ..., mint ] */ size_set { @Override public Object execute1(final Object arg_1) { return ((ISet) arg_1).size(); }; }, /** * Size of mset * * [ ..., mset ] => [ ..., mint ] */ size_mset { @Override public Object execute1(final Object arg_1) { return ((HashSet<?>) arg_1).size(); }; }, /** * Size of IMap * * [ ..., IMap ] => [ ..., mint ] */ size_map { @Override public Object execute1(final Object arg_1) { return ((IMap) arg_1).size(); }; }, /** * Size of IString * * [ ..., IString ] => [ ..., mint ] */ size_str { @Override public Object execute1(final Object arg_1) { return ((IString) arg_1).length(); }; }, /** * Size of ITuple * * [ ..., ITuple ] => [ ..., mint ] */ size_tuple { @Override public Object execute1(final Object arg_1) { return ((ITuple) arg_1).arity(); }; }, /** * Generic size function * * [ ..., IValue ] => [ ..., mint ] */ size { @Override public Object execute1(final Object arg_1) { if (arg_1 instanceof IString) { return ((IString) arg_1).length(); } else if (arg_1 instanceof IConstructor) { return ((IConstructor) arg_1).arity(); } else if (arg_1 instanceof INode) { return ((INode) arg_1).arity(); } else if (arg_1 instanceof IList) { return ((IList) arg_1).length(); } else if (arg_1 instanceof ISet) { return ((ISet) arg_1).size(); } else if (arg_1 instanceof IMap) { return ((IMap) arg_1).size(); } else if (arg_1 instanceof ITuple) { return ((ITuple) arg_1).arity(); } return 0; // TODO? }; }, /** * IList2 occurs as subslist in IList1 at position start * * [ ..., IList1, IList2, start] => [ ..., bool ] * */ starts_with { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; IList sublist = (IList) stack[sp - 3]; IList list = (IList) stack[sp - 2]; int start = (int) stack[sp - 1]; IBool eq = RascalPrimitive.Rascal_TRUE; if (start + sublist.length() <= list.length()) { for (int i = 0; i < sublist.length() && eq.getValue(); i++) { if (!sublist.get(i).equals(list.get(start + i))) { eq = RascalPrimitive.Rascal_FALSE; } } } stack[sp - 3] = eq; return sp - 2; }; }, /** * IList2 = sublist of IList given offset and length * * [ ..., IList1, offset, length ] => [ ..., IList2 ] */ sublist_list_mint_mint { @Override public int executeN(final Object[] stack, int sp, final int arity) { assert arity == 3; int length = ((int) stack[--sp]); int offset = ((int) stack[--sp]); IList lst = (IList) stack[--sp]; stack[sp++] = lst.sublist(offset, length); return sp; }; }, /** * Object = array[mint] * * [ ..., array, mint ] => [ ..., Object ] * */ subscript_array_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((Object[]) arg_2)[((int) arg_1)]; }; }, /** * Object = array[int] * * [ ..., array, int ] => [ ..., Object ] * */ subscript_array_int { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((Object[]) arg_2)[((IInteger) arg_1).intValue()]; }; }, /** * IValue = IList[mint] * * [ ..., IList, mint ] => [ ..., IValue ] */ subscript_list_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((IList) arg_2).get((int) arg_1); }; }, /** * IValue = ITuple[mint] * * [ ..., ITuple, mint ] => [ ..., IValue ] */ subscript_tuple_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((ITuple) arg_2).get((int) arg_1); }; }, /** * Make a substring * * IString2 = IString2.substring(start,end) * * [ ..., IString1, start, end ] => [ ..., IString2 ] */ substring_str_mint_mint { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; IString subject = ((IString) stack[sp - 3]); int start = ((int) stack[sp - 2]); int end = ((int) stack[sp - 1]); //System.err.println("substring: " + subject + ", " + start + ", " + end); stack[sp - 3] = subject.substring(start, end); return sp - 2; }; }, /** * bool = IString2 is tail of IString1 at start * [ ..., IString1, IString2, start ] => [ ..., bool ] */ is_tail_str_str_mint { @Override public int executeN(final Object[] stack, final int sp, final int arity) { assert arity == 3; IString subject = ((IString) stack[sp - 3]); IString substr = ((IString) stack[sp - 2]); int start = ((int) stack[sp - 1]); if(start + substr.length() == subject.length()){ stack[sp - 3] = vf.bool(subject.substring(start, start + substr.length()).compare(substr) == 0); } else { stack[sp - 3] = RascalPrimitive.Rascal_FALSE; } return sp - 2; }; }, /** * mint3 = mint1 - mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] */ subtraction_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((int) arg_2) - ((int) arg_1); }; }, /** * bool = Type1 < Type2 * * [ ..., Type1, Type2 ] => [ ..., bool ] */ subtype { @Override public Object execute2(final Object arg_2, final Object arg_1) { return vf.bool(((Type) arg_2).isSubtypeOf((Type) arg_1)); }; }, /** * Get type of an IValue or mint * * [ ..., IValueOrMint ] => [ ..., bool ] */ typeOf { @Override public Object execute1(final Object arg_1) { if (arg_1 instanceof Integer) { return TypeFactory.getInstance().integerType(); } else { return ((IValue) arg_1).getType(); } }; }, /** * Get type of mset * * [ ..., mset ] => [ ..., Type ] */ typeOfMset { @SuppressWarnings("unchecked") @Override public Object execute1(final Object arg_1) { if (arg_1 instanceof HashSet) { HashSet<IValue> mset = (HashSet<IValue>) arg_1; Type elmType = TypeFactory.getInstance().voidType(); for (IValue elm : mset) { elmType = elm.getType().lub(elmType); } return TypeFactory.getInstance().setType(elmType); } throw new CompilerError("typeOfMset"); }; }, /** * Set value of Reference to undefined * * [ ..., Reference ] => [ ..., Reference ] * */ undefine { @Override public Object execute1(final Object arg_1) { Reference ref = (Reference) arg_1; Object val = ref.getValue(); ref.undefine(); return val; }; }, /** * mint3 = mint1 * mint2 * * [ ..., mint1, mint2 ] => [ ..., mint3 ] * */ product_mint_mint { @Override public Object execute2(final Object arg_2, final Object arg_1) { return ((int) arg_2) * ((int) arg_1); }; }, /** * Make a new subject: [iValue, mint] * * [ ..., iValue, mint ] => [ ..., [iValue, mint] ] * */ make_subject { @Override public Object execute2(final Object arg_2, final Object arg_1) { Object[] subject = new Object[2]; subject[0] = arg_2; subject[1] = arg_1; return subject; }; }, /** * Accept a list match when end of subject has been reached * * [ ..., [iList, mint] ] => [ ..., ilist.length() == mint ] * */ accept_list_match { @Override public Object execute1(final Object arg_1) { Object[] subject = (Object[]) arg_1; IList listSubject = (IList) subject[0]; int cursor = (int) subject[1]; int len = listSubject.length(); if(cursor == len){ return RascalPrimitive.Rascal_TRUE; } for(int i = cursor; i < len; i++){ // Check whether only nullables follow if(!$is_nullable(listSubject.get(i))){ // TODO maybe better to make a separate accept for the concrete case return RascalPrimitive.Rascal_FALSE; } } return RascalPrimitive.Rascal_TRUE; }; } ; private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); public static final MuPrimitive[] values = MuPrimitive.values(); private static final HashSet<IValue> emptyMset = new HashSet<IValue>(0); private static final boolean profileMuPrimitives = false; private static final long timeSpent[] = new long[values.length]; public static MuPrimitive fromInteger(int muprim) { return values[muprim]; } private static boolean isNonTerminalType(Type t) { return t.isExternalType() && ((RascalType) t).isNonterminal(); } public Object execute0() { throw RascalRuntimeException.notImplemented("MuPrimitive.execute0 " + name(), null, null); } public Object execute1(final Object arg_1) { throw RascalRuntimeException.notImplemented("MuPrimitive.execute1 " + name(), null, null); } public Object execute2(final Object arg_2, final Object arg_1) { throw RascalRuntimeException.notImplemented("MuPrimitive.execute2 " + name(), null, null); } public int executeN(final Object[] stack, final int sp, final int arity) { throw RascalRuntimeException.notImplemented("MuPrimitive.executeN " + name(), null, null); } public static void recordTime(int n, long duration){ timeSpent[n] += duration; } public static void exit(PrintWriter out) { if(profileMuPrimitives){ printProfile(out); } } static void printProfile(PrintWriter out){ out.println("\nMuPrimitive execution times (ms)"); long total = 0; TreeMap<Long,String> data = new TreeMap<Long,String>(); for(int i = 0; i < values.length; i++){ if(timeSpent[i] > 0 ){ data.put(timeSpent[i], values[i].name()); total += timeSpent[i]; } } for(long t : data.descendingKeySet()){ out.printf("%30s: %3d%% (%d ms)\n", data.get(t), t * 100 / total, t); } } /******************************************************************* * AUXILIARY FUNCTIONS * ******************************************************************/ /** * @param v * @return true if v is a 'lit' or 'cilit'. */ private static boolean $is_literal(final IValue v){ if(isNonTerminalType(v.getType())) { return TreeAdapter.isLiteral((ITree) v); } return false; } private static boolean $is_nullable(final IValue v){ if (v instanceof ITree) { return TreeAdapter.getArgs((ITree) v).length() == 0; } return false; } /* * Main program: handy to map a primitive index back to its name (e.g., in profiles!) */ public static void main(String[] args) { int n = 102; System.err.println("MuPrimitive: " + fromInteger(n) + " (" + n + ")"); } } class ArrayIterator<T> implements Iterator<T> { private T array[]; private int pos = 0; public ArrayIterator(T anArray[]) { array = anArray; } public boolean hasNext() { return pos < array.length; } public T next() throws NoSuchElementException { if (hasNext()) return array[pos++]; else throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } }