/******************************************************************************* * Copyright (c) 2009-2015 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl * * Arnold Lankamp - Arnold.Lankamp@cwi.nl * * Paul Klint - Paul.Klint@cwi.nl *******************************************************************************/ package org.rascalmpl.values.uptr; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Random; import org.rascalmpl.interpreter.TypeReifier; import org.rascalmpl.interpreter.types.RascalTypeFactory; import org.rascalmpl.parser.gtd.util.ArrayList; import org.rascalmpl.value.IAnnotatable; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IExternalValue; import org.rascalmpl.value.IInteger; import org.rascalmpl.value.IList; import org.rascalmpl.value.IListRelation; import org.rascalmpl.value.IListWriter; import org.rascalmpl.value.IMap; import org.rascalmpl.value.INode; import org.rascalmpl.value.ISet; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.IWithKeywordParameters; import org.rascalmpl.value.exceptions.FactTypeUseException; import org.rascalmpl.value.exceptions.UndeclaredFieldException; import org.rascalmpl.value.impl.AbstractDefaultAnnotatable; import org.rascalmpl.value.impl.AbstractDefaultWithKeywordParameters; import org.rascalmpl.value.impl.AbstractValueFactoryAdapter; import org.rascalmpl.value.impl.AnnotatedConstructorFacade; import org.rascalmpl.value.impl.ConstructorWithKeywordParametersFacade; import org.rascalmpl.value.impl.persistent.ValueFactory; import org.rascalmpl.value.io.StandardTextReader; import org.rascalmpl.value.io.StandardTextWriter; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.type.TypeStore; import org.rascalmpl.value.visitors.IValueVisitor; import org.rascalmpl.values.uptr.visitors.TreeVisitor; import io.usethesource.capsule.AbstractSpecialisedImmutableMap; import io.usethesource.capsule.ImmutableMap; /** * The RascalValueFactory extends a given IValueFactory with the Rascal-specific builtin * data types it needs to bootstrap and to provide syntax features. This includes * * UPTR - universal parse tree format * * Type - reified types for PDB and Rascal types * * Functions/Closures - TBD; not represented here yet * * Modules - TBD; not represented here yet * * Grammars - Partially here in the definition of Production * * UPTR stands for Universal Parse Node Representation (formerly known as AsFix). It is * an abstract syntax for Rascal production rules, completed with constructors for parse forests. * UPTR is produced by parser implementations (as generated from Rascal grammars for example). * UPTR is consumed by tools that manipulate parse trees in general (such as * automatic syntax high-lighters) or tools that manipulate specific parse trees (such * as the Rascal interpreter). * * UPTR parse trees (Tree) are special ADT trees in the sense that: * * their implementation classes are specialized (compressed) implementations of IConstructor * for the sake of speed * * their instances have NonTerminalType instead of AbstractDataType * * Reified type values (Type) are special in the sense that they satisfy a special contract * which binds a reified type representation to the run-time type of the reified type: * Namely, for any instance of `Type[&T] = type(Symbol s, map[Symbol,Production] definitions)` * it holds that: * * &T is bound to the {@link Type} represented by Symbol s * * At least all definitions necessary for constructing any value of type &T are * listed in the `definitions` map. * Note that a reified type is in fact also a reified type environment. * Use {@link TypeReifier} for mapping back and forth between Types and reified types. * * For (de)serialization using (for example) {@link StandardTextReader} and {@link StandardTextWriter} * the RascalValueFactory is needed as a parameter as well as its {@method getStore()} method to * provide deserialization with the right definitions of data-types. * * For inspecting manipulating values for the data-types which are defined here please see this API: * * {@link TreeAdapter} * * {@link SymbolAdapter} * * {@link ProductionAdapter} * * All definitions included here are echoed in ParseTree.rsc and Type.rsc. The clone is necessary * for bootstrapping reasons. This class is where it all starts. */ public class RascalValueFactory extends AbstractValueFactoryAdapter implements IRascalValueFactory { public final static TypeStore uptr = new TypeStore(); private final static TypeFactory tf = TypeFactory.getInstance(); // This is where we bind the persistent implementation of IValueFactory: private static final IValueFactory bootFactory = ValueFactory.getInstance(); private final TypeReifier tr = new TypeReifier(bootFactory); private static final Type str = tf.stringType(); /* General abstract sort declarations */ public static final Type Tree = tf.abstractDataType(uptr, "Tree"); public static final Type Production = tf.abstractDataType(uptr, "Production"); public static final Type Attributes = tf.abstractDataType(uptr, "Attributes"); public static final Type Attr = tf.abstractDataType(uptr, "Attr"); public static final Type Associativity = tf.abstractDataType(uptr, "Associativity"); public static final Type Symbol = tf.abstractDataType(uptr, "Symbol"); public static final Type CharRange = tf.abstractDataType(uptr, "CharRange"); public static final Type Args = tf.listType(Tree); public static final Type Attrs = tf.setType(Attr); public static final Type Symbols = tf.listType(Symbol); public static final Type CharRanges = tf.listType(CharRange); public static final Type Alternatives = tf.setType(Tree); /* The next three declarations and the static block are order dependend */ public static final Type TypeParam = tf.parameterType("T"); public static final Type Type = RascalTypeFactory.getInstance().reifiedType(TypeParam); static { uptr.declareAbstractDataType(Type); } public static final Type Type_Reified = tf.constructor(uptr, Type, "type", Symbol, "symbol", tf.mapType(Symbol , Production), "definitions"); public static final Type ADTforType = tf.abstractDataType(uptr, "type", TypeParam); // temporary for de-serializing Type /* end order dependence */ /* Constructors for Tree */ public static final Type Tree_Appl = tf.constructor(uptr, Tree, "appl", Production, "prod", tf.listType(Tree), "args"); public static final Type Tree_Cycle = tf.constructor(uptr, Tree, "cycle", Symbol, "symbol", tf.integerType(), "cycleLength"); public static final Type Tree_Amb = tf.constructor(uptr, Tree, "amb", Alternatives, "alternatives"); public static final Type Tree_Char = tf.constructor(uptr, Tree, "char", tf.integerType(), "character"); /* Constructors for Production */ public static final Type Production_Default = tf.constructor(uptr, Production, "prod", Symbol, "def", tf.listType(Symbol), "symbols", tf.setType(Attr), "attributes"); public static final Type Production_Regular = tf.constructor(uptr, Production, "regular", Symbol, "def"); public static final Type Production_Error = tf.constructor(uptr, Production, "error", Production, "prod", tf.integerType(), "dot"); public static final Type Production_Skipped = tf.constructor(uptr, Production, "skipped"); public static final Type Production_Cons = tf.constructor(uptr, Production, "cons", Symbol, "def", tf.listType(Symbol), "symbols", tf.listType(Symbol), "kwTypes", tf.setType(Attr), "attributes"); public static final Type Production_Func = tf.constructor(uptr, Production, "func", Symbol, "def", tf.listType(Symbol), "symbols", tf.listType(Symbol), "kwTypes", tf.setType(Attr), "attributes"); public static final Type Production_Choice = tf.constructor(uptr, Production, "choice", Symbol, "def", tf.setType(Production), "alternatives"); public static final Type Production_Priority = tf.constructor(uptr, Production, "priority", Symbol, "def", tf.listType(Production), "choices"); public static final Type Production_Composition = tf.constructor(uptr, Production, "composition", Production, "lhs", Production, "rhs"); public static final Type Production_Associativity = tf.constructor(uptr, Production, "associativity", Symbol, "def", Associativity, "assoc", tf.setType(Production), "alternatives"); /* Constructors for Attr */ public static final Type Attr_Assoc = tf.constructor(uptr, Attr, "assoc", Associativity, "assoc"); public static final Type Attr_Tag = tf.constructor(uptr, Attr, "tag", tf.valueType(), "tag"); public static final Type Attr_Bracket = tf.constructor(uptr, Attr, "bracket"); /* Constructors for Associativity */ public static final Type Associativity_Left = tf.constructor(uptr, Associativity, "left"); public static final Type Associativity_Right = tf.constructor(uptr, Associativity, "right"); public static final Type Associativity_Assoc = tf.constructor(uptr, Associativity, "assoc"); public static final Type Associativity_NonAssoc = tf.constructor(uptr, Associativity, "non-assoc"); /* Constructors for Condition */ public static final Type Condition = tf.abstractDataType(uptr, "Condition"); public static final Type Condition_Follow = tf.constructor(uptr, Condition, "follow", Symbol, "symbol"); public static final Type Condition_NotFollow = tf.constructor(uptr, Condition, "not-follow", Symbol, "symbol"); public static final Type Condition_Precede = tf.constructor(uptr, Condition, "precede", Symbol, "symbol"); public static final Type Condition_NotPrecede = tf.constructor(uptr, Condition, "not-precede", Symbol, "symbol"); public static final Type Condition_Delete = tf.constructor(uptr, Condition, "delete", Symbol, "symbol"); public static final Type Condition_EndOfLine = tf.constructor(uptr, Condition, "end-of-line"); public static final Type Condition_StartOfLine = tf.constructor(uptr, Condition, "begin-of-line"); public static final Type Condition_AtColumn = tf.constructor(uptr, Condition, "at-column", tf.integerType(), "column"); public static final Type Condition_Except = tf.constructor(uptr, Condition, "except", str, "label"); /* Constructors for Symbol */ public static final Type Symbol_Label = tf.constructor(uptr, Symbol, "label", str, "name", Symbol, "symbol"); public static final Type Symbol_Start_Sort = tf.constructor(uptr, Symbol, "start", Symbol, "symbol"); public static final Type Symbol_Lit = tf.constructor(uptr, Symbol, "lit", str, "string"); public static final Type Symbol_CiLit = tf.constructor(uptr, Symbol, "cilit", str, "string"); public static final Type Symbol_Empty = tf.constructor(uptr, Symbol, "empty"); public static final Type Symbol_Seq = tf.constructor(uptr, Symbol, "seq", tf.listType(Symbol), "symbols"); public static final Type Symbol_Opt = tf.constructor(uptr, Symbol, "opt", Symbol, "symbol"); public static final Type Symbol_Alt = tf.constructor(uptr, Symbol, "alt", tf.setType(Symbol), "alternatives"); public static final Type Symbol_Sort = tf.constructor(uptr, Symbol, "sort", str, "name"); public static final Type Symbol_Lex = tf.constructor(uptr, Symbol, "lex", str, "name"); public static final Type Symbol_Keyword = tf.constructor(uptr, Symbol, "keywords", str, "name"); public static final Type Symbol_Meta = tf.constructor(uptr, Symbol, "meta", Symbol, "symbol"); public static final Type Symbol_Conditional = tf.constructor(uptr, Symbol, "conditional", Symbol, "symbol", tf.setType(Condition), "conditions"); public static final Type Symbol_IterSepX = tf.constructor(uptr, Symbol, "iter-seps", Symbol, "symbol", tf.listType(Symbol), "separators"); public static final Type Symbol_IterStarSepX = tf.constructor(uptr, Symbol, "iter-star-seps", Symbol, "symbol", tf.listType(Symbol), "separators"); public static final Type Symbol_IterPlus = tf.constructor(uptr, Symbol, "iter", Symbol, "symbol"); public static final Type Symbol_IterStar = tf.constructor(uptr, Symbol, "iter-star", Symbol, "symbol"); public static final Type Symbol_ParameterizedSort = tf.constructor(uptr, Symbol, "parameterized-sort", str, "name", tf.listType(Symbol), "parameters"); public static final Type Symbol_ParameterizedLex = tf.constructor(uptr, Symbol, "parameterized-lex", str, "name", tf.listType(Symbol), "parameters"); public static final Type Symbol_Parameter = tf.constructor(uptr, Symbol, "parameter", str, "name", Symbol, "bound"); public static final Type Symbol_LayoutX = tf.constructor(uptr, Symbol, "layouts", str, "name"); public static final Type Symbol_CharClass = tf.constructor(uptr, Symbol, "char-class", tf.listType(CharRange), "ranges"); public static final Type Symbol_Int = tf.constructor(uptr, Symbol, "int"); public static final Type Symbol_Rat = tf.constructor(uptr, Symbol, "rat"); public static final Type Symbol_Bool = tf.constructor(uptr, Symbol, "bool"); public static final Type Symbol_Real = tf.constructor(uptr, Symbol, "real"); public static final Type Symbol_Str = tf.constructor(uptr, Symbol, "str"); public static final Type Symbol_Node = tf.constructor(uptr, Symbol, "node"); public static final Type Symbol_Num = tf.constructor(uptr, Symbol, "num"); public static final Type Symbol_Void = tf.constructor(uptr, Symbol, "void"); public static final Type Symbol_Value = tf.constructor(uptr, Symbol, "value"); public static final Type Symbol_Loc = tf.constructor(uptr, Symbol, "loc"); public static final Type Symbol_Datetime = tf.constructor(uptr, Symbol, "datetime"); public static final Type Symbol_Set = tf.constructor(uptr, Symbol, "set", Symbol, "symbol"); public static final Type Symbol_Rel = tf.constructor(uptr, Symbol, "rel", tf.listType(Symbol), "symbols"); public static final Type Symbol_ListRel = tf.constructor(uptr, Symbol, "lrel", tf.listType(Symbol), "symbols"); public static final Type Symbol_Tuple = tf.constructor(uptr, Symbol, "tuple", tf.listType(Symbol), "symbols"); public static final Type Symbol_List = tf.constructor(uptr, Symbol, "list", Symbol, "symbol"); public static final Type Symbol_Map = tf.constructor(uptr, Symbol, "map", Symbol, "from", Symbol, "to"); public static final Type Symbol_Bag = tf.constructor(uptr, Symbol, "bag", Symbol, "symbol"); public static final Type Symbol_Adt = tf.constructor(uptr, Symbol, "adt", str, "name", tf.listType(Symbol), "parameters"); public static final Type Symbol_ReifiedType = tf.constructor(uptr, Symbol, "reified", Symbol, "symbol"); public static final Type Symbol_Func = tf.constructor(uptr, Symbol, "func", Symbol, "ret", tf.listType(Symbol), "parameters"); public static final Type Symbol_Alias = tf.constructor(uptr, Symbol, "alias", str, "name", tf.listType(Symbol), "parameters", Symbol, "aliased"); public static final Type Symbol_Cons = tf.constructor(uptr, Symbol, "cons", Symbol, "adt", str, "name", tf.listType(Symbol), "parameters"); public static final Type Symbol_BoundParameter = tf.constructor(uptr, Symbol, "parameter", str , "name", Symbol, "bound"); /* Internally (type checker) used constructors for Symbol: */ public static final Type Symbol_Overloaded = tf.constructor(uptr, Symbol, "overloaded", tf.setType(Symbol), "overloads", tf.setType(Symbol), "defaults"); public static final Type Symbol_Prod = tf.constructor(uptr, Symbol, "prod", Symbol, "sort", str, "name", tf.listType(Symbol), "parameters", tf.setType(Attr), "attributes"); /* Constructors for CharRange */ public static final Type CharRange_Single = tf.constructor(uptr, CharRange, "from", tf.integerType()); // TODO: can go when older parser is gone public static final Type CharRange_Range = tf.constructor(uptr, CharRange, "range", tf.integerType(), "begin", tf.integerType(), "end"); /* Constructors for Attribute */ public static final IValue Attribute_Assoc_Left = bootFactory.constructor(Attr_Assoc, bootFactory.constructor(Associativity_Left)); public static final IValue Attribute_Assoc_Right = bootFactory.constructor(Attr_Assoc, bootFactory.constructor(Associativity_Right)); public static final IValue Attribute_Assoc_Non_Assoc = bootFactory.constructor(Attr_Assoc, bootFactory.constructor(Associativity_NonAssoc)); public static final IValue Attribute_Assoc_Assoc = bootFactory.constructor(Attr_Assoc, bootFactory.constructor(Associativity_Assoc)); public static final IValue Attribute_Bracket = bootFactory.constructor(Attr_Bracket); /* Constructors for Function instances to be used in encodeAsConstructor */ public static final Type Function = tf.abstractDataType(uptr, "Function"); public static final Type Function_Choice = tf.constructor(uptr, Function, "choice", tf.listType(Function), "alternatives", tf.listType(Function), "otherwise"); public static final Type Function_Function = tf.constructor(uptr, Function, "function", tf.sourceLocationType(), "id"); public static final Type Function_Closure = tf.constructor(uptr, Function, "closure", Function, "definition", tf.mapType(str, tf.valueType()), "environment"); public static final Type Function_Composition = tf.constructor(uptr, Function, "composition", Function, "lhs", Function, "rhs"); @Deprecated /** Will be replaced by keyword parameter "origin" */ public static final String Location = "loc"; @Deprecated /** Will be removed completely */ public static final String Length = "len"; static { uptr.declareAnnotation(Tree, Location, tf.sourceLocationType()); uptr.declareAnnotation(Tree, Length, tf.integerType()); } /** nested class for thread safe singleton allocation */ static private class InstanceHolder { static final RascalValueFactory sInstance = new RascalValueFactory(); } /*package*/ static IRascalValueFactory getInstance() { return InstanceHolder.sInstance; } /** caches ASCII characters for sharing */ private final static ITree byteChars[]; private final static Type byteCharTypes[]; static { byteChars = new ITree[Byte.MAX_VALUE]; byteCharTypes = new Type[Byte.MAX_VALUE]; for (byte i = 0; i < Byte.MAX_VALUE; i++) { byteChars[i] = new CharByte(i); byteCharTypes[i] = RascalTypeFactory.getInstance().nonTerminalType(bootFactory.constructor(Symbol_CharClass, bootFactory.list(bootFactory.constructor(CharRange_Range, bootFactory.integer(i), bootFactory.integer(i))))); } } /** * Use getInstance() */ private RascalValueFactory() { super(bootFactory); } public static TypeStore getStore() { return uptr; } @Override public INode node(String name, IValue... children) { IConstructor res = specializeNode(name, children); return res != null ? res: super.node(name, children); } private IConstructor specializeNode(String name, IValue... children) { if (Type_Reified.getName().equals(name) && children.length == 2 && children[0].getType().isSubtypeOf(Type_Reified.getFieldType(0)) && children[1].getType().isSubtypeOf(Type_Reified.getFieldType(1))) { return reifiedType((IConstructor) children[0], (IMap) children[1]); } return null; } @Override public INode node(String name, Map<String, IValue> annotations, IValue... children) throws FactTypeUseException { IConstructor res = specializeNode(name, children); return res != null ? res: super.node(name, annotations, children); } @Override public INode node(String name, IValue[] children, Map<String, IValue> kws) throws FactTypeUseException { IConstructor result = specializeNode(name, children); return result != null ? (kws != null && !kws.isEmpty() ? result.asWithKeywordParameters().setParameters(kws) : result) : super.node(name, children, kws); } @Override public IConstructor constructor(Type constructor, IValue[] children, Map<String, IValue> kwParams) throws FactTypeUseException { if (constructor == null) { throw new NullPointerException(); } Arrays.stream(children).forEach(t -> { if (t == null) throw new NullPointerException(); }); kwParams.values().stream().forEach(t -> { if (t == null) throw new NullPointerException(); }); IConstructor result = specializeConstructor(constructor, children); return result != null ? (kwParams != null && !kwParams.isEmpty() && result.mayHaveKeywordParameters() ? result.asWithKeywordParameters().setParameters(kwParams) : result) : super.constructor(constructor, children, kwParams); } @Override public IConstructor constructor(Type constructor, IValue... children) throws FactTypeUseException { if (constructor == null) { throw new NullPointerException(); } Arrays.stream(children).forEach(t -> { if (t == null) throw new NullPointerException(); }); IConstructor result = specializeConstructor(constructor, children); return result != null ? result : super.constructor(constructor, children); } @Override public IConstructor constructor(Type constructor, Map<String, IValue> annotations, IValue... children) throws FactTypeUseException { if (constructor == null) { throw new NullPointerException(); } Arrays.stream(children).forEach(t -> { if (t == null) throw new NullPointerException(); }); annotations.values().stream().forEach(t -> { if (t == null) throw new NullPointerException(); }); IConstructor result = specializeConstructor(constructor, children); return result != null ? result.asAnnotatable().setAnnotations(annotations) : super.constructor(constructor, annotations, children); } /** * This is where the core functionality of this class is implemented, specializing IConstructor values */ private IConstructor specializeConstructor(Type constructor, IValue... children) { if (constructor.getAbstractDataType() == Tree) { if (constructor == Tree_Appl) { return appl((IConstructor) children[0], (IList) children[1]); } else if (constructor == Tree_Amb) { return amb((ISet) children[0]); } else if (constructor == Tree_Char) { return character(((IInteger) children[0]).intValue()); } else if (constructor == Tree_Cycle) { return cycle((IConstructor) children[0], ((IInteger) children[1]).intValue()); } } else if (constructor == Type_Reified || constructor.getAbstractDataType() == ADTforType) { return reifiedType((IConstructor) children[0], (IMap) children[1]); } return null; } @Override public IConstructor reifiedType(IConstructor symbol, IMap definitions) { java.util.Map<Type,Type> bindings = Collections.singletonMap(RascalValueFactory.TypeParam, tr.symbolToType(symbol, definitions)); return super.constructor(RascalValueFactory.Type_Reified.instantiate(bindings), symbol, definitions); } @Override public ITree character(int ch) { if (ch >= 0 && ch <= Byte.MAX_VALUE) { return character((byte) ch); } return new CharInt(ch); } @Override public ITree character(byte ch) { return byteChars[ch]; } @Override public ITree appl(Map<String,IValue> annos, IConstructor prod, IList args) { return (ITree) appl(prod, args).asAnnotatable().setAnnotations(annos); } /** * For use with the UPTRNodeFactory otherwise will be replaced */ @Deprecated @Override public ITree appl(IConstructor prod, ArrayList<ITree> args) { switch (args.size()) { case 0: return new Appl0(prod); case 1: return new Appl1(prod, args.get(0)); case 2: return new Appl2(prod, args.get(0), args.get(1)); case 3: return new Appl3(prod, args.get(0), args.get(1), args.get(2)); case 4: return new Appl4(prod, args.get(0), args.get(1), args.get(2), args.get(3)); case 5: return new Appl5(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4)); case 6: return new Appl6(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4), args.get(5)); case 7: return new Appl7(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4), args.get(5), args.get(6)); default: return new ApplN(prod, new ArrayListArgumentList(args)); } } /** * Construct a specialized IConstructor representing a Tree, applying a prod to a list of arguments */ @Override public ITree appl(IConstructor prod, IList args) { switch (args.length()) { case 0: return new Appl0(prod); case 1: return new Appl1(prod, args.get(0)); case 2: return new Appl2(prod, args.get(0), args.get(1)); case 3: return new Appl3(prod, args.get(0), args.get(1), args.get(2)); case 4: return new Appl4(prod, args.get(0), args.get(1), args.get(2), args.get(3)); case 5: return new Appl5(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4)); case 6: return new Appl6(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4), args.get(5)); case 7: return new Appl7(prod, args.get(0), args.get(1), args.get(2), args.get(3), args.get(4), args.get(5), args.get(6)); default: return new ApplN(prod, args); } } /** * Watch out, the array is not cloned! Must not modify hereafter. */ @Override public ITree appl(IConstructor prod, IValue... args) { switch (args.length) { case 0: return new Appl0(prod); case 1: return new Appl1(prod, args[0]); case 2: return new Appl2(prod, args[0], args[1]); case 3: return new Appl3(prod, args[0], args[1], args[2]); case 4: return new Appl4(prod, args[0], args[1], args[2], args[3]); case 5: return new Appl5(prod, args[0], args[1], args[2], args[3], args[4]); case 6: return new Appl6(prod, args[0], args[1], args[2], args[3], args[4], args[5]); case 7: return new Appl7(prod, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); default: return new ApplN(prod, new ArrayArgumentList(args)); } } @Override public ITree cycle(IConstructor symbol, int cycleLength) { return new Cycle(symbol, cycleLength); } @Override public ITree amb(ISet alternatives) { if (alternatives.size() == 1) { // fast builtin canonicalization of singleton ambiguity clusters is // necessary when client code filters ambiguity clusters. This may // happen during visits and during parse tree construction using the // `filter` statement or by constructing a singleton set accidentally. // // &T <: Tree amb({&T <: Tree t}) = t; // // Note that without this canonicalization pattern matches are bound // to fail because of the extra indirection of the amb cluster. return (ITree) alternatives.iterator().next(); } return new Amb(alternatives); } /* * Below here are specialized static classes for {@link IConstructor} * creating slim instances for Tree appl and for lazy {@link IList} * implementations for avoiding copying arrays/lists at parse tree creation time. * * Some classes are specialized by arity to avoid memory overhead. Specialization * is also necessary to correctly implement getType() and to optimize hashCode(). * * To avoid code duplication between specialized classes we factor out common elements in the {@link AbstractAppl} and * and {@link AbstractArgumentList} abstract classes. */ static class CharInt implements ITree, IExternalValue { final int ch; @Override public boolean isChar() { return true; } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return (ITree) v.visitTreeChar(this); } @Override public IAnnotatable<? extends ITree> asAnnotatable() { return new AbstractDefaultAnnotatable<ITree>(this) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> annotations) { return new AnnotatedCharFacade(content, annotations); } }; } public CharInt(int ch) { this.ch = ch; } @Override public IConstructor encodeAsConstructor() { return this; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch (i) { case 0: return getInstance().integer(ch); default: throw new IndexOutOfBoundsException(); } } @Override public int arity() { return 1; } @Override public String getName() { return Tree_Char.getName(); } @Override public Iterable<IValue> getChildren() { return this; } @Override public int hashCode() { return ch; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { boolean done = false; @Override public boolean hasNext() { return !done; } @Override public IValue next() { done = true; return getInstance().integer(ch); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public INode replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { throw new UnsupportedOperationException(); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitConstructor(this); } @Override public boolean isEqual(IValue other) { if (other instanceof CharInt) { CharInt o = (CharInt) other; return o.ch == ch; } return false; } @Override public boolean isAnnotatable() { return false; } @Override public boolean mayHaveKeywordParameters() { return true; } @Override public Type getType() { return RascalTypeFactory.getInstance().nonTerminalType(SymbolAdapter.charClass(ch)); } @Override public Type getConstructorType() { return Tree_Char; } @Override public Type getUninstantiatedConstructorType() { return Tree_Char; } @Override public IValue get(String label) { return get(Tree_Char.getFieldIndex(label)); } @Override public IConstructor set(String label, IValue newChild) throws FactTypeUseException { return set(Tree_Char.getFieldIndex(label), newChild); } @Override public boolean has(String label) { return Tree_Char.hasField(label); } @Override public IConstructor set(int index, IValue newChild) throws FactTypeUseException { switch (index) { case 0: return getInstance().character(((IInteger) newChild).intValue()); default: throw new IndexOutOfBoundsException(); } } @Override public Type getChildrenTypes() { return tf.tupleType(tf.integerType()); } @Override public boolean declaresAnnotation(TypeStore store, String label) { return false; } @Override public IWithKeywordParameters<ITree> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<ITree>(this, AbstractSpecialisedImmutableMap.<String,IValue>mapOf()) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> parameters) { return new CharWithKeywordParametersFacade(content, parameters); } }; } } private static class CharByte implements ITree, IExternalValue { final byte ch; public CharByte(byte ch) { this.ch = ch; } @Override public boolean isChar() { return true; } @Override public IAnnotatable<? extends ITree> asAnnotatable() { return new AbstractDefaultAnnotatable<ITree>(this) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> annotations) { return new AnnotatedCharFacade(content, annotations); } }; } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return (ITree) v.visitTreeChar(this); } @Override public IConstructor encodeAsConstructor() { return this; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch (i) { case 0: return getInstance().integer(ch); default: throw new IndexOutOfBoundsException(); } } @Override public int arity() { return 1; } @Override public String getName() { return Tree_Char.getName(); } @Override public Iterable<IValue> getChildren() { return this; } @Override public int hashCode() { return ch; } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { boolean done = false; @Override public boolean hasNext() { return !done; } @Override public IValue next() { done = true; return getInstance().integer(ch); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public INode replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { throw new UnsupportedOperationException(); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitConstructor(this); } @Override public boolean isEqual(IValue other) { if (other instanceof CharByte) { CharByte o = (CharByte) other; return o.ch == ch; } return false; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override public boolean isAnnotatable() { return false; } @Override public boolean mayHaveKeywordParameters() { return true; } @Override public Type getType() { return byteCharTypes[ch]; } @Override public Type getConstructorType() { return Tree_Char; } @Override public Type getUninstantiatedConstructorType() { return Tree_Char; } @Override public IValue get(String label) { return get(Tree_Char.getFieldIndex(label)); } @Override public IConstructor set(String label, IValue newChild) throws FactTypeUseException { return set(Tree_Char.getFieldIndex(label), newChild); } @Override public boolean has(String label) { return Tree_Char.hasField(label); } @Override public IConstructor set(int index, IValue newChild) throws FactTypeUseException { switch (index) { case 0: return getInstance().character(((IInteger) newChild).intValue()); default: throw new IndexOutOfBoundsException(); } } @Override public Type getChildrenTypes() { return tf.tupleType(tf.integerType()); } @Override public boolean declaresAnnotation(TypeStore store, String label) { return false; } @Override public IWithKeywordParameters<ITree> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<ITree>(this, AbstractSpecialisedImmutableMap.<String,IValue>mapOf()) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> parameters) { return new CharWithKeywordParametersFacade(content, parameters); } }; } } private static class Cycle implements ITree, IExternalValue { protected final IConstructor symbol; protected final int cycleLength; public Cycle(IConstructor symbol, int cycleLength) { this.symbol = symbol; this.cycleLength = cycleLength; } @Override public IAnnotatable<? extends ITree> asAnnotatable() { return new AbstractDefaultAnnotatable<ITree>(this) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> annotations) { return new AnnotatedCycleFacade(content, annotations); } }; } @Override public boolean isCycle() { return true; } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return (ITree) v.visitTreeCycle(this); } @Override public IConstructor encodeAsConstructor() { return this; } @Override public String getName() { return Tree_Cycle.getName(); } @Override public Iterable<IValue> getChildren() { return this; } @Override public int hashCode() { return 17 + 19 * symbol.hashCode() + 29 * cycleLength; } @Override public boolean isEqual(IValue other) { if (other instanceof IConstructor) { IConstructor cons = (IConstructor) other; return cons.getConstructorType() == getConstructorType() && cons.get(0).isEqual(get(0)) && ((IInteger) cons.get(1)).intValue() == cycleLength; } return false; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { private int count = 0; @Override public boolean hasNext() { return count < 2; } @Override public IValue next() { count++; switch(count) { case 1: return symbol; case 2: return getInstance().integer(cycleLength); default: return null; } } }; } @Override public int arity() { return 2; } @Override public String toString() { return StandardTextWriter.valueToString(this); } @Override public INode replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { throw new UnsupportedOperationException("Replace not supported on constructor."); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitConstructor(this); } @Override public boolean isAnnotatable() { return true; } @Override public boolean mayHaveKeywordParameters() { return false; } @Override public Type getType() { return RascalTypeFactory.getInstance().nonTerminalType(symbol); } @Override public Type getConstructorType() { return Tree_Cycle; } @Override public Type getUninstantiatedConstructorType() { return Tree_Cycle; } @Override public IValue get(String label) { switch (label) { case "symbol": return symbol; case "cycleLength": return getInstance().integer(cycleLength); default: throw new UndeclaredFieldException(Tree_Amb, label); } } @Override public IConstructor set(String label, IValue newChild) throws FactTypeUseException { switch (label) { case "symbol": return getInstance().cycle((IConstructor) newChild, cycleLength); case "cycleLength" : return getInstance().cycle(symbol, ((IInteger) newChild).intValue()); default: throw new UndeclaredFieldException(Tree_Appl, label); } } @Override public boolean has(String label) { return Tree_Cycle.hasField(label); } @Override public IConstructor set(int index, IValue newChild) throws FactTypeUseException { switch (index) { case 0: return getInstance().cycle((IConstructor) newChild, cycleLength); case 1: return getInstance().cycle(symbol, ((IInteger) newChild).intValue()); default: throw new IndexOutOfBoundsException(); } } @Override public Type getChildrenTypes() { return tf.tupleType(Symbol, tf.integerType()); } @Override public boolean declaresAnnotation(TypeStore store, String label) { return store.getAnnotations(Tree).containsKey(label); } @Override public IWithKeywordParameters<IConstructor> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<IConstructor>(this, AbstractSpecialisedImmutableMap.<String,IValue>mapOf()) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> parameters) { return new ConstructorWithKeywordParametersFacade(content, parameters); } }; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch (i) { case 0: return symbol; case 1: return getInstance().integer(cycleLength); default: throw new IndexOutOfBoundsException(); } } } private static class Amb implements ITree, IExternalValue { protected final ISet alternatives; public Amb(ISet alts) { this.alternatives = alts; } @Override public IAnnotatable<? extends ITree> asAnnotatable() { return new AbstractDefaultAnnotatable<ITree>(this) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> annotations) { return new AnnotatedAmbFacade(content, annotations); } }; } @Override public boolean isAmb() { return true; } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return (ITree) v.visitTreeAmb(this); } @Override public IConstructor encodeAsConstructor() { return this; } @Override public String getName() { return Tree_Amb.getName(); } @Override public Iterable<IValue> getChildren() { return this; } @Override public int hashCode() { return 43 + 751 * alternatives.hashCode(); } @Override public boolean isEqual(IValue other) { if (other instanceof Amb) { ITree cons = (ITree) other; return cons.getAlternatives().isEqual(alternatives); } return false; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override public ISet getAlternatives() { return alternatives; } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { private int count = 0; @Override public boolean hasNext() { return count < 1; } @Override public IValue next() { count++; switch(count) { case 1: return getAlternatives(); default: return null; } } }; } @Override public int arity() { return 1; } @Override public String toString() { return StandardTextWriter.valueToString(this); } @Override public INode replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { throw new UnsupportedOperationException("Replace not supported on constructor."); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitConstructor(this); } @Override public boolean isAnnotatable() { return true; } @Override public boolean mayHaveKeywordParameters() { return true; } @Override public Type getType() { if (!alternatives.isEmpty()) { return RascalTypeFactory.getInstance().nonTerminalType((IConstructor) alternatives.iterator().next()); } else { return RascalTypeFactory.getInstance().nonTerminalType(IRascalValueFactory.getInstance().constructor(RascalValueFactory.Symbol_Empty)); } } @Override public Type getConstructorType() { return Tree_Amb; } @Override public Type getUninstantiatedConstructorType() { return Tree_Amb; } @Override public IValue get(String label) { switch (label) { case "alternatives": return getAlternatives(); default: throw new UndeclaredFieldException(Tree_Amb, label); } } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { switch (label) { case "alternatives": return getInstance().amb((ISet) newChild); default: throw new UndeclaredFieldException(Tree_Appl, label); } } @Override public boolean has(String label) { return Tree_Amb.hasField(label); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { switch (index) { case 0: return getInstance().amb((ISet) newChild); default: throw new IndexOutOfBoundsException(); } } @Override public Type getChildrenTypes() { return tf.tupleType(Alternatives); } @Override public boolean declaresAnnotation(TypeStore store, String label) { return store.getAnnotations(Tree).containsKey(label); } @Override public IWithKeywordParameters<ITree> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<ITree>(this, AbstractSpecialisedImmutableMap.<String,IValue>mapOf()) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> parameters) { return new AmbWithKeywordParametersFacade(content, parameters); } }; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch (i) { case 0: return alternatives; default: throw new IndexOutOfBoundsException(); } } } static public class ApplWithKeywordParametersFacade extends ConstructorWithKeywordParametersFacade implements ITree { public ApplWithKeywordParametersFacade(IConstructor content, ImmutableMap<String, IValue> parameters) { super(content, parameters); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeAppl(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new ApplWithKeywordParametersFacade(newContent, parameters); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new ApplWithKeywordParametersFacade(newContent, parameters); } @Override public IWithKeywordParameters<? extends IConstructor> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<IConstructor>(content, parameters) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> parameters) { return parameters.isEmpty() ? content : new ApplWithKeywordParametersFacade(content, parameters); } }; } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { throw new UnsupportedOperationException(); } @Override public boolean isAppl() { return true; } @Override public IConstructor getProduction() { return ((ITree) content).getProduction(); } } static class AnnotatedApplFacade extends AnnotatedConstructorFacade implements ITree { public AnnotatedApplFacade(IConstructor content, ImmutableMap<String, IValue> annotations) { super(content, annotations); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeAppl(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new AnnotatedApplFacade(newContent, annotations); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new AnnotatedApplFacade(newContent, annotations); } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { return new AbstractDefaultAnnotatable<IConstructor>(content, annotations) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> annotations) { return annotations.isEmpty() ? content : new AnnotatedApplFacade(content, annotations); } }; } @Override public boolean mayHaveKeywordParameters() { return false; } @Override public IWithKeywordParameters<IConstructor> asWithKeywordParameters() { throw new UnsupportedOperationException(); } @Override public boolean isAppl() { return true; } @Override public IConstructor getProduction() { return ((ITree) content).getProduction(); } } static public class AmbWithKeywordParametersFacade extends ConstructorWithKeywordParametersFacade implements ITree { public AmbWithKeywordParametersFacade(IConstructor content, ImmutableMap<String, IValue> parameters) { super(content, parameters); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeAmb(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new AmbWithKeywordParametersFacade(newContent, parameters); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new AmbWithKeywordParametersFacade(newContent, parameters); } @Override public IWithKeywordParameters<? extends IConstructor> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<IConstructor>(content, parameters) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> parameters) { return parameters.isEmpty() ? content : new AmbWithKeywordParametersFacade(content, parameters); } }; } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { throw new UnsupportedOperationException(); } @Override public boolean isAmb() { return true; } @Override public ISet getAlternatives() { return ((ITree) content).getAlternatives(); } } static public class AnnotatedAmbFacade extends AnnotatedConstructorFacade implements ITree { public AnnotatedAmbFacade(IConstructor content, ImmutableMap<String, IValue> annotations) { super(content, annotations); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeAmb(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new AnnotatedAmbFacade(newContent, annotations); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new AnnotatedAmbFacade(newContent, annotations); } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { return new AbstractDefaultAnnotatable<IConstructor>(content, annotations) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> annotations) { return annotations.isEmpty() ? content : new AnnotatedAmbFacade(content, annotations); } }; } @Override public boolean isAmb() { return true; } @Override public ISet getAlternatives() { return ((ITree) content).getAlternatives(); } } static public class CycleWithKeywordParametersFacade extends ConstructorWithKeywordParametersFacade implements ITree { public CycleWithKeywordParametersFacade(IConstructor content, ImmutableMap<String, IValue> parameters) { super(content, parameters); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeCycle(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new CycleWithKeywordParametersFacade(newContent, parameters); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new CycleWithKeywordParametersFacade(newContent, parameters); } @Override public IWithKeywordParameters<? extends IConstructor> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<IConstructor>(content, parameters) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> parameters) { return parameters.isEmpty() ? content : new CycleWithKeywordParametersFacade(content, parameters); } }; } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { throw new UnsupportedOperationException(); } @Override public boolean isCycle() { return true; } } static class AnnotatedCycleFacade extends AnnotatedConstructorFacade implements ITree { public AnnotatedCycleFacade(IConstructor content, ImmutableMap<String, IValue> annotations) { super(content, annotations); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeCycle(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new AnnotatedCycleFacade(newContent, annotations); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new AnnotatedCycleFacade(newContent, annotations); } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { return new AbstractDefaultAnnotatable<IConstructor>(content, annotations) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> annotations) { return annotations.isEmpty() ? content : new AnnotatedCycleFacade(content, annotations); } }; } @Override public boolean isCycle() { return true; } } static public class CharWithKeywordParametersFacade extends ConstructorWithKeywordParametersFacade implements ITree { public CharWithKeywordParametersFacade(IConstructor content, ImmutableMap<String, IValue> parameters) { super(content, parameters); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeChar(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new CharWithKeywordParametersFacade(newContent, parameters); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new CharWithKeywordParametersFacade(newContent, parameters); } @Override public IWithKeywordParameters<? extends IConstructor> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<IConstructor>(content, parameters) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> parameters) { return parameters.isEmpty() ? content : new CharWithKeywordParametersFacade(content, parameters); } }; } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { throw new UnsupportedOperationException(); } @Override public boolean isChar() { return true; } @Override public IInteger getCharacter() { return ((ITree) content).getCharacter(); } } static class AnnotatedCharFacade extends AnnotatedConstructorFacade implements ITree { public AnnotatedCharFacade(IConstructor content, ImmutableMap<String, IValue> annotations) { super(content, annotations); } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return v.visitTreeChar(this); } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(label, newChild); return new AnnotatedCharFacade(newContent, annotations); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { IConstructor newContent = content.set(index, newChild); return new AnnotatedCharFacade(newContent, annotations); } @Override public IAnnotatable<? extends IConstructor> asAnnotatable() { return new AbstractDefaultAnnotatable<IConstructor>(content, annotations) { @Override protected IConstructor wrap(IConstructor content, ImmutableMap<String, IValue> annotations) { return annotations.isEmpty() ? content : new AnnotatedCharFacade(content, annotations); } }; } @Override public boolean isChar() { return true; } @Override public IInteger getCharacter() { return ((ITree) content).getCharacter(); } } private static abstract class AbstractAppl implements ITree, IExternalValue { protected final IConstructor production; @Override public IAnnotatable<? extends ITree> asAnnotatable() { return new AbstractDefaultAnnotatable<ITree>(this) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> annotations) { return new AnnotatedApplFacade(content, annotations); } }; } protected AbstractAppl(IConstructor production) { this.production = production; } @Override public IConstructor getProduction() { return production; } @Override public boolean isAppl() { return true; } @Override public IConstructor encodeAsConstructor() { return this; } @Override public <E extends Throwable> ITree accept(TreeVisitor<E> v) throws E { return (ITree) v.visitTreeAppl(this); } @Override public String getName() { return Tree_Appl.getName(); } @Override public Iterable<IValue> getChildren() { return this; } @Override public int hashCode() { return 41 + 1331 * production.hashCode() + 13331 * getArgs().hashCode(); } @Override public boolean isEqual(IValue other) { if (other instanceof IConstructor) { IConstructor cons = (IConstructor) other; return cons.getConstructorType() == getConstructorType() && cons.get(0).isEqual(get(0)) && cons.get(1).isEqual(get(1)); } return false; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override abstract public IList getArgs(); @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { private int count = 0; @Override public boolean hasNext() { return count < 2; } @Override public IValue next() { count++; switch(count) { case 1: return production; case 2: return getArgs(); default: return null; } } }; } @Override public int arity() { return 2; } @Override public String toString() { return StandardTextWriter.valueToString(this); } @Override public INode replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { throw new UnsupportedOperationException("Replace not supported on constructor."); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitConstructor(this); } @Override public boolean isAnnotatable() { return true; } @Override public boolean mayHaveKeywordParameters() { return true; } @Override public Type getType() { // it is important to give the whole tree here, to be able to check for non-empty lists which have a more concrete type // than possibly empty lists! return RascalTypeFactory.getInstance().nonTerminalType(this); } @Override public Type getConstructorType() { return Tree_Appl; } @Override public Type getUninstantiatedConstructorType() { return Tree_Appl; } @Override public IValue get(String label) { switch (label) { case "prod": return production; case "args": return getArgs(); default: throw new UndeclaredFieldException(Tree_Appl, label); } } @Override public ITree set(String label, IValue newChild) throws FactTypeUseException { switch (label) { case "prod": return getInstance().appl((IConstructor) newChild, getArgs()); case "args": return getInstance().appl(production, (IList) newChild); default: throw new UndeclaredFieldException(Tree_Appl, label); } } @Override public boolean has(String label) { return Tree_Appl.hasField(label); } @Override public ITree set(int index, IValue newChild) throws FactTypeUseException { switch (index) { case 0: return getInstance().appl((IConstructor) newChild, getArgs()); case 1: return getInstance().appl(production, newChild); default: throw new IndexOutOfBoundsException(); } } @Override public Type getChildrenTypes() { return tf.tupleType(production.getType(), Args); } @Override public boolean declaresAnnotation(TypeStore store, String label) { return store.getAnnotations(Tree).containsKey(label); } @Override public IWithKeywordParameters<ITree> asWithKeywordParameters() { return new AbstractDefaultWithKeywordParameters<ITree>(this, AbstractSpecialisedImmutableMap.<String,IValue>mapOf()) { @Override protected ITree wrap(ITree content, ImmutableMap<String, IValue> parameters) { return new ApplWithKeywordParametersFacade(content, parameters); } }; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch (i) { case 0: return production; case 1: return getArgs(); default: throw new IndexOutOfBoundsException(); } } } private static abstract class AbstractArgumentList implements IList { // caching the hash on the list level (and nowhere else) // to balance memory usage and making sure computing hash codes // for any parse tree node is in (amortized) constant time protected int hash = 0; protected abstract IList asNormal(); @Override public Type getType() { return tf.listType(getElementType()); } @Override public boolean contains(IValue e) { for (int i = 0; i < length(); i++) { if (get(i).isEqual(e)) { return true; } } return false; } @Override public String toString() { return StandardTextWriter.valueToString(this); } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitList(this); } @Override public boolean isEqual(IValue other) { if (other instanceof IList) { IList o = (IList) other; if (o.length() == length()) { for (int i = 0; i < length(); i++) { if (!o.get(i).isEqual(get(i))) { return false; } } return true; } } return false; } @Override public boolean equals(Object obj) { if (!(obj instanceof IValue)) { return false; } return isEqual((IValue) obj); } @Override public int hashCode(){ if (hash != 0) { return hash; } Iterator<IValue> iterator = iterator(); while(iterator.hasNext()){ IValue element = iterator.next(); hash = (hash << 1) ^ element.hashCode(); } return hash; } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { private int count = 0; @Override public boolean hasNext() { return count < length(); } @Override public IValue next() { count++; return get(count - 1); } }; } @Override public boolean isAnnotatable() { return false; } @Override public IAnnotatable<? extends IValue> asAnnotatable() { throw new UnsupportedOperationException(); } @Override public boolean mayHaveKeywordParameters() { throw new UnsupportedOperationException(); } @Override public IWithKeywordParameters<? extends IValue> asWithKeywordParameters() { throw new UnsupportedOperationException(); } @Override public Type getElementType() { Type lub = tf.voidType(); for (IValue elem : this) { if (lub == Tree) { // it's not going to be wider anyway return Tree; } lub = lub.lub(elem.getType()); } return lub; } @Override public IList reverse() { return asNormal().reverse(); } @Override public IList append(IValue e) { return asNormal().append(e); } @Override public IList insert(IValue e) { return asNormal().insert(e); } @Override public IList concat(IList o) { return asNormal().concat(o); } @Override public IList shuffle(Random rand) { return asNormal().shuffle(rand); } @Override public IList put(int i, IValue e) throws FactTypeUseException, IndexOutOfBoundsException { return asNormal().put(i,e); } @Override public IList replace(int first, int second, int end, IList repl) throws FactTypeUseException, IndexOutOfBoundsException { return asNormal().replace(first, second, end, repl); } @Override public IList sublist(int offset, int length) { return asNormal().sublist(offset,length); } public boolean isEmpty() { return false; } @Override public IList delete(IValue e) { return asNormal().delete(e); } @Override public IList delete(int i) { return asNormal().delete(i); } @Override public IList product(IList l) { return asNormal().product(l); } @Override public IList intersect(IList l) { return asNormal().intersect(l); } @Override public IList subtract(IList l) { return asNormal().subtract(l); } @Override public boolean isSubListOf(IList l) { return asNormal().isSubListOf(l); } @Override public boolean isRelation() { return false; } @Override public IListRelation<IList> asRelation() { throw new UnsupportedOperationException(); } } private static class ArrayArgumentList extends AbstractArgumentList { private final IValue[] array; public ArrayArgumentList(IValue[] array) { this.array = array; } @Override public int length() { return array.length; } @Override public IValue get(int i) throws IndexOutOfBoundsException { return array[i]; } @Override protected IList asNormal() { return getInstance().list(array); } } @Deprecated private static class ArrayListArgumentList extends AbstractArgumentList { private final ArrayList<ITree> list; public ArrayListArgumentList(ArrayList<ITree> list) { this.list = list; } @Override public int length() { return list.size(); } @Override public IValue get(int i) throws IndexOutOfBoundsException { return list.get(i); } @Override protected IList asNormal() { IListWriter w = getInstance().listWriter(); for (int i = 0; i < list.size(); i++) { w.append(list.get(i)); } return w.done(); } } private static class Appl0 extends AbstractAppl { private static final IList EMPTY_LIST = getInstance().listWriter().done(); public Appl0(IConstructor production) { super(production); } @Override public IList getArgs() { return EMPTY_LIST; } @Override public int hashCode() { return 17 + 13 * production.hashCode(); } } private static class ApplN extends AbstractAppl { private final IList args; public ApplN(IConstructor production, IList args) { super(production); this.args = args; } @Override public IList getArgs() { return args; } @Override public int hashCode() { return 3 + 17 * production.hashCode() + 91 * args.hashCode() ; } } private static class Appl1 extends AbstractAppl { private final IValue arg0; public Appl1(IConstructor production, IValue arg) { super(production); this.arg0 = arg; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 1; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0); } }; } @Override public int hashCode() { return 17 + 13 * production.hashCode() + 17 * arg0.hashCode() ; } } private static class Appl2 extends AbstractAppl { private final IValue arg0; private final IValue arg1; public Appl2(IConstructor production, IValue arg0, IValue arg1) { super(production); this.arg0 = arg0; this.arg1 = arg1; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 2; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1); } }; } @Override public int hashCode() { return 23 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() ; } } private static class Appl3 extends AbstractAppl { private final IValue arg0; private final IValue arg1; private final IValue arg2; public Appl3(IConstructor production, IValue arg0, IValue arg1, IValue arg2) { super(production); this.arg0 = arg0; this.arg1 = arg1; this.arg2 = arg2; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 3; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; case 2: return arg2; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1, arg2); } }; } @Override public int hashCode() { return 29 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() + 29 * arg2.hashCode() ; } } private static class Appl4 extends AbstractAppl { private final IValue arg0; private final IValue arg1; private final IValue arg2; private final IValue arg3; public Appl4(IConstructor production, IValue arg0, IValue arg1, IValue arg2, IValue arg3) { super(production); this.arg0 = arg0; this.arg1 = arg1; this.arg2 = arg2; this.arg3 = arg3; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 4; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; case 2: return arg2; case 3: return arg3; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1, arg2, arg3); } }; } @Override public int hashCode() { return 31 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() + 29 * arg2.hashCode() + 31 * arg3.hashCode() ; } } private static class Appl5 extends AbstractAppl { private final IValue arg0; private final IValue arg1; private final IValue arg2; private final IValue arg3; private final IValue arg4; public Appl5(IConstructor production, IValue arg0, IValue arg1, IValue arg2, IValue arg3, IValue arg4) { super(production); this.arg0 = arg0; this.arg1 = arg1; this.arg2 = arg2; this.arg3 = arg3; this.arg4 = arg4; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 5; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; case 2: return arg2; case 3: return arg3; case 4: return arg4; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1, arg2, arg3, arg4); } }; } @Override public int hashCode() { return 31 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() + 29 * arg2.hashCode() + 31 * arg3.hashCode() + 37 * arg4.hashCode() ; } } private static class Appl6 extends AbstractAppl { private final IValue arg0; private final IValue arg1; private final IValue arg2; private final IValue arg3; private final IValue arg4; private final IValue arg5; public Appl6(IConstructor production, IValue arg0, IValue arg1, IValue arg2, IValue arg3, IValue arg4, IValue arg5) { super(production); this.arg0 = arg0; this.arg1 = arg1; this.arg2 = arg2; this.arg3 = arg3; this.arg4 = arg4; this.arg5 = arg5; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 6; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; case 2: return arg2; case 3: return arg3; case 4: return arg4; case 5: return arg5; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1, arg2, arg3, arg4, arg5); } }; } @Override public int hashCode() { return 31 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() + 29 * arg2.hashCode() + 31 * arg3.hashCode() + 37 * arg4.hashCode() + 41 * arg5.hashCode() ; } } private static class Appl7 extends AbstractAppl { private final IValue arg0; private final IValue arg1; private final IValue arg2; private final IValue arg3; private final IValue arg4; private final IValue arg5; private final IValue arg6; public Appl7(IConstructor production, IValue arg0, IValue arg1, IValue arg2, IValue arg3, IValue arg4, IValue arg5, IValue arg6) { super(production); this.arg0 = arg0; this.arg1 = arg1; this.arg2 = arg2; this.arg3 = arg3; this.arg4 = arg4; this.arg5 = arg5; this.arg6 = arg6; } @Override public IList getArgs() { return new AbstractArgumentList() { @Override public int length() { return 7; } @Override public IValue get(int i) throws IndexOutOfBoundsException { switch(i) { case 0: return arg0; case 1: return arg1; case 2: return arg2; case 3: return arg3; case 4: return arg4; case 5: return arg5; case 6: return arg6; default: throw new IndexOutOfBoundsException(); } } @Override protected IList asNormal() { return getInstance().list(arg0, arg1, arg2, arg3, arg4, arg5, arg6); } }; } @Override public int hashCode() { return 31 + 13 * production.hashCode() + 17 * arg0.hashCode() + 23 * arg1.hashCode() + 29 * arg2.hashCode() + 31 * arg3.hashCode() + 37 * arg4.hashCode() + 41 * arg5.hashCode() + 43 * arg6.hashCode() ; } } // please put additional methods above the nested classes }