diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..824792cdb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 80 + +[*.sh] +end_of_line = lf + +[*.java] +indent_size = 4 +max_line_length = 120 + + +[*.yaml] +indent_size = 2 + +[*.yml] +indent_size = 2 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..cf1b98867 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,13 @@ +# Run this command to always ignore formatting commits in `git blame` +# git config blame.ignoreRevsFile .git-blame-ignore-revs + +# replaced tabs with spaces +8efd5a7227658bbcc5b46ba647d15edf42dc0302 + +# removed trailing whitespace +63917fec5f518cd66ebbf56903d5167ac1c815ab + +# normalize indentation +4ca06f1346d13d6e275d891de918cc6bae85c3d8 +f3301743a5e4ca39b415e4f1fa32c66a39ef37b5 + diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5159b4edb..3261f8267 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -25,6 +25,30 @@ jobs: name: Event File path: ${{ github.event_path }} + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} # run it on the PR, not on the merged commit, for better line numbers + + - uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: 'temurin' + cache: 'maven' + - name: Run checkstyle and print errors + run: mvn -B checkstyle:checkstyle checkstyle:check + - name: Report build results + uses: gmazzo/publish-report-annotations@v1 # target latest major + if: ${{ !cancelled() }} + with: + testsSummary: off + reports: "target/checkstyle-result.xml" + + + test: if: ${{ !(github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[maven-release-plugin]')) }} strategy: @@ -39,7 +63,7 @@ jobs: java-version: 11 distribution: 'temurin' cache: 'maven' - + - name: test run: mvn -B clean test @@ -49,7 +73,7 @@ jobs: with: name: Unit Test Results (${{ matrix.os }}) path: target/surefire-reports/**/*.xml - + checker-framework: if: ${{ !(github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, '[maven-release-plugin]')) }} runs-on: ubuntu-latest diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 000000000..d950a751d --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 0300485c8..717ca578e 100644 --- a/pom.xml +++ b/pom.xml @@ -164,6 +164,14 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.5.0 + + checkstyle.xml + + diff --git a/src/main/java/io/usethesource/vallang/IBool.java b/src/main/java/io/usethesource/vallang/IBool.java index 1b7ac29ae..813b7359d 100644 --- a/src/main/java/io/usethesource/vallang/IBool.java +++ b/src/main/java/io/usethesource/vallang/IBool.java @@ -13,7 +13,7 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IBool extends IValue { - @Override + @Override default int getMatchFingerprint() { if (getValue()) { return 3569038; /* "true".hashCode() */ @@ -23,17 +23,17 @@ default int getMatchFingerprint() { } } - boolean getValue(); - String getStringRepresentation(); - IBool and(IBool other); - IBool or(IBool other); - IBool xor(IBool other); - IBool not(); - IBool implies(IBool other); - IBool equivalent(IBool other); - - @Override - default T accept(IValueVisitor v) throws E { - return v.visitBoolean(this); - } + boolean getValue(); + String getStringRepresentation(); + IBool and(IBool other); + IBool or(IBool other); + IBool xor(IBool other); + IBool not(); + IBool implies(IBool other); + IBool equivalent(IBool other); + + @Override + default T accept(IValueVisitor v) throws E { + return v.visitBoolean(this); + } } diff --git a/src/main/java/io/usethesource/vallang/ICollection.java b/src/main/java/io/usethesource/vallang/ICollection.java index 75b46233b..9479c144e 100644 --- a/src/main/java/io/usethesource/vallang/ICollection.java +++ b/src/main/java/io/usethesource/vallang/ICollection.java @@ -15,19 +15,19 @@ public interface ICollection> extends IValue, Iterable< public default Type getElementType() { return getType().getElementType(); } - + /** * @return true iff this container has no elements */ public boolean isEmpty(); - + /** * @return an empty collection */ public default T empty() { return writer().done(); } - + /** * @return an empty writer for this collection kind */ @@ -37,20 +37,20 @@ public default T empty() { * @return the arity of the collection (the number of elements in it) */ public int size(); - + /** * @return this collection with an IRelation interface * @throws IllegalOperationException when the container does not contain all tuples of the same arity */ public IRelation asRelation(); - + /** * @return true iff the collection contains only tuples of a fixed width, if any. */ public default boolean isRelation() { return getElementType().isFixedWidth(); } - + /** * Computes the Cartesian product of two collections * @param that is another collection @@ -62,7 +62,7 @@ public default T product(T that) { if (that.isEmpty()) { return that; } - + for (IValue t1 : this) { for (IValue t2 : that) { w.appendTuple(t1, t2); @@ -71,11 +71,11 @@ public default T product(T that) { return w.done(); } - + /** * Computes the union of two collections, ignoring duplicates. The original duplicates in the receiver and the given container will dissappear as well. - * - * @param that is the other collection + * + * @param that is the other collection * @return a collection containing both the elements of the receiver and those of the given container, without introducing duplicates. */ public default T union(T that) { @@ -84,7 +84,7 @@ public default T union(T that) { w.appendAll(that); return w.done(); } - + /** * @return a stream of IValues from the current collection */ diff --git a/src/main/java/io/usethesource/vallang/IConstructor.java b/src/main/java/io/usethesource/vallang/IConstructor.java index 13566ca61..78cff7a12 100644 --- a/src/main/java/io/usethesource/vallang/IConstructor.java +++ b/src/main/java/io/usethesource/vallang/IConstructor.java @@ -8,7 +8,7 @@ * Contributors: * * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang; @@ -25,118 +25,118 @@ */ public interface IConstructor extends INode { - @Override - default int getMatchFingerprint() { - return getName().hashCode() + 131 * arity(); - } - - /** - * @return the specific ConstructorType of this constructor - */ - public Type getConstructorType(); - - /** + @Override + default int getMatchFingerprint() { + return getName().hashCode() + 131 * arity(); + } + + /** + * @return the specific ConstructorType of this constructor + */ + public Type getConstructorType(); + + /** * @return the specific ConstructorType of this constructor but before instantiating * type parameters. This is needed for serialization purposes. */ - public Type getUninstantiatedConstructorType(); - - /** - * Get a child from a labeled position in the tree. - * @param label the name of the child - * @return a value at the position indicated by the label. - */ - public IValue get(String label); - - /** - * Replace a child at a labeled position in the tree. - * @param label the label of the position - * @param newChild the new value of the child - * @return a new tree node that is the same as the receiver except for - * the fact that at the labeled position the new value has replaced the old value. - * All keyword fields remain equal. - * - * @throws FactTypeUseException when this label does not exist for the given tree node, or - * when the given value has a type that is not a sub-type of the declared type - * of the child with this label. - */ - public IConstructor set(String label, IValue newChild); - - /** - * Find out whether this constructor has a field a given name - * @param label name of the field - * - * @return true iff this constructor has this field name - */ - public boolean has(String label); - - /** - * Replace a child at an indexed position in the tree. - * @param label the label of the position - * @param newChild the new value of the child - * @return a new tree node that is the same as the receiver except for - * the fact that at the labeled position the new value has replaced the old value. - * All keyword fields remain equal. - * - * @throws FactTypeUseException when the index is greater than the arity of this tree node, or - * when the given value has a type that is not a sub-type of the declared type - * of the child at this index. - */ - @Override - public IConstructor set(int index, IValue newChild); - - /** - * @return a tuple type representing the children types of this node/ - */ - public Type getChildrenTypes(); - - /* - * (non-Javadoc) - * @see IValue#asWithKeywordParameters() - */ - @Override - public IWithKeywordParameters asWithKeywordParameters(); - - @Override - default boolean match(IValue value) { - if(value == this) return true; - if(value == null) return false; - - if (value instanceof IConstructor){ - IConstructor otherTree = (IConstructor) value; - - if (getConstructorType() != otherTree.getConstructorType()) { - return false; - } - - final Iterator it1 = iterator(); - final Iterator it2 = otherTree.iterator(); - - while (it1.hasNext() && it2.hasNext()) { - // call to IValue.isEqual(IValue) - if (!it1.next().match(it2.next())) { - return false; - } - } - - return true; - } - - return false; - } - - @Override + public Type getUninstantiatedConstructorType(); + + /** + * Get a child from a labeled position in the tree. + * @param label the name of the child + * @return a value at the position indicated by the label. + */ + public IValue get(String label); + + /** + * Replace a child at a labeled position in the tree. + * @param label the label of the position + * @param newChild the new value of the child + * @return a new tree node that is the same as the receiver except for + * the fact that at the labeled position the new value has replaced the old value. + * All keyword fields remain equal. + * + * @throws FactTypeUseException when this label does not exist for the given tree node, or + * when the given value has a type that is not a sub-type of the declared type + * of the child with this label. + */ + public IConstructor set(String label, IValue newChild); + + /** + * Find out whether this constructor has a field a given name + * @param label name of the field + * + * @return true iff this constructor has this field name + */ + public boolean has(String label); + + /** + * Replace a child at an indexed position in the tree. + * @param label the label of the position + * @param newChild the new value of the child + * @return a new tree node that is the same as the receiver except for + * the fact that at the labeled position the new value has replaced the old value. + * All keyword fields remain equal. + * + * @throws FactTypeUseException when the index is greater than the arity of this tree node, or + * when the given value has a type that is not a sub-type of the declared type + * of the child at this index. + */ + @Override + public IConstructor set(int index, IValue newChild); + + /** + * @return a tuple type representing the children types of this node/ + */ + public Type getChildrenTypes(); + + /* + * (non-Javadoc) + * @see IValue#asWithKeywordParameters() + */ + @Override + public IWithKeywordParameters asWithKeywordParameters(); + + @Override + default boolean match(IValue value) { + if(value == this) return true; + if(value == null) return false; + + if (value instanceof IConstructor){ + IConstructor otherTree = (IConstructor) value; + + if (getConstructorType() != otherTree.getConstructorType()) { + return false; + } + + final Iterator it1 = iterator(); + final Iterator it2 = otherTree.iterator(); + + while (it1.hasNext() && it2.hasNext()) { + // call to IValue.isEqual(IValue) + if (!it1.next().match(it2.next())) { + return false; + } + } + + return true; + } + + return false; + } + + @Override default T accept(IValueVisitor v) throws E { return v.visitConstructor(this); } - - static boolean assertTypeCorrectConstructorApplication(Type cons, IValue[] children) { + + static boolean assertTypeCorrectConstructorApplication(Type cons, IValue[] children) { assert cons.getArity() == children.length : cons + " has arity " + cons.getArity() + " while " + children.length + " arguments are provided."; - + for (int i = 0; i < cons.getArity(); i++) { assert children[i].getType().isSubtypeOf(cons.getFieldType(i)) : "Constructing " + cons + ", expected argument " + i + " of type " + cons.getFieldType(i) + " but got " + children[i].getType(); } - + return true; } } diff --git a/src/main/java/io/usethesource/vallang/IDateTime.java b/src/main/java/io/usethesource/vallang/IDateTime.java index 6a68cf701..66d16c222 100644 --- a/src/main/java/io/usethesource/vallang/IDateTime.java +++ b/src/main/java/io/usethesource/vallang/IDateTime.java @@ -18,121 +18,121 @@ * date, time, or datetime. */ public interface IDateTime extends IValue, Comparable { - /** - * Retrieve the date and time as an instant, defined as the number of - * milliseconds from 1970-01-01T00:00Z. This is compatible with the - * concept of an instant in the Java standard datetime libraries and - * in libraries such as Joda Time. - * - * @return the number of milliseconds from 1970-01-01T00:00Z - */ - public long getInstant(); - - /** - * Get the century. If isTime() == true, this value is undefined. - * - * @return the century (all but the last 2 digits of the year) - */ - public int getCentury(); - - /** - * Get the year. If isTime() == true, this value is undefined. - * - * @return the year - */ - public int getYear(); - - /** - * Get the month of year. If isTime() == true, this value is undefined. - * - * @return the month of year - */ - public int getMonthOfYear(); - - /** - * Get the day of month. If isTime() == true, this value is undefined. - * - * @return the day of month - */ - public int getDayOfMonth(); - - /** - * Get the hour of day value. Hours should be based on a 24 hour - * clock, as this interface does not provide am/pm information. - * If isDate() == true, this value is undefined. - * - * @return the hour of the day - */ - public int getHourOfDay(); - - /** - * Get the minute of hour value. If isDate() == true, this value is - * undefined. - * - * @return the minute of the hour - */ - public int getMinuteOfHour(); - - /** - * Get the second of minute value. If isDate() == true, this value - * is undefined. - * - * @return the second of the minute - */ - public int getSecondOfMinute(); - - /** - * Get the milliseconds of second value. If isDate() == true, this - * value is undefined. - * - * @return the milliseconds of the second - */ - public int getMillisecondsOfSecond(); - - /** - * Get the signed numeric value representing the hour offset from - * UTC for the time, based on the timezone assigned to the time. - * If isDate() == true, this value is undefined. - * - * @return the hour offset from UTC for the timezone of the time - */ - public int getTimezoneOffsetHours(); - - /** - * Get the value representing the minute offset from UTC for the time, - * based on the timezone assigned to the time. This should be positive - * unless getTimezoneOffsetHours() == 0. - * If isDate() == true, this value is undefined. - * - * @return the minute offset from UTC for the timezone of the time - */ - public int getTimezoneOffsetMinutes(); - - /** - * Indicates if this DateTime represents just a date (with no time). - * - * @return true if this is just a date, false otherwise - */ - public boolean isDate(); - - /** - * Indicates if this DateTime represents just a time (with no date). - * - * @return true if this is just a time, false otherwise - */ - public boolean isTime(); - - /** - * Indicates if this DateTime represents a date and time. - * - * @return true if this is a datetime, false otherwise - */ - public boolean isDateTime(); - - @Override - default T accept(IValueVisitor v) throws E { - return v.visitDateTime(this); - } - - IString format(String format); + /** + * Retrieve the date and time as an instant, defined as the number of + * milliseconds from 1970-01-01T00:00Z. This is compatible with the + * concept of an instant in the Java standard datetime libraries and + * in libraries such as Joda Time. + * + * @return the number of milliseconds from 1970-01-01T00:00Z + */ + public long getInstant(); + + /** + * Get the century. If isTime() == true, this value is undefined. + * + * @return the century (all but the last 2 digits of the year) + */ + public int getCentury(); + + /** + * Get the year. If isTime() == true, this value is undefined. + * + * @return the year + */ + public int getYear(); + + /** + * Get the month of year. If isTime() == true, this value is undefined. + * + * @return the month of year + */ + public int getMonthOfYear(); + + /** + * Get the day of month. If isTime() == true, this value is undefined. + * + * @return the day of month + */ + public int getDayOfMonth(); + + /** + * Get the hour of day value. Hours should be based on a 24 hour + * clock, as this interface does not provide am/pm information. + * If isDate() == true, this value is undefined. + * + * @return the hour of the day + */ + public int getHourOfDay(); + + /** + * Get the minute of hour value. If isDate() == true, this value is + * undefined. + * + * @return the minute of the hour + */ + public int getMinuteOfHour(); + + /** + * Get the second of minute value. If isDate() == true, this value + * is undefined. + * + * @return the second of the minute + */ + public int getSecondOfMinute(); + + /** + * Get the milliseconds of second value. If isDate() == true, this + * value is undefined. + * + * @return the milliseconds of the second + */ + public int getMillisecondsOfSecond(); + + /** + * Get the signed numeric value representing the hour offset from + * UTC for the time, based on the timezone assigned to the time. + * If isDate() == true, this value is undefined. + * + * @return the hour offset from UTC for the timezone of the time + */ + public int getTimezoneOffsetHours(); + + /** + * Get the value representing the minute offset from UTC for the time, + * based on the timezone assigned to the time. This should be positive + * unless getTimezoneOffsetHours() == 0. + * If isDate() == true, this value is undefined. + * + * @return the minute offset from UTC for the timezone of the time + */ + public int getTimezoneOffsetMinutes(); + + /** + * Indicates if this DateTime represents just a date (with no time). + * + * @return true if this is just a date, false otherwise + */ + public boolean isDate(); + + /** + * Indicates if this DateTime represents just a time (with no date). + * + * @return true if this is just a time, false otherwise + */ + public boolean isTime(); + + /** + * Indicates if this DateTime represents a date and time. + * + * @return true if this is a datetime, false otherwise + */ + public boolean isDateTime(); + + @Override + default T accept(IValueVisitor v) throws E { + return v.visitDateTime(this); + } + + IString format(String format); } diff --git a/src/main/java/io/usethesource/vallang/IExternalValue.java b/src/main/java/io/usethesource/vallang/IExternalValue.java index 193641392..561e52365 100644 --- a/src/main/java/io/usethesource/vallang/IExternalValue.java +++ b/src/main/java/io/usethesource/vallang/IExternalValue.java @@ -31,37 +31,37 @@ * interfaces but do need to integrate with them. *
* Note that implementations of IExternalValues are obliged to have a type that subclasses - * ExternalType and that they all implement encodeAsConstructor. + * ExternalType and that they all implement encodeAsConstructor. * If you do not do this, (de)serialization will not work. *
* Note that NORMAL USE OF THE PDB DOES NOT REQUIRE IMPLEMENTING THIS INTERFACE */ public interface IExternalValue extends IValue { - /** + /** * External values must re-think their pattern match fingerprint, * instead of returning `IValue.hashCode()` automatically. */ @Override int getMatchFingerprint(); - /** - * @return an ExternalType - */ - @Override - Type getType(); - - public default IConstructor encodeAsConstructor() { + /** + * @return an ExternalType + */ + @Override + Type getType(); + + public default IConstructor encodeAsConstructor() { return new IConstructor() { @Override public Type getConstructorType() { return TypeFactory.getInstance().constructor(new TypeStore(), getType(), getName()); } - + @Override public INode setChildren(IValue[] childArray) { return this; } - + @Override public Type getType() { return TypeFactory.getInstance().valueType(); @@ -111,57 +111,57 @@ public boolean mayHaveKeywordParameters() { public INode replace(int first, int second, int end, IList repl) { return this; } - + @Override public int arity() { return 0; } - + @Override public IValue get(int i) { throw new IndexOutOfBoundsException(Integer.toString(i)); } - + @Override public Iterable getChildren() { return Collections.emptyList(); } - - + + @Override public Iterator iterator() { return Collections.emptyIterator(); } - + @Override public IWithKeywordParameters asWithKeywordParameters() { - return new AbstractDefaultWithKeywordParameters(this, AbstractSpecialisedImmutableMap.mapOf()) { - @Override - protected IConstructor wrap(IConstructor content, io.usethesource.capsule.Map.Immutable parameters) { - return new ConstructorWithKeywordParametersFacade(content, parameters); - } - - @Override - public boolean hasParameters() { - return false; - } - - @Override - public java.util.Set getParameterNames() { - return Collections.emptySet(); - } - - @Override - public Map getParameters() { - return Collections.unmodifiableMap(parameters); - } - }; - } - }; + return new AbstractDefaultWithKeywordParameters(this, AbstractSpecialisedImmutableMap.mapOf()) { + @Override + protected IConstructor wrap(IConstructor content, io.usethesource.capsule.Map.Immutable parameters) { + return new ConstructorWithKeywordParametersFacade(content, parameters); + } + + @Override + public boolean hasParameters() { + return false; + } + + @Override + public java.util.Set getParameterNames() { + return Collections.emptySet(); + } + + @Override + public Map getParameters() { + return Collections.unmodifiableMap(parameters); + } + }; + } + }; + } + + @Override + default T accept(IValueVisitor v) throws E { + return v.visitExternal(this); } - - @Override - default T accept(IValueVisitor v) throws E { - return v.visitExternal(this); - } } diff --git a/src/main/java/io/usethesource/vallang/IInteger.java b/src/main/java/io/usethesource/vallang/IInteger.java index 5fd7e6d63..66e9bb212 100644 --- a/src/main/java/io/usethesource/vallang/IInteger.java +++ b/src/main/java/io/usethesource/vallang/IInteger.java @@ -25,24 +25,24 @@ default int getMatchFingerprint() { } } - /** - * @return this + other; - */ + /** + * @return this + other; + */ @Override public IInteger add(IInteger other); - + /** * @return this - other; */ @Override public IInteger subtract(IInteger other); - + /** * @return this * other; */ @Override public IInteger multiply(IInteger other); - + /** * @return this / other; */ @@ -58,93 +58,93 @@ default int getMatchFingerprint() { * This may be a negative number. */ public IInteger remainder(IInteger other); - + /** * @return -1 * this; */ @Override public IInteger negate(); - + /** * @return this % other, which is always a positive IInteger */ public IInteger mod(IInteger other); - + /** * @return an IReal that is equal to this IInteger */ @Override public IReal toReal(int precision); - + /** * @return true iff this < other */ @Override public IBool less(IInteger other); - + /** * @return true iff this > other */ @Override public IBool greater(IInteger other); - + /** * @return true iff this <= other */ @Override public IBool lessEqual(IInteger other); - + /** * @return true iff this >= other */ @Override public IBool greaterEqual(IInteger other); - + /** * @return the value of the IInteger represent as a string of decimal numbers in ASCII encoding. */ public String getStringRepresentation(); - + /** * @return the two's complement representation of this integer in the minimum - * amount of required bytes and in big-endian order. + * amount of required bytes and in big-endian order. */ public byte[] getTwosComplementRepresentation(); - + /** * Converts this IInteger to an int. If it * does not fit an ArithmeticException is thrown. - * + * * Use doubleValue() instead, if you are not sure if the * result will fit in an int. - * + * */ public int intValue() throws ArithmeticException; - + /** - * Converts this IInteger to a long. + * Converts this IInteger to a long. * If it does not fit an ArithmeticException is thrown. * * Use doubleValue() instead, if you are not sure if the * result will fit in a long. - * + * */ public long longValue() throws ArithmeticException; - + /** - * Converts this IInteger to a double. + * Converts this IInteger to a double. * The conversion may lose precision, and will yield +/- Inf * if the magnitude is too large for a double. */ public double doubleValue(); - + /** * Compares two integers * @param other * @return -1 if receiver is less than other, 0 is receiver is equal, 1 if receiver is larger */ public int compare(IInteger other); - + /** * @return return -1, 0 or 1 iff this integer is less than, equal to or greater than zero. */ @@ -156,9 +156,9 @@ default int getMatchFingerprint() { */ @Override public IInteger abs(); - - @Override - public default T accept(IValueVisitor v) throws E { - return v.visitInteger(this); - } + + @Override + public default T accept(IValueVisitor v) throws E { + return v.visitInteger(this); + } } diff --git a/src/main/java/io/usethesource/vallang/IList.java b/src/main/java/io/usethesource/vallang/IList.java index 7335d7554..36c88d22b 100644 --- a/src/main/java/io/usethesource/vallang/IList.java +++ b/src/main/java/io/usethesource/vallang/IList.java @@ -22,7 +22,7 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IList extends ICollection { - + @Override default int getMatchFingerprint() { return 3322014; // "list".hashCode() @@ -35,12 +35,12 @@ default int getMatchFingerprint() { public default int size() { return length(); } - + /** * Return the length of the list == size(); */ public int length(); - + /** * @return a new list with all elements in reverse order */ @@ -51,7 +51,7 @@ public default IList reverse() { } return w.done(); } - + /** * @param rand the random generator to use for the shuffling. If the same seed is set, the same shuffling should happen. * @return a new list with all the elements randomly shuffled. @@ -66,16 +66,16 @@ public default IList shuffle(Random rand) { } return w.done(); } - + /** * @return an IListWriter for the current list implementation */ @Override public IListWriter writer(); - + /** * Appends an element to the end of the list - * + * * @param e the new element * @return a new list with the element at the end */ @@ -86,7 +86,7 @@ default IList append(IValue e) { return w.done(); } - + /** * Inserts an element in front of the list * @param e the new element @@ -99,11 +99,11 @@ default IList insert(IValue e) { return w.done(); } - + /** * Concatenates this list with another * @param o another list - * @return a concatenated list with the elements of the + * @return a concatenated list with the elements of the * receiver before the elements of o. */ default IList concat(IList o) { @@ -112,7 +112,7 @@ default IList concat(IList o) { w.appendAll(o); return w.done(); } - + /** * Replaces the value of the ith element in the list with a new value * @param i index to replace a value at. @@ -127,7 +127,7 @@ public default IList put(int i, IValue e) { w.replaceAt(i, e); return w.done(); } - + /** * Replaces the value of the elements first, second ... end in the list with the elements in the list r * Expected: @@ -210,19 +210,19 @@ public default IList replace(int first, int second, int end, IList repl) { return result.done(); } - + /** * Return the ith element of the list. - * + * * @param i * @return the ith element of the list * @throws IndexOutOfBoundsException when i < 0 or i >= IList.length */ public IValue get(int i) throws IndexOutOfBoundsException; - + /** * Compute a sublist. - * + * * @param offset inclusive start index of the sublist * @param length number of elements in the resulting list * @return a new list that contains this[offset] until this[offset+length-1]. @@ -231,19 +231,19 @@ default IList sublist(int offset, int length) { if (offset < 0 || length < 0 || offset + length > length()) { throw new IndexOutOfBoundsException(); } - + IListWriter w = writer(); for (int i = offset; i < offset + length; i++) { w.append(get(i)); } return w.done(); } - + /** * @return true iff the list is non-empty */ public boolean isEmpty(); - + /** * @param e * @return true iff e is an element of the list @@ -256,7 +256,7 @@ public default boolean contains(IValue e) { } return false; } - + /** * Removes the first occurrence of an element, i.e. the * element with the lowest index that is present in the list, @@ -268,7 +268,7 @@ public default IList delete(IValue v) { IListWriter w = writer(); boolean deleted = false; - + for (IValue e : this) { if (!deleted && e.equals(v)) { deleted = true; // skip first occurrence @@ -281,7 +281,7 @@ public default IList delete(IValue v) { /** * Removes the element at index i. - * + * * @param i * @return a new list with one element removed. */ @@ -290,7 +290,7 @@ public default IList delete(int index) { int currentIndex = 0; boolean deleted = false; - + for (Iterator iterator = iterator(); iterator.hasNext(); currentIndex++) { IValue e = iterator.next(); @@ -302,10 +302,10 @@ public default IList delete(int index) { } return w.done(); } - + /** * Carthesian product of two lists. - * + * * @param l * @return a new list relation containing the product */ @@ -321,7 +321,7 @@ public default IList product(IList l) { return w.done(); } - + /** * Intersection of two lists * @param l @@ -338,7 +338,7 @@ public default IList intersect(IList l) { return w.done(); } - + /** * Difference of two lists * @param l @@ -355,13 +355,13 @@ public default IList subtract(IList l) { } return w.done(); } - + @Override public default boolean match(IValue other) { if (other == this) { return true; } - + if (other == null) { return false; } @@ -387,7 +387,7 @@ public default boolean match(IValue other) { return false; } - + /** * @return true if this list is a sublist of list l */ @@ -412,7 +412,7 @@ public default boolean defaultEquals(@Nullable Object other) { if (other == this) { return true; } - + if (other == null) { return false; } @@ -423,7 +423,7 @@ public default boolean defaultEquals(@Nullable Object other) { if (isEmpty() && list2.isEmpty()) { return true; } - + if (getType() != list2.getType()) return false; @@ -449,7 +449,7 @@ public default boolean defaultEquals(@Nullable Object other) { return false; } - + default int defaultHashCode() { int hash = 0; @@ -459,18 +459,18 @@ default int defaultHashCode() { return hash; } - + @Override default T accept(IValueVisitor v) throws E { return v.visitList(this); } - + @Override default IRelation asRelation() { if (!getType().isListRelation()) { throw new UnsupportedOperationException(getType() + " is not a relation"); } - + return new IRelation() { @Override public String toString() { @@ -481,11 +481,11 @@ public String toString() { public IList asContainer() { return IList.this; } - + @Override public IWriter writer() { - return IList.this.writer(); + return IList.this.writer(); } }; } -} \ No newline at end of file +} diff --git a/src/main/java/io/usethesource/vallang/IListWriter.java b/src/main/java/io/usethesource/vallang/IListWriter.java index 130ebf2b1..f51f41b07 100644 --- a/src/main/java/io/usethesource/vallang/IListWriter.java +++ b/src/main/java/io/usethesource/vallang/IListWriter.java @@ -18,46 +18,46 @@ * This interface allows to gather the elements of a list efficiently and in a specific order. * When all elements have been gathered the done() method can be used to obtain an immutable IList * with the gathered elements in the specified order. - * + * * Note: implementations are not required to guarantee thread-safe access to the writer object. */ public interface IListWriter extends IWriter { - + /** - * Inserts elements at a specific position, keeping the argument in order of appearance. - * - * @param index - * @param value an array of elements to insert . - * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. - * @throws IndexOutOfBoundsException - */ + * Inserts elements at a specific position, keeping the argument in order of appearance. + * + * @param index + * @param value an array of elements to insert . + * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. + * @throws IndexOutOfBoundsException + */ public void insertAt(int index, IValue... value); - + /** - * Inserts elements in front, keeping the argument in order of appearance. - * - * @param elems an array of elements to insert - * @param start index to start copying elements from - * @param length amount of elements to copy from the array - * - * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. - * @throws IndexOutOfBoundsException - */ + * Inserts elements in front, keeping the argument in order of appearance. + * + * @param elems an array of elements to insert + * @param start index to start copying elements from + * @param length amount of elements to copy from the array + * + * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. + * @throws IndexOutOfBoundsException + */ public void insert(IValue[] elems, int start, int length); - + /** - * Inserts elements at a specific position, keeping the argument in order of appearance. - * - * @param index place to insert elements at - * @param elems an array of elements to insert - * @param start index to start copying elements from - * @param length amount of elements to copy from the array - * - * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. - * @throws IndexOutOfBoundsException - */ + * Inserts elements at a specific position, keeping the argument in order of appearance. + * + * @param index place to insert elements at + * @param elems an array of elements to insert + * @param start index to start copying elements from + * @param length amount of elements to copy from the array + * + * @throws FactTypeUseException when done() was called before or when the elements have an incompatible type. + * @throws IndexOutOfBoundsException + */ public void insertAt(int index, IValue[] elems, int start, int length); - + /** * Replaces an existing element at index in the list. * @param index the location where to replace the element @@ -67,10 +67,10 @@ public interface IListWriter extends IWriter { * @returns the replaced element */ public IValue replaceAt(int index, IValue elem); - + /** * Return the ith element of the list. - * + * * @param i * @return the ith element of the list * @throws IndexOutOfBoundsException when i < 0 or i >= IList.length @@ -81,4 +81,4 @@ public interface IListWriter extends IWriter { * @return the number of elements in the list */ public int length(); -} +} diff --git a/src/main/java/io/usethesource/vallang/IMap.java b/src/main/java/io/usethesource/vallang/IMap.java index 5af85c1cd..b6f1180c7 100644 --- a/src/main/java/io/usethesource/vallang/IMap.java +++ b/src/main/java/io/usethesource/vallang/IMap.java @@ -8,7 +8,7 @@ * Contributors: * * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang; @@ -34,7 +34,7 @@ default int getMatchFingerprint() { /** * Adds a new entry to the map, mapping the key to value. If the * key existed before, the old value will be lost. - * @param key + * @param key * @param value * @return a copy of the map with the new key/value mapping */ @@ -44,10 +44,10 @@ public default IMap put(IValue key, IValue value) { sw.put(key, value); return sw.done(); } - + /** * Remove the values with the given key. - * + * * @param key * @return a map without entries that are isEqual to the key */ @@ -68,7 +68,7 @@ public default IMap put(IValue key, IValue value) { @EnsuresNonNullIf(expression="get(#1)", result=true) @SuppressWarnings({"contracts.conditional.postcondition"}) public boolean containsKey(IValue key); - + @EqualsMethod public default boolean defaultEquals(@Nullable Object other){ if (other == null) { @@ -93,21 +93,21 @@ public default boolean defaultEquals(@Nullable Object other){ if (size() == map2.size()) { outer:for (IValue k1 : map2) { - + // the loop might seem weird but due to the (deprecated) // semantics of node annotations we must check each element // for _deep_ equality. This is a big source of inefficiency // and one of the reasons why the semantics of annotations is // deprecated for "keyword parameters". - + for (IValue cursor : this) { if (cursor.equals(k1)) { // key was found, now check the value IValue val2 = map2.get(k1); - if (val2 != null && !val2.equals(get(k1))) { + if (val2 != null && !val2.equals(get(k1))) { return false; } - + continue outer; } } @@ -117,9 +117,9 @@ public default boolean defaultEquals(@Nullable Object other){ } } - return false; + return false; } - + public default int defaultHashCode() { int hash = 0; @@ -131,7 +131,7 @@ public default int defaultHashCode() { return hash; } - + @Override public default boolean match(IValue other) { if (other == this) { @@ -146,7 +146,7 @@ public default boolean match(IValue other) { IValue v1 = get(k1); assert v1 != null : "@AssumeAssertion(nullness)"; - + for (Iterator iterator = map2.iterator(); iterator.hasNext();) { IValue k2 = iterator.next(); if (k2.match(k1)) { @@ -164,16 +164,16 @@ public default boolean match(IValue other) { return false; // no matching key found for k1 } - return true; + return true; } } return false; } - + /** * Determine whether a certain value exists in this map. - * @param value + * @param value * @return true iff there is at least one key that maps to the given value. */ public default boolean containsValue(IValue value) { @@ -182,7 +182,7 @@ public default boolean containsValue(IValue value) { return true; } } - + return false; } @@ -192,14 +192,14 @@ public default boolean containsValue(IValue value) { public default Type getKeyType() { return getType().getKeyType(); } - + /** * @return the value type for this map */ public default Type getValueType() { return getType().getValueType(); } - + /** * Adds all key value pairs of the other map to this map (constructing a new one). * The values of the other map overwrite the values of this map. @@ -212,7 +212,7 @@ public default IMap join(IMap other) { sw.putAll(other); return sw.done(); } - + /** * Removes all key-value pairs from this map where a key exists in the other map. * @param other @@ -220,16 +220,16 @@ public default IMap join(IMap other) { */ public default IMap remove(IMap other) { IMapWriter sw = writer(); - + for (Entry entry : (Iterable>) () -> entryIterator()) { if (!other.containsKey(entry.getKey())) { sw.put(entry.getKey(), entry.getValue()); } } - + return sw.done(); } - + /** * If the value type of this map is a sub-type of the key type of the other, construct * a new map that represents the composition which maps keys of this map to values of @@ -249,15 +249,15 @@ public default IMap compose(IMap other) { return w.done(); } - + @Override public IMapWriter writer(); - + /** * Compute the common map (intersection) between this map and another. Any key-value * pair that is not present in the other will not be present in the result. This * means that if a key exists in both maps, but with a different value, the key - * will not be present in the result. + * will not be present in the result. * @param other * @return a new map containing the common pairs between the two maps. */ @@ -268,31 +268,31 @@ public default IMap common(IMap other) { IValue thisKey = entry.getKey(); IValue thisValue = entry.getValue(); IValue otherValue = other.get(thisKey); - + if (otherValue != null && thisValue.equals(otherValue)) { sw.put(thisKey, thisValue); } } - + return sw.done(); } - + /** - * Checks if the other map is defined for every key that is - * present in the receiver object. - * - * @param other - * @return true iff all for every key of the receiver there exists an entry - * in the other map. - */ + * Checks if the other map is defined for every key that is + * present in the receiver object. + * + * @param other + * @return true iff all for every key of the receiver there exists an entry + * in the other map. + */ public default boolean isSubMap(IMap other) { for (Entry entry : (Iterable>) () -> entryIterator()) { IValue key = entry.getKey(); - + if (!other.containsKey(key)) { return false; } - + if (!other.get(key).equals(entry.getValue())) { return false; } @@ -300,31 +300,31 @@ public default boolean isSubMap(IMap other) { return true; } - + /** * Repeated here for documentation purposes, this iterator * returns only the keys of the map, not its values. - * - * @return an iterator over the keys of the map + * + * @return an iterator over the keys of the map */ @Override public Iterator iterator(); - + /** * @return an iterator over the values of the map */ public Iterator valueIterator(); - + /** * @return an iterator over the keys-value pairs of the map */ public Iterator> entryIterator(); - + @Override default T accept(IValueVisitor v) throws E { return v.visitMap(this); } - + @Override /** * a map should stream key/value tuples diff --git a/src/main/java/io/usethesource/vallang/IMapWriter.java b/src/main/java/io/usethesource/vallang/IMapWriter.java index 96d51bbc2..98ebc20b7 100644 --- a/src/main/java/io/usethesource/vallang/IMapWriter.java +++ b/src/main/java/io/usethesource/vallang/IMapWriter.java @@ -28,7 +28,7 @@ public interface IMapWriter extends IWriter { * @throws FactTypeUseException */ void put(IValue key, IValue value); - + /** * Merge an entire map into the writer. Existing keys * will be overwritten by the new map @@ -36,7 +36,7 @@ public interface IMapWriter extends IWriter { * @throws FactTypeUseException */ void putAll(IMap map); - + /** * Merge an entire java.util.Map into the writer. Existing * keys will be overwritten by the new map. @@ -44,14 +44,14 @@ public interface IMapWriter extends IWriter { * @throws FactTypeUseException */ void putAll(Map map); - + /** * Lookup a given key into the state of the current map-to-be * @param key * @return null if no value exists with this key, otherwise the respective value. */ @Nullable IValue get(IValue key); - + /** * The map writer collects key/value tuples */ diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index 2d0afcf3c..b1cca5764 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) CWI 2008 +* Copyright (c) CWI 2008 * 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 @@ -25,63 +25,63 @@ /** - * Untyped node representation (a container that has a limited amount of children and a name), + * Untyped node representation (a container that has a limited amount of children and a name), * can iterate over the list of children. This data construct can be used to make trees by applying * it recursively. */ public interface INode extends IValue, Iterable { - @Override - default int getMatchFingerprint() { - int hash = getName().hashCode(); - - if (hash == 0) { - hash = 3386882 /* "node".hashCode() */; - } - - return hash + 131 * arity(); - } - - /** - * Get a child - * @param i the zero based index of the child - * @return a value - * @throws IndexOutOfBoundsException - */ - public IValue get(int i); - - /** - * Change this tree to have a different child at a certain position. - * - * @param i the zero based index of the child to be replaced - * @param newChild the new value for the child - * @return an untyped tree with the new child at position i, if the receiver was untyped, - * or a typed tree node if it was typed. - * @throws IndexOutOfBoundsException - */ - public INode set(int i, IValue newChild); - - /** - * @return the (fixed) number of children of this node (excluding keyword arguments) - */ - public int arity(); - - /** - * @return the name of this node (an identifier) - */ - public String getName(); - - /** - * @return an iterator over the direct children, equivalent to 'this'. - */ - public Iterable getChildren(); - - /** - * @return an iterator over the direct children. - */ - public Iterator iterator(); - - /** + @Override + default int getMatchFingerprint() { + int hash = getName().hashCode(); + + if (hash == 0) { + hash = 3386882 /* "node".hashCode() */; + } + + return hash + 131 * arity(); + } + + /** + * Get a child + * @param i the zero based index of the child + * @return a value + * @throws IndexOutOfBoundsException + */ + public IValue get(int i); + + /** + * Change this tree to have a different child at a certain position. + * + * @param i the zero based index of the child to be replaced + * @param newChild the new value for the child + * @return an untyped tree with the new child at position i, if the receiver was untyped, + * or a typed tree node if it was typed. + * @throws IndexOutOfBoundsException + */ + public INode set(int i, IValue newChild); + + /** + * @return the (fixed) number of children of this node (excluding keyword arguments) + */ + public int arity(); + + /** + * @return the name of this node (an identifier) + */ + public String getName(); + + /** + * @return an iterator over the direct children, equivalent to 'this'. + */ + public Iterable getChildren(); + + /** + * @return an iterator over the direct children. + */ + public Iterator iterator(); + + /** * Replaces the value of the children first, second ... end with the elements in the list r * Expected: * - support for negative indices @@ -94,111 +94,111 @@ default int getMatchFingerprint() { * @throws FactTypeUseException when the type of the element is not a subtype of the element type * @throws IndexOutOfBoundsException when the b < 0 or b >= INode.arity() or e < 0 or e > INOde.arity() */ - public default INode replace(int first, int second, int end, IList repl) { - ArrayList newChildren = new ArrayList<>(); - int rlen = repl.length(); - int increment = Math.abs(second - first); - if (first < end) { - int childIndex = 0; - // Before begin - while (childIndex < first) { - newChildren.add(this.get(childIndex++)); - } - int replIndex = 0; - boolean wrapped = false; - // Between begin and end - while (childIndex < end) { - newChildren.add(repl.get(replIndex++)); - if (replIndex == rlen) { - replIndex = 0; - wrapped = true; - } - childIndex++; //skip the replaced element - for (int j = 1; j < increment && childIndex < end; j++) { - newChildren.add(this.get(childIndex++)); - } - } - if (!wrapped) { - while (replIndex < rlen) { - newChildren.add(repl.get(replIndex++)); - } - } - // After end - int dlen = this.arity(); - while (childIndex < dlen) { - newChildren.add(this.get(childIndex++)); - } - } else { - // Before begin (from right to left) - int childIndex = this.arity() - 1; - while (childIndex > first) { - newChildren.add(0, this.get(childIndex--)); - } - // Between begin (right) and end (left) - int replIndex = 0; - boolean wrapped = false; - while (childIndex > end) { - newChildren.add(0, repl.get(replIndex++)); - if (replIndex == repl.length()) { - replIndex = 0; - wrapped = true; - } - childIndex--; //skip the replaced element - for (int j = 1; j < increment && childIndex > end; j++) { - newChildren.add(0, this.get(childIndex--)); - } - } - if (!wrapped) { - while (replIndex < rlen) { - newChildren.add(0, repl.get(replIndex++)); - } - } - // Left of end - while (childIndex >= 0) { - newChildren.add(0, this.get(childIndex--)); - } - } - - IValue[] childArray = new IValue[newChildren.size()]; - newChildren.toArray(childArray); - - return setChildren(childArray); - } - - /** - * Replace all children with a new array of children, keeping only - * the name of the original node. - * @param childArray - * @return a new node with the same name, yet new children. - */ - public INode setChildren(IValue[] childArray); + public default INode replace(int first, int second, int end, IList repl) { + ArrayList newChildren = new ArrayList<>(); + int rlen = repl.length(); + int increment = Math.abs(second - first); + if (first < end) { + int childIndex = 0; + // Before begin + while (childIndex < first) { + newChildren.add(this.get(childIndex++)); + } + int replIndex = 0; + boolean wrapped = false; + // Between begin and end + while (childIndex < end) { + newChildren.add(repl.get(replIndex++)); + if (replIndex == rlen) { + replIndex = 0; + wrapped = true; + } + childIndex++; //skip the replaced element + for (int j = 1; j < increment && childIndex < end; j++) { + newChildren.add(this.get(childIndex++)); + } + } + if (!wrapped) { + while (replIndex < rlen) { + newChildren.add(repl.get(replIndex++)); + } + } + // After end + int dlen = this.arity(); + while (childIndex < dlen) { + newChildren.add(this.get(childIndex++)); + } + } else { + // Before begin (from right to left) + int childIndex = this.arity() - 1; + while (childIndex > first) { + newChildren.add(0, this.get(childIndex--)); + } + // Between begin (right) and end (left) + int replIndex = 0; + boolean wrapped = false; + while (childIndex > end) { + newChildren.add(0, repl.get(replIndex++)); + if (replIndex == repl.length()) { + replIndex = 0; + wrapped = true; + } + childIndex--; //skip the replaced element + for (int j = 1; j < increment && childIndex > end; j++) { + newChildren.add(0, this.get(childIndex--)); + } + } + if (!wrapped) { + while (replIndex < rlen) { + newChildren.add(0, repl.get(replIndex++)); + } + } + // Left of end + while (childIndex >= 0) { + newChildren.add(0, this.get(childIndex--)); + } + } + + IValue[] childArray = new IValue[newChildren.size()]; + newChildren.toArray(childArray); + + return setChildren(childArray); + } + + /** + * Replace all children with a new array of children, keeping only + * the name of the original node. + * @param childArray + * @return a new node with the same name, yet new children. + */ + public INode setChildren(IValue[] childArray); @Override public default T accept(IValueVisitor v) throws E { - return v.visitNode(this); - } - + return v.visitNode(this); + } + @Override public default boolean mayHaveKeywordParameters() { - return true; + return true; } - + @Override public default IWithKeywordParameters asWithKeywordParameters() { - return new AbstractDefaultWithKeywordParameters(this, AbstractSpecialisedImmutableMap.mapOf()) { - @Override - protected INode wrap(INode content, Map.Immutable parameters) { - return new NodeWithKeywordParametersFacade(content, parameters); - } - }; + return new AbstractDefaultWithKeywordParameters(this, AbstractSpecialisedImmutableMap.mapOf()) { + @Override + protected INode wrap(INode content, Map.Immutable parameters) { + return new NodeWithKeywordParametersFacade(content, parameters); + } + }; } - + @Override public default boolean match(IValue value) { if(value == this) { return true; } - + if(value == null) { return false; } diff --git a/src/main/java/io/usethesource/vallang/INumber.java b/src/main/java/io/usethesource/vallang/INumber.java index 1d605ea32..7af65f9ba 100644 --- a/src/main/java/io/usethesource/vallang/INumber.java +++ b/src/main/java/io/usethesource/vallang/INumber.java @@ -11,27 +11,27 @@ package io.usethesource.vallang; public abstract interface INumber extends IValue { - /** - * Returns an integer if both arguments are integer, and a real otherwise - * @return this + other - */ + /** + * Returns an integer if both arguments are integer, and a real otherwise + * @return this + other + */ public INumber add(INumber other); - + /** - * @return this + other - */ + * @return this + other + */ public IReal add(IReal other); - + /** - * Returns an integer if both arguments are integer, and a real otherwise - * @return this + other - */ + * Returns an integer if both arguments are integer, and a real otherwise + * @return this + other + */ public INumber add(IInteger other); /** - * Returns a rational if both arguments are rationals or integers, and a real otherwise - * @return this + other - */ + * Returns a rational if both arguments are rationals or integers, and a real otherwise + * @return this + other + */ public INumber add(IRational other); /** @@ -39,18 +39,18 @@ public abstract interface INumber extends IValue { * @return this - other; */ public INumber subtract(INumber other); - + /** * @return this - other; */ public INumber subtract(IReal other); - + /** * Returns an integer if both arguments are integer, and a real otherwise * @return this - other; */ public INumber subtract(IInteger other); - + /** * @return this - other; */ @@ -61,12 +61,12 @@ public abstract interface INumber extends IValue { * @return this * other; */ public INumber multiply(INumber other); - + /** * @return this * other; */ public IReal multiply(IReal other); - + /** * Returns an integer if both arguments are integer, and a real otherwise * @return this * other; @@ -81,25 +81,25 @@ public abstract interface INumber extends IValue { /** * Integer division if both the receiver and the argument are integers, and real division otherwise - * @return this / other + * @return this / other */ public INumber divide(INumber other, int precision); - + /** - * @return this / other + * @return this / other */ public IReal divide(IReal other, int precision); - + /** * Integer division if both the receiver and the argument are integers, and real division otherwise - * @return this / other + * @return this / other */ public INumber divide(IInteger other, int precision); /** - * Rational division if both the receiver and the argument are integers/rationals, + * Rational division if both the receiver and the argument are integers/rationals, * real division otherwise - * @return this / other + * @return this / other */ public INumber divide(IRational other, int precision); @@ -108,13 +108,13 @@ public abstract interface INumber extends IValue { * @return -1 * this; */ public INumber negate(); - + /** * @param precision the precision of the result. This parameter may be ignored if another source of an accurate precision is available. * @return an IReal that is equal to this INumber */ public IReal toReal(int precision); - + /** * @return an IInteger (truncated if it was a real value) */ @@ -129,32 +129,32 @@ public abstract interface INumber extends IValue { * @return true iff the numbers are equal */ public IBool equal(INumber other); - + /** * @return true iff the numbers are equal */ public IBool equal(IInteger other); - + /** * @return true iff the numbers are equal */ public IBool equal(IReal other); - + /** * @return true iff the numbers are equal */ public IBool equal(IRational other); - + /** * @return true iff this < other */ public IBool less(INumber other); - + /** * @return true iff this < other */ public IBool less(IReal other); - + /** * @return true iff this < other */ @@ -169,12 +169,12 @@ public abstract interface INumber extends IValue { * @return true iff this > other */ public IBool greater(INumber other); - + /** * @return true iff this > other */ public IBool greater(IReal other); - + /** * @return true iff this > other */ @@ -189,12 +189,12 @@ public abstract interface INumber extends IValue { * @return true iff this <= other */ public IBool lessEqual(INumber other); - + /** * @return true iff this <= other */ public IBool lessEqual(IReal other); - + /** * @return true iff this <= other */ @@ -209,12 +209,12 @@ public abstract interface INumber extends IValue { * @return true iff this >= other */ public IBool greaterEqual(INumber other); - + /** * @return true iff this >= other */ public IBool greaterEqual(IReal other); - + /** * @return true iff this >= other */ @@ -224,20 +224,20 @@ public abstract interface INumber extends IValue { * @return true iff this >= other */ public IBool greaterEqual(IRational other); - + /** * Returns an integer if the receiver was an integer, and a real otherwise * @return absolute value of this number */ public INumber abs(); - - /** + + /** * Compares two numbers * @param other * @return -1 if receiver is less than other, 0 is receiver is equal, 1 if receiver is larger */ public int compare(INumber other); - + /** * @return return -1, 0 or 1 iff this integer is less than, equal to or greater than zero. */ diff --git a/src/main/java/io/usethesource/vallang/IRational.java b/src/main/java/io/usethesource/vallang/IRational.java index 4d8dd0c01..3960d15b8 100644 --- a/src/main/java/io/usethesource/vallang/IRational.java +++ b/src/main/java/io/usethesource/vallang/IRational.java @@ -14,46 +14,46 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IRational extends INumber { - /** - * @return this + other; - */ + /** + * @return this + other; + */ @Override public IRational add(IRational other); - + /** * @return this - other; */ @Override public IRational subtract(IRational other); - + /** * @return this * other; */ @Override public IRational multiply(IRational other); - + /** * @return this / other; */ public IRational divide(IRational other); - + /** * @return this / other; */ public IRational divide(IInteger other); - + /** * @return this rem other, which is the remainder after dividing this by other. * This may be a negative number. */ public IRational remainder(IRational other); - + /** * @return -1 * this; */ @Override public IRational negate(); - + /** * @return an IReal that approximates this IRational */ @@ -80,35 +80,35 @@ public interface IRational extends INumber { */ @Override public IBool less(IRational other); - + /** * @return true iff this > other */ @Override public IBool greater(IRational other); - + /** * @return true iff this <= other */ @Override public IBool lessEqual(IRational other); - + /** * @return true iff this >= other */ @Override public IBool greaterEqual(IRational other); - + /** * @return the value of the IRational represent as a string of decimal numbers in ASCII encoding. */ public String getStringRepresentation(); - + /** * @return The rational's numerator */ public IInteger numerator(); - + /** * @return The rational's denominator */ @@ -116,7 +116,7 @@ public interface IRational extends INumber { /** * numerator() == (toInteger() * denominator()) + remainder() - * + * * @return numerator() % denominator() */ public IInteger remainder(); @@ -127,7 +127,7 @@ public interface IRational extends INumber { * @return -1 if receiver is less than other, 0 is receiver is equal, 1 if receiver is larger */ public int compare(IRational other); - + /** * @return return -1, 0 or 1 iff this rational is less than, equal to or greater than zero. */ @@ -139,21 +139,21 @@ public interface IRational extends INumber { */ @Override public IRational abs(); - + /** * @return this number rounded down to the nearest integer number that is * less than this number. */ public IInteger floor(); - + /** * @return this number rounded to the nearest integer number. */ public IInteger round(); - + @Override default T accept(IValueVisitor v) throws E { return v.visitRational(this); } - + } diff --git a/src/main/java/io/usethesource/vallang/IReal.java b/src/main/java/io/usethesource/vallang/IReal.java index b22352382..78bd852cc 100644 --- a/src/main/java/io/usethesource/vallang/IReal.java +++ b/src/main/java/io/usethesource/vallang/IReal.java @@ -22,91 +22,91 @@ default int getMatchFingerprint() { return hash == 0 ? 3496350 /* "real".hashCode() */ : hash; } - /** - * @return this + other; - */ + /** + * @return this + other; + */ @Override public IReal add(IReal other); - + /** * @return this - other; */ @Override public IReal subtract(IReal other); - + /** * @return this * other; */ @Override public IReal multiply(IReal other); - + /** * Divides a real with a specific precision - * + * * @return this / other; */ @Override public IReal divide(IReal other, int precision); - + /** * @return this number rounded down to the nearest integer number that is * less than this number. */ public IReal floor(); - + /** * @return this number rounded to the nearest integer number. */ public IReal round(); - + /** * @return the integer value nearest to this number */ @Override public IInteger toInteger(); - + /** * @return true iff this < other */ @Override public IBool less(IReal other); - + /** * @return true iff this > other */ @Override public IBool greater(IReal other); - + /** * @return true iff this <= other */ @Override public IBool lessEqual(IReal other); - + /** * @return true iff this >= other */ @Override public IBool greaterEqual(IReal other); - + /** * @return this real represented as a string of decimal characters in scientific notation */ public String getStringRepresentation(); - + /** * @return -1 * this */ @Override public IReal negate(); - + /** * Compares two doubles * @param other * @return -1 if receiver is less than other, 0 is receiver is equal, 1 if receiver is larger */ public int compare(IReal other); - + /** * Converts this IReal to a double. Precision may be less. * If the number does not fit, it will return @@ -122,24 +122,24 @@ default int getMatchFingerprint() { * when the number is smaller or larger, respectively. */ public float floatValue(); - + /** * @return the number of digits in this.{@link #unscaled()} */ public int precision(); - + /** * The scale is the exponent of 10 with which the base is multiplied * as in scientific notation. I.e. in 1 * 103, the scale is 3. - * + * * @return the scale of the real */ public int scale(); - + /** * Returns the unscaled value of this real as an integer. This is useful * for serialization purposes among other things. - * + * * @return this * 10this.scale() */ public IInteger unscaled(); @@ -150,65 +150,65 @@ default int getMatchFingerprint() { @Override public IReal abs(); - /** - * @return logbase(this) - */ + /** + * @return logbase(this) + */ public IReal log(IInteger base, int precision); - - /** - * @return logbase(this) - */ - public IReal log(IReal base, int precision); - - /** - * @return natural log of this - */ - public IReal ln(int precision); - - /** - * @return square root of this - */ - public IReal sqrt(int precision); - - /** - * @return n-th root of this - */ - public IReal nroot(IInteger n, int precision); - - /** - * @return ethis - */ - public IReal exp(int precision); - - /** - * @return thispower - */ - public IReal pow(IInteger power); - - /** - * @return thispower but for non natural numbers - */ - public IReal pow(IReal power, int precision); - - /** - * @return tan(this) - */ - public IReal tan(int precision); - - /** - * @return sin(this) - */ - public IReal sin(int precision); - - /** - * @return cos(this) - */ - - public IReal cos(int precision); - - @Override - default T accept(IValueVisitor v) throws E { - return v.visitReal(this); - } + + /** + * @return logbase(this) + */ + public IReal log(IReal base, int precision); + + /** + * @return natural log of this + */ + public IReal ln(int precision); + + /** + * @return square root of this + */ + public IReal sqrt(int precision); + + /** + * @return n-th root of this + */ + public IReal nroot(IInteger n, int precision); + + /** + * @return ethis + */ + public IReal exp(int precision); + + /** + * @return thispower + */ + public IReal pow(IInteger power); + + /** + * @return thispower but for non natural numbers + */ + public IReal pow(IReal power, int precision); + + /** + * @return tan(this) + */ + public IReal tan(int precision); + + /** + * @return sin(this) + */ + public IReal sin(int precision); + + /** + * @return cos(this) + */ + + public IReal cos(int precision); + + @Override + default T accept(IValueVisitor v) throws E { + return v.visitReal(this); + } } diff --git a/src/main/java/io/usethesource/vallang/IRelation.java b/src/main/java/io/usethesource/vallang/IRelation.java index 834a37d90..f3d87c9aa 100644 --- a/src/main/java/io/usethesource/vallang/IRelation.java +++ b/src/main/java/io/usethesource/vallang/IRelation.java @@ -1,252 +1,252 @@ -/******************************************************************************* -* Copyright (c) 2019 NWO-I 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 - initial implementation -*******************************************************************************/ -package io.usethesource.vallang; - -import java.util.Iterator; -import java.util.function.Function; - -import io.usethesource.vallang.exceptions.IllegalOperationException; -import io.usethesource.vallang.type.Type; - -/** - * Provides Relational Calculus operators to an existing ICollection. - * This interface provides a generic implementation for all operators, - * which should be specialized by implementations that know how to optimize - * these operations with specialized data-structures. - * - * @param a collection value type like ISet or IList - */ -public interface IRelation> extends Iterable { - - @Override - default Iterator iterator() { - return asContainer().iterator(); - } - - /** - * Relational composition works only on binary relations. It matches the second column - * of the receiver with the first column of the given relation. - * TODO: generalize to n-ary. Implementing classes should specialize - * this generic implementation for more efficiency. - * - * @param that is the given relation - * @return a new binary relation with first column of the accepting relation and the second column - * of the given relation, containing only tuples where the last column of the receiver - * matches the first column of the given relation. - */ - public default C compose(IRelation that) { - C thisContainer = this.asContainer(); - C thatContainer = that.asContainer(); - Type thisElementType = thisContainer.getElementType(); - Type thatElementType = thatContainer.getElementType(); - - if (thisElementType.isBottom()) { - return thisContainer; - } - - if (thatElementType.isBottom()) { - return thatContainer; - } - - if (thisElementType.getArity() != 2 || thatElementType.getArity() != 2) { - throw new IllegalOperationException("Incompatible types for composition.", thisElementType, thatElementType); - } - - if (!thisElementType.getFieldType(1).comparable(thatElementType.getFieldType(0))) { - return asContainer().empty(); - } - - IWriter w = writer(); - - for (IValue elem1 : this) { - ITuple tuple1 = (ITuple) elem1; - for (IValue elem2 : that) { - ITuple tuple2 = (ITuple) elem2; - if (tuple1.get(1).equals(tuple2.get(0))) { - w.appendTuple(tuple1.get(0), tuple2.get(1)); - } - } - } - - return w.done(); - } - - /** - * @return the transitive non-reflexive closure of a binary relation - * @throws UnsupportedOperationException when the receiver is not a binary relation - */ - public default C closure() { - if (!isBinary()) { - throw new UnsupportedOperationException("relation is not binary"); - } - - C next = this.asContainer(); - IRelation result; - - do { - result = next.asRelation(); - next = result.compose(result).union(next); - } while (!next.equals(result.asContainer())); - - return next; - } - - /** - * @return the transitive reflexive closure of a binary relation - * @throws UnsupportedOperationException when the receiver is not a binary relation - */ - public default C closureStar() { - IWriter w = writer(); - - for (IValue val : carrier()) { - w.appendTuple(val, val); - } - w.appendAll(closure()); - - return w.done(); - } - - /** - * @return the number of columns in the relation - */ - default int arity() { - return asContainer().getElementType().getArity(); - } - - /** - * @return a new empty relation with the current factory - */ - default C empty() { - return asContainer().empty(); - } - - /** - * Reduces an n-ary relation to fewer columns, given by the fields to select. - * @param fields to select from the relation, index starts at 0 - * @return a new relation with only the columns selected by the fields parameter - */ - default C project(int... fields) { - IWriter w = writer(); - - for (IValue v : this) { - w.append(((ITuple) v).select(fields)); - } - - return w.done(); - } - - /** - * Compute the carrier set of an n-ary relation. - * @return a container with all the elements of all tuples in the relation. - */ - public default C carrier() { - IWriter w = writer().unique(); - - for (IValue t : this) { - w.appendAll((ITuple) t); - } - - return w.done(); - } - - /** - * @return a container with the first elements of all tuples in the relation - */ - public default C domain() { - IWriter w = asContainer().writer(); - - for (IValue elem : this) { - w.insert(((ITuple) elem).get(0)); - } - - return w.done(); - } - - /** - * @return a container with the last elements of all tuples in the relation - */ - public default C range() { - int columnIndex = arity() - 1; - IWriter w = writer(); - - for (IValue elem : this) { - w.insert(((ITuple) elem).get(columnIndex)); - } - - return w.done(); - } - - /** - * Lookup the values by the first column in the relation - * @return a set of the second elements of all tuples where the first column is - * equal to the given key, without the first column. - * - * TODO: generalize to producing n-ary tuples. - */ - public default C index(IValue key) { - C set1 = asContainer(); - Type elementType = getElementType(); - - if (elementType.isBottom()) { - return set1.empty(); - } - - int valueArity = elementType.getArity() - 1; - - Function mapper; - if (valueArity == 0) { - mapper = t -> t.get(1); - } - else { - int[] newTupleIndex = new int[valueArity]; - for (int k = 1; k <= valueArity; k++) { - newTupleIndex[k - 1] = k; - } - mapper = t -> t.select(newTupleIndex); - } - - IWriter result = writer(); - for (IValue val : this) { - ITuple tup = (ITuple) val; - if (tup.get(0).equals(key)) { - result.insert(mapper.apply(tup)); - } - } - - return result.done(); - } - - /** - * @return the original container this IRelation is wrapping. - */ - public C asContainer(); - - /** - * @return a fresh writer for the kind of container this IRelation is wrapping - */ - public default IWriter writer() { - return asContainer().writer(); - } - - /** - * @return the element type of the container this IRelation is wrapping - */ - public default Type getElementType() { - return asContainer().getElementType(); - } - - /** - * @return true iff the current relation is binary (has two columns) - */ - default boolean isBinary() { - return getElementType().isBottom() || getElementType().getArity() == 2; - } -} +/******************************************************************************* +* Copyright (c) 2019 NWO-I 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 - initial implementation +*******************************************************************************/ +package io.usethesource.vallang; + +import java.util.Iterator; +import java.util.function.Function; + +import io.usethesource.vallang.exceptions.IllegalOperationException; +import io.usethesource.vallang.type.Type; + +/** + * Provides Relational Calculus operators to an existing ICollection. + * This interface provides a generic implementation for all operators, + * which should be specialized by implementations that know how to optimize + * these operations with specialized data-structures. + * + * @param a collection value type like ISet or IList + */ +public interface IRelation> extends Iterable { + + @Override + default Iterator iterator() { + return asContainer().iterator(); + } + + /** + * Relational composition works only on binary relations. It matches the second column + * of the receiver with the first column of the given relation. + * TODO: generalize to n-ary. Implementing classes should specialize + * this generic implementation for more efficiency. + * + * @param that is the given relation + * @return a new binary relation with first column of the accepting relation and the second column + * of the given relation, containing only tuples where the last column of the receiver + * matches the first column of the given relation. + */ + public default C compose(IRelation that) { + C thisContainer = this.asContainer(); + C thatContainer = that.asContainer(); + Type thisElementType = thisContainer.getElementType(); + Type thatElementType = thatContainer.getElementType(); + + if (thisElementType.isBottom()) { + return thisContainer; + } + + if (thatElementType.isBottom()) { + return thatContainer; + } + + if (thisElementType.getArity() != 2 || thatElementType.getArity() != 2) { + throw new IllegalOperationException("Incompatible types for composition.", thisElementType, thatElementType); + } + + if (!thisElementType.getFieldType(1).comparable(thatElementType.getFieldType(0))) { + return asContainer().empty(); + } + + IWriter w = writer(); + + for (IValue elem1 : this) { + ITuple tuple1 = (ITuple) elem1; + for (IValue elem2 : that) { + ITuple tuple2 = (ITuple) elem2; + if (tuple1.get(1).equals(tuple2.get(0))) { + w.appendTuple(tuple1.get(0), tuple2.get(1)); + } + } + } + + return w.done(); + } + + /** + * @return the transitive non-reflexive closure of a binary relation + * @throws UnsupportedOperationException when the receiver is not a binary relation + */ + public default C closure() { + if (!isBinary()) { + throw new UnsupportedOperationException("relation is not binary"); + } + + C next = this.asContainer(); + IRelation result; + + do { + result = next.asRelation(); + next = result.compose(result).union(next); + } while (!next.equals(result.asContainer())); + + return next; + } + + /** + * @return the transitive reflexive closure of a binary relation + * @throws UnsupportedOperationException when the receiver is not a binary relation + */ + public default C closureStar() { + IWriter w = writer(); + + for (IValue val : carrier()) { + w.appendTuple(val, val); + } + w.appendAll(closure()); + + return w.done(); + } + + /** + * @return the number of columns in the relation + */ + default int arity() { + return asContainer().getElementType().getArity(); + } + + /** + * @return a new empty relation with the current factory + */ + default C empty() { + return asContainer().empty(); + } + + /** + * Reduces an n-ary relation to fewer columns, given by the fields to select. + * @param fields to select from the relation, index starts at 0 + * @return a new relation with only the columns selected by the fields parameter + */ + default C project(int... fields) { + IWriter w = writer(); + + for (IValue v : this) { + w.append(((ITuple) v).select(fields)); + } + + return w.done(); + } + + /** + * Compute the carrier set of an n-ary relation. + * @return a container with all the elements of all tuples in the relation. + */ + public default C carrier() { + IWriter w = writer().unique(); + + for (IValue t : this) { + w.appendAll((ITuple) t); + } + + return w.done(); + } + + /** + * @return a container with the first elements of all tuples in the relation + */ + public default C domain() { + IWriter w = asContainer().writer(); + + for (IValue elem : this) { + w.insert(((ITuple) elem).get(0)); + } + + return w.done(); + } + + /** + * @return a container with the last elements of all tuples in the relation + */ + public default C range() { + int columnIndex = arity() - 1; + IWriter w = writer(); + + for (IValue elem : this) { + w.insert(((ITuple) elem).get(columnIndex)); + } + + return w.done(); + } + + /** + * Lookup the values by the first column in the relation + * @return a set of the second elements of all tuples where the first column is + * equal to the given key, without the first column. + * + * TODO: generalize to producing n-ary tuples. + */ + public default C index(IValue key) { + C set1 = asContainer(); + Type elementType = getElementType(); + + if (elementType.isBottom()) { + return set1.empty(); + } + + int valueArity = elementType.getArity() - 1; + + Function mapper; + if (valueArity == 0) { + mapper = t -> t.get(1); + } + else { + int[] newTupleIndex = new int[valueArity]; + for (int k = 1; k <= valueArity; k++) { + newTupleIndex[k - 1] = k; + } + mapper = t -> t.select(newTupleIndex); + } + + IWriter result = writer(); + for (IValue val : this) { + ITuple tup = (ITuple) val; + if (tup.get(0).equals(key)) { + result.insert(mapper.apply(tup)); + } + } + + return result.done(); + } + + /** + * @return the original container this IRelation is wrapping. + */ + public C asContainer(); + + /** + * @return a fresh writer for the kind of container this IRelation is wrapping + */ + public default IWriter writer() { + return asContainer().writer(); + } + + /** + * @return the element type of the container this IRelation is wrapping + */ + public default Type getElementType() { + return asContainer().getElementType(); + } + + /** + * @return true iff the current relation is binary (has two columns) + */ + default boolean isBinary() { + return getElementType().isBottom() || getElementType().getArity() == 2; + } +} diff --git a/src/main/java/io/usethesource/vallang/ISet.java b/src/main/java/io/usethesource/vallang/ISet.java index 851585369..7b3aba3c4 100644 --- a/src/main/java/io/usethesource/vallang/ISet.java +++ b/src/main/java/io/usethesource/vallang/ISet.java @@ -20,14 +20,14 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface ISet extends ICollection { - + @Override default int getMatchFingerprint() { return 113762; // "set".hashCode() } /** - * Add an element to the set. + * Add an element to the set. * @param element * @return a relation if the element type is a tuple type, a set otherwise */ @@ -58,7 +58,7 @@ public default ISet delete(IValue elem) { } return w.done(); } - + /** * Computes the Cartesian product of two sets * @param set @@ -76,13 +76,13 @@ public default ISet product(ISet that) { return w.done(); } - + @Override public default boolean match(IValue other) { if (other == this) { return true; } - + if (other == null) { return false; } @@ -105,7 +105,7 @@ public default boolean match(IValue other) { return false; } - + /** * Compute the union of two sets. To be overridden * by implementations who know how to do this more efficiently. @@ -130,7 +130,7 @@ public default ISet union(ISet that) { w.insertAll(that); return w.done(); } - + /** * Compute the intersection of two sets. To be overridden * by implementations who know how to do this more efficiently. @@ -159,7 +159,7 @@ public default ISet intersect(ISet that) { return w.done(); } - + /** * Compute the difference of two sets by removing the elements of `that` * from the receiver. To be implemented more efficiently if possible @@ -188,13 +188,13 @@ public default ISet subtract(ISet that) { return sw.done(); } - + /** * @param element * @return true if this is an element of the set */ public boolean contains(IValue e); - + /** * @param element * @return true if this set contains an element that matches (IValue.match) an element in this set @@ -207,7 +207,7 @@ public default boolean containsMatch(IValue e) { } return false; } - + /** * @param that other set to check for subset relation * @return true if all elements of this set are elements of the other. @@ -235,13 +235,13 @@ public default int defaultHashCode() { return hash; } - + @EqualsMethod public default boolean defaultEquals(@Nullable Object that) { if (that == this) { return true; } - + if (that == null) { return false; } @@ -270,23 +270,23 @@ public default boolean defaultEquals(@Nullable Object that) { return false; } - + @Override default T accept(IValueVisitor v) throws E { return v.visitSet(this); } - + @Override default IRelation asRelation() { if (!getType().isRelation()) { throw new UnsupportedOperationException(getType() + " is not a relation"); } - + return new IRelation() { @Override public String toString() { return ISet.this.toString(); - } + } @Override public ISet asContainer() { diff --git a/src/main/java/io/usethesource/vallang/ISourceLocation.java b/src/main/java/io/usethesource/vallang/ISourceLocation.java index 9e677b9b3..828697bd1 100644 --- a/src/main/java/io/usethesource/vallang/ISourceLocation.java +++ b/src/main/java/io/usethesource/vallang/ISourceLocation.java @@ -22,82 +22,82 @@ *
* The part of the file is indicated by a character offset and length, as well as a * line and column region. The reason for the redundancy is that each representation - * can not be computed from the other without processing the entire file. + * can not be computed from the other without processing the entire file. * The goal of this representation is to allow different kinds and implementations - * of tools, such as editors, to easily jump to source locations. + * of tools, such as editors, to easily jump to source locations. */ public interface ISourceLocation extends IValue { - /** - * The {@link #top() top} method is preferred. - * @return exact url where the source is located. The particular encoding of - * the URL is not specified. - */ + /** + * The {@link #top() top} method is preferred. + * @return exact url where the source is located. The particular encoding of + * the URL is not specified. + */ public URI getURI(); /** * @return the scheme of the URI */ public String getScheme(); - + /** * @return the authority of the URI or "" if it does not exist */ - public String getAuthority(); - - /** - * @return the path of the URI or "" if it does not exist - */ - public String getPath(); - - /** - * @return the fragment of the URI or "" if it does not exist - */ - public String getFragment(); - - /** - * @return the query part of the URI or "" if it does not exist - */ - public String getQuery(); - - /** - * @return true iff the URI has an authority part - */ - public boolean hasAuthority(); - - /** + public String getAuthority(); + + /** + * @return the path of the URI or "" if it does not exist + */ + public String getPath(); + + /** + * @return the fragment of the URI or "" if it does not exist + */ + public String getFragment(); + + /** + * @return the query part of the URI or "" if it does not exist + */ + public String getQuery(); + + /** + * @return true iff the URI has an authority part + */ + public boolean hasAuthority(); + + /** * @return true iff the URI has an path part */ - public boolean hasPath(); - - /** + public boolean hasPath(); + + /** * @return true iff the URI has an fragment part */ - public boolean hasFragment(); - - /** + public boolean hasFragment(); + + /** * @return true iff the URI has a query part */ - public boolean hasQuery(); - - + public boolean hasQuery(); + + /** * @return true iff the source location has offset/length information stored with it. */ public boolean hasOffsetLength(); - + /** - * @return true iff the source location has start/end line/column info. true implies that hasOffsetLength() will also + * @return true iff the source location has start/end line/column info. true implies that hasOffsetLength() will also * return true. */ public boolean hasLineColumn(); - + /** - * @return the character offset starting from the beginning of the file located + * @return the character offset starting from the beginning of the file located * at the given url. Offsets start at 0 (zero). * @throws UnsupportedOperationException */ public int getOffset(); - + /** * @return the character length of the location (the amount characters). * @throws UnsupportedOperationException @@ -110,7 +110,7 @@ public interface ISourceLocation extends IValue { * @throws UnsupportedOperationException */ public int getBeginLine(); - + /** * @return the (exclusive) line where the location ends * @throws UnsupportedOperationException @@ -123,7 +123,7 @@ public interface ISourceLocation extends IValue { * @throws UnsupportedOperationException */ public int getBeginColumn(); - + /** * @return the (exclusive) column number where the location ends. * @throws UnsupportedOperationException @@ -134,7 +134,7 @@ public interface ISourceLocation extends IValue { * @return the source location without any offset & length information. */ public ISourceLocation top(); - + @Override default T accept(IValueVisitor v) throws E { return v.visitSourceLocation(this); diff --git a/src/main/java/io/usethesource/vallang/IString.java b/src/main/java/io/usethesource/vallang/IString.java index 924790be7..cee3ef897 100644 --- a/src/main/java/io/usethesource/vallang/IString.java +++ b/src/main/java/io/usethesource/vallang/IString.java @@ -30,56 +30,56 @@ default int getMatchFingerprint() { } } - /** - * @return the Java string that this string represents - */ + /** + * @return the Java string that this string represents + */ public String getValue(); - + /** * Concatenates two strings */ public IString concat(IString other); - + /** * Reverses a string */ public IString reverse(); /** - * Computes the length of the string - * @return amount of Unicode characters + * Computes the length of the string + * @return amount of Unicode characters */ public int length(); - + /** * Computes a substring - * + * * @param start the inclusive start index * @param end the exclusive end index */ public IString substring(int start, int end); - + /** * Computes a substring - * + * * @param start the inclusive start index */ public IString substring(int start); - + /** * Compares two strings lexicographically * @param other * @return -1 if receiver is less than other, 0 is receiver is equal, 1 if receiver is larger */ public int compare(IString other); - + /** * Returns the Unicode character at the given index. * @param index an index into the string * @return the Unicode character (in UTF-32) */ public int charAt(int index); - + /** * Replace the characters first, second ... end. * Expected: @@ -87,38 +87,38 @@ default int getMatchFingerprint() { * - support for the case begin > end * @param first inclusive index of first element * @param second index of second element - * @param end exclusive end index - * @param repl the replacement string + * @param end exclusive end index + * @param repl the replacement string * @param start the inclusive start index * @return */ public IString replace(int first, int second, int end, IString repl); - + /** * Writes (in a streaming fashion) the content of this string to a character writer. */ public void write(Writer w) throws IOException; - + /** * Build an iterator which generates the Unicode UTF-32 codepoints of the IString one-by-one. * @see Character for more information on Unicode UTF-32 codepoints. */ @Override public OfInt iterator(); - - /** + + /** * Indent all the non-empty lines in this string with the given whitespace. That means that * after every newline character which is not immediately followed by another newline character - * or the end of string, the whitespace string is inserted into the string. - * + * or the end of string, the whitespace string is inserted into the string. + * * Implementations of IString should ensure that indent itself is in O(1) and the constructed string - * will {@link #write(Writer)} in O(n) where n is the length of the string. + * will {@link #write(Writer)} in O(n) where n is the length of the string. * @param whiteSpace a non-empty string which certainly does not contain any \n characters, and expectedly only whitespace characters such as spaces and tabs - * @param indentFirstLine indicates whether or not to indent the first line of the string. If true the line will be indented. + * @param indentFirstLine indicates whether or not to indent the first line of the string. If true the line will be indented. * @return the current string indented with the given whitespace */ public IString indent(IString whitespace, boolean indentFirstLine); - + @Override default T accept(IValueVisitor v) throws E { return v.visitString(this); diff --git a/src/main/java/io/usethesource/vallang/ITuple.java b/src/main/java/io/usethesource/vallang/ITuple.java index 37b715ce1..4d61d967a 100644 --- a/src/main/java/io/usethesource/vallang/ITuple.java +++ b/src/main/java/io/usethesource/vallang/ITuple.java @@ -23,46 +23,46 @@ default int getMatchFingerprint() { /** * Retrieve the given field at the given index. - * + * * @param i the index of the field, starting at 0 * @return the value at the given label in the tuple * @throws IndexOutOfBoundsException */ public IValue get(int i); - + @Deprecated /** * Retrieve the given field at the given label. - * + * * @param label the name of the field * @return the value at the given label in the tuple - * - * TODO: this method will dissappear when field names will no longer be recorded + * + * TODO: this method will dissappear when field names will no longer be recorded * the vallang library. This is necessary to be able to provide canonical types * and use reference equality for type equality; a major factor in CPU performance. */ public IValue get(String label); - + /** * Replace the given field by a new value. - * + * * @param i the index of the field * @param arg the new value * @return * @throws IndexOutOfBoundsException */ public ITuple set(int i, IValue arg); - + @Deprecated /** * Replace the given field by a new value. - * + * * @param label the name of the field * @param arg the new value * @return * @throws FactTypeUseException - * - * TODO: this method will dissappear when field names will no longer be recorded + * + * TODO: this method will dissappear when field names will no longer be recorded * the vallang library. This is necessary to be able to provide canonical types * and use reference equality for type equality; a major factor in CPU performance. */ @@ -79,19 +79,19 @@ default int getMatchFingerprint() { * @return a new tuple with only the fields selected by the fields parameter */ public IValue select(int... fields) throws IndexOutOfBoundsException; - + @Deprecated /** * Reduces an n-ary tuple to fewer fields, given by the field names to select. * @param fields to select from the tuple * @return a new tuple with only the fields selected by the fields parameter - * - * TODO: this method will dissappear when field names will no longer be recorded + * + * TODO: this method will dissappear when field names will no longer be recorded * the vallang library. This is necessary to be able to provide canonical types * and use reference equality for type equality; a major factor in CPU performance. */ public IValue selectByFieldNames(String... fields) throws FactTypeUseException; - + @Override public default boolean match(IValue o) { if (this == o) { @@ -118,7 +118,7 @@ public default boolean match(IValue o) { } return false; } - + @Override default T accept(IValueVisitor v) throws E { return v.visitTuple(this); diff --git a/src/main/java/io/usethesource/vallang/IValue.java b/src/main/java/io/usethesource/vallang/IValue.java index ba4674b51..b615a55f6 100644 --- a/src/main/java/io/usethesource/vallang/IValue.java +++ b/src/main/java/io/usethesource/vallang/IValue.java @@ -23,10 +23,10 @@ public interface IValue { public static final TypeFactory TF = TypeFactory.getInstance(); - - /** - * @return the {@link Type} of a value - */ + + /** + * @return the {@link Type} of a value + */ public Type getType(); /** @@ -34,7 +34,7 @@ public interface IValue { * or by the Rascal interpreter. The returned integer codes are opaque, although stable. * If you need to know what kind of value you have, use the IValueVisitor or the ITypeVisitor * interfaces and the `accept` methods on IValue and Type. - * + * * @return an integer code that: * * accurate reflects the identity of the top-level structure of this value * * such that if pattern.match(this) ===> pattern.getPatternMatchFingerprint() == this.getPatternMatchFingerprint() @@ -44,10 +44,10 @@ public interface IValue { default int getMatchFingerprint() { return hashCode(); } - + /** * This method is used exclusively by code generated by the Rascal compiler, - * + * * @return an integer code that: * * is guaranteed to be different from `getMatchFingerPrint` * * is guaranteed to be constant @@ -59,84 +59,84 @@ static int getDefaultMatchFingerprint() { /** * Execute the {@link IValueVisitor} on the current node - * + * * @param v the visitor to dispatch to */ public T accept(IValueVisitor v) throws E; - + /** * This method computes logical equality between IValues. That means that it - * may equalize objects implemented by different classes implementing the + * may equalize objects implemented by different classes implementing the * same interface. It does uphold Java's equals/hashCode contract, nevertheless. - * + * *

In particular, lazy intermediate representations of IList, ISet or IString would * lead to IValue objects being equal even though their internal structure differs greatly. * Implementors should think hard how to uphold equals/hashCode contract in such cases.

- * + * *

A note on subtitutability: given that IValue's are immutable, and this equals method * implements an equivalence relation and that it upholds the hashCode/equals contract: * if equals(a,b) then a is substitutable for b and vice versa in _any_ context. This implies - * full referential transparancy as well.

- * + * full referential transparancy as well.

+ * *

On the computational complexity of equals: although equality is worst case linear, - * implementations are expected to fail fast, and succeed fast. In particular the implementations - * based on persistent and shared data-structures are expected to test for reference equality at every - * level in a value. The expected/average complexity of equals should be around log(size), as a result.

- * + * implementations are expected to fail fast, and succeed fast. In particular the implementations + * based on persistent and shared data-structures are expected to test for reference equality at every + * level in a value. The expected/average complexity of equals should be around log(size), as a result.

+ * * @param other object to compare to * @return true iff the other value is logically equal to the receiver object */ @Override public boolean equals(@Nullable Object other); - + /** * Another notion of equality which ignores secondary information: - * namely, keyword parameters (either top-level or deeply nested). - * + * namely, keyword parameters (either top-level or deeply nested). + * *

The intention is for this notion of equality to match what the notion of pattern * matching is in the Rascal language. In this case the receiver acts * as a "pattern" for the argument.

- * + * *

The following theories hold: - * + * *

  • . a.equals(b) ==> a.match(b) // and not the inverse
  • *
  • match() is an equivalence relation
*

- * + * *

Note that the match() algorithm is linear in the size of the smallest of the * two values, but implementations are expected to fail fast and succeed fast where * possible (checking for reference equality on the way).

- * + * * @param other value to compare to * @return true iff the other value is equal to the other value, while - * ignoring all "non-structural" details such the presence of keyword + * ignoring all "non-structural" details such the presence of keyword * parameters. */ public default boolean match(IValue other) { return equals(other); } - + /** * Prints the value to a string using the {@link StandardTextWriter} */ public String toString(); - + /** * @return if this {@link IValue} object may have keyword parameters */ public default boolean mayHaveKeywordParameters() { return false; } - + /** - * Creates a view that exposes the {@link IWithKeywordParameters} annotation API. - * - * @return an {@link IWithKeywordParameters} view on this {@link IValue} object + * Creates a view that exposes the {@link IWithKeywordParameters} annotation API. + * + * @return an {@link IWithKeywordParameters} view on this {@link IValue} object */ public default IWithKeywordParameters asWithKeywordParameters() { throw new UnsupportedOperationException(getType() + " does not support keyword parameters."); } - + /** * This is how all IValue implementations should be printed. * @return the literal expression format of the value as a string diff --git a/src/main/java/io/usethesource/vallang/IValueFactory.java b/src/main/java/io/usethesource/vallang/IValueFactory.java index f126af417..1653b8614 100644 --- a/src/main/java/io/usethesource/vallang/IValueFactory.java +++ b/src/main/java/io/usethesource/vallang/IValueFactory.java @@ -26,607 +26,607 @@ * class should guarantee that the values returned are immutable. For batch * construction of container classes there should be implementations of the * I{List,Set,Relation,Map}Writer interfaces. - * + * * @author jurgen@vinju.org * @author rfuhrer@watson.ibm.com - * + * */ public interface IValueFactory { - /** - * Constructs an integer from the decimal representation. - * - * @param i - * integer as a string of decimal digits - * @return a new integer - * @throws NumberFormatException - */ - public IInteger integer(String i) throws NumberFormatException; - - /** - * @param i - * @return a value representing the integer i, with type IntegerType - */ - public IInteger integer(int i); - - /** - * @param i - * @return a value representing the integer i, with type IntegerType - */ - public IInteger integer(long i); - - /** - * Construct an integer from the two's complement big-endian representation - * - * @param a - * @return a value representing the two's complement notation in a - */ - public IInteger integer(byte[] a); - - /** - * @param a - * @param b - * @return a value representing the rational a/b, with type RationalType - */ - public IRational rational(int a, int b); - - /** - * @param a - * @param b - * @return a value representing the rational a/b, with type RationalType - */ - public IRational rational(long a, long b); - - /** - * @param a - * @param b - * @return a value representing the rational a/b, with type RationalType - */ - public IRational rational(IInteger a, IInteger b); - - /** - * @param rat - * @return a value representing the rational rat, with type RationalType - */ - public IRational rational(String rat) throws NumberFormatException; - - /** - * Construct a real from the mathematical notation. - * - * @param s - * real as a string in decimal mathematical notation. - * @return the corresponding real - * @throws NumberFormatException - */ - public IReal real(String s) throws NumberFormatException; - - /** - * Construct a real from the mathematical notation. - * - * @param s - * real as a string in decimal mathematical notation. - * @param p - * precision - * @return the corresponding real - * @throws NumberFormatException - */ - public IReal real(String s, int p) throws NumberFormatException; - - /** - * @param d - * @return a value representing the double d, with type RealType - */ - public IReal real(double d); - - /** - * @param d - * @param p - * precision - * @return a value representing the double d, with type RealType - */ - public IReal real(double d, int p); - - /** - * @return the global precision for reals - */ - public int getPrecision(); - - /** - * Set the global precision for reals - * - * @param p - * @return the previous global precision - */ - public int setPrecision(int p); - - /** - * @param precision - * (max of 1000) - * @return PI with a higher precision than standard Math.PI - */ - public IReal pi(int precision); - - /** - * @param precision - * (max of 1000) - * @return E with a higher precision than standard Math.E - */ - public IReal e(int precision); - - /** - * @param s - * @return a value representing the string s, with type StringType - */ - public IString string(String s); - - /** - * Build a string from an array of unicode characters. - * - * @param chars - * array of unicode characters - * @throws IllegalArgumentException - * if one of the characters in chars is not a valid codePoint - */ - public IString string(int[] chars) throws IllegalArgumentException; - - /** - * Build a string from a unicode character. - * - * @param ch - * unicode character - * @throws IllegalArgumentException - * when ch is not a valid codePoint - */ - public IString string(int ch) throws IllegalArgumentException; - - /** - * Create an exact reference to a source location. - * - * @param uri - * exact uri where the source is located. - * @param offset - * the character offset starting from the beginning of the file - * located at the given url. Offsets start at 0 (zero). - * @param length - * the character length of the location (the amount characters). - * @param beginLine - * the (inclusive) line number where the location begins. The - * first line is always line number 1. - * @param endLine - * the (exclusive) line where the location ends - * @param beginCol - * the (inclusive) column number where the location begins. The - * first column is always column number 0 (zero). - * @param endCol - * the (exclusive) column number where the location ends. - * @return a value representing a source location, with type - * SourceLocationType - * @deprecated please use the overload with a ISourceLocation - */ - @Deprecated - public ISourceLocation sourceLocation(URI uri, int offset, int length, - int beginLine, int endLine, int beginCol, int endCol); - - /** - * Create an exact reference to a source location. - * - * @param loc - * where the source is located. (only the location part of the source location is used) - * @param offset - * the character offset starting from the beginning of the file - * located at the given url. Offsets start at 0 (zero). - * @param length - * the character length of the location (the amount characters). - * @param beginLine - * the (inclusive) line number where the location begins. The - * first line is always line number 1. - * @param endLine - * the (exclusive) line where the location ends - * @param beginCol - * the (inclusive) column number where the location begins. The - * first column is always column number 0 (zero). - * @param endCol - * the (exclusive) column number where the location ends. - * @return a value representing a source location, with type - * SourceLocationType - */ - public ISourceLocation sourceLocation(ISourceLocation loc, int offset, - int length, int beginLine, int endLine, int beginCol, int endCol); - - /** - * Create an exact reference to a source location. - * - * @param uri - * exact uri where the source is located. - * @param offset - * the character offset starting from the beginning of the file - * located at the given url. Offsets start at 0 (zero). - * @param length - * the character length of the location (the amount characters). - * - * @return a value representing a source location, with type - * SourceLocationType - * @deprecated please use the overload with a ISourceLocation - */ - @Deprecated - public ISourceLocation sourceLocation(URI uri, int offset, int length); - - /** - * Create an exact reference to a source location. - * - * @param loc - * where the source is located. (only the location part of the source location is used) - * @param offset - * the character offset starting from the beginning of the file - * located at the given url. Offsets start at 0 (zero). - * @param length - * the character length of the location (the amount characters). - * - * @return a value representing a source location, with type - * SourceLocationType - */ - public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length); - - /** - * Create an exact reference to a source location. - * - * @param path - * exact (absolute) path where the source is located. - * @param offset - * the character offset starting from the beginning of the file - * located at the given url. Offsets start at 0 (zero). - * @param length - * the character length of the location (the amount characters). - * @param beginLine - * the (inclusive) line number where the location begins. The - * first line is always line number 1. - * @param endLine - * the (exclusive) line where the location ends - * @param beginCol - * the (inclusive) column number where the location begins. The - * first column is always column number 0 (zero). - * @param endCol - * the (exclusive) column number where the location ends. - * @return a value representing a source location, with type - * SourceLocationType - */ - public ISourceLocation sourceLocation(String path, int offset, int length, - int beginLine, int endLine, int beginCol, int endCol); - - /** - * Create an exact reference to a source location. - * - * @param uri - * exact uri where the source is located. - * @return a value representing a source location, with type - * SourceLocationType - */ - public ISourceLocation sourceLocation(URI uri); - - /** - * Create an exact reference to a source location - * - * note that we assume non-encoded input - * - * @param scheme - * the scheme part of an source location - * @param authority - * the authority part of an source location - * @param path - * the path part of an source location - * @return - */ - public ISourceLocation sourceLocation(String scheme, String authority, String path) throws URISyntaxException; - - /** - * Create an exact reference to a source location - * - * note that we assume non-encoded input - * - * @param scheme - * the scheme part of an source location - * @param authority - * the authority part of an source location - * @param path - * the path part of an source location - * @param query - * the query part of an source location - * @param fragment - * the fragment part of an source location - * @return - */ - public ISourceLocation sourceLocation(String scheme, String authority, - String path, @Nullable String query, @Nullable String fragment) - throws URISyntaxException; - - /** - * Create an exact reference to a source location. - * - * @param path - * exact (absolute) path where the source is located. - * @return a value representing a source location, with type - * SourceLocationType - */ - public ISourceLocation sourceLocation(String path); - - /** - * Construct the nullary tuple - * - * @return the nullary tuple - */ - public ITuple tuple(); - - /** - * Construct a tuple - * - * @param args - * a variable length argument list or an array of IValue - * @return a tuple with as many children as there are args - */ - public ITuple tuple(IValue... args); - - /** - * Construct a nullary generic tree node - * - * @param name - * the name of the tree node - * @return a new tree value - */ - public INode node(String name); - - /** - * Construct a node - * - * @param name - * the name of the node - * @param children - * the edges (children) of the node - * @return a new tree node - */ - public INode node(String name, IValue... children); - - /** - * Construct a node with keyword arguments - * - * @param name - * the name of the node - * @param keyArgValues - * to immediately put on the constructor - * @param keyArgValues - * the keyword parameters with their values - * @param children - * an array or variable length argument list of children - * @return a new tree value - * @throws FactTypeUseException - * if the children are not of the expected types for this node - * type - */ - public INode node(String name, IValue[] children, Map keyArgValues); - - /** - * Make a nullary constructor (a typed nullary node) - * - * @param constructor - * the constructor to use - * @return a new constructor value - */ - public IConstructor constructor(Type constructor); - - /** - * Make a constructor value. - * - * @param constructor - * the constructor to use - * @param children - * an array or variable length argument list of children - * @return a new tree value - * @throws FactTypeUseException - * if the children are not of the expected types for this node - * type - */ - public IConstructor constructor(Type constructor, IValue... children); - - /** - * Make a constructor value with keyword parameters - * - * @param constructor - * the constructor to use - * @param children - * an array or variable length argument list of children - * @param kwParams keyword parameters - * @return a new tree value - * @throws FactTypeUseException - * if the children are not of the expected types for this node - * type - */ - public IConstructor constructor(Type constructor, IValue[] children, Map kwParams); - - /** - * Get a set writer of which the element type will be the least upper bound - * of the element types - * - * @return a set writer - */ - public ISetWriter setWriter(); - - /** - * Construct a set with a fixed number of elements in it. If the elements - * are compatible tuples, this will construct a relation. - * - * @param elems - * an array or variable argument list of values - * @return a set containing all the elements - */ - public ISet set(IValue... elems); - - /** - * Get a list writer of which the element type will be the least upper bound - * of the element types - * - * @return a list writer - */ - public IListWriter listWriter(); - - /** - * Construct a list with a fixed number of elements in it. - * - * @param elems - * the elements to put in the list - * @return a list [a] of type list[a.getType()] - */ - public IList list(IValue... elems); - - /** - * Get a map writer of which the key and value types will be the least upper - * bound of the keys and values that are put in. - * - * @return a list writer - */ - public IMapWriter mapWriter(); - - /** - * @return an empty map - */ - public default IMap map() { - return mapWriter().done(); - } - - /** - * Create a boolean with a certain value - * - * @return a boolean - */ - public IBool bool(boolean value); - - /** - * Create a new DateTime representing a date with the given date fields - * - * @param year - * the year of the date - * @param month - * the month of the date - * @param day - * the day of the date - * - * @return a DateTime date with the provided year, month, and day - */ - public IDateTime date(int year, int month, int day); - - /** - * Create a new DateTime representing a time with the given time fields - * - * @param hour - * the hour of the time - * @param minute - * the minute of the time - * @param second - * the second of the time - * @param millisecond - * the millisecond of the time - * - * @return a DateTime time with the provided hour, minute, second, and - * milliseconds - */ - public IDateTime time(int hour, int minute, int second, int millisecond); - - /** - * Create a new DateTime representing a time with the given time fields - * - * @param hour - * the hour of the time - * @param minute - * the minute of the time - * @param second - * the second of the time - * @param millisecond - * the millisecond of the time - * @param hourOffset - * the hour offset of the timezone for this time (can be - * negative) - * @param minuteOffset - * the minute offset of the timezone for this time (can be - * negative if the hourOffset is 0) - * - * @return a DateTime time with the provided hour, minute, second, - * milliseconds, and timezone offset - */ - public IDateTime time(int hour, int minute, int second, int millisecond, - int hourOffset, int minuteOffset); - - /** - * Create a new DateTime with the given date and time fields - * - * @param year - * the year of the date - * @param month - * the month of the date - * @param day - * the day of the date - * @param hour - * the hour of the time - * @param minute - * the minute of the time - * @param second - * the second of the time - * @param millisecond - * the millisecond of the time - * - * @return a DateTime with the values for year, month, etc provided in the - * parameters - */ - public IDateTime datetime(int year, int month, int day, int hour, - int minute, int second, int millisecond); - - /** - * Create a new DateTime with the given date and time fields - * - * @param year - * the year of the date - * @param month - * the month of the date - * @param day - * the day of the date - * @param hour - * the hour of the time - * @param minute - * the minute of the time - * @param second - * the second of the time - * @param millisecond - * the millisecond of the time - * @param hourOffset - * the hour offset of the timezone for this time (can be - * negative) - * @param minuteOffset - * the minute offset of the timezone for this time (can be - * negative if the hourOffset is 0) - * - * @return a DateTime with the values for year, month, etc provided in the - * parameters - */ - public IDateTime datetime(int year, int month, int day, int hour, - int minute, int second, int millisecond, int hourOffset, - int minuteOffset); - - /** - * Create a new DateTime representing the given instant. - * - * @param instant - * the instant in time, according to the Java epoch - * - * @return a DateTime set to the given instant in time - */ - public IDateTime datetime(long instant); - - /** - * Create a new DateTime representing the given instant. - * - * @param instant - * the instant in time, according to the Java epoch - * @param timezoneHours The hour offset for the new object's timezone - * @param timezoneMinutes The minute offset for the new object's timezone - * - * @return a DateTime set to the given instant in time - */ - public IDateTime datetime(long instant, int timezoneHours, int timezoneMinutes); + /** + * Constructs an integer from the decimal representation. + * + * @param i + * integer as a string of decimal digits + * @return a new integer + * @throws NumberFormatException + */ + public IInteger integer(String i) throws NumberFormatException; + + /** + * @param i + * @return a value representing the integer i, with type IntegerType + */ + public IInteger integer(int i); + + /** + * @param i + * @return a value representing the integer i, with type IntegerType + */ + public IInteger integer(long i); + + /** + * Construct an integer from the two's complement big-endian representation + * + * @param a + * @return a value representing the two's complement notation in a + */ + public IInteger integer(byte[] a); + + /** + * @param a + * @param b + * @return a value representing the rational a/b, with type RationalType + */ + public IRational rational(int a, int b); + + /** + * @param a + * @param b + * @return a value representing the rational a/b, with type RationalType + */ + public IRational rational(long a, long b); + + /** + * @param a + * @param b + * @return a value representing the rational a/b, with type RationalType + */ + public IRational rational(IInteger a, IInteger b); + + /** + * @param rat + * @return a value representing the rational rat, with type RationalType + */ + public IRational rational(String rat) throws NumberFormatException; + + /** + * Construct a real from the mathematical notation. + * + * @param s + * real as a string in decimal mathematical notation. + * @return the corresponding real + * @throws NumberFormatException + */ + public IReal real(String s) throws NumberFormatException; + + /** + * Construct a real from the mathematical notation. + * + * @param s + * real as a string in decimal mathematical notation. + * @param p + * precision + * @return the corresponding real + * @throws NumberFormatException + */ + public IReal real(String s, int p) throws NumberFormatException; + + /** + * @param d + * @return a value representing the double d, with type RealType + */ + public IReal real(double d); + + /** + * @param d + * @param p + * precision + * @return a value representing the double d, with type RealType + */ + public IReal real(double d, int p); + + /** + * @return the global precision for reals + */ + public int getPrecision(); + + /** + * Set the global precision for reals + * + * @param p + * @return the previous global precision + */ + public int setPrecision(int p); + + /** + * @param precision + * (max of 1000) + * @return PI with a higher precision than standard Math.PI + */ + public IReal pi(int precision); + + /** + * @param precision + * (max of 1000) + * @return E with a higher precision than standard Math.E + */ + public IReal e(int precision); + + /** + * @param s + * @return a value representing the string s, with type StringType + */ + public IString string(String s); + + /** + * Build a string from an array of unicode characters. + * + * @param chars + * array of unicode characters + * @throws IllegalArgumentException + * if one of the characters in chars is not a valid codePoint + */ + public IString string(int[] chars) throws IllegalArgumentException; + + /** + * Build a string from a unicode character. + * + * @param ch + * unicode character + * @throws IllegalArgumentException + * when ch is not a valid codePoint + */ + public IString string(int ch) throws IllegalArgumentException; + + /** + * Create an exact reference to a source location. + * + * @param uri + * exact uri where the source is located. + * @param offset + * the character offset starting from the beginning of the file + * located at the given url. Offsets start at 0 (zero). + * @param length + * the character length of the location (the amount characters). + * @param beginLine + * the (inclusive) line number where the location begins. The + * first line is always line number 1. + * @param endLine + * the (exclusive) line where the location ends + * @param beginCol + * the (inclusive) column number where the location begins. The + * first column is always column number 0 (zero). + * @param endCol + * the (exclusive) column number where the location ends. + * @return a value representing a source location, with type + * SourceLocationType + * @deprecated please use the overload with a ISourceLocation + */ + @Deprecated + public ISourceLocation sourceLocation(URI uri, int offset, int length, + int beginLine, int endLine, int beginCol, int endCol); + + /** + * Create an exact reference to a source location. + * + * @param loc + * where the source is located. (only the location part of the source location is used) + * @param offset + * the character offset starting from the beginning of the file + * located at the given url. Offsets start at 0 (zero). + * @param length + * the character length of the location (the amount characters). + * @param beginLine + * the (inclusive) line number where the location begins. The + * first line is always line number 1. + * @param endLine + * the (exclusive) line where the location ends + * @param beginCol + * the (inclusive) column number where the location begins. The + * first column is always column number 0 (zero). + * @param endCol + * the (exclusive) column number where the location ends. + * @return a value representing a source location, with type + * SourceLocationType + */ + public ISourceLocation sourceLocation(ISourceLocation loc, int offset, + int length, int beginLine, int endLine, int beginCol, int endCol); + + /** + * Create an exact reference to a source location. + * + * @param uri + * exact uri where the source is located. + * @param offset + * the character offset starting from the beginning of the file + * located at the given url. Offsets start at 0 (zero). + * @param length + * the character length of the location (the amount characters). + * + * @return a value representing a source location, with type + * SourceLocationType + * @deprecated please use the overload with a ISourceLocation + */ + @Deprecated + public ISourceLocation sourceLocation(URI uri, int offset, int length); + + /** + * Create an exact reference to a source location. + * + * @param loc + * where the source is located. (only the location part of the source location is used) + * @param offset + * the character offset starting from the beginning of the file + * located at the given url. Offsets start at 0 (zero). + * @param length + * the character length of the location (the amount characters). + * + * @return a value representing a source location, with type + * SourceLocationType + */ + public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length); + + /** + * Create an exact reference to a source location. + * + * @param path + * exact (absolute) path where the source is located. + * @param offset + * the character offset starting from the beginning of the file + * located at the given url. Offsets start at 0 (zero). + * @param length + * the character length of the location (the amount characters). + * @param beginLine + * the (inclusive) line number where the location begins. The + * first line is always line number 1. + * @param endLine + * the (exclusive) line where the location ends + * @param beginCol + * the (inclusive) column number where the location begins. The + * first column is always column number 0 (zero). + * @param endCol + * the (exclusive) column number where the location ends. + * @return a value representing a source location, with type + * SourceLocationType + */ + public ISourceLocation sourceLocation(String path, int offset, int length, + int beginLine, int endLine, int beginCol, int endCol); + + /** + * Create an exact reference to a source location. + * + * @param uri + * exact uri where the source is located. + * @return a value representing a source location, with type + * SourceLocationType + */ + public ISourceLocation sourceLocation(URI uri); + + /** + * Create an exact reference to a source location + * + * note that we assume non-encoded input + * + * @param scheme + * the scheme part of an source location + * @param authority + * the authority part of an source location + * @param path + * the path part of an source location + * @return + */ + public ISourceLocation sourceLocation(String scheme, String authority, String path) throws URISyntaxException; + + /** + * Create an exact reference to a source location + * + * note that we assume non-encoded input + * + * @param scheme + * the scheme part of an source location + * @param authority + * the authority part of an source location + * @param path + * the path part of an source location + * @param query + * the query part of an source location + * @param fragment + * the fragment part of an source location + * @return + */ + public ISourceLocation sourceLocation(String scheme, String authority, + String path, @Nullable String query, @Nullable String fragment) + throws URISyntaxException; + + /** + * Create an exact reference to a source location. + * + * @param path + * exact (absolute) path where the source is located. + * @return a value representing a source location, with type + * SourceLocationType + */ + public ISourceLocation sourceLocation(String path); + + /** + * Construct the nullary tuple + * + * @return the nullary tuple + */ + public ITuple tuple(); + + /** + * Construct a tuple + * + * @param args + * a variable length argument list or an array of IValue + * @return a tuple with as many children as there are args + */ + public ITuple tuple(IValue... args); + + /** + * Construct a nullary generic tree node + * + * @param name + * the name of the tree node + * @return a new tree value + */ + public INode node(String name); + + /** + * Construct a node + * + * @param name + * the name of the node + * @param children + * the edges (children) of the node + * @return a new tree node + */ + public INode node(String name, IValue... children); + + /** + * Construct a node with keyword arguments + * + * @param name + * the name of the node + * @param keyArgValues + * to immediately put on the constructor + * @param keyArgValues + * the keyword parameters with their values + * @param children + * an array or variable length argument list of children + * @return a new tree value + * @throws FactTypeUseException + * if the children are not of the expected types for this node + * type + */ + public INode node(String name, IValue[] children, Map keyArgValues); + + /** + * Make a nullary constructor (a typed nullary node) + * + * @param constructor + * the constructor to use + * @return a new constructor value + */ + public IConstructor constructor(Type constructor); + + /** + * Make a constructor value. + * + * @param constructor + * the constructor to use + * @param children + * an array or variable length argument list of children + * @return a new tree value + * @throws FactTypeUseException + * if the children are not of the expected types for this node + * type + */ + public IConstructor constructor(Type constructor, IValue... children); + + /** + * Make a constructor value with keyword parameters + * + * @param constructor + * the constructor to use + * @param children + * an array or variable length argument list of children + * @param kwParams keyword parameters + * @return a new tree value + * @throws FactTypeUseException + * if the children are not of the expected types for this node + * type + */ + public IConstructor constructor(Type constructor, IValue[] children, Map kwParams); + + /** + * Get a set writer of which the element type will be the least upper bound + * of the element types + * + * @return a set writer + */ + public ISetWriter setWriter(); + + /** + * Construct a set with a fixed number of elements in it. If the elements + * are compatible tuples, this will construct a relation. + * + * @param elems + * an array or variable argument list of values + * @return a set containing all the elements + */ + public ISet set(IValue... elems); + + /** + * Get a list writer of which the element type will be the least upper bound + * of the element types + * + * @return a list writer + */ + public IListWriter listWriter(); + + /** + * Construct a list with a fixed number of elements in it. + * + * @param elems + * the elements to put in the list + * @return a list [a] of type list[a.getType()] + */ + public IList list(IValue... elems); + + /** + * Get a map writer of which the key and value types will be the least upper + * bound of the keys and values that are put in. + * + * @return a list writer + */ + public IMapWriter mapWriter(); + + /** + * @return an empty map + */ + public default IMap map() { + return mapWriter().done(); + } + + /** + * Create a boolean with a certain value + * + * @return a boolean + */ + public IBool bool(boolean value); + + /** + * Create a new DateTime representing a date with the given date fields + * + * @param year + * the year of the date + * @param month + * the month of the date + * @param day + * the day of the date + * + * @return a DateTime date with the provided year, month, and day + */ + public IDateTime date(int year, int month, int day); + + /** + * Create a new DateTime representing a time with the given time fields + * + * @param hour + * the hour of the time + * @param minute + * the minute of the time + * @param second + * the second of the time + * @param millisecond + * the millisecond of the time + * + * @return a DateTime time with the provided hour, minute, second, and + * milliseconds + */ + public IDateTime time(int hour, int minute, int second, int millisecond); + + /** + * Create a new DateTime representing a time with the given time fields + * + * @param hour + * the hour of the time + * @param minute + * the minute of the time + * @param second + * the second of the time + * @param millisecond + * the millisecond of the time + * @param hourOffset + * the hour offset of the timezone for this time (can be + * negative) + * @param minuteOffset + * the minute offset of the timezone for this time (can be + * negative if the hourOffset is 0) + * + * @return a DateTime time with the provided hour, minute, second, + * milliseconds, and timezone offset + */ + public IDateTime time(int hour, int minute, int second, int millisecond, + int hourOffset, int minuteOffset); + + /** + * Create a new DateTime with the given date and time fields + * + * @param year + * the year of the date + * @param month + * the month of the date + * @param day + * the day of the date + * @param hour + * the hour of the time + * @param minute + * the minute of the time + * @param second + * the second of the time + * @param millisecond + * the millisecond of the time + * + * @return a DateTime with the values for year, month, etc provided in the + * parameters + */ + public IDateTime datetime(int year, int month, int day, int hour, + int minute, int second, int millisecond); + + /** + * Create a new DateTime with the given date and time fields + * + * @param year + * the year of the date + * @param month + * the month of the date + * @param day + * the day of the date + * @param hour + * the hour of the time + * @param minute + * the minute of the time + * @param second + * the second of the time + * @param millisecond + * the millisecond of the time + * @param hourOffset + * the hour offset of the timezone for this time (can be + * negative) + * @param minuteOffset + * the minute offset of the timezone for this time (can be + * negative if the hourOffset is 0) + * + * @return a DateTime with the values for year, month, etc provided in the + * parameters + */ + public IDateTime datetime(int year, int month, int day, int hour, + int minute, int second, int millisecond, int hourOffset, + int minuteOffset); + + /** + * Create a new DateTime representing the given instant. + * + * @param instant + * the instant in time, according to the Java epoch + * + * @return a DateTime set to the given instant in time + */ + public IDateTime datetime(long instant); + + /** + * Create a new DateTime representing the given instant. + * + * @param instant + * the instant in time, according to the Java epoch + * @param timezoneHours The hour offset for the new object's timezone + * @param timezoneMinutes The minute offset for the new object's timezone + * + * @return a DateTime set to the given instant in time + */ + public IDateTime datetime(long instant, int timezoneHours, int timezoneMinutes); } diff --git a/src/main/java/io/usethesource/vallang/IWithKeywordParameters.java b/src/main/java/io/usethesource/vallang/IWithKeywordParameters.java index 1dc772c5c..61ef669a4 100644 --- a/src/main/java/io/usethesource/vallang/IWithKeywordParameters.java +++ b/src/main/java/io/usethesource/vallang/IWithKeywordParameters.java @@ -8,7 +8,7 @@ * Contributors: * * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang; @@ -19,76 +19,76 @@ public interface IWithKeywordParameters { - /** - * Get the value of a parmeter - * - * @param label identifies the parameter - * @return a value if the parameter has a value on this node or null otherwise - */ - public @Nullable IValue getParameter(String label); - - /** - * Set the value of an parameter - * - * @param label identifies the parameter - * @param newValue the new value for the parameter - * @return a new node where the value of the parameter is replaced (if previously present) or newly added - * @throws FactTypeUseException when the type of the new value is not comparable to the old parameter value - */ - public T setParameter(String label, IValue newValue); + /** + * Get the value of a parmeter + * + * @param label identifies the parameter + * @return a value if the parameter has a value on this node or null otherwise + */ + public @Nullable IValue getParameter(String label); - /** - * Unset the value of an parameter - * - * @param label identifies the parameter - * @return a new node where the value of the parameter is not present anymore - */ - public T unsetParameter(String label); + /** + * Set the value of an parameter + * + * @param label identifies the parameter + * @param newValue the new value for the parameter + * @return a new node where the value of the parameter is replaced (if previously present) or newly added + * @throws FactTypeUseException when the type of the new value is not comparable to the old parameter value + */ + public T setParameter(String label, IValue newValue); - /** - * Unset the values of all parameters - * - * @param label identifies the parameter - * @return a new node where the value of all keyword parameters are unset - */ - public T unsetAll(); - - /** - * Check whether a certain parameter is set. - * - * @param label identifies the parameter - * @return true iff the parameter has a value on this node - * @throws FactTypeUseException when no parameter with this label is defined for this type of node. - */ - public boolean hasParameter(String label); + /** + * Unset the value of an parameter + * + * @param label identifies the parameter + * @return a new node where the value of the parameter is not present anymore + */ + public T unsetParameter(String label); - /** - * Check whether any parameters are present. - */ - public boolean hasParameters(); - - /** - * @return a set of parameter names - */ - public Set getParameterNames(); + /** + * Unset the values of all parameters + * + * @param label identifies the parameter + * @return a new node where the value of all keyword parameters are unset + */ + public T unsetAll(); - /** - * @return an unmodifiable map for the keyword parameters - */ - Map getParameters(); + /** + * Check whether a certain parameter is set. + * + * @param label identifies the parameter + * @return true iff the parameter has a value on this node + * @throws FactTypeUseException when no parameter with this label is defined for this type of node. + */ + public boolean hasParameter(String label); - /** - * - * @param params - * @return - */ - T setParameters(Map params); + /** + * Check whether any parameters are present. + */ + public boolean hasParameters(); - /** - * Given an arbitrary other IWithKeywordParameters, compare the values of the - * parameters. - * @param other - * @return true iff the parameters are the same (same labels, same values) - */ - > boolean equalParameters(U other); + /** + * @return a set of parameter names + */ + public Set getParameterNames(); + + /** + * @return an unmodifiable map for the keyword parameters + */ + Map getParameters(); + + /** + * + * @param params + * @return + */ + T setParameters(Map params); + + /** + * Given an arbitrary other IWithKeywordParameters, compare the values of the + * parameters. + * @param other + * @return true iff the parameters are the same (same labels, same values) + */ + > boolean equalParameters(U other); } diff --git a/src/main/java/io/usethesource/vallang/IWriter.java b/src/main/java/io/usethesource/vallang/IWriter.java index 40bfd7f06..f23cbe024 100644 --- a/src/main/java/io/usethesource/vallang/IWriter.java +++ b/src/main/java/io/usethesource/vallang/IWriter.java @@ -15,7 +15,7 @@ public interface IWriter> extends Iterable, Col * Modify this writer to insert only unique instances into the collection * @return */ - public default IWriter unique() { + public default IWriter unique() { return this; } @@ -35,7 +35,7 @@ public default void append(IValue... value) { /** * Append elements at the end. - * + * * @param value array of elements to append * @throws FactTypeUseException when done() was called before */ diff --git a/src/main/java/io/usethesource/vallang/exceptions/EmptyIdentifierException.java b/src/main/java/io/usethesource/vallang/exceptions/EmptyIdentifierException.java index 30caac4be..8db3ee61e 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/EmptyIdentifierException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/EmptyIdentifierException.java @@ -1,9 +1,9 @@ package io.usethesource.vallang.exceptions; public class EmptyIdentifierException extends FactTypeDeclarationException { - private static final long serialVersionUID = -7032740671919237233L; + private static final long serialVersionUID = -7032740671919237233L; - public EmptyIdentifierException() { - super("An identifier can not be empty or null"); - } + public EmptyIdentifierException() { + super("An identifier can not be empty or null"); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/FactParseError.java b/src/main/java/io/usethesource/vallang/exceptions/FactParseError.java index a7954cd1f..8de5817fd 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/FactParseError.java +++ b/src/main/java/io/usethesource/vallang/exceptions/FactParseError.java @@ -1,32 +1,32 @@ package io.usethesource.vallang.exceptions; public class FactParseError extends RuntimeException { - private static final long serialVersionUID = 8208492896666238438L; - private int offset = -1; + private static final long serialVersionUID = 8208492896666238438L; + private int offset = -1; - public FactParseError(String message, Throwable cause) { - super(message, cause); - } - - public FactParseError(String message, int offset) { - super(message); - this.offset = offset; - } - - public FactParseError(String message, int offset, Throwable cause) { - super(message + " at offset " + offset, cause); - this.offset = offset; - } + public FactParseError(String message, Throwable cause) { + super(message, cause); + } - public boolean hasCause() { - return getCause() != null; - } - - - public boolean hasOffset() { - return offset != -1; - } - public int getOffset() { - return offset; - } + public FactParseError(String message, int offset) { + super(message); + this.offset = offset; + } + + public FactParseError(String message, int offset, Throwable cause) { + super(message + " at offset " + offset, cause); + this.offset = offset; + } + + public boolean hasCause() { + return getCause() != null; + } + + + public boolean hasOffset() { + return offset != -1; + } + public int getOffset() { + return offset; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/FactTypeDeclarationException.java b/src/main/java/io/usethesource/vallang/exceptions/FactTypeDeclarationException.java index 168be8e59..b52dc6b35 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/FactTypeDeclarationException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/FactTypeDeclarationException.java @@ -13,13 +13,13 @@ package io.usethesource.vallang.exceptions; public abstract class FactTypeDeclarationException extends RuntimeException { - private static final long serialVersionUID = -2991169068626385361L; + private static final long serialVersionUID = -2991169068626385361L; - public FactTypeDeclarationException(String message) { - super(message); - } - - public FactTypeDeclarationException(String message, Throwable cause) { - super(message, cause); - } + public FactTypeDeclarationException(String message) { + super(message); + } + + public FactTypeDeclarationException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/FactTypeRedeclaredException.java b/src/main/java/io/usethesource/vallang/exceptions/FactTypeRedeclaredException.java index a9dc9bb18..31ca212cf 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/FactTypeRedeclaredException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/FactTypeRedeclaredException.java @@ -3,23 +3,23 @@ import io.usethesource.vallang.type.Type; public class FactTypeRedeclaredException extends FactTypeDeclarationException { - private static final long serialVersionUID = 9191150588452685289L; - private String name; - private Type earlier; - - public FactTypeRedeclaredException(String name, Type earlier) { - super(name + " was declared earlier as " + earlier); - this.name = name; - this.earlier = earlier; - } + private static final long serialVersionUID = 9191150588452685289L; + private String name; + private Type earlier; + + public FactTypeRedeclaredException(String name, Type earlier) { + super(name + " was declared earlier as " + earlier); + this.name = name; + this.earlier = earlier; + } + + public String getName() { + return name; + } + + public Type declaredEarlier() { + return earlier; + } + - public String getName() { - return name; - } - - public Type declaredEarlier() { - return earlier; - } - - } diff --git a/src/main/java/io/usethesource/vallang/exceptions/FactTypeUseException.java b/src/main/java/io/usethesource/vallang/exceptions/FactTypeUseException.java index f49ef8342..3e13e732f 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/FactTypeUseException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/FactTypeUseException.java @@ -16,10 +16,10 @@ public abstract class FactTypeUseException extends RuntimeException { private static final long serialVersionUID= 2135696551442574010L; public FactTypeUseException(String message) { - super(message); + super(message); } - + public FactTypeUseException(String reason, Throwable cause) { - super(reason, cause); + super(reason, cause); } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/FieldLabelMismatchException.java b/src/main/java/io/usethesource/vallang/exceptions/FieldLabelMismatchException.java index 448f6d7bc..e42559780 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/FieldLabelMismatchException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/FieldLabelMismatchException.java @@ -1,22 +1,22 @@ package io.usethesource.vallang.exceptions; public class FieldLabelMismatchException extends FactTypeDeclarationException { - private static final long serialVersionUID = 3510697170437859049L; - private int fields; - private int labels; + private static final long serialVersionUID = 3510697170437859049L; + private int fields; + private int labels; - public FieldLabelMismatchException(int fields, int labels) { - super("Expected " + fields + " field labels, but got " + labels); - this.fields = fields; - this.labels = labels; - } - - public int getFields() { - return fields; - } - - public int getLabels() { - return labels; - } + public FieldLabelMismatchException(int fields, int labels) { + super("Expected " + fields + " field labels, but got " + labels); + this.fields = fields; + this.labels = labels; + } + + public int getFields() { + return fields; + } + + public int getLabels() { + return labels; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalConstructorApplicationException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalConstructorApplicationException.java index 2375b3745..865ab5522 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalConstructorApplicationException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalConstructorApplicationException.java @@ -3,11 +3,11 @@ import io.usethesource.vallang.type.Type; public class IllegalConstructorApplicationException extends FactTypeUseException { - private static final long serialVersionUID = -1412303012184333060L; + private static final long serialVersionUID = -1412303012184333060L; + + public IllegalConstructorApplicationException(Type constructorType, Type arguments) { + super("Constructor " + constructorType + " is not applicable to " + arguments); + } - public IllegalConstructorApplicationException(Type constructorType, Type arguments) { - super("Constructor " + constructorType + " is not applicable to " + arguments); - } - } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldNameException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldNameException.java index 0d41996cd..26b0572e9 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldNameException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldNameException.java @@ -3,25 +3,25 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class IllegalFieldNameException extends FactTypeDeclarationException { - private static final long serialVersionUID = -2480224409679761754L; - private int pos; - private Object elem; + private static final long serialVersionUID = -2480224409679761754L; + private int pos; + private Object elem; - public IllegalFieldNameException(int pos, Object elem, ClassCastException cause) { - super("Expected a field name at position " + pos + ", but got something different", cause); - this.pos = pos; - this.elem = elem; - } - - public Object getElement() { - return elem; - } - - public int getPos() { - return pos; - } - - public synchronized @Nullable ClassCastException getCause() { - return (ClassCastException) super.getCause(); - } + public IllegalFieldNameException(int pos, Object elem, ClassCastException cause) { + super("Expected a field name at position " + pos + ", but got something different", cause); + this.pos = pos; + this.elem = elem; + } + + public Object getElement() { + return elem; + } + + public int getPos() { + return pos; + } + + public synchronized @Nullable ClassCastException getCause() { + return (ClassCastException) super.getCause(); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldTypeException.java index 4f4e3f68e..b3e9ff6bb 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalFieldTypeException.java @@ -1,26 +1,26 @@ package io.usethesource.vallang.exceptions; public class IllegalFieldTypeException extends FactTypeDeclarationException { - private static final long serialVersionUID = -8845629423612702596L; - private int pos; - private Object elem; + private static final long serialVersionUID = -8845629423612702596L; + private int pos; + private Object elem; - public IllegalFieldTypeException(int pos, Object elem, ClassCastException cause) { - super("Expected a field type at position " + pos + ", but got something different", cause); - this.pos = pos; - this.elem = elem; - } + public IllegalFieldTypeException(int pos, Object elem, ClassCastException cause) { + super("Expected a field type at position " + pos + ", but got something different", cause); + this.pos = pos; + this.elem = elem; + } - public Object getElement() { - return elem; - } - - public int getPos() { - return pos; - } - - public synchronized Throwable getCause() { - Throwable cause = super.getCause(); - return cause == null ? this : cause; - } + public Object getElement() { + return elem; + } + + public int getPos() { + return pos; + } + + public synchronized Throwable getCause() { + Throwable cause = super.getCause(); + return cause == null ? this : cause; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalIdentifierException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalIdentifierException.java index a11569832..7759b9d3f 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalIdentifierException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalIdentifierException.java @@ -1,15 +1,15 @@ package io.usethesource.vallang.exceptions; public class IllegalIdentifierException extends FactTypeDeclarationException { - private static final long serialVersionUID = 7380196205269771711L; - private String id; + private static final long serialVersionUID = 7380196205269771711L; + private String id; - public IllegalIdentifierException(String id) { - super(id + " is not a valid identifier"); - this.id = id; - } - - public String getIdentifier() { - return id; - } + public IllegalIdentifierException(String id) { + super(id + " is not a valid identifier"); + this.id = id; + } + + public String getIdentifier() { + return id; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalInstantiatedAbstractDataTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalInstantiatedAbstractDataTypeException.java index ae4a46623..752eb601a 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalInstantiatedAbstractDataTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalInstantiatedAbstractDataTypeException.java @@ -3,10 +3,10 @@ import io.usethesource.vallang.type.Type; public class IllegalInstantiatedAbstractDataTypeException extends - FactTypeDeclarationException { - private static final long serialVersionUID = -7171289358305194254L; + FactTypeDeclarationException { + private static final long serialVersionUID = -7171289358305194254L; - public IllegalInstantiatedAbstractDataTypeException(Type adt) { - super("should not declare instances of type-parametrized abstract data-types (" + adt + ")"); - } + public IllegalInstantiatedAbstractDataTypeException(Type adt) { + super("should not declare instances of type-parametrized abstract data-types (" + adt + ")"); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalKeywordParameterDeclarationException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalKeywordParameterDeclarationException.java index cbcae7239..cfc25c49b 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalKeywordParameterDeclarationException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalKeywordParameterDeclarationException.java @@ -3,9 +3,9 @@ import io.usethesource.vallang.type.Type; public class IllegalKeywordParameterDeclarationException extends FactTypeUseException { - private static final long serialVersionUID = -1073149631907760703L; - - public IllegalKeywordParameterDeclarationException(Type type) { - super("Keyword parameters can not be declared on " + type); - } + private static final long serialVersionUID = -1073149631907760703L; + + public IllegalKeywordParameterDeclarationException(Type type) { + super("Keyword parameters can not be declared on " + type); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/IllegalOperationException.java b/src/main/java/io/usethesource/vallang/exceptions/IllegalOperationException.java index d9336067f..dd55f50cd 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/IllegalOperationException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/IllegalOperationException.java @@ -3,13 +3,13 @@ import io.usethesource.vallang.type.Type; public class IllegalOperationException extends FactTypeUseException { - private static final long serialVersionUID = 546504861606007094L; - - public IllegalOperationException(String op, Type lhs) { - super("Operation " + op + " not allowed on " + lhs); - } - - public IllegalOperationException(String op, Type lhs, Type rhs) { - super("Operation " +op + " not allowed on " + lhs + " and " + rhs); - } + private static final long serialVersionUID = 546504861606007094L; + + public IllegalOperationException(String op, Type lhs) { + super("Operation " + op + " not allowed on " + lhs); + } + + public IllegalOperationException(String op, Type lhs, Type rhs) { + super("Operation " +op + " not allowed on " + lhs + " and " + rhs); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/InvalidDateTimeException.java b/src/main/java/io/usethesource/vallang/exceptions/InvalidDateTimeException.java index 629948535..cd0bf57e0 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/InvalidDateTimeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/InvalidDateTimeException.java @@ -1,15 +1,15 @@ -package io.usethesource.vallang.exceptions; - -public class InvalidDateTimeException extends FactTypeUseException { - - private static final long serialVersionUID = 5634976179346912971L; - - public InvalidDateTimeException(String message) { - super(message); - } - - public InvalidDateTimeException(String message, Throwable cause) { - super(message, cause); - } - -} +package io.usethesource.vallang.exceptions; + +public class InvalidDateTimeException extends FactTypeUseException { + + private static final long serialVersionUID = 5634976179346912971L; + + public InvalidDateTimeException(String message) { + super(message); + } + + public InvalidDateTimeException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/io/usethesource/vallang/exceptions/NullTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/NullTypeException.java index 11195884b..bf8962d04 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/NullTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/NullTypeException.java @@ -1,10 +1,10 @@ package io.usethesource.vallang.exceptions; public class NullTypeException extends FactTypeUseException { - private static final long serialVersionUID = -4201840676263159311L; + private static final long serialVersionUID = -4201840676263159311L; - public NullTypeException() { - super("A null reference as a type"); - } + public NullTypeException() { + super("A null reference as a type"); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/OverloadingNotSupportedException.java b/src/main/java/io/usethesource/vallang/exceptions/OverloadingNotSupportedException.java index ecd4f4a5c..0b08e5d10 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/OverloadingNotSupportedException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/OverloadingNotSupportedException.java @@ -3,14 +3,14 @@ import io.usethesource.vallang.type.Type; public class OverloadingNotSupportedException extends FactTypeUseException { - private static final long serialVersionUID = 5645367130014687132L; + private static final long serialVersionUID = 5645367130014687132L; - public OverloadingNotSupportedException(String constructorId) { - super("Overloading is not supported (" + constructorId + ")"); - } - - public OverloadingNotSupportedException(Type adt, String constructorId) { - super("Overloading is not supported (" + adt + "." + constructorId + ")"); - } + public OverloadingNotSupportedException(String constructorId) { + super("Overloading is not supported (" + constructorId + ")"); + } + + public OverloadingNotSupportedException(Type adt, String constructorId) { + super("Overloading is not supported (" + adt + "." + constructorId + ")"); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredConstructorException.java b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredConstructorException.java index 3e2c2eef6..fb48e4db7 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredConstructorException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredConstructorException.java @@ -3,28 +3,28 @@ import io.usethesource.vallang.type.Type; public class RedeclaredConstructorException extends - FactTypeDeclarationException { - private static final long serialVersionUID = 8330548728032865311L; - private String name; - private Type firstArgs; - private Type secondArgs; + FactTypeDeclarationException { + private static final long serialVersionUID = 8330548728032865311L; + private String name; + private Type firstArgs; + private Type secondArgs; - public RedeclaredConstructorException(String name, Type firstArgs, Type secondArgs) { - super("Constructor " + name + " overloaded with comparable argument types: " + firstArgs + " and " + secondArgs); - this.name = name; - this.firstArgs = firstArgs; - this.secondArgs = secondArgs; - } + public RedeclaredConstructorException(String name, Type firstArgs, Type secondArgs) { + super("Constructor " + name + " overloaded with comparable argument types: " + firstArgs + " and " + secondArgs); + this.name = name; + this.firstArgs = firstArgs; + this.secondArgs = secondArgs; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public Type getFirstArgs() { - return firstArgs; - } + public Type getFirstArgs() { + return firstArgs; + } - public Type getSecondArgs() { - return secondArgs; - } + public Type getSecondArgs() { + return secondArgs; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredFieldNameException.java b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredFieldNameException.java index d15984557..2016e231c 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredFieldNameException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredFieldNameException.java @@ -3,35 +3,35 @@ import io.usethesource.vallang.type.Type; public class RedeclaredFieldNameException extends - FactTypeDeclarationException { - private static final long serialVersionUID = -4401062690006714904L; - private String label; - private Type one; - private Type two; - private Type tupleType; - - public RedeclaredFieldNameException(String label, Type one, Type two, Type tupleType) { - super("The field name " + label + " is illegally used for both " + one + " and " + two + " in type " + tupleType); - this.label = label; - this.one = one; - this.two = two; - this.tupleType = tupleType; - } - - public String getFieldName() { - return label; - } - - public Type getFirstType() { - return one; - } - - public Type getSecondType() { - return two; - } - - public Type getTupleType() { - return tupleType; - } + FactTypeDeclarationException { + private static final long serialVersionUID = -4401062690006714904L; + private String label; + private Type one; + private Type two; + private Type tupleType; + + public RedeclaredFieldNameException(String label, Type one, Type two, Type tupleType) { + super("The field name " + label + " is illegally used for both " + one + " and " + two + " in type " + tupleType); + this.label = label; + this.one = one; + this.two = two; + this.tupleType = tupleType; + } + + public String getFieldName() { + return label; + } + + public Type getFirstType() { + return one; + } + + public Type getSecondType() { + return two; + } + + public Type getTupleType() { + return tupleType; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredKeywordParameterException.java b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredKeywordParameterException.java index 594a22c9c..08221c984 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/RedeclaredKeywordParameterException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/RedeclaredKeywordParameterException.java @@ -3,21 +3,21 @@ import io.usethesource.vallang.type.Type; public class RedeclaredKeywordParameterException extends FactTypeDeclarationException { - private static final long serialVersionUID = -2118606173620347920L; - private String label; - private Type earlier; + private static final long serialVersionUID = -2118606173620347920L; + private String label; + private Type earlier; - public RedeclaredKeywordParameterException(String label, Type earlier) { - super("Keyword parameter " + label + " was declared earlier as " + earlier); - this.label = label; - this.earlier = earlier; - } - - public String getLabel() { - return label; - } - - public Type getEarlierType() { - return earlier; - } + public RedeclaredKeywordParameterException(String label, Type earlier) { + super("Keyword parameter " + label + " was declared earlier as " + earlier); + this.label = label; + this.earlier = earlier; + } + + public String getLabel() { + return label; + } + + public Type getEarlierType() { + return earlier; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/TypeParseError.java b/src/main/java/io/usethesource/vallang/exceptions/TypeParseError.java index 1e2443198..672f978ee 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/TypeParseError.java +++ b/src/main/java/io/usethesource/vallang/exceptions/TypeParseError.java @@ -4,29 +4,29 @@ public class TypeParseError extends RuntimeException { private static final long serialVersionUID = 7054359699049181437L; private int offset = -1; - public TypeParseError(String message, Throwable cause) { - super(message, cause); - } - - public TypeParseError(String message, int offset) { - super(message); - this.offset = offset; - } - - public TypeParseError(String message, int offset, Throwable cause) { - super(message + " at offset " + offset, cause); - this.offset = offset; - } + public TypeParseError(String message, Throwable cause) { + super(message, cause); + } - public boolean hasCause() { - return getCause() != null; - } - - - public boolean hasOffset() { - return offset != -1; - } - public int getOffset() { - return offset; - } + public TypeParseError(String message, int offset) { + super(message); + this.offset = offset; + } + + public TypeParseError(String message, int offset, Throwable cause) { + super(message + " at offset " + offset, cause); + this.offset = offset; + } + + public boolean hasCause() { + return getCause() != null; + } + + + public boolean hasOffset() { + return offset != -1; + } + public int getOffset() { + return offset; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/TypeReificationException.java b/src/main/java/io/usethesource/vallang/exceptions/TypeReificationException.java index 6980efe1a..621201f12 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/TypeReificationException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/TypeReificationException.java @@ -1,9 +1,9 @@ package io.usethesource.vallang.exceptions; public class TypeReificationException extends FactTypeUseException { - private static final long serialVersionUID = -1606508959996710935L; + private static final long serialVersionUID = -1606508959996710935L; - public TypeReificationException(String reason, Throwable cause) { - super(reason, cause); - } + public TypeReificationException(String reason, Throwable cause) { + super(reason, cause); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UndeclaredAbstractDataTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UndeclaredAbstractDataTypeException.java index 97a61489e..66e66ef5f 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UndeclaredAbstractDataTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UndeclaredAbstractDataTypeException.java @@ -3,10 +3,10 @@ import io.usethesource.vallang.type.Type; public class UndeclaredAbstractDataTypeException extends - FactTypeDeclarationException { - private static final long serialVersionUID = 2192451595458909479L; + FactTypeDeclarationException { + private static final long serialVersionUID = 2192451595458909479L; - public UndeclaredAbstractDataTypeException(Type adt) { - super(adt + " is not registered"); - } + public UndeclaredAbstractDataTypeException(Type adt) { + super(adt + " is not registered"); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UndeclaredFieldException.java b/src/main/java/io/usethesource/vallang/exceptions/UndeclaredFieldException.java index 845faaa58..5e9f1daf5 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UndeclaredFieldException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UndeclaredFieldException.java @@ -3,21 +3,21 @@ import io.usethesource.vallang.type.Type; public class UndeclaredFieldException extends FactTypeUseException { - private static final long serialVersionUID = 8997399464492627705L; - private Type type; - private String label; - - public UndeclaredFieldException(Type type, String label) { - super(type + " does not have a field with label " + label + " declared for it"); - this.type = type; - this.label = label; - } - - public Type getType() { - return type; - } - - public String getLabel() { - return label; - } + private static final long serialVersionUID = 8997399464492627705L; + private Type type; + private String label; + + public UndeclaredFieldException(Type type, String label) { + super(type + " does not have a field with label " + label + " declared for it"); + this.type = type; + this.label = label; + } + + public Type getType() { + return type; + } + + public String getLabel() { + return label; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedAnnotationTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedAnnotationTypeException.java index 1f46856ed..b014cf585 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedAnnotationTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedAnnotationTypeException.java @@ -3,10 +3,10 @@ import io.usethesource.vallang.type.Type; public class UnexpectedAnnotationTypeException extends UnexpectedTypeException { - private static final long serialVersionUID = -4865168232421987847L; + private static final long serialVersionUID = -4865168232421987847L; - public UnexpectedAnnotationTypeException(Type expected, Type got) { - super(expected, got); - } + public UnexpectedAnnotationTypeException(Type expected, Type got) { + super(expected, got); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedChildTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedChildTypeException.java index c6dc11793..0739fce13 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedChildTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedChildTypeException.java @@ -3,9 +3,9 @@ import io.usethesource.vallang.type.Type; public class UnexpectedChildTypeException extends UnexpectedTypeException { - private static final long serialVersionUID = -1848764011952028440L; + private static final long serialVersionUID = -1848764011952028440L; - public UnexpectedChildTypeException(Type expected, Type got) { - super(expected, got); - } + public UnexpectedChildTypeException(Type expected, Type got) { + super(expected, got); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedConstructorTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedConstructorTypeException.java index 6ec4c9e79..e2d592dd4 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedConstructorTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedConstructorTypeException.java @@ -3,10 +3,10 @@ import io.usethesource.vallang.type.Type; public class UnexpectedConstructorTypeException extends UnexpectedTypeException { - private static final long serialVersionUID = -6198133177142765746L; + private static final long serialVersionUID = -6198133177142765746L; - public UnexpectedConstructorTypeException(Type expected, Type got) { - super(expected, got); - } + public UnexpectedConstructorTypeException(Type expected, Type got) { + super(expected, got); + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedTypeException.java index d4c2405b1..54f2f820f 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UnexpectedTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UnexpectedTypeException.java @@ -3,27 +3,27 @@ import io.usethesource.vallang.type.Type; public class UnexpectedTypeException extends FactTypeUseException { - private static final long serialVersionUID = -5107803679675463540L; - private Type expected; - private Type got; - - public UnexpectedTypeException(Type expected, Type got) { - super("Expected " + expected + ", but got " + got); - this.expected = expected; - this.got = got; - } - - public boolean hasExpected() { - return expected != null; - } - - public Type getExpected() { - return expected; - } - - public Type getGiven() { - return got; - } + private static final long serialVersionUID = -5107803679675463540L; + private Type expected; + private Type got; + + public UnexpectedTypeException(Type expected, Type got) { + super("Expected " + expected + ", but got " + got); + this.expected = expected; + this.got = got; + } + + public boolean hasExpected() { + return expected != null; + } + + public Type getExpected() { + return expected; + } + + public Type getGiven() { + return got; + } } diff --git a/src/main/java/io/usethesource/vallang/exceptions/UnsupportedTypeException.java b/src/main/java/io/usethesource/vallang/exceptions/UnsupportedTypeException.java index 90b88cb9a..fc833493d 100644 --- a/src/main/java/io/usethesource/vallang/exceptions/UnsupportedTypeException.java +++ b/src/main/java/io/usethesource/vallang/exceptions/UnsupportedTypeException.java @@ -3,14 +3,14 @@ import io.usethesource.vallang.type.Type; public class UnsupportedTypeException extends FactTypeUseException { - private static final long serialVersionUID = -8995093767494157052L; - private Type type; - public UnsupportedTypeException(String explanation, Type type) { - super(explanation); - this.type = type; - } - - public Type getType() { - return type; - } + private static final long serialVersionUID = -8995093767494157052L; + private Type type; + public UnsupportedTypeException(String explanation, Type type) { + super(explanation); + this.type = type; + } + + public Type getType() { + return type; + } } diff --git a/src/main/java/io/usethesource/vallang/impl/fields/AbstractDefaultWithKeywordParameters.java b/src/main/java/io/usethesource/vallang/impl/fields/AbstractDefaultWithKeywordParameters.java index 210f0c308..2a4fff2c4 100644 --- a/src/main/java/io/usethesource/vallang/impl/fields/AbstractDefaultWithKeywordParameters.java +++ b/src/main/java/io/usethesource/vallang/impl/fields/AbstractDefaultWithKeywordParameters.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.impl.fields; @@ -24,166 +24,166 @@ /** - * A generic wrapper for an {@link IValue} that associates keyword parameters to it. + * A generic wrapper for an {@link IValue} that associates keyword parameters to it. * * @param the interface over which this parameter wrapper closes */ public abstract class AbstractDefaultWithKeywordParameters implements IWithKeywordParameters { - protected final T content; - protected final io.usethesource.capsule.Map.Immutable parameters; - - /** - * Creates an {@link IWithKeywordParameters} view on {@link #content} with already - * provided {@link #parameters}. - * - * @param content - * is the wrapped object that supports keywod fields - * @param parameters - * is the map of fields associated to {@link #content} - */ - public AbstractDefaultWithKeywordParameters(T content, io.usethesource.capsule.Map.Immutable parameters) { - this.content = content; - this.parameters = parameters; - } - - /** - * Wraps {@link #content} with other parameters. This methods is mandatory - * because of PDB's immutable value nature: Once parameters are modified, a - * new immutable view is returned. - * - * @param content - * is the wrapped object that supports keyword fields - * @param annotations - * is the map of fields associated to {@link #content} - * @return a new representations of {@link #content} with associated - * {@link #parameters} - */ - protected abstract T wrap(final T content, final io.usethesource.capsule.Map.Immutable parameters); - - @Override - public String toString() { - return content.toString(); - } - - @Override - public @Nullable IValue getParameter(String label) { - return parameters.get(label); - } - - @Override - public T setParameter(String label, IValue newValue) { - return wrap(content, parameters.__put(label, newValue)); - } - - @Override - public T unsetParameter(String label) { - io.usethesource.capsule.Map.Immutable removed = parameters.__remove(label); - - if (removed.isEmpty()) { - return content; - } - return wrap(content, removed); - } - - @Override - public T unsetAll() { - return content; - } - - @Override - @Pure - public boolean hasParameter(String label) { - return parameters.containsKey(label); - } - - @Override - public boolean hasParameters() { - return !parameters.isEmpty(); - } - - @Override - @Pure - public Set getParameterNames() { - return Collections.unmodifiableSet(parameters.keySet()); - } - - @Override - public Map getParameters() { - return Collections.unmodifiableMap(parameters); - } - - @Override - public int hashCode() { - return 91 + content.hashCode() * 13 + 101 * parameters.hashCode(); - } - - @Override - public boolean equals(@Nullable Object other) { - if (other == null) { - return false; - } - - if (!getClass().equals(other.getClass())) { - return false; - } - - AbstractDefaultWithKeywordParameters o = (AbstractDefaultWithKeywordParameters) other; - - if (!content.equals(o.content)) { - return false; - } - - if (parameters.size() != o.parameters.size()) { - return false; - } - - // TODO: there should be a faster way for this - for (String key : parameters.keySet()) { - if (!parameters.get(key).equals(o.getParameter(key))) { - return false; - } - } - - return true; - } - - @Override - public > boolean equalParameters(U other) { - if (!(other instanceof AbstractDefaultWithKeywordParameters)) { - return false; - } - - AbstractDefaultWithKeywordParameters o = (AbstractDefaultWithKeywordParameters) other; - - if (parameters.size() != o.parameters.size()) { - return false; - } - - for (String key : parameters.keySet()) { - IValue parameter = getParameter(key); - if (parameter == null && o.getParameter(key) != null) { - return false; - } - else if (parameter != null && !parameter.equals(o.getParameter(key))) { - return false; - } - } - - return true; - } - - @Override - public T setParameters(Map params) { - if (params.isEmpty()) { - return content; - } - return wrap(content, AbstractSpecialisedImmutableMap.mapOf(params)); - } - - /** - * This method is only to be used by internal methods, such as testing and fast iterators - */ - public io.usethesource.capsule.Map.Immutable internalGetParameters() { - return parameters; - } + protected final T content; + protected final io.usethesource.capsule.Map.Immutable parameters; + + /** + * Creates an {@link IWithKeywordParameters} view on {@link #content} with already + * provided {@link #parameters}. + * + * @param content + * is the wrapped object that supports keywod fields + * @param parameters + * is the map of fields associated to {@link #content} + */ + public AbstractDefaultWithKeywordParameters(T content, io.usethesource.capsule.Map.Immutable parameters) { + this.content = content; + this.parameters = parameters; + } + + /** + * Wraps {@link #content} with other parameters. This methods is mandatory + * because of PDB's immutable value nature: Once parameters are modified, a + * new immutable view is returned. + * + * @param content + * is the wrapped object that supports keyword fields + * @param annotations + * is the map of fields associated to {@link #content} + * @return a new representations of {@link #content} with associated + * {@link #parameters} + */ + protected abstract T wrap(final T content, final io.usethesource.capsule.Map.Immutable parameters); + + @Override + public String toString() { + return content.toString(); + } + + @Override + public @Nullable IValue getParameter(String label) { + return parameters.get(label); + } + + @Override + public T setParameter(String label, IValue newValue) { + return wrap(content, parameters.__put(label, newValue)); + } + + @Override + public T unsetParameter(String label) { + io.usethesource.capsule.Map.Immutable removed = parameters.__remove(label); + + if (removed.isEmpty()) { + return content; + } + return wrap(content, removed); + } + + @Override + public T unsetAll() { + return content; + } + + @Override + @Pure + public boolean hasParameter(String label) { + return parameters.containsKey(label); + } + + @Override + public boolean hasParameters() { + return !parameters.isEmpty(); + } + + @Override + @Pure + public Set getParameterNames() { + return Collections.unmodifiableSet(parameters.keySet()); + } + + @Override + public Map getParameters() { + return Collections.unmodifiableMap(parameters); + } + + @Override + public int hashCode() { + return 91 + content.hashCode() * 13 + 101 * parameters.hashCode(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (other == null) { + return false; + } + + if (!getClass().equals(other.getClass())) { + return false; + } + + AbstractDefaultWithKeywordParameters o = (AbstractDefaultWithKeywordParameters) other; + + if (!content.equals(o.content)) { + return false; + } + + if (parameters.size() != o.parameters.size()) { + return false; + } + + // TODO: there should be a faster way for this + for (String key : parameters.keySet()) { + if (!parameters.get(key).equals(o.getParameter(key))) { + return false; + } + } + + return true; + } + + @Override + public > boolean equalParameters(U other) { + if (!(other instanceof AbstractDefaultWithKeywordParameters)) { + return false; + } + + AbstractDefaultWithKeywordParameters o = (AbstractDefaultWithKeywordParameters) other; + + if (parameters.size() != o.parameters.size()) { + return false; + } + + for (String key : parameters.keySet()) { + IValue parameter = getParameter(key); + if (parameter == null && o.getParameter(key) != null) { + return false; + } + else if (parameter != null && !parameter.equals(o.getParameter(key))) { + return false; + } + } + + return true; + } + + @Override + public T setParameters(Map params) { + if (params.isEmpty()) { + return content; + } + return wrap(content, AbstractSpecialisedImmutableMap.mapOf(params)); + } + + /** + * This method is only to be used by internal methods, such as testing and fast iterators + */ + public io.usethesource.capsule.Map.Immutable internalGetParameters() { + return parameters; + } } diff --git a/src/main/java/io/usethesource/vallang/impl/fields/AbstractValueFactoryAdapter.java b/src/main/java/io/usethesource/vallang/impl/fields/AbstractValueFactoryAdapter.java index 63320edee..8076bc10b 100644 --- a/src/main/java/io/usethesource/vallang/impl/fields/AbstractValueFactoryAdapter.java +++ b/src/main/java/io/usethesource/vallang/impl/fields/AbstractValueFactoryAdapter.java @@ -30,7 +30,7 @@ * of IValueFactory without having to extend them again and again using * inheritance. Clients extend this class and override the methods that need * special handling. - * + * * Note: this class is intended to be sub-classed. It should not be abstract * because we want the compiler to check that it provides a facade for the full * IValueFactory interface. @@ -88,7 +88,7 @@ public IDateTime datetime(long instant, int timezoneHours, int timezoneMinutes) public IInteger integer(String i) { return adapted.integer(i); } - + @Override public IInteger integer(int i) { return adapted.integer(i); diff --git a/src/main/java/io/usethesource/vallang/impl/fields/ConstructorWithKeywordParametersFacade.java b/src/main/java/io/usethesource/vallang/impl/fields/ConstructorWithKeywordParametersFacade.java index 7e830919f..42c167f57 100644 --- a/src/main/java/io/usethesource/vallang/impl/fields/ConstructorWithKeywordParametersFacade.java +++ b/src/main/java/io/usethesource/vallang/impl/fields/ConstructorWithKeywordParametersFacade.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.impl.fields; @@ -98,7 +98,7 @@ public boolean equals(@Nullable Object o) { if (o == this) { return true; } - + if (o == null) { return false; } @@ -116,7 +116,7 @@ public boolean equals(@Nullable Object o) { @Override public boolean match(IValue other) { if (other instanceof ConstructorWithKeywordParametersFacade) { - return content.match(((ConstructorWithKeywordParametersFacade) other).content); + return content.match(((ConstructorWithKeywordParametersFacade) other).content); } if (other instanceof IConstructor) { @@ -152,7 +152,7 @@ public boolean hasParameters() { @Override @SuppressWarnings("return.type.incompatible") public Set getParameterNames() { - return Collections.unmodifiableSet(parameters.keySet()); + return Collections.unmodifiableSet(parameters.keySet()); } @Override diff --git a/src/main/java/io/usethesource/vallang/impl/fields/NodeWithKeywordParametersFacade.java b/src/main/java/io/usethesource/vallang/impl/fields/NodeWithKeywordParametersFacade.java index 9fdc11d8c..fbd1f5f4a 100644 --- a/src/main/java/io/usethesource/vallang/impl/fields/NodeWithKeywordParametersFacade.java +++ b/src/main/java/io/usethesource/vallang/impl/fields/NodeWithKeywordParametersFacade.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.impl.fields; @@ -24,107 +24,107 @@ import io.usethesource.vallang.visitors.IValueVisitor; public class NodeWithKeywordParametersFacade implements INode { - protected final INode content; - protected final Map.Immutable parameters; - - public NodeWithKeywordParametersFacade(final INode content, final Map.Immutable parameters) { - this.content = content; - this.parameters = parameters; - } - - @Override - public Type getType() { - return content.getType(); - } - - @Override + protected final INode content; + protected final Map.Immutable parameters; + + public NodeWithKeywordParametersFacade(final INode content, final Map.Immutable parameters) { + this.content = content; + this.parameters = parameters; + } + + @Override + public Type getType() { + return content.getType(); + } + + @Override public INode setChildren(IValue[] childArray) { return content.setChildren(childArray).asWithKeywordParameters().setParameters(parameters); } - @Override - public T accept(IValueVisitor v) throws E { - return v.visitNode(this); - } - - @Override - public IValue get(int i) { - return content.get(i); - } - - @Override - public INode set(int i, IValue newChild) { - INode newContent = content.set(i, newChild); - return new NodeWithKeywordParametersFacade(newContent, parameters); // TODO: introduce wrap() here as well - } - - @Override - public int arity() { - return content.arity(); - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public String getName() { - return content.getName(); - } - - @Override - public Iterable getChildren() { - return content.getChildren(); - } - - @Override - public Iterator iterator() { - return content.iterator(); - } - - @Override - public INode replace(int first, int second, int end, IList repl) { - INode newContent = content.replace(first, second, end, repl); - return new NodeWithKeywordParametersFacade(newContent, parameters); // TODO: introduce wrap() here as well - } - - @Override - public boolean equals(@Nullable Object o) { - if(o == this) { - return true; - } - if(o == null) { - return false; - } - - if(o.getClass() == getClass()){ - NodeWithKeywordParametersFacade other = (NodeWithKeywordParametersFacade) o; - - return content.equals(other.content) && parameters.equals(other.parameters); - } - - return false; - } - - @Override - public int hashCode() { - return 15551 + 7 * content.hashCode() + 11 * parameters.hashCode(); - } - - @Override - public boolean mayHaveKeywordParameters() { - return true; - } - - @Override - public IWithKeywordParameters asWithKeywordParameters() { - return new AbstractDefaultWithKeywordParameters(content, parameters) { - @Override - protected INode wrap(INode content, Map.Immutable parameters) { - return new NodeWithKeywordParametersFacade(content, parameters); - } - }; - } - + @Override + public T accept(IValueVisitor v) throws E { + return v.visitNode(this); + } + + @Override + public IValue get(int i) { + return content.get(i); + } + + @Override + public INode set(int i, IValue newChild) { + INode newContent = content.set(i, newChild); + return new NodeWithKeywordParametersFacade(newContent, parameters); // TODO: introduce wrap() here as well + } + + @Override + public int arity() { + return content.arity(); + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public String getName() { + return content.getName(); + } + + @Override + public Iterable getChildren() { + return content.getChildren(); + } + + @Override + public Iterator iterator() { + return content.iterator(); + } + + @Override + public INode replace(int first, int second, int end, IList repl) { + INode newContent = content.replace(first, second, end, repl); + return new NodeWithKeywordParametersFacade(newContent, parameters); // TODO: introduce wrap() here as well + } + + @Override + public boolean equals(@Nullable Object o) { + if(o == this) { + return true; + } + if(o == null) { + return false; + } + + if(o.getClass() == getClass()){ + NodeWithKeywordParametersFacade other = (NodeWithKeywordParametersFacade) o; + + return content.equals(other.content) && parameters.equals(other.parameters); + } + + return false; + } + + @Override + public int hashCode() { + return 15551 + 7 * content.hashCode() + 11 * parameters.hashCode(); + } + + @Override + public boolean mayHaveKeywordParameters() { + return true; + } + + @Override + public IWithKeywordParameters asWithKeywordParameters() { + return new AbstractDefaultWithKeywordParameters(content, parameters) { + @Override + protected INode wrap(INode content, Map.Immutable parameters) { + return new NodeWithKeywordParametersFacade(content, parameters); + } + }; + } + } diff --git a/src/main/java/io/usethesource/vallang/impl/fields/package-info.java b/src/main/java/io/usethesource/vallang/impl/fields/package-info.java index fe2dd413e..4d6cd06af 100644 --- a/src/main/java/io/usethesource/vallang/impl/fields/package-info.java +++ b/src/main/java/io/usethesource/vallang/impl/fields/package-info.java @@ -1,5 +1,5 @@ /** * This contains generic wrapper classes to implement IAnnotable and IWithKeywordParameters for different - * host values (INode and IConstructor). + * host values (INode and IConstructor). */ package io.usethesource.vallang.impl.fields; \ No newline at end of file diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/Constructor.java b/src/main/java/io/usethesource/vallang/impl/persistent/Constructor.java index 2ccfceca1..643b08760 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/Constructor.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/Constructor.java @@ -103,7 +103,7 @@ public boolean equals(@Nullable Object o){ return false; } - + @Override public String toString() { return defaultToString(); @@ -726,7 +726,7 @@ public IConstructor set(int index, IValue newArg) { public int hashCode() { return super.hashCode(); } - + @Override public boolean equals(@Nullable Object o) { if (o == this) { @@ -823,14 +823,14 @@ public Type getUninstantiatedConstructorType() { /** * As empty constructors are very common and are only based on a type that is already maximally shared we also maximally share the Constructor0 instances - * + * * This descreases both memory footprint and allocation overhead. */ private static final LoadingCache EMPTY_CONSTRUCTOR_SINGLETONS = Caffeine.newBuilder().build(Constructor0::new); /*package*/ static IConstructor newConstructor(Type constructorType, IValue[] children) { assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, children); - + if (constructorType.isParameterized()) { return new TypeParameterizedConstructorN(constructorType, children); } @@ -853,7 +853,7 @@ private static T nonNull(@Nullable T value) { } return value; } - + /*package*/ static IConstructor newConstructor(Type constructorType, IValue[] children, Map kwParams) { IConstructor r = newConstructor(constructorType, children); diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/EmptySet.java b/src/main/java/io/usethesource/vallang/impl/persistent/EmptySet.java index d759e3335..a9467066d 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/EmptySet.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/EmptySet.java @@ -136,7 +136,7 @@ public ISet product(ISet that) { public boolean isSubsetOf(ISet other) { return true; } - + @Override public IRelation asRelation() { return new IRelation() { @@ -144,42 +144,42 @@ public IRelation asRelation() { public ISet asContainer() { return EmptySet.this; } - + @Override public ISet compose(IRelation that) { return EmptySet.this; } - + @Override public ISet closure() { return EmptySet.this; } - + @Override public ISet closureStar() { return EmptySet.this; } - + @Override public ISet carrier() { return EmptySet.this; } - + @Override public ISet domain() { return EmptySet.this; } - + @Override public ISet range() { return EmptySet.this; } - + @Override public ISet empty() { return EmptySet.this; } - + @Override public ISet index(IValue key) { return EmptySet.this; diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/List.java b/src/main/java/io/usethesource/vallang/impl/persistent/List.java index e6373e049..47a349905 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/List.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/List.java @@ -192,7 +192,7 @@ IList materializedSublist(int offset, int length){ Type oldElementType = getType().getElementType(); Type newElementType = TypeFactory.getInstance().voidType(); - + for(IValue el : newData) { if (newElementType == oldElementType) { // the type can only get more specific @@ -223,7 +223,7 @@ public boolean equals(@Nullable Object o){ if (o == this) { return true; } - + if (o == null) { return false; } @@ -326,7 +326,7 @@ public boolean equals(@Nullable Object o){ if (o == this) { return true; } - + if (o == null) { return false; } @@ -340,7 +340,7 @@ public boolean equals(@Nullable Object o){ if (o instanceof IList) { return defaultEquals(o); } - + return false; } @@ -503,7 +503,7 @@ public IList replace(int arg0, int arg1, int arg2, IList arg3) { @Override public IList reverse() { ListWriter w = new ListWriter(); - for(int i = offset + length - 1; i >= offset; i--){ + for(int i = offset + length - 1; i >= offset; i--){ w.append(base.get(i)); } return w.done(); diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/ListRelation.java b/src/main/java/io/usethesource/vallang/impl/persistent/ListRelation.java index d029d4fb9..bc895a721 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/ListRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/ListRelation.java @@ -14,12 +14,12 @@ public class ListRelation implements IRelation { public ListRelation(IList list) { this.list = list; } - + @Override public IList asContainer() { return list; } - + @Override public IList closure() { // will throw exception if not binary and reflexive @@ -41,11 +41,11 @@ public IList closure() { w.append(t1); } } - + tmp = tmp.asContainer().concat(w.done()).asRelation(); addedTuples.clear(); } - + return tmp.asContainer(); } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/ListWriter.java b/src/main/java/io/usethesource/vallang/impl/persistent/ListWriter.java index c18220ad7..84b3f9dbe 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/ListWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/ListWriter.java @@ -25,218 +25,218 @@ /** * Implementation of IListWriter. - * + * * @author Arnold Lankamp */ /*package*/ class ListWriter implements IListWriter{ private Type elementType; - private final ShareableValuesList data; - private @MonotonicNonNull IList constructedList; - private final boolean unique; - - /*package*/ ListWriter() { - super(); - - this.elementType = TypeFactory.getInstance().voidType(); - data = new ShareableValuesList(); - unique = false; - } - - private ListWriter(boolean unique) { - this.elementType = TypeFactory.getInstance().voidType(); + private final ShareableValuesList data; + private @MonotonicNonNull IList constructedList; + private final boolean unique; + + /*package*/ ListWriter() { + super(); + + this.elementType = TypeFactory.getInstance().voidType(); + data = new ShareableValuesList(); + unique = false; + } + + private ListWriter(boolean unique) { + this.elementType = TypeFactory.getInstance().voidType(); data = new ShareableValuesList(); - this.unique = unique; - } - - @Override + this.unique = unique; + } + + @Override public IWriter unique() { return new ListWriter(true); } - @Override - public Iterator iterator() { - return data.iterator(); - } - - /*package*/ ListWriter(Type elementType, ShareableValuesList data){ - super(); - - this.elementType = elementType; - this.data = data; - this.unique = false; - } - - @Override - public void insertTuple(IValue... fields) { - insert(Tuple.newTuple(fields)); - } - - public void append(IValue element){ - checkMutation(); - - if (unique && data.contains(element)) { - return; + @Override + public Iterator iterator() { + return data.iterator(); + } + + /*package*/ ListWriter(Type elementType, ShareableValuesList data){ + super(); + + this.elementType = elementType; + this.data = data; + this.unique = false; + } + + @Override + public void insertTuple(IValue... fields) { + insert(Tuple.newTuple(fields)); + } + + public void append(IValue element){ + checkMutation(); + + if (unique && data.contains(element)) { + return; + } + + updateType(element); + data.append(element); + } + + @Override + public void appendTuple(IValue... fields) { + append(Tuple.newTuple(fields)); + } + + private void updateType(IValue element) { + elementType = elementType.lub(element.getType()); + } + + @Override + public void append(IValue... elems){ + checkMutation(); + boolean notUnique = false; + + for (IValue elem : elems){ + if (unique && data.contains(elem)) { + notUnique = true; + break; + } + updateType(elem); + } + + if (!notUnique) { + data.appendAll(elems); + } + else { + for (IValue next : elems) { + if (unique && data.contains(next)) { + continue; + } + + updateType(next); + data.append(next); + } + } + } + + @Override + public void appendAll(Iterable collection){ + checkMutation(); + + for (IValue next : collection) { + if (unique && data.contains(next)) { + continue; + } + + updateType(next); + data.append(next); + } + } + + public void insert(IValue elem){ + checkMutation(); + if (unique && data.contains(elem)) { + return; + } + updateType(elem); + data.insert(elem); + } + + @Override + public void insert(IValue... elements){ + insert(elements, 0, elements.length); + } + + @Override + public void insert(IValue[] elements, int start, int length){ + checkMutation(); + checkBounds(elements, start, length); + + for(int i = start + length - 1; i >= start; i--){ + updateType(elements[i]); + + if (unique && data.contains(elements[i])) { + continue; + } + + data.insert(elements[i]); } - - updateType(element); - data.append(element); - } - - @Override - public void appendTuple(IValue... fields) { - append(Tuple.newTuple(fields)); - } - - private void updateType(IValue element) { - elementType = elementType.lub(element.getType()); - } - - @Override - public void append(IValue... elems){ - checkMutation(); - boolean notUnique = false; - - for (IValue elem : elems){ - if (unique && data.contains(elem)) { - notUnique = true; - break; - } - updateType(elem); - } - - if (!notUnique) { - data.appendAll(elems); - } - else { - for (IValue next : elems) { - if (unique && data.contains(next)) { - continue; - } - - updateType(next); - data.append(next); - } - } - } - - @Override - public void appendAll(Iterable collection){ - checkMutation(); - - for (IValue next : collection) { - if (unique && data.contains(next)) { - continue; - } - - updateType(next); - data.append(next); - } - } - - public void insert(IValue elem){ - checkMutation(); - if (unique && data.contains(elem)) { - return; - } - updateType(elem); - data.insert(elem); - } - - @Override - public void insert(IValue... elements){ - insert(elements, 0, elements.length); - } - - @Override - public void insert(IValue[] elements, int start, int length){ - checkMutation(); - checkBounds(elements, start, length); - - for(int i = start + length - 1; i >= start; i--){ - updateType(elements[i]); - - if (unique && data.contains(elements[i])) { - continue; - } - - data.insert(elements[i]); - } - } - - @Override - public void insertAll(Iterable collection){ - checkMutation(); - - for (IValue next : collection) { - if (unique && data.contains(next)) { + } + + @Override + public void insertAll(Iterable collection){ + checkMutation(); + + for (IValue next : collection) { + if (unique && data.contains(next)) { continue; } - updateType(next); - data.insert(next); - } - } - - @Override - public void insertAt(int index, IValue... elements){ - insertAt(index, elements, 0, 0); - } - - @Override - public void insertAt(int index, IValue[] elements, int start, int length){ - checkMutation(); - checkBounds(elements, start, length); - - for(int i = start + length - 1; i >= start; i--){ - updateType(elements[i]); - data.insertAt(index, elements[i]); - } - } - - @Override - public IValue replaceAt(int index, IValue element){ - checkMutation(); - - updateType(element); - return data.set(index, element); - } - - @Override - public IValue get(int i) throws IndexOutOfBoundsException { - return data.get(i); - } - - @Override - public int length() { - return data.size(); - } - - protected void checkMutation() { - if (constructedList != null) { - throw new UnsupportedOperationException("Mutation of a finalized list is not supported."); - } - } - - private void checkBounds(IValue[] elems, int start, int length){ - if (start < 0) { - throw new ArrayIndexOutOfBoundsException("start < 0"); - } - - if ((start + length) > elems.length) { - throw new ArrayIndexOutOfBoundsException("(start + length) > elems.length"); - } - } - - @Override - public IList done() { - if (constructedList == null) { - constructedList = List.newList(elementType, data); - } - - return constructedList; - } - - @Override - public Supplier> supplier() { - return () -> new ListWriter(); - } + updateType(next); + data.insert(next); + } + } + + @Override + public void insertAt(int index, IValue... elements){ + insertAt(index, elements, 0, 0); + } + + @Override + public void insertAt(int index, IValue[] elements, int start, int length){ + checkMutation(); + checkBounds(elements, start, length); + + for(int i = start + length - 1; i >= start; i--){ + updateType(elements[i]); + data.insertAt(index, elements[i]); + } + } + + @Override + public IValue replaceAt(int index, IValue element){ + checkMutation(); + + updateType(element); + return data.set(index, element); + } + + @Override + public IValue get(int i) throws IndexOutOfBoundsException { + return data.get(i); + } + + @Override + public int length() { + return data.size(); + } + + protected void checkMutation() { + if (constructedList != null) { + throw new UnsupportedOperationException("Mutation of a finalized list is not supported."); + } + } + + private void checkBounds(IValue[] elems, int start, int length){ + if (start < 0) { + throw new ArrayIndexOutOfBoundsException("start < 0"); + } + + if ((start + length) > elems.length) { + throw new ArrayIndexOutOfBoundsException("(start + length) > elems.length"); + } + } + + @Override + public IList done() { + if (constructedList == null) { + constructedList = List.newList(elementType, data); + } + + return constructedList; + } + + @Override + public Supplier> supplier() { + return () -> new ListWriter(); + } } \ No newline at end of file diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/MapWriter.java b/src/main/java/io/usethesource/vallang/impl/persistent/MapWriter.java index 5ec06c50c..b199841c8 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/MapWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/MapWriter.java @@ -29,102 +29,102 @@ final class MapWriter implements IMapWriter { - private AbstractTypeBag keyTypeBag = AbstractTypeBag.of(); - private AbstractTypeBag valTypeBag = AbstractTypeBag.of(); - private final Map.Transient mapContent = Map.Transient.of(); - - private @MonotonicNonNull IMap constructedMap; - - @Override - public void put(IValue key, IValue value) { - checkMutation(); - - final Type keyType = key.getType(); - final Type valType = value.getType(); - - int oldSize = mapContent.size(); - - final IValue replaced = mapContent.__put(key, value); - - if (oldSize == mapContent.size() && replaced == null) { - // update nothing because they key/value pair was already there - } - else if (replaced != null) { - // only update the val since the key was already there - valTypeBag = valTypeBag.decrease(replaced.getType()).increase(valType); - } - else { - // add the new entry for both bags since its entirely new - keyTypeBag = keyTypeBag.increase(keyType); - valTypeBag = valTypeBag.increase(valType); - } - - assert mapContent.size() == keyTypeBag.sum(); - } + private AbstractTypeBag keyTypeBag = AbstractTypeBag.of(); + private AbstractTypeBag valTypeBag = AbstractTypeBag.of(); + private final Map.Transient mapContent = Map.Transient.of(); + + private @MonotonicNonNull IMap constructedMap; + + @Override + public void put(IValue key, IValue value) { + checkMutation(); + + final Type keyType = key.getType(); + final Type valType = value.getType(); + + int oldSize = mapContent.size(); + + final IValue replaced = mapContent.__put(key, value); + + if (oldSize == mapContent.size() && replaced == null) { + // update nothing because they key/value pair was already there + } + else if (replaced != null) { + // only update the val since the key was already there + valTypeBag = valTypeBag.decrease(replaced.getType()).increase(valType); + } + else { + // add the new entry for both bags since its entirely new + keyTypeBag = keyTypeBag.increase(keyType); + valTypeBag = valTypeBag.increase(valType); + } + + assert mapContent.size() == keyTypeBag.sum(); + } @Override - public void putAll(IMap map) { - putAll(map.entryIterator()); - } + public void putAll(IMap map) { + putAll(map.entryIterator()); + } - @Override - public void putAll(java.util.Map map) { - putAll(map.entrySet().iterator()); - } + @Override + public void putAll(java.util.Map map) { + putAll(map.entrySet().iterator()); + } - private void putAll(Iterator> entryIterator) { - checkMutation(); + private void putAll(Iterator> entryIterator) { + checkMutation(); - while (entryIterator.hasNext()) { - Entry entry = entryIterator.next(); - IValue key = entry.getKey(); - IValue value = entry.getValue(); + while (entryIterator.hasNext()) { + Entry entry = entryIterator.next(); + IValue key = entry.getKey(); + IValue value = entry.getValue(); - this.put(key, value); - } - } + this.put(key, value); + } + } - @Override - public void insert(IValue... values) { - insertAll(Arrays.asList(values)); - } + @Override + public void insert(IValue... values) { + insertAll(Arrays.asList(values)); + } - @Override - public void insertAll(Iterable collection) { - checkMutation(); + @Override + public void insertAll(Iterable collection) { + checkMutation(); - Iterator collectionIterator = collection.iterator(); - while (collectionIterator.hasNext()) { - final Object item = collectionIterator.next(); + Iterator collectionIterator = collection.iterator(); + while (collectionIterator.hasNext()) { + final Object item = collectionIterator.next(); - if (!(item instanceof ITuple)) { - throw new IllegalArgumentException("Argument must be of ITuple type."); - } + if (!(item instanceof ITuple)) { + throw new IllegalArgumentException("Argument must be of ITuple type."); + } - final ITuple tuple = (ITuple) item; + final ITuple tuple = (ITuple) item; - if (tuple.arity() != 2) { - throw new IllegalArgumentException("Tuple must have an arity of 2."); - } + if (tuple.arity() != 2) { + throw new IllegalArgumentException("Tuple must have an arity of 2."); + } - put(tuple.get(0), tuple.get(1)); - } - } + put(tuple.get(0), tuple.get(1)); + } + } - protected void checkMutation() { - if (constructedMap != null) { - throw new UnsupportedOperationException("Mutation of a finalized map is not supported."); - } - } + protected void checkMutation() { + if (constructedMap != null) { + throw new UnsupportedOperationException("Mutation of a finalized map is not supported."); + } + } - @Override - public IMap done() { - if (constructedMap == null) { - constructedMap = new PersistentHashMap(keyTypeBag, valTypeBag, mapContent.freeze()); - } + @Override + public IMap done() { + if (constructedMap == null) { + constructedMap = new PersistentHashMap(keyTypeBag, valTypeBag, mapContent.freeze()); + } - return constructedMap; - } + return constructedMap; + } @Override public void insertTuple(IValue... fields) { @@ -135,7 +135,7 @@ public void insertTuple(IValue... fields) { public Iterator iterator() { return mapContent.keyIterator(); } - + @Override public IValue get(IValue key) { return mapContent.get(key); diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/Node.java b/src/main/java/io/usethesource/vallang/impl/persistent/Node.java index 407f13b18..a905228ff 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/Node.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/Node.java @@ -24,130 +24,130 @@ import io.usethesource.vallang.type.TypeFactory; /*package*/ class Node implements INode { - protected static final Type NODE_TYPE = TF.nodeType(); - protected static final Type VALUE_TYPE = TypeFactory.getInstance().valueType(); - - protected final String name; - protected final IValue[] children; - - /*package*/ static INode newNode(String name, IValue[] children) { - return new Node(name, children); - } - - Node(String name, IValue[] children) { - super(); - - this.name = name.intern(); - this.children = children; - } - - /*package*/ static INode newNode(String name, IList children) { - return new Node(name, children); - } - - private Node(String name, IList children) { - super(); - IValue[] childArray = new IValue[children.length()]; - this.name = name.intern(); - for(int i = 0; i < childArray.length; i++){ - childArray[i] = children.get(i); - } - this.children = childArray; - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public Type getType(){ - return NODE_TYPE; - } - - @Override - public int arity(){ - return children.length; - } - - @Override + protected static final Type NODE_TYPE = TF.nodeType(); + protected static final Type VALUE_TYPE = TypeFactory.getInstance().valueType(); + + protected final String name; + protected final IValue[] children; + + /*package*/ static INode newNode(String name, IValue[] children) { + return new Node(name, children); + } + + Node(String name, IValue[] children) { + super(); + + this.name = name.intern(); + this.children = children; + } + + /*package*/ static INode newNode(String name, IList children) { + return new Node(name, children); + } + + private Node(String name, IList children) { + super(); + IValue[] childArray = new IValue[children.length()]; + this.name = name.intern(); + for(int i = 0; i < childArray.length; i++){ + childArray[i] = children.get(i); + } + this.children = childArray; + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public Type getType(){ + return NODE_TYPE; + } + + @Override + public int arity(){ + return children.length; + } + + @Override public INode setChildren(IValue[] childArray) { return new Node(name, childArray); } - - @Override - public IValue get(int i){ - return children[i]; - } - - @Override - public String getName(){ - return name; - } - - @Override - public Iterator iterator(){ - return ArrayIterator.of(children); - } - - @Override - public Iterable getChildren(){ - return this; - } - - @Override - public INode set(int i, IValue arg){ - IValue[] newChildren = children.clone(); - newChildren[i] = arg; - - return newNode(name, newChildren); - } - - @Override - public int hashCode() { - int hash = name.hashCode(); - - for(int i = children.length - 1; i >= 0; i--){ - hash = (hash << 23) + (hash >> 5); - hash ^= children[i].hashCode(); - } - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if (o == this) { - return true; - } - - if (o == null) { - return false; - } - - if (o.getClass() != getClass()) { - return false; - } - - Node other = (Node) o; - - // Yes '!=' works here, since it has been interned. - if (name != other.name) { - return false; - } - - IValue[] otherChildren = other.children; - int nrOfChildren = children.length; - - if (otherChildren.length != nrOfChildren) { - return false; - } - - for (int i = nrOfChildren - 1; i >= 0; i--) { - if (!otherChildren[i].equals(children[i])) { - return false; - } - } - - return true; - } + + @Override + public IValue get(int i){ + return children[i]; + } + + @Override + public String getName(){ + return name; + } + + @Override + public Iterator iterator(){ + return ArrayIterator.of(children); + } + + @Override + public Iterable getChildren(){ + return this; + } + + @Override + public INode set(int i, IValue arg){ + IValue[] newChildren = children.clone(); + newChildren[i] = arg; + + return newNode(name, newChildren); + } + + @Override + public int hashCode() { + int hash = name.hashCode(); + + for(int i = children.length - 1; i >= 0; i--){ + hash = (hash << 23) + (hash >> 5); + hash ^= children[i].hashCode(); + } + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if (o == this) { + return true; + } + + if (o == null) { + return false; + } + + if (o.getClass() != getClass()) { + return false; + } + + Node other = (Node) o; + + // Yes '!=' works here, since it has been interned. + if (name != other.name) { + return false; + } + + IValue[] otherChildren = other.children; + int nrOfChildren = children.length; + + if (otherChildren.length != nrOfChildren) { + return false; + } + + for (int i = nrOfChildren - 1; i >= 0; i--) { + if (!otherChildren[i].equals(children[i])) { + return false; + } + } + + return true; + } } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java index f9c936224..75191d9aa 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java @@ -43,702 +43,702 @@ import io.usethesource.vallang.util.AbstractTypeBag; /** - * Implements both ISet and IRelation, by indexing on the first column - * and reconstructing binary tuples while iterating. This class - * is faster for compose and closure because the index has been pre-computed. - */ +* Implements both ISet and IRelation, by indexing on the first column +* and reconstructing binary tuples while iterating. This class +* is faster for compose and closure because the index has been pre-computed. +*/ public final class PersistentHashIndexedBinaryRelation implements ISet, IRelation { - private @MonotonicNonNull Type cachedRelationType; - private final AbstractTypeBag keyTypeBag; - private final AbstractTypeBag valTypeBag; - private final SetMultimap.Immutable content; - - /** - * Construction of persistent indexed binary relation with multi-map backend. - * - * DO NOT CALL OUTSIDE OF {@link PersistentSetFactory}. - * - * @param keyTypeBag precise dynamic type of first data column - * @param valTypeBag precise dynamic type of second data column - * @param content immutable multi-map - */ - PersistentHashIndexedBinaryRelation(AbstractTypeBag keyTypeBag, AbstractTypeBag valTypeBag, - SetMultimap.Immutable content) { - this.keyTypeBag = Objects.requireNonNull(keyTypeBag); - this.valTypeBag = Objects.requireNonNull(valTypeBag); - this.content = Objects.requireNonNull(content); - - assert USE_MULTIMAP_BINARY_RELATIONS + private @MonotonicNonNull Type cachedRelationType; + private final AbstractTypeBag keyTypeBag; + private final AbstractTypeBag valTypeBag; + private final SetMultimap.Immutable content; + + /** + * Construction of persistent indexed binary relation with multi-map backend. + * + * DO NOT CALL OUTSIDE OF {@link PersistentSetFactory}. + * + * @param keyTypeBag precise dynamic type of first data column + * @param valTypeBag precise dynamic type of second data column + * @param content immutable multi-map + */ + PersistentHashIndexedBinaryRelation(AbstractTypeBag keyTypeBag, AbstractTypeBag valTypeBag, + SetMultimap.Immutable content) { + this.keyTypeBag = Objects.requireNonNull(keyTypeBag); + this.valTypeBag = Objects.requireNonNull(valTypeBag); + this.content = Objects.requireNonNull(content); + + assert USE_MULTIMAP_BINARY_RELATIONS && isTupleOfArityTwo.test(TF.tupleType(keyTypeBag.lub(), valTypeBag.lub())); - assert USE_MULTIMAP_BINARY_RELATIONS && !content.isEmpty(); - assert USE_MULTIMAP_BINARY_RELATIONS && checkDynamicType(keyTypeBag, valTypeBag, content); - } + assert USE_MULTIMAP_BINARY_RELATIONS && !content.isEmpty(); + assert USE_MULTIMAP_BINARY_RELATIONS && checkDynamicType(keyTypeBag, valTypeBag, content); + } - @Override - public IRelation asRelation() { - return this; - } + @Override + public IRelation asRelation() { + return this; + } - private static final boolean checkDynamicType(final AbstractTypeBag keyTypeBag, - final AbstractTypeBag valTypeBag, final SetMultimap.Immutable content) { + private static final boolean checkDynamicType(final AbstractTypeBag keyTypeBag, + final AbstractTypeBag valTypeBag, final SetMultimap.Immutable content) { - final AbstractTypeBag expectedKeyTypeBag = calcTypeBag(content, Map.Entry::getKey); - final AbstractTypeBag expectedValTypeBag = calcTypeBag(content, Map.Entry::getValue); + final AbstractTypeBag expectedKeyTypeBag = calcTypeBag(content, Map.Entry::getKey); + final AbstractTypeBag expectedValTypeBag = calcTypeBag(content, Map.Entry::getValue); - boolean keyTypesEqual = expectedKeyTypeBag.equals(keyTypeBag); - boolean valTypesEqual = expectedValTypeBag.equals(valTypeBag); + boolean keyTypesEqual = expectedKeyTypeBag.equals(keyTypeBag); + boolean valTypesEqual = expectedValTypeBag.equals(valTypeBag); - return keyTypesEqual && valTypesEqual; - } - - @Override - public ISetWriter writer() { - return ValueFactory.getInstance().setWriter(); - } + return keyTypesEqual && valTypesEqual; + } - @Override - public Type getType() { - if (cachedRelationType == null) { - cachedRelationType = TF.relType(keyTypeBag.lub(), valTypeBag.lub()); + @Override + public ISetWriter writer() { + return ValueFactory.getInstance().setWriter(); } - return cachedRelationType; - } - private final BiFunction tupleConverter() { - return (first, second) -> Tuple.newTuple(first, second); - } + @Override + public Type getType() { + if (cachedRelationType == null) { + cachedRelationType = TF.relType(keyTypeBag.lub(), valTypeBag.lub()); + } + return cachedRelationType; + } - @Override - public boolean isEmpty() { - return content.isEmpty(); - } + private final BiFunction tupleConverter() { + return (first, second) -> Tuple.newTuple(first, second); + } - @Override - public ISet insert(IValue value) { - if (!isTupleOfArityTwo.test(value.getType())) { - /* - * NOTE: conversion of set representations are assumed to be scarce, but are costly if they - * happen though. - */ - final Stream tupleStream = content.tupleStream(tupleConverter()); - return Stream.concat(tupleStream, Stream.of(value)).collect(ValueCollectors.toSet()); + @Override + public boolean isEmpty() { + return content.isEmpty(); } - final ITuple tuple = (ITuple) value; - final IValue key = tuple.get(0); - final IValue val = tuple.get(1); + @Override + public ISet insert(IValue value) { + if (!isTupleOfArityTwo.test(value.getType())) { + /* + * NOTE: conversion of set representations are assumed to be scarce, but are costly if they + * happen though. + */ + final Stream tupleStream = content.tupleStream(tupleConverter()); + return Stream.concat(tupleStream, Stream.of(value)).collect(ValueCollectors.toSet()); + } + + final ITuple tuple = (ITuple) value; + final IValue key = tuple.get(0); + final IValue val = tuple.get(1); + + final SetMultimap.Immutable contentNew = content.__insert(key, val); - final SetMultimap.Immutable contentNew = content.__insert(key, val); + if (content == contentNew) { + return this; + } - if (content == contentNew) { - return this; + final AbstractTypeBag keyTypeBagNew = keyTypeBag.increase(key.getType()); + final AbstractTypeBag valTypeBagNew = valTypeBag.increase(val.getType()); + + return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, contentNew); } - final AbstractTypeBag keyTypeBagNew = keyTypeBag.increase(key.getType()); - final AbstractTypeBag valTypeBagNew = valTypeBag.increase(val.getType()); + @Override + public ISet delete(IValue value) { + if (!isTupleOfArityTwo.test(value.getType())) { + return this; + } + + final ITuple tuple = (ITuple) value; + final IValue key = tuple.get(0); + final IValue val = tuple.get(1); + + final SetMultimap.Immutable contentNew = content.__remove(key, val); + + if (content == contentNew) { + return this; + } + + final AbstractTypeBag keyTypeBagNew = keyTypeBag.decrease(key.getType()); + final AbstractTypeBag valTypeBagNew = valTypeBag.decrease(val.getType()); - return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, contentNew); - } + return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, contentNew); + } - @Override - public ISet delete(IValue value) { - if (!isTupleOfArityTwo.test(value.getType())) { - return this; + @Override + public int size() { + return content.size(); } - final ITuple tuple = (ITuple) value; - final IValue key = tuple.get(0); - final IValue val = tuple.get(1); + @Override + public boolean contains(IValue value) { + if (!isTupleOfArityTwo.test(value.getType())) { + return false; + } - final SetMultimap.Immutable contentNew = content.__remove(key, val); + final ITuple tuple = (ITuple) value; + final IValue key = tuple.get(0); + final IValue val = tuple.get(1); - if (content == contentNew) { - return this; + return content.containsEntry(key, val); } - final AbstractTypeBag keyTypeBagNew = keyTypeBag.decrease(key.getType()); - final AbstractTypeBag valTypeBagNew = valTypeBag.decrease(val.getType()); + @Override + public Iterator iterator() { + return content.tupleIterator(Tuple::newTuple); + } - return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, contentNew); - } + @Override + public int hashCode() { + final int hashCode = + StreamSupport.stream(spliterator(), false).mapToInt(tuple -> tuple.hashCode()).sum(); - @Override - public int size() { - return content.size(); - } + return hashCode; + } - @Override - public boolean contains(IValue value) { - if (!isTupleOfArityTwo.test(value.getType())) { - return false; + @Override + public String toString() { + return defaultToString(); } - final ITuple tuple = (ITuple) value; - final IValue key = tuple.get(0); - final IValue val = tuple.get(1); + @Override + public boolean equals(@Nullable Object other) { + if (other == this) { + return true; + } + + if (other == null) { + return false; + } + + if (other instanceof PersistentHashIndexedBinaryRelation) { + PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; - return content.containsEntry(key, val); - } + if (this.getType() != that.getType()) { + return false; + } - @Override - public Iterator iterator() { - return content.tupleIterator(Tuple::newTuple); - } + if (this.size() != that.size()) { + return false; + } - @Override - public int hashCode() { - final int hashCode = - StreamSupport.stream(spliterator(), false).mapToInt(tuple -> tuple.hashCode()).sum(); + return content.equals(that.content); + } - return hashCode; - } - - @Override - public String toString() { - return defaultToString(); - } + if (other instanceof ISet) { + return defaultEquals(other); + } - @Override - public boolean equals(@Nullable Object other) { - if (other == this) { - return true; + return false; } - - if (other == null) { - return false; + + @Override + public ISet union(ISet other) { + if (other == this) { + return this; + } + if (other == null) { + return this; + } + + if (other instanceof PersistentHashIndexedBinaryRelation) { + PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; + + final SetMultimap.Immutable one; + final SetMultimap.Immutable two; + AbstractTypeBag keyTypeBagNew; + AbstractTypeBag valTypeBagNew; + final ISet def; + + if (that.size() >= this.size()) { + def = that; + one = that.content; + keyTypeBagNew = that.keyTypeBag; + valTypeBagNew = that.valTypeBag; + two = this.content; + } else { + def = this; + one = this.content; + keyTypeBagNew = this.keyTypeBag; + valTypeBagNew = this.valTypeBag; + two = that.content; + } + + final SetMultimap.Transient tmp = one.asTransient(); + boolean modified = false; + + for (Map.Entry entry : two.entrySet()) { + final IValue key = entry.getKey(); + final IValue val = entry.getValue(); + + if (tmp.__insert(key, val)) { + modified = true; + keyTypeBagNew = keyTypeBagNew.increase(key.getType()); + valTypeBagNew = valTypeBagNew.increase(val.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); + } + return def; + } else { + return ISet.super.union(other); + } } - if (other instanceof PersistentHashIndexedBinaryRelation) { - PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; + @Override + public ISet intersect(ISet other) { + if (other == this) { + return this; + } + if (other == null) { + return EmptySet.EMPTY_SET; + } + + if (other instanceof PersistentHashIndexedBinaryRelation) { + PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; + + final SetMultimap.Immutable one; + final SetMultimap.Immutable two; + AbstractTypeBag keyTypeBagNew; + AbstractTypeBag valTypeBagNew; + final ISet def; + + if (that.size() >= this.size()) { + def = this; + one = this.content; + keyTypeBagNew = this.keyTypeBag; + valTypeBagNew = this.valTypeBag; + two = that.content; + } else { + def = that; + one = that.content; + keyTypeBagNew = that.keyTypeBag; + valTypeBagNew = that.valTypeBag; + two = this.content; + } - if (this.getType() != that.getType()) { - return false; - } + final SetMultimap.Transient tmp = one.asTransient(); + boolean modified = false; - if (this.size() != that.size()) { - return false; - } + for (Iterator> it = tmp.entryIterator(); it.hasNext(); ) { + final Map.Entry tuple = it.next(); + final IValue key = tuple.getKey(); + final IValue val = tuple.getValue(); + + if (!two.containsEntry(key, val)) { + it.remove(); + modified = true; + keyTypeBagNew = keyTypeBagNew.decrease(key.getType()); + valTypeBagNew = valTypeBagNew.decrease(val.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); + } + return def; + } else { + return ISet.super.intersect(other); + } + } + + @Override + public ISet subtract(ISet other) { + if (other == this) { + return EmptySet.EMPTY_SET; + } + if (other == null) { + return this; + } + + if (other instanceof PersistentHashIndexedBinaryRelation) { + PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; + + final SetMultimap.Immutable one; + final SetMultimap.Immutable two; + AbstractTypeBag keyTypeBagNew; + AbstractTypeBag valTypeBagNew; + final ISet def; + + def = this; + one = this.content; + keyTypeBagNew = this.keyTypeBag; + valTypeBagNew = this.valTypeBag; + two = that.content; + + final SetMultimap.Transient tmp = one.asTransient(); + boolean modified = false; + + for (Map.Entry tuple : two.entrySet()) { + final IValue key = tuple.getKey(); + final IValue val = tuple.getValue(); + + if (tmp.__remove(key, val)) { + modified = true; + keyTypeBagNew = keyTypeBagNew.decrease(key.getType()); + valTypeBagNew = valTypeBagNew.decrease(val.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); + } + return def; + } else { + return ISet.super.subtract(other); + } + } + + @Override + public ISet compose(IRelation otherSetRelation) { + if (otherSetRelation.getClass() != this.getClass()) { + return IRelation.super.compose(otherSetRelation); + } + + // Here we can optimize the compose operation because we have already an index in memory + // for both relations + + final PersistentHashIndexedBinaryRelation thatSet = + (PersistentHashIndexedBinaryRelation) otherSetRelation.asContainer(); + + final SetMultimap.Immutable xy = content; + final SetMultimap.Immutable yz = thatSet.content; + + /** + * The code below is still sub-optimal because it operates on the logical (rather than the structural) level. + * + * TODO: nodes should get proper support for stream processing such that the following template can be used: + * + * // @formatter:off + * final Stream> localStream = null; + * final Node updatedNode = localStream + * .filter((x, y) -> yz.containsKey(y)) + * .mapValues(y -> yz.get(y)) + * .collect(toNode()); + * // @formatter:on + */ + final SetMultimap.Transient xz = xy.asTransient(); + + for (IValue x : xy.keySet()) { + final Set.Immutable ys = xy.get(x); + // TODO: simplify expression with nullable data + final Set.Immutable zs = ys.stream() + .flatMap(y -> Optional.ofNullable(yz.get(y)).orElseGet(Set.Immutable::of).stream()) + .collect(CapsuleCollectors.toSet()); + + if (zs == null) { + xz.__remove(x); + } else { + // xz.__put(x, zs); // TODO: requires node batch update support + + xz.__remove(x); + zs.forEach(z -> xz.__insert(x, z)); + } + } + + final SetMultimap.Immutable data = xz.freeze(); - return content.equals(that.content); - } - - if (other instanceof ISet) { - return defaultEquals(other); - } - - return false; - } - - @Override - public ISet union(ISet other) { - if (other == this) { - return this; - } - if (other == null) { - return this; - } - - if (other instanceof PersistentHashIndexedBinaryRelation) { - PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; - - final SetMultimap.Immutable one; - final SetMultimap.Immutable two; - AbstractTypeBag keyTypeBagNew; - AbstractTypeBag valTypeBagNew; - final ISet def; - - if (that.size() >= this.size()) { - def = that; - one = that.content; - keyTypeBagNew = that.keyTypeBag; - valTypeBagNew = that.valTypeBag; - two = this.content; - } else { - def = this; - one = this.content; - keyTypeBagNew = this.keyTypeBag; - valTypeBagNew = this.valTypeBag; - two = that.content; - } - - final SetMultimap.Transient tmp = one.asTransient(); - boolean modified = false; - - for (Map.Entry entry : two.entrySet()) { - final IValue key = entry.getKey(); - final IValue val = entry.getValue(); - if (tmp.__insert(key, val)) { - modified = true; - keyTypeBagNew = keyTypeBagNew.increase(key.getType()); - valTypeBagNew = valTypeBagNew.increase(val.getType()); - } - } - - if (modified) { - return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); - } - return def; - } else { - return ISet.super.union(other); - } - } - - @Override - public ISet intersect(ISet other) { - if (other == this) { - return this; - } - if (other == null) { - return EmptySet.EMPTY_SET; - } - - if (other instanceof PersistentHashIndexedBinaryRelation) { - PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; - - final SetMultimap.Immutable one; - final SetMultimap.Immutable two; - AbstractTypeBag keyTypeBagNew; - AbstractTypeBag valTypeBagNew; - final ISet def; - - if (that.size() >= this.size()) { - def = this; - one = this.content; - keyTypeBagNew = this.keyTypeBag; - valTypeBagNew = this.valTypeBag; - two = that.content; - } else { - def = that; - one = that.content; - keyTypeBagNew = that.keyTypeBag; - valTypeBagNew = that.valTypeBag; - two = this.content; - } - - final SetMultimap.Transient tmp = one.asTransient(); - boolean modified = false; - - for (Iterator> it = tmp.entryIterator(); it.hasNext(); ) { - final Map.Entry tuple = it.next(); - final IValue key = tuple.getKey(); - final IValue val = tuple.getValue(); - - if (!two.containsEntry(key, val)) { - it.remove(); - modified = true; - keyTypeBagNew = keyTypeBagNew.decrease(key.getType()); - valTypeBagNew = valTypeBagNew.decrease(val.getType()); - } - } - - if (modified) { - return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); - } - return def; - } else { - return ISet.super.intersect(other); - } - } - - @Override - public ISet subtract(ISet other) { - if (other == this) { - return EmptySet.EMPTY_SET; - } - if (other == null) { - return this; - } - - if (other instanceof PersistentHashIndexedBinaryRelation) { - PersistentHashIndexedBinaryRelation that = (PersistentHashIndexedBinaryRelation) other; - - final SetMultimap.Immutable one; - final SetMultimap.Immutable two; - AbstractTypeBag keyTypeBagNew; - AbstractTypeBag valTypeBagNew; - final ISet def; - - def = this; - one = this.content; - keyTypeBagNew = this.keyTypeBag; - valTypeBagNew = this.valTypeBag; - two = that.content; - - final SetMultimap.Transient tmp = one.asTransient(); - boolean modified = false; - - for (Map.Entry tuple : two.entrySet()) { - final IValue key = tuple.getKey(); - final IValue val = tuple.getValue(); - - if (tmp.__remove(key, val)) { - modified = true; - keyTypeBagNew = keyTypeBagNew.decrease(key.getType()); - valTypeBagNew = valTypeBagNew.decrease(val.getType()); - } - } - - if (modified) { - return PersistentSetFactory.from(keyTypeBagNew, valTypeBagNew, tmp.freeze()); - } - return def; - } else { - return ISet.super.subtract(other); - } - } - - @Override - public ISet compose(IRelation otherSetRelation) { - if (otherSetRelation.getClass() != this.getClass()) { - return IRelation.super.compose(otherSetRelation); - } - - // Here we can optimize the compose operation because we have already an index in memory - // for both relations - - final PersistentHashIndexedBinaryRelation thatSet = - (PersistentHashIndexedBinaryRelation) otherSetRelation.asContainer(); - - final SetMultimap.Immutable xy = content; - final SetMultimap.Immutable yz = thatSet.content; - - /** - * The code below is still sub-optimal because it operates on the logical (rather than the structural) level. - * - * TODO: nodes should get proper support for stream processing such that the following template can be used: - * - * // @formatter:off - * final Stream> localStream = null; - * final Node updatedNode = localStream - * .filter((x, y) -> yz.containsKey(y)) - * .mapValues(y -> yz.get(y)) - * .collect(toNode()); - * // @formatter:on - */ - final SetMultimap.Transient xz = xy.asTransient(); - - for (IValue x : xy.keySet()) { - final Set.Immutable ys = xy.get(x); - // TODO: simplify expression with nullable data - final Set.Immutable zs = ys.stream() - .flatMap(y -> Optional.ofNullable(yz.get(y)).orElseGet(Set.Immutable::of).stream()) - .collect(CapsuleCollectors.toSet()); - - if (zs == null) { - xz.__remove(x); - } else { - // xz.__put(x, zs); // TODO: requires node batch update support - - xz.__remove(x); - zs.forEach(z -> xz.__insert(x, z)); - } - } - - final SetMultimap.Immutable data = xz.freeze(); - - - final AbstractTypeBag keyTypeBag = calcTypeBag(data, Map.Entry::getKey); - final AbstractTypeBag valTypeBag = calcTypeBag(data, Map.Entry::getValue); - - return PersistentSetFactory.from(keyTypeBag, valTypeBag, data); - } - - @Override - public int arity() { - return 2; - } - - @Override - public ISet project(int... fieldIndexes) { - if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(0))) { - return domain(); - } - - if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(1))) { - return range(); - } - - if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(0, 1))) { - return this; - } - - // TODO: replace by `inverse` API of subsequent capsule release - if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(1, 0))) { - final SetMultimap.Transient builder = - PersistentTrieSetMultimap.transientOf(Object::equals); - - content.entryIterator().forEachRemaining( - tuple -> builder.__insert(tuple.getValue(), tuple.getKey())); - - - return PersistentSetFactory.from(valTypeBag, keyTypeBag, builder.freeze()); - } - - throw new IllegalStateException("Binary relation patterns exhausted."); - } - - /** - * Flattening Set[Tuple[Tuple[K, V]], _] to Multimap[K, V]. - * - * @return canonical set of keys - */ - @Override - public ISet domain() { - final Type fieldType0 = this.getType().getFieldType(0); - - if (isTupleOfArityTwo.test(fieldType0)) { - // TODO: use lazy keySet view instead of materialized data structure - return this.content.keySet().stream().map(asInstanceOf(ITuple.class)) - .collect(ValueCollectors.toSetMultimap(tuple -> tuple.get(0), tuple -> tuple.get(1))); - } - - /** - * NOTE: the following call to {@code stream().collect(toSet())} is suboptimal because - * {@code thisSet.content.keySet()} already produces the result (modulo dynamic types). The - * usage of streams solely hides the calculation of precise dynamic type of the set. - */ - return this.content.keySet().stream().collect(ValueCollectors.toSet()); - } - - /** - * Flattening Set[Tuple[_, Tuple[K, V]]] to Multimap[K, V]. - * - * @return canonical set of values - */ - @Override - public ISet range() { - return content.values().stream().collect(ValueCollectors.toSet()); - } - - @Override - public ISet index(IValue key) { - Immutable values = content.get(key); - if (values == null) { - return EmptySet.EMPTY_SET; - } - - return PersistentSetFactory.from(values); - } - - @Override - public ISet asContainer() { - return this; - } - - @Override - public Type getElementType() { - return ISet.super.getElementType(); - } - - @Override - public ISet empty() { - return ISet.super.empty(); - } - - private static AbstractTypeBag calcTypeBag(SetMultimap contents, Function, IValue> mapper) { - return contents.entrySet().stream().map(mapper) - .map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); - } - - @Override - public ISet closure() { - Type tupleType = getElementType(); - assert tupleType.getArity() == 2; - Type keyType = tupleType.getFieldType(0); - Type valueType = tupleType.getFieldType(1); - - if (!keyType.comparable(valueType)) { - // if someone tries, then we have a very quick answer - return this; - } - - var result = computeClosure(content); - - final AbstractTypeBag keyTypeBag; - final AbstractTypeBag valTypeBag; - - if (keyType == valueType && isConcreteValueType(keyType)) { - // this means no other types can be introduced other than the originals, - // so iteration is no longer necessary to construct the new type bag - keyTypeBag = AbstractTypeBag.of(keyType, result.size()); - valTypeBag = keyTypeBag; - } - else { - keyTypeBag = calcTypeBag(result, Map.Entry::getKey); - valTypeBag = calcTypeBag(result, Map.Entry::getValue); - } - - return PersistentSetFactory.from(keyTypeBag, valTypeBag, result.freeze()); - } - - private boolean isConcreteValueType(Type keyType) { - return keyType.isSourceLocation() - || keyType.isInteger() - || keyType.isRational() - || keyType.isReal() - || keyType.isDateTime() - || (keyType.isAbstractData() && !keyType.isParameterized()) - || keyType.isString() - || keyType.isBool() - ; - } - - @Override - public ISet closureStar() { - Type tupleType = getElementType(); - assert tupleType.getArity() == 2; - Type keyType = tupleType.getFieldType(0); - Type valueType = tupleType.getFieldType(1); - - var result = computeClosure(content); - - for (var carrier: content.entrySet()) { - result.__insert(carrier.getKey(), carrier.getKey()); - result.__insert(carrier.getValue(), carrier.getValue()); - } - - final AbstractTypeBag keyTypeBag; - final AbstractTypeBag valTypeBag; - - if (keyType == valueType && isConcreteValueType(keyType)) { - // this means no other types can be introduced other than the originals, - // so iteration is no longer necessary to construct the new type bag - keyTypeBag = AbstractTypeBag.of(keyType, result.size()); - valTypeBag = keyTypeBag; - } - else { - keyTypeBag = calcTypeBag(result, Map.Entry::getKey); - valTypeBag = calcTypeBag(result, Map.Entry::getValue); - } - - return PersistentSetFactory.from(keyTypeBag, valTypeBag, result.freeze()); - } - - private static SetMultimap.Transient computeClosure(final SetMultimap.Immutable content) { - return content.size() > 256 - ? computeClosureDepthFirst(content) - : computeClosureBreadthFirst(content) - ; - } - - @SuppressWarnings("unchecked") - private static SetMultimap.Transient computeClosureDepthFirst(final SetMultimap.Immutable content) { - final SetMultimap.Transient result = content.asTransient(); - var todo = new ArrayDeque(); - var done = new HashSet(); // keep track of LHS we already did, so we don't have to go into the depth of them anymore - var mainIt = content.nativeEntryIterator(); - while (mainIt.hasNext()) { - final var focus = mainIt.next(); - final IValue lhs = focus.getKey(); - final Object values =focus.getValue(); - - assert todo.isEmpty(); - if (values instanceof IValue) { - todo.push((IValue)values); - } - else if (values instanceof Set) { - todo.addAll((Set)values); - } - else { - throw new IllegalArgumentException("Unexpected map entry"); - } - // to avoid recalculating `lhs` next time we see it, we mark it as done. - // so that the next time we come across if on the rhs, we know the range is - // already the transitive closure. - // We add it before we've done it, just to avoid scheduling - // when it occurs during the depth scan for lhs. - done.add(lhs); - IValue rhs; - while ((rhs = todo.poll()) != null) { - if (lhs == rhs) { - // no need to handle - continue; - } - boolean rhsDone = done.contains(rhs); - for (IValue composed : result.get(rhs)) { - if (result.__insert(lhs, composed) && !rhsDone) { - todo.push(composed); - } - } - } - } - return result; - } - - @SuppressWarnings("unchecked") - private static SetMultimap.Transient computeClosureBreadthFirst(final SetMultimap.Immutable content) { - /* - * we want to compute the closure of R, which in essence is a composition on itself. - * until nothing changes: - * - * solve(R) { - * R = R o R; - * } - * - * The algorithm below realizes the following things: - * - * - Instead of recomputing the compose for the whole of R, we only have to - * compose for the newly added edges (called todo in the algorithm). - * - Since the LHS of `R o R` will be using the range of R as a lookup in R - * we store the todo in inverse. - * - * In essence the algorithm becomes: - * - * result = R; - * todo = invert(R); - * - * while (todo != {}) { - * composed = fastCompose(todo, R); - * newEdges = composed - result; - * todo = invert(newEdges); - * result += newEdges; - * } - * - * fastCompose(todo, R) = { l * R[r] | <- todo}; - * + final AbstractTypeBag keyTypeBag = calcTypeBag(data, Map.Entry::getKey); + final AbstractTypeBag valTypeBag = calcTypeBag(data, Map.Entry::getValue); + + return PersistentSetFactory.from(keyTypeBag, valTypeBag, data); + } + + @Override + public int arity() { + return 2; + } + + @Override + public ISet project(int... fieldIndexes) { + if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(0))) { + return domain(); + } + + if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(1))) { + return range(); + } + + if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(0, 1))) { + return this; + } + + // TODO: replace by `inverse` API of subsequent capsule release + if (Arrays.equals(fieldIndexes, ArrayUtilsInt.arrayOfInt(1, 0))) { + final SetMultimap.Transient builder = + PersistentTrieSetMultimap.transientOf(Object::equals); + + content.entryIterator().forEachRemaining( + tuple -> builder.__insert(tuple.getValue(), tuple.getKey())); + + + return PersistentSetFactory.from(valTypeBag, keyTypeBag, builder.freeze()); + } + + throw new IllegalStateException("Binary relation patterns exhausted."); + } + + /** + * Flattening Set[Tuple[Tuple[K, V]], _] to Multimap[K, V]. + * + * @return canonical set of keys */ - final SetMultimap.Transient result = content.asTransient(); - - SetMultimap todo = content.inverseMap(); - while (!todo.isEmpty()) { - final SetMultimap.Transient nextTodo = PersistentTrieSetMultimap.transientOf(Object::equals); - - var todoIt = todo.nativeEntryIterator(); - while (todoIt.hasNext()) { - var next = todoIt.next(); - IValue lhs = next.getKey(); - Immutable values = content.get(lhs); - if (!values.isEmpty()) { - Object keys = next.getValue(); - if (keys instanceof IValue) { - singleCompose(result, nextTodo, values, (IValue)keys); - } - else if (keys instanceof Set) { - for (IValue key : (Set)keys) { - singleCompose(result, nextTodo, values, key); + @Override + public ISet domain() { + final Type fieldType0 = this.getType().getFieldType(0); + + if (isTupleOfArityTwo.test(fieldType0)) { + // TODO: use lazy keySet view instead of materialized data structure + return this.content.keySet().stream().map(asInstanceOf(ITuple.class)) + .collect(ValueCollectors.toSetMultimap(tuple -> tuple.get(0), tuple -> tuple.get(1))); + } + + /** + * NOTE: the following call to {@code stream().collect(toSet())} is suboptimal because + * {@code thisSet.content.keySet()} already produces the result (modulo dynamic types). The + * usage of streams solely hides the calculation of precise dynamic type of the set. + */ + return this.content.keySet().stream().collect(ValueCollectors.toSet()); + } + + /** + * Flattening Set[Tuple[_, Tuple[K, V]]] to Multimap[K, V]. + * + * @return canonical set of values + */ + @Override + public ISet range() { + return content.values().stream().collect(ValueCollectors.toSet()); + } + + @Override + public ISet index(IValue key) { + Immutable values = content.get(key); + if (values == null) { + return EmptySet.EMPTY_SET; + } + + return PersistentSetFactory.from(values); + } + + @Override + public ISet asContainer() { + return this; + } + + @Override + public Type getElementType() { + return ISet.super.getElementType(); + } + + @Override + public ISet empty() { + return ISet.super.empty(); + } + + private static AbstractTypeBag calcTypeBag(SetMultimap contents, Function, IValue> mapper) { + return contents.entrySet().stream().map(mapper) + .map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); + } + + @Override + public ISet closure() { + Type tupleType = getElementType(); + assert tupleType.getArity() == 2; + Type keyType = tupleType.getFieldType(0); + Type valueType = tupleType.getFieldType(1); + + if (!keyType.comparable(valueType)) { + // if someone tries, then we have a very quick answer + return this; + } + + var result = computeClosure(content); + + final AbstractTypeBag keyTypeBag; + final AbstractTypeBag valTypeBag; + + if (keyType == valueType && isConcreteValueType(keyType)) { + // this means no other types can be introduced other than the originals, + // so iteration is no longer necessary to construct the new type bag + keyTypeBag = AbstractTypeBag.of(keyType, result.size()); + valTypeBag = keyTypeBag; + } + else { + keyTypeBag = calcTypeBag(result, Map.Entry::getKey); + valTypeBag = calcTypeBag(result, Map.Entry::getValue); + } + + return PersistentSetFactory.from(keyTypeBag, valTypeBag, result.freeze()); + } + + private boolean isConcreteValueType(Type keyType) { + return keyType.isSourceLocation() + || keyType.isInteger() + || keyType.isRational() + || keyType.isReal() + || keyType.isDateTime() + || (keyType.isAbstractData() && !keyType.isParameterized()) + || keyType.isString() + || keyType.isBool() + ; + } + + @Override + public ISet closureStar() { + Type tupleType = getElementType(); + assert tupleType.getArity() == 2; + Type keyType = tupleType.getFieldType(0); + Type valueType = tupleType.getFieldType(1); + + var result = computeClosure(content); + + for (var carrier: content.entrySet()) { + result.__insert(carrier.getKey(), carrier.getKey()); + result.__insert(carrier.getValue(), carrier.getValue()); + } + + final AbstractTypeBag keyTypeBag; + final AbstractTypeBag valTypeBag; + + if (keyType == valueType && isConcreteValueType(keyType)) { + // this means no other types can be introduced other than the originals, + // so iteration is no longer necessary to construct the new type bag + keyTypeBag = AbstractTypeBag.of(keyType, result.size()); + valTypeBag = keyTypeBag; + } + else { + keyTypeBag = calcTypeBag(result, Map.Entry::getKey); + valTypeBag = calcTypeBag(result, Map.Entry::getValue); + } + + return PersistentSetFactory.from(keyTypeBag, valTypeBag, result.freeze()); + } + + private static SetMultimap.Transient computeClosure(final SetMultimap.Immutable content) { + return content.size() > 256 + ? computeClosureDepthFirst(content) + : computeClosureBreadthFirst(content) + ; + } + + @SuppressWarnings("unchecked") + private static SetMultimap.Transient computeClosureDepthFirst(final SetMultimap.Immutable content) { + final SetMultimap.Transient result = content.asTransient(); + var todo = new ArrayDeque(); + var done = new HashSet(); // keep track of LHS we already did, so we don't have to go into the depth of them anymore + var mainIt = content.nativeEntryIterator(); + while (mainIt.hasNext()) { + final var focus = mainIt.next(); + final IValue lhs = focus.getKey(); + final Object values =focus.getValue(); + + assert todo.isEmpty(); + if (values instanceof IValue) { + todo.push((IValue)values); + } + else if (values instanceof Set) { + todo.addAll((Set)values); + } + else { + throw new IllegalArgumentException("Unexpected map entry"); } - } - else { - throw new IllegalArgumentException("Unexpected map entry"); - } + // to avoid recalculating `lhs` next time we see it, we mark it as done. + // so that the next time we come across if on the rhs, we know the range is + // already the transitive closure. + // We add it before we've done it, just to avoid scheduling + // when it occurs during the depth scan for lhs. + done.add(lhs); + IValue rhs; + while ((rhs = todo.poll()) != null) { + if (lhs == rhs) { + // no need to handle + continue; + } + boolean rhsDone = done.contains(rhs); + for (IValue composed : result.get(rhs)) { + if (result.__insert(lhs, composed) && !rhsDone) { + todo.push(composed); + } + } + } + } + return result; + } + + @SuppressWarnings("unchecked") + private static SetMultimap.Transient computeClosureBreadthFirst(final SetMultimap.Immutable content) { + /* + * we want to compute the closure of R, which in essence is a composition on itself. + * until nothing changes: + * + * solve(R) { + * R = R o R; + * } + * + * The algorithm below realizes the following things: + * + * - Instead of recomputing the compose for the whole of R, we only have to + * compose for the newly added edges (called todo in the algorithm). + * - Since the LHS of `R o R` will be using the range of R as a lookup in R + * we store the todo in inverse. + * + * In essence the algorithm becomes: + * + * result = R; + * todo = invert(R); + * + * while (todo != {}) { + * composed = fastCompose(todo, R); + * newEdges = composed - result; + * todo = invert(newEdges); + * result += newEdges; + * } + * + * fastCompose(todo, R) = { l * R[r] | <- todo}; + * + */ + final SetMultimap.Transient result = content.asTransient(); + + SetMultimap todo = content.inverseMap(); + while (!todo.isEmpty()) { + final SetMultimap.Transient nextTodo = PersistentTrieSetMultimap.transientOf(Object::equals); + + var todoIt = todo.nativeEntryIterator(); + while (todoIt.hasNext()) { + var next = todoIt.next(); + IValue lhs = next.getKey(); + Immutable values = content.get(lhs); + if (!values.isEmpty()) { + Object keys = next.getValue(); + if (keys instanceof IValue) { + singleCompose(result, nextTodo, values, (IValue)keys); + } + else if (keys instanceof Set) { + for (IValue key : (Set)keys) { + singleCompose(result, nextTodo, values, key); + } + } + else { + throw new IllegalArgumentException("Unexpected map entry"); + } + } + } + + todo = nextTodo; } - } - todo = nextTodo; + return result; } - - return result; - } - private static void singleCompose(final SetMultimap.Transient result, - final SetMultimap.Transient nextTodo, Immutable values, IValue key) { - for (IValue val: values) { - if (result.__insert(key, val)) { - nextTodo.__insert(val, key); - } + private static void singleCompose(final SetMultimap.Transient result, + final SetMultimap.Transient nextTodo, Immutable values, IValue key) { + for (IValue val: values) { + if (result.__insert(key, val)) { + nextTodo.__insert(val, key); + } + } } - } } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashMap.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashMap.java index 03ddc37bd..3a2f2f815 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashMap.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashMap.java @@ -31,200 +31,200 @@ public final class PersistentHashMap implements IMap { - private @MonotonicNonNull Type cachedMapType; - private final AbstractTypeBag keyTypeBag; - private final AbstractTypeBag valTypeBag; - private final Map.Immutable<@NonNull IValue, @NonNull IValue> content; - - /* - * Passing an pre-calulated map type is only allowed from inside this class. - */ - protected PersistentHashMap(AbstractTypeBag keyTypeBag, AbstractTypeBag valTypeBag, Map.Immutable<@NonNull IValue, @NonNull IValue> content) { - this.keyTypeBag = keyTypeBag; - this.valTypeBag = valTypeBag; - this.content = content; - assert content.size() == keyTypeBag.sum(); - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public Type getType() { - if (cachedMapType == null) { - cachedMapType = TF.mapType(keyTypeBag.lub(), valTypeBag.lub()); - } - - return cachedMapType; - } - - @Override - public boolean isEmpty() { - return content.isEmpty(); - } - - @Override - public IMap put(IValue key, IValue value) { - final Map.Immutable contentNew = - content.__put(key, value); - - if (content == contentNew) - return this; - - final AbstractTypeBag keyBagNew; - final AbstractTypeBag valBagNew; - - if (content.size() == contentNew.size()) { - // value replaced - final IValue replaced = content.get(key); - keyBagNew = keyTypeBag; - valBagNew = valTypeBag.decrease(replaced.getType()).increase(value.getType()); - } else { - // pair added - keyBagNew = keyTypeBag.increase(key.getType()); - valBagNew = valTypeBag.increase(value.getType()); - } - - return new PersistentHashMap(keyBagNew, valBagNew, contentNew); - } - - @Override - public IMap removeKey(IValue key) { - final Map.Immutable newContent = content.__remove(key); - - if (newContent == content) { - return this; - } - - // this only happens if something has actually been removed: - final IValue removedValue = content.get(key); - final AbstractTypeBag newKeyBag = keyTypeBag.decrease(key.getType()); - final AbstractTypeBag newValBag = valTypeBag.decrease(removedValue.getType()); - - assert !newContent.isEmpty() || (newKeyBag.lub().isBottom() && newValBag.lub().isBottom()); - return new PersistentHashMap(newKeyBag, newValBag, newContent); - } - - @Override - public int size() { - return content.size(); - } - - @Override - @EnsuresNonNullIf(expression="get(#1)", result=true) + private @MonotonicNonNull Type cachedMapType; + private final AbstractTypeBag keyTypeBag; + private final AbstractTypeBag valTypeBag; + private final Map.Immutable<@NonNull IValue, @NonNull IValue> content; + + /* + * Passing an pre-calulated map type is only allowed from inside this class. + */ + protected PersistentHashMap(AbstractTypeBag keyTypeBag, AbstractTypeBag valTypeBag, Map.Immutable<@NonNull IValue, @NonNull IValue> content) { + this.keyTypeBag = keyTypeBag; + this.valTypeBag = valTypeBag; + this.content = content; + assert content.size() == keyTypeBag.sum(); + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public Type getType() { + if (cachedMapType == null) { + cachedMapType = TF.mapType(keyTypeBag.lub(), valTypeBag.lub()); + } + + return cachedMapType; + } + + @Override + public boolean isEmpty() { + return content.isEmpty(); + } + + @Override + public IMap put(IValue key, IValue value) { + final Map.Immutable contentNew = + content.__put(key, value); + + if (content == contentNew) + return this; + + final AbstractTypeBag keyBagNew; + final AbstractTypeBag valBagNew; + + if (content.size() == contentNew.size()) { + // value replaced + final IValue replaced = content.get(key); + keyBagNew = keyTypeBag; + valBagNew = valTypeBag.decrease(replaced.getType()).increase(value.getType()); + } else { + // pair added + keyBagNew = keyTypeBag.increase(key.getType()); + valBagNew = valTypeBag.increase(value.getType()); + } + + return new PersistentHashMap(keyBagNew, valBagNew, contentNew); + } + + @Override + public IMap removeKey(IValue key) { + final Map.Immutable newContent = content.__remove(key); + + if (newContent == content) { + return this; + } + + // this only happens if something has actually been removed: + final IValue removedValue = content.get(key); + final AbstractTypeBag newKeyBag = keyTypeBag.decrease(key.getType()); + final AbstractTypeBag newValBag = valTypeBag.decrease(removedValue.getType()); + + assert !newContent.isEmpty() || (newKeyBag.lub().isBottom() && newValBag.lub().isBottom()); + return new PersistentHashMap(newKeyBag, newValBag, newContent); + } + + @Override + public int size() { + return content.size(); + } + + @Override + @EnsuresNonNullIf(expression="get(#1)", result=true) @SuppressWarnings({"contracts.conditional.postcondition"}) // that's impossible to prove for the Checker Framework - public boolean containsKey(IValue key) { - return content.containsKey(key); - } - - @Override - public boolean containsValue(IValue value) { - return content.containsValue(value); - } - - @Override - public IValue get(IValue key) { - return content.get(key); - } - - @Override - public int hashCode() { - return content.hashCode(); - } - - @Override - public boolean equals(@Nullable Object other) { - if (other == this) { - return true; - } - - if (other == null) { - return false; - } - - - - if (other instanceof PersistentHashMap) { - PersistentHashMap that = (PersistentHashMap) other; - - if (this.getType() != that.getType()) - return false; - - if (this.size() != that.size()) - return false; - - return content.equals(that.content); - } - - if (other instanceof IMap) { - return defaultEquals(other); - } - - return false; - } - - @Override - public Iterator iterator() { - return content.keyIterator(); - } - - @Override - public Iterator valueIterator() { - return content.valueIterator(); - } - - @Override - public Iterator> entryIterator() { - return content.entryIterator(); - } - - @Override - public IMap join(IMap other) { - if (other instanceof PersistentHashMap) { - PersistentHashMap that = (PersistentHashMap) other; - - final Map.Transient transientContent = content.asTransient(); - - boolean isModified = false; - int previousSize = size(); - - AbstractTypeBag keyBagNew = keyTypeBag; - AbstractTypeBag valBagNew = valTypeBag; - - for (Iterator> it = that.entryIterator(); it.hasNext();) { - Entry tuple = it.next(); - IValue key = tuple.getKey(); - IValue value = tuple.getValue(); - - final IValue replaced = transientContent.__put(key, value); - - if (replaced != null) { - // value replaced - valBagNew = valBagNew.decrease(replaced.getType()).increase(value.getType()); - - isModified = true; - } else if (previousSize != transientContent.size()) { - // pair added - keyBagNew = keyBagNew.increase(key.getType()); - valBagNew = valBagNew.increase(value.getType()); - - isModified = true; - previousSize++; - } - } - - if (isModified) { - return new PersistentHashMap(keyBagNew, valBagNew, transientContent.freeze()); - } else { - return this; - } - } else { - return IMap.super.join(other); - } - } - + public boolean containsKey(IValue key) { + return content.containsKey(key); + } + + @Override + public boolean containsValue(IValue value) { + return content.containsValue(value); + } + + @Override + public IValue get(IValue key) { + return content.get(key); + } + + @Override + public int hashCode() { + return content.hashCode(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (other == this) { + return true; + } + + if (other == null) { + return false; + } + + + + if (other instanceof PersistentHashMap) { + PersistentHashMap that = (PersistentHashMap) other; + + if (this.getType() != that.getType()) + return false; + + if (this.size() != that.size()) + return false; + + return content.equals(that.content); + } + + if (other instanceof IMap) { + return defaultEquals(other); + } + + return false; + } + + @Override + public Iterator iterator() { + return content.keyIterator(); + } + + @Override + public Iterator valueIterator() { + return content.valueIterator(); + } + + @Override + public Iterator> entryIterator() { + return content.entryIterator(); + } + + @Override + public IMap join(IMap other) { + if (other instanceof PersistentHashMap) { + PersistentHashMap that = (PersistentHashMap) other; + + final Map.Transient transientContent = content.asTransient(); + + boolean isModified = false; + int previousSize = size(); + + AbstractTypeBag keyBagNew = keyTypeBag; + AbstractTypeBag valBagNew = valTypeBag; + + for (Iterator> it = that.entryIterator(); it.hasNext();) { + Entry tuple = it.next(); + IValue key = tuple.getKey(); + IValue value = tuple.getValue(); + + final IValue replaced = transientContent.__put(key, value); + + if (replaced != null) { + // value replaced + valBagNew = valBagNew.decrease(replaced.getType()).increase(value.getType()); + + isModified = true; + } else if (previousSize != transientContent.size()) { + // pair added + keyBagNew = keyBagNew.increase(key.getType()); + valBagNew = valBagNew.increase(value.getType()); + + isModified = true; + previousSize++; + } + } + + if (isModified) { + return new PersistentHashMap(keyBagNew, valBagNew, transientContent.freeze()); + } else { + return this; + } + } else { + return IMap.super.join(other); + } + } + @Override public Type getElementType() { return keyTypeBag.lub(); @@ -244,7 +244,7 @@ public IMapWriter writer() { public Stream stream() { return StreamSupport.stream(spliterator(), false).map(key -> Tuple.newTuple(key, get(key))); } - + @Override public IRelation asRelation() { throw new UnsupportedOperationException(); diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashSet.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashSet.java index feff8c3e6..ba1422557 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashSet.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashSet.java @@ -25,273 +25,273 @@ import io.usethesource.vallang.util.AbstractTypeBag; public final class PersistentHashSet implements ISet { - private @Nullable Type cachedSetType = null; - private final AbstractTypeBag elementTypeBag; - private final Set.Immutable content; - - /** - * Construction of persistent hash-set. - * - * DO NOT CALL OUTSIDE OF {@link PersistentSetFactory}. - * - * @param elementTypeBag precise dynamic type - * @param content immutable set - */ - PersistentHashSet(AbstractTypeBag elementTypeBag, Set.Immutable content) { - this.elementTypeBag = Objects.requireNonNull(elementTypeBag); - this.content = Objects.requireNonNull(content); - - assert checkDynamicType(elementTypeBag, content); - assert !(elementTypeBag.lub() == TF.voidType() || content.isEmpty()); - } - - @Override - public String toString() { - return defaultToString(); - } - - private static final boolean checkDynamicType(final AbstractTypeBag elementTypeBag, - final Set.Immutable content) { - - final AbstractTypeBag expectedElementTypeBag = - content.stream().map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); - - boolean expectedTypesEqual = expectedElementTypeBag.equals(elementTypeBag); - - return expectedTypesEqual; - } - - @Override - public ISetWriter writer() { - return ValueFactory.getInstance().setWriter(); - } - - @Override - public Type getType() { - if (cachedSetType == null) { - cachedSetType = TF.setType(elementTypeBag.lub()); + private @Nullable Type cachedSetType = null; + private final AbstractTypeBag elementTypeBag; + private final Set.Immutable content; + + /** + * Construction of persistent hash-set. + * + * DO NOT CALL OUTSIDE OF {@link PersistentSetFactory}. + * + * @param elementTypeBag precise dynamic type + * @param content immutable set + */ + PersistentHashSet(AbstractTypeBag elementTypeBag, Set.Immutable content) { + this.elementTypeBag = Objects.requireNonNull(elementTypeBag); + this.content = Objects.requireNonNull(content); + + assert checkDynamicType(elementTypeBag, content); + assert !(elementTypeBag.lub() == TF.voidType() || content.isEmpty()); } - - return cachedSetType; - } - - @Override - public boolean isEmpty() { - return content.isEmpty(); - } - - @Override - public ISet insert(IValue value) { - final Set.Immutable contentNew = - content.__insert(value); - - if (content == contentNew) - return this; - - final AbstractTypeBag bagNew = elementTypeBag.increase(value.getType()); - - return PersistentSetFactory.from(bagNew, contentNew); - } - - @Override - public ISet delete(IValue value) { - final Set.Immutable contentNew = - content.__remove(value); - - if (content == contentNew) - return this; - - final AbstractTypeBag bagNew = elementTypeBag.decrease(value.getType()); - - return PersistentSetFactory.from(bagNew, contentNew); - } - - @Override - public int size() { - return content.size(); - } - - @Override - public boolean contains(IValue value) { - return content.contains(value); - } - - @Override - public Iterator iterator() { - return content.iterator(); - } - - @Override - public int hashCode() { - return content.hashCode(); - } - - @Override - public boolean equals(@Nullable Object other) { - if (other == this) { - return true; + + @Override + public String toString() { + return defaultToString(); } - - if (other == null) { - return false; + + private static final boolean checkDynamicType(final AbstractTypeBag elementTypeBag, + final Set.Immutable content) { + + final AbstractTypeBag expectedElementTypeBag = + content.stream().map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); + + boolean expectedTypesEqual = expectedElementTypeBag.equals(elementTypeBag); + + return expectedTypesEqual; } - if (other instanceof PersistentHashSet) { - PersistentHashSet that = (PersistentHashSet) other; + @Override + public ISetWriter writer() { + return ValueFactory.getInstance().setWriter(); + } - if (this.getType() != that.getType()) { - return false; - } + @Override + public Type getType() { + if (cachedSetType == null) { + cachedSetType = TF.setType(elementTypeBag.lub()); + } - if (this.size() != that.size()) { - return false; - } + return cachedSetType; + } - return content.equals(that.content); + @Override + public boolean isEmpty() { + return content.isEmpty(); } - if (other instanceof ISet) { - return defaultEquals(other); + @Override + public ISet insert(IValue value) { + final Set.Immutable contentNew = + content.__insert(value); + + if (content == contentNew) + return this; + + final AbstractTypeBag bagNew = elementTypeBag.increase(value.getType()); + + return PersistentSetFactory.from(bagNew, contentNew); } - return false; - } + @Override + public ISet delete(IValue value) { + final Set.Immutable contentNew = + content.__remove(value); + + if (content == contentNew) + return this; - @Override - public ISet union(ISet other) { - if (other == this) { - return this; + final AbstractTypeBag bagNew = elementTypeBag.decrease(value.getType()); + + return PersistentSetFactory.from(bagNew, contentNew); } - - if (other instanceof PersistentHashSet) { - PersistentHashSet that = (PersistentHashSet) other; - - final Set.Immutable one; - final Set.Immutable two; - AbstractTypeBag bag; - final ISet def; - - if (that.size() >= this.size()) { - def = that; - one = that.content; - bag = that.elementTypeBag; - two = this.content; - } else { - def = this; - one = this.content; - bag = this.elementTypeBag; - two = that.content; - } - - final Set.Transient tmp = one.asTransient(); - boolean modified = false; - - for (IValue key : two) { - if (tmp.__insert(key)) { - modified = true; - bag = bag.increase(key.getType()); - } - } - - if (modified) { - return PersistentSetFactory.from(bag, tmp.freeze()); - } - return def; - } else { - return ISet.super.union(other); + + @Override + public int size() { + return content.size(); } - } - @Override - public ISet intersect(ISet other) { - if (other == this) { - return this; + @Override + public boolean contains(IValue value) { + return content.contains(value); } - if (other instanceof PersistentHashSet) { - PersistentHashSet that = (PersistentHashSet) other; - - final Set.Immutable one; - final Set.Immutable two; - AbstractTypeBag bag; - final ISet def; - - if (that.size() >= this.size()) { - def = this; - one = this.content; - bag = this.elementTypeBag; - two = that.content; - } else { - def = that; - one = that.content; - bag = that.elementTypeBag; - two = this.content; - } - - final Set.Transient tmp = one.asTransient(); - boolean modified = false; - - for (Iterator it = tmp.iterator(); it.hasNext();) { - final IValue key = it.next(); - if (!two.contains(key)) { - it.remove(); - modified = true; - bag = bag.decrease(key.getType()); - } - } - - if (modified) { - return PersistentSetFactory.from(bag, tmp.freeze()); - } - return def; - } else { - return ISet.super.intersect(other); + @Override + public Iterator iterator() { + return content.iterator(); } - } - @Override - public ISet subtract(ISet other) { - if (other == this) { - return EmptySet.EMPTY_SET; + @Override + public int hashCode() { + return content.hashCode(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (other == this) { + return true; + } + + if (other == null) { + return false; + } + + if (other instanceof PersistentHashSet) { + PersistentHashSet that = (PersistentHashSet) other; + + if (this.getType() != that.getType()) { + return false; + } + + if (this.size() != that.size()) { + return false; + } + + return content.equals(that.content); + } + + if (other instanceof ISet) { + return defaultEquals(other); + } + + return false; } - - if (other == null) { - return this; + + @Override + public ISet union(ISet other) { + if (other == this) { + return this; + } + + if (other instanceof PersistentHashSet) { + PersistentHashSet that = (PersistentHashSet) other; + + final Set.Immutable one; + final Set.Immutable two; + AbstractTypeBag bag; + final ISet def; + + if (that.size() >= this.size()) { + def = that; + one = that.content; + bag = that.elementTypeBag; + two = this.content; + } else { + def = this; + one = this.content; + bag = this.elementTypeBag; + two = that.content; + } + + final Set.Transient tmp = one.asTransient(); + boolean modified = false; + + for (IValue key : two) { + if (tmp.__insert(key)) { + modified = true; + bag = bag.increase(key.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(bag, tmp.freeze()); + } + return def; + } else { + return ISet.super.union(other); + } } - if (other instanceof PersistentHashSet) { - PersistentHashSet that = (PersistentHashSet) other; + @Override + public ISet intersect(ISet other) { + if (other == this) { + return this; + } - final Set.Immutable one; - final Set.Immutable two; - AbstractTypeBag bag; - final ISet def; + if (other instanceof PersistentHashSet) { + PersistentHashSet that = (PersistentHashSet) other; + + final Set.Immutable one; + final Set.Immutable two; + AbstractTypeBag bag; + final ISet def; + + if (that.size() >= this.size()) { + def = this; + one = this.content; + bag = this.elementTypeBag; + two = that.content; + } else { + def = that; + one = that.content; + bag = that.elementTypeBag; + two = this.content; + } + + final Set.Transient tmp = one.asTransient(); + boolean modified = false; + + for (Iterator it = tmp.iterator(); it.hasNext();) { + final IValue key = it.next(); + if (!two.contains(key)) { + it.remove(); + modified = true; + bag = bag.decrease(key.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(bag, tmp.freeze()); + } + return def; + } else { + return ISet.super.intersect(other); + } + } - def = this; - one = this.content; - bag = this.elementTypeBag; - two = that.content; + @Override + public ISet subtract(ISet other) { + if (other == this) { + return EmptySet.EMPTY_SET; + } - final Set.Transient tmp = one.asTransient(); - boolean modified = false; + if (other == null) { + return this; + } - for (IValue key : two) { - if (tmp.__remove(key)) { - modified = true; - bag = bag.decrease(key.getType()); + if (other instanceof PersistentHashSet) { + PersistentHashSet that = (PersistentHashSet) other; + + final Set.Immutable one; + final Set.Immutable two; + AbstractTypeBag bag; + final ISet def; + + def = this; + one = this.content; + bag = this.elementTypeBag; + two = that.content; + + final Set.Transient tmp = one.asTransient(); + boolean modified = false; + + for (IValue key : two) { + if (tmp.__remove(key)) { + modified = true; + bag = bag.decrease(key.getType()); + } + } + + if (modified) { + return PersistentSetFactory.from(bag, tmp.freeze()); + } + return def; + } else { + return ISet.super.subtract(other); } - } - - if (modified) { - return PersistentSetFactory.from(bag, tmp.freeze()); - } - return def; - } else { - return ISet.super.subtract(other); } - } - - @Override + + @Override public IRelation asRelation() { return new PersistentSetRelation(this); } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetFactory.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetFactory.java index 04d05b4e9..d822d5689 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetFactory.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetFactory.java @@ -23,74 +23,74 @@ import io.usethesource.vallang.util.AbstractTypeBag; /** - * Smart constructors for choosing (or converting to) the most appropriate representations based on - * dynamic types and data. - */ +* Smart constructors for choosing (or converting to) the most appropriate representations based on +* dynamic types and data. +*/ /*package*/ class PersistentSetFactory { - /** - * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation - * by recovering the precise dynamic type. - * - * @param content internal set representation of an {@link ISet} - * @return appropriate {@link ISet} based on data and type - */ - static final ISet from(final Set.Immutable content) { - - if (content.isEmpty()) { - return EmptySet.EMPTY_SET; - } - - // recover precise dynamic type - final AbstractTypeBag elementTypeBag = - content.stream().map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); - - return from(elementTypeBag, content); - } - - /** - * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation. - * - * @param keyTypeBag precise dynamic type of first data column - * @param valTypeBag precise dynamic type of second data column - * @param content internal multi-map representation of an {@link ISet} - * @return appropriate {@link ISet} based on data and type - */ - static final ISet from(final AbstractTypeBag keyTypeBag, final AbstractTypeBag valTypeBag, - final SetMultimap.Immutable content) { - - if (content.isEmpty()) { - return EmptySet.EMPTY_SET; - } + /** + * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation + * by recovering the precise dynamic type. + * + * @param content internal set representation of an {@link ISet} + * @return appropriate {@link ISet} based on data and type + */ + static final ISet from(final Set.Immutable content) { - // keep current representation - return new PersistentHashIndexedBinaryRelation(keyTypeBag, valTypeBag, content); - } + if (content.isEmpty()) { + return EmptySet.EMPTY_SET; + } - /** - * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation. - * - * @param elementTypeBag precise dynamic type of elements of a collection - * @param content internal set representation of an {@link ISet} - * @return appropriate {@link ISet} based on data and type - */ - static final ISet from(final AbstractTypeBag elementTypeBag, - final Set.Immutable content) { + // recover precise dynamic type + final AbstractTypeBag elementTypeBag = + content.stream().map(IValue::getType).collect(AbstractTypeBag.toTypeBag()); - final Type elementType = elementTypeBag.lub(); - - if (elementType.isBottom()) { - return EmptySet.EMPTY_SET; + return from(elementTypeBag, content); } - if (isTupleOfArityTwo.test(elementType)) { - // convert to binary relation - return content.stream().map(asInstanceOf(ITuple.class)) - .collect(ValueCollectors.toSetMultimap(tuple -> tuple.get(0), tuple -> tuple.get(1))); + /** + * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation. + * + * @param keyTypeBag precise dynamic type of first data column + * @param valTypeBag precise dynamic type of second data column + * @param content internal multi-map representation of an {@link ISet} + * @return appropriate {@link ISet} based on data and type + */ + static final ISet from(final AbstractTypeBag keyTypeBag, final AbstractTypeBag valTypeBag, + final SetMultimap.Immutable content) { + + if (content.isEmpty()) { + return EmptySet.EMPTY_SET; + } + + // keep current representation + return new PersistentHashIndexedBinaryRelation(keyTypeBag, valTypeBag, content); } - // keep current representation - return new PersistentHashSet(elementTypeBag, content); - } + /** + * Creating an {@link ISet} instance from a {@link SetMultimap.Immutable} representation. + * + * @param elementTypeBag precise dynamic type of elements of a collection + * @param content internal set representation of an {@link ISet} + * @return appropriate {@link ISet} based on data and type + */ + static final ISet from(final AbstractTypeBag elementTypeBag, + final Set.Immutable content) { + + final Type elementType = elementTypeBag.lub(); + + if (elementType.isBottom()) { + return EmptySet.EMPTY_SET; + } + + if (isTupleOfArityTwo.test(elementType)) { + // convert to binary relation + return content.stream().map(asInstanceOf(ITuple.class)) + .collect(ValueCollectors.toSetMultimap(tuple -> tuple.get(0), tuple -> tuple.get(1))); + } + + // keep current representation + return new PersistentHashSet(elementTypeBag, content); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetRelation.java b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetRelation.java index fd83654d7..f226d3cfc 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentSetRelation.java @@ -16,7 +16,7 @@ public class PersistentSetRelation implements IRelation { public PersistentSetRelation(ISet set) { this.set = set; } - + @Override public ISet asContainer() { return set; diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/SetWriter.java b/src/main/java/io/usethesource/vallang/impl/persistent/SetWriter.java index 03683b1e3..907c44d29 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/SetWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/SetWriter.java @@ -164,14 +164,14 @@ private void put(IValue element) { } else if (builder == null) { // first values was not a binary tuple, so let's build a normal set - builder = new SetBuilder(); + builder = new SetBuilder(); } else if (builder instanceof MultiMapBuilder) { // special case, previous values were all binary tuples, but the new value isn't MultiMapBuilder oldBuilder = (MultiMapBuilder) builder; builder = new SetBuilder(); final Builder finalSetBuilder = builder; - oldBuilder.map.tupleStream(constructTuple).forEach(t -> finalSetBuilder.put(t, t.getType())); + oldBuilder.map.tupleStream(constructTuple).forEach(t -> finalSetBuilder.put(t, t.getType())); } } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/Tuple.java b/src/main/java/io/usethesource/vallang/impl/persistent/Tuple.java index 30bdfa976..ce3c7cd2b 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/Tuple.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/Tuple.java @@ -23,178 +23,178 @@ import io.usethesource.vallang.visitors.IValueVisitor; /*package*/ class Tuple implements ITuple{ - protected static final TypeFactory typeFactory = TypeFactory.getInstance(); - private @MonotonicNonNull Type cachedTupleType; - protected final IValue[] elements; - - private static final ITuple EMPTY_TUPLE = new Tuple(); - - public static ITuple newTuple(IValue... elements) { - if (elements.length == 0) { - return EMPTY_TUPLE; - } - return new Tuple(elements); - } - - private Tuple(IValue... elements) { - super(); - - this.elements = elements; - } - - @Override - public Type getType() { - if (cachedTupleType == null) { - cachedTupleType = TypeFactory.getInstance().tupleType(elements); - } - - return cachedTupleType; - } - - @Override - public int arity() { - return elements.length; - } - - @Override - public IValue get(int i) { - return elements[i]; - } - - @Override - public IValue get(String label) { - return elements[getType().getFieldIndex(label)]; - } - - @Override - public Iterator iterator() { - return new TupleIterator(this); - } - - @Override - public T accept(IValueVisitor v) throws E { - return v.visitTuple(this); - } - - @Override - public ITuple set(int index, IValue arg) { - int nrOfElements = elements.length; - IValue[] newElements = new IValue[nrOfElements]; - Type[] elementTypes = new Type[nrOfElements]; - for (int i = nrOfElements - 1; i >= 0; i--) { - IValue element = elements[i]; - newElements[i] = element; - elementTypes[i] = element.getType(); - } - - newElements[index] = arg; - elementTypes[index] = arg.getType(); - - return new Tuple(newElements); - } - - @Override - public ITuple set(String label, IValue arg) { - int nrOfElements = elements.length; - IValue[] newElements = new IValue[nrOfElements]; - Type[] elementTypes = new Type[nrOfElements]; - for (int i = nrOfElements - 1; i >= 0; i--) { - IValue element = elements[i]; - newElements[i] = element; - elementTypes[i] = element.getType(); - } - - newElements[getType().getFieldIndex(label)] = arg; - elementTypes[getType().getFieldIndex(label)] = arg.getType(); - - return new Tuple(newElements); - } - - @Override - public IValue select(int... indexes) { - if (indexes.length == 1) - return get(indexes[0]); - - int nrOfElements = indexes.length; - IValue[] elements = new IValue[nrOfElements]; - Type[] elementTypes = new Type[nrOfElements]; - for (int i = nrOfElements - 1; i >= 0; i--) { - IValue element = get(indexes[i]); - elements[i] = element; - elementTypes[i] = element.getType(); - } - - return new Tuple(elements); - } - - @Override - public IValue selectByFieldNames(String... fields) { - if (fields.length == 1) - return get(fields[0]); - - int nrOfElements = fields.length; - IValue[] elements = new IValue[nrOfElements]; - Type[] elementTypes = new Type[nrOfElements]; - for (int i = nrOfElements - 1; i >= 0; i--) { - IValue element = get(fields[i]); - elements[i] = element; - elementTypes[i] = element.getType(); - } - - return new Tuple(elements); - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public int hashCode() { - int hash = 1331; - - for (int i = elements.length - 1; i >= 0; i--) { - hash -= (hash << 19) + (hash >>> 8); - hash ^= elements[i].hashCode(); - } - - return hash - (hash << 7); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == this) { - return true; - } - - if (o == null) { - return false; - } - - if (o.getClass() == getClass()) { - Tuple otherTuple = (Tuple) o; - - // checking for the type will dynamically allocate memory - // because tuple types are computed lazily. - // so we skip this "fast failure" check - // if (getType() != otherTuple.getType()) { return false; } - - - IValue[] otherElements = otherTuple.elements; - int nrOfElements = elements.length; - if (otherElements.length == nrOfElements) { - for (int i = nrOfElements - 1; i >= 0; i--) { - if (!otherElements[i].equals(elements[i])) - return false; - } - return true; - } - } - - return false; - } - - @Override + protected static final TypeFactory typeFactory = TypeFactory.getInstance(); + private @MonotonicNonNull Type cachedTupleType; + protected final IValue[] elements; + + private static final ITuple EMPTY_TUPLE = new Tuple(); + + public static ITuple newTuple(IValue... elements) { + if (elements.length == 0) { + return EMPTY_TUPLE; + } + return new Tuple(elements); + } + + private Tuple(IValue... elements) { + super(); + + this.elements = elements; + } + + @Override + public Type getType() { + if (cachedTupleType == null) { + cachedTupleType = TypeFactory.getInstance().tupleType(elements); + } + + return cachedTupleType; + } + + @Override + public int arity() { + return elements.length; + } + + @Override + public IValue get(int i) { + return elements[i]; + } + + @Override + public IValue get(String label) { + return elements[getType().getFieldIndex(label)]; + } + + @Override + public Iterator iterator() { + return new TupleIterator(this); + } + + @Override + public T accept(IValueVisitor v) throws E { + return v.visitTuple(this); + } + + @Override + public ITuple set(int index, IValue arg) { + int nrOfElements = elements.length; + IValue[] newElements = new IValue[nrOfElements]; + Type[] elementTypes = new Type[nrOfElements]; + for (int i = nrOfElements - 1; i >= 0; i--) { + IValue element = elements[i]; + newElements[i] = element; + elementTypes[i] = element.getType(); + } + + newElements[index] = arg; + elementTypes[index] = arg.getType(); + + return new Tuple(newElements); + } + + @Override + public ITuple set(String label, IValue arg) { + int nrOfElements = elements.length; + IValue[] newElements = new IValue[nrOfElements]; + Type[] elementTypes = new Type[nrOfElements]; + for (int i = nrOfElements - 1; i >= 0; i--) { + IValue element = elements[i]; + newElements[i] = element; + elementTypes[i] = element.getType(); + } + + newElements[getType().getFieldIndex(label)] = arg; + elementTypes[getType().getFieldIndex(label)] = arg.getType(); + + return new Tuple(newElements); + } + + @Override + public IValue select(int... indexes) { + if (indexes.length == 1) + return get(indexes[0]); + + int nrOfElements = indexes.length; + IValue[] elements = new IValue[nrOfElements]; + Type[] elementTypes = new Type[nrOfElements]; + for (int i = nrOfElements - 1; i >= 0; i--) { + IValue element = get(indexes[i]); + elements[i] = element; + elementTypes[i] = element.getType(); + } + + return new Tuple(elements); + } + + @Override + public IValue selectByFieldNames(String... fields) { + if (fields.length == 1) + return get(fields[0]); + + int nrOfElements = fields.length; + IValue[] elements = new IValue[nrOfElements]; + Type[] elementTypes = new Type[nrOfElements]; + for (int i = nrOfElements - 1; i >= 0; i--) { + IValue element = get(fields[i]); + elements[i] = element; + elementTypes[i] = element.getType(); + } + + return new Tuple(elements); + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public int hashCode() { + int hash = 1331; + + for (int i = elements.length - 1; i >= 0; i--) { + hash -= (hash << 19) + (hash >>> 8); + hash ^= elements[i].hashCode(); + } + + return hash - (hash << 7); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + + if (o == null) { + return false; + } + + if (o.getClass() == getClass()) { + Tuple otherTuple = (Tuple) o; + + // checking for the type will dynamically allocate memory + // because tuple types are computed lazily. + // so we skip this "fast failure" check + // if (getType() != otherTuple.getType()) { return false; } + + + IValue[] otherElements = otherTuple.elements; + int nrOfElements = elements.length; + if (otherElements.length == nrOfElements) { + for (int i = nrOfElements - 1; i >= 0; i--) { + if (!otherElements[i].equals(elements[i])) + return false; + } + return true; + } + } + + return false; + } + + @Override public boolean match(IValue value) { if (value == this) { return true; @@ -223,33 +223,33 @@ public boolean match(IValue value) { return false; } - - private static class TupleIterator implements Iterator { - private final IValue[] elements; - private int index = 0; - public TupleIterator(Tuple tuple) { - super(); + private static class TupleIterator implements Iterator { + private final IValue[] elements; + private int index = 0; - elements = tuple.elements; - } + public TupleIterator(Tuple tuple) { + super(); - @Override - public boolean hasNext() { - return index < elements.length; - } + elements = tuple.elements; + } - @Override - public IValue next() { - if (!hasNext()) - throw new NoSuchElementException("No more elements in this iteration."); + @Override + public boolean hasNext() { + return index < elements.length; + } - return elements[index++]; - } + @Override + public IValue next() { + if (!hasNext()) + throw new NoSuchElementException("No more elements in this iteration."); - @Override - public void remove() { - throw new UnsupportedOperationException("This iterator doesn't support removal."); - } - } + return elements[index++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This iterator doesn't support removal."); + } + } } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/ValueCollectors.java b/src/main/java/io/usethesource/vallang/impl/persistent/ValueCollectors.java index f220966b9..eadf5f37c 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/ValueCollectors.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/ValueCollectors.java @@ -41,8 +41,8 @@ class SetStruct { } public static Collector toList() { - return new DefaultCollector<>(ValueFactory.getInstance()::listWriter, (w,e) -> { w.append(e); }, - unsupportedCombiner(), w -> w.done(), Collections.emptySet()); + return new DefaultCollector<>(ValueFactory.getInstance()::listWriter, (w,e) -> { w.append(e); }, + unsupportedCombiner(), w -> w.done(), Collections.emptySet()); } diff --git a/src/main/java/io/usethesource/vallang/impl/persistent/ValueFactory.java b/src/main/java/io/usethesource/vallang/impl/persistent/ValueFactory.java index 692e7d3d6..0995d8191 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/ValueFactory.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/ValueFactory.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.impl.persistent; @@ -29,33 +29,33 @@ public class ValueFactory extends AbstractPrimitiveValueFactory { - protected ValueFactory() { - super(); - } + protected ValueFactory() { + super(); + } - private static class InstanceKeeper { - public final static ValueFactory instance = new ValueFactory(); - } + private static class InstanceKeeper { + public final static ValueFactory instance = new ValueFactory(); + } - public static ValueFactory getInstance() { - return InstanceKeeper.instance; - } + public static ValueFactory getInstance() { + return InstanceKeeper.instance; + } - @Override + @Override public IListWriter listWriter() { return new ListWriter(); } private static final IList EMPTY_LIST = List.newList(TypeFactory.getInstance().voidType(), new ShareableValuesList()); - + @Override public IList list(IValue... elements){ - if (elements.length == 0) { - return EMPTY_LIST; + if (elements.length == 0) { + return EMPTY_LIST; } IListWriter listWriter = listWriter(); listWriter.append(elements); - + return listWriter.done(); } @@ -68,7 +68,7 @@ public ISet set(IValue... elements){ setWriter.insert(elements); return setWriter.done(); } - + @Override public INode node(String name) { return Node.newNode(name, new IValue[0]); @@ -78,27 +78,27 @@ public INode node(String name) { public INode node(String name, IValue... children) { return Node.newNode(name, children.clone()); } - + @Override public INode node(String name, IValue[] children, Map keyArgValues) { return Node.newNode(name, children.clone()).asWithKeywordParameters().setParameters(keyArgValues); } - + @Override public IConstructor constructor(Type constructorType) { return Constructor.newConstructor(constructorType, new IValue[0]); } - + @Override public IConstructor constructor(Type constructorType, IValue... children){ return Constructor.newConstructor(constructorType, children.clone()); } - + @Override public IConstructor constructor(Type constructorType, IValue[] children, Map kwParams){ return Constructor.newConstructor(constructorType, children.clone(), kwParams); } - + @Override public ITuple tuple() { return Tuple.newTuple(); @@ -109,18 +109,18 @@ public ITuple tuple(IValue... args) { return Tuple.newTuple(args.clone()); } - @Override - public ISetWriter setWriter() { - return new SetWriter((a,b) -> tuple(a,b)); - } + @Override + public ISetWriter setWriter() { + return new SetWriter((a,b) -> tuple(a,b)); + } - @Override - public IMapWriter mapWriter() { - return new MapWriter(); - } + @Override + public IMapWriter mapWriter() { + return new MapWriter(); + } - @Override - public String toString() { - return "VALLANG_PERSISTENT_FACTORY"; - } + @Override + public String toString() { + return "VALLANG_PERSISTENT_FACTORY"; + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/AbstractNumberValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/AbstractNumberValue.java index 1503ce446..11e21265a 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/AbstractNumberValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/AbstractNumberValue.java @@ -18,154 +18,154 @@ import io.usethesource.vallang.type.TypeFactory; /*package*/ abstract class AbstractNumberValue implements INumber { - private final static TypeFactory typeFactory = TypeFactory.getInstance(); - - /*package*/ AbstractNumberValue(){ - super(); - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public INumber add(INumber other){ - if(isIntegerType(other)){ - return add(other.toInteger()); - } - if(isRealType(other)){ - return add(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return add(other.toRational()); - } - - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public INumber divide(INumber other, int precision){ - if(isIntegerType(other)){ - return divide(other.toInteger(), precision); - } - if(isRealType(other)){ - return divide(other.toReal(precision), precision); - } - if(isRationalType(other)){ - return divide(other.toRational(), precision); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public IBool greater(INumber other){ - if(isIntegerType(other)){ - return greater(other.toInteger()); - } - if(isRealType(other)){ - return greater(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return greater(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - - @Override - public IBool equal(INumber other){ - if(isIntegerType(other)){ - return equal(other.toInteger()); + private final static TypeFactory typeFactory = TypeFactory.getInstance(); + + /*package*/ AbstractNumberValue(){ + super(); + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public INumber add(INumber other){ + if(isIntegerType(other)){ + return add(other.toInteger()); + } + if(isRealType(other)){ + return add(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return add(other.toRational()); + } + + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public INumber divide(INumber other, int precision){ + if(isIntegerType(other)){ + return divide(other.toInteger(), precision); + } + if(isRealType(other)){ + return divide(other.toReal(precision), precision); + } + if(isRationalType(other)){ + return divide(other.toRational(), precision); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public IBool greater(INumber other){ + if(isIntegerType(other)){ + return greater(other.toInteger()); + } + if(isRealType(other)){ + return greater(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return greater(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); } - if(isRealType(other)){ - return equal(other.toReal(((IReal) other).precision())); + + + @Override + public IBool equal(INumber other) { + if (isIntegerType(other)) { + return equal(other.toInteger()); + } + if (isRealType(other)) { + return equal(other.toReal(((IReal) other).precision())); + } + if (isRationalType(other)) { + return equal(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public IBool greaterEqual(INumber other){ + if(isIntegerType(other)){ + return greaterEqual(other.toInteger()); + } + if(isRealType(other)){ + return greaterEqual(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return greaterEqual(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); } - if(isRationalType(other)){ - return equal(other.toRational()); + + @Override + public IBool less(INumber other){ + if(isIntegerType(other)){ + return less(other.toInteger()); + } + if(isRealType(other)){ + return less(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return less(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public IBool lessEqual(INumber other){ + if(isIntegerType(other)){ + return lessEqual(other.toInteger()); + } + if(isRealType(other)){ + return lessEqual(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return lessEqual(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public INumber multiply(INumber other){ + if(isIntegerType(other)){ + return multiply(other.toInteger()); + } + if(isRealType(other)){ + return multiply(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return multiply(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + @Override + public INumber subtract(INumber other){ + if(isIntegerType(other)){ + return subtract(other.toInteger()); + } + if(isRealType(other)){ + return subtract(other.toReal(((IReal) other).precision())); + } + if(isRationalType(other)){ + return subtract(other.toRational()); + } + throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); + } + + protected boolean isRationalType(INumber other) { + return other.getType().equivalent(TypeFactory.getInstance().rationalType()); + } + + protected boolean isRealType(INumber other) { + return other.getType().equivalent(TypeFactory.getInstance().realType()); + } + + protected boolean isIntegerType(INumber other) { + return other.getType().equivalent(TypeFactory.getInstance().integerType()); } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public IBool greaterEqual(INumber other){ - if(isIntegerType(other)){ - return greaterEqual(other.toInteger()); - } - if(isRealType(other)){ - return greaterEqual(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return greaterEqual(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public IBool less(INumber other){ - if(isIntegerType(other)){ - return less(other.toInteger()); - } - if(isRealType(other)){ - return less(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return less(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public IBool lessEqual(INumber other){ - if(isIntegerType(other)){ - return lessEqual(other.toInteger()); - } - if(isRealType(other)){ - return lessEqual(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return lessEqual(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public INumber multiply(INumber other){ - if(isIntegerType(other)){ - return multiply(other.toInteger()); - } - if(isRealType(other)){ - return multiply(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return multiply(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - @Override - public INumber subtract(INumber other){ - if(isIntegerType(other)){ - return subtract(other.toInteger()); - } - if(isRealType(other)){ - return subtract(other.toReal(((IReal) other).precision())); - } - if(isRationalType(other)){ - return subtract(other.toRational()); - } - throw new UnexpectedTypeException(typeFactory.numberType(), other.getType()); - } - - protected boolean isRationalType(INumber other) { - return other.getType().equivalent(TypeFactory.getInstance().rationalType()); - } - - protected boolean isRealType(INumber other) { - return other.getType().equivalent(TypeFactory.getInstance().realType()); - } - - protected boolean isIntegerType(INumber other) { - return other.getType().equivalent(TypeFactory.getInstance().integerType()); - } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/AbstractPrimitiveValueFactory.java b/src/main/java/io/usethesource/vallang/impl/primitive/AbstractPrimitiveValueFactory.java index d1ceb659a..a496ac425 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/AbstractPrimitiveValueFactory.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/AbstractPrimitiveValueFactory.java @@ -1,250 +1,250 @@ -/******************************************************************************* - * Copyright (c) 2009, 2012-2013 Centrum Wiskunde en Informatica (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 Vinju - interface and implementation - * Arnold Lankamp - implementation - * Anya Helene Bagge - rational support, labeled maps and tuples - * Davy Landman - added PI & E constants - * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI - *******************************************************************************/ -package io.usethesource.vallang.impl.primitive; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.concurrent.atomic.AtomicInteger; - -import io.usethesource.vallang.IBool; -import io.usethesource.vallang.IDateTime; -import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.IRational; -import io.usethesource.vallang.IReal; -import io.usethesource.vallang.ISourceLocation; -import io.usethesource.vallang.IString; -import io.usethesource.vallang.IValueFactory; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Base value factory with optimized representations of primitive values. - */ -public abstract class AbstractPrimitiveValueFactory implements IValueFactory { - - private final static int DEFAULT_PRECISION = 10; - private final AtomicInteger currentPrecision = new AtomicInteger(DEFAULT_PRECISION); - - @Override - public IInteger integer(String integerValue) { - return IntegerValue.newInteger(integerValue); - } - - @Override - public IInteger integer(int value) { - return IntegerValue.newInteger(value); - } - - @Override - public IInteger integer(long value) { - return IntegerValue.newInteger(value); - } - - @Override - public IInteger integer(byte[] integerData) { - return IntegerValue.newInteger(integerData); - } - - @Override - public IRational rational(int a, int b) { - return rational(integer(a), integer(b)); - } - - @Override - public IRational rational(long a, long b) { - return rational(integer(a), integer(b)); - } - - @Override - public IRational rational(IInteger a, IInteger b) { - return RationalValue.newRational(a, b); - } - - @Override - public IRational rational(String rat) throws NumberFormatException { - if (rat.contains("r")) { - String[] parts = rat.split("r"); - if (parts.length == 2) { - return rational(integer(parts[0]), integer(parts[1])); - } - if (parts.length == 1) { - return rational(integer(parts[0]), integer(1)); - } - throw new NumberFormatException(rat); - } else { - return rational(integer(rat), integer(1)); - } - } - - @Override - public IReal real(String value) { - return BigDecimalValue.newReal(value); - } - - @Override - public IReal real(String value, int precision) throws NumberFormatException { - return BigDecimalValue.newReal(value, precision); - } - - @Override - public IReal real(double value) { - return BigDecimalValue.newReal(value); - } - - @Override - public IReal real(double value, int precision) { - return BigDecimalValue.newReal(value, precision); - } - - @Override - public int getPrecision() { - return currentPrecision.get(); - } - - @Override - public int setPrecision(int p) { - return currentPrecision.getAndSet(p); - } - - @Override - public IReal pi(int precision) { - return BigDecimalValue.pi(precision); - } - - @Override - public IReal e(int precision) { - return BigDecimalValue.e(precision); - } - - @Override - public IString string(String value) { - return StringValue.newString(value); - } - - @Override - public IString string(int[] chars) { - StringBuilder b = new StringBuilder(chars.length); - for (int ch : chars) { - b.appendCodePoint(ch); - } - return string(b.toString()); - } - - @Override - public IString string(int ch) { - StringBuilder b = new StringBuilder(1); - b.appendCodePoint(ch); - return string(b.toString()); - } - - @Override - public IBool bool(boolean value) { - return BoolValue.getBoolValue(value); - } - - @Override - public IDateTime date(int year, int month, int day) { - return DateTimeValues.newDate(year, month, day); - } - - @Override - public IDateTime time(int hour, int minute, int second, int millisecond) { - return DateTimeValues.newTime(hour, minute, second, millisecond); - } - - @Override - public IDateTime time(int hour, int minute, int second, int millisecond, - int hourOffset, int minuteOffset) { - return DateTimeValues.newTime(hour, minute, second, millisecond, hourOffset, minuteOffset); - } - - @Override - public IDateTime datetime(int year, int month, int day, int hour, - int minute, int second, int millisecond) { - return DateTimeValues.newDateTime(year, month, day, hour, minute, second, millisecond); - } - - @Override - public IDateTime datetime(int year, int month, int day, int hour, - int minute, int second, int millisecond, int hourOffset, - int minuteOffset) { - return DateTimeValues.newDateTime(year, month, day, hour, minute, second, millisecond, hourOffset, minuteOffset); - } - - @Override - public IDateTime datetime(long instant) { - return DateTimeValues.newDateTime(instant); - } - - @Override - public IDateTime datetime(long instant, int timezoneHours, int timezoneMinutes) { - return DateTimeValues.newDateTime(instant, timezoneHours, timezoneMinutes); - } - - @Override - public ISourceLocation sourceLocation(URI uri, int offset, int length) { - return sourceLocation(sourceLocation(uri), offset, length); - } - - @Override - public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length) { - return SourceLocationValues.newSourceLocation(loc, offset, length); - } - - @Override - public ISourceLocation sourceLocation(URI uri, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { - return sourceLocation(sourceLocation(uri), offset, length, beginLine, endLine, beginCol, endCol); - } - @Override - public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { - return SourceLocationValues.newSourceLocation(loc, offset, length, beginLine, endLine, beginCol, endCol); - } - - @Override - public ISourceLocation sourceLocation(String path, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { - return sourceLocation(sourceLocation(path), offset, length, beginLine, endLine, beginCol, endCol); - } - - @Override - public ISourceLocation sourceLocation(URI uri) { - try { - return SourceLocationValues.newSourceLocation(uri); - } - catch (URISyntaxException e) { - throw new RuntimeException("An URI should always be a correct URI", e); - } - } - - @Override - public ISourceLocation sourceLocation(String path) { - if (!path.startsWith("/")) - path = "/" + path; - try { - return sourceLocation("file", "", path); - } catch (URISyntaxException e) { - throw new RuntimeException("Paths should not cause a incorrect syntax exception", e); - } - } - - @Override - public ISourceLocation sourceLocation(String scheme, String authority, String path) throws URISyntaxException { - return sourceLocation(scheme, authority, path, null, null); - } - - @Override - public ISourceLocation sourceLocation(String scheme, String authority, - String path, @Nullable String query, @Nullable String fragment) throws URISyntaxException { - return SourceLocationValues.newSourceLocation(scheme, authority, path, query, fragment); - } -} +/******************************************************************************* + * Copyright (c) 2009, 2012-2013 Centrum Wiskunde en Informatica (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 Vinju - interface and implementation + * Arnold Lankamp - implementation + * Anya Helene Bagge - rational support, labeled maps and tuples + * Davy Landman - added PI & E constants + * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + *******************************************************************************/ +package io.usethesource.vallang.impl.primitive; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.atomic.AtomicInteger; + +import io.usethesource.vallang.IBool; +import io.usethesource.vallang.IDateTime; +import io.usethesource.vallang.IInteger; +import io.usethesource.vallang.IRational; +import io.usethesource.vallang.IReal; +import io.usethesource.vallang.ISourceLocation; +import io.usethesource.vallang.IString; +import io.usethesource.vallang.IValueFactory; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Base value factory with optimized representations of primitive values. + */ +public abstract class AbstractPrimitiveValueFactory implements IValueFactory { + + private final static int DEFAULT_PRECISION = 10; + private final AtomicInteger currentPrecision = new AtomicInteger(DEFAULT_PRECISION); + + @Override + public IInteger integer(String integerValue) { + return IntegerValue.newInteger(integerValue); + } + + @Override + public IInteger integer(int value) { + return IntegerValue.newInteger(value); + } + + @Override + public IInteger integer(long value) { + return IntegerValue.newInteger(value); + } + + @Override + public IInteger integer(byte[] integerData) { + return IntegerValue.newInteger(integerData); + } + + @Override + public IRational rational(int a, int b) { + return rational(integer(a), integer(b)); + } + + @Override + public IRational rational(long a, long b) { + return rational(integer(a), integer(b)); + } + + @Override + public IRational rational(IInteger a, IInteger b) { + return RationalValue.newRational(a, b); + } + + @Override + public IRational rational(String rat) throws NumberFormatException { + if (rat.contains("r")) { + String[] parts = rat.split("r"); + if (parts.length == 2) { + return rational(integer(parts[0]), integer(parts[1])); + } + if (parts.length == 1) { + return rational(integer(parts[0]), integer(1)); + } + throw new NumberFormatException(rat); + } else { + return rational(integer(rat), integer(1)); + } + } + + @Override + public IReal real(String value) { + return BigDecimalValue.newReal(value); + } + + @Override + public IReal real(String value, int precision) throws NumberFormatException { + return BigDecimalValue.newReal(value, precision); + } + + @Override + public IReal real(double value) { + return BigDecimalValue.newReal(value); + } + + @Override + public IReal real(double value, int precision) { + return BigDecimalValue.newReal(value, precision); + } + + @Override + public int getPrecision() { + return currentPrecision.get(); + } + + @Override + public int setPrecision(int p) { + return currentPrecision.getAndSet(p); + } + + @Override + public IReal pi(int precision) { + return BigDecimalValue.pi(precision); + } + + @Override + public IReal e(int precision) { + return BigDecimalValue.e(precision); + } + + @Override + public IString string(String value) { + return StringValue.newString(value); + } + + @Override + public IString string(int[] chars) { + StringBuilder b = new StringBuilder(chars.length); + for (int ch : chars) { + b.appendCodePoint(ch); + } + return string(b.toString()); + } + + @Override + public IString string(int ch) { + StringBuilder b = new StringBuilder(1); + b.appendCodePoint(ch); + return string(b.toString()); + } + + @Override + public IBool bool(boolean value) { + return BoolValue.getBoolValue(value); + } + + @Override + public IDateTime date(int year, int month, int day) { + return DateTimeValues.newDate(year, month, day); + } + + @Override + public IDateTime time(int hour, int minute, int second, int millisecond) { + return DateTimeValues.newTime(hour, minute, second, millisecond); + } + + @Override + public IDateTime time(int hour, int minute, int second, int millisecond, + int hourOffset, int minuteOffset) { + return DateTimeValues.newTime(hour, minute, second, millisecond, hourOffset, minuteOffset); + } + + @Override + public IDateTime datetime(int year, int month, int day, int hour, + int minute, int second, int millisecond) { + return DateTimeValues.newDateTime(year, month, day, hour, minute, second, millisecond); + } + + @Override + public IDateTime datetime(int year, int month, int day, int hour, + int minute, int second, int millisecond, int hourOffset, + int minuteOffset) { + return DateTimeValues.newDateTime(year, month, day, hour, minute, second, millisecond, hourOffset, minuteOffset); + } + + @Override + public IDateTime datetime(long instant) { + return DateTimeValues.newDateTime(instant); + } + + @Override + public IDateTime datetime(long instant, int timezoneHours, int timezoneMinutes) { + return DateTimeValues.newDateTime(instant, timezoneHours, timezoneMinutes); + } + + @Override + public ISourceLocation sourceLocation(URI uri, int offset, int length) { + return sourceLocation(sourceLocation(uri), offset, length); + } + + @Override + public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length) { + return SourceLocationValues.newSourceLocation(loc, offset, length); + } + + @Override + public ISourceLocation sourceLocation(URI uri, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { + return sourceLocation(sourceLocation(uri), offset, length, beginLine, endLine, beginCol, endCol); + } + @Override + public ISourceLocation sourceLocation(ISourceLocation loc, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { + return SourceLocationValues.newSourceLocation(loc, offset, length, beginLine, endLine, beginCol, endCol); + } + + @Override + public ISourceLocation sourceLocation(String path, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { + return sourceLocation(sourceLocation(path), offset, length, beginLine, endLine, beginCol, endCol); + } + + @Override + public ISourceLocation sourceLocation(URI uri) { + try { + return SourceLocationValues.newSourceLocation(uri); + } + catch (URISyntaxException e) { + throw new RuntimeException("An URI should always be a correct URI", e); + } + } + + @Override + public ISourceLocation sourceLocation(String path) { + if (!path.startsWith("/")) + path = "/" + path; + try { + return sourceLocation("file", "", path); + } catch (URISyntaxException e) { + throw new RuntimeException("Paths should not cause a incorrect syntax exception", e); + } + } + + @Override + public ISourceLocation sourceLocation(String scheme, String authority, String path) throws URISyntaxException { + return sourceLocation(scheme, authority, path, null, null); + } + + @Override + public ISourceLocation sourceLocation(String scheme, String authority, + String path, @Nullable String query, @Nullable String fragment) throws URISyntaxException { + return SourceLocationValues.newSourceLocation(scheme, authority, path, query, fragment); + } +} diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/BigDecimalValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/BigDecimalValue.java index c60c03a01..8ed6028e5 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/BigDecimalValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/BigDecimalValue.java @@ -1,426 +1,426 @@ -/******************************************************************************* - * Copyright (c) 2009-2013 CWI - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * - * * Arnold Lankamp - interfaces and implementation - * * Jurgen Vinju - extensions and fixes - * * Davy Landman - added mathematical functions - * * Paul Klint - Precision handling - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI - *******************************************************************************/ -package io.usethesource.vallang.impl.primitive; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.math.RoundingMode; - -import org.checkerframework.checker.nullness.qual.Nullable; - -import io.usethesource.vallang.IBool; -import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.INumber; -import io.usethesource.vallang.IRational; -import io.usethesource.vallang.IReal; -import io.usethesource.vallang.impl.util.BigDecimalCalculations; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; - -/* - * TODO: provide specializations for smaller values, similar to IntegerValue / BigIntegerValue. - */ -/*package*/ class BigDecimalValue extends AbstractNumberValue implements IReal { - private final static Type DOUBLE_TYPE = TypeFactory.getInstance().realType(); - - protected final BigDecimal value; - - /*package*/ static IReal newReal(BigDecimal value) { - return new BigDecimalValue(value); - } - - /*package*/ static IReal newReal(String value) { - return new BigDecimalValue(new BigDecimal(value)); - } - - /*package*/ static IReal newReal(String value, int precision) throws NumberFormatException { - return new BigDecimalValue(new BigDecimal(value, new MathContext(precision))); - } - - /*package*/ static IReal newReal(double value) { - checkNanAndInfinity(value); - return new BigDecimalValue(BigDecimal.valueOf(value)); - } - - public static void checkNanAndInfinity(double value) { - if (Double.isNaN(value)) { - throw new NumberFormatException("no support for NaN"); - } - if (Double.isInfinite(value)) { - throw new NumberFormatException("no support for infinity"); - } - } - - /*package*/ static IReal newReal(double value, int precision) { - checkNanAndInfinity(value); - return new BigDecimalValue(new BigDecimal(value, new MathContext(precision))); - } - - private BigDecimalValue(BigDecimal value){ - super(); - - this.value = value; - } - - private BigDecimalValue(BigDecimal value, int precision){ - super(); - - this.value = new BigDecimal(value.toEngineeringString(), new MathContext(precision)); - } - - @Override - public IReal abs() { - return newReal(value.abs()); - } - - @Override - public IReal toReal(int precision) { - return this; - } - - @Override - public Type getType(){ - return DOUBLE_TYPE; - } - - @Override - public float floatValue(){ - return value.floatValue(); - } - - @Override - public double doubleValue(){ - return value.doubleValue(); - } - - @Override - public IInteger toInteger(){ - return IntegerValue.newInteger(value.toBigInteger()); - } - - @Override - public IRational toRational(){ - throw new UnsupportedOperationException(); - } - - @Override - public IReal floor(){ - return BigDecimalValue.newReal(value.setScale(0, RoundingMode.FLOOR)); - } - - @Override - public IReal round(){ - return BigDecimalValue.newReal(value.setScale(0, RoundingMode.HALF_UP)); - } - - @Override - public IReal add(IReal other){ - return BigDecimalValue.newReal(value.add(((BigDecimalValue) other).value)); - } - - @Override - public INumber add(IInteger other) { - return add(other.toReal(value.precision())); - } - - @Override - public INumber add(IRational other) { - return add(other.toReal(value.precision())); - } - - @Override - public IReal subtract(IReal other){ - return BigDecimalValue.newReal(value.subtract(((BigDecimalValue) other).value)); - } - - @Override - public INumber subtract(IInteger other) { - return subtract(other.toReal(value.precision())); - } - - @Override - public INumber subtract(IRational other) { - return subtract(other.toReal(value.precision())); - } - - @Override - public IReal multiply(IReal other){ - return BigDecimalValue.newReal(value.multiply(((BigDecimalValue) other).value)); - } - - @Override - public INumber multiply(IInteger other) { - return multiply(other.toReal(value.precision())); - } - - @Override - public INumber multiply(IRational other) { - return multiply(other.toReal(value.precision())); - } - - @Override - public IReal divide(IReal other, int precision){ - // make sure the precision is *at least* the same as that of the arguments - precision = Math.max(Math.max(value.precision(), other.precision()), precision); - MathContext mc = new MathContext(precision, RoundingMode.HALF_UP); - return BigDecimalValue.newReal(value.divide(((BigDecimalValue) other).value, mc)); - } - - @Override - public IReal divide(IInteger other, int precision) { - return divide(other.toReal(precision), precision); - } - - @Override - public IReal divide(IRational other, int precision) { - return divide(other.toReal(precision), precision); - } - - @Override - public IReal negate(){ - return BigDecimalValue.newReal(value.negate()); - } - - @Override - public int precision(){ - return value.precision(); - } - - @Override - public int scale(){ - return value.scale(); - } - - @Override - public IInteger unscaled(){ - return IntegerValue.newInteger(value.unscaledValue()); - } - - @Override - public IBool equal(IReal other){ - return BoolValue.getBoolValue(compare(other) == 0); - } - - @Override - public IBool equal(IInteger other) { - return equal(other.toReal(value.precision())); - } - - @Override - public IBool equal(IRational other) { - return equal(other.toReal(value.precision())); - } - - @Override - public IBool greater(IReal other){ - return BoolValue.getBoolValue(compare(other) > 0); - } - - @Override - public IBool greater(IInteger other) { - return greater(other.toReal(value.precision())); - } - - @Override - public IBool greater(IRational other) { - return greater(other.toReal(value.precision())); - } - - @Override - public IBool greaterEqual(IReal other){ - return BoolValue.getBoolValue(compare(other) >= 0); - } - - @Override - public IBool greaterEqual(IInteger other) { - return greaterEqual(other.toReal(value.precision())); - } - - @Override - public IBool greaterEqual(IRational other) { - return greaterEqual(other.toReal(value.precision())); - } - - - @Override - public IBool less(IReal other){ - return BoolValue.getBoolValue(compare(other) < 0); - } - - @Override - public IBool less(IInteger other) { - return less(other.toReal(value.precision())); - } - - @Override - public IBool less(IRational other) { - return less(other.toReal(value.precision())); - } - - @Override - public IBool lessEqual(IReal other){ - return BoolValue.getBoolValue(compare(other) <= 0); - } - - @Override - public IBool lessEqual(IInteger other) { - return lessEqual(other.toReal(value.precision())); - } - - @Override - public IBool lessEqual(IRational other) { - return lessEqual(other.toReal(value.precision())); - } - - @Override - public int compare(IReal other){ - return value.compareTo(((BigDecimalValue) other).value); - } - - @Override - public int compare(INumber other) { - return compare(other.toReal(value.precision())); - } - - /* - * Description and implementation from the (now removed) reference implementation: - * - * // Java BigDecimals have a bug, their even though 3.0 and 3.00 are equal, - * // their hashCode() is not, which is against the equals/hashCode() contract. - * // To work around this, we use this simple trick here which is correct but - * // might lead to many collisions. - * // return Double.valueOf(value.doubleValue()).hashCode(); - */ - @Override - public int hashCode(){ - // BigDecimals don't generate consistent hashcodes for things that are actually 'equal'. - // This code rectifies this problem. - long bits = Double.doubleToLongBits(value.doubleValue()); - return (int) (bits ^ (bits >>> 32)); - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) { - return false; - } - - if(o.getClass() == getClass()){ - BigDecimalValue otherDouble = (BigDecimalValue) o; - return (value.equals(otherDouble.value)); - } - - return false; - } - - @Override - public String getStringRepresentation(){ - StringBuilder sb = new StringBuilder(); - String decimalString = value.toString(); - sb.append(decimalString); - if (!decimalString.matches(".*[\\.Ee].*")) { - sb.append("."); - } - return sb.toString(); - } - - @Override - public int signum() { - return value.signum(); - } - - @Override - public IReal log(IInteger base, int precision) { - return log(base.toReal(precision), precision); - } - - @Override - public IReal log(IReal base, int precision) { - IReal lnBase = base.ln(precision + 1); - IReal lnThis = this.ln(precision + 1); - return lnThis.divide(lnBase, precision); - } - - @Override - public IReal ln(int precision) { - return newReal(BigDecimalCalculations.ln(value, precision)); - } - - @Override - public IReal sqrt(int precision) { - return newReal(BigDecimalCalculations.sqrt(value, precision)); - } - - @Override - public IReal nroot(IInteger n, int precision) { - return newReal(BigDecimalCalculations.intRoot(value, new BigInteger(n.getTwosComplementRepresentation()), precision)); - } - - @Override - public IReal exp(int precision) { - return newReal(BigDecimalCalculations.exp(value, precision)); - } - - @Override - public IReal pow(IInteger power) { - if (power.signum() < 0) { - // negative power is 1/(this^-power) - return newReal( - BigDecimal.ONE.divide(value.pow(power.negate().intValue()), value.precision(), RoundingMode.HALF_EVEN) - ); - } - return newReal(value.pow(power.intValue())); - } - @Override - public IReal pow(IReal power, int precision) { - BigDecimal actualPower = null; - if (power instanceof BigDecimalValue) { - actualPower = ((BigDecimalValue)power).value; - } - else { - actualPower = new BigDecimal(power.getStringRepresentation()); - } - return newReal(BigDecimalCalculations.pow(value, actualPower, precision)); - } - - @Override - public IReal tan(int precision) { - return newReal(BigDecimalCalculations.tan(value, precision)); - } - - @Override - public IReal sin(int precision) { - return newReal(BigDecimalCalculations.sin(value, precision)); - } - - @Override - public IReal cos(int precision) { - return newReal(BigDecimalCalculations.cos(value, precision)); - } - - public static IReal pi(int precision) { - if (precision < 0 || precision > 1000) - throw new IllegalArgumentException("PI max precision is 1000"); - return newReal(BigDecimalCalculations.PI.setScale(precision, RoundingMode.HALF_EVEN)); - } - - public static IReal e(int precision) { - if (precision < 0 || precision > 1000) - throw new IllegalArgumentException("E max precision is 1000"); - return newReal(BigDecimalCalculations.E.setScale(precision, RoundingMode.HALF_EVEN)); - } -} +/******************************************************************************* + * Copyright (c) 2009-2013 CWI + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * + * * Arnold Lankamp - interfaces and implementation + * * Jurgen Vinju - extensions and fixes + * * Davy Landman - added mathematical functions + * * Paul Klint - Precision handling + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + *******************************************************************************/ +package io.usethesource.vallang.impl.primitive; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import io.usethesource.vallang.IBool; +import io.usethesource.vallang.IInteger; +import io.usethesource.vallang.INumber; +import io.usethesource.vallang.IRational; +import io.usethesource.vallang.IReal; +import io.usethesource.vallang.impl.util.BigDecimalCalculations; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; + +/* + * TODO: provide specializations for smaller values, similar to IntegerValue / BigIntegerValue. + */ +/*package*/ class BigDecimalValue extends AbstractNumberValue implements IReal { + private final static Type DOUBLE_TYPE = TypeFactory.getInstance().realType(); + + protected final BigDecimal value; + + /*package*/ static IReal newReal(BigDecimal value) { + return new BigDecimalValue(value); + } + + /*package*/ static IReal newReal(String value) { + return new BigDecimalValue(new BigDecimal(value)); + } + + /*package*/ static IReal newReal(String value, int precision) throws NumberFormatException { + return new BigDecimalValue(new BigDecimal(value, new MathContext(precision))); + } + + /*package*/ static IReal newReal(double value) { + checkNanAndInfinity(value); + return new BigDecimalValue(BigDecimal.valueOf(value)); + } + + public static void checkNanAndInfinity(double value) { + if (Double.isNaN(value)) { + throw new NumberFormatException("no support for NaN"); + } + if (Double.isInfinite(value)) { + throw new NumberFormatException("no support for infinity"); + } + } + + /*package*/ static IReal newReal(double value, int precision) { + checkNanAndInfinity(value); + return new BigDecimalValue(new BigDecimal(value, new MathContext(precision))); + } + + private BigDecimalValue(BigDecimal value){ + super(); + + this.value = value; + } + + private BigDecimalValue(BigDecimal value, int precision){ + super(); + + this.value = new BigDecimal(value.toEngineeringString(), new MathContext(precision)); + } + + @Override + public IReal abs() { + return newReal(value.abs()); + } + + @Override + public IReal toReal(int precision) { + return this; + } + + @Override + public Type getType(){ + return DOUBLE_TYPE; + } + + @Override + public float floatValue(){ + return value.floatValue(); + } + + @Override + public double doubleValue(){ + return value.doubleValue(); + } + + @Override + public IInteger toInteger(){ + return IntegerValue.newInteger(value.toBigInteger()); + } + + @Override + public IRational toRational(){ + throw new UnsupportedOperationException(); + } + + @Override + public IReal floor(){ + return BigDecimalValue.newReal(value.setScale(0, RoundingMode.FLOOR)); + } + + @Override + public IReal round(){ + return BigDecimalValue.newReal(value.setScale(0, RoundingMode.HALF_UP)); + } + + @Override + public IReal add(IReal other){ + return BigDecimalValue.newReal(value.add(((BigDecimalValue) other).value)); + } + + @Override + public INumber add(IInteger other) { + return add(other.toReal(value.precision())); + } + + @Override + public INumber add(IRational other) { + return add(other.toReal(value.precision())); + } + + @Override + public IReal subtract(IReal other){ + return BigDecimalValue.newReal(value.subtract(((BigDecimalValue) other).value)); + } + + @Override + public INumber subtract(IInteger other) { + return subtract(other.toReal(value.precision())); + } + + @Override + public INumber subtract(IRational other) { + return subtract(other.toReal(value.precision())); + } + + @Override + public IReal multiply(IReal other){ + return BigDecimalValue.newReal(value.multiply(((BigDecimalValue) other).value)); + } + + @Override + public INumber multiply(IInteger other) { + return multiply(other.toReal(value.precision())); + } + + @Override + public INumber multiply(IRational other) { + return multiply(other.toReal(value.precision())); + } + + @Override + public IReal divide(IReal other, int precision){ + // make sure the precision is *at least* the same as that of the arguments + precision = Math.max(Math.max(value.precision(), other.precision()), precision); + MathContext mc = new MathContext(precision, RoundingMode.HALF_UP); + return BigDecimalValue.newReal(value.divide(((BigDecimalValue) other).value, mc)); + } + + @Override + public IReal divide(IInteger other, int precision) { + return divide(other.toReal(precision), precision); + } + + @Override + public IReal divide(IRational other, int precision) { + return divide(other.toReal(precision), precision); + } + + @Override + public IReal negate(){ + return BigDecimalValue.newReal(value.negate()); + } + + @Override + public int precision(){ + return value.precision(); + } + + @Override + public int scale(){ + return value.scale(); + } + + @Override + public IInteger unscaled(){ + return IntegerValue.newInteger(value.unscaledValue()); + } + + @Override + public IBool equal(IReal other) { + return BoolValue.getBoolValue(compare(other) == 0); + } + + @Override + public IBool equal(IInteger other) { + return equal(other.toReal(value.precision())); + } + + @Override + public IBool equal(IRational other) { + return equal(other.toReal(value.precision())); + } + + @Override + public IBool greater(IReal other){ + return BoolValue.getBoolValue(compare(other) > 0); + } + + @Override + public IBool greater(IInteger other) { + return greater(other.toReal(value.precision())); + } + + @Override + public IBool greater(IRational other) { + return greater(other.toReal(value.precision())); + } + + @Override + public IBool greaterEqual(IReal other){ + return BoolValue.getBoolValue(compare(other) >= 0); + } + + @Override + public IBool greaterEqual(IInteger other) { + return greaterEqual(other.toReal(value.precision())); + } + + @Override + public IBool greaterEqual(IRational other) { + return greaterEqual(other.toReal(value.precision())); + } + + + @Override + public IBool less(IReal other){ + return BoolValue.getBoolValue(compare(other) < 0); + } + + @Override + public IBool less(IInteger other) { + return less(other.toReal(value.precision())); + } + + @Override + public IBool less(IRational other) { + return less(other.toReal(value.precision())); + } + + @Override + public IBool lessEqual(IReal other){ + return BoolValue.getBoolValue(compare(other) <= 0); + } + + @Override + public IBool lessEqual(IInteger other) { + return lessEqual(other.toReal(value.precision())); + } + + @Override + public IBool lessEqual(IRational other) { + return lessEqual(other.toReal(value.precision())); + } + + @Override + public int compare(IReal other){ + return value.compareTo(((BigDecimalValue) other).value); + } + + @Override + public int compare(INumber other) { + return compare(other.toReal(value.precision())); + } + + /* + * Description and implementation from the (now removed) reference implementation: + * + * // Java BigDecimals have a bug, their even though 3.0 and 3.00 are equal, + * // their hashCode() is not, which is against the equals/hashCode() contract. + * // To work around this, we use this simple trick here which is correct but + * // might lead to many collisions. + * // return Double.valueOf(value.doubleValue()).hashCode(); + */ + @Override + public int hashCode(){ + // BigDecimals don't generate consistent hashcodes for things that are actually 'equal'. + // This code rectifies this problem. + long bits = Double.doubleToLongBits(value.doubleValue()); + return (int) (bits ^ (bits >>> 32)); + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) { + return false; + } + + if(o.getClass() == getClass()){ + BigDecimalValue otherDouble = (BigDecimalValue) o; + return (value.equals(otherDouble.value)); + } + + return false; + } + + @Override + public String getStringRepresentation(){ + StringBuilder sb = new StringBuilder(); + String decimalString = value.toString(); + sb.append(decimalString); + if (!decimalString.matches(".*[\\.Ee].*")) { + sb.append("."); + } + return sb.toString(); + } + + @Override + public int signum() { + return value.signum(); + } + + @Override + public IReal log(IInteger base, int precision) { + return log(base.toReal(precision), precision); + } + + @Override + public IReal log(IReal base, int precision) { + IReal lnBase = base.ln(precision + 1); + IReal lnThis = this.ln(precision + 1); + return lnThis.divide(lnBase, precision); + } + + @Override + public IReal ln(int precision) { + return newReal(BigDecimalCalculations.ln(value, precision)); + } + + @Override + public IReal sqrt(int precision) { + return newReal(BigDecimalCalculations.sqrt(value, precision)); + } + + @Override + public IReal nroot(IInteger n, int precision) { + return newReal(BigDecimalCalculations.intRoot(value, new BigInteger(n.getTwosComplementRepresentation()), precision)); + } + + @Override + public IReal exp(int precision) { + return newReal(BigDecimalCalculations.exp(value, precision)); + } + + @Override + public IReal pow(IInteger power) { + if (power.signum() < 0) { + // negative power is 1/(this^-power) + return newReal( + BigDecimal.ONE.divide(value.pow(power.negate().intValue()), value.precision(), RoundingMode.HALF_EVEN) + ); + } + return newReal(value.pow(power.intValue())); + } + @Override + public IReal pow(IReal power, int precision) { + BigDecimal actualPower = null; + if (power instanceof BigDecimalValue) { + actualPower = ((BigDecimalValue)power).value; + } + else { + actualPower = new BigDecimal(power.getStringRepresentation()); + } + return newReal(BigDecimalCalculations.pow(value, actualPower, precision)); + } + + @Override + public IReal tan(int precision) { + return newReal(BigDecimalCalculations.tan(value, precision)); + } + + @Override + public IReal sin(int precision) { + return newReal(BigDecimalCalculations.sin(value, precision)); + } + + @Override + public IReal cos(int precision) { + return newReal(BigDecimalCalculations.cos(value, precision)); + } + + public static IReal pi(int precision) { + if (precision < 0 || precision > 1000) + throw new IllegalArgumentException("PI max precision is 1000"); + return newReal(BigDecimalCalculations.PI.setScale(precision, RoundingMode.HALF_EVEN)); + } + + public static IReal e(int precision) { + if (precision < 0 || precision > 1000) + throw new IllegalArgumentException("E max precision is 1000"); + return newReal(BigDecimalCalculations.E.setScale(precision, RoundingMode.HALF_EVEN)); + } +} diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/BigIntegerValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/BigIntegerValue.java index 161b9a95b..d26cff496 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/BigIntegerValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/BigIntegerValue.java @@ -1,357 +1,357 @@ -/******************************************************************************* - * Copyright (c) 2009-2013 CWI - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * - * * Arnold Lankamp - interfaces and implementation - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI - *******************************************************************************/ -package io.usethesource.vallang.impl.primitive; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.checkerframework.checker.nullness.qual.Nullable; - -import io.usethesource.vallang.IBool; -import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.INumber; -import io.usethesource.vallang.IRational; -import io.usethesource.vallang.IReal; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; - -/** - * Specialized implementation for integer values that fall outside the 32-bit range. - * - * @author Arnold Lankamp - */ -/*package*/ class BigIntegerValue extends AbstractNumberValue implements IInteger, ICanBecomeABigInteger{ - private final static Type INTEGER_TYPE = TypeFactory.getInstance().integerType(); - - protected final BigInteger value; - - /*package*/ BigIntegerValue(BigInteger value){ - super(); - if(value.equals(BigInteger.ZERO)) - value = BigInteger.ZERO; - if(value.equals(BigInteger.ONE)) - value = BigInteger.ONE; - - this.value = value; - } - - @Override - public IInteger toInteger() { - return this; - } - - @Override - public Type getType(){ - return INTEGER_TYPE; - } - - @Override - public int intValue() throws ArithmeticException { - return value.intValueExact(); - } - - @Override - public long longValue() throws ArithmeticException { - return value.longValueExact(); - } - - @Override - public double doubleValue(){ - return value.doubleValue(); - } - - @Override - public IReal toReal(int precision){ - // precision is ignored intentionally - return BigDecimalValue.newReal(new BigDecimal(value)); - } - - @Override - public IRational toRational(){ - return RationalValue.newRational(this, IntegerValue.INTEGER_ONE); - } - @Override - public byte[] getTwosComplementRepresentation(){ - return value.toByteArray(); - } - - @Override - public BigInteger toBigInteger(){ - return value; - } - - @Override - public IInteger add(IInteger other){ - BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger(); - BigInteger result = value.add(o); - if(result == value) - return this; - else if(result == o) - return other; - int length = result.bitLength(); - if(length <= 31){ - return IntegerValue.newInteger(result.intValue()); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IReal add(IReal other) { - return (IReal) other.add(this); - } - - @Override - public IRational add(IRational other) { - return (IRational) other.add(this); - } - - @Override - public IInteger subtract(IInteger other){ - BigInteger result = value.subtract(((ICanBecomeABigInteger) other).toBigInteger()); - if(result == value) - return this; - - int length = result.bitLength(); - if(length <= 31){ - return IntegerValue.newInteger(result.intValue()); - } - - return IntegerValue.newInteger(result); - } - - @Override - public INumber subtract(IReal other) { - return toReal(other.precision()).subtract(other); - } - - @Override - public INumber subtract(IRational other) { - return toRational().subtract(other); - } - - @Override - public IInteger multiply(IInteger other){ - BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger(); - BigInteger result = value.multiply(o); - if(result == value) - return this; - else if(result == o) - return other; - // The result of this operation can never fit in a 32-bit integer, so no need to check. - return IntegerValue.newInteger(result); - } - - @Override - public IReal multiply(IReal other) { - return (IReal) other.multiply(this); - } - - @Override - public IRational multiply(IRational other) { - return (IRational) other.multiply(this); - } - @Override - public IInteger divide(IInteger other){ - BigInteger result = value.divide(((ICanBecomeABigInteger) other).toBigInteger()); - if(result == value) - return this; - - int length = result.bitLength(); - if(length <= 31){ - return IntegerValue.newInteger(result.intValue()); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IRational divide(IRational other) { - return toRational().divide(other); - } - - @Override - public INumber divide(IInteger other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public INumber divide(IRational other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public IReal divide(IReal other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public IInteger mod(IInteger other){ - BigInteger result = value.mod(((ICanBecomeABigInteger) other).toBigInteger()); - - if(other instanceof IntegerValue){ - int integerResult = result.intValue(); - return IntegerValue.newInteger(integerResult); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IInteger remainder(IInteger other){ - BigInteger result = value.remainder(((ICanBecomeABigInteger) other).toBigInteger()); - - if(other instanceof IntegerValue){ - int integerResult = result.intValue(); - return IntegerValue.newInteger(integerResult); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IInteger negate(){ - return new BigIntegerValue(value.negate()); - } - - @Override - public IBool equal(IInteger other){ - return BoolValue.getBoolValue(compare(other) == 0); - } - - @Override - public IBool equal(IReal other) { - return other.equal(this); - } - - @Override - public IBool equal(IRational other) { - return other.equal(this); - } - - @Override - public IBool greater(IInteger other){ - return BoolValue.getBoolValue(compare(other) > 0); - } - - @Override - public IBool greater(IReal other) { - return other.less(this); - } - - @Override - public IBool greater(IRational other) { - return other.less(this); - } - - @Override - public IBool greaterEqual(IInteger other){ - return BoolValue.getBoolValue(compare(other) >= 0); - } - - @Override - public IBool greaterEqual(IReal other) { - return other.lessEqual(this); - } - - @Override - public IBool greaterEqual(IRational other) { - return other.lessEqual(this); - } - - @Override - public IBool less(IInteger other){ - return BoolValue.getBoolValue(compare(other) < 0); - } - - @Override - public IBool less(IReal other) { - return other.greater(this); - } - - @Override - public IBool less(IRational other) { - return other.greater(this); - } - - @Override - public IBool lessEqual(IInteger other){ - return BoolValue.getBoolValue(compare(other) <= 0); - } - - @Override - public IBool lessEqual(IReal other) { - return other.greaterEqual(this); - } - - @Override - public IBool lessEqual(IRational other) { - return other.greaterEqual(this); - } - - @Override - public int compare(IInteger other){ - return value.compareTo(((ICanBecomeABigInteger) other).toBigInteger()); - } - - @Override - public int compare(INumber other) { - if (isIntegerType(other)) { - return compare(other.toInteger()); - } - else if (isRationalType(other)) { - return toRational().compare(other); - } - else { - assert other instanceof IReal; - return toReal(((IReal) other).precision()).compare(other); - } - } - - public int hashCode(){ - return value.hashCode(); - } - - public boolean equals(@Nullable Object o){ - if (o == null) { - return false; - } - - if (o == this) { - return true; - } - - if(o.getClass() == getClass()){ - BigIntegerValue otherInteger = (BigIntegerValue) o; - return value.equals(otherInteger.value); - } - - return false; - } - - @Override - public String getStringRepresentation(){ - return value.toString(); - } - - @Override - public int signum() { - return value.signum(); - } - - @Override - public IInteger abs() { - return IntegerValue.newInteger(value.abs()); - } - -} +/******************************************************************************* + * Copyright (c) 2009-2013 CWI + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * + * * Arnold Lankamp - interfaces and implementation + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + *******************************************************************************/ +package io.usethesource.vallang.impl.primitive; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import io.usethesource.vallang.IBool; +import io.usethesource.vallang.IInteger; +import io.usethesource.vallang.INumber; +import io.usethesource.vallang.IRational; +import io.usethesource.vallang.IReal; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; + +/** + * Specialized implementation for integer values that fall outside the 32-bit range. + * + * @author Arnold Lankamp + */ +/*package*/ class BigIntegerValue extends AbstractNumberValue implements IInteger, ICanBecomeABigInteger{ + private final static Type INTEGER_TYPE = TypeFactory.getInstance().integerType(); + + protected final BigInteger value; + + /*package*/ BigIntegerValue(BigInteger value){ + super(); + if(value.equals(BigInteger.ZERO)) + value = BigInteger.ZERO; + if(value.equals(BigInteger.ONE)) + value = BigInteger.ONE; + + this.value = value; + } + + @Override + public IInteger toInteger() { + return this; + } + + @Override + public Type getType(){ + return INTEGER_TYPE; + } + + @Override + public int intValue() throws ArithmeticException { + return value.intValueExact(); + } + + @Override + public long longValue() throws ArithmeticException { + return value.longValueExact(); + } + + @Override + public double doubleValue(){ + return value.doubleValue(); + } + + @Override + public IReal toReal(int precision){ + // precision is ignored intentionally + return BigDecimalValue.newReal(new BigDecimal(value)); + } + + @Override + public IRational toRational(){ + return RationalValue.newRational(this, IntegerValue.INTEGER_ONE); + } + @Override + public byte[] getTwosComplementRepresentation(){ + return value.toByteArray(); + } + + @Override + public BigInteger toBigInteger(){ + return value; + } + + @Override + public IInteger add(IInteger other){ + BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger(); + BigInteger result = value.add(o); + if(result == value) + return this; + else if(result == o) + return other; + int length = result.bitLength(); + if(length <= 31){ + return IntegerValue.newInteger(result.intValue()); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IReal add(IReal other) { + return (IReal) other.add(this); + } + + @Override + public IRational add(IRational other) { + return (IRational) other.add(this); + } + + @Override + public IInteger subtract(IInteger other){ + BigInteger result = value.subtract(((ICanBecomeABigInteger) other).toBigInteger()); + if(result == value) + return this; + + int length = result.bitLength(); + if(length <= 31){ + return IntegerValue.newInteger(result.intValue()); + } + + return IntegerValue.newInteger(result); + } + + @Override + public INumber subtract(IReal other) { + return toReal(other.precision()).subtract(other); + } + + @Override + public INumber subtract(IRational other) { + return toRational().subtract(other); + } + + @Override + public IInteger multiply(IInteger other){ + BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger(); + BigInteger result = value.multiply(o); + if(result == value) + return this; + else if(result == o) + return other; + // The result of this operation can never fit in a 32-bit integer, so no need to check. + return IntegerValue.newInteger(result); + } + + @Override + public IReal multiply(IReal other) { + return (IReal) other.multiply(this); + } + + @Override + public IRational multiply(IRational other) { + return (IRational) other.multiply(this); + } + @Override + public IInteger divide(IInteger other){ + BigInteger result = value.divide(((ICanBecomeABigInteger) other).toBigInteger()); + if(result == value) + return this; + + int length = result.bitLength(); + if(length <= 31){ + return IntegerValue.newInteger(result.intValue()); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IRational divide(IRational other) { + return toRational().divide(other); + } + + @Override + public INumber divide(IInteger other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public INumber divide(IRational other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public IReal divide(IReal other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public IInteger mod(IInteger other){ + BigInteger result = value.mod(((ICanBecomeABigInteger) other).toBigInteger()); + + if(other instanceof IntegerValue){ + int integerResult = result.intValue(); + return IntegerValue.newInteger(integerResult); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IInteger remainder(IInteger other){ + BigInteger result = value.remainder(((ICanBecomeABigInteger) other).toBigInteger()); + + if(other instanceof IntegerValue){ + int integerResult = result.intValue(); + return IntegerValue.newInteger(integerResult); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IInteger negate(){ + return new BigIntegerValue(value.negate()); + } + + @Override + public IBool equal(IInteger other) { + return BoolValue.getBoolValue(compare(other) == 0); + } + + @Override + public IBool equal(IReal other) { + return other.equal(this); + } + + @Override + public IBool equal(IRational other) { + return other.equal(this); + } + + @Override + public IBool greater(IInteger other){ + return BoolValue.getBoolValue(compare(other) > 0); + } + + @Override + public IBool greater(IReal other) { + return other.less(this); + } + + @Override + public IBool greater(IRational other) { + return other.less(this); + } + + @Override + public IBool greaterEqual(IInteger other){ + return BoolValue.getBoolValue(compare(other) >= 0); + } + + @Override + public IBool greaterEqual(IReal other) { + return other.lessEqual(this); + } + + @Override + public IBool greaterEqual(IRational other) { + return other.lessEqual(this); + } + + @Override + public IBool less(IInteger other){ + return BoolValue.getBoolValue(compare(other) < 0); + } + + @Override + public IBool less(IReal other) { + return other.greater(this); + } + + @Override + public IBool less(IRational other) { + return other.greater(this); + } + + @Override + public IBool lessEqual(IInteger other){ + return BoolValue.getBoolValue(compare(other) <= 0); + } + + @Override + public IBool lessEqual(IReal other) { + return other.greaterEqual(this); + } + + @Override + public IBool lessEqual(IRational other) { + return other.greaterEqual(this); + } + + @Override + public int compare(IInteger other){ + return value.compareTo(((ICanBecomeABigInteger) other).toBigInteger()); + } + + @Override + public int compare(INumber other) { + if (isIntegerType(other)) { + return compare(other.toInteger()); + } + else if (isRationalType(other)) { + return toRational().compare(other); + } + else { + assert other instanceof IReal; + return toReal(((IReal) other).precision()).compare(other); + } + } + + public int hashCode(){ + return value.hashCode(); + } + + public boolean equals(@Nullable Object o){ + if (o == null) { + return false; + } + + if (o == this) { + return true; + } + + if(o.getClass() == getClass()){ + BigIntegerValue otherInteger = (BigIntegerValue) o; + return value.equals(otherInteger.value); + } + + return false; + } + + @Override + public String getStringRepresentation(){ + return value.toString(); + } + + @Override + public int signum() { + return value.signum(); + } + + @Override + public IInteger abs() { + return IntegerValue.newInteger(value.abs()); + } + +} diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/BoolValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/BoolValue.java index 5e7f1bfd8..c6dc172d5 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/BoolValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/BoolValue.java @@ -19,112 +19,112 @@ import io.usethesource.vallang.type.TypeFactory; /*package*/ abstract class BoolValue implements IBool { - /*package*/ final static BoolValue TRUE = new BoolValue() { - @Override - public boolean getValue() { - return true; - } - - public int hashCode() { - return 1; - } - - @Override - public IBool not() { - return FALSE; - } - - @Override - public IBool and(IBool other) { - return other; - } - - @Override - public IBool or(IBool other) { - return this; - } - - @Override - public IBool xor(IBool other) { - return other == this ? FALSE : TRUE; - } - - @Override - public IBool implies(IBool other) { - return other; - } - - }; - - /*package*/ final static BoolValue FALSE = new BoolValue() { - @Override - public boolean getValue() { - return false; - } - - @Override - public IBool not() { - return TRUE; - } - - @Override - public IBool and(IBool other) { - return this; - } - - @Override - public IBool or(IBool other) { - return other; - } - - @Override - public IBool xor(IBool other) { - return other; - } - - @Override - public IBool implies(IBool other) { - return TRUE; - } - - public int hashCode() { - return 2; - } - }; - private final static Type BOOL_TYPE = TypeFactory.getInstance().boolType(); - - private BoolValue() { - super(); - } - - /*package*/ static BoolValue getBoolValue(boolean bool) { - return bool ? TRUE : FALSE; - } - - public abstract int hashCode(); + /*package*/ final static BoolValue TRUE = new BoolValue() { + @Override + public boolean getValue() { + return true; + } + + public int hashCode() { + return 1; + } + + @Override + public IBool not() { + return FALSE; + } + + @Override + public IBool and(IBool other) { + return other; + } + + @Override + public IBool or(IBool other) { + return this; + } + + @Override + public IBool xor(IBool other) { + return other == this ? FALSE : TRUE; + } + + @Override + public IBool implies(IBool other) { + return other; + } + + }; + + /*package*/ final static BoolValue FALSE = new BoolValue() { + @Override + public boolean getValue() { + return false; + } + + @Override + public IBool not() { + return TRUE; + } + + @Override + public IBool and(IBool other) { + return this; + } + + @Override + public IBool or(IBool other) { + return other; + } + + @Override + public IBool xor(IBool other) { + return other; + } + + @Override + public IBool implies(IBool other) { + return TRUE; + } + + public int hashCode() { + return 2; + } + }; + private final static Type BOOL_TYPE = TypeFactory.getInstance().boolType(); + + private BoolValue() { + super(); + } + + /*package*/ static BoolValue getBoolValue(boolean bool) { + return bool ? TRUE : FALSE; + } + + public abstract int hashCode(); @Override public String toString() { return defaultToString(); } - - public boolean equals(@Nullable Object o) { - return this == o; - } - - @Override - public Type getType() { - return BOOL_TYPE; - } - - @Override - public IBool equivalent(IBool other) { - return other == this ? TRUE : this; - } - - @Override - public String getStringRepresentation() { - return toString(); - } + + public boolean equals(@Nullable Object o) { + return this == o; + } + + @Override + public Type getType() { + return BOOL_TYPE; + } + + @Override + public IBool equivalent(IBool other) { + return other == this ? TRUE : this; + } + + @Override + public String getStringRepresentation() { + return toString(); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/DateTimeValues.java b/src/main/java/io/usethesource/vallang/impl/primitive/DateTimeValues.java index 6c8240f24..2c4ef835c 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/DateTimeValues.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/DateTimeValues.java @@ -1,665 +1,665 @@ -/******************************************************************************* - * Copyright (c) 2009-2013 CWI - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * - * * Mark Hills (Mark.Hills@cwi.nl) - initial API and implementation - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI - *******************************************************************************/ -package io.usethesource.vallang.impl.primitive; - -import java.time.DateTimeException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.util.concurrent.TimeUnit; -import org.checkerframework.checker.nullness.qual.Nullable; -import io.usethesource.vallang.IDateTime; -import io.usethesource.vallang.IString; -import io.usethesource.vallang.exceptions.InvalidDateTimeException; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; - - -/** A concrete instance of IDateTime, representing either a date, - * a time, or a date with time. - * - * NOTE: We currently do not support partial dates and times; i.e., - * it is not possible to represent "July 2009" or "15" (hours). - * - */ -/*package*/ class DateTimeValues { - - private static final Type DATE_TIME_TYPE = TypeFactory.getInstance().dateTimeType(); - - /*package*/ static IDateTime newDate(int year, int month, int day) { - return new DateTimeValues.DateValue(year, month, day); - } - - - private static class DateValue implements IDateTime { - private final LocalDate actual; - - /** - * Construct a DateTime object representing a date. - * - * @param year The year of the date - * @param month The month of the date - * @param day The day of the date - */ - private DateValue(int year, int month, int day) { - try { - actual = LocalDate.of(year, month, day); - } - catch (DateTimeException dt) { - throw new InvalidDateTimeException("Cannot create date with provided values.", dt); - } - } - - @Override - public Type getType() { - return DATE_TIME_TYPE; - } - - @Override - public int compareTo(IDateTime arg0) { - if (arg0 instanceof DateValue) { - return actual.compareTo(((DateValue)arg0).actual); - } - if (arg0.isDate()) { - return Long.compare(getInstant(), arg0.getInstant()); - } - throw new UnsupportedOperationException("Date and non-Date values are not comparable"); - } - - /* (non-Javadoc) - * @see IDateTime#getInstant() - */ - @Override - public long getInstant() { - return actual - .atTime(LocalTime.MIN) - .atZone(ZoneId.systemDefault()) - .toEpochSecond() * 1000; - } - - /* (non-Javadoc) - * @see IDateTime#getCentury() - */ - @Override - public int getCentury() { - return (getYear() - (getYear() % 100)) / 100; - } - - /* (non-Javadoc) - * @see IDateTime#getYear() - */ - @Override - public int getYear() { - return actual.getYear(); - } - - /* (non-Javadoc) - * @see IDateTime#getMonthOfYear() - */ - @Override - public int getMonthOfYear() { - return actual.getMonthValue(); - } - - /* (non-Javadoc) - * @see IDateTime#getDayOfMonth() - */ - @Override - public int getDayOfMonth() { - return actual.getDayOfMonth(); - } - - /* (non-Javadoc) - * @see IDateTime#getHourOfDay() - */ - @Override - public int getHourOfDay() { - throw new UnsupportedOperationException("Cannot get hours on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#getMinuteOfHour() - */ - @Override - public int getMinuteOfHour() { - throw new UnsupportedOperationException("Cannot get minutes on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#getSecondOfMinute() - */ - @Override - public int getSecondOfMinute() { - throw new UnsupportedOperationException("Cannot get seconds on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#getMillisecondsOfSecond() - */ - @Override - public int getMillisecondsOfSecond() { - throw new UnsupportedOperationException("Cannot get milliseconds on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetHours() - */ - @Override - public int getTimezoneOffsetHours() { - throw new UnsupportedOperationException("Cannot get timezone offset hours on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetMinutes() - */ - @Override - public int getTimezoneOffsetMinutes() { - throw new UnsupportedOperationException("Cannot get timezone offset minutes on a date value"); - } - - /* (non-Javadoc) - * @see IDateTime#isDate() - */ - @Override - public boolean isDate() { - return true; - } - - /* (non-Javadoc) - * @see IDateTime#isTime() - */ - @Override - public boolean isTime() { - return false; - } - - /* (non-Javadoc) - * @see IDateTime#isDateTime() - */ - @Override - public boolean isDateTime() { - return false; - } - - @Override - public int hashCode() { - return actual.hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof DateValue) { - return ((DateValue)obj).actual.equals(actual); - } - return false; - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public IString format(String format) { - return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); - } - } - - /*package*/ static IDateTime newTime(int hour, int minute, int second, int millisecond) { - return new DateTimeValues.TimeValue(hour, minute, second, millisecond); - } - - /*package*/ static IDateTime newTime(int hour, int minute, int second, int millisecond, - int hourOffset, int minuteOffset) { - return new DateTimeValues.TimeValue(hour, minute, second, millisecond, hourOffset, minuteOffset); - } - - private static long currentTotalOffset() { - // subjectief? - return OffsetDateTime.now().getOffset().getTotalSeconds(); - } - - private static int currentHourOffset() { - return (int) TimeUnit.HOURS.convert(currentTotalOffset(), TimeUnit.SECONDS); - } - - private static int currentMinuteOffset() { - return (int) (TimeUnit.MINUTES.convert(currentTotalOffset(), TimeUnit.SECONDS) % 60); - } - - private static ZoneOffset toOffset(int hourOffset, int minuteOffset) { - return ZoneOffset.ofHoursMinutes(hourOffset, minuteOffset); - } - private static class TimeValue implements IDateTime { - private final OffsetTime actual; - - /** - * Construct a DateTime object representing a time. - * - * @param hour The hour of the time - * @param minute The minute of the time - * @param second The second of the time - * @param millisecond The millisecond of the time - */ - private TimeValue(int hour, int minute, int second, int millisecond) { - this(hour, minute, second, millisecond, currentHourOffset(), currentMinuteOffset()); - } - - /** - * Construct a DateTime object representing a time with an explicit timezone offset. - * - * @param hour The hour of the time - * @param minute The minute of the time - * @param second The second of the time - * @param millisecond The millisecond of the time - * @param hourOffset The timezone offset of the time, in hours - * @param minuteOffset The timezone offset of the time, in minutes - */ - private TimeValue(int hour, int minute, int second, int millisecond, int hourOffset, int minuteOffset) { - try { - actual = OffsetTime.of(hour, minute, second, (int)TimeUnit.MILLISECONDS.toNanos(millisecond), toOffset(hourOffset, minuteOffset)); - } - catch (DateTimeException dt) { - throw new InvalidDateTimeException("Cannot create date with provided values.", dt); - } - } - - @Override - public Type getType() { - return DATE_TIME_TYPE; - } - - @Override - public int compareTo(IDateTime arg0) { - if (arg0 instanceof TimeValue) { - return actual.compareTo(((TimeValue)arg0).actual); - } - if (arg0.isTime()) { - return Long.compare(getInstant(), arg0.getInstant()); - } - throw new UnsupportedOperationException("Time and non-Time values are not comparable"); - } - - /* (non-Javadoc) - * @see IDateTime#getInstant() - */ - @Override - public long getInstant() { - return actual - .atDate(LocalDate.of(1970, 1, 1)) - .toInstant() - .toEpochMilli() - ; - } - - /* (non-Javadoc) - * @see IDateTime#getCentury() - */ - @Override - public int getCentury() { - throw new UnsupportedOperationException("Cannot get century on a time value"); - } - - /* (non-Javadoc) - * @see IDateTime#getYear() - */ - @Override - public int getYear() { - throw new UnsupportedOperationException("Cannot get year on a time value"); - } - - /* (non-Javadoc) - * @see IDateTime#getMonthOfYear() - */ - @Override - public int getMonthOfYear() { - throw new UnsupportedOperationException("Cannot get month on a time value"); - } - - /* (non-Javadoc) - * @see IDateTime#getDayOfMonth() - */ - @Override - public int getDayOfMonth() { - throw new UnsupportedOperationException("Cannot get day on a time value"); - } - - /* (non-Javadoc) - * @see IDateTime#getHourOfDay() - */ - @Override - public int getHourOfDay() { - return actual.getHour(); - } - - /* (non-Javadoc) - * @see IDateTime#getMinuteOfHour() - */ - @Override - public int getMinuteOfHour() { - return actual.getMinute(); - } - - /* (non-Javadoc) - * @see IDateTime#getSecondOfMinute() - */ - @Override - public int getSecondOfMinute() { - return actual.getSecond(); - } - - /* (non-Javadoc) - * @see IDateTime#getMillisecondsOfSecond() - */ - @Override - public int getMillisecondsOfSecond() { - return (int) TimeUnit.MILLISECONDS.convert(actual.getNano(), TimeUnit.NANOSECONDS); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetHours() - */ - @Override - public int getTimezoneOffsetHours() { - return (int)TimeUnit.HOURS.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetMinutes() - */ - @Override - public int getTimezoneOffsetMinutes() { - return (int)(TimeUnit.MINUTES.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS) % 60); - } - - /* (non-Javadoc) - * @see IDateTime#isDate() - */ - @Override - public boolean isDate() { - return false; - } - - /* (non-Javadoc) - * @see IDateTime#isTime() - */ - @Override - public boolean isTime() { - return true; - } - - /* (non-Javadoc) - * @see IDateTime#isDateTime() - */ - @Override - public boolean isDateTime() { - return false; - } - - @Override - public int hashCode() { - return actual.hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof TimeValue) { - return actual.equals(((TimeValue)obj).actual); - } - return false; - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public IString format(String format) { - return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); - } - } - - /*package*/ static IDateTime newDateTime(int year, int month, int day, int hour, - int minute, int second, int millisecond) { - return new DateTimeValues.DateTimeValue(year, month, day, hour, minute, second, millisecond); - } - - /*package*/ static IDateTime newDateTime(int year, int month, int day, int hour, - int minute, int second, int millisecond, int hourOffset, - int minuteOffset) { - return new DateTimeValues.DateTimeValue(year, month, day, hour, minute, second, millisecond, hourOffset, minuteOffset); - } - - /*package*/ static IDateTime newDateTime(long instant) { - return new DateTimeValues.DateTimeValue(instant, 0, 0); - } - - /*package*/ static IDateTime newDateTime(long instant, int timezoneHours, int timezoneMinutes) { - return new DateTimeValues.DateTimeValue(instant, timezoneHours, timezoneMinutes); - } - - private static class DateTimeValue implements IDateTime { - private final OffsetDateTime actual; - - /** - * Construct a DateTime object representing a date and time. - * - * @param year The year of the datetime - * @param month The month of the datetime - * @param day The day of the datetime - * @param hour The hour of the datetime - * @param minute The minute of the datetime - * @param second The second of the datetime - * @param millisecond The millisecond of the datetime - */ - private DateTimeValue(int year, int month, int day, int hour, int minute, int second, int millisecond) { - this(year, month, day, hour, minute, second, millisecond, currentHourOffset(), currentMinuteOffset()); - } - - /** - * Construct a DateTime object representing a date and time, with an explicit timezone. - * - * @param year The year of the datetime - * @param month The month of the datetime - * @param day The day of the datetime - * @param hour The hour of the datetime - * @param minute The minute of the datetime - * @param second The second of the datetime - * @param millisecond The millisecond of the datetime - * @param hourOffset The timezone offset of the time, in hours - * @param minuteOffset The timezone offset of the time, in minutes - */ - private DateTimeValue(int year, int month, int day, int hour, int minute, int second, int millisecond, int hourOffset, int minuteOffset) { - try { - actual = OffsetDateTime.of(year, month, day, hour, minute, second, (int)TimeUnit.MILLISECONDS.toNanos(millisecond), toOffset(hourOffset, minuteOffset)); - } - catch (DateTimeException dt) { - throw new InvalidDateTimeException("Cannot create date with provided values.", dt); - } - } - - /** - * Construct a DateTime object representing the current instant on the date/time - * scale (in milliseconds, based on the Java epoch). - * - * @param instant The millisecond instant. - * @param timezoneHours The hour offset for the new object's timezone - * @param timezoneMinutes The minute offset for the new object's timezone - */ - private DateTimeValue(long instant, int timezoneHours, int timezoneMinutes) { - try { - actual = Instant.ofEpochMilli(instant).atOffset(toOffset(timezoneHours, timezoneMinutes)); - } - catch (DateTimeException dt) { - throw new InvalidDateTimeException("Cannot create date with provided values.", dt); - } - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public Type getType() { - return DATE_TIME_TYPE; - } - - @Override - public int compareTo(IDateTime arg0) { - if (arg0 instanceof DateTimeValue) { - return actual.compareTo(((DateTimeValue)arg0).actual); - } - if (arg0.isDateTime()) { - return Long.compare(getInstant(), arg0.getInstant()); - } - throw new UnsupportedOperationException("DateTime and non-DateTime values are not comparable"); - } - - /* (non-Javadoc) - * @see IDateTime#getInstant() - */ - @Override - public long getInstant() { - return actual.toInstant().toEpochMilli(); - } - - /* (non-Javadoc) - * @see IDateTime#getCentury() - */ - @Override - public int getCentury() { - return (getYear() - (getYear() % 100)) / 100; - } - - /* (non-Javadoc) - * @see IDateTime#getYear() - */ - @Override - public int getYear() { - return actual.getYear(); - } - - /* (non-Javadoc) - * @see IDateTime#getMonthOfYear() - */ - @Override - public int getMonthOfYear() { - return actual.getMonthValue(); - } - - /* (non-Javadoc) - * @see IDateTime#getDayOfMonth() - */ - @Override - public int getDayOfMonth() { - return actual.getDayOfMonth(); - } - - /* (non-Javadoc) - * @see IDateTime#getHourOfDay() - */ - @Override - public int getHourOfDay() { - return actual.getHour(); - } - - /* (non-Javadoc) - * @see IDateTime#getMinuteOfHour() - */ - @Override - public int getMinuteOfHour() { - return actual.getMinute(); - } - - /* (non-Javadoc) - * @see IDateTime#getSecondOfMinute() - */ - @Override - public int getSecondOfMinute() { - return actual.getSecond(); - } - - /* (non-Javadoc) - * @see IDateTime#getMillisecondsOfSecond() - */ - @Override - public int getMillisecondsOfSecond() { - return (int) TimeUnit.MILLISECONDS.convert(actual.getNano(), TimeUnit.NANOSECONDS); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetHours() - */ - @Override - public int getTimezoneOffsetHours() { - return (int) TimeUnit.HOURS.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS); - } - - /* (non-Javadoc) - * @see IDateTime#getTimezoneOffsetMinutes() - */ - @Override - public int getTimezoneOffsetMinutes() { - return (int) (TimeUnit.MINUTES.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS) % 60); - } - - /* (non-Javadoc) - * @see IDateTime#isDate() - */ - @Override - public boolean isDate() { - return false; - } - - /* (non-Javadoc) - * @see IDateTime#isTime() - */ - @Override - public boolean isTime() { - return false; - } - - /* (non-Javadoc) - * @see IDateTime#isDateTime() - */ - @Override - public boolean isDateTime() { - return true; - } - - @Override - public int hashCode() { - return actual.hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof DateTimeValue) { - return actual.equals(((DateTimeValue)obj).actual); - } - return false; - } - - @Override - public IString format(String format) { - return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); - } - } +/******************************************************************************* + * Copyright (c) 2009-2013 CWI + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * + * * Mark Hills (Mark.Hills@cwi.nl) - initial API and implementation + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + *******************************************************************************/ +package io.usethesource.vallang.impl.primitive; + +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.Nullable; +import io.usethesource.vallang.IDateTime; +import io.usethesource.vallang.IString; +import io.usethesource.vallang.exceptions.InvalidDateTimeException; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; + + +/** A concrete instance of IDateTime, representing either a date, + * a time, or a date with time. + * + * NOTE: We currently do not support partial dates and times; i.e., + * it is not possible to represent "July 2009" or "15" (hours). + * + */ +/*package*/ class DateTimeValues { + + private static final Type DATE_TIME_TYPE = TypeFactory.getInstance().dateTimeType(); + + /*package*/ static IDateTime newDate(int year, int month, int day) { + return new DateTimeValues.DateValue(year, month, day); + } + + + private static class DateValue implements IDateTime { + private final LocalDate actual; + + /** + * Construct a DateTime object representing a date. + * + * @param year The year of the date + * @param month The month of the date + * @param day The day of the date + */ + private DateValue(int year, int month, int day) { + try { + actual = LocalDate.of(year, month, day); + } + catch (DateTimeException dt) { + throw new InvalidDateTimeException("Cannot create date with provided values.", dt); + } + } + + @Override + public Type getType() { + return DATE_TIME_TYPE; + } + + @Override + public int compareTo(IDateTime arg0) { + if (arg0 instanceof DateValue) { + return actual.compareTo(((DateValue)arg0).actual); + } + if (arg0.isDate()) { + return Long.compare(getInstant(), arg0.getInstant()); + } + throw new UnsupportedOperationException("Date and non-Date values are not comparable"); + } + + /* (non-Javadoc) + * @see IDateTime#getInstant() + */ + @Override + public long getInstant() { + return actual + .atTime(LocalTime.MIN) + .atZone(ZoneId.systemDefault()) + .toEpochSecond() * 1000; + } + + /* (non-Javadoc) + * @see IDateTime#getCentury() + */ + @Override + public int getCentury() { + return (getYear() - (getYear() % 100)) / 100; + } + + /* (non-Javadoc) + * @see IDateTime#getYear() + */ + @Override + public int getYear() { + return actual.getYear(); + } + + /* (non-Javadoc) + * @see IDateTime#getMonthOfYear() + */ + @Override + public int getMonthOfYear() { + return actual.getMonthValue(); + } + + /* (non-Javadoc) + * @see IDateTime#getDayOfMonth() + */ + @Override + public int getDayOfMonth() { + return actual.getDayOfMonth(); + } + + /* (non-Javadoc) + * @see IDateTime#getHourOfDay() + */ + @Override + public int getHourOfDay() { + throw new UnsupportedOperationException("Cannot get hours on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#getMinuteOfHour() + */ + @Override + public int getMinuteOfHour() { + throw new UnsupportedOperationException("Cannot get minutes on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#getSecondOfMinute() + */ + @Override + public int getSecondOfMinute() { + throw new UnsupportedOperationException("Cannot get seconds on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#getMillisecondsOfSecond() + */ + @Override + public int getMillisecondsOfSecond() { + throw new UnsupportedOperationException("Cannot get milliseconds on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetHours() + */ + @Override + public int getTimezoneOffsetHours() { + throw new UnsupportedOperationException("Cannot get timezone offset hours on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetMinutes() + */ + @Override + public int getTimezoneOffsetMinutes() { + throw new UnsupportedOperationException("Cannot get timezone offset minutes on a date value"); + } + + /* (non-Javadoc) + * @see IDateTime#isDate() + */ + @Override + public boolean isDate() { + return true; + } + + /* (non-Javadoc) + * @see IDateTime#isTime() + */ + @Override + public boolean isTime() { + return false; + } + + /* (non-Javadoc) + * @see IDateTime#isDateTime() + */ + @Override + public boolean isDateTime() { + return false; + } + + @Override + public int hashCode() { + return actual.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof DateValue) { + return ((DateValue)obj).actual.equals(actual); + } + return false; + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public IString format(String format) { + return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); + } + } + + /*package*/ static IDateTime newTime(int hour, int minute, int second, int millisecond) { + return new DateTimeValues.TimeValue(hour, minute, second, millisecond); + } + + /*package*/ static IDateTime newTime(int hour, int minute, int second, int millisecond, + int hourOffset, int minuteOffset) { + return new DateTimeValues.TimeValue(hour, minute, second, millisecond, hourOffset, minuteOffset); + } + + private static long currentTotalOffset() { + // subjectief? + return OffsetDateTime.now().getOffset().getTotalSeconds(); + } + + private static int currentHourOffset() { + return (int) TimeUnit.HOURS.convert(currentTotalOffset(), TimeUnit.SECONDS); + } + + private static int currentMinuteOffset() { + return (int) (TimeUnit.MINUTES.convert(currentTotalOffset(), TimeUnit.SECONDS) % 60); + } + + private static ZoneOffset toOffset(int hourOffset, int minuteOffset) { + return ZoneOffset.ofHoursMinutes(hourOffset, minuteOffset); + } + private static class TimeValue implements IDateTime { + private final OffsetTime actual; + + /** + * Construct a DateTime object representing a time. + * + * @param hour The hour of the time + * @param minute The minute of the time + * @param second The second of the time + * @param millisecond The millisecond of the time + */ + private TimeValue(int hour, int minute, int second, int millisecond) { + this(hour, minute, second, millisecond, currentHourOffset(), currentMinuteOffset()); + } + + /** + * Construct a DateTime object representing a time with an explicit timezone offset. + * + * @param hour The hour of the time + * @param minute The minute of the time + * @param second The second of the time + * @param millisecond The millisecond of the time + * @param hourOffset The timezone offset of the time, in hours + * @param minuteOffset The timezone offset of the time, in minutes + */ + private TimeValue(int hour, int minute, int second, int millisecond, int hourOffset, int minuteOffset) { + try { + actual = OffsetTime.of(hour, minute, second, (int)TimeUnit.MILLISECONDS.toNanos(millisecond), toOffset(hourOffset, minuteOffset)); + } + catch (DateTimeException dt) { + throw new InvalidDateTimeException("Cannot create date with provided values.", dt); + } + } + + @Override + public Type getType() { + return DATE_TIME_TYPE; + } + + @Override + public int compareTo(IDateTime arg0) { + if (arg0 instanceof TimeValue) { + return actual.compareTo(((TimeValue)arg0).actual); + } + if (arg0.isTime()) { + return Long.compare(getInstant(), arg0.getInstant()); + } + throw new UnsupportedOperationException("Time and non-Time values are not comparable"); + } + + /* (non-Javadoc) + * @see IDateTime#getInstant() + */ + @Override + public long getInstant() { + return actual + .atDate(LocalDate.of(1970, 1, 1)) + .toInstant() + .toEpochMilli() + ; + } + + /* (non-Javadoc) + * @see IDateTime#getCentury() + */ + @Override + public int getCentury() { + throw new UnsupportedOperationException("Cannot get century on a time value"); + } + + /* (non-Javadoc) + * @see IDateTime#getYear() + */ + @Override + public int getYear() { + throw new UnsupportedOperationException("Cannot get year on a time value"); + } + + /* (non-Javadoc) + * @see IDateTime#getMonthOfYear() + */ + @Override + public int getMonthOfYear() { + throw new UnsupportedOperationException("Cannot get month on a time value"); + } + + /* (non-Javadoc) + * @see IDateTime#getDayOfMonth() + */ + @Override + public int getDayOfMonth() { + throw new UnsupportedOperationException("Cannot get day on a time value"); + } + + /* (non-Javadoc) + * @see IDateTime#getHourOfDay() + */ + @Override + public int getHourOfDay() { + return actual.getHour(); + } + + /* (non-Javadoc) + * @see IDateTime#getMinuteOfHour() + */ + @Override + public int getMinuteOfHour() { + return actual.getMinute(); + } + + /* (non-Javadoc) + * @see IDateTime#getSecondOfMinute() + */ + @Override + public int getSecondOfMinute() { + return actual.getSecond(); + } + + /* (non-Javadoc) + * @see IDateTime#getMillisecondsOfSecond() + */ + @Override + public int getMillisecondsOfSecond() { + return (int) TimeUnit.MILLISECONDS.convert(actual.getNano(), TimeUnit.NANOSECONDS); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetHours() + */ + @Override + public int getTimezoneOffsetHours() { + return (int)TimeUnit.HOURS.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetMinutes() + */ + @Override + public int getTimezoneOffsetMinutes() { + return (int)(TimeUnit.MINUTES.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS) % 60); + } + + /* (non-Javadoc) + * @see IDateTime#isDate() + */ + @Override + public boolean isDate() { + return false; + } + + /* (non-Javadoc) + * @see IDateTime#isTime() + */ + @Override + public boolean isTime() { + return true; + } + + /* (non-Javadoc) + * @see IDateTime#isDateTime() + */ + @Override + public boolean isDateTime() { + return false; + } + + @Override + public int hashCode() { + return actual.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof TimeValue) { + return actual.equals(((TimeValue)obj).actual); + } + return false; + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public IString format(String format) { + return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); + } + } + + /*package*/ static IDateTime newDateTime(int year, int month, int day, int hour, + int minute, int second, int millisecond) { + return new DateTimeValues.DateTimeValue(year, month, day, hour, minute, second, millisecond); + } + + /*package*/ static IDateTime newDateTime(int year, int month, int day, int hour, + int minute, int second, int millisecond, int hourOffset, + int minuteOffset) { + return new DateTimeValues.DateTimeValue(year, month, day, hour, minute, second, millisecond, hourOffset, minuteOffset); + } + + /*package*/ static IDateTime newDateTime(long instant) { + return new DateTimeValues.DateTimeValue(instant, 0, 0); + } + + /*package*/ static IDateTime newDateTime(long instant, int timezoneHours, int timezoneMinutes) { + return new DateTimeValues.DateTimeValue(instant, timezoneHours, timezoneMinutes); + } + + private static class DateTimeValue implements IDateTime { + private final OffsetDateTime actual; + + /** + * Construct a DateTime object representing a date and time. + * + * @param year The year of the datetime + * @param month The month of the datetime + * @param day The day of the datetime + * @param hour The hour of the datetime + * @param minute The minute of the datetime + * @param second The second of the datetime + * @param millisecond The millisecond of the datetime + */ + private DateTimeValue(int year, int month, int day, int hour, int minute, int second, int millisecond) { + this(year, month, day, hour, minute, second, millisecond, currentHourOffset(), currentMinuteOffset()); + } + + /** + * Construct a DateTime object representing a date and time, with an explicit timezone. + * + * @param year The year of the datetime + * @param month The month of the datetime + * @param day The day of the datetime + * @param hour The hour of the datetime + * @param minute The minute of the datetime + * @param second The second of the datetime + * @param millisecond The millisecond of the datetime + * @param hourOffset The timezone offset of the time, in hours + * @param minuteOffset The timezone offset of the time, in minutes + */ + private DateTimeValue(int year, int month, int day, int hour, int minute, int second, int millisecond, int hourOffset, int minuteOffset) { + try { + actual = OffsetDateTime.of(year, month, day, hour, minute, second, (int)TimeUnit.MILLISECONDS.toNanos(millisecond), toOffset(hourOffset, minuteOffset)); + } + catch (DateTimeException dt) { + throw new InvalidDateTimeException("Cannot create date with provided values.", dt); + } + } + + /** + * Construct a DateTime object representing the current instant on the date/time + * scale (in milliseconds, based on the Java epoch). + * + * @param instant The millisecond instant. + * @param timezoneHours The hour offset for the new object's timezone + * @param timezoneMinutes The minute offset for the new object's timezone + */ + private DateTimeValue(long instant, int timezoneHours, int timezoneMinutes) { + try { + actual = Instant.ofEpochMilli(instant).atOffset(toOffset(timezoneHours, timezoneMinutes)); + } + catch (DateTimeException dt) { + throw new InvalidDateTimeException("Cannot create date with provided values.", dt); + } + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public Type getType() { + return DATE_TIME_TYPE; + } + + @Override + public int compareTo(IDateTime arg0) { + if (arg0 instanceof DateTimeValue) { + return actual.compareTo(((DateTimeValue)arg0).actual); + } + if (arg0.isDateTime()) { + return Long.compare(getInstant(), arg0.getInstant()); + } + throw new UnsupportedOperationException("DateTime and non-DateTime values are not comparable"); + } + + /* (non-Javadoc) + * @see IDateTime#getInstant() + */ + @Override + public long getInstant() { + return actual.toInstant().toEpochMilli(); + } + + /* (non-Javadoc) + * @see IDateTime#getCentury() + */ + @Override + public int getCentury() { + return (getYear() - (getYear() % 100)) / 100; + } + + /* (non-Javadoc) + * @see IDateTime#getYear() + */ + @Override + public int getYear() { + return actual.getYear(); + } + + /* (non-Javadoc) + * @see IDateTime#getMonthOfYear() + */ + @Override + public int getMonthOfYear() { + return actual.getMonthValue(); + } + + /* (non-Javadoc) + * @see IDateTime#getDayOfMonth() + */ + @Override + public int getDayOfMonth() { + return actual.getDayOfMonth(); + } + + /* (non-Javadoc) + * @see IDateTime#getHourOfDay() + */ + @Override + public int getHourOfDay() { + return actual.getHour(); + } + + /* (non-Javadoc) + * @see IDateTime#getMinuteOfHour() + */ + @Override + public int getMinuteOfHour() { + return actual.getMinute(); + } + + /* (non-Javadoc) + * @see IDateTime#getSecondOfMinute() + */ + @Override + public int getSecondOfMinute() { + return actual.getSecond(); + } + + /* (non-Javadoc) + * @see IDateTime#getMillisecondsOfSecond() + */ + @Override + public int getMillisecondsOfSecond() { + return (int) TimeUnit.MILLISECONDS.convert(actual.getNano(), TimeUnit.NANOSECONDS); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetHours() + */ + @Override + public int getTimezoneOffsetHours() { + return (int) TimeUnit.HOURS.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS); + } + + /* (non-Javadoc) + * @see IDateTime#getTimezoneOffsetMinutes() + */ + @Override + public int getTimezoneOffsetMinutes() { + return (int) (TimeUnit.MINUTES.convert(actual.getOffset().getTotalSeconds(), TimeUnit.SECONDS) % 60); + } + + /* (non-Javadoc) + * @see IDateTime#isDate() + */ + @Override + public boolean isDate() { + return false; + } + + /* (non-Javadoc) + * @see IDateTime#isTime() + */ + @Override + public boolean isTime() { + return false; + } + + /* (non-Javadoc) + * @see IDateTime#isDateTime() + */ + @Override + public boolean isDateTime() { + return true; + } + + @Override + public int hashCode() { + return actual.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof DateTimeValue) { + return actual.equals(((DateTimeValue)obj).actual); + } + return false; + } + + @Override + public IString format(String format) { + return StringValue.newString(actual.format(DateTimeFormatter.ofPattern(format))); + } + } } \ No newline at end of file diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/ICanBecomeABigInteger.java b/src/main/java/io/usethesource/vallang/impl/primitive/ICanBecomeABigInteger.java index c9ffa49f4..27d70badd 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/ICanBecomeABigInteger.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/ICanBecomeABigInteger.java @@ -15,15 +15,15 @@ /** * Strangely named class, which defines that the implementor can convert something to a big integer. - * + * * @author Arnold Lankamp */ public interface ICanBecomeABigInteger{ - - /** - * Returns the big integer. - * - * @return The big integer. - */ - BigInteger toBigInteger(); + + /** + * Returns the big integer. + * + * @return The big integer. + */ + BigInteger toBigInteger(); } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java index d2bce4b20..1ca324ede 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java @@ -29,542 +29,542 @@ * Implementation for IInteger. *

* Integer values that fall outside the 32-bit range will be store in BigIntegerValue instead. - * + * * @author Arnold Lankamp */ /*package*/ class IntegerValue extends AbstractNumberValue implements IInteger, ICanBecomeABigInteger{ - private final static Type INTEGER_TYPE = TypeFactory.getInstance().integerType(); - - private final static String INTEGER_MAX_STRING = "2147483647"; - private final static String NEGATIVE_INTEGER_MAX_STRING = "-2147483648"; - - private final static int SEVEN_BITS_MASK = 0x0000007f; - private final static int FIFTEEN_BITS_MASK = 0x00007fff; - private final static int TWENTYTHREE_BITS_MASK = 0x007fffff; - - private final static IInteger[] smallValues; - private final static BigInteger[] smallBigIntegerValues; - private final static int minSmallValue = -100; - private final static int maxSmallValue = 100; - public final static IInteger INTEGER_ONE; - public final static IInteger INTEGER_ZERO; - static { - smallValues = new IInteger[(maxSmallValue - minSmallValue) + 1]; - smallBigIntegerValues = new BigInteger[(maxSmallValue - minSmallValue) + 1]; - for (int i = minSmallValue; i <= maxSmallValue; i++) { - smallValues[i - minSmallValue] = new IntegerValue(i); - smallBigIntegerValues[i - minSmallValue] = new BigInteger("" + i); - } - INTEGER_ONE = smallValues[1 - minSmallValue]; - INTEGER_ZERO = smallValues[0 - minSmallValue]; - } - - protected final int value; - - /* - * TODO: Unify IntegerValue and BigIntegerValue in same java class file. - */ - /*package*/ static IInteger newInteger(BigInteger value) { - if (value.bitLength() > 31) { - return new BigIntegerValue(value); - } - return newInteger(value.intValue()); - } - - - /*package*/ static IInteger newInteger(int value) { - if (minSmallValue <= value && value <= maxSmallValue) { - return smallValues[value - minSmallValue]; - } + private final static Type INTEGER_TYPE = TypeFactory.getInstance().integerType(); + + private final static String INTEGER_MAX_STRING = "2147483647"; + private final static String NEGATIVE_INTEGER_MAX_STRING = "-2147483648"; + + private final static int SEVEN_BITS_MASK = 0x0000007f; + private final static int FIFTEEN_BITS_MASK = 0x00007fff; + private final static int TWENTYTHREE_BITS_MASK = 0x007fffff; + + private final static IInteger[] smallValues; + private final static BigInteger[] smallBigIntegerValues; + private final static int minSmallValue = -100; + private final static int maxSmallValue = 100; + public final static IInteger INTEGER_ONE; + public final static IInteger INTEGER_ZERO; + static { + smallValues = new IInteger[(maxSmallValue - minSmallValue) + 1]; + smallBigIntegerValues = new BigInteger[(maxSmallValue - minSmallValue) + 1]; + for (int i = minSmallValue; i <= maxSmallValue; i++) { + smallValues[i - minSmallValue] = new IntegerValue(i); + smallBigIntegerValues[i - minSmallValue] = new BigInteger("" + i); + } + INTEGER_ONE = smallValues[1 - minSmallValue]; + INTEGER_ZERO = smallValues[0 - minSmallValue]; + } + + protected final int value; + + /* + * TODO: Unify IntegerValue and BigIntegerValue in same java class file. + */ + /*package*/ static IInteger newInteger(BigInteger value) { + if (value.bitLength() > 31) { + return new BigIntegerValue(value); + } + return newInteger(value.intValue()); + } + + + /*package*/ static IInteger newInteger(int value) { + if (minSmallValue <= value && value <= maxSmallValue) { + return smallValues[value - minSmallValue]; + } return new IntegerValue(value); - } - - /*package*/ static IInteger newInteger(String integerValue) { - if (integerValue.startsWith("-")) { - if (integerValue.length() < 11 || (integerValue.length() == 11 && integerValue.compareTo(NEGATIVE_INTEGER_MAX_STRING) <= 0)) { - return newInteger(Integer.parseInt(integerValue)); - } - return new BigIntegerValue(new BigInteger(integerValue)); - } - - if (integerValue.length() < 10 || (integerValue.length() == 10 && integerValue.compareTo(INTEGER_MAX_STRING) <= 0)) { - return newInteger(Integer.parseInt(integerValue)); - } - return new BigIntegerValue(new BigInteger(integerValue)); - } - - /*package*/ static IInteger newInteger(long value) { - if (((value & 0x000000007fffffffL) == value) || ((value & 0xffffffff80000000L) == 0xffffffff80000000L)) { - return newInteger((int) value); - } else { - byte[] valueData = new byte[8]; - valueData[0] = (byte) ((value >>> 56) & 0xff); - valueData[1] = (byte) ((value >>> 48) & 0xff); - valueData[2] = (byte) ((value >>> 40) & 0xff); - valueData[3] = (byte) ((value >>> 32) & 0xff); - valueData[4] = (byte) ((value >>> 24) & 0xff); - valueData[5] = (byte) ((value >>> 16) & 0xff); - valueData[6] = (byte) ((value >>> 8) & 0xff); - valueData[7] = (byte) (value & 0xff); - return newInteger(valueData); - } - } - - /*package*/ static IInteger newInteger(byte[] integerData) { - if (integerData.length <= 4) { - int value = 0; - for (int i = integerData.length - 1, j = 0; i >= 0; i--, j++) { - value |= ((integerData[i] & 0xff) << (j * 8)); - } - - return newInteger(value); - } - return new BigIntegerValue(new BigInteger(integerData)); - } - - private IntegerValue(int value){ - super(); - this.value = value; - } - - @Override - public IInteger toInteger() { - return this; - } - - @Override - public Type getType(){ - return INTEGER_TYPE; - } - - @Override - public int intValue(){ - return value; - } - - @Override - public long longValue(){ - return value; - } - - @Override - public double doubleValue(){ - return value; - } - - @Override - public IReal toReal(int precision){ - return BigDecimalValue.newReal(BigDecimal.valueOf(value)); - } - - @Override - public byte[] getTwosComplementRepresentation(){ - if((value & SEVEN_BITS_MASK) == value){ - byte[] data = new byte[1]; - data[0] = (byte) (value & 0x7f); - return data; - }else if((value & FIFTEEN_BITS_MASK) == value){ - byte[] data = new byte[2]; - data[0] = (byte) ((value >> 8) & 0x7f); - data[1] = (byte) (value & 0xff); - return data; - }else if((value & TWENTYTHREE_BITS_MASK) == value){ - byte[] data = new byte[3]; - data[0] = (byte) ((value >> 16) & 0x7f); - data[1] = (byte) ((value >> 8) & 0xff); - data[2] = (byte) (value & 0xff); - return data; - } - - byte[] data = new byte[4]; - data[0] = (byte) ((value >> 24) & 0xff); - data[1] = (byte) ((value >> 16) & 0xff); - data[2] = (byte) ((value >> 8) & 0xff); - data[3] = (byte) (value & 0xff); - return data; - } - - @Override - public BigInteger toBigInteger(){ - if (minSmallValue <= value && value <= maxSmallValue) { - return smallBigIntegerValues[value - minSmallValue]; - } - return new BigInteger(getTwosComplementRepresentation()); - } - - @Override - public IInteger add(IInteger other){ - if(value == 0) - return other; - - if(other instanceof BigIntegerValue){ - return other.add(this); - } - - int otherIntValue = other.intValue(); - - if(otherIntValue == 0) - return this; - - int result = value + otherIntValue; - if((value < 0) && (otherIntValue < 0) && (result >= 0)){// Overflow -> positive. - byte[] intValueData = new byte[5]; - intValueData[0] = (byte) 0xff; - intValueData[1] = (byte)((result >>> 24) & 0xff); - intValueData[2] = (byte)((result >>> 16) & 0xff); - intValueData[3] = (byte)((result >>> 8) & 0xff); - intValueData[4] = (byte)(result & 0xff); - - return IntegerValue.newInteger(new BigInteger(intValueData)); - }else if((value > 0) && (otherIntValue > 0) && (result < 0)){// Overflow -> negative. - byte[] intValueData = new byte[5]; - intValueData[0] = 0; - intValueData[1] = (byte)((result >>> 24) & 0xff); - intValueData[2] = (byte)((result >>> 16) & 0xff); - intValueData[3] = (byte)((result >>> 8) & 0xff); - intValueData[4] = (byte)(result & 0xff); - - return IntegerValue.newInteger(new BigInteger(intValueData)); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IRational add(IRational other) { - return (IRational ) other.add(this); - } - - @Override - public IReal add(IReal other) { - return (IReal) other.add(this); - } - - @Override - public INumber subtract(IReal other) { - return toReal(other.precision()).subtract(other); - } - - @Override - public IInteger subtract(IInteger other){ - if(value == 0) - return other.negate(); - - if(other instanceof BigIntegerValue){ - return other.negate().subtract(this.negate()); - } - - int otherIntValue = other.intValue(); - - if(otherIntValue == 0) - return this; - - int result = value - otherIntValue; - if((value < 0) && (otherIntValue > 0) && (result > 0)){// Overflow -> positive. - byte[] intValueData = new byte[5]; - intValueData[0] = (byte) 0xff; - intValueData[1] = (byte)((result >>> 24) & 0xff); - intValueData[2] = (byte)((result >>> 16) & 0xff); - intValueData[3] = (byte)((result >>> 8) & 0xff); - intValueData[4] = (byte)(result & 0xff); - - return IntegerValue.newInteger(new BigInteger(intValueData)); - }else if((value > 0) && (otherIntValue < 0) && (result < 0)){// Overflow -> negative. - byte[] intValueData = new byte[5]; - intValueData[0] = 0; - intValueData[1] = (byte)((result >>> 24) & 0xff); - intValueData[2] = (byte)((result >>> 16) & 0xff); - intValueData[3] = (byte)((result >>> 8) & 0xff); - intValueData[4] = (byte)(result & 0xff); - - return IntegerValue.newInteger(new BigInteger(intValueData)); - } - - return IntegerValue.newInteger(result); - } - - @Override - public IRational subtract(IRational other) { - return toRational().subtract(other); - } - - @Override - public IInteger multiply(IInteger other){ - if(value == 0) - return this; - if(value == 1) - return other; - - if(other instanceof BigIntegerValue){ - return other.multiply(this); - } - - int otherIntValue = other.intValue(); - if(otherIntValue == 0) return other; - if(otherIntValue == 1) return this; - - boolean resultIsPositive = ((((value ^ otherIntValue) ^ 0x80000000) & 0x80000000) == 0x80000000); - if(resultIsPositive){ - int div = Integer.MAX_VALUE / otherIntValue; - if((value > 0)){ - if(value <= div){ - return IntegerValue.newInteger(value * other.intValue()); - } - }else{ - if(value >= div){ - return IntegerValue.newInteger(value * other.intValue()); - } - } - }else{ - int div = Integer.MIN_VALUE / otherIntValue; - if((value > 0)){ - if(value <= div){ - return IntegerValue.newInteger(value * other.intValue()); - } - }else{ - if(value >= div){ - return IntegerValue.newInteger(value * other.intValue()); - } - } - } - - return IntegerValue.newInteger(toBigInteger().multiply(((ICanBecomeABigInteger) other).toBigInteger())); - } - - @Override - public IRational multiply(IRational other) { - return (IRational) other.multiply(this); - } - - @Override - public IReal multiply(IReal other) { - return (IReal) other.multiply(this); - } - - @Override - public IInteger divide(IInteger other) { - if (other.equals(INTEGER_ZERO)) { - throw new ArithmeticException("/ by zero"); - } - - if (value == 0) { - return this; - } - - if (other instanceof BigIntegerValue){ - return IntegerValue.newInteger(toBigInteger().divide(((ICanBecomeABigInteger) other).toBigInteger())); - } - - int otherIntValue = other.intValue(); - if (otherIntValue == 1) { - return this; - } - - return IntegerValue.newInteger(value / otherIntValue); - } - - - @Override - public IRational divide(IRational other) { - return toRational().divide(other); - } - - @Override - public INumber divide(IInteger other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public INumber divide(IRational other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public IReal divide(IReal other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public IInteger mod(IInteger other){ - if(other instanceof BigIntegerValue){ - if(value < 0){ - BigInteger m = ((BigIntegerValue)other).toBigInteger(); - // i.e. -1 % m = m + (-1) - BigInteger res = m.add(toBigInteger()); - return IntegerValue.newInteger(res); - } - return this; - } - int otherVal = other.intValue(); - int newValue = value % other.intValue(); - newValue = newValue >= 0 ? newValue : newValue + otherVal; - return IntegerValue.newInteger(newValue); - } - - @Override - public IInteger remainder(IInteger other){ - if(other instanceof BigIntegerValue){ - return this; - } - - return IntegerValue.newInteger(value % other.intValue()); - } - - @Override - public IInteger negate(){ - if(value == 0) - return this; - else - return IntegerValue.newInteger((~((long) value)) + 1); - } - - @Override - public IBool equal(IInteger other){ - return BoolValue.getBoolValue(compare(other) == 0); - } - - @Override - public IBool equal(IRational other) { - return other.equal(this); - } - - @Override - public IBool equal(IReal other) { - return other.equal(this); - } - - @Override - public IBool greater(IInteger other){ - return BoolValue.getBoolValue(compare(other) > 0); - } - - @Override - public IBool greater(IRational other) { - return other.less(this); - } - - @Override - public IBool greater(IReal other) { - return other.less(this); - } - - @Override - public IBool greaterEqual(IInteger other){ - return BoolValue.getBoolValue(compare(other) >= 0); - } - - @Override - public IBool greaterEqual(IRational other) { - return other.lessEqual(this); - } - - @Override - public IBool greaterEqual(IReal other) { - return BoolValue.getBoolValue(compare(other) >= 0); - } - - @Override - public IBool less(IInteger other){ - return BoolValue.getBoolValue(compare(other) < 0); - } - - @Override - public IBool less(IRational other) { - return other.greater(this); - } - - @Override - public IBool less(IReal other) { - return other.greater(this); - } - - @Override - public IBool lessEqual(IInteger other){ - return BoolValue.getBoolValue(compare(other) <= 0); - } - - @Override - public IBool lessEqual(IRational other) { - return other.greaterEqual(this); - } - - @Override - public IBool lessEqual(IReal other) { - return other.greaterEqual(this); - } - - @Override - public int compare(IInteger other){ - if(other instanceof BigIntegerValue){ - return ((~other.compare(this)) + 1); - } - - if(value > other.intValue()) return 1; - if(value < other.intValue()) return -1; - - return 0; - } - - @Override - public int compare(INumber other) { - if (isIntegerType(other)) { - return compare(other.toInteger()); - } - else if (isRationalType(other)) { - return toRational().compare(other); - } - else { - assert other instanceof IReal; - return toReal(((IReal) other).precision()).compare(other); - } - } - - @Override - public int hashCode(){ - int h = value ^ 0x85ebca6b; - // based on the final Avalanching phase of MurmurHash2 - // providing a nice mix of bits even for small numbers. - h ^= h >>> 13; - h *= 0x5bd1e995; - h ^= h >>> 15; - - return h; - } - - public boolean equals(@Nullable Object o){ - if(o == null) { - return false; - } - else if(o == this) { - return true; - } - - if (o.getClass() == getClass()) { - IntegerValue otherInteger = (IntegerValue) o; - return (value == otherInteger.value); - } - - return false; - } - - @Override - public String getStringRepresentation(){ - return Integer.toString(value); - } - - @Override - public int signum() { - return value < 0 ? -1 : (value == 0 ? 0 : 1); - } - - @Override - public IInteger abs() { - return newInteger(Math.abs(value)); - } - - @Override - public IRational toRational() { - return RationalValue.newRational(this, INTEGER_ONE); - } + } + + /*package*/ static IInteger newInteger(String integerValue) { + if (integerValue.startsWith("-")) { + if (integerValue.length() < 11 || (integerValue.length() == 11 && integerValue.compareTo(NEGATIVE_INTEGER_MAX_STRING) <= 0)) { + return newInteger(Integer.parseInt(integerValue)); + } + return new BigIntegerValue(new BigInteger(integerValue)); + } + + if (integerValue.length() < 10 || (integerValue.length() == 10 && integerValue.compareTo(INTEGER_MAX_STRING) <= 0)) { + return newInteger(Integer.parseInt(integerValue)); + } + return new BigIntegerValue(new BigInteger(integerValue)); + } + + /*package*/ static IInteger newInteger(long value) { + if (((value & 0x000000007fffffffL) == value) || ((value & 0xffffffff80000000L) == 0xffffffff80000000L)) { + return newInteger((int) value); + } else { + byte[] valueData = new byte[8]; + valueData[0] = (byte) ((value >>> 56) & 0xff); + valueData[1] = (byte) ((value >>> 48) & 0xff); + valueData[2] = (byte) ((value >>> 40) & 0xff); + valueData[3] = (byte) ((value >>> 32) & 0xff); + valueData[4] = (byte) ((value >>> 24) & 0xff); + valueData[5] = (byte) ((value >>> 16) & 0xff); + valueData[6] = (byte) ((value >>> 8) & 0xff); + valueData[7] = (byte) (value & 0xff); + return newInteger(valueData); + } + } + + /*package*/ static IInteger newInteger(byte[] integerData) { + if (integerData.length <= 4) { + int value = 0; + for (int i = integerData.length - 1, j = 0; i >= 0; i--, j++) { + value |= ((integerData[i] & 0xff) << (j * 8)); + } + + return newInteger(value); + } + return new BigIntegerValue(new BigInteger(integerData)); + } + + private IntegerValue(int value){ + super(); + this.value = value; + } + + @Override + public IInteger toInteger() { + return this; + } + + @Override + public Type getType(){ + return INTEGER_TYPE; + } + + @Override + public int intValue(){ + return value; + } + + @Override + public long longValue(){ + return value; + } + + @Override + public double doubleValue(){ + return value; + } + + @Override + public IReal toReal(int precision){ + return BigDecimalValue.newReal(BigDecimal.valueOf(value)); + } + + @Override + public byte[] getTwosComplementRepresentation(){ + if((value & SEVEN_BITS_MASK) == value){ + byte[] data = new byte[1]; + data[0] = (byte) (value & 0x7f); + return data; + }else if((value & FIFTEEN_BITS_MASK) == value){ + byte[] data = new byte[2]; + data[0] = (byte) ((value >> 8) & 0x7f); + data[1] = (byte) (value & 0xff); + return data; + }else if((value & TWENTYTHREE_BITS_MASK) == value){ + byte[] data = new byte[3]; + data[0] = (byte) ((value >> 16) & 0x7f); + data[1] = (byte) ((value >> 8) & 0xff); + data[2] = (byte) (value & 0xff); + return data; + } + + byte[] data = new byte[4]; + data[0] = (byte) ((value >> 24) & 0xff); + data[1] = (byte) ((value >> 16) & 0xff); + data[2] = (byte) ((value >> 8) & 0xff); + data[3] = (byte) (value & 0xff); + return data; + } + + @Override + public BigInteger toBigInteger(){ + if (minSmallValue <= value && value <= maxSmallValue) { + return smallBigIntegerValues[value - minSmallValue]; + } + return new BigInteger(getTwosComplementRepresentation()); + } + + @Override + public IInteger add(IInteger other){ + if(value == 0) + return other; + + if(other instanceof BigIntegerValue){ + return other.add(this); + } + + int otherIntValue = other.intValue(); + + if(otherIntValue == 0) + return this; + + int result = value + otherIntValue; + if((value < 0) && (otherIntValue < 0) && (result >= 0)){// Overflow -> positive. + byte[] intValueData = new byte[5]; + intValueData[0] = (byte) 0xff; + intValueData[1] = (byte)((result >>> 24) & 0xff); + intValueData[2] = (byte)((result >>> 16) & 0xff); + intValueData[3] = (byte)((result >>> 8) & 0xff); + intValueData[4] = (byte)(result & 0xff); + + return IntegerValue.newInteger(new BigInteger(intValueData)); + }else if((value > 0) && (otherIntValue > 0) && (result < 0)){// Overflow -> negative. + byte[] intValueData = new byte[5]; + intValueData[0] = 0; + intValueData[1] = (byte)((result >>> 24) & 0xff); + intValueData[2] = (byte)((result >>> 16) & 0xff); + intValueData[3] = (byte)((result >>> 8) & 0xff); + intValueData[4] = (byte)(result & 0xff); + + return IntegerValue.newInteger(new BigInteger(intValueData)); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IRational add(IRational other) { + return (IRational ) other.add(this); + } + + @Override + public IReal add(IReal other) { + return (IReal) other.add(this); + } + + @Override + public INumber subtract(IReal other) { + return toReal(other.precision()).subtract(other); + } + + @Override + public IInteger subtract(IInteger other){ + if(value == 0) + return other.negate(); + + if(other instanceof BigIntegerValue){ + return other.negate().subtract(this.negate()); + } + + int otherIntValue = other.intValue(); + + if(otherIntValue == 0) + return this; + + int result = value - otherIntValue; + if((value < 0) && (otherIntValue > 0) && (result > 0)){// Overflow -> positive. + byte[] intValueData = new byte[5]; + intValueData[0] = (byte) 0xff; + intValueData[1] = (byte)((result >>> 24) & 0xff); + intValueData[2] = (byte)((result >>> 16) & 0xff); + intValueData[3] = (byte)((result >>> 8) & 0xff); + intValueData[4] = (byte)(result & 0xff); + + return IntegerValue.newInteger(new BigInteger(intValueData)); + }else if((value > 0) && (otherIntValue < 0) && (result < 0)){// Overflow -> negative. + byte[] intValueData = new byte[5]; + intValueData[0] = 0; + intValueData[1] = (byte)((result >>> 24) & 0xff); + intValueData[2] = (byte)((result >>> 16) & 0xff); + intValueData[3] = (byte)((result >>> 8) & 0xff); + intValueData[4] = (byte)(result & 0xff); + + return IntegerValue.newInteger(new BigInteger(intValueData)); + } + + return IntegerValue.newInteger(result); + } + + @Override + public IRational subtract(IRational other) { + return toRational().subtract(other); + } + + @Override + public IInteger multiply(IInteger other){ + if(value == 0) + return this; + if(value == 1) + return other; + + if(other instanceof BigIntegerValue){ + return other.multiply(this); + } + + int otherIntValue = other.intValue(); + if(otherIntValue == 0) return other; + if(otherIntValue == 1) return this; + + boolean resultIsPositive = ((((value ^ otherIntValue) ^ 0x80000000) & 0x80000000) == 0x80000000); + if(resultIsPositive){ + int div = Integer.MAX_VALUE / otherIntValue; + if((value > 0)){ + if(value <= div){ + return IntegerValue.newInteger(value * other.intValue()); + } + }else{ + if(value >= div){ + return IntegerValue.newInteger(value * other.intValue()); + } + } + }else{ + int div = Integer.MIN_VALUE / otherIntValue; + if((value > 0)){ + if(value <= div){ + return IntegerValue.newInteger(value * other.intValue()); + } + }else{ + if(value >= div){ + return IntegerValue.newInteger(value * other.intValue()); + } + } + } + + return IntegerValue.newInteger(toBigInteger().multiply(((ICanBecomeABigInteger) other).toBigInteger())); + } + + @Override + public IRational multiply(IRational other) { + return (IRational) other.multiply(this); + } + + @Override + public IReal multiply(IReal other) { + return (IReal) other.multiply(this); + } + + @Override + public IInteger divide(IInteger other) { + if (other.equals(INTEGER_ZERO)) { + throw new ArithmeticException("/ by zero"); + } + + if (value == 0) { + return this; + } + + if (other instanceof BigIntegerValue){ + return IntegerValue.newInteger(toBigInteger().divide(((ICanBecomeABigInteger) other).toBigInteger())); + } + + int otherIntValue = other.intValue(); + if (otherIntValue == 1) { + return this; + } + + return IntegerValue.newInteger(value / otherIntValue); + } + + + @Override + public IRational divide(IRational other) { + return toRational().divide(other); + } + + @Override + public INumber divide(IInteger other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public INumber divide(IRational other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public IReal divide(IReal other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public IInteger mod(IInteger other){ + if(other instanceof BigIntegerValue){ + if(value < 0){ + BigInteger m = ((BigIntegerValue)other).toBigInteger(); + // i.e. -1 % m = m + (-1) + BigInteger res = m.add(toBigInteger()); + return IntegerValue.newInteger(res); + } + return this; + } + int otherVal = other.intValue(); + int newValue = value % other.intValue(); + newValue = newValue >= 0 ? newValue : newValue + otherVal; + return IntegerValue.newInteger(newValue); + } + + @Override + public IInteger remainder(IInteger other){ + if(other instanceof BigIntegerValue){ + return this; + } + + return IntegerValue.newInteger(value % other.intValue()); + } + + @Override + public IInteger negate(){ + if(value == 0) + return this; + else + return IntegerValue.newInteger((~((long) value)) + 1); + } + + @Override + public IBool equal(IInteger other) { + return BoolValue.getBoolValue(compare(other) == 0); + } + + @Override + public IBool equal(IRational other) { + return other.equal(this); + } + + @Override + public IBool equal(IReal other) { + return other.equal(this); + } + + @Override + public IBool greater(IInteger other){ + return BoolValue.getBoolValue(compare(other) > 0); + } + + @Override + public IBool greater(IRational other) { + return other.less(this); + } + + @Override + public IBool greater(IReal other) { + return other.less(this); + } + + @Override + public IBool greaterEqual(IInteger other){ + return BoolValue.getBoolValue(compare(other) >= 0); + } + + @Override + public IBool greaterEqual(IRational other) { + return other.lessEqual(this); + } + + @Override + public IBool greaterEqual(IReal other) { + return BoolValue.getBoolValue(compare(other) >= 0); + } + + @Override + public IBool less(IInteger other){ + return BoolValue.getBoolValue(compare(other) < 0); + } + + @Override + public IBool less(IRational other) { + return other.greater(this); + } + + @Override + public IBool less(IReal other) { + return other.greater(this); + } + + @Override + public IBool lessEqual(IInteger other){ + return BoolValue.getBoolValue(compare(other) <= 0); + } + + @Override + public IBool lessEqual(IRational other) { + return other.greaterEqual(this); + } + + @Override + public IBool lessEqual(IReal other) { + return other.greaterEqual(this); + } + + @Override + public int compare(IInteger other){ + if(other instanceof BigIntegerValue){ + return ((~other.compare(this)) + 1); + } + + if(value > other.intValue()) return 1; + if(value < other.intValue()) return -1; + + return 0; + } + + @Override + public int compare(INumber other) { + if (isIntegerType(other)) { + return compare(other.toInteger()); + } + else if (isRationalType(other)) { + return toRational().compare(other); + } + else { + assert other instanceof IReal; + return toReal(((IReal) other).precision()).compare(other); + } + } + + @Override + public int hashCode(){ + int h = value ^ 0x85ebca6b; + // based on the final Avalanching phase of MurmurHash2 + // providing a nice mix of bits even for small numbers. + h ^= h >>> 13; + h *= 0x5bd1e995; + h ^= h >>> 15; + + return h; + } + + public boolean equals(@Nullable Object o){ + if(o == null) { + return false; + } + else if(o == this) { + return true; + } + + if (o.getClass() == getClass()) { + IntegerValue otherInteger = (IntegerValue) o; + return (value == otherInteger.value); + } + + return false; + } + + @Override + public String getStringRepresentation(){ + return Integer.toString(value); + } + + @Override + public int signum() { + return value < 0 ? -1 : (value == 0 ? 0 : 1); + } + + @Override + public IInteger abs() { + return newInteger(Math.abs(value)); + } + + @Override + public IRational toRational() { + return RationalValue.newRational(this, INTEGER_ONE); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/RationalValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/RationalValue.java index ba5390d45..f321276e7 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/RationalValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/RationalValue.java @@ -23,357 +23,357 @@ import io.usethesource.vallang.type.TypeFactory; /*package*/ class RationalValue extends AbstractNumberValue implements IRational { - public static final Type RATIONAL_TYPE = TypeFactory.getInstance().rationalType(); - - protected final IInteger num; - protected final IInteger denom; - - /*package*/ static IRational newRational(IInteger a, IInteger b) { - return new RationalValue(a, b); - } - - private RationalValue(IInteger num, IInteger denom) { - if(denom.signum() < 0) { - num = num.negate(); - denom = denom.negate(); - } - // normalize infinites - if(denom.signum() == 0) { - if(num.signum() > 0) - num = intOne(); - else if(num.signum() < 0) - num = intOne().negate(); - else - throw new ArithmeticException("Illegal fraction 0/0"); - - } - else if(num.signum() == 0) { - denom = intOne(); - } - else { - IInteger gcd = gcd(num, denom); - while(gcd.compare(intOne()) != 0) { - num = num.divide(gcd); - denom = denom.divide(gcd); - gcd = gcd(num, denom); - } - } - this.num = num; - this.denom = denom; - } - - @Override - public IRational add(IRational other) { - // (num*other.denom + denom*other.num) / denom*other.denom - return toRational( - num.multiply(other.denominator()).add(denom.multiply(other.numerator())), - denom.multiply(other.denominator())); - } - - @Override - public IReal add(IReal other) { - return toReal(other.precision()).add(other); - } - - @Override - public INumber add(IInteger other) { - return toRational(num.add(other.multiply(denom)), denom); - } - - @Override - public IRational subtract(IRational other) { - // (num*other.denom - denom*other.num) / denom*other.denom - return toRational( - num.multiply(other.denominator()).subtract(denom.multiply(other.numerator())), - denom.multiply(other.denominator())); - } - - @Override - public INumber subtract(IReal other) { - return toReal(other.precision()).subtract(other); - } - - @Override - public INumber subtract(IInteger other) { - return toRational(num.subtract(other.multiply(denom)), denom); - } - - @Override - public IRational multiply(IRational other) { - return toRational(num.multiply(other.numerator()), - denom.multiply(other.denominator())); - } - - @Override - public IReal multiply(IReal other) { - return toReal(other.precision()).multiply(other); - } - - @Override - public INumber multiply(IInteger other) { - return toRational(num.multiply(other), denom); - } - - // TODO: should we perhaps drop this and only have the other divide? - // or vice-versa? - @Override - public IRational divide(IRational other) { - return toRational(num.multiply(other.denominator()), - denom.multiply(other.numerator())); - } - - @Override - public IReal divide(IReal other, int precision) { - return toReal(precision).divide(other, precision); - } - - @Override - public IRational divide(IInteger other, int precision) { - return divide(other); // forget precision - } - - @Override - public IRational divide(IInteger other) { - if (other.equals(IntegerValue.INTEGER_ZERO)) { - throw new ArithmeticException("/ by zero"); - } - - return toRational(num, denom.multiply(other)); - } - - - @Override - public INumber divide(IRational other, int precision) { - return toRational(num.multiply(other.denominator()), - denom.multiply(other.numerator())); - } - - @Override - public IBool less(IRational other) { - return BoolValue.getBoolValue(compare(other) < 0); - } - - @Override - public IBool less(IReal other) { - return other.greater(this); - } - - @Override - public IBool less(IInteger other) { - return less(other.toRational()); - } - - @Override - public IBool greater(IRational other) { - return BoolValue.getBoolValue(compare(other) > 0); - } - - @Override - public IBool greater(IReal other) { - return other.less(this); - } - - @Override - public IBool greater(IInteger other) { - return greater(other.toRational()); - } - - @Override - public IBool equal(IRational other) { - return BoolValue.getBoolValue(compare(other) == 0); - } - - @Override - public IBool equal(IReal other) { - return other.equal(this); - } - - @Override - public IBool equal(IInteger other) { - return equal(other.toRational()); - } - - @Override - public IBool lessEqual(IRational other) { - return BoolValue.getBoolValue(compare(other) <= 0); - } - - @Override - public IBool lessEqual(IReal other) { - return other.greaterEqual(this); - } - - @Override - public IBool lessEqual(IInteger other) { - return lessEqual(other.toRational()); - } - - @Override - public IBool greaterEqual(IRational other) { - return BoolValue.getBoolValue(compare(other) >= 0); - } - - @Override - public IBool greaterEqual(IReal other) { - return other.lessEqual(this); - } - - @Override - public IBool greaterEqual(IInteger other) { - return greaterEqual(other.toRational()); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == null) { - return false; - } - - if (o == this) { - return true; - } - - if(o.getClass() == getClass()){ - RationalValue other = (RationalValue) o; - return num.equals(other.num) && denom.equals(other.denom); - } - - return false; - } - - @Override - public int compare(INumber other) { - if(isIntegerType(other)) { - IInteger div = num.divide(denom); - IInteger rem = num.remainder(denom); - if(div.compare(other) != 0) - return div.compare(other); - else - return rem.signum(); - } - else if(isRationalType(other)){ - IRational diff = subtract((IRational)other); - return diff.signum(); - } - else { - assert other instanceof IReal; - return toReal(((IReal) other).precision()).compare(other); - } - } - - @Override - public Type getType() { - return RATIONAL_TYPE; - } - - @Override - public IRational negate() { - return toRational(num.negate(), denom); - } - - @Override - public IReal toReal(int precision) { - IReal r1 = num.toReal(precision); - IReal r2 = denom.toReal(precision); - r1 = r1.divide(r2, precision); - return r1; - } - - @Override - public IInteger toInteger() { - return num.divide(denom); - } - - @Override - public String getStringRepresentation() { - return num.getStringRepresentation() + "r" + (denom.equals(intOne()) ? "" : denom.getStringRepresentation()); - } - - @Override - public int compare(IRational other) { - IRational diff = subtract(other); - return diff.signum(); - } - - @Override - public int signum() { - return num.signum(); - } - - @Override - public IRational abs() { - return toRational(num.abs(), denom); - } - - @Override - public IInteger floor() { - return num.divide(denom); - } - - @Override - public IInteger round() { - return toReal(2).round().toInteger(); - } - - @Override - public IRational toRational() { - return this; - } - - public IRational toRational(IInteger n, IInteger d) { - return newRational(n, d); - } - - @Override - public IRational remainder(IRational other) { - throw new UnsupportedOperationException(); - } - - @Override - public int hashCode() { - if(denom.equals(intOne())) - return num.hashCode(); - else { - final int prime = 31; - int result = 1; - result = prime * result + num.hashCode(); - result = prime * result + denom.hashCode(); - return result; - } - } - - @Override - public IInteger numerator() { - return num; - } - - @Override - public IInteger denominator() { - return denom; - } - - @Override - public IInteger remainder() { - return num.remainder(denom); - } - - protected static IInteger gcd(IInteger n, IInteger d) { - n = n.abs(); - d = d.abs(); - while(d.signum() > 0) { - IInteger tmp = d; - d = n.mod(d); - n = tmp; - } - return n; - } - - protected static IInteger intOne() { - return IntegerValue.INTEGER_ONE; - } - - @Override - public double doubleValue() { - return num.doubleValue() / denom.doubleValue(); - } + public static final Type RATIONAL_TYPE = TypeFactory.getInstance().rationalType(); + + protected final IInteger num; + protected final IInteger denom; + + /*package*/ static IRational newRational(IInteger a, IInteger b) { + return new RationalValue(a, b); + } + + private RationalValue(IInteger num, IInteger denom) { + if(denom.signum() < 0) { + num = num.negate(); + denom = denom.negate(); + } + // normalize infinites + if(denom.signum() == 0) { + if(num.signum() > 0) + num = intOne(); + else if(num.signum() < 0) + num = intOne().negate(); + else + throw new ArithmeticException("Illegal fraction 0/0"); + + } + else if(num.signum() == 0) { + denom = intOne(); + } + else { + IInteger gcd = gcd(num, denom); + while(gcd.compare(intOne()) != 0) { + num = num.divide(gcd); + denom = denom.divide(gcd); + gcd = gcd(num, denom); + } + } + this.num = num; + this.denom = denom; + } + + @Override + public IRational add(IRational other) { + // (num*other.denom + denom*other.num) / denom*other.denom + return toRational( + num.multiply(other.denominator()).add(denom.multiply(other.numerator())), + denom.multiply(other.denominator())); + } + + @Override + public IReal add(IReal other) { + return toReal(other.precision()).add(other); + } + + @Override + public INumber add(IInteger other) { + return toRational(num.add(other.multiply(denom)), denom); + } + + @Override + public IRational subtract(IRational other) { + // (num*other.denom - denom*other.num) / denom*other.denom + return toRational( + num.multiply(other.denominator()).subtract(denom.multiply(other.numerator())), + denom.multiply(other.denominator())); + } + + @Override + public INumber subtract(IReal other) { + return toReal(other.precision()).subtract(other); + } + + @Override + public INumber subtract(IInteger other) { + return toRational(num.subtract(other.multiply(denom)), denom); + } + + @Override + public IRational multiply(IRational other) { + return toRational(num.multiply(other.numerator()), + denom.multiply(other.denominator())); + } + + @Override + public IReal multiply(IReal other) { + return toReal(other.precision()).multiply(other); + } + + @Override + public INumber multiply(IInteger other) { + return toRational(num.multiply(other), denom); + } + + // TODO: should we perhaps drop this and only have the other divide? + // or vice-versa? + @Override + public IRational divide(IRational other) { + return toRational(num.multiply(other.denominator()), + denom.multiply(other.numerator())); + } + + @Override + public IReal divide(IReal other, int precision) { + return toReal(precision).divide(other, precision); + } + + @Override + public IRational divide(IInteger other, int precision) { + return divide(other); // forget precision + } + + @Override + public IRational divide(IInteger other) { + if (other.equals(IntegerValue.INTEGER_ZERO)) { + throw new ArithmeticException("/ by zero"); + } + + return toRational(num, denom.multiply(other)); + } + + + @Override + public INumber divide(IRational other, int precision) { + return toRational(num.multiply(other.denominator()), + denom.multiply(other.numerator())); + } + + @Override + public IBool less(IRational other) { + return BoolValue.getBoolValue(compare(other) < 0); + } + + @Override + public IBool less(IReal other) { + return other.greater(this); + } + + @Override + public IBool less(IInteger other) { + return less(other.toRational()); + } + + @Override + public IBool greater(IRational other) { + return BoolValue.getBoolValue(compare(other) > 0); + } + + @Override + public IBool greater(IReal other) { + return other.less(this); + } + + @Override + public IBool greater(IInteger other) { + return greater(other.toRational()); + } + + @Override + public IBool equal(IRational other) { + return BoolValue.getBoolValue(compare(other) == 0); + } + + @Override + public IBool equal(IReal other) { + return other.equal(this); + } + + @Override + public IBool equal(IInteger other) { + return equal(other.toRational()); + } + + @Override + public IBool lessEqual(IRational other) { + return BoolValue.getBoolValue(compare(other) <= 0); + } + + @Override + public IBool lessEqual(IReal other) { + return other.greaterEqual(this); + } + + @Override + public IBool lessEqual(IInteger other) { + return lessEqual(other.toRational()); + } + + @Override + public IBool greaterEqual(IRational other) { + return BoolValue.getBoolValue(compare(other) >= 0); + } + + @Override + public IBool greaterEqual(IReal other) { + return other.lessEqual(this); + } + + @Override + public IBool greaterEqual(IInteger other) { + return greaterEqual(other.toRational()); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null) { + return false; + } + + if (o == this) { + return true; + } + + if(o.getClass() == getClass()){ + RationalValue other = (RationalValue) o; + return num.equals(other.num) && denom.equals(other.denom); + } + + return false; + } + + @Override + public int compare(INumber other) { + if(isIntegerType(other)) { + IInteger div = num.divide(denom); + IInteger rem = num.remainder(denom); + if(div.compare(other) != 0) + return div.compare(other); + else + return rem.signum(); + } + else if(isRationalType(other)){ + IRational diff = subtract((IRational)other); + return diff.signum(); + } + else { + assert other instanceof IReal; + return toReal(((IReal) other).precision()).compare(other); + } + } + + @Override + public Type getType() { + return RATIONAL_TYPE; + } + + @Override + public IRational negate() { + return toRational(num.negate(), denom); + } + + @Override + public IReal toReal(int precision) { + IReal r1 = num.toReal(precision); + IReal r2 = denom.toReal(precision); + r1 = r1.divide(r2, precision); + return r1; + } + + @Override + public IInteger toInteger() { + return num.divide(denom); + } + + @Override + public String getStringRepresentation() { + return num.getStringRepresentation() + "r" + (denom.equals(intOne()) ? "" : denom.getStringRepresentation()); + } + + @Override + public int compare(IRational other) { + IRational diff = subtract(other); + return diff.signum(); + } + + @Override + public int signum() { + return num.signum(); + } + + @Override + public IRational abs() { + return toRational(num.abs(), denom); + } + + @Override + public IInteger floor() { + return num.divide(denom); + } + + @Override + public IInteger round() { + return toReal(2).round().toInteger(); + } + + @Override + public IRational toRational() { + return this; + } + + public IRational toRational(IInteger n, IInteger d) { + return newRational(n, d); + } + + @Override + public IRational remainder(IRational other) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + if(denom.equals(intOne())) + return num.hashCode(); + else { + final int prime = 31; + int result = 1; + result = prime * result + num.hashCode(); + result = prime * result + denom.hashCode(); + return result; + } + } + + @Override + public IInteger numerator() { + return num; + } + + @Override + public IInteger denominator() { + return denom; + } + + @Override + public IInteger remainder() { + return num.remainder(denom); + } + + protected static IInteger gcd(IInteger n, IInteger d) { + n = n.abs(); + d = d.abs(); + while(d.signum() > 0) { + IInteger tmp = d; + d = n.mod(d); + n = tmp; + } + return n; + } + + protected static IInteger intOne() { + return IntegerValue.INTEGER_ONE; + } + + @Override + public double doubleValue() { + return num.doubleValue() / denom.doubleValue(); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationURIValues.java b/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationURIValues.java index 2e2fa0e86..61246513f 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationURIValues.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationURIValues.java @@ -16,7 +16,7 @@ */ /*package*/ class SourceLocationURIValues { private static final Pattern doubleSlashes = Pattern.compile("//+"); - + static ISourceLocation newURI(@Nullable String scheme, @Nullable String authority, @Nullable String path, @Nullable String query, @Nullable String fragment) throws URISyntaxException { scheme = nullifyIfEmpty(scheme); authority = nullifyIfEmpty(authority); @@ -91,30 +91,30 @@ else if (!path.startsWith("/")) { return new SourceLocationURIValues.FragmentQueryPathAuthorityURI(scheme, authority, path, query, fragment); } - // since this is called a lot, instead of a regex we just use a simple char loop - // RFC3986: - // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - private static boolean validScheme(@Nullable String s) { - if (s == null || s.isEmpty()) { - return false; - } - char current = s.charAt(0); - if (('A' <= current && current <= 'Z') || ('a' <= current && current <= 'z')) { - for (int i = 1; i < s.length(); i++) { - current = s.charAt(i); - if (current < '+' || current > 'z' // anything outside this, is not valid - || current == ',' || current == '/' // these two chars between + and 0 that aren't valid - || ('9' < current && current < 'A') // chars between 9 and A are invalid - || ('Z' < current && current < 'a') // chars between Z and a are invalid - ) { - return false; - } - } - return true; - - } - return false; - } + // since this is called a lot, instead of a regex we just use a simple char loop + // RFC3986: + // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + private static boolean validScheme(@Nullable String s) { + if (s == null || s.isEmpty()) { + return false; + } + char current = s.charAt(0); + if (('A' <= current && current <= 'Z') || ('a' <= current && current <= 'z')) { + for (int i = 1; i < s.length(); i++) { + current = s.charAt(i); + if (current < '+' || current > 'z' // anything outside this, is not valid + || current == ',' || current == '/' // these two chars between + and 0 that aren't valid + || ('9' < current && current < 'A') // chars between 9 and A are invalid + || ('Z' < current && current < 'a') // chars between Z and a are invalid + ) { + return false; + } + } + return true; + + } + return false; + } private static @Nullable String nullifyIfEmpty(@Nullable String str) { @@ -127,963 +127,963 @@ private static boolean validScheme(@Nullable String s) { private static final Interner INTERNED_SCHEMES = Interner.newStrongInterner(); private static class BaseURI implements ISourceLocation { - protected final String scheme; - - public BaseURI(String scheme) { - this.scheme = INTERNED_SCHEMES.intern(scheme); - } - - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - try { - return new URI(scheme,"","/",null,null); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - return scheme == ((BaseURI)obj).scheme; - } - - return false; - } - - @Override - public int hashCode() { - return scheme.hashCode(); - } - - @Override - public String getScheme() { - return scheme; - } - - @Override - public String getAuthority() { - return ""; - } - - @Override - public String getPath() { - return "/"; - } - - @Override - public String getFragment() { - return ""; - } - - @Override - public String getQuery() { - return ""; - } - - @Override - public boolean hasAuthority() { - return false; - } - - @Override - public boolean hasPath() { - return true; - } - - @Override - public boolean hasFragment() { - return false; - } - - @Override - public boolean hasQuery() { - return false; - } - - @Override - public Type getType() { - return TypeFactory.getInstance().sourceLocationType(); - } - - @Override - public boolean mayHaveKeywordParameters() { - return false; - } - - @Override - public int getBeginColumn() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public int getBeginLine() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public int getEndColumn() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public int getEndLine() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public int getLength() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public int getOffset() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - - @Override - public boolean hasLineColumn() { - return false; - } - - - @Override - public boolean hasOffsetLength() { - return false; - } - - - @Override - public ISourceLocation top() { - return this; - } - } - - private static final Pattern squareBrackets = Pattern.compile("(\\[|\\])"); - - @SuppressWarnings("nullness") // jdk of CF doesn't have the URI class in there - private static URI buildURIWithAuthority(String scheme, String authority, - String path, String query, String fragment) { - try { - URI result = new URI(scheme, authority, path, query, fragment); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - if (authority != null && squareBrackets.matcher(authority).find()) { - // Java URI do not correctly quote the brackets inside the authority - // even though RFC2732 specifies this. - // it has to do with the fact that the encoding/quotation is a single pass - // and that authority is actually ambigious, so it requires backtracking to - // decide which alternative of the authority part is used, and the quoting rules are - // slightly different. - // so if it fails to parse, we put some placeholder chars, which get encoded, - // we then replace the encoded values with the correct encoded values - // and create a new URI out of this. (to avoid double encoding) - authority = hideBrackets(authority); - URI temp = buildURIWithAuthority(scheme, authority, path, query, fragment); - return unhideBrackets(temp); - } - throw new RuntimeException("Internal state corrupted?", e); - } - - } - - private static final Pattern squareBracketOpenPlaceholder = Pattern.compile("%00%00%EF%BF%B0%00%00"); - private static final Pattern squareBracketClosePlaceholder = Pattern.compile("%00%00%EF%BF%B1%00%00"); - private static URI unhideBrackets(URI temp) { - String newURI = temp.toASCIIString(); - newURI = squareBracketOpenPlaceholder.matcher(newURI).replaceAll("%5B"); - newURI = squareBracketClosePlaceholder.matcher(newURI).replaceAll("%5D"); - try { - return new URI(newURI); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - private static final Pattern squareBracketOpen = Pattern.compile("\\["); - private static final Pattern squareBracketClose = Pattern.compile("\\]"); - private static String hideBrackets(String authority) { - authority = squareBracketOpen.matcher(authority).replaceAll("\0\0\uFFF0\0\0"); - return squareBracketClose.matcher(authority).replaceAll("\0\0\uFFF1\0\0"); - } - - private static final Interner INTERNED_AUTHORIES = Interner.newStrongInterner(); - private static class AuthorityURI extends BaseURI { - protected final String authority; - - public AuthorityURI(String scheme, String authority) { - super(scheme); - - this.authority = INTERNED_AUTHORIES.intern(authority); - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, null, null, null); - } - - @Override - public boolean hasPath() { - return false; - } - - @Override - public boolean hasAuthority() { - return true; - } - @Override - public String getAuthority() { - return authority; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - AuthorityURI u = (AuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority; - } - - return false; - } - } - - private static class PathURI extends BaseURI { - protected final String path; - private int hash = 0; // we can cache the hash code since the 8-byte alignment leaves room for one - - public PathURI(String scheme, String path) { - super(scheme); - this.path = path; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - try { - URI result = new URI(scheme, "", path, null, null); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasPath() { - return true; - } - - @Override - public String getPath() { - return path; - } - - @Override - public int hashCode() { - if (hash == 0) { - hash = scheme.hashCode() + path.hashCode(); - } - - return hash; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - PathURI u = (PathURI)obj; - if (hash != 0 && u.hash != 0 && hash != u.hash) { - return false; - } - - return scheme == u.scheme - && path.equals(u.path); - } - return false; - } - } - - private static class PathAuthorityURI extends AuthorityURI { - protected final String path; - - public PathAuthorityURI(String scheme, String authority, String path) { - super(scheme, authority); - this.path = path; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, path, null, null); - } - - @Override - public boolean hasPath() { - return true; - } - @Override - public String getPath() { - return path; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + path.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - PathAuthorityURI u = (PathAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && path.equals(u.path); - } - - return false; - } - } - - private static class QueryURI extends BaseURI { - protected final String query; - - public QueryURI(String scheme, String query) { - super(scheme); - this.query = query; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + protected final String scheme; + + public BaseURI(String scheme) { + this.scheme = INTERNED_SCHEMES.intern(scheme); + } + + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + try { + return new URI(scheme,"","/",null,null); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { + return false; + } + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + return scheme == ((BaseURI)obj).scheme; + } + + return false; + } + + @Override + public int hashCode() { + return scheme.hashCode(); + } + + @Override + public String getScheme() { + return scheme; + } + + @Override + public String getAuthority() { + return ""; + } + + @Override + public String getPath() { + return "/"; + } + + @Override + public String getFragment() { + return ""; + } + + @Override + public String getQuery() { + return ""; + } + + @Override + public boolean hasAuthority() { + return false; + } + + @Override + public boolean hasPath() { + return true; + } + + @Override + public boolean hasFragment() { + return false; + } + + @Override + public boolean hasQuery() { + return false; + } + + @Override + public Type getType() { + return TypeFactory.getInstance().sourceLocationType(); + } + + @Override + public boolean mayHaveKeywordParameters() { + return false; + } + + @Override + public int getBeginColumn() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public int getBeginLine() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public int getEndColumn() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public int getEndLine() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public int getLength() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public int getOffset() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + + @Override + public boolean hasLineColumn() { + return false; + } + + + @Override + public boolean hasOffsetLength() { + return false; + } + + + @Override + public ISourceLocation top() { + return this; + } + } + + private static final Pattern squareBrackets = Pattern.compile("(\\[|\\])"); + + @SuppressWarnings("nullness") // jdk of CF doesn't have the URI class in there + private static URI buildURIWithAuthority(String scheme, String authority, + String path, String query, String fragment) { + try { + URI result = new URI(scheme, authority, path, query, fragment); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + if (authority != null && squareBrackets.matcher(authority).find()) { + // Java URI do not correctly quote the brackets inside the authority + // even though RFC2732 specifies this. + // it has to do with the fact that the encoding/quotation is a single pass + // and that authority is actually ambigious, so it requires backtracking to + // decide which alternative of the authority part is used, and the quoting rules are + // slightly different. + // so if it fails to parse, we put some placeholder chars, which get encoded, + // we then replace the encoded values with the correct encoded values + // and create a new URI out of this. (to avoid double encoding) + authority = hideBrackets(authority); + URI temp = buildURIWithAuthority(scheme, authority, path, query, fragment); + return unhideBrackets(temp); + } + throw new RuntimeException("Internal state corrupted?", e); + } + + } + + private static final Pattern squareBracketOpenPlaceholder = Pattern.compile("%00%00%EF%BF%B0%00%00"); + private static final Pattern squareBracketClosePlaceholder = Pattern.compile("%00%00%EF%BF%B1%00%00"); + private static URI unhideBrackets(URI temp) { + String newURI = temp.toASCIIString(); + newURI = squareBracketOpenPlaceholder.matcher(newURI).replaceAll("%5B"); + newURI = squareBracketClosePlaceholder.matcher(newURI).replaceAll("%5D"); + try { + return new URI(newURI); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + private static final Pattern squareBracketOpen = Pattern.compile("\\["); + private static final Pattern squareBracketClose = Pattern.compile("\\]"); + private static String hideBrackets(String authority) { + authority = squareBracketOpen.matcher(authority).replaceAll("\0\0\uFFF0\0\0"); + return squareBracketClose.matcher(authority).replaceAll("\0\0\uFFF1\0\0"); + } + + private static final Interner INTERNED_AUTHORIES = Interner.newStrongInterner(); + private static class AuthorityURI extends BaseURI { + protected final String authority; + + public AuthorityURI(String scheme, String authority) { + super(scheme); + + this.authority = INTERNED_AUTHORIES.intern(authority); + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, null, null, null); + } + + @Override + public boolean hasPath() { + return false; + } + + @Override + public boolean hasAuthority() { + return true; + } + @Override + public String getAuthority() { + return authority; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { + return false; + } + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + AuthorityURI u = (AuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority; + } + + return false; + } + } + + private static class PathURI extends BaseURI { + protected final String path; + private int hash = 0; // we can cache the hash code since the 8-byte alignment leaves room for one + + public PathURI(String scheme, String path) { + super(scheme); + this.path = path; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + try { + URI result = new URI(scheme, "", path, null, null); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasPath() { + return true; + } + + @Override + public String getPath() { + return path; + } + + @Override + public int hashCode() { + if (hash == 0) { + hash = scheme.hashCode() + path.hashCode(); + } + + return hash; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { + return false; + } + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + PathURI u = (PathURI)obj; + if (hash != 0 && u.hash != 0 && hash != u.hash) { + return false; + } + + return scheme == u.scheme + && path.equals(u.path); + } + return false; + } + } + + private static class PathAuthorityURI extends AuthorityURI { + protected final String path; + + public PathAuthorityURI(String scheme, String authority, String path) { + super(scheme, authority); + this.path = path; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, path, null, null); + } + + @Override + public boolean hasPath() { + return true; + } + @Override + public String getPath() { + return path; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + path.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { + return false; + } + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + PathAuthorityURI u = (PathAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && path.equals(u.path); + } + + return false; + } + } + + private static class QueryURI extends BaseURI { + protected final String query; + + public QueryURI(String scheme, String query) { + super(scheme); + this.query = query; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", "/", query, null); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasQuery() { - return true; - } - @Override - public String getQuery() { - return query; - } - @Override - public int hashCode() { - return scheme.hashCode() + query.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", "/", query, null); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasQuery() { + return true; + } + @Override + public String getQuery() { + return query; + } + @Override + public int hashCode() { + return scheme.hashCode() + query.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - QueryURI u = (QueryURI)obj; - return scheme == u.scheme - && query.equals(u.query) - ; - } - return false; - } - } - - private static class QueryAuthorityURI extends AuthorityURI { - protected final String query; - - public QueryAuthorityURI(String scheme, String authority, String query) { - super(scheme, authority); - this.query = query; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, null, query, null); - } - - @Override - public boolean hasQuery() { - return true; - } - @Override - public String getQuery() { - return query; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + query.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + QueryURI u = (QueryURI)obj; + return scheme == u.scheme + && query.equals(u.query) + ; + } + return false; + } + } + + private static class QueryAuthorityURI extends AuthorityURI { + protected final String query; + + public QueryAuthorityURI(String scheme, String authority, String query) { + super(scheme, authority); + this.query = query; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, null, query, null); + } + + @Override + public boolean hasQuery() { + return true; + } + @Override + public String getQuery() { + return query; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + query.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - QueryAuthorityURI u = (QueryAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && query.equals(u.query) - ; - } - return false; - } - } - - private static class QueryPathURI extends PathURI { - protected final String query; - - public QueryPathURI(String scheme, String path, String query) { - super(scheme, path); - this.query = query; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + QueryAuthorityURI u = (QueryAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && query.equals(u.query) + ; + } + return false; + } + } + + private static class QueryPathURI extends PathURI { + protected final String query; + + public QueryPathURI(String scheme, String path, String query) { + super(scheme, path); + this.query = query; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", path, query, null); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasQuery() { - return true; - } - @Override - public String getQuery() { - return query; - } - @Override - public int hashCode() { - return scheme.hashCode() + path.hashCode() + query.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", path, query, null); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasQuery() { + return true; + } + @Override + public String getQuery() { + return query; + } + @Override + public int hashCode() { + return scheme.hashCode() + path.hashCode() + query.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - QueryPathURI u = (QueryPathURI)obj; - return scheme == u.scheme - && path.equals(u.path) - && query.equals(u.query) - ; - } - return false; - } - } - - private static class QueryPathAuthorityURI extends PathAuthorityURI { - protected final String query; - - public QueryPathAuthorityURI(String scheme, String authority, String path, String query) { - super(scheme, authority, path); - this.query = query; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, path,query,null); - } - - @Override - public boolean hasQuery() { - return true; - } - @Override - public String getQuery() { - return query; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + path.hashCode() + query.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + QueryPathURI u = (QueryPathURI)obj; + return scheme == u.scheme + && path.equals(u.path) + && query.equals(u.query) + ; + } + return false; + } + } + + private static class QueryPathAuthorityURI extends PathAuthorityURI { + protected final String query; + + public QueryPathAuthorityURI(String scheme, String authority, String path, String query) { + super(scheme, authority, path); + this.query = query; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, path,query,null); + } + + @Override + public boolean hasQuery() { + return true; + } + @Override + public String getQuery() { + return query; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + path.hashCode() + query.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if(obj.getClass() == getClass()){ - QueryPathAuthorityURI u = (QueryPathAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && path.equals(u.path) - && query.equals(u.query) - ; - } - return false; - } - } - - private static class FragmentURI extends BaseURI { - protected final String fragment; - - public FragmentURI(String scheme, String fragment) { - super(scheme); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + + if (this == obj) { + return true; + } + + if(obj.getClass() == getClass()){ + QueryPathAuthorityURI u = (QueryPathAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && path.equals(u.path) + && query.equals(u.query) + ; + } + return false; + } + } + + private static class FragmentURI extends BaseURI { + protected final String fragment; + + public FragmentURI(String scheme, String fragment) { + super(scheme); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", "/", null, fragment); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", "/", null, fragment); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentURI u = (FragmentURI)obj; - return scheme == u.scheme - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentAuthorityURI extends AuthorityURI { - protected final String fragment; - - public FragmentAuthorityURI(String scheme, String authority, String fragment) { - super(scheme, authority); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, null, null, fragment); - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentURI u = (FragmentURI)obj; + return scheme == u.scheme + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentAuthorityURI extends AuthorityURI { + protected final String fragment; + + public FragmentAuthorityURI(String scheme, String authority, String fragment) { + super(scheme, authority); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, null, null, fragment); + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentAuthorityURI u = (FragmentAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentPathURI extends PathURI { - protected final String fragment; - - public FragmentPathURI(String scheme, String path, String fragment) { - super(scheme, path); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentAuthorityURI u = (FragmentAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentPathURI extends PathURI { + protected final String fragment; + + public FragmentPathURI(String scheme, String path, String fragment) { + super(scheme, path); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", path, null, fragment); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + path.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", path, null, fragment); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + path.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentPathURI u = (FragmentPathURI)obj; - return scheme == u.scheme - && path.equals(u.path) - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentPathAuthorityURI extends PathAuthorityURI { - protected final String fragment; - - public FragmentPathAuthorityURI(String scheme, String authority, String path, String fragment) { - super(scheme, authority, path); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, path, null, fragment); - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + path.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentPathURI u = (FragmentPathURI)obj; + return scheme == u.scheme + && path.equals(u.path) + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentPathAuthorityURI extends PathAuthorityURI { + protected final String fragment; + + public FragmentPathAuthorityURI(String scheme, String authority, String path, String fragment) { + super(scheme, authority, path); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, path, null, fragment); + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + path.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentPathAuthorityURI u = (FragmentPathAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && path.equals(u.path) - && fragment.equals(u.fragment) - ; - } - return false; - } - } - private static class FragmentQueryURI extends QueryURI { - protected final String fragment; - - public FragmentQueryURI(String scheme, String query, String fragment) { - super(scheme, query); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentPathAuthorityURI u = (FragmentPathAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && path.equals(u.path) + && fragment.equals(u.fragment) + ; + } + return false; + } + } + private static class FragmentQueryURI extends QueryURI { + protected final String fragment; + + public FragmentQueryURI(String scheme, String query, String fragment) { + super(scheme, query); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", "/", query, fragment); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + query.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", "/", query, fragment); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + query.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentQueryURI u = (FragmentQueryURI)obj; - return scheme == u.scheme - && query.equals(u.query) - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentQueryAuthorityURI extends QueryAuthorityURI { - protected final String fragment; - - public FragmentQueryAuthorityURI(String scheme, String authority, String query, String fragment) { - super(scheme, authority, query); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, null, query, fragment); - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + query.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentQueryURI u = (FragmentQueryURI)obj; + return scheme == u.scheme + && query.equals(u.query) + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentQueryAuthorityURI extends QueryAuthorityURI { + protected final String fragment; + + public FragmentQueryAuthorityURI(String scheme, String authority, String query, String fragment) { + super(scheme, authority, query); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, null, query, fragment); + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + query.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentQueryAuthorityURI u = (FragmentQueryAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && query.equals(u.query) - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentQueryPathURI extends QueryPathURI { - protected final String fragment; - - public FragmentQueryPathURI(String scheme, String path, String query, String fragment) { - super(scheme, path, query); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentQueryAuthorityURI u = (FragmentQueryAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && query.equals(u.query) + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentQueryPathURI extends QueryPathURI { + protected final String fragment; + + public FragmentQueryPathURI(String scheme, String path, String query, String fragment) { + super(scheme, path, query); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI public URI getURI() { - try { - URI result = new URI(scheme, "", path, query, fragment); - return new URI(result.toASCIIString()); - } catch (URISyntaxException e) { - throw new RuntimeException("Internal state corrupted?", e); - } - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + path.hashCode() + query.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + try { + URI result = new URI(scheme, "", path, query, fragment); + return new URI(result.toASCIIString()); + } catch (URISyntaxException e) { + throw new RuntimeException("Internal state corrupted?", e); + } + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + path.hashCode() + query.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentQueryPathURI u = (FragmentQueryPathURI)obj; - return scheme == u.scheme - && path.equals(u.path) - && query.equals(u.query) - && fragment.equals(u.fragment) - ; - } - return false; - } - } - - private static class FragmentQueryPathAuthorityURI extends QueryPathAuthorityURI { - protected final String fragment; - - public FragmentQueryPathAuthorityURI(String scheme, String authority, String path, String query, String fragment) { - super(scheme, authority, path, query); - this.fragment = fragment; - } - - @Override - @SuppressWarnings("nullness") // CF doesn't have a model for URI - public URI getURI() { - return buildURIWithAuthority(scheme, authority, path, query, fragment); - } - - @Override - public boolean hasFragment() { - return true; - } - @Override - public String getFragment() { - return fragment; - } - @Override - public int hashCode() { - return scheme.hashCode() + authority.hashCode() + path.hashCode() + query.hashCode() + fragment.hashCode(); - } - @Override - public boolean equals(@Nullable Object obj) { - if (obj == null) { + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentQueryPathURI u = (FragmentQueryPathURI)obj; + return scheme == u.scheme + && path.equals(u.path) + && query.equals(u.query) + && fragment.equals(u.fragment) + ; + } + return false; + } + } + + private static class FragmentQueryPathAuthorityURI extends QueryPathAuthorityURI { + protected final String fragment; + + public FragmentQueryPathAuthorityURI(String scheme, String authority, String path, String query, String fragment) { + super(scheme, authority, path, query); + this.fragment = fragment; + } + + @Override + @SuppressWarnings("nullness") // CF doesn't have a model for URI + public URI getURI() { + return buildURIWithAuthority(scheme, authority, path, query, fragment); + } + + @Override + public boolean hasFragment() { + return true; + } + @Override + public String getFragment() { + return fragment; + } + @Override + public int hashCode() { + return scheme.hashCode() + authority.hashCode() + path.hashCode() + query.hashCode() + fragment.hashCode(); + } + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) { return false; } - - if (this == obj) { - return true; - } - - if (obj.getClass() == getClass()){ - FragmentQueryPathAuthorityURI u = (FragmentQueryPathAuthorityURI)obj; - return scheme == u.scheme - && authority == u.authority - && path.equals(u.path) - && query.equals(u.query) - && fragment.equals(u.fragment) - ; - } - return false; - } - } + + if (this == obj) { + return true; + } + + if (obj.getClass() == getClass()){ + FragmentQueryPathAuthorityURI u = (FragmentQueryPathAuthorityURI)obj; + return scheme == u.scheme + && authority == u.authority + && path.equals(u.path) + && query.equals(u.query) + && fragment.equals(u.fragment) + ; + } + return false; + } + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationValues.java b/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationValues.java index fa318c867..2481b3323 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationValues.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/SourceLocationValues.java @@ -29,823 +29,823 @@ /** * This is a container class for a number of implementations of ISourceLocation. Each implementation is extremely similar to the others. * except that different native types are used to store offsets, lengths, line and column indices. The goal is to use a minimum amount - * of heap for each source location object, since at run-time there will be so many of them. We measured the effect of this on some real + * of heap for each source location object, since at run-time there will be so many of them. We measured the effect of this on some real * applications and showed more than 50% improvement in memory usage. */ /*package*/ class SourceLocationValues { - - - - /*package*/ static ISourceLocation newSourceLocation(ISourceLocation loc, int offset, int length) { - ISourceLocation root = loc.top(); - if (offset < 0) throw new IllegalArgumentException("offset should be positive"); - if (length < 0) throw new IllegalArgumentException("length should be positive"); - - if (offset < Byte.MAX_VALUE && length < Byte.MAX_VALUE) { - return new SourceLocationValues.ByteByte(root, (byte) offset, (byte) length); - } - - if (offset < Character.MAX_VALUE && length < Character.MAX_VALUE) { - return new SourceLocationValues.CharChar(root, (char) offset, (char) length); - } - - return new SourceLocationValues.IntInt(root, offset, length); - } - - /*package*/ static ISourceLocation newSourceLocation(ISourceLocation loc, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { - ISourceLocation root = loc.top(); - if (offset < 0) throw new IllegalArgumentException("offset should be positive"); - if (length < 0) throw new IllegalArgumentException("length should be positive"); - if (beginLine < 0) throw new IllegalArgumentException("beginLine should be positive"); - if (beginCol < 0) throw new IllegalArgumentException("beginCol should be positive"); - if (endCol < 0) throw new IllegalArgumentException("endCol should be positive"); - if (endLine < beginLine) - throw new IllegalArgumentException("endLine should be larger than or equal to beginLine"); - if (endLine == beginLine && endCol < beginCol) - throw new IllegalArgumentException("endCol should be larger than or equal to beginCol, if on the same line"); - - if (offset < Character.MAX_VALUE - && length < Character.MAX_VALUE - && beginLine < Byte.MAX_VALUE - && endLine < Byte.MAX_VALUE - && beginCol < Byte.MAX_VALUE - && endCol < Byte.MAX_VALUE) { - return new SourceLocationValues.CharCharByteByteByteByte(root, (char) offset, (char) length, (byte) beginLine, (byte) endLine, (byte) beginCol, (byte) endCol); - } else if (offset < Character.MAX_VALUE - && length < Character.MAX_VALUE - && beginLine < Character.MAX_VALUE - && endLine < Character.MAX_VALUE - && beginCol < Character.MAX_VALUE - && endCol < Character.MAX_VALUE) { - return new SourceLocationValues.CharCharCharCharCharChar(root, (char) offset, (char) length, (char) beginLine, (char) endLine, (char) beginCol, (char) endCol); - } else if (beginLine < Character.MAX_VALUE - && endLine < Character.MAX_VALUE - && beginCol < Byte.MAX_VALUE - && endCol < Byte.MAX_VALUE) { - return new SourceLocationValues.IntIntCharCharByteByte(root, offset, length, (char) beginLine, (char) endLine, (byte) beginCol, (byte) endCol); - } else if (beginCol < Byte.MAX_VALUE - && endCol < Byte.MAX_VALUE) { - return new SourceLocationValues.IntIntIntIntByteByte(root, offset, length, beginLine, endLine, (byte) beginCol, (byte) endCol); - } - - return new SourceLocationValues.IntIntIntIntIntInt(root, offset, length, beginLine, endLine, beginCol, endCol); - } - - private final static Cache reverseLocationCache = Caffeine.newBuilder() + + + + /*package*/ static ISourceLocation newSourceLocation(ISourceLocation loc, int offset, int length) { + ISourceLocation root = loc.top(); + if (offset < 0) throw new IllegalArgumentException("offset should be positive"); + if (length < 0) throw new IllegalArgumentException("length should be positive"); + + if (offset < Byte.MAX_VALUE && length < Byte.MAX_VALUE) { + return new SourceLocationValues.ByteByte(root, (byte) offset, (byte) length); + } + + if (offset < Character.MAX_VALUE && length < Character.MAX_VALUE) { + return new SourceLocationValues.CharChar(root, (char) offset, (char) length); + } + + return new SourceLocationValues.IntInt(root, offset, length); + } + + /*package*/ static ISourceLocation newSourceLocation(ISourceLocation loc, int offset, int length, int beginLine, int endLine, int beginCol, int endCol) { + ISourceLocation root = loc.top(); + if (offset < 0) throw new IllegalArgumentException("offset should be positive"); + if (length < 0) throw new IllegalArgumentException("length should be positive"); + if (beginLine < 0) throw new IllegalArgumentException("beginLine should be positive"); + if (beginCol < 0) throw new IllegalArgumentException("beginCol should be positive"); + if (endCol < 0) throw new IllegalArgumentException("endCol should be positive"); + if (endLine < beginLine) + throw new IllegalArgumentException("endLine should be larger than or equal to beginLine"); + if (endLine == beginLine && endCol < beginCol) + throw new IllegalArgumentException("endCol should be larger than or equal to beginCol, if on the same line"); + + if (offset < Character.MAX_VALUE + && length < Character.MAX_VALUE + && beginLine < Byte.MAX_VALUE + && endLine < Byte.MAX_VALUE + && beginCol < Byte.MAX_VALUE + && endCol < Byte.MAX_VALUE) { + return new SourceLocationValues.CharCharByteByteByteByte(root, (char) offset, (char) length, (byte) beginLine, (byte) endLine, (byte) beginCol, (byte) endCol); + } else if (offset < Character.MAX_VALUE + && length < Character.MAX_VALUE + && beginLine < Character.MAX_VALUE + && endLine < Character.MAX_VALUE + && beginCol < Character.MAX_VALUE + && endCol < Character.MAX_VALUE) { + return new SourceLocationValues.CharCharCharCharCharChar(root, (char) offset, (char) length, (char) beginLine, (char) endLine, (char) beginCol, (char) endCol); + } else if (beginLine < Character.MAX_VALUE + && endLine < Character.MAX_VALUE + && beginCol < Byte.MAX_VALUE + && endCol < Byte.MAX_VALUE) { + return new SourceLocationValues.IntIntCharCharByteByte(root, offset, length, (char) beginLine, (char) endLine, (byte) beginCol, (byte) endCol); + } else if (beginCol < Byte.MAX_VALUE + && endCol < Byte.MAX_VALUE) { + return new SourceLocationValues.IntIntIntIntByteByte(root, offset, length, beginLine, endLine, (byte) beginCol, (byte) endCol); + } + + return new SourceLocationValues.IntIntIntIntIntInt(root, offset, length, beginLine, endLine, beginCol, endCol); + } + + private final static Cache reverseLocationCache = Caffeine.newBuilder() .expireAfterAccess(5, TimeUnit.MINUTES) .maximumSize(1000) .build(); - /** - * As the parser is always calling the URI constructor, we cache the result, as not to unpack it all the time. - */ - private final static Cache locationCache = Caffeine.newBuilder() + /** + * As the parser is always calling the URI constructor, we cache the result, as not to unpack it all the time. + */ + private final static Cache locationCache = Caffeine.newBuilder() .expireAfterAccess(5, TimeUnit.MINUTES) .maximumSize(1000) .weakKeys() // loose entries quickly, and force reference equality, such that URI's are only compared based on instance, not on contents (as their equality is case-insensitive) .build(); - - /*package*/ static ISourceLocation newSourceLocation(URI uri) throws URISyntaxException { - if (uri.isOpaque()) { - throw new UnsupportedOperationException("Opaque URI schemes are not supported; the scheme-specific part must start with a / character."); - } - ISourceLocation result = locationCache.get(uri, (u) -> { - try { - return newSourceLocation(u.getScheme(), u.getAuthority(), u.getPath(), u.getQuery(), u.getFragment()); - } catch (URISyntaxException e) { - throw new RuntimeException("We can't get a URISyntaxException when we start with an URI"); - } - }); - if (result == null) { - throw new RuntimeException("Cache is not working as expected"); - } - return result; - } - - /*package*/ static ISourceLocation newSourceLocation(String scheme, String authority, - String path, @Nullable String query, @Nullable String fragment) throws URISyntaxException { - return SourceLocationURIValues.newURI(scheme, authority, path, query, fragment); - } - - - private abstract static class Complete extends Incomplete { - private Complete(ISourceLocation root) { - super(root); - } - - @Override - public boolean hasOffsetLength() { - return true; - } - - @Override - public boolean hasLineColumn() { - return true; - } - } - - - private abstract static class Incomplete implements ISourceLocation { - protected ISourceLocation root; - - public Incomplete(ISourceLocation root) { - this.root = root; - } - - @Override - public boolean hasAuthority() { - return root.hasAuthority(); - } - - @Override - public boolean hasFragment() { - return root.hasFragment(); - } - - @Override - public boolean hasPath() { - return root.hasPath(); - } - - @Override - public String toString() { - return defaultToString(); - } - - - @Override - public boolean hasQuery() { - return root.hasQuery(); - } - - @Override - public String getAuthority() { - return root.getAuthority(); - } - - @Override - public String getFragment() { - return root.getFragment(); - } - - @Override - public String getPath() { - return root.getPath(); - } - - @Override - public String getQuery() { - return root.getQuery(); - } - - @Override - public String getScheme() { - return root.getScheme(); - } - - @Override - public ISourceLocation top() { - return root; - } - - @Override - public URI getURI() { - URI result = reverseLocationCache.get(root, u -> { + + /*package*/ static ISourceLocation newSourceLocation(URI uri) throws URISyntaxException { + if (uri.isOpaque()) { + throw new UnsupportedOperationException("Opaque URI schemes are not supported; the scheme-specific part must start with a / character."); + } + ISourceLocation result = locationCache.get(uri, (u) -> { + try { + return newSourceLocation(u.getScheme(), u.getAuthority(), u.getPath(), u.getQuery(), u.getFragment()); + } catch (URISyntaxException e) { + throw new RuntimeException("We can't get a URISyntaxException when we start with an URI"); + } + }); + if (result == null) { + throw new RuntimeException("Cache is not working as expected"); + } + return result; + } + + /*package*/ static ISourceLocation newSourceLocation(String scheme, String authority, + String path, @Nullable String query, @Nullable String fragment) throws URISyntaxException { + return SourceLocationURIValues.newURI(scheme, authority, path, query, fragment); + } + + + private abstract static class Complete extends Incomplete { + private Complete(ISourceLocation root) { + super(root); + } + + @Override + public boolean hasOffsetLength() { + return true; + } + + @Override + public boolean hasLineColumn() { + return true; + } + } + + + private abstract static class Incomplete implements ISourceLocation { + protected ISourceLocation root; + + public Incomplete(ISourceLocation root) { + this.root = root; + } + + @Override + public boolean hasAuthority() { + return root.hasAuthority(); + } + + @Override + public boolean hasFragment() { + return root.hasFragment(); + } + + @Override + public boolean hasPath() { + return root.hasPath(); + } + + @Override + public String toString() { + return defaultToString(); + } + + + @Override + public boolean hasQuery() { + return root.hasQuery(); + } + + @Override + public String getAuthority() { + return root.getAuthority(); + } + + @Override + public String getFragment() { + return root.getFragment(); + } + + @Override + public String getPath() { + return root.getPath(); + } + + @Override + public String getQuery() { + return root.getQuery(); + } + + @Override + public String getScheme() { + return root.getScheme(); + } + + @Override + public ISourceLocation top() { + return root; + } + + @Override + public URI getURI() { + URI result = reverseLocationCache.get(root, u -> { URI calculated = u.getURI(); try { // assure correct encoding, side effect of JRE's implementation of URIs return new URI(calculated.toASCIIString()); } catch (URISyntaxException ignored) { - return calculated; - } - }); - if (result == null) { - throw new RuntimeException("Error translating URI"); - } - return result; - } - - @Override - public Type getType(){ - return TypeFactory.getInstance().sourceLocationType(); - } - - @Override - public boolean hasLineColumn() { - return false; - } - - @Override - public boolean hasOffsetLength() { - return false; - } - - @Override - public int getBeginColumn() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - @Override - public int getBeginLine() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - @Override - public int getEndColumn() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - @Override - public int getEndLine() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - @Override - public int getLength() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - @Override - public int getOffset() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - } - - private static class IntIntIntIntIntInt extends Complete { - protected final int offset; - protected final int length; - protected final int beginLine; - protected final int endLine; - protected final int beginCol; - protected final int endCol; - - private IntIntIntIntIntInt(ISourceLocation root, int offset, int length, int beginLine, int endLine, int beginCol, int endCol){ - super(root); - - this.offset = offset; - this.length = length; - this.beginLine = beginLine; - this.endLine = endLine; - this.beginCol = beginCol; - this.endCol = endCol; - } - @Override - public Type getType(){ - return TypeFactory.getInstance().sourceLocationType(); - } - - @Override - public int getBeginLine(){ - return beginLine; - } - - @Override - public int getEndLine(){ - return endLine; - } - - @Override - public int getBeginColumn(){ - return beginCol; - } - - @Override - public int getEndColumn(){ - return endCol; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= beginLine << 3; - hash ^= (endLine << 23); - hash ^= (beginCol << 13); - hash ^= (endCol << 18); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if (o == null) { - return false; - } - - if(o.getClass() == getClass()){ - IntIntIntIntIntInt otherSourceLocation = (IntIntIntIntIntInt) o; - return (root.equals(otherSourceLocation.root) - && (beginLine == otherSourceLocation.beginLine) - && (endLine == otherSourceLocation.endLine) - && (beginCol == otherSourceLocation.beginCol) - && (endCol == otherSourceLocation.endCol) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class CharCharByteByteByteByte extends Complete { - protected final char offset; - protected final char length; - protected final byte beginLine; - protected final byte endLine; - protected final byte beginCol; - protected final byte endCol; - - private CharCharByteByteByteByte(ISourceLocation root, char offset, char length, byte beginLine, byte endLine, byte beginCol, byte endCol){ - super(root); - - this.offset = offset; - this.length = length; - this.beginLine = beginLine; - this.endLine = endLine; - this.beginCol = beginCol; - this.endCol = endCol; - } - @Override - public Type getType(){ - return TypeFactory.getInstance().sourceLocationType(); - } - - @Override - public int getBeginLine(){ - return beginLine; - } - - @Override - public int getEndLine(){ - return endLine; - } - - @Override - public int getBeginColumn(){ - return beginCol; - } - - @Override - public int getEndColumn(){ - return endCol; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= beginLine << 3; - hash ^= (endLine << 23); - hash ^= (beginCol << 13); - hash ^= (endCol << 18); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if (o == null) { - return false; - } - - if (o.getClass() == getClass()){ - CharCharByteByteByteByte otherSourceLocation = (CharCharByteByteByteByte) o; - return (root.equals(otherSourceLocation.root) - && (beginLine == otherSourceLocation.beginLine) - && (endLine == otherSourceLocation.endLine) - && (beginCol == otherSourceLocation.beginCol) - && (endCol == otherSourceLocation.endCol) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class CharCharCharCharCharChar extends Complete { - protected final char offset; - protected final char length; - protected final char beginLine; - protected final char endLine; - protected final char beginCol; - protected final char endCol; - - private CharCharCharCharCharChar(ISourceLocation root, char offset, char length, char beginLine, char endLine, char beginCol, char endCol){ - super(root); - - this.offset = offset; - this.length = length; - this.beginLine = beginLine; - this.endLine = endLine; - this.beginCol = beginCol; - this.endCol = endCol; - } - @Override - public Type getType(){ - return TypeFactory.getInstance().sourceLocationType(); - } - - @Override - public int getBeginLine(){ - return beginLine; - } - - @Override - public int getEndLine(){ - return endLine; - } - - @Override - public int getBeginColumn(){ - return beginCol; - } - - @Override - public int getEndColumn(){ - return endCol; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= beginLine << 3; - hash ^= (endLine << 23); - hash ^= (beginCol << 13); - hash ^= (endCol << 18); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - CharCharCharCharCharChar otherSourceLocation = (CharCharCharCharCharChar) o; - return (root.equals(otherSourceLocation.root) - && (beginLine == otherSourceLocation.beginLine) - && (endLine == otherSourceLocation.endLine) - && (beginCol == otherSourceLocation.beginCol) - && (endCol == otherSourceLocation.endCol) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class IntIntIntIntByteByte extends Complete { - protected final int offset; - protected final int length; - protected final int beginLine; - protected final int endLine; - protected final byte beginCol; - protected final byte endCol; - - private IntIntIntIntByteByte(ISourceLocation root, int offset, int length, int beginLine, int endLine, byte beginCol, byte endCol){ - super(root); - - this.offset = offset; - this.length = length; - this.beginLine = beginLine; - this.endLine = endLine; - this.beginCol = beginCol; - this.endCol = endCol; - } - - @Override - public int getBeginLine(){ - return beginLine; - } - - @Override - public int getEndLine(){ - return endLine; - } - - @Override - public int getBeginColumn(){ - return beginCol; - } - - @Override - public int getEndColumn(){ - return endCol; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= beginLine << 3; - hash ^= (endLine << 23); - hash ^= (beginCol << 13); - hash ^= (endCol << 18); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - IntIntIntIntByteByte otherSourceLocation = (IntIntIntIntByteByte) o; - return (root.equals(otherSourceLocation.root) - && (beginLine == otherSourceLocation.beginLine) - && (endLine == otherSourceLocation.endLine) - && (beginCol == otherSourceLocation.beginCol) - && (endCol == otherSourceLocation.endCol) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class IntIntCharCharByteByte extends Complete { - protected final int offset; - protected final int length; - protected final char beginLine; - protected final char endLine; - protected final byte beginCol; - protected final byte endCol; - - private IntIntCharCharByteByte(ISourceLocation root, int offset, int length, char beginLine, char endLine, byte beginCol, byte endCol){ - super(root); - - this.offset = offset; - this.length = length; - this.beginLine = beginLine; - this.endLine = endLine; - this.beginCol = beginCol; - this.endCol = endCol; - } - - @Override - public int getBeginLine(){ - return beginLine; - } - - @Override - public int getEndLine(){ - return endLine; - } - - @Override - public int getBeginColumn(){ - return beginCol; - } - - @Override - public int getEndColumn(){ - return endCol; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= beginLine << 3; - hash ^= (endLine << 23); - hash ^= (beginCol << 13); - hash ^= (endCol << 18); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - IntIntCharCharByteByte otherSourceLocation = (IntIntCharCharByteByte) o; - return (root.equals(otherSourceLocation.root) - && (beginLine == otherSourceLocation.beginLine) - && (endLine == otherSourceLocation.endLine) - && (beginCol == otherSourceLocation.beginCol) - && (endCol == otherSourceLocation.endCol) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class ByteByte extends Incomplete { - protected final byte offset; - protected final byte length; - - private ByteByte(ISourceLocation root, byte offset, byte length){ - super(root); - - this.offset = offset; - this.length = length; - } - - @Override - public boolean hasOffsetLength() { - return true; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - ByteByte otherSourceLocation = (ByteByte) o; - return (root.equals(otherSourceLocation.root) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class CharChar extends Incomplete { - protected final char offset; - protected final char length; - - private CharChar(ISourceLocation root, char offset, char length){ - super(root); - - this.offset = offset; - this.length = length; - } - - @Override - public boolean hasOffsetLength() { - return true; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - CharChar otherSourceLocation = (CharChar) o; - return (root.equals(otherSourceLocation.root) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } - - private static class IntInt extends Incomplete { - protected final int offset; - protected final int length; - - private IntInt(ISourceLocation root, int offset, int length){ - super(root); - - this.offset = offset; - this.length = length; - } - - @Override - public boolean hasOffsetLength() { - return true; - } - - @Override - public boolean hasLineColumn() { - return false; - } - - @Override - public int getOffset(){ - return offset; - } - - @Override - public int getLength(){ - return length; - } - - @Override - public int hashCode(){ - int hash = root.hashCode(); - hash ^= (offset << 8); - hash ^= (length << 29); - - return hash; - } - - @Override - public boolean equals(@Nullable Object o){ - if(o == null) return false; - - if(o.getClass() == getClass()){ - IntInt otherSourceLocation = (IntInt) o; - return (root.equals(otherSourceLocation.root) - && (offset == otherSourceLocation.offset) - && (length == otherSourceLocation.length)); - } - - return false; - } - } + return calculated; + } + }); + if (result == null) { + throw new RuntimeException("Error translating URI"); + } + return result; + } + + @Override + public Type getType(){ + return TypeFactory.getInstance().sourceLocationType(); + } + + @Override + public boolean hasLineColumn() { + return false; + } + + @Override + public boolean hasOffsetLength() { + return false; + } + + @Override + public int getBeginColumn() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public int getBeginLine() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public int getEndColumn() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public int getEndLine() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public int getLength() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public int getOffset() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + } + + private static class IntIntIntIntIntInt extends Complete { + protected final int offset; + protected final int length; + protected final int beginLine; + protected final int endLine; + protected final int beginCol; + protected final int endCol; + + private IntIntIntIntIntInt(ISourceLocation root, int offset, int length, int beginLine, int endLine, int beginCol, int endCol){ + super(root); + + this.offset = offset; + this.length = length; + this.beginLine = beginLine; + this.endLine = endLine; + this.beginCol = beginCol; + this.endCol = endCol; + } + @Override + public Type getType(){ + return TypeFactory.getInstance().sourceLocationType(); + } + + @Override + public int getBeginLine(){ + return beginLine; + } + + @Override + public int getEndLine(){ + return endLine; + } + + @Override + public int getBeginColumn(){ + return beginCol; + } + + @Override + public int getEndColumn(){ + return endCol; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= beginLine << 3; + hash ^= (endLine << 23); + hash ^= (beginCol << 13); + hash ^= (endCol << 18); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if (o == null) { + return false; + } + + if(o.getClass() == getClass()){ + IntIntIntIntIntInt otherSourceLocation = (IntIntIntIntIntInt) o; + return (root.equals(otherSourceLocation.root) + && (beginLine == otherSourceLocation.beginLine) + && (endLine == otherSourceLocation.endLine) + && (beginCol == otherSourceLocation.beginCol) + && (endCol == otherSourceLocation.endCol) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class CharCharByteByteByteByte extends Complete { + protected final char offset; + protected final char length; + protected final byte beginLine; + protected final byte endLine; + protected final byte beginCol; + protected final byte endCol; + + private CharCharByteByteByteByte(ISourceLocation root, char offset, char length, byte beginLine, byte endLine, byte beginCol, byte endCol){ + super(root); + + this.offset = offset; + this.length = length; + this.beginLine = beginLine; + this.endLine = endLine; + this.beginCol = beginCol; + this.endCol = endCol; + } + @Override + public Type getType(){ + return TypeFactory.getInstance().sourceLocationType(); + } + + @Override + public int getBeginLine(){ + return beginLine; + } + + @Override + public int getEndLine(){ + return endLine; + } + + @Override + public int getBeginColumn(){ + return beginCol; + } + + @Override + public int getEndColumn(){ + return endCol; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= beginLine << 3; + hash ^= (endLine << 23); + hash ^= (beginCol << 13); + hash ^= (endCol << 18); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if (o == null) { + return false; + } + + if (o.getClass() == getClass()){ + CharCharByteByteByteByte otherSourceLocation = (CharCharByteByteByteByte) o; + return (root.equals(otherSourceLocation.root) + && (beginLine == otherSourceLocation.beginLine) + && (endLine == otherSourceLocation.endLine) + && (beginCol == otherSourceLocation.beginCol) + && (endCol == otherSourceLocation.endCol) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class CharCharCharCharCharChar extends Complete { + protected final char offset; + protected final char length; + protected final char beginLine; + protected final char endLine; + protected final char beginCol; + protected final char endCol; + + private CharCharCharCharCharChar(ISourceLocation root, char offset, char length, char beginLine, char endLine, char beginCol, char endCol){ + super(root); + + this.offset = offset; + this.length = length; + this.beginLine = beginLine; + this.endLine = endLine; + this.beginCol = beginCol; + this.endCol = endCol; + } + @Override + public Type getType(){ + return TypeFactory.getInstance().sourceLocationType(); + } + + @Override + public int getBeginLine(){ + return beginLine; + } + + @Override + public int getEndLine(){ + return endLine; + } + + @Override + public int getBeginColumn(){ + return beginCol; + } + + @Override + public int getEndColumn(){ + return endCol; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= beginLine << 3; + hash ^= (endLine << 23); + hash ^= (beginCol << 13); + hash ^= (endCol << 18); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + CharCharCharCharCharChar otherSourceLocation = (CharCharCharCharCharChar) o; + return (root.equals(otherSourceLocation.root) + && (beginLine == otherSourceLocation.beginLine) + && (endLine == otherSourceLocation.endLine) + && (beginCol == otherSourceLocation.beginCol) + && (endCol == otherSourceLocation.endCol) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class IntIntIntIntByteByte extends Complete { + protected final int offset; + protected final int length; + protected final int beginLine; + protected final int endLine; + protected final byte beginCol; + protected final byte endCol; + + private IntIntIntIntByteByte(ISourceLocation root, int offset, int length, int beginLine, int endLine, byte beginCol, byte endCol){ + super(root); + + this.offset = offset; + this.length = length; + this.beginLine = beginLine; + this.endLine = endLine; + this.beginCol = beginCol; + this.endCol = endCol; + } + + @Override + public int getBeginLine(){ + return beginLine; + } + + @Override + public int getEndLine(){ + return endLine; + } + + @Override + public int getBeginColumn(){ + return beginCol; + } + + @Override + public int getEndColumn(){ + return endCol; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= beginLine << 3; + hash ^= (endLine << 23); + hash ^= (beginCol << 13); + hash ^= (endCol << 18); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + IntIntIntIntByteByte otherSourceLocation = (IntIntIntIntByteByte) o; + return (root.equals(otherSourceLocation.root) + && (beginLine == otherSourceLocation.beginLine) + && (endLine == otherSourceLocation.endLine) + && (beginCol == otherSourceLocation.beginCol) + && (endCol == otherSourceLocation.endCol) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class IntIntCharCharByteByte extends Complete { + protected final int offset; + protected final int length; + protected final char beginLine; + protected final char endLine; + protected final byte beginCol; + protected final byte endCol; + + private IntIntCharCharByteByte(ISourceLocation root, int offset, int length, char beginLine, char endLine, byte beginCol, byte endCol){ + super(root); + + this.offset = offset; + this.length = length; + this.beginLine = beginLine; + this.endLine = endLine; + this.beginCol = beginCol; + this.endCol = endCol; + } + + @Override + public int getBeginLine(){ + return beginLine; + } + + @Override + public int getEndLine(){ + return endLine; + } + + @Override + public int getBeginColumn(){ + return beginCol; + } + + @Override + public int getEndColumn(){ + return endCol; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= beginLine << 3; + hash ^= (endLine << 23); + hash ^= (beginCol << 13); + hash ^= (endCol << 18); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + IntIntCharCharByteByte otherSourceLocation = (IntIntCharCharByteByte) o; + return (root.equals(otherSourceLocation.root) + && (beginLine == otherSourceLocation.beginLine) + && (endLine == otherSourceLocation.endLine) + && (beginCol == otherSourceLocation.beginCol) + && (endCol == otherSourceLocation.endCol) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class ByteByte extends Incomplete { + protected final byte offset; + protected final byte length; + + private ByteByte(ISourceLocation root, byte offset, byte length){ + super(root); + + this.offset = offset; + this.length = length; + } + + @Override + public boolean hasOffsetLength() { + return true; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + ByteByte otherSourceLocation = (ByteByte) o; + return (root.equals(otherSourceLocation.root) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class CharChar extends Incomplete { + protected final char offset; + protected final char length; + + private CharChar(ISourceLocation root, char offset, char length){ + super(root); + + this.offset = offset; + this.length = length; + } + + @Override + public boolean hasOffsetLength() { + return true; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + CharChar otherSourceLocation = (CharChar) o; + return (root.equals(otherSourceLocation.root) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } + + private static class IntInt extends Incomplete { + protected final int offset; + protected final int length; + + private IntInt(ISourceLocation root, int offset, int length){ + super(root); + + this.offset = offset; + this.length = length; + } + + @Override + public boolean hasOffsetLength() { + return true; + } + + @Override + public boolean hasLineColumn() { + return false; + } + + @Override + public int getOffset(){ + return offset; + } + + @Override + public int getLength(){ + return length; + } + + @Override + public int hashCode(){ + int hash = root.hashCode(); + hash ^= (offset << 8); + hash ^= (length << 29); + + return hash; + } + + @Override + public boolean equals(@Nullable Object o){ + if(o == null) return false; + + if(o.getClass() == getClass()){ + IntInt otherSourceLocation = (IntInt) o; + return (root.equals(otherSourceLocation.root) + && (offset == otherSourceLocation.offset) + && (length == otherSourceLocation.length)); + } + + return false; + } + } } diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/StringValue.java b/src/main/java/io/usethesource/vallang/impl/primitive/StringValue.java index 11503f8ff..5e84b6a56 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/StringValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/StringValue.java @@ -11,7 +11,7 @@ * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI * * Jurgen Vinju - balanced trees and lazy indent - CWI * * Bert Lisser - balanced trees and lazy indent - CWI - * * Davy Landman - smart unicode implementations - CWI, SWAT.engineering + * * Davy Landman - smart unicode implementations - CWI, SWAT.engineering *******************************************************************************/ package io.usethesource.vallang.impl.primitive; @@ -43,22 +43,22 @@ /** * Find here the implementations of IString, which all are (must be) sub-classes of {@link AbstractString} * as an internal design invariant. - * + * * The challenges solved by this implementation: * - cater for and optimize for the normal case of strings containing only normal ASCII characters, while * still allowing all 24-bit unicode characters, see {@link FullUnicodeString} and {@link SimpleUnicodeString} * - optimize string {@link IString#concat(IString)} method, in combination with {@link IString#write(Writer)} and {@link IString#iterator()}, * see {@link IStringTreeNode} and {@link LazyConcatString}. - * - optimize the {@link IString#indent(IString)} method, in combination with {@link IString#write(Writer)} and {@link IString#iterator()}, + * - optimize the {@link IString#indent(IString)} method, in combination with {@link IString#write(Writer)} and {@link IString#iterator()}, * see {@link IIndentableString} and {@link IndentedString} - * - allow non-canonical representations of the same string, in particular making sure that equals() and hashCode() works + * - allow non-canonical representations of the same string, in particular making sure that equals() and hashCode() works * well across and between different representations of (accidentally) the same string, see {@link AbstractString#hashCode()}, - * and {@link AbstractString#equals()} and their overrides. - * + * and {@link AbstractString#equals()} and their overrides. + * * The 'normal' case is defined by what people normally do in Rascal, i.e. using string template expanders a lot, * and reading and writing to text files, searching through strings. The other operations on strings are implemented, * but less optimally. They're traded for the optimization of {@link IString#concat(IString)} and {@link IString#indent(IString)}. - * + * * TODO: make a faster path for short strings (i.e. English words) which do not contain high surrogate pairs */ /* package */ public class StringValue { @@ -259,7 +259,7 @@ public int nextInt() { } }; } - + @Override public IString indent(IString whitespace, boolean indentFirstLine) { return !indentFirstLine ? this : whitespace; @@ -334,8 +334,8 @@ public IString concat(IString other) { return StringValue.newString(buffer.toString(), hasNonBMPCodePoints() || o.hasNonBMPCodePoints(), newLineCount); } else { - // For longer strings with many newlines it's usually better to concatenate lazily - // This makes concatenation in O(1) as opposed to O(n) where n is the length of the resulting string. + // For longer strings with many newlines it's usually better to concatenate lazily + // This makes concatenation in O(1) as opposed to O(n) where n is the length of the resulting string. return LazyConcatString.build(this, (AbstractString) other); } } @@ -349,7 +349,7 @@ public IString concat(IString other) { public int hashCode() { return value.hashCode(); } - + @Override public boolean equals(@Nullable Object other) { return super.equals(other); @@ -392,7 +392,7 @@ private int nextCP(CharBuffer cbuf) { private void skipCP(CharBuffer cbuf) { if (cbuf.hasRemaining()) { Buffer buffer = (Buffer) cbuf; // to select the right overloaded `position` method in Java 9 - + int cp = Character.codePointAt(cbuf, 0); buffer.position(buffer.position() + Character.charCount(cp)); } @@ -519,7 +519,7 @@ public void indentedWrite(Writer w, Deque whitespace, boolean indentFir return; } - // otherwise we have to find the newline characters one-by-one. + // otherwise we have to find the newline characters one-by-one. // this implementation tries to quickly find the next newline using indexOf, and streams // line by line to optimize copying the characters onto the stream in bigger blobs than 1 character. for (int pos = value.indexOf(NEWLINE), next = 0; ; next = pos + 1, pos = value.indexOf(NEWLINE, next)) { @@ -636,32 +636,32 @@ public int nextInt() { } /** - * About Lazy indentation + * About Lazy indentation * --- - * + * * The next expensive operation on larger strings is indentation. The {@link #indent(IString)} * method should take every non-empty line of the current string and indent it with a given * string of whitespace characters. - * + * * This operation is a bottleneck, after the concatenation bottleneck, since it requires * duplicating the entire input in memory if done naively, and that several times depending on the - * nesting depth of indentation. A typical expanded string template would require making a number - * of copies in O(d * n), where d is the nesting depth and n is the length of the original string. - * + * nesting depth of indentation. A typical expanded string template would require making a number + * of copies in O(d * n), where d is the nesting depth and n is the length of the original string. + * * A lazy implementation simply remembers that indentation has to be done (in O(1)), and streams the * indented value on request directly to a writer (in O(1)). Since large generated strings are bound to be - * streamed and not further analyzed, this is beneficial for the typical use. - * - * However, all other operations must still work, so relatively complex "indented" versions of + * streamed and not further analyzed, this is beneficial for the typical use. + * + * However, all other operations must still work, so relatively complex "indented" versions of * all IStringimplementations are distributed over the implementation classes of IString. These * operations are slower than their non-indented counterparts since they have to discover where * the newlines are over and over again. For example {@link #charAt(int)} goes from being in O(1) - * to O(n) since we have to find all exact positions of newline characters. - * + * to O(n) since we have to find all exact positions of newline characters. + * * Always caching these positions would have too much of a * memory overhead. There might be something to say for caching these values for very large * strings, while recomputing them on-the-fly for smaller strings, in the future. - * + * */ private interface IIndentableString extends IString { @@ -669,8 +669,8 @@ private interface IIndentableString extends IString { * The non-empty lines are the ones which would be indented. This * exists to be able to quickly compute the exact length of an indented string, * and to be able to blt buffers of single lines directly to the underlying - * I/O buffer. - * + * I/O buffer. + * * @return the number of _non-empty_ lines in a string. */ int lineCount(); @@ -679,7 +679,7 @@ private interface IIndentableString extends IString { * When concatenating indentable strings, the {@link #lineCount()} can * be computed exactly in O(1) by knowing if the left string does or does not * end in a newline:
- * + * * Example:
* concat("#####\n", "@@@@@@") has two lines,
* because both consituents have a single line and the left ends in a newline.
@@ -694,9 +694,9 @@ default boolean isNewlineTerminated() { /** * Utility function for use in the construction of IIndentableString implementations. - * There are details to be handled with respect to the final line of left and the + * There are details to be handled with respect to the final line of left and the * first line of right. - * + * * @param left * @param right * @return the sum of linecounts of left and right, which depends on whether the concatenation @@ -704,14 +704,14 @@ default boolean isNewlineTerminated() { * a merge does not happen. */ public static int concatLineCount(IIndentableString left, IIndentableString right) { - return left.lineCount() - (left.isNewlineTerminated() ? 0 : 1) + right.lineCount(); + return left.lineCount() - (left.isNewlineTerminated() ? 0 : 1) + right.lineCount(); } /** * Specialized (hopefully optimized) implementations of streaming an indented version * of an IString. Implementations should avoid allocating memory and try to write as many - * bytes as possible in one block into the writer. - * + * bytes as possible in one block into the writer. + * * @param w writer to write to * @param whiteSpace the whitespace to write before non-empty lines * @param indentFirstLine whether or not to indent the first line @@ -724,8 +724,8 @@ default public void indentedWrite(Writer w, Deque indentStack, boolean /** * About balanced concat trees - * --- - * + * --- + * * Concatenation must be fast when generating large strings (for example by a * Rascal program which uses `+` and template expansion. With the basic * implementation the left-hand side of the concat would always need to be @@ -733,14 +733,14 @@ default public void indentedWrite(Writer w, Deque indentStack, boolean * bottleneck. The worst case execution time is in O(n^2) where n is the length * of the produced string. The smaller the steps taken (the more concat * operations) towards this length, the worse it gets. - * + * * A simple solution is to build a binary tree of concatenation nodes which can * later be streamed in a linear fashion. That's a good solution because it is * an easy immutable implementation. However, the trees can become quite * unbalanced and therefore extremely deep (consider a number of Rascal for * loops in a template). The recursion required to stream such a tree would run * out of stack space regularly (we know from experience). - * + * * So the current implementation of a lazy concat string _balances_ the tree to * maintain an invariant of an (almost) balanced tree. The worst case depth of * the tree will alway be in O(log(length)). We flatten out strings below 512 @@ -748,11 +748,11 @@ default public void indentedWrite(Writer w, Deque indentStack, boolean * efficient. The cost we pay for balancing the tree is in O(log(length)), so * concat is now in O(log(length)) instead of in O(1), all to avoid the * StackOverflow. - * + * * Note that an implementation with a destructively updated linked list would be * much faster, but due to immutability and lots of sharing of IStrings this is * not feasible. - * + * */ private static interface IStringTreeNode extends IString { @@ -815,7 +815,7 @@ private abstract static class AbstractString implements IString, IStringTreeNode public String toString() { return defaultToString(); } - + @Override public Type getType() { return STRING_TYPE; @@ -828,11 +828,11 @@ public IString indent(IString whitespace, boolean indentFirstLine) { if (whitespace.length() == 0) { return this; } - + if (!indentFirstLine && lineCount() <= 1) { return this; } - + return new IndentedString(this, whitespace, indentFirstLine); } @@ -842,9 +842,9 @@ public IString indent(IString whitespace, boolean indentFirstLine) { */ public String getValue() { // the IString.length() under-estimates the size of the string if the string - // contains many surrogate pairs, but that does not happen a lot in + // contains many surrogate pairs, but that does not happen a lot in // most of what we see, so we decided to go for a tight estimate for - // "normal" ASCII strings which contain around 10% non BMP code points. + // "normal" ASCII strings which contain around 10% non BMP code points. int len = length(); @@ -895,7 +895,7 @@ public boolean equals(@Nullable Object other) { if (other == null) { return false; } - + if (other == this) { return true; } @@ -934,7 +934,7 @@ public boolean equals(@Nullable Object other) { /** * Note that we used the hashcode algorithm for java.lang.String here, which is * necessary because that is also used by the specialized implementations of IString, - * namely FullUnicodeString and its subclasses, + * namely FullUnicodeString and its subclasses, * which must implement together with this class the hashCode/equals contract. */ public int hashCode() { @@ -1009,7 +1009,7 @@ public int hashCode() { return hash; } - + @Override public boolean equals(@Nullable Object other) { return super.equals(other); @@ -1203,12 +1203,12 @@ public int nextInt() { } }; } - + /** * Static helper function for the iterator() method. * * It finds the left-most leaf of the tree, and collects - * the path of nodes to this leaf as a side-effect in the todo + * the path of nodes to this leaf as a side-effect in the todo * stack. */ private static OfInt leftmostLeafIterator(Deque todo, IStringTreeNode start) { @@ -1224,7 +1224,7 @@ private static OfInt leftmostLeafIterator(Deque todo, IStringTre } private static class IndentedString extends AbstractString { - private final IString indent; + private final IString indent; private final AbstractString wrapped; private final boolean indentFirstLine; private volatile @MonotonicNonNull AbstractString flattened = null; @@ -1247,7 +1247,7 @@ protected boolean hasNonBMPCodePoints() { if (flattened != null) { return flattened.hasNonBMPCodePoints(); } - + return wrapped.hasNonBMPCodePoints(); } @@ -1256,11 +1256,11 @@ public IString concat(IString other) { if (other.length() == 0) { return this; } - + if (flattened != null) { return LazyConcatString.build(flattened, (AbstractString) other); } - + if (other instanceof IndentedString) { IndentedString o = (IndentedString) other; @@ -1282,11 +1282,11 @@ public IString indent(IString indent, boolean indentFirstLine) { if (indent.length() == 0) { return this; } - + if (flattened != null) { return new IndentedString(flattened, indent, indentFirstLine); } - + return new IndentedString(wrapped, indent.concat(this.indent), indentFirstLine); } @@ -1309,7 +1309,7 @@ public OfInt iterator() { public boolean hasNext() { return content.hasNext(); // || !nextIndentation.isEmpty() is not needed because if we are out of content we should not indent anyway - // so this makes sure that after a terminating \n no superfluous whitespace is printed before EOF. + // so this makes sure that after a terminating \n no superfluous whitespace is printed before EOF. } @Override @@ -1322,7 +1322,7 @@ public int nextInt() { // done with indenting, so continue with the content int cur = content.nextInt(); - // detect if we have to start indenting + // detect if we have to start indenting if (cur == NEWLINE) { nextIndentation = indent.iterator(); } @@ -1353,17 +1353,17 @@ private IString applyIndentation() { @Override public IString substring(int start, int end) { - return applyIndentation().substring(start,end); + return applyIndentation().substring(start,end); } @Override public int charAt(int index) { - return applyIndentation().charAt(index); + return applyIndentation().charAt(index); } @Override public IString replace(int first, int second, int end, IString repl) { - return applyIndentation().replace(first, second, end, repl); + return applyIndentation().replace(first, second, end, repl); } @Override @@ -1372,7 +1372,7 @@ public void write(Writer w) throws IOException { flattened.write(w); return; } - + Deque indents = new ArrayDeque<>(10); indents.push(indent); wrapped.indentedWrite(w, indents, indentFirstLine); @@ -1386,7 +1386,7 @@ public void indentedWrite(Writer w, Deque whitespace, boolean indentFir flattened.indentedWrite(w, whitespace, indentFirstLine); return; } - + // TODO: this concat on whitespace is worrying for longer files which consist of about 40% of indentation. // for those files this concat is particular quadratic since the strings are short and they // are copied over and over again. @@ -1400,7 +1400,7 @@ public int length() { if (flattened != null) { return flattened.length(); } - + // for every non-empty line an indent would be added to the total number of characters return wrapped.length() + (wrapped.lineCount() - (indentFirstLine?0:1)) * indent.length(); } @@ -1410,7 +1410,7 @@ public int lineCount() { if (flattened != null) { return flattened.lineCount(); } - + return wrapped.lineCount(); } @@ -1419,14 +1419,14 @@ public boolean isNewlineTerminated() { if (flattened != null) { return flattened.isNewlineTerminated(); } - + return wrapped.isNewlineTerminated(); } } /** - * This embedded class is used to fine tune parameters of the string indentation feature. - * + * This embedded class is used to fine tune parameters of the string indentation feature. + * * NB! make sure to run with asserts disabled. */ public static class IndentationBenchmarkTool { @@ -1435,26 +1435,26 @@ public static class IndentationBenchmarkTool { /** * Comparing between lazy and eager implementations of indent, we did not observe - * a significant effect on the differential diagnostics while testing with real - * files as opposed to this (faster) null writer. + * a significant effect on the differential diagnostics while testing with real + * files as opposed to this (faster) null writer. */ private static class NullWriter extends Writer { @Override public void write(char[] cbuf, int off, int len) throws IOException { } - + @Override public void write(String str) throws IOException { } - + @Override public void write(String str, int off, int len) throws IOException { } - + @Override public void write(char[] cbuf) throws IOException { } - + @Override public void write(int c) throws IOException { } - + @Override public void flush() throws IOException { } @@ -1463,14 +1463,14 @@ public void close() throws IOException { } } public static void main(String[] args) throws IOException { - + long lazyTime = 0L, eagerTime = 0L; boolean runLazy = true, runEager =true; warmup(); - + if (runLazy) { System.err.println("Benchmarking lazy implementation... press enter"); System.in.read(); @@ -1484,7 +1484,7 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < 100; i++) { value.write(new NullWriter()); } - + long afterWrite = bean.getCurrentThreadCpuTime(); lazyTime = afterWrite - start; @@ -1500,7 +1500,7 @@ public static void main(String[] args) throws IOException { if (runEager) { System.err.println("Benchmarking eager implementation... press enter"); System.in.read(); - + long start = bean.getCurrentThreadCpuTime(); IString value = buildLargeEagerValue(); @@ -1510,7 +1510,7 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < 100; i++) { value.write(new NullWriter()); } - + long afterWrite = bean.getCurrentThreadCpuTime(); eagerTime = afterWrite - start; @@ -1564,7 +1564,7 @@ private static IString buildLargeEagerValue() { } /** - * Generates 388650000 characters, which is around 400Mb when written to disk in UTF8, and 800Mb in memory. + * Generates 388650000 characters, which is around 400Mb when written to disk in UTF8, and 800Mb in memory. */ private static IString buildLargeLazyValue() { IString ws = vf.string(" "); diff --git a/src/main/java/io/usethesource/vallang/impl/primitive/package-info.java b/src/main/java/io/usethesource/vallang/impl/primitive/package-info.java index 279f07ff6..e534ad755 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/package-info.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/package-info.java @@ -2,16 +2,16 @@ * This contains an abstract IValueFactory implementation, AbstractPrimitiveValueFactory, which offers the * implementation for the atomic data-types of Vallang, to be re-used by factories * which specialize on the implementation of the container types. - * + * *
    - *
  • IBool: see BoolValue
  • + *
  • IBool: see BoolValue
  • *
  • IInteger: see AbstractNumberValue, BigIntegerValue and IntegerValue, ICanBecomeABigInteger
  • *
  • IReal: see AbstractNumberValue, BigDecimalValue
  • *
  • IRational: see AbstractNumberValue, RationalValue
  • *
  • ISourceLocation: see SourceLocationURIValues and SourceLocationValues
  • *
  • IString: see StringValue
  • *
  • IDateTime: see DateTimeValues
  • - * + * *
*/ package io.usethesource.vallang.impl.primitive; \ No newline at end of file diff --git a/src/main/java/io/usethesource/vallang/impl/reference/Constructor.java b/src/main/java/io/usethesource/vallang/impl/reference/Constructor.java index 49d51c5d9..9385af120 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/Constructor.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/Constructor.java @@ -68,7 +68,7 @@ public Type getConstructorType() { } return fType; - } + } public IValue get(String label) { return super.get(fType.getFieldIndex(label)); @@ -111,7 +111,7 @@ else if (getClass() == obj.getClass()) { Constructor other = (Constructor) obj; return fType == other.fType && super.equals(obj); } - + return false; } diff --git a/src/main/java/io/usethesource/vallang/impl/reference/List.java b/src/main/java/io/usethesource/vallang/impl/reference/List.java index b129f9bf8..c42dce876 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/List.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/List.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.impl.reference; @@ -21,59 +21,59 @@ import io.usethesource.vallang.type.Type; /*package*/ class List implements IList { - private final Type type; - private final java.util.List content; - - /*package*/ List(Type elementType, java.util.List content) { - super(); - this.type = TF.listType(elementType); - this.content = content; - } - - @Override - public Type getType() { - return type; - } - - @Override - public Iterator iterator() { - return content.iterator(); - } - - @Override - public int length() { - return content.size(); - } - - @Override - public IValue get(int i) { - return content.get(i); - } - - @Override - public boolean isEmpty() { - return content.isEmpty(); - } - - @Override - public int hashCode() { - return content.hashCode(); - } - - @Override - public boolean equals(@Nullable Object that) { - if (that == null) { - return false; - } - - return defaultEquals(that); - } - - @Override - public String toString() { - return defaultToString(); - } - + private final Type type; + private final java.util.List content; + + /*package*/ List(Type elementType, java.util.List content) { + super(); + this.type = TF.listType(elementType); + this.content = content; + } + + @Override + public Type getType() { + return type; + } + + @Override + public Iterator iterator() { + return content.iterator(); + } + + @Override + public int length() { + return content.size(); + } + + @Override + public IValue get(int i) { + return content.get(i); + } + + @Override + public boolean isEmpty() { + return content.isEmpty(); + } + + @Override + public int hashCode() { + return content.hashCode(); + } + + @Override + public boolean equals(@Nullable Object that) { + if (that == null) { + return false; + } + + return defaultEquals(that); + } + + @Override + public String toString() { + return defaultToString(); + } + @Override public IListWriter writer() { return new ListWriter(); diff --git a/src/main/java/io/usethesource/vallang/impl/reference/ListWriter.java b/src/main/java/io/usethesource/vallang/impl/reference/ListWriter.java index 9a0b38a23..95dc5ea98 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/ListWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/ListWriter.java @@ -48,17 +48,17 @@ listContent = new LinkedList<>(); unique = false; } - + private ListWriter(boolean unique) { this(); this.unique = unique; } - + @Override public IWriter unique() { return new ListWriter(true); } - + @Override public Iterator iterator() { return listContent.iterator(); @@ -72,19 +72,19 @@ private void put(int index, IValue elem) { if (unique && listContent.contains(elem)) { return; } - + eltType = eltType.lub(elem.getType()); listContent.add(index, elem); } public void insert(IValue elem) throws FactTypeUseException { checkMutation(); - + put(0, elem); } @Override - public void insert(IValue[] elems, int start, int length) throws FactTypeUseException{ + public void insert(IValue[] elems, int start, int length) throws FactTypeUseException{ checkMutation(); checkBounds(elems, start, length); @@ -95,19 +95,19 @@ public void insert(IValue[] elems, int start, int length) throws FactTypeUseExce } @Override - public IValue replaceAt(int index, IValue elem) throws FactTypeUseException, IndexOutOfBoundsException { + public IValue replaceAt(int index, IValue elem) throws FactTypeUseException, IndexOutOfBoundsException { checkMutation(); updateType(elem); return listContent.set(index, elem); } @Override - public void insert(IValue... elems) throws FactTypeUseException{ + public void insert(IValue... elems) throws FactTypeUseException{ insert(elems, 0, elems.length); } @Override - public void insertAt(int index, IValue[] elems, int start, int length) throws FactTypeUseException{ + public void insertAt(int index, IValue[] elems, int start, int length) throws FactTypeUseException{ checkMutation(); checkBounds(elems, start, length); @@ -118,7 +118,7 @@ public void insertAt(int index, IValue[] elems, int start, int length) throws Fa } @Override - public void insertAt(int index, IValue... elems) throws FactTypeUseException{ + public void insertAt(int index, IValue... elems) throws FactTypeUseException{ insertAt(index, elems, 0, 0); } @@ -129,7 +129,7 @@ public void append(IValue elem) throws FactTypeUseException{ } @Override - public void append(IValue... elems) throws FactTypeUseException{ + public void append(IValue... elems) throws FactTypeUseException{ checkMutation(); for(IValue elem : elems){ @@ -137,14 +137,14 @@ public void append(IValue... elems) throws FactTypeUseException{ put(listContent.size(), elem); } } - + @Override public void appendTuple(IValue... fields) { append(new Tuple(fields)); } @Override - public void appendAll(Iterable collection) throws FactTypeUseException{ + public void appendAll(Iterable collection) throws FactTypeUseException{ checkMutation(); for(IValue v : collection){ @@ -155,9 +155,9 @@ public void appendAll(Iterable collection) throws FactTypeUseE private void updateType(IValue v) { eltType = eltType.lub(v.getType()); } - + @Override - public IList done() { + public IList done() { if (constructedList == null) { constructedList = new List(eltType, listContent); } @@ -169,15 +169,15 @@ private void checkBounds(IValue[] elems, int start, int length) { if(start < 0) throw new ArrayIndexOutOfBoundsException("start < 0"); if((start + length) > elems.length) throw new ArrayIndexOutOfBoundsException("(start + length) > elems.length"); } - + @Override public IValue get(int i) throws IndexOutOfBoundsException { return listContent.get(i); } - + @Override public int length() { - return listContent.size(); + return listContent.size(); } @Override diff --git a/src/main/java/io/usethesource/vallang/impl/reference/Map.java b/src/main/java/io/usethesource/vallang/impl/reference/Map.java index 4fa848c17..e809dc104 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/Map.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/Map.java @@ -32,68 +32,68 @@ import io.usethesource.vallang.type.Type; /*package*/ class Map implements IMap { - final Type type; - final java.util.Map content; - - /*package*/ Map(Type candidateMapType, java.util.Map content) { - super(); - this.content = content; - this.type = candidateMapType; - } - - @Override - public Type getType() { - return type; - } - - @Override - public int size() { - return content.size(); - } - - @Override - @SuppressWarnings({"contracts.conditional.postcondition"}) - public boolean containsKey(IValue key) { - return content.containsKey(key); - } - - @Override - public IMap removeKey(IValue key) { - IMapWriter w = writer(); - for (Entry cursor :(Iterable>) this::entryIterator) { - if (!cursor.getKey().equals(key)) { - w.put(cursor.getKey(), cursor.getValue()); - } - } - - return w.done(); - } - - @Override - public boolean isEmpty() { - return content.isEmpty(); - } - - @Override - @Pure - public @Nullable IValue get(IValue key) { - return content.get(key); - } - - @Override - public Iterator iterator() { - return content.keySet().iterator(); - } - - @Override - public Iterator valueIterator() { - return content.values().iterator(); - } - - @Override - public Iterator> entryIterator() { - return content.entrySet().iterator(); - } + final Type type; + final java.util.Map content; + + /*package*/ Map(Type candidateMapType, java.util.Map content) { + super(); + this.content = content; + this.type = candidateMapType; + } + + @Override + public Type getType() { + return type; + } + + @Override + public int size() { + return content.size(); + } + + @Override + @SuppressWarnings({"contracts.conditional.postcondition"}) + public boolean containsKey(IValue key) { + return content.containsKey(key); + } + + @Override + public IMap removeKey(IValue key) { + IMapWriter w = writer(); + for (Entry cursor :(Iterable>) this::entryIterator) { + if (!cursor.getKey().equals(key)) { + w.put(cursor.getKey(), cursor.getValue()); + } + } + + return w.done(); + } + + @Override + public boolean isEmpty() { + return content.isEmpty(); + } + + @Override + @Pure + public @Nullable IValue get(IValue key) { + return content.get(key); + } + + @Override + public Iterator iterator() { + return content.keySet().iterator(); + } + + @Override + public Iterator valueIterator() { + return content.values().iterator(); + } + + @Override + public Iterator> entryIterator() { + return content.entrySet().iterator(); + } @Override public Type getElementType() { @@ -115,7 +115,7 @@ public IMapWriter writer() { public IRelation asRelation() { throw new UnsupportedOperationException(); } - + @Override public String toString() { return defaultToString(); @@ -125,15 +125,15 @@ public String toString() { public int hashCode() { return content.hashCode(); } - + @Override public boolean equals(@Nullable Object obj) { - if (obj == null) { - return false; - } + if (obj == null) { + return false; + } return defaultEquals(obj); } - + @Override public Stream stream() { Iterable> it = this::entryIterator; diff --git a/src/main/java/io/usethesource/vallang/impl/reference/MapWriter.java b/src/main/java/io/usethesource/vallang/impl/reference/MapWriter.java index 32fb48d6a..3a0637a32 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/MapWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/MapWriter.java @@ -34,105 +34,105 @@ import io.usethesource.vallang.util.AbstractTypeBag; /*package*/ class MapWriter implements IMapWriter { - private AbstractTypeBag keyTypeBag; + private AbstractTypeBag keyTypeBag; private AbstractTypeBag valTypeBag; - private final java.util.Map mapContent; - private @MonotonicNonNull Map constructedMap; + private final java.util.Map mapContent; + private @MonotonicNonNull Map constructedMap; - /*package*/ MapWriter() { - super(); - - keyTypeBag = AbstractTypeBag.of(); + /*package*/ MapWriter() { + super(); + + keyTypeBag = AbstractTypeBag.of(); valTypeBag = AbstractTypeBag.of(); - - mapContent = new java.util.HashMap<>(); - } - - @Override - public Iterator iterator() { - return mapContent.keySet().iterator(); - } - - @Override - public @Nullable IValue get(IValue key) { - return mapContent.get(key); - } - - @Override - public void insertTuple(IValue... fields) { - if (fields.length != 2) { - throw new IllegalArgumentException("can only insert tuples of arity 2 into a map"); - } - - put(fields[0], fields[1]); - } - - private void checkMutation() { - if (constructedMap != null) { - throw new UnsupportedOperationException("Mutation of a finalized list is not supported."); - } - } - - @Override - public void putAll(IMap map) throws FactTypeUseException{ - checkMutation(); - - for (Entry entry : (Iterable>) () -> map.entryIterator()) { - updateTypes(entry.getKey(), entry.getValue()); - mapContent.put(entry.getKey(), entry.getValue()); - } - } - - private void updateTypes(IValue key, IValue value) { + + mapContent = new java.util.HashMap<>(); + } + + @Override + public Iterator iterator() { + return mapContent.keySet().iterator(); + } + + @Override + public @Nullable IValue get(IValue key) { + return mapContent.get(key); + } + + @Override + public void insertTuple(IValue... fields) { + if (fields.length != 2) { + throw new IllegalArgumentException("can only insert tuples of arity 2 into a map"); + } + + put(fields[0], fields[1]); + } + + private void checkMutation() { + if (constructedMap != null) { + throw new UnsupportedOperationException("Mutation of a finalized list is not supported."); + } + } + + @Override + public void putAll(IMap map) throws FactTypeUseException{ + checkMutation(); + + for (Entry entry : (Iterable>) () -> map.entryIterator()) { + updateTypes(entry.getKey(), entry.getValue()); + mapContent.put(entry.getKey(), entry.getValue()); + } + } + + private void updateTypes(IValue key, IValue value) { if (mapContent.containsKey(key)) { - // key will be overwritten, so the corresponding value must be subtracted from the type bag too - valTypeBag = valTypeBag.decrease(mapContent.get(key).getType()); - valTypeBag = valTypeBag.increase(value.getType()); - } - else { - keyTypeBag = keyTypeBag.increase(key.getType()); - valTypeBag = valTypeBag.increase(value.getType()); - } - } - - @Override - public void putAll(java.util.Map map) throws FactTypeUseException{ - checkMutation(); - for(Entry entry : map.entrySet()){ - IValue value = entry.getValue(); - updateTypes(entry.getKey(), value); - mapContent.put(entry.getKey(), value); - } - } - - @Override - public void put(IValue key, IValue value) throws FactTypeUseException{ - checkMutation(); - updateTypes(key, value); - mapContent.put(key, value); - } - - @Override - public void insert(IValue... value) throws FactTypeUseException { - for (IValue tuple : value) { - ITuple t = (ITuple) tuple; - IValue key = t.get(0); - IValue value2 = t.get(1); - updateTypes(key,value2); - put(key, value2); - } - } - - @Override - public IMap done(){ - if (constructedMap == null) { - constructedMap = new Map(IMap.TF.mapType(keyTypeBag.lub(), valTypeBag.lub()), mapContent); - } - - return constructedMap; - } - - @Override + // key will be overwritten, so the corresponding value must be subtracted from the type bag too + valTypeBag = valTypeBag.decrease(mapContent.get(key).getType()); + valTypeBag = valTypeBag.increase(value.getType()); + } + else { + keyTypeBag = keyTypeBag.increase(key.getType()); + valTypeBag = valTypeBag.increase(value.getType()); + } + } + + @Override + public void putAll(java.util.Map map) throws FactTypeUseException{ + checkMutation(); + for(Entry entry : map.entrySet()){ + IValue value = entry.getValue(); + updateTypes(entry.getKey(), value); + mapContent.put(entry.getKey(), value); + } + } + + @Override + public void put(IValue key, IValue value) throws FactTypeUseException{ + checkMutation(); + updateTypes(key, value); + mapContent.put(key, value); + } + + @Override + public void insert(IValue... value) throws FactTypeUseException { + for (IValue tuple : value) { + ITuple t = (ITuple) tuple; + IValue key = t.get(0); + IValue value2 = t.get(1); + updateTypes(key,value2); + put(key, value2); + } + } + + @Override + public IMap done(){ + if (constructedMap == null) { + constructedMap = new Map(IMap.TF.mapType(keyTypeBag.lub(), valTypeBag.lub()), mapContent); + } + + return constructedMap; + } + + @Override public Supplier> supplier() { return () -> ValueFactory.getInstance().mapWriter(); } diff --git a/src/main/java/io/usethesource/vallang/impl/reference/Set.java b/src/main/java/io/usethesource/vallang/impl/reference/Set.java index 24953ce53..7f628765a 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/Set.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/Set.java @@ -27,60 +27,60 @@ import io.usethesource.vallang.type.Type; /*package*/ class Set implements ISet { - final Type type; - final java.util.Set content; + final Type type; + final java.util.Set content; - /*package*/ Set(Type elementType, java.util.Set content) { - super(); - this.type = TF.setType(elementType); - this.content = content; - } + /*package*/ Set(Type elementType, java.util.Set content) { + super(); + this.type = TF.setType(elementType); + this.content = content; + } - @Override - public Type getType() { - return type; - } - - @Override - public boolean contains(IValue e) { - return content.contains(e); - } - - @Override - public ISetWriter writer() { - return ValueFactory.getInstance().setWriter(); - } - - @Override - public boolean isEmpty() { - return content.isEmpty(); - } + @Override + public Type getType() { + return type; + } - @Override - public int size() { - return content.size(); - } + @Override + public boolean contains(IValue e) { + return content.contains(e); + } - @Override - public int hashCode() { - return content.hashCode(); - } + @Override + public ISetWriter writer() { + return ValueFactory.getInstance().setWriter(); + } - @Override - public boolean equals(@Nullable Object other) { - if (other == null) { - return false; - } - return defaultEquals(other); - } - - @Override - public String toString() { - return defaultToString(); - } + @Override + public boolean isEmpty() { + return content.isEmpty(); + } - @Override - public Iterator iterator() { - return content.iterator(); - } + @Override + public int size() { + return content.size(); + } + + @Override + public int hashCode() { + return content.hashCode(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (other == null) { + return false; + } + return defaultEquals(other); + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public Iterator iterator() { + return content.iterator(); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/reference/SetWriter.java b/src/main/java/io/usethesource/vallang/impl/reference/SetWriter.java index 33e3b6465..9c95b7d4b 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/SetWriter.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/SetWriter.java @@ -46,7 +46,7 @@ public Iterator iterator() { return setContent.iterator(); } - + private void put(IValue elem) { updateType(elem); setContent.add(elem); @@ -60,9 +60,9 @@ private void updateType(IValue elem) { public void insertTuple(IValue... fields) { insert(ValueFactory.getInstance().tuple(fields)); } - + @Override - public void insert(IValue... elems) throws FactTypeUseException { + public void insert(IValue... elems) throws FactTypeUseException { checkMutation(); for (IValue elem : elems) { @@ -71,7 +71,7 @@ public void insert(IValue... elems) throws FactTypeUseException { } @Override - public void insertAll(Iterable collection) throws FactTypeUseException { + public void insertAll(Iterable collection) throws FactTypeUseException { checkMutation(); for (IValue v : collection) { @@ -80,7 +80,7 @@ public void insertAll(Iterable collection) throws FactTypeUseE } @Override - public ISet done() { + public ISet done() { if (constructedSet == null) { constructedSet = new Set(eltType, setContent); } @@ -93,7 +93,7 @@ private void checkMutation() { throw new UnsupportedOperationException("Mutation of a finalized set is not supported."); } } - + @Override public Supplier> supplier() { return () -> ValueFactory.getInstance().setWriter(); diff --git a/src/main/java/io/usethesource/vallang/impl/reference/Tuple.java b/src/main/java/io/usethesource/vallang/impl/reference/Tuple.java index 583c796ec..6b065d27d 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/Tuple.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/Tuple.java @@ -23,157 +23,157 @@ import io.usethesource.vallang.type.TypeFactory; /*package*/ class Tuple implements ITuple { - protected final Type fType; - protected final IValue[] fElements; - - /*package*/ Tuple(IValue... elements) { - super(); - this.fType = TypeFactory.getInstance().tupleType(elements); - this.fElements = elements; - } - - private Tuple(Tuple other, int i, IValue elem) { - this.fType = other.getType(); - fElements = other.fElements.clone(); - fElements[i] = elem; - } - - @Override - public Type getType() { - return fType; - } - - @Override - public Iterator iterator() { - return new Iterator() { - private int count = 0; - - @Override - public boolean hasNext() { - return count < arity(); - } - - @Override - public IValue next() { - return get(count++); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("Can not remove elements from a tuple"); - } - }; - } - - @Override - public int hashCode() { - int hash = 0; - - for (int i = 0; i < fElements.length; i++) { - hash = (hash << 1) ^ (hash >> 1) ^ fElements[i].hashCode(); - } - return hash; - } - - @Override - public String toString() { - return defaultToString(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) { - return true; - } else if (o == null) { - return false; - } else if (getClass() == o.getClass()) { - Tuple peer = (Tuple) o; - - if (fType != peer.fType) { - return false; - } - - int arity = arity(); - if (arity != peer.arity()) { - return false; - } - for (int i = 0; i < arity; i++) { - if (!get(i).equals(peer.get(i))) { - return false; - } - } - return true; - } - return false; - } - - @Override - public IValue get(int i) throws IndexOutOfBoundsException { - try { - return fElements[i]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new IndexOutOfBoundsException("Tuple index " + i + " is larger than tuple width " + arity()); - } - } - - @Override - public IValue get(String label) throws FactTypeUseException { - return fElements[fType.getFieldIndex(label)]; - } - - @Override - public ITuple set(int i, IValue arg) throws IndexOutOfBoundsException { - return new Tuple(this, i, arg); - } - - @Override - public ITuple set(String label, IValue arg) throws FactTypeUseException { - int i = fType.getFieldIndex(label); - return new Tuple(this, i, arg); - } - - @Override - public int arity() { - return fElements.length; - } - - @Override - public IValue select(int... fields) throws IndexOutOfBoundsException { - Type type = fType.select(fields); - - if (type.isFixedWidth()) { - return doSelect(type, fields); - } - - return get(fields[0]); - } - - @Override - public IValue selectByFieldNames(String... fields) throws FactTypeUseException { - Type type = fType.select(fields); - - if (type.isFixedWidth()) { - int[] indexes = new int[fields.length]; - int i = 0; - for (String name : fields) { - indexes[i] = type.getFieldIndex(name); - } - - return doSelect(type, indexes); - } - - return get(fields[0]); - } - - private IValue doSelect(Type type, int... fields) throws IndexOutOfBoundsException { - if (fields.length == 1) - return get(fields[0]); - IValue[] elems = new IValue[fields.length]; - Type[] elemTypes = new Type[fields.length]; - for (int i = 0; i < fields.length; i++) { - elems[i] = get(fields[i]); - elemTypes[i] = elems[i].getType(); - } - return new Tuple(elems); - } + protected final Type fType; + protected final IValue[] fElements; + + /*package*/ Tuple(IValue... elements) { + super(); + this.fType = TypeFactory.getInstance().tupleType(elements); + this.fElements = elements; + } + + private Tuple(Tuple other, int i, IValue elem) { + this.fType = other.getType(); + fElements = other.fElements.clone(); + fElements[i] = elem; + } + + @Override + public Type getType() { + return fType; + } + + @Override + public Iterator iterator() { + return new Iterator() { + private int count = 0; + + @Override + public boolean hasNext() { + return count < arity(); + } + + @Override + public IValue next() { + return get(count++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Can not remove elements from a tuple"); + } + }; + } + + @Override + public int hashCode() { + int hash = 0; + + for (int i = 0; i < fElements.length; i++) { + hash = (hash << 1) ^ (hash >> 1) ^ fElements[i].hashCode(); + } + return hash; + } + + @Override + public String toString() { + return defaultToString(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } else if (o == null) { + return false; + } else if (getClass() == o.getClass()) { + Tuple peer = (Tuple) o; + + if (fType != peer.fType) { + return false; + } + + int arity = arity(); + if (arity != peer.arity()) { + return false; + } + for (int i = 0; i < arity; i++) { + if (!get(i).equals(peer.get(i))) { + return false; + } + } + return true; + } + return false; + } + + @Override + public IValue get(int i) throws IndexOutOfBoundsException { + try { + return fElements[i]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("Tuple index " + i + " is larger than tuple width " + arity()); + } + } + + @Override + public IValue get(String label) throws FactTypeUseException { + return fElements[fType.getFieldIndex(label)]; + } + + @Override + public ITuple set(int i, IValue arg) throws IndexOutOfBoundsException { + return new Tuple(this, i, arg); + } + + @Override + public ITuple set(String label, IValue arg) throws FactTypeUseException { + int i = fType.getFieldIndex(label); + return new Tuple(this, i, arg); + } + + @Override + public int arity() { + return fElements.length; + } + + @Override + public IValue select(int... fields) throws IndexOutOfBoundsException { + Type type = fType.select(fields); + + if (type.isFixedWidth()) { + return doSelect(type, fields); + } + + return get(fields[0]); + } + + @Override + public IValue selectByFieldNames(String... fields) throws FactTypeUseException { + Type type = fType.select(fields); + + if (type.isFixedWidth()) { + int[] indexes = new int[fields.length]; + int i = 0; + for (String name : fields) { + indexes[i] = type.getFieldIndex(name); + } + + return doSelect(type, indexes); + } + + return get(fields[0]); + } + + private IValue doSelect(Type type, int... fields) throws IndexOutOfBoundsException { + if (fields.length == 1) + return get(fields[0]); + IValue[] elems = new IValue[fields.length]; + Type[] elemTypes = new Type[fields.length]; + for (int i = 0; i < fields.length; i++) { + elems[i] = get(fields[i]); + elemTypes[i] = elems[i].getType(); + } + return new Tuple(elems); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/reference/ValueFactory.java b/src/main/java/io/usethesource/vallang/impl/reference/ValueFactory.java index 77766275a..fdf8e8fb6 100644 --- a/src/main/java/io/usethesource/vallang/impl/reference/ValueFactory.java +++ b/src/main/java/io/usethesource/vallang/impl/reference/ValueFactory.java @@ -34,124 +34,124 @@ * not necessarily very efficient manner. */ public class ValueFactory extends AbstractPrimitiveValueFactory { - private static final ValueFactory sInstance = new ValueFactory(); - public static ValueFactory getInstance() { - return sInstance; - } - - protected ValueFactory() { - super(); - } - - protected static void checkNull(Object... args) { - for (Object a : args) { - Objects.requireNonNull(a); - } - } - - protected static void checkNull(java.util.Map args) { - for (java.util.Map.Entry entry : args.entrySet()) { - if (entry == null || entry.getKey() == null || entry.getValue() == null) { - throw new NullPointerException(); - } - } - } - - @Override - public ISetWriter setWriter() { - return new SetWriter(); - } - - @Override - public ISet set(IValue... elems) throws FactTypeUseException { - checkNull((Object[]) elems); - - ISetWriter sw = setWriter(); - sw.insert(elems); - return sw.done(); - } - - @Override - public IListWriter listWriter() { - return new ListWriter(); - } - - @Override - public IList list(IValue... rest) { - checkNull((Object[]) rest); - IListWriter lw = listWriter(); - lw.append(rest); - return lw.done(); - } - - @Override - public ITuple tuple() { - return new Tuple(new IValue[0]); - } - - @Override - public ITuple tuple(IValue... args) { - checkNull((Object[]) args); - - return new Tuple(args.clone()); - } - - @Override - public INode node(String name) { - checkNull(name); - return new Node(name); - } - - @Override - public INode node(String name, IValue... children) { - checkNull(name); - checkNull((Object[]) children); - return new Node(name, children); - } - - @Override - public INode node(String name, IValue[] children, java.util.Map keyArgValues) - throws FactTypeUseException { - checkNull(name); - checkNull((Object[]) children); -// checkNull(keyArgValues); // fails; are null values allowed? - - return new Node(name, children.clone()).asWithKeywordParameters().setParameters(keyArgValues); - } - - @Override - public IConstructor constructor(Type constructorType, IValue... children) { - checkNull(constructorType); - checkNull((Object[]) children); - assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, children); - return new Constructor(constructorType, children); - } - - @Override - public IConstructor constructor(Type constructorType, IValue[] children, java.util.Map kwParams) { - checkNull(constructorType); - checkNull(kwParams); - checkNull((Object[]) children); - assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, children); - - return new Constructor(constructorType, children).asWithKeywordParameters().setParameters(kwParams); - } - - @Override - public IConstructor constructor(Type constructorType) { - checkNull(constructorType); - assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, new IValue[0]); - return new Constructor(constructorType); - } - - @Override - public IMapWriter mapWriter() { - return new MapWriter(); - } - - @Override - public String toString() { - return "VALLANG_REFERENCE_FACTORY"; - } - + private static final ValueFactory sInstance = new ValueFactory(); + public static ValueFactory getInstance() { + return sInstance; + } + + protected ValueFactory() { + super(); + } + + protected static void checkNull(Object... args) { + for (Object a : args) { + Objects.requireNonNull(a); + } + } + + protected static void checkNull(java.util.Map args) { + for (java.util.Map.Entry entry : args.entrySet()) { + if (entry == null || entry.getKey() == null || entry.getValue() == null) { + throw new NullPointerException(); + } + } + } + + @Override + public ISetWriter setWriter() { + return new SetWriter(); + } + + @Override + public ISet set(IValue... elems) throws FactTypeUseException { + checkNull((Object[]) elems); + + ISetWriter sw = setWriter(); + sw.insert(elems); + return sw.done(); + } + + @Override + public IListWriter listWriter() { + return new ListWriter(); + } + + @Override + public IList list(IValue... rest) { + checkNull((Object[]) rest); + IListWriter lw = listWriter(); + lw.append(rest); + return lw.done(); + } + + @Override + public ITuple tuple() { + return new Tuple(new IValue[0]); + } + + @Override + public ITuple tuple(IValue... args) { + checkNull((Object[]) args); + + return new Tuple(args.clone()); + } + + @Override + public INode node(String name) { + checkNull(name); + return new Node(name); + } + + @Override + public INode node(String name, IValue... children) { + checkNull(name); + checkNull((Object[]) children); + return new Node(name, children); + } + + @Override + public INode node(String name, IValue[] children, java.util.Map keyArgValues) + throws FactTypeUseException { + checkNull(name); + checkNull((Object[]) children); +// checkNull(keyArgValues); // fails; are null values allowed? + + return new Node(name, children.clone()).asWithKeywordParameters().setParameters(keyArgValues); + } + + @Override + public IConstructor constructor(Type constructorType, IValue... children) { + checkNull(constructorType); + checkNull((Object[]) children); + assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, children); + return new Constructor(constructorType, children); + } + + @Override + public IConstructor constructor(Type constructorType, IValue[] children, java.util.Map kwParams) { + checkNull(constructorType); + checkNull(kwParams); + checkNull((Object[]) children); + assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, children); + + return new Constructor(constructorType, children).asWithKeywordParameters().setParameters(kwParams); + } + + @Override + public IConstructor constructor(Type constructorType) { + checkNull(constructorType); + assert IConstructor.assertTypeCorrectConstructorApplication(constructorType, new IValue[0]); + return new Constructor(constructorType); + } + + @Override + public IMapWriter mapWriter() { + return new MapWriter(); + } + + @Override + public String toString() { + return "VALLANG_REFERENCE_FACTORY"; + } + } diff --git a/src/main/java/io/usethesource/vallang/impl/util/BigDecimalCalculations.java b/src/main/java/io/usethesource/vallang/impl/util/BigDecimalCalculations.java index 9316bcece..b43459415 100644 --- a/src/main/java/io/usethesource/vallang/impl/util/BigDecimalCalculations.java +++ b/src/main/java/io/usethesource/vallang/impl/util/BigDecimalCalculations.java @@ -19,87 +19,85 @@ public class BigDecimalCalculations { - /** - * pi in 1000 decimals places - */ - public static final BigDecimal PI = new BigDecimal( - "3.141592653589793238462643383279502884197169399375105820974944592307" + - "81640628620899862803482534211706798214808651328230664709384460955058" + - "22317253594081284811174502841027019385211055596446229489549303819644" + - "28810975665933446128475648233786783165271201909145648566923460348610" + - "45432664821339360726024914127372458700660631558817488152092096282925" + - "40917153643678925903600113305305488204665213841469519415116094330572" + - "70365759591953092186117381932611793105118548074462379962749567351885" + - "75272489122793818301194912983367336244065664308602139494639522473719" + - "07021798609437027705392171762931767523846748184676694051320005681271" + - "45263560827785771342757789609173637178721468440901224953430146549585" + - "37105079227968925892354201995611212902196086403441815981362977477130" + - "99605187072113499999983729780499510597317328160963185950244594553469" + - "08302642522308253344685035261931188171010003137838752886587533208381" + - "42061717766914730359825349042875546873115956286388235378759375195778" + - "18577805321712268066130019278766111959092164201988") ; - + /** + * pi in 1000 decimals places + */ + public static final BigDecimal PI = new BigDecimal( + "3.141592653589793238462643383279502884197169399375105820974944592307" + + "81640628620899862803482534211706798214808651328230664709384460955058" + + "22317253594081284811174502841027019385211055596446229489549303819644" + + "28810975665933446128475648233786783165271201909145648566923460348610" + + "45432664821339360726024914127372458700660631558817488152092096282925" + + "40917153643678925903600113305305488204665213841469519415116094330572" + + "70365759591953092186117381932611793105118548074462379962749567351885" + + "75272489122793818301194912983367336244065664308602139494639522473719" + + "07021798609437027705392171762931767523846748184676694051320005681271" + + "45263560827785771342757789609173637178721468440901224953430146549585" + + "37105079227968925892354201995611212902196086403441815981362977477130" + + "99605187072113499999983729780499510597317328160963185950244594553469" + + "08302642522308253344685035261931188171010003137838752886587533208381" + + "42061717766914730359825349042875546873115956286388235378759375195778" + + "18577805321712268066130019278766111959092164201988") ; + public static final BigDecimal halfPI = PI.divide(new BigDecimal(2)); public static final BigDecimal twoPI = PI.multiply(new BigDecimal(2)); /** - * e in 1000 decimals places - */ + * e in 1000 decimals places + */ public static final BigDecimal E = new BigDecimal( - "2.718281828459045235360287471352662497757247093699959574966967627724" + - "07663035354759457138217852516642742746639193200305992181741359662904" + - "35729003342952605956307381323286279434907632338298807531952510190115" + - "73834187930702154089149934884167509244761460668082264800168477411853" + - "74234544243710753907774499206955170276183860626133138458300075204493" + - "38265602976067371132007093287091274437470472306969772093101416928368" + - "19025515108657463772111252389784425056953696770785449969967946864454" + - "90598793163688923009879312773617821542499922957635148220826989519366" + - "80331825288693984964651058209392398294887933203625094431173012381970" + - "68416140397019837679320683282376464804295311802328782509819455815301" + - "75671736133206981125099618188159304169035159888851934580727386673858" + - "94228792284998920868058257492796104841984443634632449684875602336248" + - "27041978623209002160990235304369941849146314093431738143640546253152" + - "09618369088870701676839642437814059271456354906130310720851038375051" + - "011574770417189861068739696552126715468895703503540"); - + "2.718281828459045235360287471352662497757247093699959574966967627724" + + "07663035354759457138217852516642742746639193200305992181741359662904" + + "35729003342952605956307381323286279434907632338298807531952510190115" + + "73834187930702154089149934884167509244761460668082264800168477411853" + + "74234544243710753907774499206955170276183860626133138458300075204493" + + "38265602976067371132007093287091274437470472306969772093101416928368" + + "19025515108657463772111252389784425056953696770785449969967946864454" + + "90598793163688923009879312773617821542499922957635148220826989519366" + + "80331825288693984964651058209392398294887933203625094431173012381970" + + "68416140397019837679320683282376464804295311802328782509819455815301" + + "75671736133206981125099618188159304169035159888851934580727386673858" + + "94228792284998920868058257492796104841984443634632449684875602336248" + + "27041978623209002160990235304369941849146314093431738143640546253152" + + "09618369088870701676839642437814059271456354906130310720851038375051" + + "011574770417189861068739696552126715468895703503540"); + /** * above 500 (/below -500) the approximation slows down more than the normalisation costs. * So we normalize first */ private static final BigDecimal sincosNormalizePoint = BigDecimal.valueOf(500); - + private static BigInteger maxBigDecimalPowExp = BigInteger.valueOf(999999999); // maximum exponent for BigDecimal.pow - - - /** + + + /** * Compute the sine of x to a given scale - * @param x + * @param x * the value of x - * @param + * @param * scale the desired scale of the result * @return the result value */ - public static BigDecimal sin(BigDecimal x, int scale) - { + public static BigDecimal sin(BigDecimal x, int scale) { if (x.signum() == 0) - return BigDecimal.ZERO; + return BigDecimal.ZERO; if (x.abs().compareTo(sincosNormalizePoint) >= 0 ) { - x = x.remainder(twoPI, new MathContext(scale + 1)); + x = x.remainder(twoPI, new MathContext(scale + 1)); } if (x.signum() == -1) return sinTaylor(x.negate(), scale).negate(); - else - return sinTaylor(x, scale); + else + return sinTaylor(x, scale); } - - + + private static BigDecimal calculateConvergenceTolerance(int scale) { - return BigDecimal.valueOf(5).movePointLeft(scale + 1); + return BigDecimal.valueOf(5).movePointLeft(scale + 1); } - - // code based on arctanTaylor by Ronald Mak - private static BigDecimal sinTaylor(BigDecimal x, int scale) - { + + // code based on arctanTaylor by Ronald Mak + private static BigDecimal sinTaylor(BigDecimal x, int scale) { int sp1 = scale + 1; int i = 3; boolean addFlag = false; @@ -120,7 +118,7 @@ private static BigDecimal sinTaylor(BigDecimal x, int scale) term = power.divide(fac, sp1,RoundingMode.HALF_EVEN); // result = result +- (x^i)/(i!) result = addFlag ? result.add(term) : result.subtract(term); - + // state for next round i += 2; fac = fac.multiply(BigDecimal.valueOf(i - 1)).multiply(BigDecimal.valueOf(i)); @@ -130,30 +128,28 @@ private static BigDecimal sinTaylor(BigDecimal x, int scale) return result; } - + /** * Compute the cosine of x to a given scale * @param x the value of x * @param scale the desired scale of the result * @return the result value */ - public static BigDecimal cos(BigDecimal x, int scale) - { + public static BigDecimal cos(BigDecimal x, int scale) { if (x.signum() == 0) - return BigDecimal.ONE; + return BigDecimal.ONE; if (x.abs().compareTo(sincosNormalizePoint) >= 0 ) { - x = x.remainder(twoPI, new MathContext(scale + 1)); + x = x.remainder(twoPI, new MathContext(scale + 1)); } if (x.signum() == -1) return cosTaylor(x.negate(), scale); - else - return cosTaylor(x, scale); + else + return cosTaylor(x, scale); } - - // code based on arctanTaylor by Ronald Mak + + // code based on arctanTaylor by Ronald Mak // same as sin but without the x starting point and +1 in faculty - private static BigDecimal cosTaylor(BigDecimal x, int scale) - { + private static BigDecimal cosTaylor(BigDecimal x, int scale) { int sp1 = scale + 1; int i = 2; boolean addFlag = false; @@ -174,7 +170,7 @@ private static BigDecimal cosTaylor(BigDecimal x, int scale) term = power.divide(fac, sp1, RoundingMode.HALF_EVEN); // result = result +- (x^i)/(i!) result = addFlag ? result.add(term) : result.subtract(term); - + // prepare state for next loop i += 2; fac = fac.multiply(BigDecimal.valueOf(i -1)).multiply(BigDecimal.valueOf(i)); @@ -183,357 +179,357 @@ private static BigDecimal cosTaylor(BigDecimal x, int scale) } while (term.compareTo(tolerance) > 0); return result; } - - - /** - * Compute the tangent of x to a given scale, |x| < pi/2 - * - * @param x - * the value of x - * @param scale - * the desired scale of the result - * @return the result value - */ - public static BigDecimal tan(BigDecimal x, int scale) { - if (x.signum() == 0) - return BigDecimal.ZERO; - if (x.abs().compareTo(halfPI) > 0) - throw new ArithmeticException("x should be between -(pi/2) and (pi/2)"); - // easiest implementation of tan (no need for Bernoulli numbers) but this is slower than the other 2 - return sin(x, scale + 1).divide(cos(x, scale + 1), scale, RoundingMode.HALF_UP); - } - - - /** - * Compute x^exponent to a given scale. - * - * @param x - * the value x - * @param exponent - * the exponent value - * @param scale - * the desired scale of the result - * @return the result value - */ - private static BigDecimal intPower(BigDecimal x, BigInteger exponent, int scale) { - boolean negativeExponent = exponent.signum() == -1; - - if (negativeExponent) { - exponent = exponent.negate(); - } - - if (exponent.equals(BigInteger.ZERO)) { - return BigDecimal.ONE.setScale(scale); - } - - MathContext mc = new MathContext(scale, RoundingMode.HALF_EVEN); - - if (exponent.equals(BigInteger.ONE)) { - if (negativeExponent) { - return BigDecimal.ONE.divide(x, mc); - } - return x.setScale(scale, RoundingMode.HALF_EVEN); - } - - BigDecimal result = BigDecimal.valueOf(1); - - if (exponent.compareTo(maxBigDecimalPowExp) >= 0) { - BigDecimal maxExpPow = x.pow(maxBigDecimalPowExp.intValue(), mc); - while (exponent.compareTo(maxBigDecimalPowExp) >= 0) { - result = result.multiply(maxExpPow); - exponent = exponent.subtract(maxBigDecimalPowExp); - } - } - - result = result.multiply(x.pow(exponent.intValue(), mc)); - - if (negativeExponent) { - return BigDecimal.ONE.divide(result, mc); - } - - return result.setScale(scale, RoundingMode.HALF_EVEN); - } - - /** - * The functions below this line are based on the Numerical implementations of - * Java Number Cruncher: The Java Programmer's Guide - * to Numerical Computing - * by Ronald Mak - * - * He has shared the code in the book at the following page: - * http://authors.phptr.com/mak/downloads.html - * - * And has put the source in the public domain: - * "I wrote all these programs strictly as - * illustrative examples for my book. - * You're free to use the source code any - * way you like, but bear in mind that this is - * NOT fully tested, commercial-quality code. - * Neither Prentice Hall PTR nor I can be - * responsible for anything bad that may happen - * if you use these programs." - * - * The only changes were the removal of call to Thread.yield(), switching to - * and formatting improvements - */ - - /** - * Compute the integral root of x to a given scale, x >= 0. Use Newton's - * algorithm. - * - * @param x - * the value of x - * @param index - * the integral root value - * @param scale - * the desired scale of the result - * @return the result value - */ - public static BigDecimal intRoot(BigDecimal x, BigInteger index, int scale) { - // Check that x >= 0. - if (x.signum() < 0) { - throw new ArithmeticException("x < 0"); - } - - int sp1 = scale + 1; - BigDecimal n = x; - BigDecimal i = new BigDecimal(index); - BigDecimal im1 = i.subtract(BigDecimal.ONE); - BigDecimal tolerance = BigDecimal.valueOf(5).movePointLeft(sp1); - BigDecimal xPrev; - BigInteger indexm1 = index.subtract(BigInteger.ONE); - - // The initial approximation is x/index. - x = x.divide(i, scale, RoundingMode.HALF_EVEN); - - // Loop until the approximations converge - // (two successive approximations are equal after rounding). - do { - // x^(index-1) - BigDecimal xToIm1 = intPower(x, indexm1, sp1 + 1); - // x^index - BigDecimal xToI = x.multiply(xToIm1); - // n + (index-1)*(x^index) - BigDecimal numerator = n.add(im1.multiply(xToI)); - // (index*(x^(index-1)) - BigDecimal denominator = i.multiply(xToIm1); - // x = (n + (index-1)*(x^index)) / (index*(x^(index-1))) - xPrev = x; - if (denominator.compareTo(BigDecimal.ZERO) == 0) { - x = BigDecimal.ZERO.setScale(sp1); - } - else { - x = numerator.divide(denominator, sp1, RoundingMode.DOWN); - } - - } while (x.subtract(xPrev).abs().compareTo(tolerance) > 0); - - return x.setScale(scale, RoundingMode.HALF_EVEN); - } - - /** - * Compute e^x to a given scale. Break x into its whole and fraction parts - * and compute (e^(1 + fraction/whole))^whole using Taylor's formula. - * - * @param x - * the value of x - * @param scale - * the desired scale of the result - * @return the result value - */ - public static BigDecimal exp(BigDecimal x, int scale) { - // e^0 = 1 - if (x.signum() == 0) { - return BigDecimal.valueOf(1); - } - - boolean isNegative = x.signum() == -1; - - if (isNegative) { - x = x.negate(); - } - - // Compute the whole part of x. - BigDecimal xWhole = x.setScale(0, RoundingMode.DOWN); - - BigDecimal result; - - // If there isn't a whole part, compute and return e^x. - if (xWhole.signum() == 0) { - result = expTaylor(x, scale); - } - else { - // Compute the fraction part of x. - BigDecimal xFraction = x.subtract(xWhole); - - // z = 1 + fraction/whole - BigDecimal z = BigDecimal.valueOf(1).add( - xFraction.divide(xWhole, scale, RoundingMode.HALF_EVEN)); - - // t = e^z - BigDecimal t = expTaylor(z, scale); - - result = intPower(t, xWhole.toBigInteger(), scale); - } - - if (isNegative) { - return BigDecimal.ONE.divide(result, new MathContext(scale, RoundingMode.HALF_EVEN)); - } - - return result; - } - - /** - * Compute e^x to a given scale by the Taylor series. - * - * @param x - * the value of x - * @param scale - * the desired scale of the result - * @return the result value - */ - private static BigDecimal expTaylor(BigDecimal x, int scale) { - BigDecimal factorial = BigDecimal.valueOf(1); - BigDecimal xPower = x; - BigDecimal sumPrev; - - // 1 + x - BigDecimal sum = x.add(BigDecimal.valueOf(1)); - // Loop until the sums converge - // (two successive sums are equal after rounding). - int i = 2; - do { - // x^i - xPower = xPower.multiply(x).setScale(scale, RoundingMode.HALF_EVEN); - // i! - factorial = factorial.multiply(BigDecimal.valueOf(i)); - // x^i/i! - BigDecimal term = xPower.divide(factorial, scale, RoundingMode.HALF_EVEN); - // sum = sum + x^i/i! - sumPrev = sum; - sum = sum.add(term); - - ++i; - } while (sum.compareTo(sumPrev) != 0); - - return sum; - } - - /** - * Compute the natural logarithm of x to a given scale, x > 0. - * @param x - * the value of x - * @param scale - * the desired scale of the result - * @return - * the natural logarithm of x - */ - public static BigDecimal ln(BigDecimal x, int scale) { - // Check that x > 0. - if (x.signum() <= 0) { - throw new ArithmeticException("x <= 0"); - } - // The number of digits to the left of the decimal point. - int magnitude = x.toString().length() - x.scale() - 1; - if (magnitude < 3) { - return lnNewton(x, scale); - } - // Compute magnitude*ln(x^(1/magnitude)). - else { - // x^(1/magnitude) - BigDecimal root = intRoot(x, BigInteger.valueOf(magnitude), scale); - // ln(x^(1/magnitude)) - BigDecimal lnRoot = lnNewton(root, scale); - // magnitude*ln(x^(1/magnitude)) - return BigDecimal.valueOf(magnitude).multiply(lnRoot) - .setScale(scale, RoundingMode.HALF_EVEN); - } - } - - /** - * Compute the natural logarithm of x to a given scale, x > 0. Use Newton's - * algorithm. - */ - private static BigDecimal lnNewton(BigDecimal x, int scale) { - int sp1 = scale + 1; - BigDecimal n = x; - BigDecimal term; - - // Convergence tolerance = 5*(10^-(scale+1)) - BigDecimal tolerance = BigDecimal.valueOf(5).movePointLeft(sp1); - // Loop until the approximations converge - // (two successive approximations are within the tolerance). - do { - // e^x - BigDecimal eToX = exp(x, sp1); - // (e^x - n)/e^x - if (eToX.compareTo(BigDecimal.ZERO) == 0) { - break; - } - term = eToX.subtract(n).divide(eToX, sp1, RoundingMode.DOWN); - // x - (e^x - n)/e^x - x = x.subtract(term); - - } while (term.compareTo(tolerance) > 0); - - return x.setScale(scale, RoundingMode.HALF_EVEN); - } - - /** - * Compute the square root of x to a given scale, x >= 0. Use Newton's - * algorithm. - * - * @param x - * the value of x - * @param scale - * the desired scale of the result - * @return the result value - */ - public static BigDecimal sqrt(BigDecimal x, int scale) { - // Check that x >= 0. - if (x.signum() < 0) { - throw new ArithmeticException("x < 0"); - } - if (x.signum()==0) { - return BigDecimal.ZERO.setScale(scale); - } - - // n = x*(10^(2*scale)) - BigInteger n = x.movePointRight(scale << 1).toBigInteger(); - - // The first approximation is the upper half of n. - int bits = (n.bitLength() + 1) >> 1; - BigInteger ix = n.shiftRight(bits); - BigInteger ixPrev; - - // Loop until the approximations converge - // (two successive approximations are equal after rounding). - do { - ixPrev = ix; - // x = (x + n/x)/2 - ix = ix.add(n.divide(ix)).shiftRight(1); - - } while (ix.compareTo(ixPrev) != 0); - - return new BigDecimal(ix, scale); - } - - public static BigDecimal pow(BigDecimal a, BigDecimal b, int scale) { - if (a.signum() == -1) { - throw new ArithmeticException("x < 0"); - } - if (a.equals(BigDecimal.ZERO)) { - return BigDecimal.ZERO; - } - scale = Math.max(Math.max(a.precision(), b.precision()), scale) + 1; - MathContext mc = new MathContext(scale, RoundingMode.HALF_UP); - BigDecimal remainer = b.remainder(BigDecimal.ONE, mc); - if (remainer.equals(BigDecimal.ZERO)) { - return a.pow(b.intValue(), mc); - } - // else we have to do the more expansive route: - // a^b=exp(b*ln(a)) - return exp(b.multiply(ln(a, scale), mc), scale).setScale(scale - 1, RoundingMode.HALF_EVEN); - } + + + /** + * Compute the tangent of x to a given scale, |x| < pi/2 + * + * @param x + * the value of x + * @param scale + * the desired scale of the result + * @return the result value + */ + public static BigDecimal tan(BigDecimal x, int scale) { + if (x.signum() == 0) + return BigDecimal.ZERO; + if (x.abs().compareTo(halfPI) > 0) + throw new ArithmeticException("x should be between -(pi/2) and (pi/2)"); + // easiest implementation of tan (no need for Bernoulli numbers) but this is slower than the other 2 + return sin(x, scale + 1).divide(cos(x, scale + 1), scale, RoundingMode.HALF_UP); + } + + + /** + * Compute x^exponent to a given scale. + * + * @param x + * the value x + * @param exponent + * the exponent value + * @param scale + * the desired scale of the result + * @return the result value + */ + private static BigDecimal intPower(BigDecimal x, BigInteger exponent, int scale) { + boolean negativeExponent = exponent.signum() == -1; + + if (negativeExponent) { + exponent = exponent.negate(); + } + + if (exponent.equals(BigInteger.ZERO)) { + return BigDecimal.ONE.setScale(scale); + } + + MathContext mc = new MathContext(scale, RoundingMode.HALF_EVEN); + + if (exponent.equals(BigInteger.ONE)) { + if (negativeExponent) { + return BigDecimal.ONE.divide(x, mc); + } + return x.setScale(scale, RoundingMode.HALF_EVEN); + } + + BigDecimal result = BigDecimal.valueOf(1); + + if (exponent.compareTo(maxBigDecimalPowExp) >= 0) { + BigDecimal maxExpPow = x.pow(maxBigDecimalPowExp.intValue(), mc); + while (exponent.compareTo(maxBigDecimalPowExp) >= 0) { + result = result.multiply(maxExpPow); + exponent = exponent.subtract(maxBigDecimalPowExp); + } + } + + result = result.multiply(x.pow(exponent.intValue(), mc)); + + if (negativeExponent) { + return BigDecimal.ONE.divide(result, mc); + } + + return result.setScale(scale, RoundingMode.HALF_EVEN); + } + + /** + * The functions below this line are based on the Numerical implementations of + * Java Number Cruncher: The Java Programmer's Guide + * to Numerical Computing + * by Ronald Mak + * + * He has shared the code in the book at the following page: + * http://authors.phptr.com/mak/downloads.html + * + * And has put the source in the public domain: + * "I wrote all these programs strictly as + * illustrative examples for my book. + * You're free to use the source code any + * way you like, but bear in mind that this is + * NOT fully tested, commercial-quality code. + * Neither Prentice Hall PTR nor I can be + * responsible for anything bad that may happen + * if you use these programs." + * + * The only changes were the removal of call to Thread.yield(), switching to + * and formatting improvements + */ + + /** + * Compute the integral root of x to a given scale, x >= 0. Use Newton's + * algorithm. + * + * @param x + * the value of x + * @param index + * the integral root value + * @param scale + * the desired scale of the result + * @return the result value + */ + public static BigDecimal intRoot(BigDecimal x, BigInteger index, int scale) { + // Check that x >= 0. + if (x.signum() < 0) { + throw new ArithmeticException("x < 0"); + } + + int sp1 = scale + 1; + BigDecimal n = x; + BigDecimal i = new BigDecimal(index); + BigDecimal im1 = i.subtract(BigDecimal.ONE); + BigDecimal tolerance = BigDecimal.valueOf(5).movePointLeft(sp1); + BigDecimal xPrev; + BigInteger indexm1 = index.subtract(BigInteger.ONE); + + // The initial approximation is x/index. + x = x.divide(i, scale, RoundingMode.HALF_EVEN); + + // Loop until the approximations converge + // (two successive approximations are equal after rounding). + do { + // x^(index-1) + BigDecimal xToIm1 = intPower(x, indexm1, sp1 + 1); + // x^index + BigDecimal xToI = x.multiply(xToIm1); + // n + (index-1)*(x^index) + BigDecimal numerator = n.add(im1.multiply(xToI)); + // (index*(x^(index-1)) + BigDecimal denominator = i.multiply(xToIm1); + // x = (n + (index-1)*(x^index)) / (index*(x^(index-1))) + xPrev = x; + if (denominator.compareTo(BigDecimal.ZERO) == 0) { + x = BigDecimal.ZERO.setScale(sp1); + } + else { + x = numerator.divide(denominator, sp1, RoundingMode.DOWN); + } + + } while (x.subtract(xPrev).abs().compareTo(tolerance) > 0); + + return x.setScale(scale, RoundingMode.HALF_EVEN); + } + + /** + * Compute e^x to a given scale. Break x into its whole and fraction parts + * and compute (e^(1 + fraction/whole))^whole using Taylor's formula. + * + * @param x + * the value of x + * @param scale + * the desired scale of the result + * @return the result value + */ + public static BigDecimal exp(BigDecimal x, int scale) { + // e^0 = 1 + if (x.signum() == 0) { + return BigDecimal.valueOf(1); + } + + boolean isNegative = x.signum() == -1; + + if (isNegative) { + x = x.negate(); + } + + // Compute the whole part of x. + BigDecimal xWhole = x.setScale(0, RoundingMode.DOWN); + + BigDecimal result; + + // If there isn't a whole part, compute and return e^x. + if (xWhole.signum() == 0) { + result = expTaylor(x, scale); + } + else { + // Compute the fraction part of x. + BigDecimal xFraction = x.subtract(xWhole); + + // z = 1 + fraction/whole + BigDecimal z = BigDecimal.valueOf(1).add( + xFraction.divide(xWhole, scale, RoundingMode.HALF_EVEN)); + + // t = e^z + BigDecimal t = expTaylor(z, scale); + + result = intPower(t, xWhole.toBigInteger(), scale); + } + + if (isNegative) { + return BigDecimal.ONE.divide(result, new MathContext(scale, RoundingMode.HALF_EVEN)); + } + + return result; + } + + /** + * Compute e^x to a given scale by the Taylor series. + * + * @param x + * the value of x + * @param scale + * the desired scale of the result + * @return the result value + */ + private static BigDecimal expTaylor(BigDecimal x, int scale) { + BigDecimal factorial = BigDecimal.valueOf(1); + BigDecimal xPower = x; + BigDecimal sumPrev; + + // 1 + x + BigDecimal sum = x.add(BigDecimal.valueOf(1)); + // Loop until the sums converge + // (two successive sums are equal after rounding). + int i = 2; + do { + // x^i + xPower = xPower.multiply(x).setScale(scale, RoundingMode.HALF_EVEN); + // i! + factorial = factorial.multiply(BigDecimal.valueOf(i)); + // x^i/i! + BigDecimal term = xPower.divide(factorial, scale, RoundingMode.HALF_EVEN); + // sum = sum + x^i/i! + sumPrev = sum; + sum = sum.add(term); + + ++i; + } while (sum.compareTo(sumPrev) != 0); + + return sum; + } + + /** + * Compute the natural logarithm of x to a given scale, x > 0. + * @param x + * the value of x + * @param scale + * the desired scale of the result + * @return + * the natural logarithm of x + */ + public static BigDecimal ln(BigDecimal x, int scale) { + // Check that x > 0. + if (x.signum() <= 0) { + throw new ArithmeticException("x <= 0"); + } + // The number of digits to the left of the decimal point. + int magnitude = x.toString().length() - x.scale() - 1; + if (magnitude < 3) { + return lnNewton(x, scale); + } + // Compute magnitude*ln(x^(1/magnitude)). + else { + // x^(1/magnitude) + BigDecimal root = intRoot(x, BigInteger.valueOf(magnitude), scale); + // ln(x^(1/magnitude)) + BigDecimal lnRoot = lnNewton(root, scale); + // magnitude*ln(x^(1/magnitude)) + return BigDecimal.valueOf(magnitude).multiply(lnRoot) + .setScale(scale, RoundingMode.HALF_EVEN); + } + } + + /** + * Compute the natural logarithm of x to a given scale, x > 0. Use Newton's + * algorithm. + */ + private static BigDecimal lnNewton(BigDecimal x, int scale) { + int sp1 = scale + 1; + BigDecimal n = x; + BigDecimal term; + + // Convergence tolerance = 5*(10^-(scale+1)) + BigDecimal tolerance = BigDecimal.valueOf(5).movePointLeft(sp1); + // Loop until the approximations converge + // (two successive approximations are within the tolerance). + do { + // e^x + BigDecimal eToX = exp(x, sp1); + // (e^x - n)/e^x + if (eToX.compareTo(BigDecimal.ZERO) == 0) { + break; + } + term = eToX.subtract(n).divide(eToX, sp1, RoundingMode.DOWN); + // x - (e^x - n)/e^x + x = x.subtract(term); + + } while (term.compareTo(tolerance) > 0); + + return x.setScale(scale, RoundingMode.HALF_EVEN); + } + + /** + * Compute the square root of x to a given scale, x >= 0. Use Newton's + * algorithm. + * + * @param x + * the value of x + * @param scale + * the desired scale of the result + * @return the result value + */ + public static BigDecimal sqrt(BigDecimal x, int scale) { + // Check that x >= 0. + if (x.signum() < 0) { + throw new ArithmeticException("x < 0"); + } + if (x.signum()==0) { + return BigDecimal.ZERO.setScale(scale); + } + + // n = x*(10^(2*scale)) + BigInteger n = x.movePointRight(scale << 1).toBigInteger(); + + // The first approximation is the upper half of n. + int bits = (n.bitLength() + 1) >> 1; + BigInteger ix = n.shiftRight(bits); + BigInteger ixPrev; + + // Loop until the approximations converge + // (two successive approximations are equal after rounding). + do { + ixPrev = ix; + // x = (x + n/x)/2 + ix = ix.add(n.divide(ix)).shiftRight(1); + + } while (ix.compareTo(ixPrev) != 0); + + return new BigDecimal(ix, scale); + } + + public static BigDecimal pow(BigDecimal a, BigDecimal b, int scale) { + if (a.signum() == -1) { + throw new ArithmeticException("x < 0"); + } + if (a.equals(BigDecimal.ZERO)) { + return BigDecimal.ZERO; + } + scale = Math.max(Math.max(a.precision(), b.precision()), scale) + 1; + MathContext mc = new MathContext(scale, RoundingMode.HALF_UP); + BigDecimal remainer = b.remainder(BigDecimal.ONE, mc); + if (remainer.equals(BigDecimal.ZERO)) { + return a.pow(b.intValue(), mc); + } + // else we have to do the more expansive route: + // a^b=exp(b*ln(a)) + return exp(b.multiply(ln(a, scale), mc), scale).setScale(scale - 1, RoundingMode.HALF_EVEN); + } } diff --git a/src/main/java/io/usethesource/vallang/impl/util/collections/ShareableValuesList.java b/src/main/java/io/usethesource/vallang/impl/util/collections/ShareableValuesList.java index 67a5d963a..bac926df2 100644 --- a/src/main/java/io/usethesource/vallang/impl/util/collections/ShareableValuesList.java +++ b/src/main/java/io/usethesource/vallang/impl/util/collections/ShareableValuesList.java @@ -17,60 +17,60 @@ /** * A specialized version of the ShareableList, specifically meant for storing values. - * + * * @author Arnold Lankamp */ public class ShareableValuesList extends ShareableList { - - public ShareableValuesList(){ - super(); - } - - public ShareableValuesList(ShareableValuesList shareableValuesList){ - super(shareableValuesList); - } - - public ShareableValuesList(ShareableValuesList shareableValuesList, int offset, int length){ - super(shareableValuesList, offset, length); - } - - public boolean contains(IValue value){ - Iterator valuesIterator = iterator(); - while(valuesIterator.hasNext()){ - IValue next = valuesIterator.next(); - if(next.equals(value)) { - return true; - } - } - - return false; - } - - public boolean remove(IValue value){ - int index = 0; - Iterator valuesIterator = iterator(); - while (valuesIterator.hasNext()){ - IValue next = valuesIterator.next(); - if (next.equals(value)) { - break; - } - - index++; - } - - if(index < size()){ - remove(index); - return true; - } - - return false; - } - - public ShareableValuesList subList(int offset, int length){ - if(offset < 0) throw new IndexOutOfBoundsException("Offset may not be smaller than 0."); - if(length < 0) throw new IndexOutOfBoundsException("Length may not be smaller than 0."); - if((offset + length) > size()) throw new IndexOutOfBoundsException("'offset + length' may not be larger than 'list.size()'"); - - return new ShareableValuesList(this, offset, length); - } + + public ShareableValuesList(){ + super(); + } + + public ShareableValuesList(ShareableValuesList shareableValuesList){ + super(shareableValuesList); + } + + public ShareableValuesList(ShareableValuesList shareableValuesList, int offset, int length){ + super(shareableValuesList, offset, length); + } + + public boolean contains(IValue value){ + Iterator valuesIterator = iterator(); + while(valuesIterator.hasNext()){ + IValue next = valuesIterator.next(); + if(next.equals(value)) { + return true; + } + } + + return false; + } + + public boolean remove(IValue value){ + int index = 0; + Iterator valuesIterator = iterator(); + while (valuesIterator.hasNext()){ + IValue next = valuesIterator.next(); + if (next.equals(value)) { + break; + } + + index++; + } + + if(index < size()){ + remove(index); + return true; + } + + return false; + } + + public ShareableValuesList subList(int offset, int length){ + if(offset < 0) throw new IndexOutOfBoundsException("Offset may not be smaller than 0."); + if(length < 0) throw new IndexOutOfBoundsException("Length may not be smaller than 0."); + if((offset + length) > size()) throw new IndexOutOfBoundsException("'offset + length' may not be larger than 'list.size()'"); + + return new ShareableValuesList(this, offset, length); + } } diff --git a/src/main/java/io/usethesource/vallang/io/ATermReader.java b/src/main/java/io/usethesource/vallang/io/ATermReader.java index 23c1ff615..8cff4e95a 100644 --- a/src/main/java/io/usethesource/vallang/io/ATermReader.java +++ b/src/main/java/io/usethesource/vallang/io/ATermReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) INRIA-LORIA and CWI 2006-2009 + * Copyright (c) INRIA-LORIA and CWI 2006-2009 * 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 @@ -90,36 +90,36 @@ private IValue parse(SharingStream reader, Type expected) start = reader.getPosition(); switch (reader.getLastChar()) { - case -1: - throw new FactParseError("premature EOF encountered.", start); - case '#': - return parseAbbrev(reader); - case '[': - result = parseList(reader, expected); - break; - case '<': - throw new FactParseError("Placeholders are not supported", start); - case '"': - result = parseString(reader, expected); - break; - case '(': - result = parseTuple(reader, expected); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - result = parseNumber(reader, expected); - break; - default: - result = parseAppl(reader, expected); + case -1: + throw new FactParseError("premature EOF encountered.", start); + case '#': + return parseAbbrev(reader); + case '[': + result = parseList(reader, expected); + break; + case '<': + throw new FactParseError("Placeholders are not supported", start); + case '"': + result = parseString(reader, expected); + break; + case '(': + result = parseTuple(reader, expected); + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + result = parseNumber(reader, expected); + break; + default: + result = parseAppl(reader, expected); } if (reader.getLastChar() == '{') { @@ -164,7 +164,7 @@ private IValue parseAppl(SharingStream reader, Type expected) if (!iterator.hasNext()) { throw new UndeclaredAbstractDataTypeException(expected); } - node = iterator.next(); + node = iterator.next(); } else { node = expected; @@ -186,7 +186,7 @@ private IValue parseAppl(SharingStream reader, Type expected) if(node.isConstructor()) result = vf.constructor(node, new IValue[0]); else - result = vf.node(funname, new IValue[0]); + result = vf.node(funname, new IValue[0]); } else { IValue[] list; @@ -474,42 +474,42 @@ private String parseStringLiteral(SharingStream reader) throws IOException { if (escaped) { switch (lastChar) { - case 'n': - str.append('\n'); - break; - case 't': - str.append('\t'); - break; - case 'b': - str.append('\b'); - break; - case 'r': - str.append('\r'); - break; - case 'f': - str.append('\f'); - break; - case '\\': - str.append('\\'); - break; - case '\'': - str.append('\''); - break; - case '\"': - str.append('\"'); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - str.append(reader.readOct()); - break; - default: - str.append('\\').append((char) lastChar); + case 'n': + str.append('\n'); + break; + case 't': + str.append('\t'); + break; + case 'b': + str.append('\b'); + break; + case 'r': + str.append('\r'); + break; + case 'f': + str.append('\f'); + break; + case '\\': + str.append('\\'); + break; + case '\'': + str.append('\''); + break; + case '\"': + str.append('\"'); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + str.append(reader.readOct()); + break; + default: + str.append('\\').append((char) lastChar); } } else if (lastChar != '\"'){ str.append((char) lastChar); @@ -568,7 +568,7 @@ private Type getElementType(Type expected) { return base.getFieldTypes(); } else if (base.isTop()) { return base; - } + } else { throw new IllegalOperationException("getElementType", expected); } diff --git a/src/main/java/io/usethesource/vallang/io/ATermWriter.java b/src/main/java/io/usethesource/vallang/io/ATermWriter.java index ad71b0030..6153e520e 100644 --- a/src/main/java/io/usethesource/vallang/io/ATermWriter.java +++ b/src/main/java/io/usethesource/vallang/io/ATermWriter.java @@ -40,233 +40,233 @@ * See also {@link ATermReader} */ public class ATermWriter implements IValueTextWriter { - public void write(IValue value, java.io.Writer stream) throws IOException { - value.accept(new Writer(stream)); - } - - public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { - write(value, stream); - } - - private static class Writer implements IValueVisitor { - private java.io.Writer stream; - - public Writer(java.io.Writer stream) { - this.stream = stream; - } - - private void append(String string) throws IOException { - stream.write(string); - } - - private void append(char c) throws IOException { - stream.write(c); - } - - @Override - public IValue visitBoolean(IBool boolValue) throws IOException { - append(boolValue.getStringRepresentation()); - return boolValue; - } - - @Override - public IValue visitConstructor(IConstructor o) throws IOException { - return visitNode(o); - } - - @Override - public IValue visitReal(IReal o) throws IOException { - append(o.getStringRepresentation()); - return o; - } - - @Override - public IValue visitInteger(IInteger o) throws IOException { - append(o.getStringRepresentation()); - return o; - } - - // TODO: There probably isn't a good ATerm repr of rationals, - // what should we do here? - @Override - public IValue visitRational(IRational o) throws IOException { - append("rat"); - append('('); - append(o.numerator().getStringRepresentation()); - append(','); - append(o.denominator().getStringRepresentation()); - append(')'); - return o; - } - - @Override - public IValue visitList(IList o) throws IOException { - append('['); - - Iterator listIterator = o.iterator(); - if(listIterator.hasNext()){ - append(listIterator.next().toString()); - - while(listIterator.hasNext()){ - append(','); - listIterator.next().accept(this); - } - } - - append(']'); - - return o; - } - - @Override - public IValue visitMap(IMap o) throws IOException { - append('['); - - Iterator> mapIterator = o.entryIterator(); - if (mapIterator.hasNext()) { - Entry entry = mapIterator.next(); - append('('); - IValue key = entry.getKey(); - key.accept(this); - append(','); - entry.getValue().accept(this); - append(')'); - - while(mapIterator.hasNext()) { - entry = mapIterator.next(); - append(','); - append('('); - key = entry.getKey(); - append(','); - entry.getValue().accept(this); - append(')'); - } - } - - append(']'); - - return o; - } - - @Override + public void write(IValue value, java.io.Writer stream) throws IOException { + value.accept(new Writer(stream)); + } + + public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { + write(value, stream); + } + + private static class Writer implements IValueVisitor { + private java.io.Writer stream; + + public Writer(java.io.Writer stream) { + this.stream = stream; + } + + private void append(String string) throws IOException { + stream.write(string); + } + + private void append(char c) throws IOException { + stream.write(c); + } + + @Override + public IValue visitBoolean(IBool boolValue) throws IOException { + append(boolValue.getStringRepresentation()); + return boolValue; + } + + @Override + public IValue visitConstructor(IConstructor o) throws IOException { + return visitNode(o); + } + + @Override + public IValue visitReal(IReal o) throws IOException { + append(o.getStringRepresentation()); + return o; + } + + @Override + public IValue visitInteger(IInteger o) throws IOException { + append(o.getStringRepresentation()); + return o; + } + + // TODO: There probably isn't a good ATerm repr of rationals, + // what should we do here? + @Override + public IValue visitRational(IRational o) throws IOException { + append("rat"); + append('('); + append(o.numerator().getStringRepresentation()); + append(','); + append(o.denominator().getStringRepresentation()); + append(')'); + return o; + } + + @Override + public IValue visitList(IList o) throws IOException { + append('['); + + Iterator listIterator = o.iterator(); + if(listIterator.hasNext()){ + append(listIterator.next().toString()); + + while(listIterator.hasNext()){ + append(','); + listIterator.next().accept(this); + } + } + + append(']'); + + return o; + } + + @Override + public IValue visitMap(IMap o) throws IOException { + append('['); + + Iterator> mapIterator = o.entryIterator(); + if (mapIterator.hasNext()) { + Entry entry = mapIterator.next(); + append('('); + IValue key = entry.getKey(); + key.accept(this); + append(','); + entry.getValue().accept(this); + append(')'); + + while(mapIterator.hasNext()) { + entry = mapIterator.next(); + append(','); + append('('); + key = entry.getKey(); + append(','); + entry.getValue().accept(this); + append(')'); + } + } + + append(']'); + + return o; + } + + @Override public IValue visitNode(INode o) throws IOException { - String name = o.getName(); - - append(name); - append('('); - - Iterator it = o.iterator(); - while (it.hasNext()) { - it.next().accept(this); - if (it.hasNext()) { - append(','); - } - } - append(')'); - - if (o.asWithKeywordParameters().hasParameters()) { - append("{["); - int i = 0; - Map kwFields = o.asWithKeywordParameters().getParameters(); - for (Entry entry : kwFields.entrySet()) { - append("[" + entry.getKey() + ","); - entry.getValue().accept(this); - append("]"); - - if (++i < kwFields.size()) { - append(","); - } - } - append("]}"); - } - - return o; - } + String name = o.getName(); + + append(name); + append('('); + + Iterator it = o.iterator(); + while (it.hasNext()) { + it.next().accept(this); + if (it.hasNext()) { + append(','); + } + } + append(')'); + + if (o.asWithKeywordParameters().hasParameters()) { + append("{["); + int i = 0; + Map kwFields = o.asWithKeywordParameters().getParameters(); + for (Entry entry : kwFields.entrySet()) { + append("[" + entry.getKey() + ","); + entry.getValue().accept(this); + append("]"); + + if (++i < kwFields.size()) { + append(","); + } + } + append("]}"); + } + + return o; + } @Override - public IValue visitSet(ISet o) throws IOException { - append('['); - - Iterator setIterator = o.iterator(); - if(setIterator.hasNext()){ - setIterator.next().accept(this); - - while(setIterator.hasNext()){ - append(","); - setIterator.next().accept(this); - } - } - - append(']'); - return o; - } + public IValue visitSet(ISet o) throws IOException { + append('['); + + Iterator setIterator = o.iterator(); + if(setIterator.hasNext()){ + setIterator.next().accept(this); + + while(setIterator.hasNext()){ + append(","); + setIterator.next().accept(this); + } + } + + append(']'); + return o; + } @Override - public IValue visitSourceLocation(ISourceLocation o) - throws IOException { - append("loc("); - append('\"'); - append(o.getURI().toString()); - append('\"'); - append("," + o.getOffset()); - append("," + o.getLength()); - append("," + o.getBeginLine()); - append("," + o.getBeginColumn()); - append("," + o.getEndLine()); - append("," + o.getEndColumn()); - append(')'); - return o; - } + public IValue visitSourceLocation(ISourceLocation o) + throws IOException { + append("loc("); + append('\"'); + append(o.getURI().toString()); + append('\"'); + append("," + o.getOffset()); + append("," + o.getLength()); + append("," + o.getBeginLine()); + append("," + o.getBeginColumn()); + append("," + o.getEndLine()); + append("," + o.getEndColumn()); + append(')'); + return o; + } @Override - public IValue visitString(IString o) throws IOException { - // TODO optimize this implementation and finish all escapes - append('\"'); - append(o.getValue().replaceAll("\"", "\\\"").replaceAll("\n","\\\\n")); - append('\"'); - return o; - } + public IValue visitString(IString o) throws IOException { + // TODO optimize this implementation and finish all escapes + append('\"'); + append(o.getValue().replaceAll("\"", "\\\"").replaceAll("\n","\\\\n")); + append('\"'); + return o; + } @Override - public IValue visitTuple(ITuple o) throws IOException { - append('('); - - Iterator it = o.iterator(); - - if (it.hasNext()) { - it.next().accept(this); - } - - while (it.hasNext()) { - append(','); - it.next().accept(this); - } - append(')'); - - return o; - } + public IValue visitTuple(ITuple o) throws IOException { + append('('); + + Iterator it = o.iterator(); + + if (it.hasNext()) { + it.next().accept(this); + } + + while (it.hasNext()) { + append(','); + it.next().accept(this); + } + append(')'); + + return o; + } @Override - public IValue visitExternal(IExternalValue externalValue) { - // ignore external values - return externalValue; - } + public IValue visitExternal(IExternalValue externalValue) { + // ignore external values + return externalValue; + } @Override - public IValue visitDateTime(IDateTime o) throws IOException { - append("$"); - if (o.isDate()) { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); - append(df.format(new Date(o.getInstant()))); - } else if (o.isTime()) { - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSSZZZ"); - append("T"); - append(df.format(new Date(o.getInstant()))); - } else { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ"); - append(df.format(new Date(o.getInstant()))); - } - return o; - } - } + public IValue visitDateTime(IDateTime o) throws IOException { + append("$"); + if (o.isDate()) { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + append(df.format(new Date(o.getInstant()))); + } else if (o.isTime()) { + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSSZZZ"); + append("T"); + append(df.format(new Date(o.getInstant()))); + } else { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ"); + append(df.format(new Date(o.getInstant()))); + } + return o; + } + } } diff --git a/src/main/java/io/usethesource/vallang/io/AbstractBinaryReader.java b/src/main/java/io/usethesource/vallang/io/AbstractBinaryReader.java index 878916d54..29be48433 100644 --- a/src/main/java/io/usethesource/vallang/io/AbstractBinaryReader.java +++ b/src/main/java/io/usethesource/vallang/io/AbstractBinaryReader.java @@ -11,13 +11,13 @@ import io.usethesource.vallang.type.TypeStore; public abstract class AbstractBinaryReader implements IValueBinaryReader { - public IValue read(IValueFactory factory, Type type, InputStream stream) - throws FactTypeUseException, IOException { - return read(factory, new TypeStore(), type, stream); - } + public IValue read(IValueFactory factory, Type type, InputStream stream) + throws FactTypeUseException, IOException { + return read(factory, new TypeStore(), type, stream); + } - public IValue read(IValueFactory factory, InputStream stream) - throws FactTypeUseException, IOException { - return read(factory, new TypeStore(), TypeFactory.getInstance().valueType(), stream); - } + public IValue read(IValueFactory factory, InputStream stream) + throws FactTypeUseException, IOException { + return read(factory, new TypeStore(), TypeFactory.getInstance().valueType(), stream); + } } diff --git a/src/main/java/io/usethesource/vallang/io/AbstractTextReader.java b/src/main/java/io/usethesource/vallang/io/AbstractTextReader.java index 4efdca5ef..633de2973 100644 --- a/src/main/java/io/usethesource/vallang/io/AbstractTextReader.java +++ b/src/main/java/io/usethesource/vallang/io/AbstractTextReader.java @@ -11,13 +11,13 @@ import io.usethesource.vallang.type.TypeStore; public abstract class AbstractTextReader implements IValueTextReader { - public IValue read(IValueFactory factory, Type type, Reader reader) - throws FactTypeUseException, IOException { - return read(factory, new TypeStore(), type, reader); - } + public IValue read(IValueFactory factory, Type type, Reader reader) + throws FactTypeUseException, IOException { + return read(factory, new TypeStore(), type, reader); + } - public IValue read(IValueFactory factory, Reader reader) - throws FactTypeUseException, IOException { - return read(factory, new TypeStore(), TypeFactory.getInstance().valueType(), reader); - } + public IValue read(IValueFactory factory, Reader reader) + throws FactTypeUseException, IOException { + return read(factory, new TypeStore(), TypeFactory.getInstance().valueType(), reader); + } } diff --git a/src/main/java/io/usethesource/vallang/io/IValueBinaryReader.java b/src/main/java/io/usethesource/vallang/io/IValueBinaryReader.java index cfb86e6e4..be2e747f3 100644 --- a/src/main/java/io/usethesource/vallang/io/IValueBinaryReader.java +++ b/src/main/java/io/usethesource/vallang/io/IValueBinaryReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) CWI 2008 + * Copyright (c) CWI 2008 * 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 @@ -26,51 +26,51 @@ * There should be a corresponding IValueWriter to serialize them again. Note * that IValueReaders should also validate the serialized input * against a {@link Type}. - * + * * @author jurgenv - * + * */ public interface IValueBinaryReader { - /** - * Parse an IValue, validate it and build it if it can be validated. - * - * @param factory - * used when building the value - * @param store - * declarations of types to use - * @param type - * used to validate the value - * @param stream - * source of bytes to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, TypeStore store, Type type, + /** + * Parse an IValue, validate it and build it if it can be validated. + * + * @param factory + * used when building the value + * @param store + * declarations of types to use + * @param type + * used to validate the value + * @param stream + * source of bytes to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, TypeStore store, Type type, InputStream stream) throws FactTypeUseException, IOException; - /** - * Parse an IValue, validate it and build it if it can be validated. - * - * @param factory - * used when building the value - * @param type - * used to validate the value - * @param stream - * source of bytes to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, Type type, InputStream stream) - throws FactTypeUseException, IOException; - - /** - * Parse an IValue without validation. - * - * @param factory - * used when building the value - * @param stream - * source of bytes to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, InputStream stream) - throws FactTypeUseException, IOException; + /** + * Parse an IValue, validate it and build it if it can be validated. + * + * @param factory + * used when building the value + * @param type + * used to validate the value + * @param stream + * source of bytes to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, Type type, InputStream stream) + throws FactTypeUseException, IOException; + + /** + * Parse an IValue without validation. + * + * @param factory + * used when building the value + * @param stream + * source of bytes to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, InputStream stream) + throws FactTypeUseException, IOException; } diff --git a/src/main/java/io/usethesource/vallang/io/IValueBinaryWriter.java b/src/main/java/io/usethesource/vallang/io/IValueBinaryWriter.java index d4a060656..3d8c027b3 100644 --- a/src/main/java/io/usethesource/vallang/io/IValueBinaryWriter.java +++ b/src/main/java/io/usethesource/vallang/io/IValueBinaryWriter.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) CWI 2008 +* Copyright (c) CWI 2008 * 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 @@ -22,13 +22,13 @@ * An instance of IValueWriter can serialize all types of IValues. * There should be a corresponding IValueReader to de-serialize them * back to IValues. - * + * * @author jurgenv * */ public interface IValueBinaryWriter { - void write(IValue value, OutputStream stream) throws IOException; - void write(IValue value, OutputStream stream, boolean compression) throws IOException; - void write(IValue value, OutputStream stream, TypeStore typeStore) throws IOException; - void write(IValue value, OutputStream stream, boolean compression, TypeStore typeStore) throws IOException; + void write(IValue value, OutputStream stream) throws IOException; + void write(IValue value, OutputStream stream, boolean compression) throws IOException; + void write(IValue value, OutputStream stream, TypeStore typeStore) throws IOException; + void write(IValue value, OutputStream stream, boolean compression, TypeStore typeStore) throws IOException; } diff --git a/src/main/java/io/usethesource/vallang/io/IValueTextReader.java b/src/main/java/io/usethesource/vallang/io/IValueTextReader.java index 4a2f830e1..8615f39f2 100644 --- a/src/main/java/io/usethesource/vallang/io/IValueTextReader.java +++ b/src/main/java/io/usethesource/vallang/io/IValueTextReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) CWI 2008 + * Copyright (c) CWI 2008 * 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 @@ -28,33 +28,33 @@ */ public interface IValueTextReader { - /** - * Parse an IValue, validate it and build it if it can be validated. - * - * @param factory used when building the value - * @param store declarations of types to use - * @param type used to validate the value - * @param stream source of bytes to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, TypeStore store, Type type, Reader reader) throws FactTypeUseException, IOException; - - /** - * Parse an IValue, validate it and build it if it can be validated. - * - * @param factory used when building the value - * @param type used to validate the value - * @param reader source of character to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, Type type, Reader reader) throws FactTypeUseException, IOException; - - /** - * Parse an IValue without validation. - * - * @param factory used when building the value - * @param reader source of characters to parse - * @return an IValue that represents the string input - */ - IValue read(IValueFactory factory, Reader reader) throws FactTypeUseException, IOException; + /** + * Parse an IValue, validate it and build it if it can be validated. + * + * @param factory used when building the value + * @param store declarations of types to use + * @param type used to validate the value + * @param stream source of bytes to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, TypeStore store, Type type, Reader reader) throws FactTypeUseException, IOException; + + /** + * Parse an IValue, validate it and build it if it can be validated. + * + * @param factory used when building the value + * @param type used to validate the value + * @param reader source of character to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, Type type, Reader reader) throws FactTypeUseException, IOException; + + /** + * Parse an IValue without validation. + * + * @param factory used when building the value + * @param reader source of characters to parse + * @return an IValue that represents the string input + */ + IValue read(IValueFactory factory, Reader reader) throws FactTypeUseException, IOException; } diff --git a/src/main/java/io/usethesource/vallang/io/IValueTextWriter.java b/src/main/java/io/usethesource/vallang/io/IValueTextWriter.java index 195ef8207..791476e53 100644 --- a/src/main/java/io/usethesource/vallang/io/IValueTextWriter.java +++ b/src/main/java/io/usethesource/vallang/io/IValueTextWriter.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) CWI 2008 +* Copyright (c) CWI 2008 * 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 @@ -24,19 +24,19 @@ * back to IValues. */ public interface IValueTextWriter { - /** - * Serialize a value using the given writer - * @param value the value to serialize - * @param writer the writer to output character to - * @throws IOException in case the writer does - */ - void write(IValue value, Writer writer) throws IOException; - - /** - * Serialize a value using the given writer - * @param value the value to serialize - * @param writer the writer to output character to - * @throws IOException in case the writer does - */ - void write(IValue value, Writer writer, TypeStore typeStore) throws IOException; + /** + * Serialize a value using the given writer + * @param value the value to serialize + * @param writer the writer to output character to + * @throws IOException in case the writer does + */ + void write(IValue value, Writer writer) throws IOException; + + /** + * Serialize a value using the given writer + * @param value the value to serialize + * @param writer the writer to output character to + * @throws IOException in case the writer does + */ + void write(IValue value, Writer writer, TypeStore typeStore) throws IOException; } diff --git a/src/main/java/io/usethesource/vallang/io/StandardTextReader.java b/src/main/java/io/usethesource/vallang/io/StandardTextReader.java index c05c6da91..c3de33036 100644 --- a/src/main/java/io/usethesource/vallang/io/StandardTextReader.java +++ b/src/main/java/io/usethesource/vallang/io/StandardTextReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) CWI 2008 + * Copyright (c) CWI 2008 * 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 @@ -49,9 +49,9 @@ /** * This class implements the standard readable syntax for {@link IValue}'s. * Note that the parser also validates the input according to a given {@link Type}. - * + * * Note however that overloaded constructors for abstract data-types are not supported. - * + * * See also {@link StandardTextWriter} */ public class StandardTextReader extends AbstractTextReader { @@ -86,8 +86,8 @@ private static class TextReader { private static final char NEGATIVE_SIGN = '-'; private static final TypeFactory types = TypeFactory.getInstance(); - - private final TypeStore store; + + private final TypeStore store; private final NoWhiteSpaceReader stream; private final IValueFactory factory; @@ -104,20 +104,20 @@ public TextReader(IValueFactory factory, TypeStore store, Reader stream) { public IValue read(Type expected) throws IOException { current = stream.read(); IValue result = readValue(expected); - + if (current != -1 || this.stream.read() != -1) { throw unexpectedException(); } - - return result; + + return result; } - + private IValue readValue(Type expected) throws IOException { IValue result = null; if (Character.isDigit(current) || current == DOUBLE_DOT || current == NEGATIVE_SIGN) { result = readNumber(expected); - } + } else if ((Character.isJavaIdentifierStart(current) && '$' != current) || current == '\\') { boolean escaped = current == '\\'; @@ -131,7 +131,7 @@ else if (!escaped && id.equals("false") && !expected.isAbstractData()) { } else if (current == '=') { return factory.string(id); - } + } else if (current == START_OF_ARGUMENTS) { result = readConstructor(id, expected); } @@ -141,29 +141,29 @@ else if (current == START_OF_ARGUMENTS) { } else { switch (current) { - case START_OF_STRING: - result = readString(expected); - break; - case START_OF_LIST: - result = readList(expected); - break; - case START_OF_SET: - result = readSet(expected); - break; - case START_OF_TUPLE: - result = readTuple(expected); - break; - case START_OF_MAP: - result = readMap(expected); - break; - case START_OF_LOC: - result = readLocation(expected); - break; - case START_OF_DATETIME: - result = readDateTime(expected); - break; - default: - throw unexpectedException(); + case START_OF_STRING: + result = readString(expected); + break; + case START_OF_LIST: + result = readList(expected); + break; + case START_OF_SET: + result = readSet(expected); + break; + case START_OF_TUPLE: + result = readTuple(expected); + break; + case START_OF_MAP: + result = readMap(expected); + break; + case START_OF_LOC: + result = readLocation(expected); + break; + case START_OF_DATETIME: + result = readDateTime(expected); + break; + default: + throw unexpectedException(); } } @@ -330,10 +330,8 @@ private IValue readList(Type expected) throws FactTypeUseException, IOException private void checkMoreThanOnce(String input, char needle) { boolean first = true; - for (int i=0; i < input.length(); i++) - { - if (input.charAt(i) == needle) - { + for (int i=0; i < input.length(); i++) { + if (input.charAt(i) == needle) { if (first) { first = false; } @@ -400,7 +398,7 @@ private IValue readConstructor(String id, Type expected) throws IOException { throw new OverloadingNotSupportedException(expected, id); } else if (alternatives.size() == 0) { - args = types.valueType(); + args = types.valueType(); // TODO: Should not it be an undeclared abstract data/constructor exception?! } else { @@ -428,13 +426,13 @@ else if (alternatives.size() == 0) { /** * Read in a single character from the input stream and append it to the * given buffer only if it is numeric. - * - * @param buf The buffer to which the read character should be appended - * - * @return True if the input character was numeric [0-9] and was appended, - * false otherwise. - * - * @throws IOException when an error is encountered reading the input stream + * + * @param buf The buffer to which the read character should be appended + * + * @return True if the input character was numeric [0-9] and was appended, + * false otherwise. + * + * @throws IOException when an error is encountered reading the input stream */ private boolean readAndAppendIfNumeric(StringBuilder buf) throws IOException { current = stream.read(); @@ -447,13 +445,13 @@ private boolean readAndAppendIfNumeric(StringBuilder buf) throws IOException { } /** - * Read in a date value, given as a string of the form NNNN-NN-NN, where each + * Read in a date value, given as a string of the form NNNN-NN-NN, where each * N is a digit [0-9]. The groups are the year, month, and day of month. - * + * * @return A DateParts object with year, month, and day filled in. - * - * @throws IOException when an error is encountered reading the input stream - * @throws FactParseError when the correct characters are not found while lexing + * + * @throws IOException when an error is encountered reading the input stream + * @throws FactParseError when the correct characters are not found while lexing * the date */ private DateParts readDate(char firstChar) throws IOException, FactParseError { @@ -469,7 +467,7 @@ private DateParts readDate(char firstChar) throws IOException, FactParseError { } // The next character should be a '-' - current = stream.read(); + current = stream.read(); if ('-' != current) { throw new FactParseError("Error reading date, expected '-', found: " + current, stream.offset); } @@ -483,7 +481,7 @@ private DateParts readDate(char firstChar) throws IOException, FactParseError { } // The next character should be a '-' - current = stream.read(); + current = stream.read(); if ('-' != current) { throw new FactParseError("Error reading date, expected '-', found: " + current, stream.offset); } @@ -507,12 +505,12 @@ private DateParts readDate(char firstChar) throws IOException, FactParseError { * Read in a time value, given as a string of the form NN:NN:NN.NNN[+-]NN:NN, * where each N is a digit [0-9]. The groups are the hour, minute, second, * millisecond, timezone hour offset, and timezone minute offset. - * + * * @return A TimeParts objects with hours, minutes, seconds, milliseconds, * and timezone information filled in. - * - * @throws IOException when an error is encountered reading the input stream - * @throws FactParseError when the correct characters are not found while lexing + * + * @throws IOException when an error is encountered reading the input stream + * @throws FactParseError when the correct characters are not found while lexing * the time */ private TimeParts readTime() throws IOException, FactParseError { @@ -527,7 +525,7 @@ private TimeParts readTime() throws IOException, FactParseError { } // The next character should be a ':' - current = stream.read(); + current = stream.read(); if (':' != current) { throw new FactParseError("Error reading time, expected ':', found: " + current, stream.offset); } @@ -541,7 +539,7 @@ private TimeParts readTime() throws IOException, FactParseError { } // The next character should be a ':' - current = stream.read(); + current = stream.read(); if (':' != current) { throw new FactParseError("Error reading time, expected ':', found: " + current, stream.offset); } @@ -555,7 +553,7 @@ private TimeParts readTime() throws IOException, FactParseError { } // The next character should be a '.' - current = stream.read(); + current = stream.read(); if ('.' != current) { throw new FactParseError("Error reading time, expected '.', found: " + current, stream.offset); } @@ -569,7 +567,7 @@ private TimeParts readTime() throws IOException, FactParseError { } // The next character should be '+' or '-' - current = stream.read(); + current = stream.read(); if (! ('+' == current || '-' == current)) { throw new FactParseError("Error reading time, expected '+' or '-', found: " + current, stream.offset); } @@ -610,8 +608,8 @@ private TimeParts readTime() throws IOException, FactParseError { private IValue readDateTime(Type expected) throws IOException, FactParseError { DateParts dateParts = null; TimeParts timeParts = null; - boolean isDate = false; - boolean isTime = false; + boolean isDate = false; + boolean isTime = false; // Retrieve the string to parse and pick the correct format string, // based on whether we are reading a time, a date, or a datetime. @@ -641,8 +639,8 @@ private IValue readDateTime(Type expected) throws IOException, FactParseError { if (isDate) { assert dateParts != null : "@AssumeAssertion(nullness)"; - return factory.date(dateParts.getYear(), dateParts.getMonth(), dateParts.getDay()); - } else { + return factory.date(dateParts.getYear(), dateParts.getMonth(), dateParts.getDay()); + } else { if (isTime) { assert timeParts != null : "@AssumeAssertion(nullness)"; @@ -664,7 +662,7 @@ private String readIdentifier() throws IOException { current = stream.read(); } - while (Character.isJavaIdentifierStart(current) + while (Character.isJavaIdentifierStart(current) || Character.isJavaIdentifierPart(current) || (escaped && current == '-')) { builder.append((char) current); @@ -682,70 +680,70 @@ private IValue readString(Type expected) throws IOException { if (current == '\\') { current = stream.read(); switch (current) { - case 'n': - builder.append('\n'); - break; - case 't': - builder.append('\t'); - break; - case 'r': - builder.append('\r'); - break; - case 'f': - builder.append('\f'); - break; - case 'b': - builder.append('\b'); - break; - case '\"': - builder.append('\"'); - break; - case '>': - builder.append('>'); - break; - case '<': - builder.append('<'); - break; - case '\'': - builder.append('\''); - break; - case '\\': - builder.append('\\'); - break; - case 'a': - StringBuilder a = new StringBuilder(); - a.append((char)stream.read()); - a.append((char)stream.read()); - builder.append((char) Integer.parseInt(a.toString(), 16)); - break; - case 'u': - StringBuilder u = new StringBuilder(); - u.append((char) stream.read()); - u.append((char)stream.read()); - u.append((char)stream.read()); - u.append((char)stream.read()); - builder.append((char) Integer.parseInt(u.toString(), 16)); - break; - case 'U': - StringBuilder U = new StringBuilder(); - U.append((char)stream.read()); - U.append((char)stream.read()); - U.append((char)stream.read()); - U.append((char)stream.read()); - U.append((char)stream.read()); - U.append((char)stream.read()); - int cp = Integer.parseInt(U.toString(), 16); - - if (!Character.isValidCodePoint(cp)) { - throw new FactParseError(U + " is not a valid 24 bit Unicode character", stream.getOffset()); - } - builder.appendCodePoint(cp); - break; - default: - if (current == -1) { - throw new FactParseError("End of input before finding end of String", stream.offset); - } - builder.append((char)current); + case 'n': + builder.append('\n'); + break; + case 't': + builder.append('\t'); + break; + case 'r': + builder.append('\r'); + break; + case 'f': + builder.append('\f'); + break; + case 'b': + builder.append('\b'); + break; + case '\"': + builder.append('\"'); + break; + case '>': + builder.append('>'); + break; + case '<': + builder.append('<'); + break; + case '\'': + builder.append('\''); + break; + case '\\': + builder.append('\\'); + break; + case 'a': + StringBuilder a = new StringBuilder(); + a.append((char)stream.read()); + a.append((char)stream.read()); + builder.append((char) Integer.parseInt(a.toString(), 16)); + break; + case 'u': + StringBuilder u = new StringBuilder(); + u.append((char) stream.read()); + u.append((char)stream.read()); + u.append((char)stream.read()); + u.append((char)stream.read()); + builder.append((char) Integer.parseInt(u.toString(), 16)); + break; + case 'U': + StringBuilder U = new StringBuilder(); + U.append((char)stream.read()); + U.append((char)stream.read()); + U.append((char)stream.read()); + U.append((char)stream.read()); + U.append((char)stream.read()); + U.append((char)stream.read()); + int cp = Integer.parseInt(U.toString(), 16); + + if (!Character.isValidCodePoint(cp)) { + throw new FactParseError(U + " is not a valid 24 bit Unicode character", stream.getOffset()); + } + builder.appendCodePoint(cp); + break; + default: + if (current == -1) { + throw new FactParseError("End of input before finding end of String", stream.offset); + } + builder.append((char)current); } current = stream.read(); } @@ -780,7 +778,7 @@ else if (current == -1) { * The reader still supports the old annotation format for bootstrapping reasons and backward compatibility * (for a while). The annotations are read as annotations but stored as keyword parameters. For the * parse tree type Tree, the `@\loc` annotation is also rewritten to the `.src` keyword field. - * + * * @param expected * @param result * @return @@ -792,11 +790,11 @@ private IValue readAnnos(Type expected, INode result) throws IOException { while (current != ']') { checkAndRead('@'); String key = readIdentifier(); - + if (isLegacyParseTreeSourceAnnotation(key, result.getType())) { key = "src"; } - + checkAndRead('='); Type annoType = getAnnoType(expected, key); @@ -987,7 +985,7 @@ public int getDay() { } public String toString() { - return String.format("%04d", year) + "-" + String.format("%02d", month) + "-" + String.format("%02d", day); + return String.format("%04d", year) + "-" + String.format("%02d", month) + "-" + String.format("%02d", day); } } diff --git a/src/main/java/io/usethesource/vallang/io/StandardTextWriter.java b/src/main/java/io/usethesource/vallang/io/StandardTextWriter.java index db4879c4c..57ee7a161 100644 --- a/src/main/java/io/usethesource/vallang/io/StandardTextWriter.java +++ b/src/main/java/io/usethesource/vallang/io/StandardTextWriter.java @@ -1,700 +1,700 @@ -/******************************************************************************* - * Copyright (c) CWI 2009-2017 - * 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 Vinju (jurgenv@cwi.nl) - initial API and implementation - *******************************************************************************/ -package io.usethesource.vallang.io; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.PrimitiveIterator.OfInt; - -import io.usethesource.vallang.IBool; -import io.usethesource.vallang.IConstructor; -import io.usethesource.vallang.IDateTime; -import io.usethesource.vallang.IExternalValue; -import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.IList; -import io.usethesource.vallang.IMap; -import io.usethesource.vallang.INode; -import io.usethesource.vallang.IRational; -import io.usethesource.vallang.IReal; -import io.usethesource.vallang.ISet; -import io.usethesource.vallang.ISourceLocation; -import io.usethesource.vallang.IString; -import io.usethesource.vallang.ITuple; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IWithKeywordParameters; -import io.usethesource.vallang.impl.primitive.StringValue; -import io.usethesource.vallang.type.ITypeVisitor; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeStore; -import io.usethesource.vallang.visitors.IValueVisitor; - -/** - * This class implements the standard readable syntax for {@link IValue}'s. - * See also {@link StandardTextReader} - */ -public class StandardTextWriter implements IValueTextWriter { - protected final boolean indent; - protected final int tabSize; - - public StandardTextWriter() { - this(false); - } - - public StandardTextWriter(boolean indent) { - this(indent, 2); - } - - public StandardTextWriter(boolean indent, int tabSize) { - this.indent = indent; - this.tabSize = tabSize; - } - - public static String valueToString(IValue value) { - try(StringWriter stream = new StringWriter()) { - new StandardTextWriter().write(value, stream); - return stream.toString(); - } catch (IOException ioex) { - throw new RuntimeException("Should have never happened.", ioex); - } - } - - public void write(IValue value, java.io.Writer stream) throws IOException { - try { - value.accept(new Writer(stream, indent, tabSize)); - } - finally { - stream.flush(); - } - } - - public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { - write(value, stream); - } - - protected static class Writer implements IValueVisitor { - private final java.io.Writer stream; - private final int tabSize; - private final boolean indent; - private int tab = 0; - - public Writer(java.io.Writer stream, boolean indent, int tabSize) { - this.stream = stream; - this.indent = indent; - this.tabSize = tabSize; - } - - private void append(String string) throws IOException { - stream.write(string); - } - - private void append(int cp) throws IOException { - if (Character.isBmpCodePoint(cp)) { - stream.write(cp); - } - else { - stream.write(Character.highSurrogate(cp)); - stream.write(Character.lowSurrogate(cp)); - } - } - - private void append(char c) throws IOException { - stream.write(c); - } - - private void tab() { - this.tab++; - } - - private void untab() { - this.tab--; - } - - @Override - public IValue visitBoolean(IBool boolValue) - throws IOException { - append(boolValue.getValue() ? "true" : "false"); - return boolValue; - } - - @Override - public IValue visitReal(IReal o) throws IOException { - append(o.getStringRepresentation()); - return o; - } - - @Override - public IValue visitInteger(IInteger o) throws IOException { - append(o.getStringRepresentation()); - return o; - } - - @Override - public IValue visitRational(IRational o) throws IOException { - append(o.getStringRepresentation()); - return o; - } - - @Override - public IValue visitList(IList o) throws IOException { - append('['); - - boolean indent = checkIndent(o); - Iterator listIterator = o.iterator(); - tab(); - indent(indent); - if(listIterator.hasNext()){ - listIterator.next().accept(this); - - while(listIterator.hasNext()){ - append(','); - if (indent) indent(); - listIterator.next().accept(this); - } - } - untab(); - indent(indent); - append(']'); - - return o; - } - - @Override - public IValue visitMap(IMap o) throws IOException { - append('('); - tab(); - boolean indent = checkIndent(o); - indent(indent); - Iterator> mapIterator = o.entryIterator(); - if(mapIterator.hasNext()){ - Entry entry = mapIterator.next(); - IValue key = entry.getKey(); - key.accept(this); - append(':'); - entry.getValue().accept(this); - - while(mapIterator.hasNext()){ - append(','); - indent(indent); - entry = mapIterator.next(); - key = entry.getKey(); - key.accept(this); - append(':'); - entry.getValue().accept(this); - } - } - untab(); - indent(indent); - append(')'); - - return o; - } - - @Override - public IValue visitConstructor(IConstructor o) throws IOException { - String name = o.getName(); - - if (name.equals("loc")) { - append('\\'); - } - - if (name.indexOf('-') != -1) { - append('\\'); - } - append(name); - - boolean indent = checkIndent(o); - - append('('); - tab(); - indent(indent); - Iterator it = o.iterator(); - int k = 0; - while (it.hasNext()) { - it.next().accept(this); - if (it.hasNext()) { - append(','); - indent(indent); - } - k++; - } - - if (o.mayHaveKeywordParameters()) { - IWithKeywordParameters wkw = o.asWithKeywordParameters(); - if (wkw.hasParameters()) { - if (k > 0) { - append(','); - indent(indent); - } - - Iterator> iterator = wkw.getParameters().entrySet().iterator(); - while (iterator.hasNext()) { - Entry e = iterator.next(); - - append(e.getKey()); - append('='); - e.getValue().accept(this); - - if (iterator.hasNext()) { - append(','); - indent(indent); - } - } - } - } - - append(')'); - untab(); - - try { - stream.flush(); - } - catch (IOException e) { - // flushing is just to make sure we get some intermediate output - } - - return o; - } - - private void indent() throws IOException { - indent(indent); - } - - private void indent(boolean indent) throws IOException { - if (indent) { - append('\n'); - for (int i = 0; i < tabSize * tab; i++) { - append(' '); - } - } - } - - @Override - public IValue visitSet(ISet o) throws IOException { - append('{'); - - boolean indent = checkIndent(o); - tab(); - indent(indent); - Iterator setIterator = o.iterator(); - if(setIterator.hasNext()){ - setIterator.next().accept(this); - - while(setIterator.hasNext()){ - append(","); - indent(indent); - setIterator.next().accept(this); - } - } - untab(); - indent(indent); - append('}'); - return o; - } - - private boolean checkIndent(ISet o) { - if (indent && o.size() > 1) { - for (IValue x : o) { - Type type = x.getType(); - return indented(type); - } - } - return false; - } - - private boolean indented(Type type) { - return type.accept(new ITypeVisitor() { - @Override - public Boolean visitReal(Type type) { - return false; - } - - @Override - public Boolean visitInteger(Type type) { - return false; - } - - @Override - public Boolean visitRational(Type type) { - return false; - } - - @Override - public Boolean visitList(Type type) { - return true; - } - - @Override - public Boolean visitMap(Type type) { - return true; - } - - @Override - public Boolean visitNumber(Type type) { - return false; - } - - @Override - public Boolean visitAlias(Type type) { - return type.getAliased().accept(this); - } - - @Override - public Boolean visitSet(Type type) { - return true; - } - - @Override - public Boolean visitSourceLocation(Type type) { - return true; - } - - @Override - public Boolean visitString(Type type) { - return false; - } - - @Override - public Boolean visitNode(Type type) { - return true; - } - - @Override - public Boolean visitConstructor(Type type) { - return true; - } - - @Override - public Boolean visitAbstractData(Type type) { - return true; - } - - @Override - public Boolean visitTuple(Type type) { - return true; - } - - @Override - public Boolean visitValue(Type type) { - return false; - } - - @Override - public Boolean visitFunction(Type type) { - return false; - } - - @Override - public Boolean visitVoid(Type type) { - return false; - } - - @Override - public Boolean visitBool(Type type) { - return false; - } - - @Override - public Boolean visitParameter(Type type) { - return type.getBound().accept(this); - } - - @Override - public Boolean visitExternal(Type type) { - return false; - } - - @Override - public Boolean visitDateTime(Type type) { - return false; - } - }); - } - - private boolean checkIndent(IList o) { - if (indent && o.length() > 1) { - for (IValue x : o) { - Type type = x.getType(); - if (indented(type)) { - return true; - } - } - } - return false; - } - - private boolean checkIndent(INode o) { - int kwArity = o.mayHaveKeywordParameters() ? o.asWithKeywordParameters().getParameters().size() : 0; - if (indent && (o.arity() + kwArity) > 1) { - for (IValue x : o) { - Type type = x.getType(); - if (indented(type)) { - return true; - } - } - if (o.mayHaveKeywordParameters()) { - for (IValue x : o.asWithKeywordParameters().getParameters().values()) { - Type type = x.getType(); - if (indented(type)) { - return true; - } - } - } - } - return false; - } - - private boolean checkIndent(IMap o) { - if (indent && o.size() > 1) { - for (Entry entry : (Iterable>) () -> o.entryIterator()) { - IValue x = entry.getKey(); - Type type = x.getType(); - Type vType = entry.getValue().getType(); - if (indented(type)) { - return true; - } - if (indented(vType)) { - return true; - } - } - } - return false; - } - - @Override - public IValue visitSourceLocation(ISourceLocation o) - throws IOException { - append('|'); - append(o.getURI().toString()); - append('|'); - - if (o.hasOffsetLength()) { - append('('); - append(Integer.toString(o.getOffset())); - append(','); - append(Integer.toString(o.getLength())); - - if (o.hasLineColumn()) { - append(','); - append('<'); - append(Integer.toString(o.getBeginLine())); - append(','); - append(Integer.toString(o.getBeginColumn())); - append('>'); - append(','); - append('<'); - append(Integer.toString(o.getEndLine())); - append(','); - append(Integer.toString(o.getEndColumn())); - append('>'); - } - append(')'); - } - return o; - } - - @Override - public IValue visitString(IString o) throws IOException { - append('\"'); - OfInt it = o.iterator(); - while (it.hasNext()) { - int ch = it.nextInt(); - - switch (ch) { - case '\"': - append('\\'); - append('\"'); - break; - case '>': - append('\\'); - append('>'); - break; - case '<': - append('\\'); - append('<'); - break; - case '\'': - append('\\'); - append('\''); - break; - case '\\': - append('\\'); - append('\\'); - break; - case '\n': - append('\\'); - append('n'); - break; - case '\r': - append('\\'); - append('r'); - break; - case '\t': - append('\\'); - append('t'); - break; - case ' ': - // needed because other space chars will be escaped in the default branch - append(' '); - break; - default: - if (Character.isSpaceChar(ch) - || Character.isISOControl(ch) - || Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(ch))) { - // these characters are invisible or otherwise unreadable and we escape them here - // for clarity of the serialized string - - if (ch <= Byte.MAX_VALUE) { - append("\\a" + String.format("%02x", ch)); - } - else if (ch <= Character.MAX_VALUE) { - append("\\u" + String.format("%04x", ch)); - } - else { - append("\\U" + String.format("%06x", ch)); - } - } - else { - append(ch); - } - } - } - append('\"'); - return o; - } - - @Override - public IValue visitTuple(ITuple o) throws IOException { - append('<'); - - Iterator it = o.iterator(); - - if (it.hasNext()) { - it.next().accept(this); - } - - while (it.hasNext()) { - append(','); - it.next().accept(this); - } - append('>'); - - return o; - } - - @Override - public IValue visitExternal(IExternalValue externalValue) throws IOException { - return visitConstructor(externalValue.encodeAsConstructor()); - } - - @Override - public IValue visitDateTime(IDateTime o) throws IOException { - append("$"); - if (o.isDate()) { - append(String.format("%04d", o.getYear())); - append("-"); - append(String.format("%02d", o.getMonthOfYear())); - append("-"); - append(String.format("%02d", o.getDayOfMonth())); - } else if (o.isTime()) { - append("T"); - append(String.format("%02d", o.getHourOfDay())); - append(":"); - append(String.format("%02d", o.getMinuteOfHour())); - append(":"); - append(String.format("%02d", o.getSecondOfMinute())); - append("."); - append(String.format("%03d", o.getMillisecondsOfSecond())); - if (o.getTimezoneOffsetHours() < 0 || (o.getTimezoneOffsetHours() == 0 && o.getTimezoneOffsetMinutes() < 0)) - append("-"); - else - append("+"); - append(String.format("%02d", Math.abs(o.getTimezoneOffsetHours()))); - append(":"); - append(String.format("%02d", Math.abs(o.getTimezoneOffsetMinutes()))); - } else { - append(String.format("%04d", o.getYear())); - append("-"); - append(String.format("%02d", o.getMonthOfYear())); - append("-"); - append(String.format("%02d", o.getDayOfMonth())); - - append("T"); - append(String.format("%02d", o.getHourOfDay())); - append(":"); - append(String.format("%02d", o.getMinuteOfHour())); - append(":"); - append(String.format("%02d", o.getSecondOfMinute())); - append("."); - append(String.format("%03d", o.getMillisecondsOfSecond())); - if (o.getTimezoneOffsetHours() < 0 || (o.getTimezoneOffsetHours() == 0 && o.getTimezoneOffsetMinutes() < 0)) - append("-"); - else - append("+"); - append(String.format("%02d", Math.abs(o.getTimezoneOffsetHours()))); - append(":"); - append(String.format("%02d", Math.abs(o.getTimezoneOffsetMinutes()))); - } - append("$"); - return o; - } - - @Override - public IValue visitNode(INode o) throws IOException { - visitString(StringValue.newString(o.getName())); - - boolean indent = checkIndent(o); - - append('('); - tab(); - indent(indent); - Iterator it = o.iterator(); - int k = 0; - while (it.hasNext()) { - it.next().accept(this); - if (it.hasNext()) { - append(','); - indent(indent); - } - k++; - } - - - if (o.mayHaveKeywordParameters()) { - IWithKeywordParameters wkw = o.asWithKeywordParameters(); - if (wkw.hasParameters()) { - if (k > 0) { - append(','); - } - - Iterator> kwIt = wkw.getParameters().entrySet().iterator(); - while (kwIt.hasNext()) { - Entry e = kwIt.next(); - indent(); - append(e.getKey()); - append('='); - e.getValue().accept(this); - - if (kwIt.hasNext()) { - append(','); - } - - } - } - } - append(')'); - untab(); - - return o; - } - } -} +/******************************************************************************* + * Copyright (c) CWI 2009-2017 + * 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 Vinju (jurgenv@cwi.nl) - initial API and implementation + *******************************************************************************/ +package io.usethesource.vallang.io; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.PrimitiveIterator.OfInt; + +import io.usethesource.vallang.IBool; +import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IDateTime; +import io.usethesource.vallang.IExternalValue; +import io.usethesource.vallang.IInteger; +import io.usethesource.vallang.IList; +import io.usethesource.vallang.IMap; +import io.usethesource.vallang.INode; +import io.usethesource.vallang.IRational; +import io.usethesource.vallang.IReal; +import io.usethesource.vallang.ISet; +import io.usethesource.vallang.ISourceLocation; +import io.usethesource.vallang.IString; +import io.usethesource.vallang.ITuple; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IWithKeywordParameters; +import io.usethesource.vallang.impl.primitive.StringValue; +import io.usethesource.vallang.type.ITypeVisitor; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeStore; +import io.usethesource.vallang.visitors.IValueVisitor; + +/** + * This class implements the standard readable syntax for {@link IValue}'s. + * See also {@link StandardTextReader} + */ +public class StandardTextWriter implements IValueTextWriter { + protected final boolean indent; + protected final int tabSize; + + public StandardTextWriter() { + this(false); + } + + public StandardTextWriter(boolean indent) { + this(indent, 2); + } + + public StandardTextWriter(boolean indent, int tabSize) { + this.indent = indent; + this.tabSize = tabSize; + } + + public static String valueToString(IValue value) { + try(StringWriter stream = new StringWriter()) { + new StandardTextWriter().write(value, stream); + return stream.toString(); + } catch (IOException ioex) { + throw new RuntimeException("Should have never happened.", ioex); + } + } + + public void write(IValue value, java.io.Writer stream) throws IOException { + try { + value.accept(new Writer(stream, indent, tabSize)); + } + finally { + stream.flush(); + } + } + + public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { + write(value, stream); + } + + protected static class Writer implements IValueVisitor { + private final java.io.Writer stream; + private final int tabSize; + private final boolean indent; + private int tab = 0; + + public Writer(java.io.Writer stream, boolean indent, int tabSize) { + this.stream = stream; + this.indent = indent; + this.tabSize = tabSize; + } + + private void append(String string) throws IOException { + stream.write(string); + } + + private void append(int cp) throws IOException { + if (Character.isBmpCodePoint(cp)) { + stream.write(cp); + } + else { + stream.write(Character.highSurrogate(cp)); + stream.write(Character.lowSurrogate(cp)); + } + } + + private void append(char c) throws IOException { + stream.write(c); + } + + private void tab() { + this.tab++; + } + + private void untab() { + this.tab--; + } + + @Override + public IValue visitBoolean(IBool boolValue) + throws IOException { + append(boolValue.getValue() ? "true" : "false"); + return boolValue; + } + + @Override + public IValue visitReal(IReal o) throws IOException { + append(o.getStringRepresentation()); + return o; + } + + @Override + public IValue visitInteger(IInteger o) throws IOException { + append(o.getStringRepresentation()); + return o; + } + + @Override + public IValue visitRational(IRational o) throws IOException { + append(o.getStringRepresentation()); + return o; + } + + @Override + public IValue visitList(IList o) throws IOException { + append('['); + + boolean indent = checkIndent(o); + Iterator listIterator = o.iterator(); + tab(); + indent(indent); + if(listIterator.hasNext()){ + listIterator.next().accept(this); + + while(listIterator.hasNext()){ + append(','); + if (indent) indent(); + listIterator.next().accept(this); + } + } + untab(); + indent(indent); + append(']'); + + return o; + } + + @Override + public IValue visitMap(IMap o) throws IOException { + append('('); + tab(); + boolean indent = checkIndent(o); + indent(indent); + Iterator> mapIterator = o.entryIterator(); + if(mapIterator.hasNext()){ + Entry entry = mapIterator.next(); + IValue key = entry.getKey(); + key.accept(this); + append(':'); + entry.getValue().accept(this); + + while(mapIterator.hasNext()){ + append(','); + indent(indent); + entry = mapIterator.next(); + key = entry.getKey(); + key.accept(this); + append(':'); + entry.getValue().accept(this); + } + } + untab(); + indent(indent); + append(')'); + + return o; + } + + @Override + public IValue visitConstructor(IConstructor o) throws IOException { + String name = o.getName(); + + if (name.equals("loc")) { + append('\\'); + } + + if (name.indexOf('-') != -1) { + append('\\'); + } + append(name); + + boolean indent = checkIndent(o); + + append('('); + tab(); + indent(indent); + Iterator it = o.iterator(); + int k = 0; + while (it.hasNext()) { + it.next().accept(this); + if (it.hasNext()) { + append(','); + indent(indent); + } + k++; + } + + if (o.mayHaveKeywordParameters()) { + IWithKeywordParameters wkw = o.asWithKeywordParameters(); + if (wkw.hasParameters()) { + if (k > 0) { + append(','); + indent(indent); + } + + Iterator> iterator = wkw.getParameters().entrySet().iterator(); + while (iterator.hasNext()) { + Entry e = iterator.next(); + + append(e.getKey()); + append('='); + e.getValue().accept(this); + + if (iterator.hasNext()) { + append(','); + indent(indent); + } + } + } + } + + append(')'); + untab(); + + try { + stream.flush(); + } + catch (IOException e) { + // flushing is just to make sure we get some intermediate output + } + + return o; + } + + private void indent() throws IOException { + indent(indent); + } + + private void indent(boolean indent) throws IOException { + if (indent) { + append('\n'); + for (int i = 0; i < tabSize * tab; i++) { + append(' '); + } + } + } + + @Override + public IValue visitSet(ISet o) throws IOException { + append('{'); + + boolean indent = checkIndent(o); + tab(); + indent(indent); + Iterator setIterator = o.iterator(); + if(setIterator.hasNext()){ + setIterator.next().accept(this); + + while(setIterator.hasNext()){ + append(","); + indent(indent); + setIterator.next().accept(this); + } + } + untab(); + indent(indent); + append('}'); + return o; + } + + private boolean checkIndent(ISet o) { + if (indent && o.size() > 1) { + for (IValue x : o) { + Type type = x.getType(); + return indented(type); + } + } + return false; + } + + private boolean indented(Type type) { + return type.accept(new ITypeVisitor() { + @Override + public Boolean visitReal(Type type) { + return false; + } + + @Override + public Boolean visitInteger(Type type) { + return false; + } + + @Override + public Boolean visitRational(Type type) { + return false; + } + + @Override + public Boolean visitList(Type type) { + return true; + } + + @Override + public Boolean visitMap(Type type) { + return true; + } + + @Override + public Boolean visitNumber(Type type) { + return false; + } + + @Override + public Boolean visitAlias(Type type) { + return type.getAliased().accept(this); + } + + @Override + public Boolean visitSet(Type type) { + return true; + } + + @Override + public Boolean visitSourceLocation(Type type) { + return true; + } + + @Override + public Boolean visitString(Type type) { + return false; + } + + @Override + public Boolean visitNode(Type type) { + return true; + } + + @Override + public Boolean visitConstructor(Type type) { + return true; + } + + @Override + public Boolean visitAbstractData(Type type) { + return true; + } + + @Override + public Boolean visitTuple(Type type) { + return true; + } + + @Override + public Boolean visitValue(Type type) { + return false; + } + + @Override + public Boolean visitFunction(Type type) { + return false; + } + + @Override + public Boolean visitVoid(Type type) { + return false; + } + + @Override + public Boolean visitBool(Type type) { + return false; + } + + @Override + public Boolean visitParameter(Type type) { + return type.getBound().accept(this); + } + + @Override + public Boolean visitExternal(Type type) { + return false; + } + + @Override + public Boolean visitDateTime(Type type) { + return false; + } + }); + } + + private boolean checkIndent(IList o) { + if (indent && o.length() > 1) { + for (IValue x : o) { + Type type = x.getType(); + if (indented(type)) { + return true; + } + } + } + return false; + } + + private boolean checkIndent(INode o) { + int kwArity = o.mayHaveKeywordParameters() ? o.asWithKeywordParameters().getParameters().size() : 0; + if (indent && (o.arity() + kwArity) > 1) { + for (IValue x : o) { + Type type = x.getType(); + if (indented(type)) { + return true; + } + } + if (o.mayHaveKeywordParameters()) { + for (IValue x : o.asWithKeywordParameters().getParameters().values()) { + Type type = x.getType(); + if (indented(type)) { + return true; + } + } + } + } + return false; + } + + private boolean checkIndent(IMap o) { + if (indent && o.size() > 1) { + for (Entry entry : (Iterable>) () -> o.entryIterator()) { + IValue x = entry.getKey(); + Type type = x.getType(); + Type vType = entry.getValue().getType(); + if (indented(type)) { + return true; + } + if (indented(vType)) { + return true; + } + } + } + return false; + } + + @Override + public IValue visitSourceLocation(ISourceLocation o) + throws IOException { + append('|'); + append(o.getURI().toString()); + append('|'); + + if (o.hasOffsetLength()) { + append('('); + append(Integer.toString(o.getOffset())); + append(','); + append(Integer.toString(o.getLength())); + + if (o.hasLineColumn()) { + append(','); + append('<'); + append(Integer.toString(o.getBeginLine())); + append(','); + append(Integer.toString(o.getBeginColumn())); + append('>'); + append(','); + append('<'); + append(Integer.toString(o.getEndLine())); + append(','); + append(Integer.toString(o.getEndColumn())); + append('>'); + } + append(')'); + } + return o; + } + + @Override + public IValue visitString(IString o) throws IOException { + append('\"'); + OfInt it = o.iterator(); + while (it.hasNext()) { + int ch = it.nextInt(); + + switch (ch) { + case '\"': + append('\\'); + append('\"'); + break; + case '>': + append('\\'); + append('>'); + break; + case '<': + append('\\'); + append('<'); + break; + case '\'': + append('\\'); + append('\''); + break; + case '\\': + append('\\'); + append('\\'); + break; + case '\n': + append('\\'); + append('n'); + break; + case '\r': + append('\\'); + append('r'); + break; + case '\t': + append('\\'); + append('t'); + break; + case ' ': + // needed because other space chars will be escaped in the default branch + append(' '); + break; + default: + if (Character.isSpaceChar(ch) + || Character.isISOControl(ch) + || Character.UnicodeBlock.SPECIALS.equals(Character.UnicodeBlock.of(ch))) { + // these characters are invisible or otherwise unreadable and we escape them here + // for clarity of the serialized string + + if (ch <= Byte.MAX_VALUE) { + append("\\a" + String.format("%02x", ch)); + } + else if (ch <= Character.MAX_VALUE) { + append("\\u" + String.format("%04x", ch)); + } + else { + append("\\U" + String.format("%06x", ch)); + } + } + else { + append(ch); + } + } + } + append('\"'); + return o; + } + + @Override + public IValue visitTuple(ITuple o) throws IOException { + append('<'); + + Iterator it = o.iterator(); + + if (it.hasNext()) { + it.next().accept(this); + } + + while (it.hasNext()) { + append(','); + it.next().accept(this); + } + append('>'); + + return o; + } + + @Override + public IValue visitExternal(IExternalValue externalValue) throws IOException { + return visitConstructor(externalValue.encodeAsConstructor()); + } + + @Override + public IValue visitDateTime(IDateTime o) throws IOException { + append("$"); + if (o.isDate()) { + append(String.format("%04d", o.getYear())); + append("-"); + append(String.format("%02d", o.getMonthOfYear())); + append("-"); + append(String.format("%02d", o.getDayOfMonth())); + } else if (o.isTime()) { + append("T"); + append(String.format("%02d", o.getHourOfDay())); + append(":"); + append(String.format("%02d", o.getMinuteOfHour())); + append(":"); + append(String.format("%02d", o.getSecondOfMinute())); + append("."); + append(String.format("%03d", o.getMillisecondsOfSecond())); + if (o.getTimezoneOffsetHours() < 0 || (o.getTimezoneOffsetHours() == 0 && o.getTimezoneOffsetMinutes() < 0)) + append("-"); + else + append("+"); + append(String.format("%02d", Math.abs(o.getTimezoneOffsetHours()))); + append(":"); + append(String.format("%02d", Math.abs(o.getTimezoneOffsetMinutes()))); + } else { + append(String.format("%04d", o.getYear())); + append("-"); + append(String.format("%02d", o.getMonthOfYear())); + append("-"); + append(String.format("%02d", o.getDayOfMonth())); + + append("T"); + append(String.format("%02d", o.getHourOfDay())); + append(":"); + append(String.format("%02d", o.getMinuteOfHour())); + append(":"); + append(String.format("%02d", o.getSecondOfMinute())); + append("."); + append(String.format("%03d", o.getMillisecondsOfSecond())); + if (o.getTimezoneOffsetHours() < 0 || (o.getTimezoneOffsetHours() == 0 && o.getTimezoneOffsetMinutes() < 0)) + append("-"); + else + append("+"); + append(String.format("%02d", Math.abs(o.getTimezoneOffsetHours()))); + append(":"); + append(String.format("%02d", Math.abs(o.getTimezoneOffsetMinutes()))); + } + append("$"); + return o; + } + + @Override + public IValue visitNode(INode o) throws IOException { + visitString(StringValue.newString(o.getName())); + + boolean indent = checkIndent(o); + + append('('); + tab(); + indent(indent); + Iterator it = o.iterator(); + int k = 0; + while (it.hasNext()) { + it.next().accept(this); + if (it.hasNext()) { + append(','); + indent(indent); + } + k++; + } + + + if (o.mayHaveKeywordParameters()) { + IWithKeywordParameters wkw = o.asWithKeywordParameters(); + if (wkw.hasParameters()) { + if (k > 0) { + append(','); + } + + Iterator> kwIt = wkw.getParameters().entrySet().iterator(); + while (kwIt.hasNext()) { + Entry e = kwIt.next(); + indent(); + append(e.getKey()); + append('='); + e.getValue().accept(this); + + if (kwIt.hasNext()) { + append(','); + } + + } + } + } + append(')'); + untab(); + + return o; + } + } +} diff --git a/src/main/java/io/usethesource/vallang/io/XMLReader.java b/src/main/java/io/usethesource/vallang/io/XMLReader.java index 49b63dbcf..f90002853 100644 --- a/src/main/java/io/usethesource/vallang/io/XMLReader.java +++ b/src/main/java/io/usethesource/vallang/io/XMLReader.java @@ -56,15 +56,15 @@ * lists of lists, tuples of tuples, lists in tuples, sets in tuples, etc. * If such nesting is needed, it is required to use a wrapping tree node. * - * There is no support for NamedTypes yet, only TreeSortType and ConstructorType are + * There is no support for NamedTypes yet, only TreeSortType and ConstructorType are * allowed. - * + * * The limitations of this class are governed by wanting to avoid ambiguity * while validating XML using the pdb's type system and the inherent impedance * mismatch between the type system of pdb and the structure of XML. - * + * * Use this class to import many forms of XML data into PDB. - * + * */ public class XMLReader extends AbstractTextReader { private static final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); @@ -90,7 +90,7 @@ public IValue read(IValueFactory factory, TypeStore store, Type type, Reader str private static class Parser { private final IValueFactory vf; private final TypeStore ts; - + public Parser(IValueFactory vf, TypeStore ts) { this.vf = vf; this.ts = ts; @@ -286,7 +286,7 @@ private IValue parseRelation(Node node, Type expected) { IValue[] elements = new IValue[fields.getArity()]; for (int j = 0; i < children.getLength() && j < fields.getArity(); j++) { - elements[j] = parse(children.item(i++), fields.getFieldType(j)); + elements[j] = parse(children.item(i++), fields.getFieldType(j)); } @SuppressWarnings("nullness") @@ -316,7 +316,7 @@ private IValue parseSet(Node node, Type expected) { IValue[] elements = new IValue[tuple.getArity()]; for (int j = 0; i < children.getLength() && j < tuple.getArity(); j++) { - elements[j] = parse(children.item(i++), tuple.getFieldType(j)); + elements[j] = parse(children.item(i++), tuple.getFieldType(j)); } @SuppressWarnings("nullness") @@ -347,7 +347,7 @@ private IValue parseList(Node node, Type expected) { IValue[] elements = new IValue[tuple.getArity()]; for (int j = 0; i < children.getLength() && j < tuple.getArity(); j++) { - elements[j] = parse(children.item(i++), tuple.getFieldType(j)); + elements[j] = parse(children.item(i++), tuple.getFieldType(j)); } @SuppressWarnings("nullness") diff --git a/src/main/java/io/usethesource/vallang/io/XMLWriter.java b/src/main/java/io/usethesource/vallang/io/XMLWriter.java index b5cd898a8..856ec344d 100644 --- a/src/main/java/io/usethesource/vallang/io/XMLWriter.java +++ b/src/main/java/io/usethesource/vallang/io/XMLWriter.java @@ -45,213 +45,213 @@ import io.usethesource.vallang.type.TypeStore; /** - * This IValueWriter serializes values to XML documents. - * It will not serialize all IValues, see XMLReader for limitations. + * This IValueWriter serializes values to XML documents. + * It will not serialize all IValues, see XMLReader for limitations. */ public class XMLWriter implements IValueTextWriter { private static final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - public void write(IValue value, java.io.Writer stream) throws IOException { - try { - Document doc = dbf.newDocumentBuilder().newDocument(); - - Node top = give(value, doc); - doc.appendChild(top); - - Transformer t = TransformerFactory.newInstance().newTransformer(); - t.setOutputProperty(OutputKeys.INDENT, "yes"); - - t.transform(new DOMSource(doc), new StreamResult(stream)); - } catch (ParserConfigurationException e) { - throw new IOException("XML configuration is invalid: " + e.getMessage()); - } catch (TransformerException e) { - throw new IOException("Exception while serializing XML: " + e.getMessage()); - } catch (DOMException e) { - throw new UnsupportedTypeException("" + e.getMessage(), value.getType()); - } - } - - public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { - write(value, stream); - } - - private Node give(IValue value, Document doc) { - Type type = value.getType(); - - if (type.isAbstractData()) { - Type node = ((IConstructor) value).getConstructorType(); - - if (isListWrapper(node)) { - return giveList((INode) value, doc); - } - else if (isSetWrapper(node)) { - return giveSet((INode) value, doc); - } - else if (isRelationWrapper(node)) { - return giveRelation((INode) value, doc); - } - else if (isMapWrapper(node)) { - return giveMap((INode) value, doc); - } - else { - return giveTree((INode) value, doc); - } - } - else if (type.isString()) { - return giveString((IString) value, doc); - } - else if (type.isInteger()) { - return giveInt((IInteger) value, doc); - } - else if (type.isRational()) { - return giveRational((IRational) value, doc); - } - else if (type.isReal()) { - return giveDouble((IReal) value, doc); - } - else if (type.isExternalType()) { - return giveExternal((IExternalValue) value, doc); - } - - throw new UnsupportedTypeException( - "Outermost or nested tuples, lists, sets, relations or maps are not allowed.", type); - } - - private boolean isListWrapper(Type nodeType) { - return nodeType.getArity() == 1 - && nodeType.getFieldTypes().getFieldType(0).isList(); - } - - private boolean isSetWrapper(Type nodeType) { - return nodeType.getArity() == 1 - && nodeType.getFieldTypes().getFieldType(0).isSet(); - } - - private boolean isRelationWrapper(Type nodeType) { - return nodeType.getArity() == 1 - && nodeType.getFieldTypes().getFieldType(0) - .isRelation(); - } - - private boolean isMapWrapper(Type nodeType) { - return nodeType.getArity() == 1 - && nodeType.getFieldTypes().getFieldType(0).isMap(); - } - - - private Node giveDouble(IReal value, Document doc) { - return doc.createTextNode(value.toString()); - } - - private Node giveInt(IInteger value, Document doc) { - return doc.createTextNode(value.toString()); - } - - private Node giveRational(IRational value, Document doc) { - Element element = doc.createElementNS("values", "rat"); - element.setAttribute("num", value.numerator().toString()); - element.setAttribute("denom", value.denominator().toString()); - return element; - } - - private Node giveString(IString value, Document doc) { - return doc.createTextNode(value.getValue()); - } - - private Node giveExternal(IExternalValue value, Document doc) { - return doc.createTextNode(value.toString()); - } - - private Node giveMap(INode node, Document doc) { - Element treeNode = doc.createElement(node.getName()); - IMap map = (IMap) node.get(0); - - for (Entry entry : (Iterable>) () -> map.entryIterator()) { - IValue key = entry.getKey(); - IValue value = entry.getValue(); - - if (key.getType().isTuple()) { + + public void write(IValue value, java.io.Writer stream) throws IOException { + try { + Document doc = dbf.newDocumentBuilder().newDocument(); + + Node top = give(value, doc); + doc.appendChild(top); + + Transformer t = TransformerFactory.newInstance().newTransformer(); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + + t.transform(new DOMSource(doc), new StreamResult(stream)); + } catch (ParserConfigurationException e) { + throw new IOException("XML configuration is invalid: " + e.getMessage()); + } catch (TransformerException e) { + throw new IOException("Exception while serializing XML: " + e.getMessage()); + } catch (DOMException e) { + throw new UnsupportedTypeException("" + e.getMessage(), value.getType()); + } + } + + public void write(IValue value, java.io.Writer stream, TypeStore typeStore) throws IOException { + write(value, stream); + } + + private Node give(IValue value, Document doc) { + Type type = value.getType(); + + if (type.isAbstractData()) { + Type node = ((IConstructor) value).getConstructorType(); + + if (isListWrapper(node)) { + return giveList((INode) value, doc); + } + else if (isSetWrapper(node)) { + return giveSet((INode) value, doc); + } + else if (isRelationWrapper(node)) { + return giveRelation((INode) value, doc); + } + else if (isMapWrapper(node)) { + return giveMap((INode) value, doc); + } + else { + return giveTree((INode) value, doc); + } + } + else if (type.isString()) { + return giveString((IString) value, doc); + } + else if (type.isInteger()) { + return giveInt((IInteger) value, doc); + } + else if (type.isRational()) { + return giveRational((IRational) value, doc); + } + else if (type.isReal()) { + return giveDouble((IReal) value, doc); + } + else if (type.isExternalType()) { + return giveExternal((IExternalValue) value, doc); + } + + throw new UnsupportedTypeException( + "Outermost or nested tuples, lists, sets, relations or maps are not allowed.", type); + } + + private boolean isListWrapper(Type nodeType) { + return nodeType.getArity() == 1 + && nodeType.getFieldTypes().getFieldType(0).isList(); + } + + private boolean isSetWrapper(Type nodeType) { + return nodeType.getArity() == 1 + && nodeType.getFieldTypes().getFieldType(0).isSet(); + } + + private boolean isRelationWrapper(Type nodeType) { + return nodeType.getArity() == 1 + && nodeType.getFieldTypes().getFieldType(0) + .isRelation(); + } + + private boolean isMapWrapper(Type nodeType) { + return nodeType.getArity() == 1 + && nodeType.getFieldTypes().getFieldType(0).isMap(); + } + + + private Node giveDouble(IReal value, Document doc) { + return doc.createTextNode(value.toString()); + } + + private Node giveInt(IInteger value, Document doc) { + return doc.createTextNode(value.toString()); + } + + private Node giveRational(IRational value, Document doc) { + Element element = doc.createElementNS("values", "rat"); + element.setAttribute("num", value.numerator().toString()); + element.setAttribute("denom", value.denominator().toString()); + return element; + } + + private Node giveString(IString value, Document doc) { + return doc.createTextNode(value.getValue()); + } + + private Node giveExternal(IExternalValue value, Document doc) { + return doc.createTextNode(value.toString()); + } + + private Node giveMap(INode node, Document doc) { + Element treeNode = doc.createElement(node.getName()); + IMap map = (IMap) node.get(0); + + for (Entry entry : (Iterable>) () -> map.entryIterator()) { + IValue key = entry.getKey(); + IValue value = entry.getValue(); + + if (key.getType().isTuple()) { appendTupleElements(doc, treeNode, key); } else { - treeNode.appendChild(give(key, doc)); + treeNode.appendChild(give(key, doc)); } - + if (value.getType().isTuple()) { appendTupleElements(doc, treeNode, value); } else { treeNode.appendChild(give(value, doc)); } - } - - return treeNode; - } - - private void appendTupleElements(Document doc, Element treeNode, IValue tupleValue) { - ITuple tuple = (ITuple) tupleValue; - - for (IValue element : tuple) { - treeNode.appendChild(give(element, doc)); - } - } - - private Node giveRelation(INode node, Document doc) { - Element treeNode = doc.createElement(node.getName()); - ISet relation = (ISet) node.get(0); - assert (relation.getType().isRelation()); - - for (IValue tuple : relation) { - appendTupleElements(doc, treeNode, tuple); - } - - return treeNode; - } - - private Node giveSet(INode node, Document doc) { - Element treeNode = doc.createElement(node.getName()); - ISet set = (ISet) node.get(0); - - for (IValue elem : set) { - if (elem.getType().isTuple()) { - appendTupleElements(doc, treeNode, elem); - } - else { - treeNode.appendChild(give(elem, doc)); - } - } - - return treeNode; - } - - private Node giveList(INode node, Document doc) { - Element treeNode = doc.createElement(node.getName()); - IList list = (IList) node.get(0); - - for (IValue elem : list) { - if (elem.getType().isTuple()) { - appendTupleElements(doc, treeNode, elem); - } - else { - treeNode.appendChild(give(elem, doc)); - } - } - - return treeNode; - } - - private Node giveTree(INode value, Document doc) { - Element treeNode = doc.createElement(value.getName()); - - for (IValue child : value) { - if (child.getType().isTuple()) { - appendTupleElements(doc, treeNode, child); - } - else { - treeNode.appendChild(give(child, doc)); - } - } - - return treeNode; - } + } + + return treeNode; + } + + private void appendTupleElements(Document doc, Element treeNode, IValue tupleValue) { + ITuple tuple = (ITuple) tupleValue; + + for (IValue element : tuple) { + treeNode.appendChild(give(element, doc)); + } + } + + private Node giveRelation(INode node, Document doc) { + Element treeNode = doc.createElement(node.getName()); + ISet relation = (ISet) node.get(0); + assert (relation.getType().isRelation()); + + for (IValue tuple : relation) { + appendTupleElements(doc, treeNode, tuple); + } + + return treeNode; + } + + private Node giveSet(INode node, Document doc) { + Element treeNode = doc.createElement(node.getName()); + ISet set = (ISet) node.get(0); + + for (IValue elem : set) { + if (elem.getType().isTuple()) { + appendTupleElements(doc, treeNode, elem); + } + else { + treeNode.appendChild(give(elem, doc)); + } + } + + return treeNode; + } + + private Node giveList(INode node, Document doc) { + Element treeNode = doc.createElement(node.getName()); + IList list = (IList) node.get(0); + + for (IValue elem : list) { + if (elem.getType().isTuple()) { + appendTupleElements(doc, treeNode, elem); + } + else { + treeNode.appendChild(give(elem, doc)); + } + } + + return treeNode; + } + + private Node giveTree(INode value, Document doc) { + Element treeNode = doc.createElement(value.getName()); + + for (IValue child : value) { + if (child.getType().isTuple()) { + appendTupleElements(doc, treeNode, child); + } + else { + treeNode.appendChild(give(child, doc)); + } + } + + return treeNode; + } } diff --git a/src/main/java/io/usethesource/vallang/io/binary/message/IValueIDs.java b/src/main/java/io/usethesource/vallang/io/binary/message/IValueIDs.java index b2cda2791..5ef7199df 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/message/IValueIDs.java +++ b/src/main/java/io/usethesource/vallang/io/binary/message/IValueIDs.java @@ -1,29 +1,29 @@ -/** - * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.message; /** * Constants for Rascal Serialization Format */ public class IValueIDs { - + // This is an overview of the message id's, low values are quicker and more compact to encode // Never change them, that would break backwards compatiblity - - private static final int HEADER_ID = 4242; + + private static final int HEADER_ID = 4242; private static final int LAST_VALUE_ID = 4243; // a special marker to signal the end of the stream of values private static final int LAST_TYPE_ID = 4342; // a special marker to signal the end of the stream of types - + public static final class Header { public static final int ID = HEADER_ID; public static final int VALUE_WINDOW = 1; @@ -38,7 +38,7 @@ public static final class LastValue { public static final class LastType { public static final int ID = LAST_TYPE_ID; } - + // Atomic values private static final int PREVIOUS_VALUE_ID = 1; private static final int BOOLEAN_VALUE_ID = 2; @@ -48,9 +48,9 @@ public static final class LastType { private static final int STRING_VALUE_ID = 6; // above 32 for less often occuring messages (they take a byte extra to encode and decode) - private static final int DATETIME_VALUE_ID = 32; + private static final int DATETIME_VALUE_ID = 32; private static final int RAT_VALUE_ID = 33; - + // Compound values private static final int CONSTRUCTOR_VALUE_ID = 7; @@ -61,21 +61,21 @@ public static final class LastType { private static final int SET_VALUE_ID = 12; private static final int NAMED_VALUES_ID = 13; // WARNING: when adding here, don't forget to update the ranges at the end of this class - + public static class Common { public static final int CAN_BE_BACK_REFERENCED = 31; } - + public static class PreviousValue { public static final int ID = PREVIOUS_VALUE_ID; - public static final int HOW_FAR_BACK = 1; + public static final int HOW_FAR_BACK = 1; } public static class BoolValue { public static final int ID = BOOLEAN_VALUE_ID; public static final int VALUE = 1; } - + public static class DateTimeValue { public static final int ID = DATETIME_VALUE_ID; public static final int YEAR = 1; @@ -88,13 +88,13 @@ public static class DateTimeValue { public static final int TZ_HOUR = 8; public static final int TZ_MINUTE = 9; } - + public static class IntegerValue { public static final int ID = INTEGER_VALUE_ID; public static final int INTVALUE = 1; public static final int BIGVALUE = 2; } - + public static class SourceLocationValue { public static final int ID = SOURCE_LOCATION_VALUE_ID; public static final int PREVIOUS_URI = 1; @@ -116,18 +116,18 @@ public static class RationalValue { public static final int NUMERATOR = 1; public static final int DENOMINATOR = 2; } - + public static class RealValue { public static final int ID = REAL_VALUE_ID; public static final int CONTENT = 1; public static final int SCALE = 2; } - + public static class StringValue { public static final int ID = STRING_VALUE_ID; public static final int CONTENT = 1; } - + public static class ConstructorValue { public static final int ID = CONSTRUCTOR_VALUE_ID; public static final int PARAMS = 1; @@ -148,12 +148,12 @@ public static class TupleValue { public static final int ID = TUPLE_VALUE_ID; public static final int CHILDREN = 1; } - + public static class ListValue { public static final int ID = LIST_VALUE_ID; public static final int ELEMENTS = 1; } - + public static class MapValue { public static final int ID = MAP_VALUE_ID; public static final int KV_PAIRS = 1; @@ -173,7 +173,7 @@ public static class NamedValues { // Types aren't serialized that often so the overhead is acceptable private static final int PREVIOUS_TYPE_ID_ID = 101; - + // Atomic types private static final int BOOL_TYPE_ID = 102; private static final int LOC_TYPE_ID = 103; @@ -185,7 +185,7 @@ public static class NamedValues { private static final int STR_TYPE_ID = 109; private static final int VALUE_TYPE_ID = 110; private static final int VOID_TYPE_ID = 111; - + // Compound types private static final int NODE_TYPE_ID = 112; private static final int ADT_TYPE_ID = 113; @@ -198,7 +198,7 @@ public static class NamedValues { private static final int PARAMETER_TYPE_ID = 120; private static final int ALIAS_TYPE_ID = 121; private static final int FUNCTION_TYPE_ID = 122; - + public static class PreviousType { public static final int ID = PREVIOUS_TYPE_ID_ID; public static final int HOW_LONG_AGO = 1; @@ -240,7 +240,7 @@ public static class ParameterType { public static final int NAME = 1; public static final int BOUND = 2; } - + public static class ADTType { public static final int ID = ADT_TYPE_ID; public static final int NAME = 1; @@ -252,7 +252,7 @@ public static class ConstructorType { public static final int ADT = 2; public static final int FIELD_TYPES = 3; } - + public static class AliasType { public static final int ID = ALIAS_TYPE_ID; public static final int NAME = 1; @@ -272,22 +272,22 @@ public static class MapType { public static final int KEY_TYPE = 1; public static final int VALUE_TYPE = 2; } - + public static class NodeType { public static final int ID = NODE_TYPE_ID; } - + public static class ExternalType { public static final int ID = EXTERNAL_TYPE_ID; public static final int SYMBOL = 1; } - + public static class TupleType { public static final int ID = TUPLE_TYPE_ID; public static final int NAMES = 1; public static final int TYPES = 2; } - + public static final class Ranges { // these ranges are for splitting up the reader public static final int VALUES_MIN = PREVIOUS_VALUE_ID; @@ -295,7 +295,7 @@ public static final class Ranges { public static final int COMMON_VALUES_MIN = PREVIOUS_VALUE_ID; public static final int COMMON_VALUES_MAX = SET_VALUE_ID; - + public static final int TYPES_MIN = PREVIOUS_TYPE_ID_ID; public static final int TYPES_MAX = FUNCTION_TYPE_ID; } diff --git a/src/main/java/io/usethesource/vallang/io/binary/message/IValueReader.java b/src/main/java/io/usethesource/vallang/io/binary/message/IValueReader.java index 95b7d88b9..ce2e507b1 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/message/IValueReader.java +++ b/src/main/java/io/usethesource/vallang/io/binary/message/IValueReader.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.message; import java.io.IOException; @@ -87,7 +87,7 @@ public static IValue readValue(IWireInputStream reader, IValueFactory vf, Suppli } /** - * Read a type from the wire reader. + * Read a type from the wire reader. */ public static Type readType(IWireInputStream reader, IValueFactory vf, Supplier typeStoreSupplier) throws IOException { int typeWindowSize = 0; @@ -146,58 +146,58 @@ private void done() { private final TrackLastRead typeWindow; private final TrackLastRead valueWindow; private final TrackLastRead uriWindow; - + @SuppressWarnings("deprecation") private Type readType(final IWireInputStream reader) throws IOException{ reader.next(); switch (reader.message()) { - case IValueIDs.BoolType.ID: + case IValueIDs.BoolType.ID: reader.skipMessage(); // forward to the end return tf.boolType(); - case IValueIDs.DateTimeType.ID: + case IValueIDs.DateTimeType.ID: reader.skipMessage(); return tf.dateTimeType(); - case IValueIDs.IntegerType.ID: - reader.skipMessage(); + case IValueIDs.IntegerType.ID: + reader.skipMessage(); return tf.integerType(); - case IValueIDs.NodeType.ID: + case IValueIDs.NodeType.ID: reader.skipMessage(); return tf.nodeType(); - case IValueIDs.NumberType.ID: + case IValueIDs.NumberType.ID: reader.skipMessage(); return tf.numberType(); - case IValueIDs.RationalType.ID: + case IValueIDs.RationalType.ID: reader.skipMessage(); return tf.rationalType(); - case IValueIDs.RealType.ID: + case IValueIDs.RealType.ID: reader.skipMessage(); return tf.realType(); - case IValueIDs.SourceLocationType.ID: + case IValueIDs.SourceLocationType.ID: reader.skipMessage(); return tf.sourceLocationType(); - case IValueIDs.StringType.ID: + case IValueIDs.StringType.ID: reader.skipMessage(); return tf.stringType(); - case IValueIDs.ValueType.ID: + case IValueIDs.ValueType.ID: reader.skipMessage(); return tf.valueType(); - case IValueIDs.VoidType.ID: + case IValueIDs.VoidType.ID: reader.skipMessage(); return tf.voidType(); // Composite types - case IValueIDs.ADTType.ID: { + case IValueIDs.ADTType.ID: { String name = ""; boolean backReference = false; Type typeParam = VOID_TYPE; @@ -205,10 +205,10 @@ private Type readType(final IWireInputStream reader) throws IOException{ while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.ADTType.NAME: - name = reader.getString(); + name = reader.getString(); break; case IValueIDs.ADTType.TYPE_PARAMS: typeParam = readType(reader); @@ -223,7 +223,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ return returnAndStore(backReference, typeWindow, tf.abstractDataTypeFromTuple(store, name, typeParam)); } - case IValueIDs.AliasType.ID: { + case IValueIDs.AliasType.ID: { String name = ""; boolean backReference = false; Type typeParameters = VOID_TYPE; @@ -232,10 +232,10 @@ private Type readType(final IWireInputStream reader) throws IOException{ while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.AliasType.NAME: - name = reader.getString(); + name = reader.getString(); break; case IValueIDs.AliasType.ALIASED: aliasedType = readType(reader); @@ -263,10 +263,10 @@ private Type readType(final IWireInputStream reader) throws IOException{ while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.ConstructorType.NAME: - name = reader.getString(); + name = reader.getString(); break; case IValueIDs.ConstructorType.ADT: adtType = readType(reader); @@ -285,12 +285,12 @@ private Type readType(final IWireInputStream reader) throws IOException{ // External case IValueIDs.ExternalType.ID: { - boolean backReference = false; + boolean backReference = false; @MonotonicNonNull IConstructor symbol = null; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.ExternalType.SYMBOL: symbol = (IConstructor) readValue(reader); @@ -315,7 +315,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.ListType.ELEMENT_TYPE: elemType = readType(reader); @@ -325,14 +325,14 @@ private Type readType(final IWireInputStream reader) throws IOException{ return returnAndStore(backReference, typeWindow, tf.listType(elemType)); } - case IValueIDs.MapType.ID: { + case IValueIDs.MapType.ID: { boolean backReference = false; Type valType = VOID_TYPE; Type keyType = VOID_TYPE; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.MapType.KEY_TYPE: keyType = readType(reader); @@ -351,17 +351,17 @@ private Type readType(final IWireInputStream reader) throws IOException{ Type bound = VOID_TYPE; while (reader.next() != IWireInputStream.MESSAGE_END) { - switch (reader.field()){ + switch (reader.field()){ case IValueIDs.ParameterType.NAME: name = reader.getString(); break; case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.ParameterType.BOUND: bound = readType(reader); break; - + } } assert !name.isEmpty(); @@ -375,7 +375,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; case IValueIDs.SetType.ELEMENT_TYPE: elemType = readType(reader); @@ -391,7 +391,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ Type[] elemTypes = new Type[0]; while (reader.next() != IWireInputStream.MESSAGE_END) { - switch (reader.field()){ + switch (reader.field()){ case IValueIDs.TupleType.NAMES: fieldNames = reader.getStrings(); break; @@ -402,7 +402,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ } break; case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + backReference = true; break; } } @@ -418,7 +418,7 @@ private Type readType(final IWireInputStream reader) throws IOException{ case IValueIDs.PreviousType.ID: { int n = -1; while (reader.next() != IWireInputStream.MESSAGE_END) { - switch (reader.field()){ + switch (reader.field()){ case IValueIDs.PreviousType.HOW_LONG_AGO: n = reader.getInteger(); break; @@ -492,14 +492,14 @@ private IValue readTuple(final IWireInputStream reader) throws IOException { IValue[] children = new IValue[0]; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()) { - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; case IValueIDs.TupleValue.CHILDREN: int size = reader.getRepeatedLength(); children = new IValue[size]; switch (size) { - case 1: + case 1: children[0] = readValue(reader); break; case 2: @@ -526,8 +526,8 @@ private IValue readSet(final IWireInputStream reader) throws IOException { boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()) { - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; case IValueIDs.SetValue.ELEMENTS: int size = reader.getRepeatedLength(); @@ -560,8 +560,8 @@ private IValue readList(final IWireInputStream reader) throws IOException { boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()) { - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; case IValueIDs.ListValue.ELEMENTS: int size = reader.getRepeatedLength(); @@ -596,8 +596,8 @@ private IValue readMap(final IWireInputStream reader) throws IOException { boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()) { - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; case IValueIDs.MapValue.KV_PAIRS: int size = reader.getRepeatedLength(); @@ -622,33 +622,33 @@ private IValue readNode(final IWireInputStream reader) throws IOException { boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; - case IValueIDs.NodeValue.NAME: - name = reader.getString(); + case IValueIDs.NodeValue.NAME: + name = reader.getString(); break; - case IValueIDs.NodeValue.PARAMS: + case IValueIDs.NodeValue.PARAMS: children = new IValue[reader.getRepeatedLength()]; for (int i = 0; i < children.length; i++) { children[i] = readValue(reader); } break; - case IValueIDs.NodeValue.KWPARAMS: + case IValueIDs.NodeValue.KWPARAMS: kwParams = readNamedValues(reader); break; - case IValueIDs.NodeValue.ANNOS: + case IValueIDs.NodeValue.ANNOS: annos = readNamedValues(reader); break; } } INode node = vf.node(name, children); - + if (!annos.isEmpty()) { kwParams = simulateAnnotationsWithKeywordParameters(tf.nodeType(), kwParams, annos); } - + if (!kwParams.isEmpty()) { node = node.asWithKeywordParameters().setParameters(kwParams); } @@ -666,13 +666,13 @@ private IValue readConstructor(final IWireInputStream reader) throws IOException boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()){ - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; - case IValueIDs.ConstructorValue.TYPE: + case IValueIDs.ConstructorValue.TYPE: type = readType(reader); break; - case IValueIDs.ConstructorValue.PARAMS: + case IValueIDs.ConstructorValue.PARAMS: children = new IValue[reader.getRepeatedLength()]; switch (children.length) { case 1 : @@ -695,10 +695,10 @@ private IValue readConstructor(final IWireInputStream reader) throws IOException } assert paramsAreCorrectType(children, type); break; - case IValueIDs.ConstructorValue.KWPARAMS: + case IValueIDs.ConstructorValue.KWPARAMS: kwParams = readNamedValues(reader); break; - case IValueIDs.ConstructorValue.ANNOS: + case IValueIDs.ConstructorValue.ANNOS: annos = readNamedValues(reader); break; } @@ -709,24 +709,24 @@ private IValue readConstructor(final IWireInputStream reader) throws IOException } IConstructor constr = vf.constructor(type, children); - + if (!annos.isEmpty()) { kwParams = simulateAnnotationsWithKeywordParameters(constr.getType(), kwParams, annos); } - + if (!kwParams.isEmpty()) { constr = constr.asWithKeywordParameters().setParameters(kwParams); } - + return returnAndStore(backReference, valueWindow, constr); } - /** + /** * For bootstrapping purposes we still support annotations in the binary reader (not in the writer). * Here all annotations are converted to corresponding keyword parameters and the `Tree@\loc` annotation * is rewritten to `Tree.src` - * @param receiver - * + * @param receiver + * * @deprecated * @param kwParams * @param annos @@ -737,10 +737,10 @@ private Immutable simulateAnnotationsWithKeywordParameters(Type for (Entry entry : (Iterable>) () -> annos.entryIterator()) { String key = entry.getKey(); IValue value = entry.getValue(); - + kwParams = kwParams.__put(isLegacyParseTreeLocAnnotation(key, receiver) ? "src" : key, value); } - + return kwParams; } @@ -783,11 +783,11 @@ private IValue readString(final IWireInputStream reader) throws IOException { boolean backReference = false; while (reader.next() != IWireInputStream.MESSAGE_END) { switch(reader.field()) { - case IValueIDs.Common.CAN_BE_BACK_REFERENCED: - backReference = true; + case IValueIDs.Common.CAN_BE_BACK_REFERENCED: + backReference = true; break; - case IValueIDs.StringValue.CONTENT: - str = reader.getString(); + case IValueIDs.StringValue.CONTENT: + str = reader.getString(); break; default: reader.skipNestedField(); @@ -809,10 +809,10 @@ private IValue readReal(final IWireInputStream reader) throws IOException { backReference = true; break; case IValueIDs.RealValue.SCALE: - scale = reader.getInteger(); + scale = reader.getInteger(); break; case IValueIDs.RealValue.CONTENT: - bytes = reader.getBytes(); + bytes = reader.getBytes(); break; default: reader.skipNestedField(); @@ -870,8 +870,8 @@ private IValue readSourceLocation(final IWireInputStream reader) throws IOExcept case IValueIDs.SourceLocationValue.SCHEME: scheme = reader.getString(); break; case IValueIDs.SourceLocationValue.AUTHORITY: authority = reader.getString(); break; case IValueIDs.SourceLocationValue.PATH: path = reader.getString(); break; - case IValueIDs.SourceLocationValue.QUERY: query = reader.getString(); break; - case IValueIDs.SourceLocationValue.FRAGMENT: fragment = reader.getString(); break; + case IValueIDs.SourceLocationValue.QUERY: query = reader.getString(); break; + case IValueIDs.SourceLocationValue.FRAGMENT: fragment = reader.getString(); break; case IValueIDs.SourceLocationValue.OFFSET: offset = reader.getInteger(); break; case IValueIDs.SourceLocationValue.LENGTH: length = reader.getInteger(); break; case IValueIDs.SourceLocationValue.BEGINLINE: beginLine = reader.getInteger(); break; @@ -883,7 +883,7 @@ private IValue readSourceLocation(final IWireInputStream reader) throws IOExcept ISourceLocation loc; if (previousURI != -1) { loc = uriWindow.lookBack(previousURI); - } + } else { try { loc = vf.sourceLocation(scheme, authority, path, query, fragment); @@ -979,5 +979,5 @@ private IValue readBoolean(final IWireInputStream reader) throws IOException { return vf.bool(value); } - + } diff --git a/src/main/java/io/usethesource/vallang/io/binary/message/IValueWriter.java b/src/main/java/io/usethesource/vallang/io/binary/message/IValueWriter.java index 86bc6d1c6..a25d1f5da 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/message/IValueWriter.java +++ b/src/main/java/io/usethesource/vallang/io/binary/message/IValueWriter.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.message; import java.io.IOException; @@ -50,7 +50,7 @@ public class IValueWriter { * Write an IValue to an exisiting wire stream.
*
* In most cases you want to use the {@linkplain IValueOutputStream}. - * + * * @param writer the wire writer to use * @param vf the value factory used to rewrite external value types * @param size the window sizes to use @@ -75,7 +75,7 @@ public static void write(IWireOutputStream writer, IValueFactory vf, WindowSizes /** * Write an Type to an existing wire stream. - * + * * @param writer the wire writer to use * @param vf the value factory used to rewrite external value types * @param size the window sizes to use @@ -98,7 +98,7 @@ public static void write(IWireOutputStream writer, IValueFactory vf, WindowSizes windowFactory.returnTrackLastWrittenReferenceEquality(uriCache); } } - + private static void writeHeader(IWireOutputStream writer, int valueWindowSize, int typeWindowSize, int uriWindowSize) throws IOException { writer.startMessage(IValueIDs.Header.ID); @@ -111,8 +111,8 @@ private static void write(final IWireOutputStream writer, IValueFactory vf, fina type.accept(new ITypeVisitor() { private boolean writeFromCache(Type type) throws IOException { - int lastSeen = typeCache.howLongAgo(type); - if (lastSeen != -1) { + int lastSeen = typeCache.howLongAgo(type); + if (lastSeen != -1) { writeSingleValueMessage(writer, IValueIDs.PreviousType.ID, IValueIDs.PreviousType.HOW_LONG_AGO, lastSeen); return true; } @@ -358,13 +358,13 @@ public Void visitVoid(Type t) throws IOException { } }); } - + private static void writeSingleValueMessage(final IWireOutputStream writer, int messageID, int fieldId, int fieldValue) throws IOException { writer.startMessage(messageID); writer.writeField(fieldId, fieldValue); writer.endMessage(); } - + private static void writeSingleValueMessage(final IWireOutputStream writer, int messageID, int fieldId, String fieldValue) throws IOException { writer.startMessage(messageID); writer.writeField(fieldId, fieldValue); @@ -559,7 +559,7 @@ public void visitInteger(IInteger ii) throws IOException { writer.startMessage(IValueIDs.IntegerValue.ID); if(ii. greaterEqual(MININT).getValue() && ii.lessEqual(MAXINT).getValue()){ writer.writeField(IValueIDs.IntegerValue.INTVALUE, ii.intValue()); - } + } else { writer.writeField(IValueIDs.IntegerValue.BIGVALUE, ii.getTwosComplementRepresentation()); } @@ -603,7 +603,7 @@ public void visitSourceLocation(ISourceLocation loc) throws IOException { if(loc.hasOffsetLength()){ writer.writeField(IValueIDs.SourceLocationValue.OFFSET, loc.getOffset()); writer.writeField(IValueIDs.SourceLocationValue.LENGTH, loc.getLength()); - } + } if(loc.hasLineColumn()){ writer.writeField(IValueIDs.SourceLocationValue.BEGINLINE, loc.getBeginLine()); writer.writeField(IValueIDs.SourceLocationValue.ENDLINE, loc.getEndLine()); @@ -615,14 +615,14 @@ public void visitSourceLocation(ISourceLocation loc) throws IOException { @Override public void visitString(IString o) throws IOException { - // TODO: if `o` is a really big binary tree string this o.getValue() duplicates the memory consumption, and it can be slow because of this. - // We can then optimize using the writer interface or the character iterators of IString + // TODO: if `o` is a really big binary tree string this o.getValue() duplicates the memory consumption, and it can be slow because of this. + // We can then optimize using the writer interface or the character iterators of IString writeSingleValueMessage(writer, IValueIDs.StringValue.ID, IValueIDs.StringValue.CONTENT, o.getValue()); } - + @Override public void visitRational(IRational val) throws IOException { - writer.startMessage(IValueIDs.RationalValue.ID); + writer.startMessage(IValueIDs.RationalValue.ID); writer.writeNestedField(IValueIDs.RationalValue.NUMERATOR); visitInteger(val.numerator()); writer.writeNestedField(IValueIDs.RationalValue.DENOMINATOR); diff --git a/src/main/java/io/usethesource/vallang/io/binary/stream/Compressor.java b/src/main/java/io/usethesource/vallang/io/binary/stream/Compressor.java index 47df58eff..d49c541cb 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/stream/Compressor.java +++ b/src/main/java/io/usethesource/vallang/io/binary/stream/Compressor.java @@ -1,16 +1,16 @@ /** * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions * and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other materials provided with * the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR diff --git a/src/main/java/io/usethesource/vallang/io/binary/stream/Header.java b/src/main/java/io/usethesource/vallang/io/binary/stream/Header.java index 7ca9ed79e..b1b78c9b6 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/stream/Header.java +++ b/src/main/java/io/usethesource/vallang/io/binary/stream/Header.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.stream; /*package*/ final class Header { diff --git a/src/main/java/io/usethesource/vallang/io/binary/stream/IValueInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/stream/IValueInputStream.java index 7775bf8eb..26900aaf5 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/stream/IValueInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/stream/IValueInputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.stream; import java.io.Closeable; @@ -34,7 +34,7 @@ * At the moment, it automatically detects the old serializer format, and try to read using the old {@linkplain BinaryReader}. */ public class IValueInputStream implements Closeable { - + private final @Nullable BinaryWireInputStream reader; private final IValueFactory vf; private final Supplier typeStoreSupplier; @@ -58,7 +58,7 @@ public IValueInputStream(InputStream in, IValueFactory vf, Supplier t in = Compressor.wrapStream(in, compression); reader = new BinaryWireInputStream(in); } - + private static String toHex(byte[] main) { String result = ""; @@ -79,7 +79,7 @@ public IValue read() throws IOException { } return IValueReader.readValue(reader, vf, typeStoreSupplier); } - + @Override public void close() throws IOException { if (reader != null) { diff --git a/src/main/java/io/usethesource/vallang/io/binary/stream/IValueOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/stream/IValueOutputStream.java index 0d91f55ed..e9064ec7c 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/stream/IValueOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/stream/IValueOutputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Paul Klint, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.stream; import io.usethesource.vallang.io.binary.stream.Header.Compression; @@ -41,7 +41,7 @@ * This does enforce you to adopt the same {@link IWireOutputStream wire format} format. */ public class IValueOutputStream implements Closeable { - + /** * Compression of the serializer, balances lookback windows and compression algorithm @@ -65,12 +65,12 @@ public enum CompressionRate { CompressionRate(int compressionAlgorithm, int compressionLevel) { this.compressionLevel = compressionLevel; this.compressionAlgorithm = compressionAlgorithm; - } + } } - - - - + + + + private CompressionRate compression; private OutputStream rawStream; private @MonotonicNonNull IWireOutputStream writer; @@ -79,12 +79,12 @@ public enum CompressionRate { public IValueOutputStream(OutputStream out, IValueFactory vf) throws IOException { this(out, vf, CompressionRate.Normal); } - + public IValueOutputStream(FileChannel channel, IValueFactory vf, CompressionRate compression) throws IOException { this(byteBufferedOutput(channel), vf, compression); } - + public IValueOutputStream(OutputStream out, IValueFactory vf, CompressionRate compression) throws IOException { out.write(Header.MAIN); this.rawStream = out; @@ -95,8 +95,8 @@ public IValueOutputStream(OutputStream out, IValueFactory vf, CompressionRate co private static OutputStream byteBufferedOutput(FileChannel channel) { return new FileChannelDirectOutputStream(channel, 10); } - - + + public void write(IValue value) throws IOException { WindowSizes sizes = compression.compressionLevel == 0 ? WindowSizes.NO_WINDOW : WindowSizes.NORMAL_WINDOW; if (writer == null) { diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/ArrayUtil.java b/src/main/java/io/usethesource/vallang/io/binary/util/ArrayUtil.java index 5d58df0db..ec82027c9 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/ArrayUtil.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/ArrayUtil.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; public class ArrayUtil { @@ -22,24 +22,24 @@ public class ArrayUtil { public static void fill(T[] array, T value) { int len = array.length; - if (len > 0){ - array[0] = value; + if (len > 0) { + array[0] = value; } for (int i = 1; i < len; i += i) { - System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i); + System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i); } } public static void fill(int[] array, int value) { int len = array.length; - if (len > 0){ - array[0] = value; + if (len > 0) { + array[0] = value; } for (int i = 1; i < len; i += i) { - System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i); + System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i); } } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferInputStream.java index 86039dc79..7b2b58a76 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferInputStream.java @@ -5,9 +5,9 @@ import java.nio.ByteBuffer; public class ByteBufferInputStream extends InputStream { - + protected ByteBuffer source; - + public ByteBuffer getByteBuffer() { return source; } @@ -15,7 +15,7 @@ public ByteBuffer getByteBuffer() { public ByteBufferInputStream(ByteBuffer source) { this.source = source; } - + protected ByteBuffer refill(ByteBuffer torefill) throws IOException { return torefill; } @@ -48,16 +48,16 @@ public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b) throws IOException { return read(b, 0, b.length); } - + @Override public int read() throws IOException { if (!source.hasRemaining()) { source = refill(source); if (!source.hasRemaining()) { return -1; - } + } } return Byte.toUnsignedInt(source.get()); } - + } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferOutputStream.java index bf088965f..f2565eb2e 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/ByteBufferOutputStream.java @@ -5,27 +5,27 @@ import java.nio.ByteBuffer; public abstract class ByteBufferOutputStream extends OutputStream { - + protected ByteBuffer target; protected boolean closed = false; public ByteBufferOutputStream(ByteBuffer target) { this.target = target; } - - + + public ByteBuffer getBuffer() { return target; } - + /*** - * Flush the buffer (that has been flipped already) and return the same buffer (but cleared) or a new buffer for the next round. + * Flush the buffer (that has been flipped already) and return the same buffer (but cleared) or a new buffer for the next round. * @param toflush the flipped buffer to flush * @return a new or the same buffer that has room available for writing. * @throws IOException */ protected abstract ByteBuffer flush(ByteBuffer toflush) throws IOException; - + @Override public void flush() throws IOException { if (closed) { @@ -46,13 +46,13 @@ public void flush() throws IOException { } assert target.hasRemaining(): "after a flush, we should have a buffer with some room. (it was: " + target + ")"; } - + @Override public void close() throws IOException { if (!closed ) { try { flush(); - } + } finally { closed = true; } @@ -90,12 +90,12 @@ public void write(byte[] b, int off, int len) throws IOException { public void write(byte[] b) throws IOException { write(b, 0, b.length); } - + public void write(ByteBuffer buf) throws IOException { if (closed) { throw new IOException("Stream closed"); } - int originalLimit = buf.limit(); + int originalLimit = buf.limit(); while (buf.hasRemaining()) { if (!target.hasRemaining()) { flush(); @@ -106,5 +106,5 @@ public void write(ByteBuffer buf) throws IOException { buf.limit(originalLimit); } } - + } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/CacheFactory.java b/src/main/java/io/usethesource/vallang/io/binary/util/CacheFactory.java index 6a2cf9e68..80efb2ba2 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/CacheFactory.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/CacheFactory.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.lang.ref.ReferenceQueue; @@ -34,17 +34,17 @@ * */ public class CacheFactory { - - - // or when more memory is needed. - private static final class LastUsedTracker extends SoftReference { + + + // or when more memory is needed. + private static final class LastUsedTracker extends SoftReference { private final long lastUsed; public LastUsedTracker(T obj, ReferenceQueue queue) { super(obj, queue); - this.lastUsed = System.nanoTime(); - } - + this.lastUsed = System.nanoTime(); + } + public boolean clearIfOlderThan(long timeStamp) { if (timeStamp > lastUsed) { clear(); @@ -52,20 +52,20 @@ public boolean clearIfOlderThan(long timeStamp) { } return false; } - } - - private static final class SoftPool { - private final Deque> dequeue = new ConcurrentLinkedDeque<>(); - private final ReferenceQueue references = new ReferenceQueue<>(); - - public void performHouseKeeping() { - synchronized (references) { - Object cleared; - while ((cleared = references.poll()) != null) { - dequeue.removeLastOccurrence(cleared); - } + } + + private static final class SoftPool { + private final Deque> dequeue = new ConcurrentLinkedDeque<>(); + private final ReferenceQueue references = new ReferenceQueue<>(); + + public void performHouseKeeping() { + synchronized (references) { + Object cleared; + while ((cleared = references.poll()) != null) { + dequeue.removeLastOccurrence(cleared); + } } - } + } public @Nullable SoftReference poll() { return dequeue.poll(); @@ -78,58 +78,58 @@ public void push(T o) { public Iterator> descendingIterator() { return dequeue.descendingIterator(); } - } - - private final Map> caches = new ConcurrentHashMap<>(); - private final Function cleaner; - private final long expireNanos; - - public CacheFactory(int expireAfter, TimeUnit unit, Function clearer) { - this.expireNanos = unit.toNanos(expireAfter); - this.cleaner = clearer; - registerInstance(this); - } - - /** - * Private internal function, to be called from the cleanup thread - */ - private void cleanup() { - long cleanBefore = System.nanoTime() - expireNanos; - for (SoftPool v : caches.values()) { - Iterator> it = v.descendingIterator(); - while (it.hasNext()) { - LastUsedTracker current = it.next(); - if (current.clearIfOlderThan(cleanBefore)) { - it.remove(); - } - else { - break; // end of the chain of outdated stuff reached - } - } - v.performHouseKeeping(); - } - } - - public @NonNull T get(int size, Function computeNew) { + } + + private final Map> caches = new ConcurrentHashMap<>(); + private final Function cleaner; + private final long expireNanos; + + public CacheFactory(int expireAfter, TimeUnit unit, Function clearer) { + this.expireNanos = unit.toNanos(expireAfter); + this.cleaner = clearer; + registerInstance(this); + } + + /** + * Private internal function, to be called from the cleanup thread + */ + private void cleanup() { + long cleanBefore = System.nanoTime() - expireNanos; + for (SoftPool v : caches.values()) { + Iterator> it = v.descendingIterator(); + while (it.hasNext()) { + LastUsedTracker current = it.next(); + if (current.clearIfOlderThan(cleanBefore)) { + it.remove(); + } + else { + break; // end of the chain of outdated stuff reached + } + } + v.performHouseKeeping(); + } + } + + public @NonNull T get(int size, Function computeNew) { SoftPool reads = caches.computeIfAbsent(size, i -> new SoftPool<>()); SoftReference tracker; while ((tracker = reads.poll()) != null) { T result = tracker.get(); if (result != null) { - return result; + return result; } } return computeNew.apply(size); - } - - public void put(int size, T returned) { - if (returned != null) { - returned = cleaner.apply(returned); + } + + public void put(int size, T returned) { + if (returned != null) { + returned = cleaner.apply(returned); SoftPool entries = caches.computeIfAbsent(size, i -> new SoftPool<>()); entries.push(returned); - } - } - + } + } + private static final ConcurrentLinkedQueue>> CLEANUP_CACHES = new ConcurrentLinkedQueue<>(); diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/ClearableWindow.java b/src/main/java/io/usethesource/vallang/io/binary/util/ClearableWindow.java index fd39da803..a45f0295f 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/ClearableWindow.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/ClearableWindow.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; public interface ClearableWindow { diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/DelayedCompressionOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/DelayedCompressionOutputStream.java index 1b3ee6205..5dae4a269 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/DelayedCompressionOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/DelayedCompressionOutputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.io.IOException; @@ -23,7 +23,7 @@ public class DelayedCompressionOutputStream extends OutputStream { private OutputStream out; private WrappingCompressorFunction compress; private int compressHeader; - + @FunctionalInterface public interface WrappingCompressorFunction { OutputStream wrap(OutputStream toWrap) throws IOException; @@ -36,7 +36,7 @@ public DelayedCompressionOutputStream(OutputStream out, int compressHeader, Wrap buffer = new byte[COMPRESS_AFTER]; written = 0; } - + @Override public void flush() throws IOException { if (written != -1) { @@ -46,14 +46,14 @@ public void flush() throws IOException { } out.flush(); } - + @Override public void close() throws IOException { try (OutputStream out2 = out) { flush(); } } - + @Override public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); // normally shouldn't occur, so take slow path @@ -62,7 +62,7 @@ public void write(int b) throws IOException { public void write(byte[] b) throws IOException { write(b, 0, b.length); } - + @Override public void write(byte[] b, int off, int len) throws IOException { if (written != -1) { diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/DelayedZstdOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/DelayedZstdOutputStream.java index 1da4bb2d7..b763e0c9f 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/DelayedZstdOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/DelayedZstdOutputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.io.IOException; @@ -27,7 +27,7 @@ public class DelayedZstdOutputStream extends ByteBufferOutputStream { private final int level; private boolean firstFlush = true; private @MonotonicNonNull ZstdDirectBufferCompressingStream compressor = null; - + public DelayedZstdOutputStream(ByteBufferOutputStream out, int compressHeader, int level) throws IOException { super(DirectByteBufferCache.getInstance().get(COMPRESS_AFTER)); @@ -39,7 +39,7 @@ public DelayedZstdOutputStream(ByteBufferOutputStream out, int compressHeader, i this.compressHeader = compressHeader; this.level = level; } - + @Override protected ByteBuffer flush(ByteBuffer toflush) throws IOException { if (out.target == this.target) { @@ -67,7 +67,7 @@ protected ByteBuffer flushBuffer(ByteBuffer toFlush) throws IOException { out.write(0); } } - + if (compressor != null) { compressor.compress(toflush); } @@ -82,8 +82,8 @@ protected ByteBuffer flushBuffer(ByteBuffer toFlush) throws IOException { } return toflush; } - - + + @Override public void close() throws IOException { if (out.target == this.target) { @@ -102,11 +102,11 @@ public void close() throws IOException { finally { out.close(); } - } + } finally { DirectByteBufferCache.getInstance().put(target); } } } - + } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/DirectByteBufferCache.java b/src/main/java/io/usethesource/vallang/io/binary/util/DirectByteBufferCache.java index e40227f8c..c35d8d177 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/DirectByteBufferCache.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/DirectByteBufferCache.java @@ -4,38 +4,38 @@ import java.util.concurrent.TimeUnit; public class DirectByteBufferCache { - + static private class InstanceHolder { static final DirectByteBufferCache sInstance = new DirectByteBufferCache(); } - + public static DirectByteBufferCache getInstance() { return InstanceHolder.sInstance; } - + private DirectByteBufferCache() { } - - + + private final CacheFactory buffers = new CacheFactory<>(3, TimeUnit.SECONDS, DirectByteBufferCache::clear); - + private static ByteBuffer clear(ByteBuffer b) { - b.clear(); + b.clear(); return b; } - + private static int roundSize(int size) { return (int)(Math.ceil(size / (8*1024.0)) * (8*1024)); } - + public ByteBuffer get(int size) { return getExact(roundSize(size)); } - + public void put(ByteBuffer returned) { - if (returned.capacity() > (8*1024)) { - buffers.put(returned.capacity(), returned); - } + if (returned.capacity() > (8*1024)) { + buffers.put(returned.capacity(), returned); + } } public ByteBuffer getExact(int size) { diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/DirectZstdInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/DirectZstdInputStream.java index efa716355..6cbaa0cb7 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/DirectZstdInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/DirectZstdInputStream.java @@ -17,7 +17,7 @@ public DirectZstdInputStream(ByteBufferInputStream originalStream) { this.orginalStream = originalStream; decompressor = new ZstdDirectBufferDecompressingStream(originalStream.getByteBuffer()); } - + @Override protected ByteBuffer refill(ByteBuffer torefill) throws IOException { torefill.clear(); @@ -36,7 +36,7 @@ private static ByteBuffer constructDecompressedBuffer(ByteBufferInputStream oriS result.limit(0); // delay compression for first read return result; } - + @Override public void close() throws IOException { if (!closed ) { diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectInputStream.java index 1609761ca..ebb1df203 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectInputStream.java @@ -24,7 +24,7 @@ public FileChannelDirectInputStream(FileChannel channel) throws IOException { this.channel = channel; this.small = smallFile(channel); } - + private static ByteBuffer getSmallBuffer(FileChannel channel) throws IOException { return (ByteBuffer) DirectByteBufferCache.getInstance().get((int)channel.size()).flip(); } @@ -85,7 +85,7 @@ public void close() throws IOException { cleaner.set(MethodHandles.lookup().findVirtual( unsafeClass, "invokeCleaner", MethodType.methodType(void.class, ByteBuffer.class))); - + Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe"); theUnsafeField.setAccessible(true); diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectOutputStream.java index 1edadd9a1..d89a694fc 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/FileChannelDirectOutputStream.java @@ -47,7 +47,7 @@ public void write(ByteBuffer buf) throws IOException { buf.limit(buf.position() + target.remaining()); target.put(buf); buf.limit(oldLimit); - + flush(); if (target.remaining() >= buf.remaining()) { // now it does fit, no problem diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/LinearCircularLookupWindow.java b/src/main/java/io/usethesource/vallang/io/binary/util/LinearCircularLookupWindow.java index f0f65eefd..a16b1fb80 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/LinearCircularLookupWindow.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/LinearCircularLookupWindow.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.util.Arrays; @@ -26,14 +26,14 @@ public class LinearCircularLookupWindow implements Tr public LinearCircularLookupWindow(int size) { data = (T[]) new Object[Math.min(512, size)]; written = 0; - maxSize = size + 1; + maxSize = size + 1; } - + private int translate(long index) { return (int) (index % data.length); } - - + + @Override public T lookBack(int offset) { assert offset + 1 <= written && offset < maxSize; @@ -43,7 +43,7 @@ public T lookBack(int offset) { } return result; } - + @Override public void read(T obj) { growIfNeeded(); diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/MapLastWritten.java b/src/main/java/io/usethesource/vallang/io/binary/util/MapLastWritten.java index 8f557d5e0..80ac6d50f 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/MapLastWritten.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/MapLastWritten.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.util.LinkedHashMap; @@ -51,7 +51,7 @@ protected boolean removeEldestEntry(java.util.Map.Entry, Long }; written = 0; } - + @Override public int howLongAgo(T obj) { Long writtenAt = lookupData.get(new IdentityWrapper<>(obj)); @@ -60,7 +60,7 @@ public int howLongAgo(T obj) { } return -1; } - + @Override public void write(T obj) { lookupData.put(new IdentityWrapper<>(obj), written++); diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/OpenAddressingLastWritten.java b/src/main/java/io/usethesource/vallang/io/binary/util/OpenAddressingLastWritten.java index cbf1ace4b..53f7f99a3 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/OpenAddressingLastWritten.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/OpenAddressingLastWritten.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.util.Objects; @@ -19,7 +19,7 @@ /** * A track last written implementation that uses linear open addressing to implement the very specific hashmap - * + * * This implementation is just as fast as using the IdentityHashMap, however it uses less memory on average and we can also use value equality. * @author Davy Landman */ @@ -42,7 +42,7 @@ public abstract class OpenAddressingLastWritten imple * how many entries are already written */ private long written; - + /** * Create a n OpenAddressingLastWritten container using reference equality and identiy hashcode. * @param maximumEntries larger than 0 and smaller than Integer.MAX_VALUE / 2 @@ -67,7 +67,7 @@ protected int hash(T obj) { protected boolean equals(T a, T b) { return a.equals(b); } - + @Override protected int hash(T obj) { return obj.hashCode(); @@ -87,7 +87,7 @@ public OpenAddressingLastWritten(int maximumEntries) { } this.maximumEntries = maximumEntries; maximumSize = closestPrime(maximumEntries * 3); // load factor of max 33% - tableSize = Math.min(571, maximumSize); + tableSize = Math.min(571, maximumSize); resizeAfter = Math.min(tableSize / 3, maximumEntries); keys = new Object[this.tableSize]; @@ -98,7 +98,7 @@ public OpenAddressingLastWritten(int maximumEntries) { ArrayUtil.fill(oldest, -1); written = 0; } - + //http://stackoverflow.com/a/20798440/11098 private static boolean isPrime(int num) { if (num < 2) { @@ -117,7 +117,7 @@ private static boolean isPrime(int num) { } return true; } - + private static int closestPrime(int i) { if (i <= 2) { return 2; @@ -143,11 +143,11 @@ public int howLongAgo(T obj) { } return -1; } - + private int translateOldest(long index) { return (int) (index % resizeAfter); } - + @SuppressWarnings("unchecked") private int locate(T obj) { int pos = (hash(obj) & 0x7FFFFFFF) % tableSize; // 0x7FFFFF to make it positive, Math.abs can fail when MAX_INT is returned @@ -156,7 +156,7 @@ private int locate(T obj) { if (current == null) { return -1; } - + while (!equals((T)current, obj)) { pos = (pos + 1) % tableSize; current = keys[pos]; @@ -164,7 +164,7 @@ private int locate(T obj) { return -1; } } - + return pos; } @@ -172,9 +172,9 @@ private int locate(T obj) { protected abstract int hash(T obj); private int findSpace(int hash) { - int pos = (hash & 0x7FFFFFFF) % tableSize; + int pos = (hash & 0x7FFFFFFF) % tableSize; while (keys[pos] != null) { - pos = (pos + 1) % tableSize; + pos = (pos + 1) % tableSize; } return pos; } @@ -200,7 +200,7 @@ public void write(T obj) { * Implements the remove entry algorithm from wikipedia, which is based on Knuth's remark. * The simple solution would be to use thombstone values, but this quickly degrades the lookup performance to * O(n) since the array is now one big chain. - * + * * This algorithm reconnects the chain after a hole has been made somewhere in it. * The biggest challenge is that the chain can actually be part of 2 seperate chains (due to clusters in the mod factor) * @param oldestEntry index of the entry to remove @@ -209,26 +209,26 @@ private void remove(int oldestEntry) { int space = oldestEntry; final @Nullable Object[] keys = this.keys; while (true) { - int candidate = space; - Object curr = null; - while (true) { - candidate = (candidate + 1) % tableSize; - curr = keys[candidate]; - if (curr == null) { - keys[space] = null; - return; - } - int k = (hashes[candidate] & 0x7FFFFFFF) % tableSize; - if (space <= candidate ? ((space >= k) || (k > candidate)) : ((space >= k) && (k > candidate))) { - break; - } - } - keys[space] = Objects.requireNonNull(curr); - writtenAt[space] = writtenAt[candidate]; - hashes[space] = hashes[candidate]; - //assert oldest[translateOldest(writtenAt[space])] == candidate; - oldest[translateOldest(writtenAt[space])] = space; - space = candidate; + int candidate = space; + Object curr = null; + while (true) { + candidate = (candidate + 1) % tableSize; + curr = keys[candidate]; + if (curr == null) { + keys[space] = null; + return; + } + int k = (hashes[candidate] & 0x7FFFFFFF) % tableSize; + if (space <= candidate ? ((space >= k) || (k > candidate)) : ((space >= k) && (k > candidate))) { + break; + } + } + keys[space] = Objects.requireNonNull(curr); + writtenAt[space] = writtenAt[candidate]; + hashes[space] = hashes[candidate]; + //assert oldest[translateOldest(writtenAt[space])] == candidate; + oldest[translateOldest(writtenAt[space])] = space; + space = candidate; } } @@ -245,7 +245,7 @@ private void growIfNeeded() { hashes = new int[this.tableSize]; oldest = new int[resizeAfter]; ArrayUtil.fill(oldest, -1); - + for (int i = 0; i < oldKeys.length; i++) { Object key = oldKeys[i]; if (key != null) { @@ -260,18 +260,18 @@ private void growIfNeeded() { } } } - + @Override public int size() { return maximumEntries; } - + @Override public void clear() { ArrayUtil.fill(keys, null); ArrayUtil.fill(oldest, -1); written = 0; - + } } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/StacklessStructuredVisitor.java b/src/main/java/io/usethesource/vallang/io/binary/util/StacklessStructuredVisitor.java index 8c5e9c8a7..62f841786 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/StacklessStructuredVisitor.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/StacklessStructuredVisitor.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.util.ArrayDeque; @@ -69,7 +69,7 @@ private static abstract class VisitStep { abstract boolean hasSteps(); abstract void step(Deque> worklist, StructuredIValueVisitor visit) throws E; } - + private static final class SingleIValueStep extends VisitStep { final IValue val; boolean completed = false; @@ -107,7 +107,7 @@ void step(Deque> worklist, StructuredIValueVisitor visit) throws next.accept(values.next(), worklist, visit); } } - + private static void visitValue(IValue current, Deque> workList, StructuredIValueVisitor visit) throws E { current.accept(new IValueVisitor() { @@ -168,7 +168,7 @@ else if (entries.hasNext()) { } } }, StacklessStructuredVisitor::visitValue)); - + } return null; } @@ -204,10 +204,10 @@ public Void visitNode(INode node) throws E { })); } - } + } workList.push(new IteratingSteps<>(node.iterator(), StacklessStructuredVisitor::visitValue)); - + } return null; } @@ -252,7 +252,7 @@ public Void visitConstructor(IConstructor constr) throws E { })); } - } + } workList.push(new IteratingSteps<>(constr.iterator(), StacklessStructuredVisitor::visitValue)); } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/StructuredIValueVisitor.java b/src/main/java/io/usethesource/vallang/io/binary/util/StructuredIValueVisitor.java index ec84fe63b..ba77db43c 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/StructuredIValueVisitor.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/StructuredIValueVisitor.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import io.usethesource.vallang.IBool; @@ -28,10 +28,10 @@ import io.usethesource.vallang.IValue; public interface StructuredIValueVisitor { - + void enterNamedValues(String[] names, int numberOfNestedValues) throws E; void leaveNamedValue() throws E; - + boolean enterConstructor(IConstructor cons, int children) throws E; void enterConstructorKeywordParameters() throws E; void leaveConstructor(IValue cons) throws E; @@ -45,10 +45,10 @@ public interface StructuredIValueVisitor { boolean enterSet(ISet set, int elements) throws E; void leaveSet(IValue set) throws E; - + boolean enterMap(IMap map, int elements) throws E; void leaveMap(IValue map) throws E; - + boolean enterTuple(ITuple tuple, int arity) throws E; void leaveTuple(IValue tuple) throws E; diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/TaggedInt.java b/src/main/java/io/usethesource/vallang/io/binary/util/TaggedInt.java index bdbb935c6..ea4994e52 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/TaggedInt.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/TaggedInt.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; /** @@ -26,16 +26,16 @@ private TaggedInt() {} assert (1 << (TAG_BITS - 1)) == Integer.highestOneBit(TAG_MASK); assert getOriginal(make(MAX_ORIGINAL_VALUE, 3)) == MAX_ORIGINAL_VALUE; } - + public static int make(final int original, final int tag) { assert (tag & TAG_MASK) == tag && original <= MAX_ORIGINAL_VALUE; return (original << TAG_BITS) | tag; } - + public static int getOriginal(final int i) { return i >>> TAG_BITS; } - + public static int getTag(final int i) { return i & TAG_MASK; } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastRead.java b/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastRead.java index b92dd618b..f8db1ef40 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastRead.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastRead.java @@ -1,21 +1,21 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import org.checkerframework.checker.nullness.qual.NonNull; /** - * + * * The inverse of the {@link TrackLastWritten}, keeping track of when an object was read. * Most commonly with a window size (that should be at least as large as during writing). * @author Davy Landman diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastWritten.java b/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastWritten.java index ff0c0641a..ad3fc75ec 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastWritten.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/TrackLastWritten.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import org.checkerframework.checker.nullness.qual.NonNull; @@ -23,12 +23,12 @@ */ public interface TrackLastWritten { /** - * Register that an object has just been written. + * Register that an object has just been written. * It is very important that this object is not in the window anymore (eg howLongAgo(obj) == -1) * @param obj the new object to track. */ void write(T obj); - + /** * How long ago an object was written. * @param obj which object diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/WindowCacheFactory.java b/src/main/java/io/usethesource/vallang/io/binary/util/WindowCacheFactory.java index 22d94a424..e8723e6e4 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/WindowCacheFactory.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/WindowCacheFactory.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; import java.util.concurrent.TimeUnit; @@ -22,18 +22,18 @@ * */ public class WindowCacheFactory { - static private class InstanceHolder { - static final WindowCacheFactory sInstance = new WindowCacheFactory(); - } - - public static WindowCacheFactory getInstance() { - return InstanceHolder.sInstance; - } + static private class InstanceHolder { + static final WindowCacheFactory sInstance = new WindowCacheFactory(); + } + + public static WindowCacheFactory getInstance() { + return InstanceHolder.sInstance; + } private final CacheFactory> lastReads = new CacheFactory<>(60, TimeUnit.SECONDS, WindowCacheFactory::clear); private final CacheFactory> lastWrittenReference = new CacheFactory<>(60, TimeUnit.SECONDS, WindowCacheFactory::clear); private final CacheFactory> lastWrittenObject = new CacheFactory<>(60, TimeUnit.SECONDS, WindowCacheFactory::clear); - + private final TrackLastRead disabledReadWindow = new TrackLastRead() { @Override public Object lookBack(int howLongBack) { throw new IllegalArgumentException(); } @@ -46,7 +46,7 @@ public void write(Object obj) { } @Override public int howLongAgo(Object obj) { return -1; } }; - + @SuppressWarnings({"unchecked","type.argument"}) public TrackLastRead getTrackLastRead(int size) { if (size == 0) { @@ -69,7 +69,7 @@ public TrackLastRead getTrackLastRead(int size) { } return (TrackLastWritten) lastWrittenObject.get(size, OpenAddressingLastWritten::objectEquality); } - + @SuppressWarnings("unchecked") public void returnTrackLastRead(TrackLastRead returned) { if (returned != disabledReadWindow) { @@ -89,12 +89,12 @@ public TrackLastRead getTrackLastRead(int size) { doReturn(lastWrittenObject, (TrackLastWritten) returned); } } - + private void doReturn(CacheFactory target, T returned) { if (returned instanceof ClearableWindow) { int windowSize = ((ClearableWindow) returned).size(); - if (windowSize >= 1000) { - target.put(windowSize, returned); + if (windowSize >= 1000) { + target.put(windowSize, returned); } } } diff --git a/src/main/java/io/usethesource/vallang/io/binary/util/WindowSizes.java b/src/main/java/io/usethesource/vallang/io/binary/util/WindowSizes.java index d57c8aa85..dac8f7976 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/util/WindowSizes.java +++ b/src/main/java/io/usethesource/vallang/io/binary/util/WindowSizes.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.util; public class WindowSizes { diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/FieldKind.java b/src/main/java/io/usethesource/vallang/io/binary/wire/FieldKind.java index 9100d5c94..9b6da4a8d 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/FieldKind.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/FieldKind.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.wire; public class FieldKind { @@ -24,10 +24,10 @@ public class FieldKind { private static final int UNUSED1 = 6; @SuppressWarnings("unused") private static final int UNUSED2 = 7; - + public static class Repeated { /* values from 0-7 are valid */ - public static final int BYTES = 0; + public static final int BYTES = 0; @SuppressWarnings("unused") private static final int UNUSED0 = 1; public static final int INTS = FieldKind.INT; // 2 diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/IWireInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/wire/IWireInputStream.java index e7b5bd07c..f2d3cd0d0 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/IWireInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/IWireInputStream.java @@ -1,14 +1,14 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package io.usethesource.vallang.io.binary.wire; @@ -52,8 +52,8 @@ public interface IWireInputStream extends Closeable { int field(); /** * The current field type, see {@link FieldKind} for the different kind of field types.
- * Normally, the value of the field is also read, for type of {@linkplain FieldKind#NESTED} we do not read the nested message, and a call to {@linkplain next} is needed to move to - * + * Normally, the value of the field is also read, for type of {@linkplain FieldKind#NESTED} we do not read the nested message, and a call to {@linkplain next} is needed to move to + * * @return */ int getFieldType(); @@ -97,7 +97,7 @@ public interface IWireInputStream extends Closeable { * @return */ int[] getIntegers(); - + /** * skip the current message, also takes care to skip nested messages @@ -114,7 +114,7 @@ else if (getFieldType() == FieldKind.REPEATED && getRepeatedType() == FieldKind. int repeated = getRepeatedLength(); for (int i = 0; i < repeated; i++ ){ next(); // go into the message - skipMessage(); + skipMessage(); } } } diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/IWireOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/wire/IWireOutputStream.java index 723eabc31..ed6e46966 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/IWireOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/IWireOutputStream.java @@ -1,14 +1,14 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package io.usethesource.vallang.io.binary.wire; diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireInputStream.java b/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireInputStream.java index 2107c488c..aa2d5b009 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireInputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireInputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.wire.binary; import java.io.BufferedInputStream; @@ -50,7 +50,7 @@ public class BinaryWireInputStream implements IWireInputStream { public BinaryWireInputStream(InputStream stream) throws IOException { this(stream, 8*1024); } - + public BinaryWireInputStream(InputStream stream, int bufferSize) throws IOException { if (stream instanceof BufferedInputStream || stream instanceof ByteBufferInputStream) { __stream = stream; @@ -58,7 +58,7 @@ public BinaryWireInputStream(InputStream stream, int bufferSize) throws IOExcept else { this.__stream = new BufferedInputStream(stream, bufferSize); } - + byte[] header = readBytes(stream, WIRE_VERSION.length); if (!Arrays.equals(WIRE_VERSION, header)) { throw new IOException("Unsupported wire format"); @@ -84,18 +84,18 @@ public void close() throws IOException { private void assertNotClosed() throws IOException { if (closed) { - throw new IOException("Stream already closed"); + throw new IOException("Stream already closed"); } } private byte[] readBytes(int len) throws IOException { - return readBytes(__stream, len); + return readBytes(__stream, len); } private static byte[] readBytes(InputStream stream, int len) throws IOException, EOFException { byte[] result = new byte[len]; - - int pos = 0; + + int pos = 0; while (pos < len) { int read = stream.read(result, pos, len - pos); if (read == -1) { @@ -103,17 +103,17 @@ private static byte[] readBytes(InputStream stream, int len) throws IOException, } pos += read; } - + return result; } - + /* * LEB128 decoding (or actually LEB32) of positive and negative integers, negative integers always use 5 bytes, positive integers are compact. */ private int decodeInteger() throws IOException { return decodeInteger(__stream); } - + private static int decodeInteger(InputStream stream) throws IOException { try { // manually unrolling the loop was the fastest for reading, yet not for writing @@ -216,7 +216,7 @@ public int next() throws IOException { } this.intValues = intValues; break; - case FieldKind.Repeated.STRINGS: + case FieldKind.Repeated.STRINGS: String[] stringValues = new String[nestedLength]; for (int i = 0; i < nestedLength; i++) { stringValues[i]= readNestedString(); @@ -267,7 +267,7 @@ public int field() { assert current == FIELD; return fieldID; } - + @Override public int getInteger() { assert fieldType == FieldKind.INT; @@ -286,26 +286,26 @@ private static T nonNull(@Nullable T field) { } return field; } - - + + @Override public byte[] getBytes() { assert fieldType == FieldKind.REPEATED && nestedType == FieldKind.Repeated.BYTES; return nonNull(bytesValue); } - + @Override public int getFieldType() { assert current == FIELD; return fieldType; } - + @Override public int getRepeatedType() { assert current == FIELD && fieldType == FieldKind.REPEATED; return nestedType; } - + @Override public int getRepeatedLength() { assert current == FIELD && fieldType == FieldKind.REPEATED; @@ -317,13 +317,13 @@ public String[] getStrings() { assert getRepeatedType() == FieldKind.Repeated.STRINGS; return nonNull(stringValues); } - + @Override public int[] getIntegers() { assert getRepeatedType() == FieldKind.Repeated.INTS; return nonNull(intValues); } - + @Override public void skipMessage() throws IOException { int toSkip = 1; diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireOutputStream.java index b004531ca..5f31fd200 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/binary/BinaryWireOutputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.wire.binary; import java.io.BufferedOutputStream; @@ -46,7 +46,7 @@ public BinaryWireOutputStream(OutputStream stream, int stringSharingWindowSize, encodeInteger(__stream, stringSharingWindowSize); this.stringsWritten = WindowCacheFactory.getInstance().getTrackLastWrittenObjectEquality(stringSharingWindowSize); } - + @Override public void flush() throws IOException { @@ -94,10 +94,10 @@ public void close() throws IOException { } } } - + private void assertNotClosed() throws IOException { if (closed) { - throw new IOException("Stream already closed"); + throw new IOException("Stream already closed"); } } @@ -125,14 +125,14 @@ public void writeField(int fieldId, String value) throws IOException { stringsWritten.write(value); } } - + @Override public void writeField(int fieldId, int value) throws IOException { assertNotClosed(); writeFieldTag(fieldId, FieldKind.INT); encodeInteger(value); } - + @Override public void writeField(int fieldId, byte[] value) throws IOException { assertNotClosed(); @@ -147,7 +147,7 @@ public void writeField(int fieldId, byte[] value) throws IOException { } writeBytes(value); } - + @Override public void writeField(int fieldId, int[] values) throws IOException { assertNotClosed(); @@ -164,7 +164,7 @@ public void writeField(int fieldId, int[] values) throws IOException { encodeInteger(v); } } - + @Override public void writeField(int fieldId, String[] values) throws IOException { assertNotClosed(); @@ -193,12 +193,12 @@ private void writeNestedString(String s) throws IOException { stringsWritten.write(s); } } - + @Override public void writeNestedField(int fieldId) throws IOException { assertNotClosed(); writeFieldTag(fieldId, FieldKind.NESTED); - + } @Override public void writeRepeatedNestedField(int fieldId, int numberOfNestedElements) throws IOException { diff --git a/src/main/java/io/usethesource/vallang/io/binary/wire/xml/XMLWireOutputStream.java b/src/main/java/io/usethesource/vallang/io/binary/wire/xml/XMLWireOutputStream.java index 90f877a75..228a67c44 100644 --- a/src/main/java/io/usethesource/vallang/io/binary/wire/xml/XMLWireOutputStream.java +++ b/src/main/java/io/usethesource/vallang/io/binary/wire/xml/XMLWireOutputStream.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.binary.wire.xml; import java.io.IOException; diff --git a/src/main/java/io/usethesource/vallang/random/util/RandomUtil.java b/src/main/java/io/usethesource/vallang/random/util/RandomUtil.java index 2aea6e8a2..924a3b044 100644 --- a/src/main/java/io/usethesource/vallang/random/util/RandomUtil.java +++ b/src/main/java/io/usethesource/vallang/random/util/RandomUtil.java @@ -15,166 +15,166 @@ import io.usethesource.vallang.type.TypeStore; public class RandomUtil { - - private interface StringGen { - public void generate(Random rand, int length, StringBuilder result); - } - - private static class CharRanges implements StringGen { - private int[] start; - private int[] stop; - - public CharRanges(int[] start, int[] stop) { - assert start.length == stop.length; - this.start = start; - this.stop = stop; - } - - public void generate(Random rand, int length, StringBuilder result) { - for (int c = 0; c < length; c++) { - int r = rand.nextInt(start.length); - result.appendCodePoint(generateCodePoint(rand, start[r], stop[r])); - } - } - - private int generateCodePoint(Random rand, int start, int stop) { - int range = stop - start; - int result = 0; - do - result = start + rand.nextInt(range + 1); - while (!validCodePoint(result)); - return result; - } - } - - private static class CharSets implements StringGen { - private int[] chars; - - public CharSets(int... chars) { - this.chars = chars; - } - - @Override - public void generate(Random rand, int length, StringBuilder result) { - for (int c = 0; c < length; c++) - result.appendCodePoint(chars[rand.nextInt(chars.length)]); - } - } - - private static class MixGenerators implements StringGen { - private StringGen[] generators; - - public MixGenerators(StringGen... generators) { - this.generators = generators; - } - @Override - public void generate(Random rand, int length, StringBuilder result) { - int left = length; - while (left > 0) { - int chunk = 1 + rand.nextInt(left); - generators[rand.nextInt(generators.length)].generate(rand, chunk, result); - left -= chunk; - } - } - } - - private static boolean validCodePoint(int cp) { - return Character.isDefined(cp) - && Character.isValidCodePoint(cp) - && Character.getType(cp) != Character.UNASSIGNED - ; - } - - private static String sanitize(String unclean) { - // let's avoid testing with invalid codepoints - int i = 0; - char [] chars = unclean.toCharArray(); - while (i < chars.length) { - char c = chars[i]; - if (Character.isHighSurrogate(c)) { - i++; - if (i < chars.length) { - int cp = Character.toCodePoint(c, chars[i]); - if (!validCodePoint(cp) || !Character.isSurrogatePair(c, chars[i])) { - chars[i-1] = '_'; - chars[i] = '_'; - } - } - else { - chars[i-1] = '_'; - } - } - else if (Character.isLowSurrogate(c)) { - // this means the previous was not high - chars[i] = '_'; - } - else if (!validCodePoint(c)) { - chars[i] = '_'; - } - i++; - } - return new String(chars); - } - - - private final static StringGen alphaOnly = new CharRanges(new int[]{'a','A'}, new int[]{'z','Z'}); - private final static StringGen numeric = new CharRanges(new int[]{'0'}, new int[]{'9'}); - private final static StringGen generalStrangeChars = new CharRanges(new int[]{0x00, 0x21,0xA1}, new int[]{0x09,0x2F,0xAC}); - private final static StringGen normalUnicode = new CharRanges(new int[]{0x0100,0x3400,0xD000}, new int[]{0x0200,0x4D00,0xD700}); - private final static StringGen strangeUnicode = new CharRanges(new int[]{0x12000, 0x20000}, new int[]{0x1247F, 0x215FF}); - private final static StringGen whiteSpace = new CharSets(' ','\t','\n','\t'); - private final static StringGen strangeWhiteSpace = new CharSets(0x85, 0xA0, 0x1680, 0x2000, 0x2028, 0x2029,0x205F,0x3000); - private final static StringGen rascalEscapes = new CharSets('\"','\'','>','\\','<','@','`'); - - private final static StringGen[] generators = new StringGen[] { - alphaOnly, - new MixGenerators(alphaOnly, numeric), - new MixGenerators(alphaOnly, numeric), // increase chances of normal strings - numeric, - normalUnicode, - new MixGenerators(alphaOnly, numeric, generalStrangeChars), - new MixGenerators(alphaOnly, numeric, whiteSpace), - new MixGenerators(strangeWhiteSpace, whiteSpace), - new MixGenerators(normalUnicode, strangeUnicode), - new MixGenerators(alphaOnly, numeric, rascalEscapes), - new MixGenerators(alphaOnly, numeric, generalStrangeChars, normalUnicode, whiteSpace, rascalEscapes) - }; - - public static boolean oneEvery(Random random, int n) { - return random.nextInt(n) == 0; - } - - public static String string(Random rand, int depth) { - StringGen randomGenerator = generators[rand.nextInt(generators.length)]; - StringBuilder result = new StringBuilder(depth * 2); - randomGenerator.generate(rand, depth, result); - return sanitize(result.toString()); - } - public static String stringAlphaNumeric(Random rand, int depth) { - StringBuilder result = new StringBuilder(depth); - new MixGenerators(alphaOnly, numeric).generate(rand, depth, result); - return sanitize(result.toString()); - } - - public static String stringAlpha(Random rand, int depth) { - StringBuilder result = new StringBuilder(depth); - alphaOnly.generate(rand, depth, result); - return sanitize(result.toString()); - } - - public static String stringNumeric(Random rand, int depth) { - StringBuilder result = new StringBuilder(depth); - numeric.generate(rand, depth, result); - return sanitize(result.toString()); - } - - public static String stringAllKindsOfWhitespace(Random rand, int depth) { - StringBuilder result = new StringBuilder(depth); - new MixGenerators(whiteSpace, strangeWhiteSpace).generate(rand, depth, result); - return sanitize(result.toString()); - } - - public static IValue randomADT(Type type, Random random, IValueFactory vf, TypeStore store, Map typeParameters, + + private interface StringGen { + public void generate(Random rand, int length, StringBuilder result); + } + + private static class CharRanges implements StringGen { + private int[] start; + private int[] stop; + + public CharRanges(int[] start, int[] stop) { + assert start.length == stop.length; + this.start = start; + this.stop = stop; + } + + public void generate(Random rand, int length, StringBuilder result) { + for (int c = 0; c < length; c++) { + int r = rand.nextInt(start.length); + result.appendCodePoint(generateCodePoint(rand, start[r], stop[r])); + } + } + + private int generateCodePoint(Random rand, int start, int stop) { + int range = stop - start; + int result = 0; + do + result = start + rand.nextInt(range + 1); + while (!validCodePoint(result)); + return result; + } + } + + private static class CharSets implements StringGen { + private int[] chars; + + public CharSets(int... chars) { + this.chars = chars; + } + + @Override + public void generate(Random rand, int length, StringBuilder result) { + for (int c = 0; c < length; c++) + result.appendCodePoint(chars[rand.nextInt(chars.length)]); + } + } + + private static class MixGenerators implements StringGen { + private StringGen[] generators; + + public MixGenerators(StringGen... generators) { + this.generators = generators; + } + @Override + public void generate(Random rand, int length, StringBuilder result) { + int left = length; + while (left > 0) { + int chunk = 1 + rand.nextInt(left); + generators[rand.nextInt(generators.length)].generate(rand, chunk, result); + left -= chunk; + } + } + } + + private static boolean validCodePoint(int cp) { + return Character.isDefined(cp) + && Character.isValidCodePoint(cp) + && Character.getType(cp) != Character.UNASSIGNED + ; + } + + private static String sanitize(String unclean) { + // let's avoid testing with invalid codepoints + int i = 0; + char [] chars = unclean.toCharArray(); + while (i < chars.length) { + char c = chars[i]; + if (Character.isHighSurrogate(c)) { + i++; + if (i < chars.length) { + int cp = Character.toCodePoint(c, chars[i]); + if (!validCodePoint(cp) || !Character.isSurrogatePair(c, chars[i])) { + chars[i-1] = '_'; + chars[i] = '_'; + } + } + else { + chars[i-1] = '_'; + } + } + else if (Character.isLowSurrogate(c)) { + // this means the previous was not high + chars[i] = '_'; + } + else if (!validCodePoint(c)) { + chars[i] = '_'; + } + i++; + } + return new String(chars); + } + + + private final static StringGen alphaOnly = new CharRanges(new int[]{'a','A'}, new int[]{'z','Z'}); + private final static StringGen numeric = new CharRanges(new int[]{'0'}, new int[]{'9'}); + private final static StringGen generalStrangeChars = new CharRanges(new int[]{0x00, 0x21,0xA1}, new int[]{0x09,0x2F,0xAC}); + private final static StringGen normalUnicode = new CharRanges(new int[]{0x0100,0x3400,0xD000}, new int[]{0x0200,0x4D00,0xD700}); + private final static StringGen strangeUnicode = new CharRanges(new int[]{0x12000, 0x20000}, new int[]{0x1247F, 0x215FF}); + private final static StringGen whiteSpace = new CharSets(' ','\t','\n','\t'); + private final static StringGen strangeWhiteSpace = new CharSets(0x85, 0xA0, 0x1680, 0x2000, 0x2028, 0x2029,0x205F,0x3000); + private final static StringGen rascalEscapes = new CharSets('\"','\'','>','\\','<','@','`'); + + private final static StringGen[] generators = new StringGen[] { + alphaOnly, + new MixGenerators(alphaOnly, numeric), + new MixGenerators(alphaOnly, numeric), // increase chances of normal strings + numeric, + normalUnicode, + new MixGenerators(alphaOnly, numeric, generalStrangeChars), + new MixGenerators(alphaOnly, numeric, whiteSpace), + new MixGenerators(strangeWhiteSpace, whiteSpace), + new MixGenerators(normalUnicode, strangeUnicode), + new MixGenerators(alphaOnly, numeric, rascalEscapes), + new MixGenerators(alphaOnly, numeric, generalStrangeChars, normalUnicode, whiteSpace, rascalEscapes) + }; + + public static boolean oneEvery(Random random, int n) { + return random.nextInt(n) == 0; + } + + public static String string(Random rand, int depth) { + StringGen randomGenerator = generators[rand.nextInt(generators.length)]; + StringBuilder result = new StringBuilder(depth * 2); + randomGenerator.generate(rand, depth, result); + return sanitize(result.toString()); + } + public static String stringAlphaNumeric(Random rand, int depth) { + StringBuilder result = new StringBuilder(depth); + new MixGenerators(alphaOnly, numeric).generate(rand, depth, result); + return sanitize(result.toString()); + } + + public static String stringAlpha(Random rand, int depth) { + StringBuilder result = new StringBuilder(depth); + alphaOnly.generate(rand, depth, result); + return sanitize(result.toString()); + } + + public static String stringNumeric(Random rand, int depth) { + StringBuilder result = new StringBuilder(depth); + numeric.generate(rand, depth, result); + return sanitize(result.toString()); + } + + public static String stringAllKindsOfWhitespace(Random rand, int depth) { + StringBuilder result = new StringBuilder(depth); + new MixGenerators(whiteSpace, strangeWhiteSpace).generate(rand, depth, result); + return sanitize(result.toString()); + } + + public static IValue randomADT(Type type, Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth) { Type uninstantiatedADT = store.lookupAbstractDataType(type.getName()); if (uninstantiatedADT == null) { @@ -197,7 +197,7 @@ public static IValue randomADT(Type type, Random random, IValueFactory vf, TypeS // find the constructor that does not add depth Iterator it = candidates.iterator(); while (alwaysIncreasesDepth(constructor) && it.hasNext()) { - constructor = it.next(); + constructor = it.next(); } if (alwaysIncreasesDepth(constructor)) { constructor = original; // keep it random @@ -205,7 +205,7 @@ public static IValue randomADT(Type type, Random random, IValueFactory vf, TypeS } return generateConstructor(constructor, random, vf, store, bindings, maxDepth, maxWidth); - + } private static boolean alwaysIncreasesDepth(Type constructor) { for (int i = 0; i < constructor.getArity(); i++) { @@ -226,7 +226,7 @@ private static Type pickRandom(Random random, Collection types) { int index = 0; for (Type t: types) { if (index == nth) { - return t; + return t; } index++; } @@ -236,9 +236,9 @@ private static Type pickRandom(Random random, Collection types) { private static IValue generateConstructor(Type type, Random random, IValueFactory vf, TypeStore store, Map bindings, int maxDepth, int maxWidth) { Map kwParamsType = store.getKeywordParameters(type); - if (type.getArity() == 0 && kwParamsType.size() == 0) { + if (type.getArity() == 0 && kwParamsType.size() == 0) { return vf.constructor(type); - } + } IValue[] args = new IValue[type.getArity()]; Type instantiatedConstructor = type.instantiate(bindings); diff --git a/src/main/java/io/usethesource/vallang/type/AbstractDataType.java b/src/main/java/io/usethesource/vallang/type/AbstractDataType.java index 774b32414..fbc2687f2 100644 --- a/src/main/java/io/usethesource/vallang/type/AbstractDataType.java +++ b/src/main/java/io/usethesource/vallang/type/AbstractDataType.java @@ -37,7 +37,7 @@ * A AbstractDataType is an algebraic sort. A sort is produced by * constructors, @see NodeType. There can be many constructors for a single * sort. - * + * * @see ConstructorType */ /* package */ class AbstractDataType extends NodeType { @@ -139,14 +139,14 @@ public Type randomInstance(Supplier next, TypeStore store, RandomTypesConf if (!rnd.isWithRandomAbstractDatatypes()) { return next.get(); } - + if (rnd.nextBoolean()) { Type[] adts = store.getAbstractDataTypes().toArray(new Type[0]); if (adts.length > 0) { // otherwise we will generate a new instance down below return adts[rnd.nextInt(adts.length)]; } - } + } Type adt; @@ -168,13 +168,13 @@ public Type randomInstance(Supplier next, TypeStore store, RandomTypesConf // first declare the open type adt = tf().abstractDataTypeFromTuple(store, adtName, tf().tupleType(param1, param2)); } - } + } else { adt = tf().abstractDataType(store, adtName); } // should be defined by at least one nullary constructor - tf().constructor(store, adt, randomLabel(rnd)); + tf().constructor(store, adt, randomLabel(rnd)); if (rnd.nextBoolean()) { // and perhaps we generate another one with it: @@ -209,22 +209,22 @@ public Type lub(Type other) { public Type glb(Type type) { return type.glbWithAbstractData(this); } - + @Override public boolean intersects(Type other) { return other.intersectsWithAbstractData(this); } - + @Override protected boolean intersectsWithAbstractData(Type type) { if (!isParameterized()) { return type == this; } - + if (type.getName().equals(this.getName())) { return getTypeParameters().intersects(type.getTypeParameters()); } - + return false; } @@ -442,7 +442,7 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< match(done.getType(), typeParameters); return done; } - + @Override public boolean isAbstractData() { return true; diff --git a/src/main/java/io/usethesource/vallang/type/AliasType.java b/src/main/java/io/usethesource/vallang/type/AliasType.java index f6b3bd8c7..a280bfd59 100644 --- a/src/main/java/io/usethesource/vallang/type/AliasType.java +++ b/src/main/java/io/usethesource/vallang/type/AliasType.java @@ -34,7 +34,7 @@ /** * A AliasType is a named for a type, i.e. a type alias that can be used to * abstract from types that have a complex structure. Since a - * + * * @{link Type} represents a set of values, a AliasType is defined to be an * alias (because it represents the same set of values). *

@@ -44,623 +44,623 @@ * refer to the AliasType. */ /* package */ final class AliasType extends Type { - private final String fName; - private final Type fAliased; - private final Type fParameters; - - /* package */ AliasType(String name, Type aliased) { - fName = name; - fAliased = aliased; - fParameters = TypeFactory.getInstance().voidType(); - } - - /* package */ AliasType(String name, Type aliased, Type parameters) { - fName = name; - fAliased = aliased; - fParameters = parameters; - } - - public static class Info extends TypeFactory.TypeReifier { - - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("alias", TF.stringType(), "name", TF.listType(symbols().symbolADT()), "parameters", symbols().symbolADT(), "aliased"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - String name = ((IString) symbol.get("name")).getValue(); - Type aliased = symbols().fromSymbol((IConstructor) symbol.get("aliased"), store, grammar); - IList parameters = (IList) symbol.get("parameters"); - - // we expand the aliases here, but only if the - // type parameters have been instantiated or there are none - if (parameters.isEmpty()) { - return aliased; - } - else { + private final String fName; + private final Type fAliased; + private final Type fParameters; + + /* package */ AliasType(String name, Type aliased) { + fName = name; + fAliased = aliased; + fParameters = TypeFactory.getInstance().voidType(); + } + + /* package */ AliasType(String name, Type aliased, Type parameters) { + fName = name; + fAliased = aliased; + fParameters = parameters; + } + + public static class Info extends TypeFactory.TypeReifier { + + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("alias", TF.stringType(), "name", TF.listType(symbols().symbolADT()), "parameters", symbols().symbolADT(), "aliased"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + String name = ((IString) symbol.get("name")).getValue(); + Type aliased = symbols().fromSymbol((IConstructor) symbol.get("aliased"), store, grammar); + IList parameters = (IList) symbol.get("parameters"); + + // we expand the aliases here, but only if the + // type parameters have been instantiated or there are none + if (parameters.isEmpty()) { + return aliased; + } + else { Type params = symbols().fromSymbols(parameters, store, grammar); - return params.isOpen() ? TF.aliasTypeFromTuple(store, name, aliased, params) : aliased; - } - } + return params.isOpen() ? TF.aliasTypeFromTuple(store, name, aliased, params) : aliased; + } + } - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - // we expand aliases away here! - return type.getAliased().asSymbol(vf, store, grammar, done); - } - - @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - type.getAliased().asProductions(vf, store, grammar, done); - type.getTypeParameters().asProductions(vf, store, grammar, done); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - // we don't generate aliases because we also never reify them - if (!rnd.isWithAliases()) { - return tf().randomType(store, rnd); - } - else { - // TODO: could generate some type parameters as well - return tf().aliasType(store, randomLabel(rnd), tf().randomType(store, rnd)); - } - } - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public boolean isParameterized() { - return !fParameters.isBottom(); - } - - @Override - public boolean isOpen() { - return fParameters.isOpen() || fAliased.isOpen(); - } - - @Override - public boolean isAliased() { - return true; - } - - @Override - public boolean isFixedWidth() { - return fAliased.isFixedWidth(); - } - - /** - * @return the type parameters of the alias type, void when there are none - */ - @Override - public Type getTypeParameters() { - return fParameters; - } - - @Override - public String getName() { - return fName; - } - - @Override - public Type getAliased() { - return fAliased; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfAlias(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithAlias(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithAlias(this); - } - - @Override - protected Type lubWithAlias(Type type) { - if (this == type) - return this; - if (getName().equals(type.getName())) { - return TypeFactory.getInstance().aliasTypeFromTuple(new TypeStore(), type.getName(), - getAliased().lub(type.getAliased()), getTypeParameters().lub(type.getTypeParameters())); - } - - return getAliased().lub(type); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append(fName); - if (isParameterized()) { - sb.append("["); - int idx = 0; - for (Type elemType : fParameters) { - if (idx++ > 0) { - sb.append(","); - } - sb.append(elemType.toString()); - } - sb.append("]"); - } - return sb.toString(); - } - - @Override - public int hashCode() { - return 49991 + 49831 * fName.hashCode() + 67349 * fAliased.hashCode() + 1433 * fParameters.hashCode(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == null) { - return false; - } - - if (o == this) { - return true; - } - - if (o instanceof AliasType) { - AliasType other = (AliasType) o; - return fName.equals(other.fName) && fAliased == other.fAliased && fParameters == other.fParameters; - } - return false; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitAlias(this); - } - - @Override - public int getArity() { - return fAliased.getArity(); - } - - @Override - public Type getBound() { - return fAliased.getBound(); - } - - @Override - public Type getElementType() { - return fAliased.getElementType(); - } - - @Override - public int getFieldIndex(String fieldName) { - return fAliased.getFieldIndex(fieldName); - } - - @Override - public String getFieldName(int i) { - return fAliased.getFieldName(i); - } - - @Override - public String getKeyLabel() { - return fAliased.getKeyLabel(); - } - - @Override - public String getValueLabel() { - return fAliased.getValueLabel(); - } - - @Override - public Type getFieldType(int i) { - return fAliased.getFieldType(i); - } - - @Override - public Type getFieldType(String fieldName) { - return fAliased.getFieldType(fieldName); - } - - @Override - public Type getFieldTypes() { - return fAliased.getFieldTypes(); - } - - @Override - public Type getKeyType() { - return fAliased.getKeyType(); - } - - @Override - public boolean isBottom() { - return fAliased.isBottom(); - } - - @Override - public Type getValueType() { - return fAliased.getValueType(); - } - - @Override - public Type compose(Type other) { - return fAliased.compose(other); - } - - @Override - public boolean hasFieldNames() { - return fAliased.hasFieldNames(); - } - - @Override - public boolean hasKeywordField(String fieldName, TypeStore store) { - return fAliased.hasKeywordField(fieldName, store); - } - - @Override - public Type instantiate(Map bindings) { - if (isParameterized()) { - // note how we do not declare the new alias anywhere. - return TypeFactory.getInstance().getFromCache(new AliasType(fName, fAliased.instantiate(bindings), fParameters.instantiate(bindings))); - } - - // if an alias is not parametrized, then instantiation should not have an effect. - // if it would have an effect, then the alias type would contain an unbound type parameter - // which is a bug we assume is absent here. - return this; - } - - @Override - public boolean match(Type matched, Map bindings) throws FactTypeUseException { - return super.match(matched, bindings) && fAliased.match(matched, bindings); - } - - @Override - public Iterator iterator() { - return fAliased.iterator(); - } - - @Override - public Type select(int... fields) { - return fAliased.select(fields); - } - - @Override - public Type select(String... names) { - return fAliased.select(names); - } - - @Override - public boolean hasField(String fieldName) { - return fAliased.hasField(fieldName); - } - - @Override - public boolean hasField(String fieldName, TypeStore store) { - return fAliased.hasField(fieldName, store); - } - - @Override - protected boolean isSubtypeOfReal(Type type) { - return fAliased.isSubtypeOfReal(type); - } - - @Override - protected boolean isSubtypeOfInteger(Type type) { - return fAliased.isSubtypeOfInteger(type); - } - - @Override - protected boolean isSubtypeOfRational(Type type) { - return fAliased.isSubtypeOfRational(type); - } - - @Override - protected boolean isSubtypeOfList(Type type) { - return fAliased.isSubtypeOfList(type); - } - - @Override - protected boolean isSubtypeOfMap(Type type) { - return fAliased.isSubtypeOfMap(type); - } - - @Override - protected boolean isSubtypeOfNumber(Type type) { - return fAliased.isSubtypeOfNumber(type); - } - - @Override - protected boolean isSubtypeOfSet(Type type) { - return fAliased.isSubtypeOfSet(type); - } - - @Override - protected boolean isSubtypeOfSourceLocation(Type type) { - return fAliased.isSubtypeOfSourceLocation(type); - } - - @Override - protected boolean isSubtypeOfString(Type type) { - return fAliased.isSubtypeOfString(type); - } - - @Override - protected boolean isSubtypeOfNode(Type type) { - return fAliased.isSubtypeOfNode(type); - } - - @Override - protected boolean isSubtypeOfConstructor(Type type) { - return fAliased.isSubtypeOfConstructor(type); - } - - @Override - protected boolean isSubtypeOfAbstractData(Type type) { - return fAliased.isSubtypeOfAbstractData(type); - } - - @Override - protected boolean isSubtypeOfTuple(Type type) { - return fAliased.isSubtypeOfTuple(type); - } - - @Override - protected boolean isSubtypeOfFunction(Type type) { - return fAliased.isSubtypeOfFunction(type); - } - - @Override - protected boolean isSubtypeOfVoid(Type type) { - return fAliased.isSubtypeOfVoid(type); - } - - @Override - protected boolean isSubtypeOfBool(Type type) { - return fAliased.isSubtypeOfBool(type); - } - - @Override - protected boolean isSubtypeOfExternal(Type type) { - return fAliased.isSubtypeOfExternal(type); - } - - @Override - protected boolean isSubtypeOfDateTime(Type type) { - return fAliased.isSubtypeOfDateTime(type); - } - - @Override - protected Type lubWithReal(Type type) { - return fAliased.lubWithReal(type); - } - - @Override - protected Type lubWithInteger(Type type) { - return fAliased.lubWithInteger(type); - } - - @Override - protected Type lubWithRational(Type type) { - return fAliased.lubWithRational(type); - } - - @Override - protected Type lubWithList(Type type) { - return fAliased.lubWithList(type); - } - - @Override - protected Type lubWithMap(Type type) { - return fAliased.lubWithMap(type); - } - - @Override - protected Type lubWithNumber(Type type) { - return fAliased.lubWithNumber(type); - } - - @Override - protected Type lubWithSet(Type type) { - return fAliased.lubWithSet(type); - } - - @Override - protected Type lubWithSourceLocation(Type type) { - return fAliased.lubWithSourceLocation(type); - } - - @Override - protected Type lubWithString(Type type) { - return fAliased.lubWithString(type); - } - - @Override - protected Type lubWithNode(Type type) { - return fAliased.lubWithNode(type); - } - - @Override - protected Type lubWithConstructor(Type type) { - return fAliased.lubWithConstructor(type); - } - - @Override - protected Type lubWithAbstractData(Type type) { - return fAliased.lubWithAbstractData(type); - } - - @Override - protected Type lubWithTuple(Type type) { - return fAliased.lubWithTuple(type); - } - - @Override - protected Type lubWithFunction(Type type) { - return fAliased.lubWithFunction(type); - } - - @Override - protected Type lubWithValue(Type type) { - return fAliased.lubWithValue(type); - } - - @Override - protected Type lubWithVoid(Type type) { - return fAliased.lubWithVoid(type); - } - - @Override - protected Type lubWithBool(Type type) { - return fAliased.lubWithBool(type); - } - - @Override - protected Type lubWithExternal(Type type) { - return fAliased.lubWithExternal(type); - } - - @Override - protected Type lubWithDateTime(Type type) { - return fAliased.lubWithDateTime(type); - } - - @Override - protected boolean isSubtypeOfValue(Type type) { - return true; - } - - @Override - protected Type glbWithReal(Type type) { - return fAliased.glbWithReal(type); - } - - @Override - protected Type glbWithInteger(Type type) { - return fAliased.glbWithInteger(type); - } - - @Override - protected Type glbWithRational(Type type) { - return fAliased.glbWithRational(type); - } - - @Override - protected Type glbWithList(Type type) { - return fAliased.glbWithList(type); - } - - @Override - protected Type glbWithMap(Type type) { - return fAliased.glbWithMap(type); - } - - @Override - protected Type glbWithNumber(Type type) { - return fAliased.glbWithNumber(type); - } - - @Override - protected Type glbWithSet(Type type) { - return fAliased.glbWithSet(type); - } - - @Override - protected Type glbWithSourceLocation(Type type) { - return fAliased.glbWithSourceLocation(type); - } - - @Override - protected Type glbWithString(Type type) { - return fAliased.glbWithString(type); - } - - @Override - protected Type glbWithNode(Type type) { - return fAliased.glbWithNode(type); - } - - @Override - protected Type glbWithConstructor(Type type) { - return fAliased.glbWithConstructor(type); - } - - @Override - protected Type glbWithAlias(Type type) { - if (this == type) - return this; - if (getName().equals(type.getName())) { - return TypeFactory.getInstance().aliasTypeFromTuple(new TypeStore(), type.getName(), - getAliased().glb(type.getAliased()), getTypeParameters().glb(type.getTypeParameters())); - } - - return getAliased().glb(type); - } - - @Override - protected Type glbWithAbstractData(Type type) { - return fAliased.glbWithAbstractData(type); - } - - @Override - protected Type glbWithTuple(Type type) { - return fAliased.glbWithTuple(type); - } - - @Override - protected Type glbWithFunction(Type type) { - return fAliased.glbWithFunction(type); - } - - @Override - protected Type glbWithValue(Type type) { - return fAliased.glbWithValue(type); - } - - @Override - protected Type glbWithVoid(Type type) { - return fAliased.glbWithVoid(type); - } - - @Override - protected Type glbWithBool(Type type) { - return fAliased.glbWithBool(type); - } - - @Override - protected Type glbWithExternal(Type type) { - return fAliased.glbWithExternal(type); - } - - @Override - protected Type glbWithDateTime(Type type) { - return fAliased.glbWithDateTime(type); - } - - @Override - public Type getAbstractDataType() { - return fAliased.getAbstractDataType(); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxBreadth) { - return getAliased().randomValue(random, vf, store, typeParameters, maxDepth, maxBreadth); - } + // we expand aliases away here! + return type.getAliased().asSymbol(vf, store, grammar, done); + } + + @Override + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + type.getAliased().asProductions(vf, store, grammar, done); + type.getTypeParameters().asProductions(vf, store, grammar, done); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + // we don't generate aliases because we also never reify them + if (!rnd.isWithAliases()) { + return tf().randomType(store, rnd); + } + else { + // TODO: could generate some type parameters as well + return tf().aliasType(store, randomLabel(rnd), tf().randomType(store, rnd)); + } + } + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public boolean isParameterized() { + return !fParameters.isBottom(); + } + + @Override + public boolean isOpen() { + return fParameters.isOpen() || fAliased.isOpen(); + } + + @Override + public boolean isAliased() { + return true; + } + + @Override + public boolean isFixedWidth() { + return fAliased.isFixedWidth(); + } + + /** + * @return the type parameters of the alias type, void when there are none + */ + @Override + public Type getTypeParameters() { + return fParameters; + } + + @Override + public String getName() { + return fName; + } + + @Override + public Type getAliased() { + return fAliased; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfAlias(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithAlias(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithAlias(this); + } + + @Override + protected Type lubWithAlias(Type type) { + if (this == type) + return this; + if (getName().equals(type.getName())) { + return TypeFactory.getInstance().aliasTypeFromTuple(new TypeStore(), type.getName(), + getAliased().lub(type.getAliased()), getTypeParameters().lub(type.getTypeParameters())); + } + + return getAliased().lub(type); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(fName); + if (isParameterized()) { + sb.append("["); + int idx = 0; + for (Type elemType : fParameters) { + if (idx++ > 0) { + sb.append(","); + } + sb.append(elemType.toString()); + } + sb.append("]"); + } + return sb.toString(); + } + + @Override + public int hashCode() { + return 49991 + 49831 * fName.hashCode() + 67349 * fAliased.hashCode() + 1433 * fParameters.hashCode(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null) { + return false; + } + + if (o == this) { + return true; + } + + if (o instanceof AliasType) { + AliasType other = (AliasType) o; + return fName.equals(other.fName) && fAliased == other.fAliased && fParameters == other.fParameters; + } + return false; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitAlias(this); + } + + @Override + public int getArity() { + return fAliased.getArity(); + } + + @Override + public Type getBound() { + return fAliased.getBound(); + } + + @Override + public Type getElementType() { + return fAliased.getElementType(); + } + + @Override + public int getFieldIndex(String fieldName) { + return fAliased.getFieldIndex(fieldName); + } + + @Override + public String getFieldName(int i) { + return fAliased.getFieldName(i); + } + + @Override + public String getKeyLabel() { + return fAliased.getKeyLabel(); + } + + @Override + public String getValueLabel() { + return fAliased.getValueLabel(); + } + + @Override + public Type getFieldType(int i) { + return fAliased.getFieldType(i); + } + + @Override + public Type getFieldType(String fieldName) { + return fAliased.getFieldType(fieldName); + } + + @Override + public Type getFieldTypes() { + return fAliased.getFieldTypes(); + } + + @Override + public Type getKeyType() { + return fAliased.getKeyType(); + } + + @Override + public boolean isBottom() { + return fAliased.isBottom(); + } + + @Override + public Type getValueType() { + return fAliased.getValueType(); + } + + @Override + public Type compose(Type other) { + return fAliased.compose(other); + } + + @Override + public boolean hasFieldNames() { + return fAliased.hasFieldNames(); + } + + @Override + public boolean hasKeywordField(String fieldName, TypeStore store) { + return fAliased.hasKeywordField(fieldName, store); + } + + @Override + public Type instantiate(Map bindings) { + if (isParameterized()) { + // note how we do not declare the new alias anywhere. + return TypeFactory.getInstance().getFromCache(new AliasType(fName, fAliased.instantiate(bindings), fParameters.instantiate(bindings))); + } + + // if an alias is not parametrized, then instantiation should not have an effect. + // if it would have an effect, then the alias type would contain an unbound type parameter + // which is a bug we assume is absent here. + return this; + } + + @Override + public boolean match(Type matched, Map bindings) throws FactTypeUseException { + return super.match(matched, bindings) && fAliased.match(matched, bindings); + } + + @Override + public Iterator iterator() { + return fAliased.iterator(); + } + + @Override + public Type select(int... fields) { + return fAliased.select(fields); + } + + @Override + public Type select(String... names) { + return fAliased.select(names); + } + + @Override + public boolean hasField(String fieldName) { + return fAliased.hasField(fieldName); + } + + @Override + public boolean hasField(String fieldName, TypeStore store) { + return fAliased.hasField(fieldName, store); + } + + @Override + protected boolean isSubtypeOfReal(Type type) { + return fAliased.isSubtypeOfReal(type); + } + + @Override + protected boolean isSubtypeOfInteger(Type type) { + return fAliased.isSubtypeOfInteger(type); + } + + @Override + protected boolean isSubtypeOfRational(Type type) { + return fAliased.isSubtypeOfRational(type); + } + + @Override + protected boolean isSubtypeOfList(Type type) { + return fAliased.isSubtypeOfList(type); + } + + @Override + protected boolean isSubtypeOfMap(Type type) { + return fAliased.isSubtypeOfMap(type); + } + + @Override + protected boolean isSubtypeOfNumber(Type type) { + return fAliased.isSubtypeOfNumber(type); + } + + @Override + protected boolean isSubtypeOfSet(Type type) { + return fAliased.isSubtypeOfSet(type); + } + + @Override + protected boolean isSubtypeOfSourceLocation(Type type) { + return fAliased.isSubtypeOfSourceLocation(type); + } + + @Override + protected boolean isSubtypeOfString(Type type) { + return fAliased.isSubtypeOfString(type); + } + + @Override + protected boolean isSubtypeOfNode(Type type) { + return fAliased.isSubtypeOfNode(type); + } + + @Override + protected boolean isSubtypeOfConstructor(Type type) { + return fAliased.isSubtypeOfConstructor(type); + } + + @Override + protected boolean isSubtypeOfAbstractData(Type type) { + return fAliased.isSubtypeOfAbstractData(type); + } + + @Override + protected boolean isSubtypeOfTuple(Type type) { + return fAliased.isSubtypeOfTuple(type); + } + + @Override + protected boolean isSubtypeOfFunction(Type type) { + return fAliased.isSubtypeOfFunction(type); + } + + @Override + protected boolean isSubtypeOfVoid(Type type) { + return fAliased.isSubtypeOfVoid(type); + } + + @Override + protected boolean isSubtypeOfBool(Type type) { + return fAliased.isSubtypeOfBool(type); + } + + @Override + protected boolean isSubtypeOfExternal(Type type) { + return fAliased.isSubtypeOfExternal(type); + } + + @Override + protected boolean isSubtypeOfDateTime(Type type) { + return fAliased.isSubtypeOfDateTime(type); + } + + @Override + protected Type lubWithReal(Type type) { + return fAliased.lubWithReal(type); + } + + @Override + protected Type lubWithInteger(Type type) { + return fAliased.lubWithInteger(type); + } + + @Override + protected Type lubWithRational(Type type) { + return fAliased.lubWithRational(type); + } + + @Override + protected Type lubWithList(Type type) { + return fAliased.lubWithList(type); + } + + @Override + protected Type lubWithMap(Type type) { + return fAliased.lubWithMap(type); + } + + @Override + protected Type lubWithNumber(Type type) { + return fAliased.lubWithNumber(type); + } + + @Override + protected Type lubWithSet(Type type) { + return fAliased.lubWithSet(type); + } + + @Override + protected Type lubWithSourceLocation(Type type) { + return fAliased.lubWithSourceLocation(type); + } + + @Override + protected Type lubWithString(Type type) { + return fAliased.lubWithString(type); + } + + @Override + protected Type lubWithNode(Type type) { + return fAliased.lubWithNode(type); + } + + @Override + protected Type lubWithConstructor(Type type) { + return fAliased.lubWithConstructor(type); + } + + @Override + protected Type lubWithAbstractData(Type type) { + return fAliased.lubWithAbstractData(type); + } + + @Override + protected Type lubWithTuple(Type type) { + return fAliased.lubWithTuple(type); + } + + @Override + protected Type lubWithFunction(Type type) { + return fAliased.lubWithFunction(type); + } + + @Override + protected Type lubWithValue(Type type) { + return fAliased.lubWithValue(type); + } + + @Override + protected Type lubWithVoid(Type type) { + return fAliased.lubWithVoid(type); + } + + @Override + protected Type lubWithBool(Type type) { + return fAliased.lubWithBool(type); + } + + @Override + protected Type lubWithExternal(Type type) { + return fAliased.lubWithExternal(type); + } + + @Override + protected Type lubWithDateTime(Type type) { + return fAliased.lubWithDateTime(type); + } + + @Override + protected boolean isSubtypeOfValue(Type type) { + return true; + } + + @Override + protected Type glbWithReal(Type type) { + return fAliased.glbWithReal(type); + } + + @Override + protected Type glbWithInteger(Type type) { + return fAliased.glbWithInteger(type); + } + + @Override + protected Type glbWithRational(Type type) { + return fAliased.glbWithRational(type); + } + + @Override + protected Type glbWithList(Type type) { + return fAliased.glbWithList(type); + } + + @Override + protected Type glbWithMap(Type type) { + return fAliased.glbWithMap(type); + } + + @Override + protected Type glbWithNumber(Type type) { + return fAliased.glbWithNumber(type); + } + + @Override + protected Type glbWithSet(Type type) { + return fAliased.glbWithSet(type); + } + + @Override + protected Type glbWithSourceLocation(Type type) { + return fAliased.glbWithSourceLocation(type); + } + + @Override + protected Type glbWithString(Type type) { + return fAliased.glbWithString(type); + } + + @Override + protected Type glbWithNode(Type type) { + return fAliased.glbWithNode(type); + } + + @Override + protected Type glbWithConstructor(Type type) { + return fAliased.glbWithConstructor(type); + } + + @Override + protected Type glbWithAlias(Type type) { + if (this == type) + return this; + if (getName().equals(type.getName())) { + return TypeFactory.getInstance().aliasTypeFromTuple(new TypeStore(), type.getName(), + getAliased().glb(type.getAliased()), getTypeParameters().glb(type.getTypeParameters())); + } + + return getAliased().glb(type); + } + + @Override + protected Type glbWithAbstractData(Type type) { + return fAliased.glbWithAbstractData(type); + } + + @Override + protected Type glbWithTuple(Type type) { + return fAliased.glbWithTuple(type); + } + + @Override + protected Type glbWithFunction(Type type) { + return fAliased.glbWithFunction(type); + } + + @Override + protected Type glbWithValue(Type type) { + return fAliased.glbWithValue(type); + } + + @Override + protected Type glbWithVoid(Type type) { + return fAliased.glbWithVoid(type); + } + + @Override + protected Type glbWithBool(Type type) { + return fAliased.glbWithBool(type); + } + + @Override + protected Type glbWithExternal(Type type) { + return fAliased.glbWithExternal(type); + } + + @Override + protected Type glbWithDateTime(Type type) { + return fAliased.glbWithDateTime(type); + } + + @Override + public Type getAbstractDataType() { + return fAliased.getAbstractDataType(); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxBreadth) { + return getAliased().randomValue(random, vf, store, typeParameters, maxDepth, maxBreadth); + } @Override public boolean intersects(Type other) { @@ -730,9 +730,9 @@ protected boolean intersectsWithAbstractData(Type type) { @Override protected boolean intersectsWithTuple(Type type) { return fAliased.intersectsWithTuple(type); - } - - @Override + } + + @Override protected boolean intersectsWithFunction(Type type) { return fAliased.intersectsWithFunction(type); } @@ -744,7 +744,7 @@ protected boolean intersectsWithValue(Type type) { @Override protected boolean intersectsWithVoid(Type type) { - return fAliased.intersectsWithVoid(type); + return fAliased.intersectsWithVoid(type); } @Override diff --git a/src/main/java/io/usethesource/vallang/type/BoolType.java b/src/main/java/io/usethesource/vallang/type/BoolType.java index ab79642e3..4fb91629c 100644 --- a/src/main/java/io/usethesource/vallang/type/BoolType.java +++ b/src/main/java/io/usethesource/vallang/type/BoolType.java @@ -26,115 +26,115 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class BoolType extends DefaultSubtypeOfValue { - private final static class InstanceKeeper { - public final static BoolType sInstance = new BoolType(); - } - - public static BoolType getInstance() { - return InstanceKeeper.sInstance; - } - - public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("bool"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, - Function> grammar) { - return getInstance(); - } + private final static class InstanceKeeper { + public final static BoolType sInstance = new BoolType(); + } + + public static BoolType getInstance() { + return InstanceKeeper.sInstance; + } + + public static class Info extends TypeFactory.TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("bool"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, + Function> grammar) { + return getInstance(); + } @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { return tf().boolType(); } - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxBreadth) { - return vf.bool(random.nextBoolean()); - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - /** - * Should never need to be called; there should be only one instance of - * IntegerType - */ - @Override - public boolean equals(@Nullable Object obj) { - return obj == BoolType.getInstance(); -} - - @Override - public int hashCode() { - return 84121; - } - - @Override - public String toString() { - return "bool"; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitBool(this); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithBool(this); - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfBool(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithBool(this); - } - - @Override - protected boolean isSubtypeOfBool(Type type) { - return true; - } - - - @Override - protected Type lubWithBool(Type type) { - return this; - } - - @Override - public Type glb(Type type) { - return type.glbWithBool(this); - } - - - @Override - protected boolean intersectsWithBool(Type type) { - return true; - } - - @Override - protected Type glbWithBool(Type type) { - return this; - } - - @Override - public boolean isBool() { - return true; - } + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxBreadth) { + return vf.bool(random.nextBoolean()); + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + /** + * Should never need to be called; there should be only one instance of + * IntegerType + */ + @Override + public boolean equals(@Nullable Object obj) { + return obj == BoolType.getInstance(); + } + + @Override + public int hashCode() { + return 84121; + } + + @Override + public String toString() { + return "bool"; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitBool(this); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithBool(this); + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfBool(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithBool(this); + } + + @Override + protected boolean isSubtypeOfBool(Type type) { + return true; + } + + + @Override + protected Type lubWithBool(Type type) { + return this; + } + + @Override + public Type glb(Type type) { + return type.glbWithBool(this); + } + + + @Override + protected boolean intersectsWithBool(Type type) { + return true; + } + + @Override + protected Type glbWithBool(Type type) { + return this; + } + + @Override + public boolean isBool() { + return true; + } } diff --git a/src/main/java/io/usethesource/vallang/type/ConstructorType.java b/src/main/java/io/usethesource/vallang/type/ConstructorType.java index d74f3023c..ba7b85b86 100644 --- a/src/main/java/io/usethesource/vallang/type/ConstructorType.java +++ b/src/main/java/io/usethesource/vallang/type/ConstructorType.java @@ -33,99 +33,99 @@ /** * A tree type is a type of tree node, defined by its name, the types of * its children and the type it produces. Example tree types would be: - * + * * Address ::= dutchAddress(Street, City, Postcode) * Address ::= usAddress(Street, City, State, PostalCode) - * + * * Here Address is the AbstractDataType, the type a tree produces. dutchAddress * and usAddress are the names of the node types and the other capitalized names * are the types of the children. - * + * * Children types can also be named as in: * Boolean ::= and(Boolean lhs, Boolean rhs) * Boolean ::= or(Boolean lhs, Boolean rhs) - * + * */ /*package*/ final class ConstructorType extends AbstractDataType { - private final Type fChildrenTypes; - private final Type fADT; - private final String fName; - - /* package */ ConstructorType(String name, Type childrenTypes, Type adt) { - super(adt.getName(), adt.getTypeParameters()); - fName = name.intern(); // TODO remove this expensive trick - fChildrenTypes = childrenTypes; - fADT = adt; - } - - public static class Info extends TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("cons", symbols().symbolADT(), "adt", tf().stringType(), "name", tf().listType(symbols().symbolADT()), "parameters"); - } - - public Type getProductionConstructorType() { - return symbols().typeProductionConstructor("cons", symbols().symbolADT(), "def", TF.listType(symbols().symbolADT()), "symbols", TF.listType(symbols().symbolADT()), "kwTypes", tf().setType(symbols().attrADT()), "attributes"); - } - - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - IListWriter w = vf.listWriter(); - - if (type.hasFieldNames()) { - for (int i = 0; i < type.getArity(); i++) { - w.append(symbols().labelSymbol(vf, type.getFieldType(i).asSymbol(vf, store, grammar, done), type.getFieldName(i))); - } - } - else { - for (Type field : type.getFieldTypes()) { - w.append(field.asSymbol(vf, store, grammar, done)); - } - } - - IConstructor adt = type.getAbstractDataType().asSymbol(vf, store, grammar, done); - IConstructor cons = vf.constructor(getSymbolConstructorType(), adt, vf.string(type.getName()), w.done()); - - return cons; - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - Type adt = symbols().fromSymbol((IConstructor) symbol.get("adt"), store, grammar); - IList parameters = (IList) symbol.get("parameters"); - String name = ((IString) symbol.get("name")).getValue(); - return TF.constructorFromTuple(store, adt, name, symbols().fromSymbols(parameters, store, grammar)); - } - - /*package*/ Type fromProduction(IConstructor prod, TypeStore store, Function> grammar) { - if (prod.getConstructorType() == getSymbolConstructorType()) { - // TODO this should not be necessary after standardizing cons representations - return fromAlternativeProduction(prod, store, grammar); - } - - // TODO remove double field name after bootstrap - IConstructor adt = (IConstructor) (prod.has("def") ? prod.get("def") : prod.get("adt")); - String name = symbols().getLabel(adt); - IConstructor sym = symbols().getLabeledSymbol(adt); - IList parameters = (IList) prod.get("symbols"); - IList kwtypes = (IList) prod.get("kwTypes"); - - Type cons = TF.constructorFromTuple(store, symbols().fromSymbol(sym, store, grammar), name, symbols().fromSymbols(parameters, store, grammar)); - - for (IValue kwType : kwtypes) { - store.declareKeywordParameter(cons, symbols().getLabel(kwType), symbols().fromSymbol(symbols().getLabeledSymbol(kwType), store, grammar)); - } - - return cons; - } - - private Type fromAlternativeProduction(IConstructor prod, TypeStore store, Function> grammar) { - IConstructor adt = (IConstructor) prod.get("adt"); + private final Type fChildrenTypes; + private final Type fADT; + private final String fName; + + /* package */ ConstructorType(String name, Type childrenTypes, Type adt) { + super(adt.getName(), adt.getTypeParameters()); + fName = name.intern(); // TODO remove this expensive trick + fChildrenTypes = childrenTypes; + fADT = adt; + } + + public static class Info extends TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("cons", symbols().symbolADT(), "adt", tf().stringType(), "name", tf().listType(symbols().symbolADT()), "parameters"); + } + + public Type getProductionConstructorType() { + return symbols().typeProductionConstructor("cons", symbols().symbolADT(), "def", TF.listType(symbols().symbolADT()), "symbols", TF.listType(symbols().symbolADT()), "kwTypes", tf().setType(symbols().attrADT()), "attributes"); + } + + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + IListWriter w = vf.listWriter(); + + if (type.hasFieldNames()) { + for (int i = 0; i < type.getArity(); i++) { + w.append(symbols().labelSymbol(vf, type.getFieldType(i).asSymbol(vf, store, grammar, done), type.getFieldName(i))); + } + } + else { + for (Type field : type.getFieldTypes()) { + w.append(field.asSymbol(vf, store, grammar, done)); + } + } + + IConstructor adt = type.getAbstractDataType().asSymbol(vf, store, grammar, done); + IConstructor cons = vf.constructor(getSymbolConstructorType(), adt, vf.string(type.getName()), w.done()); + + return cons; + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + Type adt = symbols().fromSymbol((IConstructor) symbol.get("adt"), store, grammar); + IList parameters = (IList) symbol.get("parameters"); + String name = ((IString) symbol.get("name")).getValue(); + return TF.constructorFromTuple(store, adt, name, symbols().fromSymbols(parameters, store, grammar)); + } + + /*package*/ Type fromProduction(IConstructor prod, TypeStore store, Function> grammar) { + if (prod.getConstructorType() == getSymbolConstructorType()) { + // TODO this should not be necessary after standardizing cons representations + return fromAlternativeProduction(prod, store, grammar); + } + + // TODO remove double field name after bootstrap + IConstructor adt = (IConstructor) (prod.has("def") ? prod.get("def") : prod.get("adt")); + String name = symbols().getLabel(adt); + IConstructor sym = symbols().getLabeledSymbol(adt); + IList parameters = (IList) prod.get("symbols"); + IList kwtypes = (IList) prod.get("kwTypes"); + + Type cons = TF.constructorFromTuple(store, symbols().fromSymbol(sym, store, grammar), name, symbols().fromSymbols(parameters, store, grammar)); + + for (IValue kwType : kwtypes) { + store.declareKeywordParameter(cons, symbols().getLabel(kwType), symbols().fromSymbol(symbols().getLabeledSymbol(kwType), store, grammar)); + } + + return cons; + } + + private Type fromAlternativeProduction(IConstructor prod, TypeStore store, Function> grammar) { + IConstructor adt = (IConstructor) prod.get("adt"); String name = ((IString) prod.get("name")).getValue(); IList parameters = (IList) prod.get("parameters"); @@ -133,288 +133,288 @@ private Type fromAlternativeProduction(IConstructor prod, TypeStore store, Funct } @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - IConstructor adt = type.getAbstractDataType().asSymbol(vf, store, grammar, done); - - IListWriter w = vf.listWriter(); - if (type.hasFieldNames()) { - for (int i = 0; i < type.getArity(); i++) { - w.append(symbols().labelSymbol(vf, type.getFieldType(i).asSymbol(vf, store, grammar, done), type.getFieldName(i))); - } - } - else { - for (Type field : type.getFieldTypes()) { - w.append(field.asSymbol(vf, store, grammar, done)); - } - } - - IListWriter kwTypes = vf.listWriter(); - Map keywordParameters = store.getKeywordParameters(type); - - for (String label : keywordParameters.keySet()) { - kwTypes.insert(symbols().labelSymbol(vf, keywordParameters.get(label).asSymbol(vf, store, grammar, done), label)); - } - - IConstructor cons = vf.constructor(getProductionConstructorType(), symbols().labelSymbol(vf, adt, type.getName()), w.done(), kwTypes.done(), vf.set()); - - grammar.insert(vf.tuple(adt, cons)); - } - + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + IConstructor adt = type.getAbstractDataType().asSymbol(vf, store, grammar, done); + + IListWriter w = vf.listWriter(); + if (type.hasFieldNames()) { + for (int i = 0; i < type.getArity(); i++) { + w.append(symbols().labelSymbol(vf, type.getFieldType(i).asSymbol(vf, store, grammar, done), type.getFieldName(i))); + } + } + else { + for (Type field : type.getFieldTypes()) { + w.append(field.asSymbol(vf, store, grammar, done)); + } + } + + IListWriter kwTypes = vf.listWriter(); + Map keywordParameters = store.getKeywordParameters(type); + + for (String label : keywordParameters.keySet()) { + kwTypes.insert(symbols().labelSymbol(vf, keywordParameters.get(label).asSymbol(vf, store, grammar, done), label)); + } + + IConstructor cons = vf.constructor(getProductionConstructorType(), symbols().labelSymbol(vf, adt, type.getName()), w.done(), kwTypes.done(), vf.set()); + + grammar.insert(vf.tuple(adt, cons)); + } + @Override public boolean isRecursive() { return true; } - + @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - // constructors should not be random types of values (a value never has a constructor type) + // constructors should not be random types of values (a value never has a constructor type) return new AbstractDataType.Info(symbols()).randomInstance(next, store, rnd); } - } + } - @Override + @Override public TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public Type carrier() { - return fChildrenTypes.carrier(); - } - - @Override - public int hashCode() { - return 21 + 44927 * ((fName != null) ? fName.hashCode() : 1) + - 181 * fChildrenTypes.hashCode() + - 354767453 * fADT.hashCode(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == null) { - return false; - } - - if (o.getClass().equals(getClass())) { - ConstructorType other = (ConstructorType) o; - - if (fName != other.fName) { // fName is interned, change to equals when intern() is removed - return false; - } - - if (fChildrenTypes != other.fChildrenTypes) { - return false; - } - - if (fADT != other.fADT) { - return false; - } - - - // nothing is different - return true; - } - - // not a constructor type - return false; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - boolean hasNames = hasFieldNames(); - builder.append(fADT); - builder.append(" = "); - builder.append(fName); - builder.append("("); - - for (int i = 0; i < getArity(); i++) { - Type argType = fChildrenTypes.getFieldType(i); - builder.append(argType); - - if (hasNames) { - builder.append(' '); - builder.append(fChildrenTypes.getFieldName(i)); - } - - if (i < getArity() - 1) { - builder.append(','); - } - } - - builder.append(")"); - - return builder.toString(); - } - - @Override - public int getArity() { - return fChildrenTypes.getArity(); - } - - @Override - public int getFieldIndex(String fieldName) throws FactTypeUseException { - return fChildrenTypes.getFieldIndex(fieldName); - } - - @Override - public boolean hasField(String fieldName) { - return fChildrenTypes.hasField(fieldName); - } - - @Override - public boolean hasField(String fieldName, TypeStore store) { - return hasField(fieldName) ; - } - - @Override - public boolean hasKeywordField(String fieldName, TypeStore store) { - return store.hasKeywordParameter(this, fieldName); - } - - @Override - public Type getFieldTypes() { - return fChildrenTypes; - } - - - @Override - public String getName() { - return fName; - } - - @Override - public Type getAbstractDataType() { - return fADT; - } - - @Override - public Type getFieldType(int i) { - return fChildrenTypes.getFieldType(i); - } - - @Override - public Type getFieldType(String fieldName) throws FactTypeUseException { - return fChildrenTypes.getFieldType(fieldName); - } - - @Override - public String getFieldName(int i) { - return fChildrenTypes.getFieldName(i); - } - - @Override - public String[] getFieldNames() { - return fChildrenTypes.getFieldNames(); - } - - @Override - public boolean hasFieldNames() { - return fChildrenTypes.hasFieldNames(); - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitConstructor(this); - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfConstructor(this); - } - - @Override - public Type lub(Type type) { - return type.lubWithConstructor(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithConstructor(this); - } - - @Override - protected boolean isSubtypeOfConstructor(Type type) { - if (type.getName().equals(getName())) { - return getAbstractDataType().isSubtypeOf(type.getAbstractDataType()) - && getFieldTypes().isSubtypeOf(type.getFieldTypes()); - } - else { - return false; - } - } - - @Override - protected boolean isSubtypeOfAbstractData(Type type) { - return getAbstractDataType().isSubtypeOfAbstractData(type); - } - - @Override - protected Type lubWithConstructor(Type type) { - if(this == type) { - return this; - } - return getAbstractDataType().lubWithAbstractData(type.getAbstractDataType()); - } - - @Override - protected Type glbWithConstructor(Type type) { - if (type.isSubtypeOf(this)) { - return type; - } - else if (isSubtypeOf(type)) { - return this; - } - else { - return TF.voidType(); - } - } - - @Override - protected Type glbWithAbstractData(Type type) { - if (isSubtypeOf(type)) { - return this; - } - - return TF.voidType(); - } - - @Override - protected Type glbWithNode(Type type) { - return this; - } - - @Override - public boolean match(Type matched, Map bindings) - throws FactTypeUseException { - return super.match(matched, bindings) - && fADT.match(matched.getAbstractDataType(), bindings) - && getFieldTypes().match(matched.getFieldTypes(), bindings); - } - - @Override - public Type instantiate(Map bindings) { - if (bindings.isEmpty()) { - return this; - } - Type adt = fADT.instantiate(bindings); - Type fields = getFieldTypes().instantiate(bindings); - - TypeStore store = new TypeStore(); - store.declareAbstractDataType(fADT); - store.declareConstructor(this); - - return TypeFactory.getInstance().constructorFromTuple(store, adt, getName(), fields); - } - - @Override - public boolean isParameterized() { - return fADT.isParameterized(); - } - - @Override - public boolean isConstructor() { - return true; - } + return new Info(symbols); + } + + @Override + public Type carrier() { + return fChildrenTypes.carrier(); + } + + @Override + public int hashCode() { + return 21 + 44927 * ((fName != null) ? fName.hashCode() : 1) + + 181 * fChildrenTypes.hashCode() + + 354767453 * fADT.hashCode(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null) { + return false; + } + + if (o.getClass().equals(getClass())) { + ConstructorType other = (ConstructorType) o; + + if (fName != other.fName) { // fName is interned, change to equals when intern() is removed + return false; + } + + if (fChildrenTypes != other.fChildrenTypes) { + return false; + } + + if (fADT != other.fADT) { + return false; + } + + + // nothing is different + return true; + } + + // not a constructor type + return false; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + boolean hasNames = hasFieldNames(); + builder.append(fADT); + builder.append(" = "); + builder.append(fName); + builder.append("("); + + for (int i = 0; i < getArity(); i++) { + Type argType = fChildrenTypes.getFieldType(i); + builder.append(argType); + + if (hasNames) { + builder.append(' '); + builder.append(fChildrenTypes.getFieldName(i)); + } + + if (i < getArity() - 1) { + builder.append(','); + } + } + + builder.append(")"); + + return builder.toString(); + } + + @Override + public int getArity() { + return fChildrenTypes.getArity(); + } + + @Override + public int getFieldIndex(String fieldName) throws FactTypeUseException { + return fChildrenTypes.getFieldIndex(fieldName); + } + + @Override + public boolean hasField(String fieldName) { + return fChildrenTypes.hasField(fieldName); + } + + @Override + public boolean hasField(String fieldName, TypeStore store) { + return hasField(fieldName) ; + } + + @Override + public boolean hasKeywordField(String fieldName, TypeStore store) { + return store.hasKeywordParameter(this, fieldName); + } + + @Override + public Type getFieldTypes() { + return fChildrenTypes; + } + + + @Override + public String getName() { + return fName; + } + + @Override + public Type getAbstractDataType() { + return fADT; + } + + @Override + public Type getFieldType(int i) { + return fChildrenTypes.getFieldType(i); + } + + @Override + public Type getFieldType(String fieldName) throws FactTypeUseException { + return fChildrenTypes.getFieldType(fieldName); + } + + @Override + public String getFieldName(int i) { + return fChildrenTypes.getFieldName(i); + } + + @Override + public String[] getFieldNames() { + return fChildrenTypes.getFieldNames(); + } + + @Override + public boolean hasFieldNames() { + return fChildrenTypes.hasFieldNames(); + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitConstructor(this); + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfConstructor(this); + } + + @Override + public Type lub(Type type) { + return type.lubWithConstructor(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithConstructor(this); + } + + @Override + protected boolean isSubtypeOfConstructor(Type type) { + if (type.getName().equals(getName())) { + return getAbstractDataType().isSubtypeOf(type.getAbstractDataType()) + && getFieldTypes().isSubtypeOf(type.getFieldTypes()); + } + else { + return false; + } + } + + @Override + protected boolean isSubtypeOfAbstractData(Type type) { + return getAbstractDataType().isSubtypeOfAbstractData(type); + } + + @Override + protected Type lubWithConstructor(Type type) { + if(this == type) { + return this; + } + return getAbstractDataType().lubWithAbstractData(type.getAbstractDataType()); + } + + @Override + protected Type glbWithConstructor(Type type) { + if (type.isSubtypeOf(this)) { + return type; + } + else if (isSubtypeOf(type)) { + return this; + } + else { + return TF.voidType(); + } + } + + @Override + protected Type glbWithAbstractData(Type type) { + if (isSubtypeOf(type)) { + return this; + } + + return TF.voidType(); + } + + @Override + protected Type glbWithNode(Type type) { + return this; + } + + @Override + public boolean match(Type matched, Map bindings) + throws FactTypeUseException { + return super.match(matched, bindings) + && fADT.match(matched.getAbstractDataType(), bindings) + && getFieldTypes().match(matched.getFieldTypes(), bindings); + } + + @Override + public Type instantiate(Map bindings) { + if (bindings.isEmpty()) { + return this; + } + Type adt = fADT.instantiate(bindings); + Type fields = getFieldTypes().instantiate(bindings); + + TypeStore store = new TypeStore(); + store.declareAbstractDataType(fADT); + store.declareConstructor(this); + + return TypeFactory.getInstance().constructorFromTuple(store, adt, getName(), fields); + } + + @Override + public boolean isParameterized() { + return fADT.isParameterized(); + } + + @Override + public boolean isConstructor() { + return true; + } } diff --git a/src/main/java/io/usethesource/vallang/type/DateTimeType.java b/src/main/java/io/usethesource/vallang/type/DateTimeType.java index cee1fc05d..1a8135f10 100644 --- a/src/main/java/io/usethesource/vallang/type/DateTimeType.java +++ b/src/main/java/io/usethesource/vallang/type/DateTimeType.java @@ -35,161 +35,161 @@ * */ public class DateTimeType extends DefaultSubtypeOfValue { - private static final class InstanceKeeper { - public final static DateTimeType sInstance= new DateTimeType(); - } - - public static DateTimeType getInstance() { - return InstanceKeeper.sInstance; - } - - public static class Info extends TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("datetime"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, - Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().dateTimeType(); - } - } - - @Override - public TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - private static long between(Random r, ChronoField chrono) { - return between(r, chrono.range().getMinimum(), chrono.range().getMaximum()); - } - - private static long between(Random r, long a, long b) { - return r.longs(1, a, b).sum(); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxBreadth) { - boolean partialDateTime = "true".equals(System.getProperty("vallang.random.partialDateTime")); - boolean zoneOffsets = "true".equals(System.getProperty("vallang.random.zoneOffsets")); - + private static final class InstanceKeeper { + public final static DateTimeType sInstance= new DateTimeType(); + } + + public static DateTimeType getInstance() { + return InstanceKeeper.sInstance; + } + + public static class Info extends TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("datetime"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, + Function> grammar) { + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().dateTimeType(); + } + } + + @Override + public TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + private static long between(Random r, ChronoField chrono) { + return between(r, chrono.range().getMinimum(), chrono.range().getMaximum()); + } + + private static long between(Random r, long a, long b) { + return r.longs(1, a, b).sum(); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxBreadth) { + boolean partialDateTime = "true".equals(System.getProperty("vallang.random.partialDateTime")); + boolean zoneOffsets = "true".equals(System.getProperty("vallang.random.zoneOffsets")); + try { - if (partialDateTime && random.nextDouble() > 0.8) { - LocalTime result = LocalTime.ofSecondOfDay(between(random, ChronoField.SECOND_OF_DAY)); - return vf.time( - result.getHour(), - result.getMinute(), - result.getSecond(), - (int) TimeUnit.MILLISECONDS.convert(result.getNano(), TimeUnit.NANOSECONDS) - ); - } - if (partialDateTime && random.nextDouble() > 0.8) { - LocalDate result = LocalDate.ofEpochDay(between(random, - LocalDate.of(0,1, 1).toEpochDay(), - LocalDate.of(9999,1, 1).toEpochDay() - )); - return vf.date( - result.getYear(), - result.getMonthValue(), - result.getDayOfMonth() - ); - } - Instant result = Instant.ofEpochSecond(between(random, - -TimeUnit.DAYS.toSeconds(700), - Instant.now().getEpochSecond() + TimeUnit.DAYS.toSeconds(700) - ), 0 - ); - if (!zoneOffsets || random.nextDouble() > 0.5) { - return vf.datetime(result.toEpochMilli()); - } - ZoneOffset off = ZoneOffset.ofTotalSeconds((int)between(random, ChronoField.OFFSET_SECONDS)); - return vf.datetime(result.toEpochMilli(), - (int)TimeUnit.HOURS.convert(off.getTotalSeconds(), TimeUnit.SECONDS), - (int)TimeUnit.MINUTES.convert(off.getTotalSeconds(), TimeUnit.SECONDS) % 60 - ); - } catch (DateTimeException e) { - // this may happen if the generated random time does - // not exist due to timezone shifting or due to historical - // calendar standardization changes - // So, we just try again until we hit a better random date - return randomValue(random, vf, store, typeParameters, maxDepth, maxBreadth); - // The chances of continued failure before we run out of stack are low. - } - } - - @Override - public boolean equals(@Nullable Object obj) { - return obj == DateTimeType.getInstance(); - } - - @Override - public boolean isDateTime() { - return true; - } - - @Override - public int hashCode() { - return 63097; - } - - @Override - public String toString() { - return "datetime"; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitDateTime(this); - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfDateTime(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithDateTime(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithDateTime(this); - } - - @Override - protected boolean isSubtypeOfDateTime(Type type) { - return true; - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithDateTime(this); - } - - @Override - protected boolean intersectsWithDateTime(Type type) { - return true; - } - - @Override - protected Type lubWithDateTime(Type type) { - return this; - } - - @Override - protected Type glbWithDateTime(Type type) { - return this; - } + if (partialDateTime && random.nextDouble() > 0.8) { + LocalTime result = LocalTime.ofSecondOfDay(between(random, ChronoField.SECOND_OF_DAY)); + return vf.time( + result.getHour(), + result.getMinute(), + result.getSecond(), + (int) TimeUnit.MILLISECONDS.convert(result.getNano(), TimeUnit.NANOSECONDS) + ); + } + if (partialDateTime && random.nextDouble() > 0.8) { + LocalDate result = LocalDate.ofEpochDay(between(random, + LocalDate.of(0,1, 1).toEpochDay(), + LocalDate.of(9999,1, 1).toEpochDay() + )); + return vf.date( + result.getYear(), + result.getMonthValue(), + result.getDayOfMonth() + ); + } + Instant result = Instant.ofEpochSecond(between(random, + -TimeUnit.DAYS.toSeconds(700), + Instant.now().getEpochSecond() + TimeUnit.DAYS.toSeconds(700) + ), 0 + ); + if (!zoneOffsets || random.nextDouble() > 0.5) { + return vf.datetime(result.toEpochMilli()); + } + ZoneOffset off = ZoneOffset.ofTotalSeconds((int)between(random, ChronoField.OFFSET_SECONDS)); + return vf.datetime(result.toEpochMilli(), + (int)TimeUnit.HOURS.convert(off.getTotalSeconds(), TimeUnit.SECONDS), + (int)TimeUnit.MINUTES.convert(off.getTotalSeconds(), TimeUnit.SECONDS) % 60 + ); + } catch (DateTimeException e) { + // this may happen if the generated random time does + // not exist due to timezone shifting or due to historical + // calendar standardization changes + // So, we just try again until we hit a better random date + return randomValue(random, vf, store, typeParameters, maxDepth, maxBreadth); + // The chances of continued failure before we run out of stack are low. + } + } + + @Override + public boolean equals(@Nullable Object obj) { + return obj == DateTimeType.getInstance(); + } + + @Override + public boolean isDateTime() { + return true; + } + + @Override + public int hashCode() { + return 63097; + } + + @Override + public String toString() { + return "datetime"; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitDateTime(this); + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfDateTime(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithDateTime(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithDateTime(this); + } + + @Override + protected boolean isSubtypeOfDateTime(Type type) { + return true; + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithDateTime(this); + } + + @Override + protected boolean intersectsWithDateTime(Type type) { + return true; + } + + @Override + protected Type lubWithDateTime(Type type) { + return this; + } + + @Override + protected Type glbWithDateTime(Type type) { + return this; + } } diff --git a/src/main/java/io/usethesource/vallang/type/DefaultSubtypeOfValue.java b/src/main/java/io/usethesource/vallang/type/DefaultSubtypeOfValue.java index 2db0d5370..bb7812376 100644 --- a/src/main/java/io/usethesource/vallang/type/DefaultSubtypeOfValue.java +++ b/src/main/java/io/usethesource/vallang/type/DefaultSubtypeOfValue.java @@ -18,10 +18,10 @@ public boolean isTop() { return false; } - + @Override public abstract boolean intersects(Type other); - + protected boolean intersectsWithValue(Type type) { // everything intersects with value return true; @@ -100,87 +100,87 @@ protected boolean intersectsWithBool(Type type) { protected boolean intersectsWithDateTime(Type type) { return false; } - - @Override - public abstract Type glb(Type type); - @Override - protected Type glbWithValue(Type type) { - return this; // such that sub-classes do not have to override - } + @Override + public abstract Type glb(Type type); + + @Override + protected Type glbWithValue(Type type) { + return this; // such that sub-classes do not have to override + } - protected Type glbWithReal(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithReal(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithInteger(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithInteger(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithRational(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithRational(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithList(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithList(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithMap(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithMap(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithNumber(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithNumber(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithRelation(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithRelation(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithSet(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithSet(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithSourceLocation(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithSourceLocation(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithString(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithString(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithNode(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithNode(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithConstructor(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithConstructor(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithAbstractData(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithAbstractData(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithTuple(Type type) { - return VoidType.getInstance(); + protected Type glbWithTuple(Type type) { + return VoidType.getInstance(); } - + protected Type glbWithFunction(Type type) { - return VoidType.getInstance(); - } + return VoidType.getInstance(); + } - protected Type glbWithVoid(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithVoid(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithBool(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithBool(Type type) { + return VoidType.getInstance(); + } - protected Type glbWithDateTime(Type type) { - return VoidType.getInstance(); - } + protected Type glbWithDateTime(Type type) { + return VoidType.getInstance(); + } } diff --git a/src/main/java/io/usethesource/vallang/type/DefaultTypeVisitor.java b/src/main/java/io/usethesource/vallang/type/DefaultTypeVisitor.java index f02a5f456..e21064315 100644 --- a/src/main/java/io/usethesource/vallang/type/DefaultTypeVisitor.java +++ b/src/main/java/io/usethesource/vallang/type/DefaultTypeVisitor.java @@ -1,114 +1,114 @@ package io.usethesource.vallang.type; public abstract class DefaultTypeVisitor implements ITypeVisitor { - protected final T def; - - public DefaultTypeVisitor(T def) { - this.def = def; - } - - @Override - public T visitReal(Type type) throws E { - return def; - } - - @Override - public T visitInteger(Type type) throws E { - return def; - } - - @Override - public T visitRational(Type type) throws E { - return def; - } - - @Override - public T visitList(Type type) throws E { - return def; - } - - @Override - public T visitMap(Type type) throws E { - return def; - } - - @Override - public T visitNumber(Type type) throws E { - return def; - } - - @Override - public T visitAlias(Type type) throws E { - return def; - } - - @Override - public T visitSet(Type type) throws E { - return def; - } - - @Override - public T visitSourceLocation(Type type) throws E { - return def; - } - - @Override - public T visitString(Type type) throws E { - return def; - } - - @Override - public T visitNode(Type type) throws E { - return def; - } - - @Override - public T visitConstructor(Type type) throws E { - return def; - } - - @Override - public T visitAbstractData(Type type) throws E { - return def; - } - - @Override - public T visitTuple(Type type) throws E { - return def; - } - - @Override - public T visitValue(Type type) throws E { - return def; - } - - @Override - public T visitVoid(Type type) throws E { - return def; - } - - @Override - public T visitBool(Type type) throws E { - return def; - } - - @Override - public T visitParameter(Type type) throws E { - return def; - } - - @Override - public T visitExternal(Type type) throws E { - return def; - } - - @Override - public T visitDateTime(Type type) throws E { - return def; - } - - @Override - public T visitFunction(Type type) throws E { - return def; - } + protected final T def; + + public DefaultTypeVisitor(T def) { + this.def = def; + } + + @Override + public T visitReal(Type type) throws E { + return def; + } + + @Override + public T visitInteger(Type type) throws E { + return def; + } + + @Override + public T visitRational(Type type) throws E { + return def; + } + + @Override + public T visitList(Type type) throws E { + return def; + } + + @Override + public T visitMap(Type type) throws E { + return def; + } + + @Override + public T visitNumber(Type type) throws E { + return def; + } + + @Override + public T visitAlias(Type type) throws E { + return def; + } + + @Override + public T visitSet(Type type) throws E { + return def; + } + + @Override + public T visitSourceLocation(Type type) throws E { + return def; + } + + @Override + public T visitString(Type type) throws E { + return def; + } + + @Override + public T visitNode(Type type) throws E { + return def; + } + + @Override + public T visitConstructor(Type type) throws E { + return def; + } + + @Override + public T visitAbstractData(Type type) throws E { + return def; + } + + @Override + public T visitTuple(Type type) throws E { + return def; + } + + @Override + public T visitValue(Type type) throws E { + return def; + } + + @Override + public T visitVoid(Type type) throws E { + return def; + } + + @Override + public T visitBool(Type type) throws E { + return def; + } + + @Override + public T visitParameter(Type type) throws E { + return def; + } + + @Override + public T visitExternal(Type type) throws E { + return def; + } + + @Override + public T visitDateTime(Type type) throws E { + return def; + } + + @Override + public T visitFunction(Type type) throws E { + return def; + } } diff --git a/src/main/java/io/usethesource/vallang/type/ExternalType.java b/src/main/java/io/usethesource/vallang/type/ExternalType.java index 7333289b9..7fa78e8c6 100644 --- a/src/main/java/io/usethesource/vallang/type/ExternalType.java +++ b/src/main/java/io/usethesource/vallang/type/ExternalType.java @@ -22,64 +22,64 @@ * ExternalType facilitates a limited form of extensibility to the PDB's type system. * It can be used for example to add 'function types' to the PDB. Any such extension * to PDB must be a subclass of ExternalType and override isSubTypeOf() and lub(). - *
+ *
* Note that NORMAL USE OF THE VALUES LIBRARY DOES NOT REQUIRE EXTENDING THIS CLASS */ public abstract class ExternalType extends DefaultSubtypeOfValue { - - /** - * Provide the type of the values produced by {@link IExternalValue}.encodeAsConstructor() - */ - public abstract Type asAbstractDataType(); - - @Override - public Type getTypeParameters() { - return TypeFactory.getInstance().voidType(); - } - - @Override - public boolean isExternalType() { - return true; - } - - @Override - public final T accept(ITypeVisitor visitor) throws E { - return visitor.visitExternal(this); - } - - @Override - public final Type lub(Type other) { - return other.lubWithExternal(this); - } - - @Override - public final Type glb(Type type) { - return type.glbWithExternal(this); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithExternal(this); - } - - @Override - protected /*final*/ boolean isSupertypeOf(Type type) { - return type.isSubtypeOfExternal(this); - } - - @Override - abstract protected Type lubWithExternal(Type type); - - @Override - abstract protected boolean intersectsWithExternal(Type type); - - @Override + + /** + * Provide the type of the values produced by {@link IExternalValue}.encodeAsConstructor() + */ + public abstract Type asAbstractDataType(); + + @Override + public Type getTypeParameters() { + return TypeFactory.getInstance().voidType(); + } + + @Override + public boolean isExternalType() { + return true; + } + + @Override + public final T accept(ITypeVisitor visitor) throws E { + return visitor.visitExternal(this); + } + + @Override + public final Type lub(Type other) { + return other.lubWithExternal(this); + } + + @Override + public final Type glb(Type type) { + return type.glbWithExternal(this); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithExternal(this); + } + + @Override + protected /*final*/ boolean isSupertypeOf(Type type) { + return type.isSubtypeOfExternal(this); + } + + @Override + abstract protected Type lubWithExternal(Type type); + + @Override + abstract protected boolean intersectsWithExternal(Type type); + + @Override abstract protected Type glbWithExternal(Type type); - - - @Override - abstract protected boolean isSubtypeOfExternal(Type type); - - @Override - abstract public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxBreadth); + + + @Override + abstract protected boolean isSubtypeOfExternal(Type type); + + @Override + abstract public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxBreadth); } diff --git a/src/main/java/io/usethesource/vallang/type/FunctionType.java b/src/main/java/io/usethesource/vallang/type/FunctionType.java index 6655fb276..277b82b7f 100644 --- a/src/main/java/io/usethesource/vallang/type/FunctionType.java +++ b/src/main/java/io/usethesource/vallang/type/FunctionType.java @@ -48,29 +48,29 @@ * which follow the typing rules of Rascal functions (co and contra-variant in their argument types). */ public class FunctionType extends DefaultSubtypeOfValue { - private final Type returnType; - private final TupleType argumentTypes; - private final @Nullable TupleType keywordParameters; - - /*package*/ FunctionType(Type returnType, TupleType argumentTypes, TupleType keywordParameters) { - this.argumentTypes = argumentTypes; - this.returnType = returnType; - this.keywordParameters = keywordParameters == null ? null : (keywordParameters.getArity() == 0 ? null : keywordParameters); - } - - public static class Reifier extends TypeReifier { - public Reifier(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - throw new UnsupportedOperationException(); - } - + private final Type returnType; + private final TupleType argumentTypes; + private final @Nullable TupleType keywordParameters; + + /*package*/ FunctionType(Type returnType, TupleType argumentTypes, TupleType keywordParameters) { + this.argumentTypes = argumentTypes; + this.returnType = returnType; + this.keywordParameters = keywordParameters == null ? null : (keywordParameters.getArity() == 0 ? null : keywordParameters); + } + + public static class Reifier extends TypeReifier { + public Reifier(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + throw new UnsupportedOperationException(); + } + @Override public Set getSymbolConstructorTypes() { - return Arrays.stream(new Type[] { + return Arrays.stream(new Type[] { normalFunctionSymbol() }).collect(Collectors.toSet()); } @@ -78,7 +78,7 @@ public Set getSymbolConstructorTypes() { private Type normalFunctionSymbol() { return symbols().typeSymbolConstructor("func", symbols().symbolADT(), "ret", TF.listType(symbols().symbolADT()), "parameters", TF.listType(symbols().symbolADT()), "kwTypes"); } - + @Override public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { Type returnType = symbols().fromSymbol((IConstructor) symbol.get("ret"), store, grammar); @@ -87,7 +87,7 @@ public Type fromSymbol(IConstructor symbol, TypeStore store, Function next, TypeStore store, RandomTypesConfig rnd) { - // TODO: as we do not have IFunction yet in vallang, we should not generate random - // function types either. It will lead to exceptions otherwise. - // return TF.functionType(next.get(), (TupleType) TF.tupleType(next.get()), (TupleType) TF.tupleEmpty()); - return TF.integerType(); + // TODO: as we do not have IFunction yet in vallang, we should not generate random + // function types either. It will lead to exceptions otherwise. + // return TF.functionType(next.get(), (TupleType) TF.tupleType(next.get()), (TupleType) TF.tupleEmpty()); + return TF.integerType(); } - + @Override public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { @@ -110,11 +110,11 @@ public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWrit arg.asProductions(vf, store, grammar, done); } } - + @Override public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { IListWriter w = vf.listWriter(); - + int i = 0; Type args = ((FunctionType) type).getFieldTypes(); for (Type arg : args) { @@ -125,9 +125,9 @@ public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISet i++; w.append(sym); } - + IListWriter kw = vf.listWriter(); - + i = 0; Type kwArgs = ((FunctionType) type).getKeywordParameterTypes(); if (kwArgs != null && !kwArgs.isBottom()) { @@ -140,355 +140,355 @@ public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISet kw.append(sym); } } - - + + return vf.constructor(normalFunctionSymbol(), ((FunctionType) type).getReturnType().asSymbol(vf, store, grammar, done), w.done(), kw.done()); } - } - - @Override - public TypeReifier getTypeReifier(TypeValues symbols) { - return new Reifier(symbols); - } - - @Override - public boolean isFunction() { - return true; - } - - @Override - public Type getFieldType(int i) { - return argumentTypes.getFieldType(i); - } - - @Override - public Type getFieldType(String fieldName) throws FactTypeUseException { - return argumentTypes.getFieldType(fieldName); - } - - @Override - public int getFieldIndex(String fieldName) { - return argumentTypes.getFieldIndex(fieldName); - } - - @Override - public String getFieldName(int i) { - return argumentTypes.getFieldName(i); - } - - @Override - public String[] getFieldNames() { - return argumentTypes.getFieldNames(); - } - - @Override - public Type getFieldTypes() { - return argumentTypes; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitFunction(this); - } - + } + @Override - public Type getReturnType() { - return returnType; - } - - @Override - public int getArity() { - return argumentTypes.getArity(); - } - + public TypeReifier getTypeReifier(TypeValues symbols) { + return new Reifier(symbols); + } + @Override - public Type getKeywordParameterTypes() { - return keywordParameters == null ? TypeFactory.getInstance().tupleEmpty() : keywordParameters; - } - + public boolean isFunction() { + return true; + } + @Override - public @Nullable Type getKeywordParameterType(String label) { - return keywordParameters != null ? keywordParameters.getFieldType(label) : null; - } - + public Type getFieldType(int i) { + return argumentTypes.getFieldType(i); + } + + @Override + public Type getFieldType(String fieldName) throws FactTypeUseException { + return argumentTypes.getFieldType(fieldName); + } + + @Override + public int getFieldIndex(String fieldName) { + return argumentTypes.getFieldIndex(fieldName); + } + + @Override + public String getFieldName(int i) { + return argumentTypes.getFieldName(i); + } + @Override - public boolean hasKeywordParameter(String label) { - return keywordParameters != null ? keywordParameters.hasField(label) : false; - } - + public String[] getFieldNames() { + return argumentTypes.getFieldNames(); + } + @Override - public boolean hasKeywordParameters() { - return keywordParameters != null; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfFunction(this); - } - - @Override - public Type lub(Type type) { - return type.lubWithFunction(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithFunction(this); - } - - @Override - public boolean intersects(Type type) { - return type.intersectsWithFunction(this); - } - - @Override - protected boolean intersectsWithFunction(Type other) { - FunctionType otherType = (FunctionType) other; - - if (other.getArity() != getArity()) { - return false; - } - - if (otherType.getReturnType().isBottom() && getReturnType().isBottom()) { - return otherType.getFieldTypes().intersects(getFieldTypes()); - } - - // TODO should the return type intersect or just be comparable? - return otherType.getReturnType().intersects(getReturnType()) - && otherType.getFieldTypes().intersects(getFieldTypes()); - } - - @Override - public boolean isSubtypeOfFunction(Type other) { - // Vallang functions are co-variant in the return type position and - // *variant* (co- _and_ contra-variant) in their argument positions, such that a sub-function - // can safely simulate a super function and in particular overloaded functions may have contributions which - // do not match the currently requested function type. - - // For example, an overloadeded function `X f(int) + X f(str)` is substitutable at high-order parameter positions of type `X (int)` - // even though its function type is `X (value)`. Rascal's type system does not check completeness of function definitions, - // only _possible_ applicability in this manner. Every function may throw `CallFailed` at run-time - // if non of their arguments match for none of their alternatives. - - FunctionType otherType = (FunctionType) other; - - if (getReturnType().isSubtypeOf(otherType.getReturnType())) { - - Type argTypes = getFieldTypes(); - Type otherArgTypes = otherType.getFieldTypes(); - - if (argTypes.getArity() != otherArgTypes.getArity()) { - return false; - } - - int N = argTypes.getArity(); - - for (int i = 0; i < N; i++) { - Type field = argTypes.getFieldType(i); - Type otherField = otherArgTypes.getFieldType(i); - - if (field.isBottom() || otherField.isBottom()) { - continue; - } - - if (!field.intersects(otherField)) { - return false; - } - } - - return true; - - } - - return false; - } - - @Override - protected Type lubWithFunction(Type type) { - if (this == type) { - return this; - } - - FunctionType f = (FunctionType) type; - - Type returnType = getReturnType().lub(f.getReturnType()); - Type argumentTypes = getFieldTypes().lub(f.getFieldTypes()); - - if (argumentTypes.isTuple() && argumentTypes.getArity() == getArity()) { - return TypeFactory.getInstance().functionType(returnType, - argumentTypes, - getKeywordParameterTypes() == f.getKeywordParameterTypes() - ? getKeywordParameterTypes() - : TF.tupleEmpty()); - } - - return TF.valueType(); - } - - @Override - protected Type glbWithFunction(Type type) { - if (this == type) { - return this; - } - - FunctionType f = (FunctionType) type; - - Type returnType = getReturnType().glb(f.getReturnType()); - Type argumentTypes = getFieldTypes().lub(f.getFieldTypes()); - - if (argumentTypes.isTuple()) { - // TODO: figure out what glb means for keyword parameters - return TF.functionType(returnType, argumentTypes, TF.tupleEmpty()); - } - - return TF.voidType(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append(returnType); - sb.append(' '); - sb.append('('); - int i = 0; - for (Type arg : argumentTypes) { - if (i > 0) { - sb.append(", "); - } - sb.append(arg.toString()); - if (argumentTypes.hasFieldNames()) { - sb.append(" " + argumentTypes.getFieldName(i)); - } - - i++; - } - - if (keywordParameters != null) { - i = 0; - for (Type arg : keywordParameters) { - sb.append(", "); - sb.append(arg.toString()); - if (keywordParameters.hasFieldNames()) { - sb.append(" " + keywordParameters.getFieldName(i) + " = ..."); - } - - i++; - } - } - sb.append(')'); - return sb.toString(); - } - - @Override - public int hashCode() { - return 19 + 19 * returnType.hashCode() + 23 * argumentTypes.hashCode() - + (keywordParameters != null ? 29 * keywordParameters.hashCode() : 0) - ; - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == null) { - return false; - } - - if (o == this) { - return true; - } - - if (o instanceof FunctionType) { - FunctionType other = (FunctionType) o; - - if (returnType != other.returnType) { - return false; - } - - if (argumentTypes != other.argumentTypes) { - return false; - } - - if (keywordParameters != other.keywordParameters) { - return false; - } - - return true; - } - - return false; - } - - @Override - public Type instantiate(Map bindings) { - return TF.functionType(returnType.instantiate(bindings), instantiateTuple(argumentTypes, bindings), keywordParameters != null ? instantiateTuple(keywordParameters, bindings) : TypeFactory.getInstance().tupleEmpty()); - } - - @Override - public boolean isOpen() { - return returnType.isOpen() || argumentTypes.isOpen(); - } - - @Override - public boolean match(Type matched, Map bindings) - throws FactTypeUseException { - if (matched.isBottom()) { - return argumentTypes.match(matched, bindings) && returnType.match(matched, bindings); - } else { - // Fix for cases where we have aliases to function types, aliases to aliases to function types, etc - while (matched.isAliased()) { - matched = matched.getAliased(); - } - - if (matched.isFunction()) { - FunctionType matchedFunction = (FunctionType) matched; - - if (argumentTypes.getArity() != matchedFunction.getArity()) { - return false; - } - - for (int i = argumentTypes.getArity() - 1; i >= 0; i--) { - Type fieldType = argumentTypes.getFieldType(i); + public Type getFieldTypes() { + return argumentTypes; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitFunction(this); + } + + @Override + public Type getReturnType() { + return returnType; + } + + @Override + public int getArity() { + return argumentTypes.getArity(); + } + + @Override + public Type getKeywordParameterTypes() { + return keywordParameters == null ? TypeFactory.getInstance().tupleEmpty() : keywordParameters; + } + + @Override + public @Nullable Type getKeywordParameterType(String label) { + return keywordParameters != null ? keywordParameters.getFieldType(label) : null; + } + + @Override + public boolean hasKeywordParameter(String label) { + return keywordParameters != null ? keywordParameters.hasField(label) : false; + } + + @Override + public boolean hasKeywordParameters() { + return keywordParameters != null; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfFunction(this); + } + + @Override + public Type lub(Type type) { + return type.lubWithFunction(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithFunction(this); + } + + @Override + public boolean intersects(Type type) { + return type.intersectsWithFunction(this); + } + + @Override + protected boolean intersectsWithFunction(Type other) { + FunctionType otherType = (FunctionType) other; + + if (other.getArity() != getArity()) { + return false; + } + + if (otherType.getReturnType().isBottom() && getReturnType().isBottom()) { + return otherType.getFieldTypes().intersects(getFieldTypes()); + } + + // TODO should the return type intersect or just be comparable? + return otherType.getReturnType().intersects(getReturnType()) + && otherType.getFieldTypes().intersects(getFieldTypes()); + } + + @Override + public boolean isSubtypeOfFunction(Type other) { + // Vallang functions are co-variant in the return type position and + // *variant* (co- _and_ contra-variant) in their argument positions, such that a sub-function + // can safely simulate a super function and in particular overloaded functions may have contributions which + // do not match the currently requested function type. + + // For example, an overloadeded function `X f(int) + X f(str)` is substitutable at high-order parameter positions of type `X (int)` + // even though its function type is `X (value)`. Rascal's type system does not check completeness of function definitions, + // only _possible_ applicability in this manner. Every function may throw `CallFailed` at run-time + // if non of their arguments match for none of their alternatives. + + FunctionType otherType = (FunctionType) other; + + if (getReturnType().isSubtypeOf(otherType.getReturnType())) { + + Type argTypes = getFieldTypes(); + Type otherArgTypes = otherType.getFieldTypes(); + + if (argTypes.getArity() != otherArgTypes.getArity()) { + return false; + } + + int N = argTypes.getArity(); + + for (int i = 0; i < N; i++) { + Type field = argTypes.getFieldType(i); + Type otherField = otherArgTypes.getFieldType(i); + + if (field.isBottom() || otherField.isBottom()) { + continue; + } + + if (!field.intersects(otherField)) { + return false; + } + } + + return true; + + } + + return false; + } + + @Override + protected Type lubWithFunction(Type type) { + if (this == type) { + return this; + } + + FunctionType f = (FunctionType) type; + + Type returnType = getReturnType().lub(f.getReturnType()); + Type argumentTypes = getFieldTypes().lub(f.getFieldTypes()); + + if (argumentTypes.isTuple() && argumentTypes.getArity() == getArity()) { + return TypeFactory.getInstance().functionType(returnType, + argumentTypes, + getKeywordParameterTypes() == f.getKeywordParameterTypes() + ? getKeywordParameterTypes() + : TF.tupleEmpty()); + } + + return TF.valueType(); + } + + @Override + protected Type glbWithFunction(Type type) { + if (this == type) { + return this; + } + + FunctionType f = (FunctionType) type; + + Type returnType = getReturnType().glb(f.getReturnType()); + Type argumentTypes = getFieldTypes().lub(f.getFieldTypes()); + + if (argumentTypes.isTuple()) { + // TODO: figure out what glb means for keyword parameters + return TF.functionType(returnType, argumentTypes, TF.tupleEmpty()); + } + + return TF.voidType(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(returnType); + sb.append(' '); + sb.append('('); + int i = 0; + for (Type arg : argumentTypes) { + if (i > 0) { + sb.append(", "); + } + sb.append(arg.toString()); + if (argumentTypes.hasFieldNames()) { + sb.append(" " + argumentTypes.getFieldName(i)); + } + + i++; + } + + if (keywordParameters != null) { + i = 0; + for (Type arg : keywordParameters) { + sb.append(", "); + sb.append(arg.toString()); + if (keywordParameters.hasFieldNames()) { + sb.append(" " + keywordParameters.getFieldName(i) + " = ..."); + } + + i++; + } + } + sb.append(')'); + return sb.toString(); + } + + @Override + public int hashCode() { + return 19 + 19 * returnType.hashCode() + 23 * argumentTypes.hashCode() + + (keywordParameters != null ? 29 * keywordParameters.hashCode() : 0) + ; + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null) { + return false; + } + + if (o == this) { + return true; + } + + if (o instanceof FunctionType) { + FunctionType other = (FunctionType) o; + + if (returnType != other.returnType) { + return false; + } + + if (argumentTypes != other.argumentTypes) { + return false; + } + + if (keywordParameters != other.keywordParameters) { + return false; + } + + return true; + } + + return false; + } + + @Override + public Type instantiate(Map bindings) { + return TF.functionType(returnType.instantiate(bindings), instantiateTuple(argumentTypes, bindings), keywordParameters != null ? instantiateTuple(keywordParameters, bindings) : TypeFactory.getInstance().tupleEmpty()); + } + + @Override + public boolean isOpen() { + return returnType.isOpen() || argumentTypes.isOpen(); + } + + @Override + public boolean match(Type matched, Map bindings) + throws FactTypeUseException { + if (matched.isBottom()) { + return argumentTypes.match(matched, bindings) && returnType.match(matched, bindings); + } else { + // Fix for cases where we have aliases to function types, aliases to aliases to function types, etc + while (matched.isAliased()) { + matched = matched.getAliased(); + } + + if (matched.isFunction()) { + FunctionType matchedFunction = (FunctionType) matched; + + if (argumentTypes.getArity() != matchedFunction.getArity()) { + return false; + } + + for (int i = argumentTypes.getArity() - 1; i >= 0; i--) { + Type fieldType = argumentTypes.getFieldType(i); Type otherFieldType = matchedFunction.getFieldTypes().getFieldType(i); Map originalBindings = new HashMap<>(); originalBindings.putAll(bindings); - + if (!fieldType.match(otherFieldType, bindings)) { bindings = originalBindings; if (!otherFieldType.match(matchedFunction, bindings)) { // neither co nor contra-variant return false; } - } - } - + } + } + return returnType.match(matchedFunction.getReturnType(), bindings); - } - else { - return false; - } - } - } - - @Override - public Type compose(Type right) { - if (right.isBottom()) { - return right; - } - - if (right.isFunction()) { - if (TF.tupleType(right.getReturnType()).isSubtypeOf(this.argumentTypes)) { - return TF.functionType(this.returnType, right.getFieldTypes(), right.getKeywordParameterTypes()); - } - } else { - throw new IllegalOperationException("compose", this, right); - } - - return TF.voidType(); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxBreadth) { - throw new RuntimeException("randomValue on FunctionType not yet implemented"); - } + } + else { + return false; + } + } + } + + @Override + public Type compose(Type right) { + if (right.isBottom()) { + return right; + } + + if (right.isFunction()) { + if (TF.tupleType(right.getReturnType()).isSubtypeOf(this.argumentTypes)) { + return TF.functionType(this.returnType, right.getFieldTypes(), right.getKeywordParameterTypes()); + } + } else { + throw new IllegalOperationException("compose", this, right); + } + + return TF.voidType(); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxBreadth) { + throw new RuntimeException("randomValue on FunctionType not yet implemented"); + } } diff --git a/src/main/java/io/usethesource/vallang/type/ITypeVisitor.java b/src/main/java/io/usethesource/vallang/type/ITypeVisitor.java index af9cad7d7..96ad01948 100644 --- a/src/main/java/io/usethesource/vallang/type/ITypeVisitor.java +++ b/src/main/java/io/usethesource/vallang/type/ITypeVisitor.java @@ -12,30 +12,30 @@ package io.usethesource.vallang.type; /** - * Visitor interface for all kinds of Types + * Visitor interface for all kinds of Types * * @param the result type of the visit methods */ public interface ITypeVisitor { - T visitReal(Type type) throws E; - T visitInteger(Type type) throws E; - T visitRational(Type type) throws E; - T visitList(Type type) throws E; - T visitMap(Type type) throws E; - T visitNumber(Type type) throws E; - T visitAlias(Type type) throws E; - T visitSet(Type type) throws E; - T visitSourceLocation(Type type) throws E; - T visitString(Type type) throws E; - T visitNode(Type type) throws E; - T visitConstructor(Type type) throws E; - T visitAbstractData(Type type) throws E; - T visitTuple(Type type) throws E; - T visitValue(Type type) throws E; - T visitVoid(Type type) throws E; - T visitBool(Type type) throws E; - T visitParameter(Type type) throws E; - T visitExternal(Type type) throws E; - T visitDateTime(Type type) throws E; - T visitFunction(Type type) throws E; + T visitReal(Type type) throws E; + T visitInteger(Type type) throws E; + T visitRational(Type type) throws E; + T visitList(Type type) throws E; + T visitMap(Type type) throws E; + T visitNumber(Type type) throws E; + T visitAlias(Type type) throws E; + T visitSet(Type type) throws E; + T visitSourceLocation(Type type) throws E; + T visitString(Type type) throws E; + T visitNode(Type type) throws E; + T visitConstructor(Type type) throws E; + T visitAbstractData(Type type) throws E; + T visitTuple(Type type) throws E; + T visitValue(Type type) throws E; + T visitVoid(Type type) throws E; + T visitBool(Type type) throws E; + T visitParameter(Type type) throws E; + T visitExternal(Type type) throws E; + T visitDateTime(Type type) throws E; + T visitFunction(Type type) throws E; } diff --git a/src/main/java/io/usethesource/vallang/type/IntegerType.java b/src/main/java/io/usethesource/vallang/type/IntegerType.java index d1f5782d3..41382cb52 100644 --- a/src/main/java/io/usethesource/vallang/type/IntegerType.java +++ b/src/main/java/io/usethesource/vallang/type/IntegerType.java @@ -29,46 +29,46 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class IntegerType extends NumberType { - private static final class InstanceKeeper { - public final static IntegerType sInstance= new IntegerType(); + private static final class InstanceKeeper { + public final static IntegerType sInstance= new IntegerType(); } - + public static IntegerType getInstance() { return InstanceKeeper.sInstance; } - + public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { + public Info(TypeValues symbols) { super(symbols); } @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("int"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, - Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().integerType(); - } - } - + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("int"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, + Function> grammar) { + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().integerType(); + } + } + @Override public boolean isInteger() { return true; } @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + /** * Should never need to be called; there should be only one instance of IntegerType */ @@ -76,7 +76,7 @@ public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { public boolean equals(@Nullable Object obj) { return obj == IntegerType.getInstance(); } - + @Override public int hashCode() { return 74843; @@ -86,87 +86,87 @@ public int hashCode() { public String toString() { return "int"; } - + @Override public T accept(ITypeVisitor visitor) throws E { - return visitor.visitInteger(this); + return visitor.visitInteger(this); } - + @Override protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfInteger(this); + return type.isSubtypeOfInteger(this); } - + @Override public Type lub(Type other) { - return other.lubWithInteger(this); + return other.lubWithInteger(this); } - + @Override public Type glb(Type type) { - return type.glbWithInteger(this); + return type.glbWithInteger(this); } - + @Override protected boolean isSubtypeOfInteger(Type type) { - return true; + return true; } - + @Override protected Type lubWithInteger(Type type) { - return this; + return this; } @Override public boolean intersects(Type other) { return other.intersectsWithInteger(this); } - + @Override protected boolean intersectsWithInteger(Type type) { return true; } - + @Override protected boolean intersectsWithRational(Type type) { return false; } - + @Override protected boolean intersectsWithReal(Type type) { return false; } - + @Override protected Type glbWithReal(Type type) { - return TF.voidType(); + return TF.voidType(); } - + @Override protected Type glbWithRational(Type type) { - return TF.voidType(); + return TF.voidType(); } - + @Override protected Type glbWithNumber(Type type) { - return this; + return this; } - + @Override public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxBreadth) { if (oneEvery(random, 5) && maxDepth > 1) { return vf.integer(random.nextInt()); } - + if (oneEvery(random, 5)) { return vf.integer(random.nextInt(10)); } - + if (oneEvery(random, 5)) { return vf.integer(-random.nextInt(10)); } - + if (oneEvery(random, 20) && maxDepth > 1) { // sometimes, a very huge number IInteger result = vf.integer(random.nextLong()); @@ -176,7 +176,7 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< while (random.nextFloat() > 0.4); return result.add(vf.integer(random.nextInt())); } - + return vf.integer(0); } } diff --git a/src/main/java/io/usethesource/vallang/type/ListType.java b/src/main/java/io/usethesource/vallang/type/ListType.java index 97938f0ce..3dcba491a 100644 --- a/src/main/java/io/usethesource/vallang/type/ListType.java +++ b/src/main/java/io/usethesource/vallang/type/ListType.java @@ -35,290 +35,290 @@ import io.usethesource.vallang.type.TypeFactory.TypeValues; /*package*/ class ListType extends DefaultSubtypeOfValue { - protected final Type fEltType; - - /*package*/ ListType(Type eltType) { - fEltType = eltType; - } - - public static class Info extends TypeReifier { - - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - if (symbol.getConstructorType() == getListType()) { - return tf().listType(symbols().fromSymbol((IConstructor) symbol.get("symbol"), store, grammar)); - } - else { - // TODO remove; this is for bootstrapping with an old version - return tf().listType(symbols().fromSymbols((IList) symbol.get("symbols"), store, grammar)); - } - } - - @Override - public Type getSymbolConstructorType() { - throw new UnsupportedOperationException(); - } - - @Override - public Set getSymbolConstructorTypes() { - return Arrays.stream(new Type[] { - getListType(), - getRelType() // TODO: can be removed after bootstrap - }).collect(Collectors.toSet()); - } - - private Type getRelType() { - return symbols().typeSymbolConstructor("lrel", tf().listType(symbols().symbolADT()), "symbols"); - } - - private Type getListType() { - return symbols().typeSymbolConstructor("list", symbols().symbolADT(), "symbol"); - } - - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - return vf.constructor(getListType(), type.getElementType().asSymbol(vf, store, grammar, done)); - } - - @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - type.getElementType().asProductions(vf, store, grammar, done); - } + protected final Type fEltType; + + /*package*/ ListType(Type eltType) { + fEltType = eltType; + } + + public static class Info extends TypeReifier { + + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + if (symbol.getConstructorType() == getListType()) { + return tf().listType(symbols().fromSymbol((IConstructor) symbol.get("symbol"), store, grammar)); + } + else { + // TODO remove; this is for bootstrapping with an old version + return tf().listType(symbols().fromSymbols((IList) symbol.get("symbols"), store, grammar)); + } + } + + @Override + public Type getSymbolConstructorType() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getSymbolConstructorTypes() { + return Arrays.stream(new Type[] { + getListType(), + getRelType() // TODO: can be removed after bootstrap + }).collect(Collectors.toSet()); + } + + private Type getRelType() { + return symbols().typeSymbolConstructor("lrel", tf().listType(symbols().symbolADT()), "symbols"); + } + + private Type getListType() { + return symbols().typeSymbolConstructor("list", symbols().symbolADT(), "symbol"); + } + + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + return vf.constructor(getListType(), type.getElementType().asSymbol(vf, store, grammar, done)); + } + + @Override + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + type.getElementType().asProductions(vf, store, grammar, done); + } @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { return tf().listType(next.get()); } - + @Override public boolean isRecursive() { return false; } - } - - @Override - public TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public Type getElementType() { - return fEltType; - } - - @Override - public boolean hasFieldNames() { - return fEltType.hasFieldNames(); - } - - @Override - public boolean isList() { - return true; - } - - @Override - public boolean isListRelation() { - return fEltType.isTuple() || fEltType.isBottom(); - } - - @Override - public boolean hasField(String fieldName) { - return fEltType.hasField(fieldName); - } - - @Override - public int getFieldIndex(String fieldName) { - return fEltType.getFieldIndex(fieldName); - } - - @Override - public Type getFieldType(int i) { - return fEltType.getFieldType(i); - } - - @Override - public String getFieldName(int i) { - return fEltType.getFieldName(i); - } - - @Override - public String[] getFieldNames() { - return fEltType.getFieldNames(); - } - - @Override - public int getArity() { - return fEltType.getArity(); - } - - @Override - public Type getFieldType(String fieldName) throws FactTypeUseException { - return fEltType.getFieldType(fieldName); - } - - @Override - public Type getFieldTypes() { - return fEltType.getFieldTypes(); - } - - @Override - public Type carrier() { - return fEltType.carrier(); - } - - @Override - public Type closure() { - return TF.listType(fEltType.closure()); - } - - @Override - public Type compose(Type other) { - return TF.listType(fEltType.compose(other.getElementType())); - } - - @Override - public Type select(int... fields) { - return TF.listType(fEltType.select(fields)); - } - - @Override - public Type select(String... names) { - return TF.listType(fEltType.select(names)); - } - - @Override - public String toString() { - if (fEltType.isFixedWidth() && !fEltType.equivalent(VoidType.getInstance())) { - StringBuilder sb = new StringBuilder(); - sb.append("lrel["); - int idx = 0; - Iterator iter = fEltType.iterator(); - while(iter.hasNext()) { - Type elemType = iter.next(); - if (idx++ > 0) - sb.append(","); - sb.append(elemType.toString()); - if (hasFieldNames()) { - sb.append(" " + fEltType.getFieldName(idx - 1)); - } - } - sb.append("]"); - return sb.toString(); - } - else { - return "list[" + fEltType + "]"; - } - } - - @Override - public boolean equals(@Nullable Object o) { - if(o == this) { - return true; - } - else if (o instanceof ListType) { - ListType other = (ListType) o; - return fEltType == other.fEltType; - } - - return false; - } - - @Override - public int hashCode() { - return 75703 + 104543 * fEltType.hashCode(); - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitList(this); - } - - @Override - public boolean isOpen() { - return fEltType.isOpen(); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithList(this); - } - - @Override - protected boolean intersectsWithList(Type type) { - // there is always the empty list! - return true; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfList(this); - } - - @Override - protected boolean isSubtypeOfList(Type type) { - return fEltType.isSubtypeOf(type.getElementType()); - } - - @Override - public Type lub(Type other) { - return other.lubWithList(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithList(this); - } - - @Override - public Type lubWithList(Type type) { - return this == type ? this : TF.listType(fEltType.lub(type.getElementType())); - } - - @Override - protected Type glbWithList(Type type) { - return this == type ? this : TF.listType(fEltType.glb(type.getElementType())); - } - - @Override - public boolean match(Type matched, Map bindings) throws FactTypeUseException { - if (!super.match(matched, bindings)) { - return false; - } - else if (matched.isList() || (matched.isAliased() && matched.getAliased().isList()) || matched.isBottom()) { - return getElementType().match(matched.getElementType(), bindings); - } - - return true; - } - - @Override - public Type instantiate(Map bindings) { - return TypeFactory.getInstance().listType(getElementType().instantiate(bindings)); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - IListWriter result = vf.listWriter(); + } + + @Override + public TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public Type getElementType() { + return fEltType; + } + + @Override + public boolean hasFieldNames() { + return fEltType.hasFieldNames(); + } + + @Override + public boolean isList() { + return true; + } + + @Override + public boolean isListRelation() { + return fEltType.isTuple() || fEltType.isBottom(); + } + + @Override + public boolean hasField(String fieldName) { + return fEltType.hasField(fieldName); + } + + @Override + public int getFieldIndex(String fieldName) { + return fEltType.getFieldIndex(fieldName); + } + + @Override + public Type getFieldType(int i) { + return fEltType.getFieldType(i); + } + + @Override + public String getFieldName(int i) { + return fEltType.getFieldName(i); + } + + @Override + public String[] getFieldNames() { + return fEltType.getFieldNames(); + } + + @Override + public int getArity() { + return fEltType.getArity(); + } + + @Override + public Type getFieldType(String fieldName) throws FactTypeUseException { + return fEltType.getFieldType(fieldName); + } + + @Override + public Type getFieldTypes() { + return fEltType.getFieldTypes(); + } + + @Override + public Type carrier() { + return fEltType.carrier(); + } + + @Override + public Type closure() { + return TF.listType(fEltType.closure()); + } + + @Override + public Type compose(Type other) { + return TF.listType(fEltType.compose(other.getElementType())); + } + + @Override + public Type select(int... fields) { + return TF.listType(fEltType.select(fields)); + } + + @Override + public Type select(String... names) { + return TF.listType(fEltType.select(names)); + } + + @Override + public String toString() { + if (fEltType.isFixedWidth() && !fEltType.equivalent(VoidType.getInstance())) { + StringBuilder sb = new StringBuilder(); + sb.append("lrel["); + int idx = 0; + Iterator iter = fEltType.iterator(); + while(iter.hasNext()) { + Type elemType = iter.next(); + if (idx++ > 0) + sb.append(","); + sb.append(elemType.toString()); + if (hasFieldNames()) { + sb.append(" " + fEltType.getFieldName(idx - 1)); + } + } + sb.append("]"); + return sb.toString(); + } + else { + return "list[" + fEltType + "]"; + } + } + + @Override + public boolean equals(@Nullable Object o) { + if(o == this) { + return true; + } + else if (o instanceof ListType) { + ListType other = (ListType) o; + return fEltType == other.fEltType; + } + + return false; + } + + @Override + public int hashCode() { + return 75703 + 104543 * fEltType.hashCode(); + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitList(this); + } + + @Override + public boolean isOpen() { + return fEltType.isOpen(); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithList(this); + } + + @Override + protected boolean intersectsWithList(Type type) { + // there is always the empty list! + return true; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfList(this); + } + + @Override + protected boolean isSubtypeOfList(Type type) { + return fEltType.isSubtypeOf(type.getElementType()); + } + + @Override + public Type lub(Type other) { + return other.lubWithList(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithList(this); + } + + @Override + public Type lubWithList(Type type) { + return this == type ? this : TF.listType(fEltType.lub(type.getElementType())); + } + + @Override + protected Type glbWithList(Type type) { + return this == type ? this : TF.listType(fEltType.glb(type.getElementType())); + } + + @Override + public boolean match(Type matched, Map bindings) throws FactTypeUseException { + if (!super.match(matched, bindings)) { + return false; + } + else if (matched.isList() || (matched.isAliased() && matched.getAliased().isList()) || matched.isBottom()) { + return getElementType().match(matched.getElementType(), bindings); + } + + return true; + } + + @Override + public Type instantiate(Map bindings) { + return TypeFactory.getInstance().listType(getElementType().instantiate(bindings)); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + IListWriter result = vf.listWriter(); if (maxDepth > 0 && random.nextBoolean()) { int size = Math.min(maxWidth, 1 + random.nextInt(maxDepth)); - + if (!getElementType().isSubtypeOf(TypeFactory.getInstance().voidType())) { for (int i =0; i < size; i++) { result.append(getElementType().randomValue(random, vf, store, typeParameters, maxDepth - 1, maxWidth)); } } } - + IList done = result.done(); match(done.getType(), typeParameters); - + return done; - } + } } diff --git a/src/main/java/io/usethesource/vallang/type/MapType.java b/src/main/java/io/usethesource/vallang/type/MapType.java index 8d66c071f..b24fe10a6 100644 --- a/src/main/java/io/usethesource/vallang/type/MapType.java +++ b/src/main/java/io/usethesource/vallang/type/MapType.java @@ -34,133 +34,133 @@ /*package*/ class MapType extends DefaultSubtypeOfValue { protected final Type fKeyType; protected final Type fValueType; - + /*package*/ MapType(Type keyType, Type valueType) { - fKeyType= keyType; - fValueType = valueType; + fKeyType= keyType; + fValueType = valueType; } - + public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } + public Info(TypeValues symbols) { + super(symbols); + } - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("map", symbols().symbolADT(), "from", symbols().symbolADT(), "to"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - IConstructor from = (IConstructor) symbol.get("from"); - IConstructor to = (IConstructor) symbol.get("to"); - String fromLabel = null; - String toLabel = null; - - if (symbols().isLabel(from)) { - fromLabel = symbols().getLabel(from); - from = (IConstructor) from.get("symbol"); - } - if (symbols().isLabel(to)) { - toLabel = symbols().getLabel(to); - to = (IConstructor) to.get("symbol"); - } - if (fromLabel != null && toLabel != null) { - return tf().mapType(symbols().fromSymbol(from, store, grammar), fromLabel, symbols().fromSymbol(to, store, grammar), toLabel); - } - else { - return tf().mapType(symbols().fromSymbol(from, store, grammar), symbols().fromSymbol(to, store, grammar)); - } - } - - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("map", symbols().symbolADT(), "from", symbols().symbolADT(), "to"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + IConstructor from = (IConstructor) symbol.get("from"); + IConstructor to = (IConstructor) symbol.get("to"); + String fromLabel = null; + String toLabel = null; + + if (symbols().isLabel(from)) { + fromLabel = symbols().getLabel(from); + from = (IConstructor) from.get("symbol"); + } + if (symbols().isLabel(to)) { + toLabel = symbols().getLabel(to); + to = (IConstructor) to.get("symbol"); + } + if (fromLabel != null && toLabel != null) { + return tf().mapType(symbols().fromSymbol(from, store, grammar), fromLabel, symbols().fromSymbol(to, store, grammar), toLabel); + } + else { + return tf().mapType(symbols().fromSymbol(from, store, grammar), symbols().fromSymbol(to, store, grammar)); + } + } + + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - if (type.hasFieldNames()) { - return vf.constructor(getSymbolConstructorType(), symbols().labelSymbol(vf, type.getKeyType().asSymbol(vf, store, grammar, done), type.getKeyLabel()), symbols().labelSymbol(vf, type.getValueType().asSymbol(vf, store, grammar, done), type.getValueLabel())); - } - else { - return vf.constructor(getSymbolConstructorType(), type.getKeyType().asSymbol(vf, store, grammar, done), type.getValueType().asSymbol(vf, store, grammar, done)); - } - } - - @Override + if (type.hasFieldNames()) { + return vf.constructor(getSymbolConstructorType(), symbols().labelSymbol(vf, type.getKeyType().asSymbol(vf, store, grammar, done), type.getKeyLabel()), symbols().labelSymbol(vf, type.getValueType().asSymbol(vf, store, grammar, done), type.getValueLabel())); + } + else { + return vf.constructor(getSymbolConstructorType(), type.getKeyType().asSymbol(vf, store, grammar, done), type.getValueType().asSymbol(vf, store, grammar, done)); + } + } + + @Override public boolean isRecursive() { return false; } - - @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - type.getKeyType().asProductions(vf, store, grammar, done); - type.getValueType().asProductions(vf, store, grammar, done); - } + + @Override + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + type.getKeyType().asProductions(vf, store, grammar, done); + type.getValueType().asProductions(vf, store, grammar, done); + } @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { return tf().mapType(next.get(), next.get()); } - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override public Type getKeyType() { - return fKeyType; + return fKeyType; + } + + @Override + public int getArity() { + return 2; } - - @Override - public int getArity() { - return 2; - } - + @Override public Type getValueType() { - return fValueType; + return fValueType; } @Override public boolean isMap() { return true; } - + @Override public boolean hasFieldNames() { - return false; + return false; } - + @Override public Type getFieldType(int i) { - switch (i) { - case 0: return fKeyType; - case 1: return fValueType; - default: - throw new IndexOutOfBoundsException(); - } + switch (i) { + case 0: return fKeyType; + case 1: return fValueType; + default: + throw new IndexOutOfBoundsException(); + } } - + @Override public Type select(int... fields) { - return TypeFactory.getInstance().setType(getFieldTypes().select(fields)); + return TypeFactory.getInstance().setType(getFieldTypes().select(fields)); } - + @Override public Type getFieldTypes() { return TypeFactory.getInstance().tupleType(fKeyType, fValueType); } - + @Override public Type carrier() { - TypeFactory tf = TypeFactory.getInstance(); - return tf.setType(fKeyType.lub(fValueType)); + TypeFactory tf = TypeFactory.getInstance(); + return tf.setType(fKeyType.lub(fValueType)); } @Override public int hashCode() { - return 56509 + 3511 * fKeyType.hashCode() + 1171 * fValueType.hashCode(); + return 56509 + 3511 * fKeyType.hashCode() + 1171 * fValueType.hashCode(); } @Override @@ -168,11 +168,11 @@ public boolean equals(@Nullable Object obj) { if (obj == null) { return false; } - + if (!obj.getClass().equals(getClass())) { return false; } - + MapType other= (MapType) obj; // N.B.: The element type must have been created and canonicalized before any @@ -183,87 +183,88 @@ public boolean equals(@Nullable Object obj) { @Override public String toString() { - return "map[" + fKeyType + ", " + fValueType + "]"; + return "map[" + fKeyType + ", " + fValueType + "]"; } - + @Override public T accept(ITypeVisitor visitor) throws E { - return visitor.visitMap(this); + return visitor.visitMap(this); } @Override public boolean intersects(Type other) { return other.intersectsWithMap(this); } - + @Override protected boolean intersectsWithMap(Type type) { // there is always the empty map! return true; } - + @Override protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfMap(this); + return type.isSubtypeOfMap(this); } - + @Override public Type lub(Type other) { - return other.lubWithMap(this); + return other.lubWithMap(this); } - + @Override public Type glb(Type type) { - return type.glbWithMap(this); + return type.glbWithMap(this); } - + @Override protected boolean isSubtypeOfMap(Type type) { - return fKeyType.isSubtypeOf(type.getKeyType()) - && fValueType.isSubtypeOf(type.getValueType()); + return fKeyType.isSubtypeOf(type.getKeyType()) + && fValueType.isSubtypeOf(type.getValueType()); } - + @Override protected Type lubWithMap(Type type) { - return this == type ? this : TF.mapTypeFromTuple(getFieldTypes().lub(type.getFieldTypes())); + return this == type ? this : TF.mapTypeFromTuple(getFieldTypes().lub(type.getFieldTypes())); } - + @Override protected Type glbWithMap(Type type) { - return this == type ? this : TF.mapTypeFromTuple(getFieldTypes().glb(type.getFieldTypes())); + return this == type ? this : TF.mapTypeFromTuple(getFieldTypes().glb(type.getFieldTypes())); } - + @Override public boolean isOpen() { - return fKeyType.isOpen() || fValueType.isOpen(); + return fKeyType.isOpen() || fValueType.isOpen(); } - - @Override - public boolean match(Type matched, Map bindings)throws FactTypeUseException { + + @Override + public boolean match(Type matched, Map bindings) throws FactTypeUseException { if (!super.match(matched, bindings)) { - return false; + return false; } - if (matched.isMap() || (matched.isAliased() && matched.getAliased().isMap()) || matched.isBottom()) { - return getKeyType().match(matched.getKeyType(), bindings) - && getValueType().match(matched.getValueType(), bindings); + if (matched.isMap() || (matched.isAliased() && matched.getAliased().isMap()) || matched.isBottom()) { + return getKeyType().match(matched.getKeyType(), bindings) + && getValueType().match(matched.getValueType(), bindings); } return true; - } - - @Override - public Type instantiate(Map bindings) { - return TypeFactory.getInstance().mapType(getKeyType().instantiate(bindings), getValueType().instantiate(bindings)); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - IMapWriter result = vf.mapWriter(); + } + + @Override + public Type instantiate(Map bindings) { + return TypeFactory.getInstance().mapType(getKeyType().instantiate(bindings), + getValueType().instantiate(bindings)); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + IMapWriter result = vf.mapWriter(); if (maxDepth > 0 && random.nextBoolean()) { int size = Math.min(maxWidth, 1 + random.nextInt(maxDepth)); - + if (!getKeyType().isBottom() && !getValueType().isBottom()) { for (int i =0; i < size; i++) { result.put( @@ -272,10 +273,10 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< } } } - + IMap done = result.done(); match(done.getType(), typeParameters); - + return done; - } + } } diff --git a/src/main/java/io/usethesource/vallang/type/MapTypeWithFieldNames.java b/src/main/java/io/usethesource/vallang/type/MapTypeWithFieldNames.java index bceee927d..d2fafae13 100644 --- a/src/main/java/io/usethesource/vallang/type/MapTypeWithFieldNames.java +++ b/src/main/java/io/usethesource/vallang/type/MapTypeWithFieldNames.java @@ -23,89 +23,89 @@ /*package*/ final class MapTypeWithFieldNames extends MapType { private final String fKeyLabel; private final String fValueLabel; - + /*package*/ MapTypeWithFieldNames(Type keyType, String keyLabel, Type valueType, String valueLabel) { super(keyType, valueType); - fKeyLabel = keyLabel; - fValueLabel = valueLabel; + fKeyLabel = keyLabel; + fValueLabel = valueLabel; + } + + @Override + public String getValueLabel() { + return fValueLabel; } - - @Override - public String getValueLabel() { - return fValueLabel; - } - - @Override - public String getKeyLabel() { - return fKeyLabel; - } - + + @Override + public String getKeyLabel() { + return fKeyLabel; + } + @Override public boolean hasFieldNames() { - return true; + return true; } - + @Override public Type getFieldType(String fieldName) throws FactTypeUseException { - if (fKeyLabel.equals(fieldName)) { - return fKeyType; - } - - if (fValueLabel.equals(fieldName)) { - return fValueType; - } - - throw new UndeclaredFieldException(this, fieldName); + if (fKeyLabel.equals(fieldName)) { + return fKeyType; + } + + if (fValueLabel.equals(fieldName)) { + return fValueType; + } + + throw new UndeclaredFieldException(this, fieldName); } - + @Override public boolean hasField(String fieldName) { - if (fieldName.equals(fKeyLabel)) { - return true; - } - else if (fieldName.equals(fValueLabel)) { - return true; - } - - return false; + if (fieldName.equals(fKeyLabel)) { + return true; + } + else if (fieldName.equals(fValueLabel)) { + return true; + } + + return false; } - + @Override public String getFieldName(int i) { - switch (i) { - case 0: return fKeyLabel; - case 1: return fValueLabel; - default: - throw new IndexOutOfBoundsException(); - } + switch (i) { + case 0: return fKeyLabel; + case 1: return fValueLabel; + default: + throw new IndexOutOfBoundsException(); + } } - + @Override public Type select(String... names) { - return TypeFactory.getInstance().setType(getFieldTypes().select(names)); + return TypeFactory.getInstance().setType(getFieldTypes().select(names)); } - + @Override public int getFieldIndex(String fieldName) { - if (fKeyLabel.equals(fieldName)) { - return 0; - } - if (fValueLabel.equals(fieldName)) { - return 1; - } - throw new UndeclaredFieldException(this, fieldName); + if (fKeyLabel.equals(fieldName)) { + return 0; + } + if (fValueLabel.equals(fieldName)) { + return 1; + } + throw new UndeclaredFieldException(this, fieldName); } - + @SuppressWarnings("deprecation") @Override public Type getFieldTypes() { return TypeFactory.getInstance().tupleType(fKeyType, fKeyLabel, fValueType, fValueLabel); } - + @Override public int hashCode() { - return 56509 + 3511 * fKeyType.hashCode() + 1171 * fValueType.hashCode() + 13 * fKeyLabel.hashCode() + 1331 * fValueLabel.hashCode(); + return 56509 + 3511 * fKeyType.hashCode() + 1171 * fValueType.hashCode() + 13 * fKeyLabel.hashCode() + 1331 * fValueLabel.hashCode(); } @Override @@ -113,18 +113,18 @@ public boolean equals(@Nullable Object obj) { if (obj == null) { return false; } - + if (!obj.getClass().equals(getClass())) { return false; } - + MapTypeWithFieldNames other= (MapTypeWithFieldNames) obj; // N.B.: The element type must have been created and canonicalized before any // attempt to manipulate the outer type (i.e. SetType), so we can use object // identity here for the fEltType. - return fKeyType == other.fKeyType - && fValueType == other.fValueType + return fKeyType == other.fKeyType + && fValueType == other.fValueType && fKeyLabel.equals(other.fKeyLabel) && fValueLabel.equals(other.fValueLabel) ; @@ -132,14 +132,14 @@ public boolean equals(@Nullable Object obj) { @Override public String toString() { - return "map[" - + fKeyType + " " + fKeyLabel + ", " - + fValueType + " " + fValueLabel - + "]"; + return "map[" + + fKeyType + " " + fKeyLabel + ", " + + fValueType + " " + fValueLabel + + "]"; + } + + @Override + public Type instantiate(Map bindings) { + return TypeFactory.getInstance().mapType(getKeyType().instantiate(bindings), fKeyLabel, getValueType().instantiate(bindings), fValueLabel); } - - @Override - public Type instantiate(Map bindings) { - return TypeFactory.getInstance().mapType(getKeyType().instantiate(bindings), fKeyLabel, getValueType().instantiate(bindings), fValueLabel); - } } diff --git a/src/main/java/io/usethesource/vallang/type/NodeType.java b/src/main/java/io/usethesource/vallang/type/NodeType.java index 55c6be727..fe7bb77dd 100644 --- a/src/main/java/io/usethesource/vallang/type/NodeType.java +++ b/src/main/java/io/usethesource/vallang/type/NodeType.java @@ -34,139 +34,139 @@ * IConstructors have NodeType as a supertype. */ class NodeType extends DefaultSubtypeOfValue { - protected static class InstanceKeeper { - public final static NodeType sInstance = new NodeType(); - } - - public static NodeType getInstance() { - return InstanceKeeper.sInstance; - } - - public static class Info extends TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("node"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, - Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().nodeType(); - } - } - - @Override - public TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - - @Override - public String toString() { - return "node"; - } - - /** - * Should never be called, NodeType is a singleton - */ - @Override - public boolean equals(@Nullable Object o) { - return o == NodeType.getInstance(); - } - - @Override - public int hashCode() { - return 20102; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfNode(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithNode(this); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithNode(this); - } - - @Override - protected boolean intersectsWithNode(Type type) { - return true; - } - - @Override - protected boolean intersectsWithAbstractData(Type type) { - return true; - } - - @Override - protected boolean intersectsWithConstructor(Type type) { - return true; - } - - @Override - protected boolean isSubtypeOfNode(Type type) { - return true; - } - - @Override - protected Type lubWithAbstractData(Type type) { - return this; - } - - @Override - protected Type lubWithConstructor(Type type) { - return this; - } - - @Override - protected Type lubWithNode(Type type) { - return type; - } - - @Override - public Type glb(Type type) { - return type.glbWithNode(this); - } - - @Override - protected Type glbWithNode(Type type) { - return this; - } - - @Override - protected Type glbWithConstructor(Type type) { - return type; - } - - @Override - protected Type glbWithAbstractData(Type type) { - return type; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitNode(this); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - String name = random.nextBoolean() ? RandomUtil.string(random, 1 + random.nextInt(5)) : RandomUtil.stringAlpha(random, random.nextInt(5)); + protected static class InstanceKeeper { + public final static NodeType sInstance = new NodeType(); + } + + public static NodeType getInstance() { + return InstanceKeeper.sInstance; + } + + public static class Info extends TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("node"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, + Function> grammar) { + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().nodeType(); + } + } + + @Override + public TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + + @Override + public String toString() { + return "node"; + } + + /** + * Should never be called, NodeType is a singleton + */ + @Override + public boolean equals(@Nullable Object o) { + return o == NodeType.getInstance(); + } + + @Override + public int hashCode() { + return 20102; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfNode(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithNode(this); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithNode(this); + } + + @Override + protected boolean intersectsWithNode(Type type) { + return true; + } + + @Override + protected boolean intersectsWithAbstractData(Type type) { + return true; + } + + @Override + protected boolean intersectsWithConstructor(Type type) { + return true; + } + + @Override + protected boolean isSubtypeOfNode(Type type) { + return true; + } + + @Override + protected Type lubWithAbstractData(Type type) { + return this; + } + + @Override + protected Type lubWithConstructor(Type type) { + return this; + } + + @Override + protected Type lubWithNode(Type type) { + return type; + } + + @Override + public Type glb(Type type) { + return type.glbWithNode(this); + } + + @Override + protected Type glbWithNode(Type type) { + return this; + } + + @Override + protected Type glbWithConstructor(Type type) { + return type; + } + + @Override + protected Type glbWithAbstractData(Type type) { + return type; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitNode(this); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + String name = random.nextBoolean() ? RandomUtil.string(random, 1 + random.nextInt(5)) : RandomUtil.stringAlpha(random, random.nextInt(5)); int arity = maxDepth <= 0 ? 0 : random.nextInt(maxDepth); IValue[] args = new IValue[arity]; @@ -181,7 +181,7 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< String kwName = ""; while (kwName.isEmpty()) { // names have to start with alpha character - kwName = RandomUtil.stringAlpha(random, 3); + kwName = RandomUtil.stringAlpha(random, 3); } kwName += RandomUtil.stringAlphaNumeric(random, 4); kwParams.put(kwName, TypeFactory.getInstance().valueType().randomValue(random, vf, store, typeParameters, maxDepth - 1, maxWidth)); @@ -189,11 +189,11 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< return vf.node(name, args, kwParams); } - return vf.node(name, args); - } - - @Override - public boolean isNode() { - return true; - } + return vf.node(name, args); + } + + @Override + public boolean isNode() { + return true; + } } diff --git a/src/main/java/io/usethesource/vallang/type/NumberType.java b/src/main/java/io/usethesource/vallang/type/NumberType.java index 74c1008a8..f1b350232 100644 --- a/src/main/java/io/usethesource/vallang/type/NumberType.java +++ b/src/main/java/io/usethesource/vallang/type/NumberType.java @@ -30,166 +30,166 @@ * A type for values that are either ints or reals */ /* package */class NumberType extends DefaultSubtypeOfValue { - private static final class InstanceKeeper { - protected final static NumberType sInstance = new NumberType(); - } - - public static NumberType getInstance() { - return InstanceKeeper.sInstance; - } - - public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("num"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + private static final class InstanceKeeper { + protected final static NumberType sInstance = new NumberType(); + } + + public static NumberType getInstance() { + return InstanceKeeper.sInstance; + } + + public static class Info extends TypeFactory.TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("num"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().numberType(); - } - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public String toString() { - return "num"; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfNumber(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithNumber(this); - } - - @Override - protected boolean isSubtypeOfNumber(Type type) { - return true; - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithNumber(this); - } - - - @Override - protected boolean intersectsWithNumber(Type type) { - return true; - } - - @Override - protected boolean intersectsWithInteger(Type type) { - return true; - } - - @Override - protected boolean intersectsWithRational(Type type) { - return true; - } - - @Override - protected boolean intersectsWithReal(Type type) { - return true; - } - - - @Override - protected Type lubWithNumber(Type type) { - return type; - } - - @Override - protected Type lubWithInteger(Type type) { - return NumberType.getInstance(); - } - - @Override - protected Type lubWithReal(Type type) { - return NumberType.getInstance(); - } - - @Override - protected Type lubWithRational(Type type) { - return NumberType.getInstance(); - } - - @Override - public Type glb(Type type) { - return type.glbWithNumber(this); - } - - @Override - protected Type glbWithNumber(Type type) { - return this; - } - - @Override - protected Type glbWithInteger(Type type) { - return type; - } - - @Override - protected Type glbWithReal(Type type) { - return type; - } - - @Override - protected Type glbWithRational(Type type) { - return type; - } - - /** - * Should never be called, NodeType is a singleton - */ - @Override - public boolean equals(@Nullable Object o) { - return o == NumberType.getInstance(); - } - - @Override - public int hashCode() { - return 133020331; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitNumber(this); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - switch (random.nextInt(3)) { - case 0: - return TypeFactory.getInstance().integerType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); - case 1: - return TypeFactory.getInstance().realType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); - default: - return TypeFactory.getInstance().rationalType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); - } - } - - @Override - public boolean isNumber() { - return true; - } + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().numberType(); + } + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public String toString() { + return "num"; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfNumber(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithNumber(this); + } + + @Override + protected boolean isSubtypeOfNumber(Type type) { + return true; + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithNumber(this); + } + + + @Override + protected boolean intersectsWithNumber(Type type) { + return true; + } + + @Override + protected boolean intersectsWithInteger(Type type) { + return true; + } + + @Override + protected boolean intersectsWithRational(Type type) { + return true; + } + + @Override + protected boolean intersectsWithReal(Type type) { + return true; + } + + + @Override + protected Type lubWithNumber(Type type) { + return type; + } + + @Override + protected Type lubWithInteger(Type type) { + return NumberType.getInstance(); + } + + @Override + protected Type lubWithReal(Type type) { + return NumberType.getInstance(); + } + + @Override + protected Type lubWithRational(Type type) { + return NumberType.getInstance(); + } + + @Override + public Type glb(Type type) { + return type.glbWithNumber(this); + } + + @Override + protected Type glbWithNumber(Type type) { + return this; + } + + @Override + protected Type glbWithInteger(Type type) { + return type; + } + + @Override + protected Type glbWithReal(Type type) { + return type; + } + + @Override + protected Type glbWithRational(Type type) { + return type; + } + + /** + * Should never be called, NodeType is a singleton + */ + @Override + public boolean equals(@Nullable Object o) { + return o == NumberType.getInstance(); + } + + @Override + public int hashCode() { + return 133020331; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitNumber(this); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + switch (random.nextInt(3)) { + case 0: + return TypeFactory.getInstance().integerType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); + case 1: + return TypeFactory.getInstance().realType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); + default: + return TypeFactory.getInstance().rationalType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); + } + } + + @Override + public boolean isNumber() { + return true; + } } diff --git a/src/main/java/io/usethesource/vallang/type/ParameterType.java b/src/main/java/io/usethesource/vallang/type/ParameterType.java index 243e1d5d6..b78ec73a2 100644 --- a/src/main/java/io/usethesource/vallang/type/ParameterType.java +++ b/src/main/java/io/usethesource/vallang/type/ParameterType.java @@ -38,470 +38,470 @@ * later. */ /*package*/ final class ParameterType extends DefaultSubtypeOfValue { - private final String fName; - private final Type fBound; - - /* package */ ParameterType(String name, Type bound) { - fName = name.intern(); - fBound = bound; - } - - /* package */ ParameterType(String name) { - fName = name.intern(); - fBound = TypeFactory.getInstance().valueType(); - } - - public static class Info extends TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("parameter", tf().stringType() , "name", symbols().symbolADT(), "bound"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return tf().parameterType(((IString) symbol.get("name")).getValue(), symbols().fromSymbol((IConstructor) symbol.get("bound"), store, grammar)); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - if (rnd.isWithTypeParameters()) { - return tf().parameterType(randomLabel(rnd)); - } - - return next.get(); - } - - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - return vf.constructor(getSymbolConstructorType(), vf.string(type.getName()), type.getBound().asSymbol(vf, store, grammar, done)); - } - - @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - type.getBound().asProductions(vf, store, grammar, done); - } - } - - @Override - public TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public Type getTypeParameters() { - return getBound().getTypeParameters(); - } - - @Override - public Type getBound() { - return fBound; - } - - @Override - public String getName() { - return fName; - } - - @Override - public int getArity(){ - return fBound.getArity(); - } - - @Override - public Type getFieldType(int i){ - return fBound.getFieldType(i); - } - - @Override - public String[] getFieldNames(){ - return fBound.getFieldNames(); - } - - @Override - public String toString() { - return fBound.equivalent(ValueType.getInstance()) ? "&" + fName : "&" + fName + "<:" + fBound.toString(); - } - - @Override - public int hashCode() { - return 49991 + 49831 * fName.hashCode() + 133020331 * fBound.hashCode(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (o == null) { - return false; - } - - if (o instanceof ParameterType) { - ParameterType other = (ParameterType) o; - return fName.equals(other.fName) && fBound == other.fBound; - } - return false; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitParameter(this); - } - - @Override - public boolean intersects(Type other) { - if (other == this) { - return true; - } - + private final String fName; + private final Type fBound; + + /* package */ ParameterType(String name, Type bound) { + fName = name.intern(); + fBound = bound; + } + + /* package */ ParameterType(String name) { + fName = name.intern(); + fBound = TypeFactory.getInstance().valueType(); + } + + public static class Info extends TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("parameter", tf().stringType() , "name", symbols().symbolADT(), "bound"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + return tf().parameterType(((IString) symbol.get("name")).getValue(), symbols().fromSymbol((IConstructor) symbol.get("bound"), store, grammar)); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + if (rnd.isWithTypeParameters()) { + return tf().parameterType(randomLabel(rnd)); + } + + return next.get(); + } + + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + return vf.constructor(getSymbolConstructorType(), vf.string(type.getName()), type.getBound().asSymbol(vf, store, grammar, done)); + } + + @Override + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + type.getBound().asProductions(vf, store, grammar, done); + } + } + + @Override + public TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public Type getTypeParameters() { + return getBound().getTypeParameters(); + } + + @Override + public Type getBound() { + return fBound; + } + + @Override + public String getName() { + return fName; + } + + @Override + public int getArity(){ + return fBound.getArity(); + } + + @Override + public Type getFieldType(int i){ + return fBound.getFieldType(i); + } + + @Override + public String[] getFieldNames(){ + return fBound.getFieldNames(); + } + + @Override + public String toString() { + return fBound.equivalent(ValueType.getInstance()) ? "&" + fName : "&" + fName + "<:" + fBound.toString(); + } + + @Override + public int hashCode() { + return 49991 + 49831 * fName.hashCode() + 133020331 * fBound.hashCode(); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null) { + return false; + } + + if (o instanceof ParameterType) { + ParameterType other = (ParameterType) o; + return fName.equals(other.fName) && fBound == other.fBound; + } + return false; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitParameter(this); + } + + @Override + public boolean intersects(Type other) { + if (other == this) { + return true; + } + return getBound().intersects(other); - } - - @Override - /** - * Type parameters are universal, extending their semantics over - * possible extensions of the vallang type system. - */ - protected boolean intersectsWithExternal(Type type) { - return getBound().intersects(type); - } - /** + } + + @Override + /** + * Type parameters are universal, extending their semantics over + * possible extensions of the vallang type system. + */ + protected boolean intersectsWithExternal(Type type) { + return getBound().intersects(type); + } + /** * Read this as "could be instantiated as a super-type of" */ - @Override - protected boolean isSupertypeOf(Type type) { - if (type == this) { - // here we assume hygenic type parameter binding - return true; - } - - // if the type parameter is totally free, - // it is bound by `value` only, then it can - // be a supertype of anything. This is also - // a stop condition for an infinite recursion. - if (getBound().isTop()) { - return true; - } - - // otherwise, the instantiated type goes no higher than the - // bound, so if the bound is not a supertype, - // then the parameter can't be either: - return getBound().isSupertypeOf(type); - } - - @Override - protected boolean isSubtypeOfAbstractData(Type type) { - return couldBeSubtypeOf(type); - } - - /** - * @return true iff this parameter type when instantiated could - * be a sub-type of the given type. - */ + @Override + protected boolean isSupertypeOf(Type type) { + if (type == this) { + // here we assume hygenic type parameter binding + return true; + } + + // if the type parameter is totally free, + // it is bound by `value` only, then it can + // be a supertype of anything. This is also + // a stop condition for an infinite recursion. + if (getBound().isTop()) { + return true; + } + + // otherwise, the instantiated type goes no higher than the + // bound, so if the bound is not a supertype, + // then the parameter can't be either: + return getBound().isSupertypeOf(type); + } + + @Override + protected boolean isSubtypeOfAbstractData(Type type) { + return couldBeSubtypeOf(type); + } + + /** + * @return true iff this parameter type when instantiated could + * be a sub-type of the given type. + */ private boolean couldBeSubtypeOf(Type type) { // the only way that this is impossible if is the compared type // is not comparable to the bound return getBound().comparable(type); } - - @Override - protected boolean isSubtypeOfBool(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfConstructor(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfDateTime(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfExternal(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfInteger(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfList(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfMap(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfNode(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfNumber(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfParameter(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfRational(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfReal(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfSet(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfSourceLocation(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfString(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfTuple(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfValue(Type type) { - return couldBeSubtypeOf(type); - } - - @Override - protected boolean isSubtypeOfVoid(Type type) { - return couldBeSubtypeOf(type); - } - @Override - protected boolean intersectsWithValue(Type type) { - return true; - } - - @Override + + @Override + protected boolean isSubtypeOfBool(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfConstructor(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfDateTime(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfExternal(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfInteger(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfList(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfMap(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfNode(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfNumber(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfParameter(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfRational(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfReal(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfSet(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfSourceLocation(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfString(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfTuple(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfValue(Type type) { + return couldBeSubtypeOf(type); + } + + @Override + protected boolean isSubtypeOfVoid(Type type) { + return couldBeSubtypeOf(type); + } + @Override + protected boolean intersectsWithValue(Type type) { + return true; + } + + @Override protected boolean intersectsWithReal(Type type) { return getBound().intersects(type); - } - - @Override + } + + @Override protected boolean intersectsWithInteger(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithRational(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithList(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithMap(Type type) { - return getBound().intersects(type); + return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithNumber(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithRelation(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithSet(Type type) { - return getBound().intersects(type); + return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithSourceLocation(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithString(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithNode(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithConstructor(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithAbstractData(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithTuple(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithFunction(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithVoid(Type type) { // the intersection of void, even with itself is empty. return false; } - @Override + @Override protected boolean intersectsWithBool(Type type) { return getBound().intersects(type); } - @Override + @Override protected boolean intersectsWithDateTime(Type type) { return getBound().intersects(type); - } - - @Override - public Type lub(Type type) { - if (type == this) { - return this; - } - - if (type.isSubtypeOf(getBound())) { + } + + @Override + public Type lub(Type type) { + if (type == this) { + return this; + } + + if (type.isSubtypeOf(getBound())) { + return this; + } + + return getBound().lub(type); + } + + @Override + public Type glb(Type type) { + if (type == this) { + return this; + } + + if (type.isSupertypeOf(getBound())) { return this; } - - return getBound().lub(type); - } - - @Override - public Type glb(Type type) { - if (type == this) { - return this; - } - - if (type.isSupertypeOf(getBound())) { - return this; - } - - return getBound().glb(type); - } - - @Override - public boolean match(Type matched, Map bindings) throws FactTypeUseException { - if (!super.match(matched, bindings)) { - return false; - } - - Type earlier = bindings.get(this); - - if (earlier != null) { - // now it is time for earlier bindings to have an effect - // on the current binding if there is recursive use of type parameters - // such as in self-application of higher-order functions like "curry" - Type lub = earlier; - Map newBindings = new HashMap<>(bindings); - - if (matched.isOpen() && !matched.isParameter() && matched.match(earlier, newBindings)) { - if (newBindings.size() > bindings.size()) { - bindings.put(this, matched.instantiate(newBindings)); - bindings.putAll(newBindings); - } - - return true; - } - // matched must be on the left side of lub here to prevent loss of field names - else if ((lub = matched.lub(earlier)).isSubtypeOf(getBound())) { - bindings.put(this, lub); - getBound().match(matched, bindings); - return true; - } - else { - return false; - } - } - else { - bindings.put(this, matched); - getBound().match(matched, bindings); - } - - return true; - } - - @Override - public Type instantiate(Map bindings) { - Type result = bindings.get(this); - - if (result != null && result != this) { - try { - return result.instantiate(bindings); - } - catch (StackOverflowError e) { - assert false : "type bindings are not hygenic: cyclic parameter binding leads to infinite recursion"; - return result; - } - } - else { - return TypeFactory.getInstance().parameterType(fName, getBound().instantiate(bindings)); - } - } - - @Override - public boolean isOpen() { - return true; - } - - @Override - public boolean isParameter() { - return true; - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - IValue val = getBound().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); - - inferBinding(typeParameters, val); - - return val; - } + + return getBound().glb(type); + } + + @Override + public boolean match(Type matched, Map bindings) throws FactTypeUseException { + if (!super.match(matched, bindings)) { + return false; + } + + Type earlier = bindings.get(this); + + if (earlier != null) { + // now it is time for earlier bindings to have an effect + // on the current binding if there is recursive use of type parameters + // such as in self-application of higher-order functions like "curry" + Type lub = earlier; + Map newBindings = new HashMap<>(bindings); + + if (matched.isOpen() && !matched.isParameter() && matched.match(earlier, newBindings)) { + if (newBindings.size() > bindings.size()) { + bindings.put(this, matched.instantiate(newBindings)); + bindings.putAll(newBindings); + } + + return true; + } + // matched must be on the left side of lub here to prevent loss of field names + else if ((lub = matched.lub(earlier)).isSubtypeOf(getBound())) { + bindings.put(this, lub); + getBound().match(matched, bindings); + return true; + } + else { + return false; + } + } + else { + bindings.put(this, matched); + getBound().match(matched, bindings); + } + + return true; + } + + @Override + public Type instantiate(Map bindings) { + Type result = bindings.get(this); + + if (result != null && result != this) { + try { + return result.instantiate(bindings); + } + catch (StackOverflowError e) { + assert false : "type bindings are not hygenic: cyclic parameter binding leads to infinite recursion"; + return result; + } + } + else { + return TypeFactory.getInstance().parameterType(fName, getBound().instantiate(bindings)); + } + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public boolean isParameter() { + return true; + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + IValue val = getBound().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); + + inferBinding(typeParameters, val); + + return val; + } private void inferBinding(Map typeParameters, IValue val) { Type tv = typeParameters.get(this); - - if (tv != null) { - tv = tv.lub(val.getType()); - } - else { - tv = val.getType(); - } - - typeParameters.put(this, tv); + + if (tv != null) { + tv = tv.lub(val.getType()); + } + else { + tv = val.getType(); + } + + typeParameters.put(this, tv); } } diff --git a/src/main/java/io/usethesource/vallang/type/RationalType.java b/src/main/java/io/usethesource/vallang/type/RationalType.java index e289e49d5..52d22f71c 100644 --- a/src/main/java/io/usethesource/vallang/type/RationalType.java +++ b/src/main/java/io/usethesource/vallang/type/RationalType.java @@ -26,137 +26,137 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class RationalType extends NumberType { - private static final class InstanceKeeper { - public final static RationalType sInstance= new RationalType(); - } + private static final class InstanceKeeper { + public final static RationalType sInstance= new RationalType(); + } - public static RationalType getInstance() { - return InstanceKeeper.sInstance; - } + public static RationalType getInstance() { + return InstanceKeeper.sInstance; + } - public static class Info extends TypeFactory.TypeReifier { + public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } + public Info(TypeValues symbols) { + super(symbols); + } - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("rat"); - } + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("rat"); + } - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().rationalType(); - } - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - /** - * Should never need to be called; there should be only one instance of IntegerType - */ - @Override - public boolean equals(@Nullable Object obj) { - return obj == RationalType.getInstance(); -} + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().rationalType(); + } + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + /** + * Should never need to be called; there should be only one instance of IntegerType + */ + @Override + public boolean equals(@Nullable Object obj) { + return obj == RationalType.getInstance(); + } + + @Override + public int hashCode() { + return 212873; + } - @Override - public int hashCode() { - return 212873; - } - - @Override - public String toString() { - return "rat"; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitRational(this); - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfRational(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithRational(this); - } - - @Override - protected Type lubWithRational(Type type) { - return this; - } - - @Override - protected boolean isSubtypeOfRational(Type type) { - return true; - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithRational(this); - } - - @Override - protected boolean intersectsWithRational(Type type) { - return true; - } - - @Override - protected boolean intersectsWithInteger(Type type) { - return false; - } - - @Override - protected boolean intersectsWithReal(Type type) { - return false; - } - - @Override - public Type glb(Type type) { - return type.glbWithRational(this); - } - - @Override - protected Type glbWithNumber(Type type) { - return this; - } - - @Override - protected Type glbWithRational(Type type) { - return this; - } - - @Override - protected Type glbWithReal(Type type) { - return VoidType.getInstance(); - } - - protected Type glbWithInteger(Type type) { - return VoidType.getInstance(); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { + @Override + public String toString() { + return "rat"; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitRational(this); + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfRational(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithRational(this); + } + + @Override + protected Type lubWithRational(Type type) { + return this; + } + + @Override + protected boolean isSubtypeOfRational(Type type) { + return true; + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithRational(this); + } + + @Override + protected boolean intersectsWithRational(Type type) { + return true; + } + + @Override + protected boolean intersectsWithInteger(Type type) { + return false; + } + + @Override + protected boolean intersectsWithReal(Type type) { + return false; + } + + @Override + public Type glb(Type type) { + return type.glbWithRational(this); + } + + @Override + protected Type glbWithNumber(Type type) { + return this; + } + + @Override + protected Type glbWithRational(Type type) { + return this; + } + + @Override + protected Type glbWithReal(Type type) { + return VoidType.getInstance(); + } + + protected Type glbWithInteger(Type type) { + return VoidType.getInstance(); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { return vf.rational(random.nextInt(), random.nextInt() + 1); - } - - @Override - public boolean isRational() { - return true; + } + + @Override + public boolean isRational() { + return true; } } diff --git a/src/main/java/io/usethesource/vallang/type/RealType.java b/src/main/java/io/usethesource/vallang/type/RealType.java index ec6ed25c6..be4467884 100644 --- a/src/main/java/io/usethesource/vallang/type/RealType.java +++ b/src/main/java/io/usethesource/vallang/type/RealType.java @@ -29,140 +29,140 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class RealType extends NumberType { - private final static class InstanceKeeper { - public final static RealType sInstance = new RealType(); - } - - public static RealType getInstance() { - return InstanceKeeper.sInstance; - } - - public static class Info extends TypeFactory.TypeReifier { - - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("real"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + private final static class InstanceKeeper { + public final static RealType sInstance = new RealType(); + } + + public static RealType getInstance() { + return InstanceKeeper.sInstance; + } + + public static class Info extends TypeFactory.TypeReifier { + + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("real"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().realType(); - } - } - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - /** - * Should never need to be called; there should be only one instance of - * IntegerType - */ - @Override - public boolean equals(@Nullable Object obj) { - return obj == RealType.getInstance(); -} + return getInstance(); + } - @Override - public int hashCode() { - return 84121; - } - - @Override - public String toString() { - return "real"; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitReal(this); - } - - @Override - public boolean isReal() { - return true; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfReal(this); - } - - @Override - public Type lub(Type type) { - return type.lubWithReal(this); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithReal(this); - } - - @Override - protected boolean intersectsWithReal(Type type) { - return true; - } - - @Override - protected boolean intersectsWithRational(Type type) { - return false; - } - - @Override - protected boolean intersectsWithInteger(Type type) { - return false; - } - - @Override - public Type glb(Type type) { - return type.glbWithReal(this); - } - - @Override - protected Type lubWithReal(Type type) { - return this; - } - - @Override - protected Type glbWithReal(Type type) { - return this; - } - - @Override - protected Type glbWithNumber(Type type) { - return this; - } - - @Override - protected Type glbWithRational(Type type) { - return VoidType.getInstance(); - } - - @Override - protected Type glbWithInteger(Type type) { - return VoidType.getInstance(); - } - - @Override - protected boolean isSubtypeOfReal(Type type) { - return true; - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - if (RandomUtil.oneEvery(random, 5)) { + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().realType(); + } + } + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + /** + * Should never need to be called; there should be only one instance of + * IntegerType + */ + @Override + public boolean equals(@Nullable Object obj) { + return obj == RealType.getInstance(); + } + + @Override + public int hashCode() { + return 84121; + } + + @Override + public String toString() { + return "real"; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitReal(this); + } + + @Override + public boolean isReal() { + return true; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfReal(this); + } + + @Override + public Type lub(Type type) { + return type.lubWithReal(this); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithReal(this); + } + + @Override + protected boolean intersectsWithReal(Type type) { + return true; + } + + @Override + protected boolean intersectsWithRational(Type type) { + return false; + } + + @Override + protected boolean intersectsWithInteger(Type type) { + return false; + } + + @Override + public Type glb(Type type) { + return type.glbWithReal(this); + } + + @Override + protected Type lubWithReal(Type type) { + return this; + } + + @Override + protected Type glbWithReal(Type type) { + return this; + } + + @Override + protected Type glbWithNumber(Type type) { + return this; + } + + @Override + protected Type glbWithRational(Type type) { + return VoidType.getInstance(); + } + + @Override + protected Type glbWithInteger(Type type) { + return VoidType.getInstance(); + } + + @Override + protected boolean isSubtypeOfReal(Type type) { + return true; + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + if (RandomUtil.oneEvery(random, 5)) { return vf.real(10 * random.nextDouble()); } if (RandomUtil.oneEvery(random, 5)) { @@ -182,5 +182,5 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< } return vf.real(0.0); - } + } } diff --git a/src/main/java/io/usethesource/vallang/type/SetType.java b/src/main/java/io/usethesource/vallang/type/SetType.java index 7276ab9b9..312088e91 100644 --- a/src/main/java/io/usethesource/vallang/type/SetType.java +++ b/src/main/java/io/usethesource/vallang/type/SetType.java @@ -33,290 +33,290 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/class SetType extends DefaultSubtypeOfValue { - protected final Type fEltType; - - /* package */SetType(Type eltType) { - fEltType = eltType; - } - - public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - throw new UnsupportedOperationException(); - } - - @Override - public Set getSymbolConstructorTypes() { - return Arrays.stream(new Type[] { - getSetType(), - getRelType() // TODO: can be removed after bootstrap - }).collect(Collectors.toSet()); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().setType(next.get()); - } - - @Override - public boolean isRecursive() { - return false; - } - - private Type getRelType() { - return symbols().typeSymbolConstructor("rel", tf().listType(symbols().symbolADT()), "symbols"); - } - - private Type getSetType() { - return symbols().typeSymbolConstructor("set", symbols().symbolADT(), "symbol"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - if (symbol.getConstructorType() == getSetType()) { - return tf().setType(symbols().fromSymbol((IConstructor) symbol.get("symbol"), store, grammar)); - } - else { - // TODO remove; this is for bootstrapping with an old version - return tf().setType(symbols().fromSymbols((IList) symbol.get("symbols"), store, grammar)); - } - } - - @Override - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + protected final Type fEltType; + + /* package */SetType(Type eltType) { + fEltType = eltType; + } + + public static class Info extends TypeFactory.TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getSymbolConstructorTypes() { + return Arrays.stream(new Type[] { + getSetType(), + getRelType() // TODO: can be removed after bootstrap + }).collect(Collectors.toSet()); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().setType(next.get()); + } + + @Override + public boolean isRecursive() { + return false; + } + + private Type getRelType() { + return symbols().typeSymbolConstructor("rel", tf().listType(symbols().symbolADT()), "symbols"); + } + + private Type getSetType() { + return symbols().typeSymbolConstructor("set", symbols().symbolADT(), "symbol"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + if (symbol.getConstructorType() == getSetType()) { + return tf().setType(symbols().fromSymbol((IConstructor) symbol.get("symbol"), store, grammar)); + } + else { + // TODO remove; this is for bootstrapping with an old version + return tf().setType(symbols().fromSymbols((IList) symbol.get("symbols"), store, grammar)); + } + } + + @Override + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - return vf.constructor(getSetType(), type.getElementType().asSymbol(vf, store, grammar, done)); - } - - @Override - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, - Set done) { - type.getElementType().asProductions(vf, store, grammar, done); - } - } - - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public Type getElementType() { - return fEltType; - } - - @Override - public boolean hasFieldNames() { - return fEltType.hasFieldNames(); - } - - @Override - public boolean hasField(String fieldName) { - return fEltType.hasField(fieldName); - } - - @Override - public boolean isSet() { - return true; - } - - @Override - public boolean isRelation() { - return fEltType.isTuple() || fEltType.isBottom(); - } - - @Override - public int getFieldIndex(String fieldName) { - return fEltType.getFieldIndex(fieldName); - } - - @Override - public Type getFieldType(int i) { - return fEltType.getFieldType(i); - } - - @Override - public String getFieldName(int i) { - return fEltType.getFieldName(i); - } - - @Override - public String[] getFieldNames() { - return fEltType.getFieldNames(); - } - - @Override - public Type getFieldType(String fieldName) throws FactTypeUseException { - return fEltType.getFieldType(fieldName); - } - - @Override - public Type getFieldTypes() { - return fEltType.getFieldTypes(); - } - - @Override - public int getArity() { - return fEltType.getArity(); - } - - @Override - public Type carrier() { - return fEltType.carrier(); - } - - @Override - public Type closure() { - return TF.setType(fEltType.closure()); - } - - @Override - public Type compose(Type other) { - return TF.setType(fEltType.compose(other.getElementType())); - } - - @Override - public Type select(int... fields) { - return TF.setType(fEltType.select(fields)); - } - - @Override - public Type select(String... names) { - return TF.setType(fEltType.select(names)); - } - - - @Override - public int hashCode() { - return 56509 + 3511 * fEltType.hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (!(obj instanceof SetType)) { - return false; - } - SetType other = (SetType) obj; - // N.B.: The element type must have been created and canonicalized before - // any - // attempt to manipulate the outer type (i.e. SetType), so we can use object - // identity here for the fEltType. - return fEltType == other.fEltType; -} + return vf.constructor(getSetType(), type.getElementType().asSymbol(vf, store, grammar, done)); + } - @Override - public String toString() { - if (fEltType.isFixedWidth() && !fEltType.equivalent(VoidType.getInstance())) { - StringBuilder sb = new StringBuilder(); - sb.append("rel["); - int idx = 0; - Iterator iter = fEltType.iterator(); - while(iter.hasNext()) { - Type elemType = iter.next(); - if (idx++ > 0) - sb.append(","); - sb.append(elemType.toString()); - if (hasFieldNames()) { - sb.append(" " + fEltType.getFieldName(idx - 1)); - } - } - sb.append("]"); - return sb.toString(); - } - else { - return "set[" + fEltType + "]"; - } - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitSet(this); - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfSet(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithSet(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithSet(this); - } - - @Override - protected Type glbWithSet(Type type) { - return this == type ? this : TF.setType(fEltType.glb(type.getElementType())); - } - - @Override - protected boolean isSubtypeOfSet(Type type) { - return fEltType.isSubtypeOf(type.getElementType()); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithSet(this); - } - - @Override - protected boolean intersectsWithSet(Type type) { - // there is always the empty set - return true; - } - - @Override - protected Type lubWithSet(Type type) { - return TF.setType(fEltType.lub(type.getElementType())); - } - - @Override - public boolean isOpen() { - return fEltType.isOpen(); - } - - @Override - public boolean match(Type matched, Map bindings) throws FactTypeUseException { - if (!super.match(matched, bindings)) { - return false; - } - else if (matched.isSet() || (matched.isAliased() && matched.getAliased().isSet()) || matched.isBottom()) { - return getElementType().match(matched.getElementType(), bindings); - } - - return true; - } - - @Override - public Type instantiate(Map bindings) { - return TypeFactory.getInstance().setType(getElementType().instantiate(bindings)); - } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - ISetWriter result = vf.setWriter(); + @Override + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, + Set done) { + type.getElementType().asProductions(vf, store, grammar, done); + } + } + + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public Type getElementType() { + return fEltType; + } + + @Override + public boolean hasFieldNames() { + return fEltType.hasFieldNames(); + } + + @Override + public boolean hasField(String fieldName) { + return fEltType.hasField(fieldName); + } + + @Override + public boolean isSet() { + return true; + } + + @Override + public boolean isRelation() { + return fEltType.isTuple() || fEltType.isBottom(); + } + + @Override + public int getFieldIndex(String fieldName) { + return fEltType.getFieldIndex(fieldName); + } + + @Override + public Type getFieldType(int i) { + return fEltType.getFieldType(i); + } + + @Override + public String getFieldName(int i) { + return fEltType.getFieldName(i); + } + + @Override + public String[] getFieldNames() { + return fEltType.getFieldNames(); + } + + @Override + public Type getFieldType(String fieldName) throws FactTypeUseException { + return fEltType.getFieldType(fieldName); + } + + @Override + public Type getFieldTypes() { + return fEltType.getFieldTypes(); + } + + @Override + public int getArity() { + return fEltType.getArity(); + } + + @Override + public Type carrier() { + return fEltType.carrier(); + } + + @Override + public Type closure() { + return TF.setType(fEltType.closure()); + } + + @Override + public Type compose(Type other) { + return TF.setType(fEltType.compose(other.getElementType())); + } + + @Override + public Type select(int... fields) { + return TF.setType(fEltType.select(fields)); + } + + @Override + public Type select(String... names) { + return TF.setType(fEltType.select(names)); + } + + + @Override + public int hashCode() { + return 56509 + 3511 * fEltType.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof SetType)) { + return false; + } + SetType other = (SetType) obj; + // N.B.: The element type must have been created and canonicalized before + // any + // attempt to manipulate the outer type (i.e. SetType), so we can use object + // identity here for the fEltType. + return fEltType == other.fEltType; + } + + @Override + public String toString() { + if (fEltType.isFixedWidth() && !fEltType.equivalent(VoidType.getInstance())) { + StringBuilder sb = new StringBuilder(); + sb.append("rel["); + int idx = 0; + Iterator iter = fEltType.iterator(); + while(iter.hasNext()) { + Type elemType = iter.next(); + if (idx++ > 0) + sb.append(","); + sb.append(elemType.toString()); + if (hasFieldNames()) { + sb.append(" " + fEltType.getFieldName(idx - 1)); + } + } + sb.append("]"); + return sb.toString(); + } + else { + return "set[" + fEltType + "]"; + } + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitSet(this); + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfSet(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithSet(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithSet(this); + } + + @Override + protected Type glbWithSet(Type type) { + return this == type ? this : TF.setType(fEltType.glb(type.getElementType())); + } + + @Override + protected boolean isSubtypeOfSet(Type type) { + return fEltType.isSubtypeOf(type.getElementType()); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithSet(this); + } + + @Override + protected boolean intersectsWithSet(Type type) { + // there is always the empty set + return true; + } + + @Override + protected Type lubWithSet(Type type) { + return TF.setType(fEltType.lub(type.getElementType())); + } + + @Override + public boolean isOpen() { + return fEltType.isOpen(); + } + + @Override + public boolean match(Type matched, Map bindings) throws FactTypeUseException { + if (!super.match(matched, bindings)) { + return false; + } + else if (matched.isSet() || (matched.isAliased() && matched.getAliased().isSet()) || matched.isBottom()) { + return getElementType().match(matched.getElementType(), bindings); + } + + return true; + } + + @Override + public Type instantiate(Map bindings) { + return TypeFactory.getInstance().setType(getElementType().instantiate(bindings)); + } + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + ISetWriter result = vf.setWriter(); if (maxDepth > 0 && random.nextBoolean()) { int size = Math.min(maxWidth, 1 + random.nextInt(maxDepth)); - + if (!getElementType().isBottom()) { for (int i =0; i < size; i++) { result.insert(getElementType().randomValue(random, vf, store, typeParameters, maxDepth, maxWidth)); } } } - + ISet done = result.done(); match(done.getType(), typeParameters); return done; - } + } } diff --git a/src/main/java/io/usethesource/vallang/type/SourceLocationType.java b/src/main/java/io/usethesource/vallang/type/SourceLocationType.java index 9e1493578..aad489770 100644 --- a/src/main/java/io/usethesource/vallang/type/SourceLocationType.java +++ b/src/main/java/io/usethesource/vallang/type/SourceLocationType.java @@ -31,8 +31,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class SourceLocationType extends DefaultSubtypeOfValue { - private static final class InstanceKeeper { - public final static SourceLocationType sInstance= new SourceLocationType(); + private static final class InstanceKeeper { + public final static SourceLocationType sInstance= new SourceLocationType(); } public static SourceLocationType getInstance() { @@ -41,39 +41,39 @@ public static SourceLocationType getInstance() { public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { + public Info(TypeValues symbols) { super(symbols); } @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("loc"); - } + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("loc"); + } - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override + return getInstance(); + } + + @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { return tf().sourceLocationType(); } - } - + } + @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + /** * Should never need to be called; there should be only one instance of IntegerType */ @Override public boolean equals(@Nullable Object obj) { - return obj == SourceLocationType.getInstance(); -} + return obj == SourceLocationType.getInstance(); + } @Override public int hashCode() { @@ -84,52 +84,52 @@ public int hashCode() { public String toString() { return "loc"; } - + @Override public T accept(ITypeVisitor visitor) throws E { - return visitor.visitSourceLocation(this); + return visitor.visitSourceLocation(this); } @Override protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfSourceLocation(this); + return type.isSubtypeOfSourceLocation(this); } - + @Override public Type lub(Type other) { - return other.lubWithSourceLocation(this); + return other.lubWithSourceLocation(this); } - + @Override public boolean intersects(Type other) { return other.intersectsWithSourceLocation(this); } - + @Override protected boolean intersectsWithSourceLocation(Type type) { return true; } - + @Override public Type glb(Type type) { - return type.glbWithSourceLocation(this); + return type.glbWithSourceLocation(this); } - + @Override protected boolean isSubtypeOfSourceLocation(Type type) { - return true; + return true; } - + @Override protected Type lubWithSourceLocation(Type type) { - return this; + return this; } - + @Override protected Type glbWithSourceLocation(Type type) { - return this; + return this; } - + @Override public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth) { @@ -194,7 +194,7 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< } } } - + @Override public boolean isSourceLocation() { return true; diff --git a/src/main/java/io/usethesource/vallang/type/StringType.java b/src/main/java/io/usethesource/vallang/type/StringType.java index 1524315e0..be82d9976 100644 --- a/src/main/java/io/usethesource/vallang/type/StringType.java +++ b/src/main/java/io/usethesource/vallang/type/StringType.java @@ -27,8 +27,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; /*package*/ final class StringType extends DefaultSubtypeOfValue { - private static final class InstanceKeeper { - private final static StringType sInstance= new StringType(); + private static final class InstanceKeeper { + private final static StringType sInstance= new StringType(); } public static StringType getInstance() { @@ -37,39 +37,39 @@ public static StringType getInstance() { public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } + public Info(TypeValues symbols) { + super(symbols); + } - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("str"); - } + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("str"); + } - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override + return getInstance(); + } + + @Override public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { return tf().stringType(); } - } - + } + @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + /** * Should never need to be called; there should be only one instance of IntegerType */ @Override public boolean equals(@Nullable Object obj) { - return obj == StringType.getInstance(); -} + return obj == StringType.getInstance(); + } @Override public int hashCode() { @@ -80,62 +80,62 @@ public int hashCode() { public String toString() { return "str"; } - + @Override public T accept(ITypeVisitor visitor) throws E { - return visitor.visitString(this); + return visitor.visitString(this); } - + @Override protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfString(this); + return type.isSubtypeOfString(this); } - + @Override public Type lub(Type other) { - return other.lubWithString(this); + return other.lubWithString(this); } - + @Override public Type glb(Type type) { - return type.glbWithString(this); + return type.glbWithString(this); } - + @Override public boolean intersects(Type other) { return other.intersectsWithString(this); } - + @Override protected boolean intersectsWithString(Type type) { return true; } - + @Override protected boolean isSubtypeOfString(Type type) { - return true; + return true; } - + @Override protected Type lubWithString(Type type) { - return this; + return this; } - + @Override protected Type glbWithString(Type type) { - return this; + return this; } - + @Override public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth) { if (random.nextBoolean() || maxDepth <= 0) { return vf.string(""); } - + return vf.string(RandomUtil.string(random, 1 + random.nextInt(maxDepth + 3))); } - + @Override public boolean isString() { return true; diff --git a/src/main/java/io/usethesource/vallang/type/TupleType.java b/src/main/java/io/usethesource/vallang/type/TupleType.java index b0a46a8a0..b7759b973 100644 --- a/src/main/java/io/usethesource/vallang/type/TupleType.java +++ b/src/main/java/io/usethesource/vallang/type/TupleType.java @@ -178,7 +178,7 @@ public String[] getFieldNames() { public Type closure() { if (getArity() == 2) { Type lub = fFieldTypes[0].lub(fFieldTypes[1]); - return TF.tupleType(lub, lub); + return TF.tupleType(lub, lub); } return super.closure(); } @@ -186,7 +186,7 @@ public Type closure() { /** * Compute a new tupletype that is the lub of t1 and t2. Precondition: t1 * and t2 have the same arity. - * + * * @param t1 * @param t2 * @return a TupleType which is the lub of t1 and t2 @@ -205,7 +205,7 @@ static Type lubTupleTypes(Type t1, Type t2) { /** * Compute a new tupletype that is the glb of t1 and t2. Precondition: t1 * and t2 have the same arity. - * + * * @param t1 * @param t2 * @return a TupleType which is the glb of t1 and t2 @@ -220,12 +220,12 @@ static Type glbTupleTypes(Type t1, Type t2) { return TypeFactory.getInstance().tupleType(fieldTypes); } - + @Override public boolean hasFieldNames() { return false; } - + @Override public boolean hasField(String fieldName) { return false; @@ -249,11 +249,11 @@ public boolean equals(@Nullable Object obj) { if (obj == null) { return false; } - + if (obj == this) { return true; } - + if (!obj.getClass().equals(getClass())) { return false; } @@ -330,26 +330,26 @@ public Type lub(Type other) { public Type glb(Type type) { return type.glbWithTuple(this); } - + @Override public boolean intersects(Type other) { return other.intersectsWithTuple(this); } - + @Override protected boolean intersectsWithTuple(Type type) { int N = this.getArity(); - + if (N != type.getArity()) { return false; } - + for (int i = 0; i < N; i++) { if (!this.getFieldType(i).intersects(type.getFieldType(i))) { return false; } } - + return true; } @@ -367,10 +367,10 @@ protected boolean isSubtypeOfTuple(Type type) { return false; } - + @Override protected boolean isSubtypeOfVoid(Type type) { - // this can happen if one of the elements is a type parameter which + // this can happen if one of the elements is a type parameter which // might degenerate to void. if (isOpen()) { for (Type elem : this) { @@ -457,22 +457,22 @@ public Type select(int... fields) { return TypeFactory.getInstance().tupleType(fieldTypes); } } - + @Override public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth) { IValue[] elems = new IValue[getArity()]; - + for (int i = 0; i < elems.length; i++) { assert !getFieldType(i).isBottom() : "field " + i + " has illegal type void"; elems[i] = getFieldType(i).randomValue(random, vf, store, typeParameters, maxDepth - 1, maxWidth); } - + ITuple done = vf.tuple(elems); match(done.getType(), typeParameters); - + return done; } - + @Override public boolean isTuple() { return true; diff --git a/src/main/java/io/usethesource/vallang/type/TupleTypeWithFieldNames.java b/src/main/java/io/usethesource/vallang/type/TupleTypeWithFieldNames.java index 329c31dda..e04e98d63 100644 --- a/src/main/java/io/usethesource/vallang/type/TupleTypeWithFieldNames.java +++ b/src/main/java/io/usethesource/vallang/type/TupleTypeWithFieldNames.java @@ -26,7 +26,7 @@ final String[] fFieldNames; /** - * Creates a tuple type with the given field types and names. + * Creates a tuple type with the given field types and names. * Does not copy the arrays. */ /*package*/ TupleTypeWithFieldNames(Type[] fieldTypes, String[] fieldNames) { @@ -113,7 +113,7 @@ public Type compose(Type other) { /** * Compute a new tupleType that is the lub of t1 and t2. Precondition: t1 * and t2 have the same arity. - * + * * @param t1 * @param t2 * @return a TupleType which is the lub of t1 and t2, if all the names are @@ -160,7 +160,7 @@ private static Type lubNamedTupleTypes(Type t1, Type t2) { /** * Compute a new tupletype that is the glb of t1 and t2. Precondition: t1 * and t2 have the same arity. - * + * * @param t1 * @param t2 * @return a TupleType which is the glb of t1 and t2, if all the names are @@ -218,7 +218,7 @@ public boolean equals(@Nullable Object obj) { if (obj == null) { return false; } - + if (!obj.getClass().equals(getClass())) { return false; } @@ -237,14 +237,14 @@ public boolean equals(@Nullable Object obj) { if (fFieldTypes[i] != other.fFieldTypes[i]) { return false; } - + if (!fFieldNames[i].equals(other.fFieldNames[i])) { return false; } } return true; -} + } @Override public String toString() { @@ -275,7 +275,7 @@ protected Type lubWithTuple(Type type) { return TF.valueType(); } - + @Override protected Type glbWithTuple(Type type) { if (getArity() == type.getArity()) { diff --git a/src/main/java/io/usethesource/vallang/type/Type.java b/src/main/java/io/usethesource/vallang/type/Type.java index b80148560..ca55ab52a 100644 --- a/src/main/java/io/usethesource/vallang/type/Type.java +++ b/src/main/java/io/usethesource/vallang/type/Type.java @@ -31,784 +31,784 @@ import io.usethesource.vallang.type.TypeFactory.TypeValues; /** - * This class is the abstract implementation for all types. Types are ordered in - * a partially ordered type hierarchy with 'value' as the largest type and - * 'void' as the smallest. Each type represents a set of values. - *

- * Users of this API will generally use the interface of @{link Type} and - * {@link TypeFactory}, the other classes in this package are not part of the - * interface. To construct {@link IValue}'s, use the 'make' methods of - * - * @{link Type}. - *

- * Technical detail: since void is a sub-type of all types and alias - * types may be sub-types of any types, a Java encoding of the hierarchy - * using single inheritance will not work. Therefore, all methods of all - * types are present on this abstract class Type. void and alias type - * implement all methods, while the other methods implement only the - * relevant methods. Calling a method that is not present on any of the - * specific types will lead to a @{link FactTypeError} exception. - */ +* This class is the abstract implementation for all types. Types are ordered in +* a partially ordered type hierarchy with 'value' as the largest type and +* 'void' as the smallest. Each type represents a set of values. +*

+* Users of this API will generally use the interface of @{link Type} and +* {@link TypeFactory}, the other classes in this package are not part of the +* interface. To construct {@link IValue}'s, use the 'make' methods of +* +* @{link Type}. +*

+* Technical detail: since void is a sub-type of all types and alias +* types may be sub-types of any types, a Java encoding of the hierarchy +* using single inheritance will not work. Therefore, all methods of all +* types are present on this abstract class Type. void and alias type +* implement all methods, while the other methods implement only the +* relevant methods. Calling a method that is not present on any of the +* specific types will lead to a @{link FactTypeError} exception. +*/ public abstract class Type implements Iterable, Comparable { - protected static final TypeFactory TF = TypeFactory.getInstance(); - - protected abstract TypeFactory.TypeReifier getTypeReifier(TypeValues values); - - /** - * Retrieve the type of elements in a set or a relation. - * - * @return type of elements - */ - public Type getElementType() { - throw new IllegalOperationException("getElementType", this); - } - - /** - * Retrieve the key type of a map - * - * @return key type - */ - public Type getKeyType() { - throw new IllegalOperationException("getKeyType", this); - } - - /** - * Retrieve the value type of a map - * - * @return value type - */ - public Type getValueType() { - throw new IllegalOperationException("getValueType", this); - } - - /** - * Retrieve the name of a named type, a tree node type or a parameter type. - * - * @return name of the type - */ - public String getName() { - throw new IllegalOperationException("getName", this); - } - - /** - * Retrieve the type of a field of a tuple type, a relation type or a tree - * node type. - * - * @param i - * index of the field to retrieve - * @return type of the field at index i - */ - public Type getFieldType(int i) { - throw new IllegalOperationException("getFieldType", this); - } - - /** - * Retrieve the type of a field of a tuple type, a relation type or a tree - * node type. - *

- * - * @param fieldName - * label of the field to retrieve - * @return type of the field at index i - * @throws FactTypeUseException - * when the type has no field labels (tuples and relations - * optionally have field labels). - */ - public Type getFieldType(String fieldName) throws FactTypeUseException { - throw new IllegalOperationException("getFieldType", this); - } - - /** - * Retrieve the field types of a tree node type or a relation, represented as - * a tuple type. - * - * @return a tuple type representing the field types - */ - public Type getFieldTypes() { - throw new IllegalOperationException("getFieldTypes", this); - } - - /** - * Get the return type of a function type - */ - public Type getReturnType() { - throw new IllegalOperationException("getReturnType", this); - } - - /** - * Get the keyword parameter types of a function type - */ - public Type getKeywordParameterTypes() { - throw new IllegalOperationException("getKeywordParameterTypes", this); - } - - /** - * Retrieve the field name at a certain index for a tuple type, a relation - * type or a tree node type. - * - * @param i - * index of the field name to retrieve - * @return the field name at index i - * @throws FactTypeUseException - * when this type does not have field labels. Tuples and relations - * optionally have field labels. - */ - public String getFieldName(int i) { - throw new IllegalOperationException("getFieldName", this); - } - - /** - * Retrieve the field name at a certain index for a tuple type, a relation - * type or a tree node type. - * - * @param i index of the field name to retrieve - * @return the field name at the given index, optionally. - */ - public Optional getOptionalFieldName(int i) { - if (hasFieldNames()) { - return Optional.of(Objects.requireNonNull(getFieldName(i))); - } else { - return Optional.empty(); - } - } - - /** - * Retrieve all the field names of tuple type, a relation type or a tree node - * type. - * - * @return the field name at index i - * @throws FactTypeUseException - * when this type does not have field labels. Tuples and relations - * optionally have field labels. - */ - @Pure - public String[] getFieldNames() { - throw new IllegalOperationException("getFieldNames", this); - } - - /** - * Retrieve a field index for a certain label for a tuple type, a relation - * type or a tree node type. - * - * @param fieldName - * name of the field to retrieve - * @return the index of fieldName - */ - public int getFieldIndex(String fieldName) { - throw new IllegalOperationException("getFieldIndex", this); - } - - /** - * @param fieldName - * name of the field to check for - * @return true iff this type has a field named fieldName - */ - public boolean hasField(String fieldName) { - throw new IllegalOperationException("hasField", this); - } - - /** - * @param fieldName - * name of the field to check for - * @return true iff this type has a field named fieldName - */ - public boolean hasField(String fieldName, TypeStore store) { - return hasField(fieldName); - } - - /** - * @param fieldName - * name of the keyword field to check for - * @return true iff this type has a keyword field named fieldName - */ - public boolean hasKeywordField(String fieldName, TypeStore store) { - throw new IllegalOperationException("hasKeywordField", this); - } - - /** - * Retrieve the width, a.k.a. arity, of a tuple, a relation or a tree node - * type. - * - * @return the arity - */ - public int getArity() { - throw new IllegalOperationException("getArity", this); - } - - /** - * Represent this type as a value of the abstract data-type "Symbol". As a side-effect - * it will also add Production values to the grammar map, including all necessary productions - * to build values of the receiver type, transitively. - * - * @param vf valuefactory to use - * @param store store to lookup additional necessary definitions in to store in the grammar - * @param grammar map to store production values in as a side-effect - * @param done a working set to store data-types which have been explored already to avoid infinite recursion - * @return a value to uniquely represent this type. - */ - public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - return getTypeReifier(TF.cachedTypeValues()).toSymbol(this, vf, store, grammar, done); - } - - /** - * Map the given typestore to a set of production values, with only definitions - * reachable from the receiver type - * - * @param vf valuefactory to use - * @param store typestore which contains source definitions - * @param done a working set to store data-types which have been explored already to avoid infinite recursion - */ - public void asProductions(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - getTypeReifier(TF.cachedTypeValues()).asProductions(this, vf, store, grammar, done); - } - - - /** - * Compose two binary tuples or binary relation types. - * - * @param other - * @return a new type that represent the composition - * @throws IllegalOperationException - * if the receiver or the other is not binary or if the last type of - * the receiver is not comparable to the first type of the other. - */ - public Type compose(Type other) { - throw new IllegalOperationException("compose", this, other); - } - - /** - * For relation types rel[t_1,t_2] this will compute rel[t_3,t_3] where t_3 = - * t_1.lub(t_2). - * - * @return rel[t_3,t_3] - * @throws IllegalOperationException - * when this is not a binary relation or t_1 is not comparable to - * t_2 (i.e. the relation is not reflexive) - */ - public Type closure() { - throw new IllegalOperationException("closure", this); - } - - /** - * Computes the least upper bound of all elements of this type and returns a - * set of this type. Works on all types that have elements/fields or children - * such as tuples, relations, sets and constructors. - * - * @return a set[lub]. - */ - public Type carrier() { - throw new IllegalOperationException("carrier", this); - } - - /** - * Iterate over fields of the type - */ - public Iterator iterator() { - throw new IllegalOperationException("iterator", this); - } - - /** - * Select fields from tuples and relation - * - * @param fields - * @return a new tuple or relation type with the selected fields - */ - public Type select(int... fields) { - throw new IllegalOperationException("select", this); - - } - - /** - * Select fields from tuples and relation - * - * @param fields - * @return a new tuple or relation type with the selected fields - */ - public Type select(String... names) { - throw new IllegalOperationException("select", this); - } - - /** - * For a constructor, return the algebraic data-type it constructs - * - * @return a type - */ - public Type getAbstractDataType() { - throw new IllegalOperationException("getAbstractDataType", this); - } - - /** - * For an alias type, return which type it aliases. - * - * @return a type - */ - public Type getAliased() { - throw new IllegalOperationException("getAliased", this); - } - - /** - * For a parameter type, return its bound - * - * @return a type - */ - public Type getBound() { - throw new IllegalOperationException("getBound", this); - } - - /** - * For a tuple type or a relation type, determine whether the fields are - * labelled or not. - * - * @return if the fields of a type or relation have been labelled - */ - @Pure - public boolean hasFieldNames() { - return false; - } - - /** - * For function types, return whether or not it has - * keyword parameters - */ - @Pure - public boolean hasKeywordParameters() { - return false; - } - - public @Nullable Type getKeywordParameterType(String label) { - throw new IllegalOperationException("getKeywordParameterType", this); - } - - public boolean hasKeywordParameter(String label) { - throw new IllegalOperationException("hasKeywordParameter", this); - } - - public String getKeyLabel() { - throw new IllegalOperationException("getKeyLabel", this); - } - - public String getValueLabel() { - throw new IllegalOperationException("getValueLabel", this); - } - - /** - * Returns the smallest non-strict supertype of two types, which contains all values of - * the receiver as well as the argument type. Lub can be seen as `type union`, but - * not all unions have a representation in the type lattice; so the smallest set which - * contains the whole union must be returned (which does have a representation). - * - * Consider for example `int.lub(str)`; the smallest union that contains both in - * the vallang type lattica is `value`, even though we by-catch all other values now - * as well. Other lubs are more tight: `tuple[int,num].lub(tuple[num,int]])` is - * `tuple[num,num]`. - * - * @return the least upper bound type of the receiver and the argument type. - */ - public abstract Type lub(Type type); - - /** - * Returns the largest non-strict sub-type of two types which contains the intersection - * of both types. Glb is the dual of `lub`. Glb can be seen as "type intersection", but - * not all intersections have a representation in the vallang type lattice; so the largest - * set which contains the intersection must be returned (which does have a representation) - * - * The glb is commonly `void` for non-comparable types, say for example - * @param type - * @return - */ - public abstract Type glb(Type type); - - /** - * The sub-type relation. Value is the biggest type and void is the smallest. - * Value is the top and void is the bottom of the type hierarchy. - * - * @param other - * @return true if the receiver is a subtype of the other type - */ - public final boolean isSubtypeOf(Type other) { - return other == this || other.isSupertypeOf(this); - } - - public final boolean isStrictSubtypeOf(Type other) { - return (!other.equivalent(this)) && other.isSupertypeOf(this); - } - - protected abstract boolean isSupertypeOf(Type type); - - /** - * Return whether an ADT or an alias Type has any type parameters - * - * @return true if the type is parameterized - */ - public boolean isParameterized() { - return false; - } - - /** - * @return true iff the type contains any uninstantiated type parameters - */ - public boolean isOpen() { - return false; - } - - /** - * @return true iff the type is an alias - */ - public boolean isAliased() { - return false; - } - - public boolean isSet() { - return false; - } - - public boolean isList() { - return false; - } - - public boolean isMap() { - return false; - } - - public boolean isBool() { - return false; - } - - public boolean isRelation() { - return false; - } - - public boolean isListRelation() { - return false; - } - - public boolean isInteger() { - return false; - } - - public boolean isReal() { - return false; - } - - public boolean isRational() { - return false; - } - - public boolean isNumber() { - return false; - } - - public boolean isTop() { - return false; - } - - public boolean isBottom() { - return false; - } - - public boolean isParameter() { - return false; - } - - public boolean isNode() { - return false; - } - - public boolean isAbstractData() { - return false; - } - - public boolean isConstructor() { - return false; - } - - public boolean isString() { - return false; - } - - public boolean isSourceLocation() { - return false; - } - - public boolean isDateTime() { - return false; - } - - public boolean isTuple() { - return false; - } - - public boolean isFunction() { - return false; - } - - public boolean isExternalType() { - return false; - } - - /** - * @return true iff type is a tuple - */ - public boolean isFixedWidth() { - return false; - } - - /** - * Compute whether this type is a subtype of the other or vice versa. - * - * @param other - * type to compare to - * @return true if the types are comparable. - */ - public final boolean comparable(Type other) { - return (other == this) || isSubtypeOf(other) || other.isSubtypeOf(this); - } - - /** - * Compute whether these types have a non-empty intersection. - * - * All types which are `comparable` have a non-empty intersection, - * but there are some more. For example `tuple[int, value]` and - * `tuple[value,int]` intersect at `tuple[int, int]`. - * - * If the `glb` of two types is not `void` then they have a non-empty - * intersection. - * - * Another example is `lrel[int, int]` and `list[tuple[int,int]]`; - * their `glb` is `list[void]` and its only element is `[]` - * -the empty list- so indeed their intersection is non-empty. - * - * Another way of explaining `t.intersects(u)` is as a fast check of: - * `t.glb(u) != void` without memory allocation. - * - * @param other type to intersect with. - * @return true iff these two types share values. - */ - public abstract boolean intersects(Type other); - - /** - * Computer whether this type is equivalent to another. - * - * @param other - * type to compare to - * @return true if the two types are sub-types of each-other; - */ - public final boolean equivalent(Type other) { - return (other == this) || (isSubtypeOf(other) && other.isSubtypeOf(this)); - } - - /** - * If this type has parameters and there are parameter types embedded in it, - * instantiate will replace the parameter types using the given bindings. - * - * @param bindings - * a map from parameter type names to actual types. - * @return a type with all parameter types substituted. - */ - public Type instantiate(Map bindings) { - return this; - } - - /** - * Construct a map of parameter type names to actual type names. The receiver - * is a pattern that may contain parameter types. - * - * @param matched - * a type to matched to the receiver. - * @throws FactTypeUseException - * when a pattern can not be matched because the matched types do - * not fit the bounds of the parameter types, or when a pattern - * simply can not be matched because of incompatibility. - */ - public boolean match(Type matched, Map bindings) throws FactTypeUseException { - return matched.isSubtypeOf(this); - } - - public abstract T accept(ITypeVisitor visitor) throws E; - - /** - * For alias types and adt types return which type parameters there are. - * - * @return void if there are no type parameters, or a tuple of type parameters - * otherwise. - */ - public Type getTypeParameters() { - throw new IllegalOperationException("getTypeParameters", this); - } - - /** - * Compare against another type. - * - * A type is 'less' than another if it is a subtype, 'greater' if the other is - * a subtype, or 'equal' if both are subtypes of each other. - * - * Note: this class has a natural ordering that is inconsistent with equals. - * equals() on types is exact equality, which may be different from - * compareTo(o) == 0 - * - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - public int compareTo(Type o) { - if (isSubtypeOf(o)) { - return -1; - } else if (o.isSubtypeOf(this)) { - return 1; - } - return 0; - } - - protected boolean isSubtypeOfParameter(Type type) { - return isSubtypeOf(type.getBound()); - } - - protected final boolean isSubtypeOfAlias(Type type) { - return isSubtypeOf(type.getAliased()); - } - - /** - * Instantiate a tuple but do not reduce to void like TupleType.instantiate would - * if one of the parameters was substituted by void. This is needed for other types - * which use TupleType as an array of Types (i.e. for type parameters, fields and keyword fields) - */ - protected Type instantiateTuple(TupleType t, Map bindings) { - Type[] fChildren = new Type[t.getArity()]; - for (int i = t.fFieldTypes.length - 1; i >= 0; i--) { - fChildren[i] = t.getFieldType(i).instantiate(bindings); - } - - return TypeFactory.getInstance().getFromCache(new TupleType(fChildren)); - } - - abstract protected boolean isSubtypeOfReal(Type type); - abstract protected boolean isSubtypeOfInteger(Type type); - abstract protected boolean isSubtypeOfRational(Type type); - abstract protected boolean isSubtypeOfList(Type type); - abstract protected boolean isSubtypeOfMap(Type type); - abstract protected boolean isSubtypeOfNumber(Type type); - abstract protected boolean isSubtypeOfSet(Type type); - abstract protected boolean isSubtypeOfSourceLocation(Type type); - abstract protected boolean isSubtypeOfString(Type type); - abstract protected boolean isSubtypeOfNode(Type type); - abstract protected boolean isSubtypeOfConstructor(Type type); - abstract protected boolean isSubtypeOfAbstractData(Type type); - abstract protected boolean isSubtypeOfTuple(Type type); - abstract protected boolean isSubtypeOfFunction(Type type); - abstract protected boolean isSubtypeOfValue(Type type); - abstract protected boolean isSubtypeOfVoid(Type type); - abstract protected boolean isSubtypeOfBool(Type type); - abstract protected boolean isSubtypeOfExternal(Type type); - abstract protected boolean isSubtypeOfDateTime(Type type); - - abstract protected boolean intersectsWithReal(Type type); - abstract protected boolean intersectsWithInteger(Type type); - abstract protected boolean intersectsWithRational(Type type); - abstract protected boolean intersectsWithList(Type type); - abstract protected boolean intersectsWithMap(Type type); - abstract protected boolean intersectsWithNumber(Type type); - abstract protected boolean intersectsWithSet(Type type); - abstract protected boolean intersectsWithSourceLocation(Type type); - abstract protected boolean intersectsWithString(Type type); - abstract protected boolean intersectsWithNode(Type type); - abstract protected boolean intersectsWithConstructor(Type type); - abstract protected boolean intersectsWithAbstractData(Type type); - abstract protected boolean intersectsWithTuple(Type type); - abstract protected boolean intersectsWithFunction(Type type); - abstract protected boolean intersectsWithValue(Type type); - abstract protected boolean intersectsWithVoid(Type type); - abstract protected boolean intersectsWithBool(Type type); - protected boolean intersectsWithExternal(Type type) { - // delegate to the external type always - return type.intersects(this); - } - abstract protected boolean intersectsWithDateTime(Type type); - - protected Type lubWithAlias(Type type) { - return lub(type.getAliased()); - } - - protected Type lubWithParameter(Type type) { - if (type == this) { - return this; - } - - return lub(type.getBound()); - } - - abstract protected Type lubWithReal(Type type) ; - abstract protected Type lubWithInteger(Type type) ; - abstract protected Type lubWithRational(Type type) ; - abstract protected Type lubWithList(Type type) ; - abstract protected Type lubWithMap(Type type) ; - abstract protected Type lubWithNumber(Type type) ; - abstract protected Type lubWithSet(Type type) ; - abstract protected Type lubWithSourceLocation(Type type) ; - abstract protected Type lubWithString(Type type) ; - abstract protected Type lubWithNode(Type type) ; - abstract protected Type lubWithConstructor(Type type) ; - abstract protected Type lubWithAbstractData(Type type) ; - abstract protected Type lubWithTuple(Type type) ; - abstract protected Type lubWithFunction(Type type) ; - abstract protected Type lubWithValue(Type type) ; - abstract protected Type lubWithVoid(Type type) ; - abstract protected Type lubWithBool(Type type) ; - abstract protected Type lubWithDateTime(Type type) ; - - protected Type glbWithAlias(Type type) { - return glb(type.getAliased()); - } - - protected Type glbWithParameter(Type type) { - if (type == this) { - return this; - } - - return glb(type.getBound()); - } - - abstract protected Type glbWithReal(Type type) ; - abstract protected Type glbWithInteger(Type type) ; - abstract protected Type glbWithRational(Type type) ; - abstract protected Type glbWithList(Type type) ; - abstract protected Type glbWithMap(Type type) ; - abstract protected Type glbWithNumber(Type type) ; - abstract protected Type glbWithSet(Type type) ; - abstract protected Type glbWithSourceLocation(Type type) ; - abstract protected Type glbWithString(Type type) ; - abstract protected Type glbWithNode(Type type) ; - abstract protected Type glbWithConstructor(Type type) ; - abstract protected Type glbWithAbstractData(Type type) ; - abstract protected Type glbWithTuple(Type type) ; - abstract protected Type glbWithFunction(Type type) ; - abstract protected Type glbWithValue(Type type) ; - abstract protected Type glbWithVoid(Type type) ; - abstract protected Type glbWithBool(Type type) ; - abstract protected Type glbWithDateTime(Type type) ; - - /** - * This makes sure that lubbing can be done by the external type whether - * or not it is the initial receiver or the second parameter to lub. - */ - protected Type lubWithExternal(Type type) { - // the external type should be the receiver - return lub(type); - } - - protected Type glbWithExternal(Type type) { - // the external type should be the receiver - return glb(type); - } - - /** - * Generate a random value which is guaranteed to have a type that is - * a (non-strict) sub-type of the receiver. - * - * @param random pass in reused Random instance for better random uniformity between calls to this method. - * @param vf IValueFactory to use when building values - * @param store TypeStore to lookup constructors and fields in - * @param typeParameters will be filled with the inferred (least-upper-bound) type for every open type parameter as a side-effect. - * @param maxDepth how deeply to generate recursive values - * @param maxWidth how wide collections and fixed-width data-types should be (maximally) - * @return - */ - abstract public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth); -} \ No newline at end of file + protected static final TypeFactory TF = TypeFactory.getInstance(); + + protected abstract TypeFactory.TypeReifier getTypeReifier(TypeValues values); + + /** + * Retrieve the type of elements in a set or a relation. + * + * @return type of elements + */ + public Type getElementType() { + throw new IllegalOperationException("getElementType", this); + } + + /** + * Retrieve the key type of a map + * + * @return key type + */ + public Type getKeyType() { + throw new IllegalOperationException("getKeyType", this); + } + + /** + * Retrieve the value type of a map + * + * @return value type + */ + public Type getValueType() { + throw new IllegalOperationException("getValueType", this); + } + + /** + * Retrieve the name of a named type, a tree node type or a parameter type. + * + * @return name of the type + */ + public String getName() { + throw new IllegalOperationException("getName", this); + } + + /** + * Retrieve the type of a field of a tuple type, a relation type or a tree + * node type. + * + * @param i + * index of the field to retrieve + * @return type of the field at index i + */ + public Type getFieldType(int i) { + throw new IllegalOperationException("getFieldType", this); + } + + /** + * Retrieve the type of a field of a tuple type, a relation type or a tree + * node type. + *

+ * + * @param fieldName + * label of the field to retrieve + * @return type of the field at index i + * @throws FactTypeUseException + * when the type has no field labels (tuples and relations + * optionally have field labels). + */ + public Type getFieldType(String fieldName) throws FactTypeUseException { + throw new IllegalOperationException("getFieldType", this); + } + + /** + * Retrieve the field types of a tree node type or a relation, represented as + * a tuple type. + * + * @return a tuple type representing the field types + */ + public Type getFieldTypes() { + throw new IllegalOperationException("getFieldTypes", this); + } + + /** + * Get the return type of a function type + */ + public Type getReturnType() { + throw new IllegalOperationException("getReturnType", this); + } + + /** + * Get the keyword parameter types of a function type + */ + public Type getKeywordParameterTypes() { + throw new IllegalOperationException("getKeywordParameterTypes", this); + } + + /** + * Retrieve the field name at a certain index for a tuple type, a relation + * type or a tree node type. + * + * @param i + * index of the field name to retrieve + * @return the field name at index i + * @throws FactTypeUseException + * when this type does not have field labels. Tuples and relations + * optionally have field labels. + */ + public String getFieldName(int i) { + throw new IllegalOperationException("getFieldName", this); + } + + /** + * Retrieve the field name at a certain index for a tuple type, a relation + * type or a tree node type. + * + * @param i index of the field name to retrieve + * @return the field name at the given index, optionally. + */ + public Optional getOptionalFieldName(int i) { + if (hasFieldNames()) { + return Optional.of(Objects.requireNonNull(getFieldName(i))); + } else { + return Optional.empty(); + } + } + + /** + * Retrieve all the field names of tuple type, a relation type or a tree node + * type. + * + * @return the field name at index i + * @throws FactTypeUseException + * when this type does not have field labels. Tuples and relations + * optionally have field labels. + */ + @Pure + public String[] getFieldNames() { + throw new IllegalOperationException("getFieldNames", this); + } + + /** + * Retrieve a field index for a certain label for a tuple type, a relation + * type or a tree node type. + * + * @param fieldName + * name of the field to retrieve + * @return the index of fieldName + */ + public int getFieldIndex(String fieldName) { + throw new IllegalOperationException("getFieldIndex", this); + } + + /** + * @param fieldName + * name of the field to check for + * @return true iff this type has a field named fieldName + */ + public boolean hasField(String fieldName) { + throw new IllegalOperationException("hasField", this); + } + + /** + * @param fieldName + * name of the field to check for + * @return true iff this type has a field named fieldName + */ + public boolean hasField(String fieldName, TypeStore store) { + return hasField(fieldName); + } + + /** + * @param fieldName + * name of the keyword field to check for + * @return true iff this type has a keyword field named fieldName + */ + public boolean hasKeywordField(String fieldName, TypeStore store) { + throw new IllegalOperationException("hasKeywordField", this); + } + + /** + * Retrieve the width, a.k.a. arity, of a tuple, a relation or a tree node + * type. + * + * @return the arity + */ + public int getArity() { + throw new IllegalOperationException("getArity", this); + } + + /** + * Represent this type as a value of the abstract data-type "Symbol". As a side-effect + * it will also add Production values to the grammar map, including all necessary productions + * to build values of the receiver type, transitively. + * + * @param vf valuefactory to use + * @param store store to lookup additional necessary definitions in to store in the grammar + * @param grammar map to store production values in as a side-effect + * @param done a working set to store data-types which have been explored already to avoid infinite recursion + * @return a value to uniquely represent this type. + */ + public IConstructor asSymbol(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { + return getTypeReifier(TF.cachedTypeValues()).toSymbol(this, vf, store, grammar, done); + } + + /** + * Map the given typestore to a set of production values, with only definitions + * reachable from the receiver type + * + * @param vf valuefactory to use + * @param store typestore which contains source definitions + * @param done a working set to store data-types which have been explored already to avoid infinite recursion + */ + public void asProductions(IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { + getTypeReifier(TF.cachedTypeValues()).asProductions(this, vf, store, grammar, done); + } + + + /** + * Compose two binary tuples or binary relation types. + * + * @param other + * @return a new type that represent the composition + * @throws IllegalOperationException + * if the receiver or the other is not binary or if the last type of + * the receiver is not comparable to the first type of the other. + */ + public Type compose(Type other) { + throw new IllegalOperationException("compose", this, other); + } + + /** + * For relation types rel[t_1,t_2] this will compute rel[t_3,t_3] where t_3 = + * t_1.lub(t_2). + * + * @return rel[t_3,t_3] + * @throws IllegalOperationException + * when this is not a binary relation or t_1 is not comparable to + * t_2 (i.e. the relation is not reflexive) + */ + public Type closure() { + throw new IllegalOperationException("closure", this); + } + + /** + * Computes the least upper bound of all elements of this type and returns a + * set of this type. Works on all types that have elements/fields or children + * such as tuples, relations, sets and constructors. + * + * @return a set[lub]. + */ + public Type carrier() { + throw new IllegalOperationException("carrier", this); + } + + /** + * Iterate over fields of the type + */ + public Iterator iterator() { + throw new IllegalOperationException("iterator", this); + } + + /** + * Select fields from tuples and relation + * + * @param fields + * @return a new tuple or relation type with the selected fields + */ + public Type select(int... fields) { + throw new IllegalOperationException("select", this); + + } + + /** + * Select fields from tuples and relation + * + * @param fields + * @return a new tuple or relation type with the selected fields + */ + public Type select(String... names) { + throw new IllegalOperationException("select", this); + } + + /** + * For a constructor, return the algebraic data-type it constructs + * + * @return a type + */ + public Type getAbstractDataType() { + throw new IllegalOperationException("getAbstractDataType", this); + } + + /** + * For an alias type, return which type it aliases. + * + * @return a type + */ + public Type getAliased() { + throw new IllegalOperationException("getAliased", this); + } + + /** + * For a parameter type, return its bound + * + * @return a type + */ + public Type getBound() { + throw new IllegalOperationException("getBound", this); + } + + /** + * For a tuple type or a relation type, determine whether the fields are + * labelled or not. + * + * @return if the fields of a type or relation have been labelled + */ + @Pure + public boolean hasFieldNames() { + return false; + } + + /** + * For function types, return whether or not it has + * keyword parameters + */ + @Pure + public boolean hasKeywordParameters() { + return false; + } + + public @Nullable Type getKeywordParameterType(String label) { + throw new IllegalOperationException("getKeywordParameterType", this); + } + + public boolean hasKeywordParameter(String label) { + throw new IllegalOperationException("hasKeywordParameter", this); + } + + public String getKeyLabel() { + throw new IllegalOperationException("getKeyLabel", this); + } + + public String getValueLabel() { + throw new IllegalOperationException("getValueLabel", this); + } + + /** + * Returns the smallest non-strict supertype of two types, which contains all values of + * the receiver as well as the argument type. Lub can be seen as `type union`, but + * not all unions have a representation in the type lattice; so the smallest set which + * contains the whole union must be returned (which does have a representation). + * + * Consider for example `int.lub(str)`; the smallest union that contains both in + * the vallang type lattica is `value`, even though we by-catch all other values now + * as well. Other lubs are more tight: `tuple[int,num].lub(tuple[num,int]])` is + * `tuple[num,num]`. + * + * @return the least upper bound type of the receiver and the argument type. + */ + public abstract Type lub(Type type); + + /** + * Returns the largest non-strict sub-type of two types which contains the intersection + * of both types. Glb is the dual of `lub`. Glb can be seen as "type intersection", but + * not all intersections have a representation in the vallang type lattice; so the largest + * set which contains the intersection must be returned (which does have a representation) + * + * The glb is commonly `void` for non-comparable types, say for example + * @param type + * @return + */ + public abstract Type glb(Type type); + + /** + * The sub-type relation. Value is the biggest type and void is the smallest. + * Value is the top and void is the bottom of the type hierarchy. + * + * @param other + * @return true if the receiver is a subtype of the other type + */ + public final boolean isSubtypeOf(Type other) { + return other == this || other.isSupertypeOf(this); + } + + public final boolean isStrictSubtypeOf(Type other) { + return (!other.equivalent(this)) && other.isSupertypeOf(this); + } + + protected abstract boolean isSupertypeOf(Type type); + + /** + * Return whether an ADT or an alias Type has any type parameters + * + * @return true if the type is parameterized + */ + public boolean isParameterized() { + return false; + } + + /** + * @return true iff the type contains any uninstantiated type parameters + */ + public boolean isOpen() { + return false; + } + + /** + * @return true iff the type is an alias + */ + public boolean isAliased() { + return false; + } + + public boolean isSet() { + return false; + } + + public boolean isList() { + return false; + } + + public boolean isMap() { + return false; + } + + public boolean isBool() { + return false; + } + + public boolean isRelation() { + return false; + } + + public boolean isListRelation() { + return false; + } + + public boolean isInteger() { + return false; + } + + public boolean isReal() { + return false; + } + + public boolean isRational() { + return false; + } + + public boolean isNumber() { + return false; + } + + public boolean isTop() { + return false; + } + + public boolean isBottom() { + return false; + } + + public boolean isParameter() { + return false; + } + + public boolean isNode() { + return false; + } + + public boolean isAbstractData() { + return false; + } + + public boolean isConstructor() { + return false; + } + + public boolean isString() { + return false; + } + + public boolean isSourceLocation() { + return false; + } + + public boolean isDateTime() { + return false; + } + + public boolean isTuple() { + return false; + } + + public boolean isFunction() { + return false; + } + + public boolean isExternalType() { + return false; + } + + /** + * @return true iff type is a tuple + */ + public boolean isFixedWidth() { + return false; + } + + /** + * Compute whether this type is a subtype of the other or vice versa. + * + * @param other + * type to compare to + * @return true if the types are comparable. + */ + public final boolean comparable(Type other) { + return (other == this) || isSubtypeOf(other) || other.isSubtypeOf(this); + } + + /** + * Compute whether these types have a non-empty intersection. + * + * All types which are `comparable` have a non-empty intersection, + * but there are some more. For example `tuple[int, value]` and + * `tuple[value,int]` intersect at `tuple[int, int]`. + * + * If the `glb` of two types is not `void` then they have a non-empty + * intersection. + * + * Another example is `lrel[int, int]` and `list[tuple[int,int]]`; + * their `glb` is `list[void]` and its only element is `[]` + * -the empty list- so indeed their intersection is non-empty. + * + * Another way of explaining `t.intersects(u)` is as a fast check of: + * `t.glb(u) != void` without memory allocation. + * + * @param other type to intersect with. + * @return true iff these two types share values. + */ + public abstract boolean intersects(Type other); + + /** + * Computer whether this type is equivalent to another. + * + * @param other + * type to compare to + * @return true if the two types are sub-types of each-other; + */ + public final boolean equivalent(Type other) { + return (other == this) || (isSubtypeOf(other) && other.isSubtypeOf(this)); + } + + /** + * If this type has parameters and there are parameter types embedded in it, + * instantiate will replace the parameter types using the given bindings. + * + * @param bindings + * a map from parameter type names to actual types. + * @return a type with all parameter types substituted. + */ + public Type instantiate(Map bindings) { + return this; + } + + /** + * Construct a map of parameter type names to actual type names. The receiver + * is a pattern that may contain parameter types. + * + * @param matched + * a type to matched to the receiver. + * @throws FactTypeUseException + * when a pattern can not be matched because the matched types do + * not fit the bounds of the parameter types, or when a pattern + * simply can not be matched because of incompatibility. + */ + public boolean match(Type matched, Map bindings) throws FactTypeUseException { + return matched.isSubtypeOf(this); + } + + public abstract T accept(ITypeVisitor visitor) throws E; + + /** + * For alias types and adt types return which type parameters there are. + * + * @return void if there are no type parameters, or a tuple of type parameters + * otherwise. + */ + public Type getTypeParameters() { + throw new IllegalOperationException("getTypeParameters", this); + } + + /** + * Compare against another type. + * + * A type is 'less' than another if it is a subtype, 'greater' if the other is + * a subtype, or 'equal' if both are subtypes of each other. + * + * Note: this class has a natural ordering that is inconsistent with equals. + * equals() on types is exact equality, which may be different from + * compareTo(o) == 0 + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Type o) { + if (isSubtypeOf(o)) { + return -1; + } else if (o.isSubtypeOf(this)) { + return 1; + } + return 0; + } + + protected boolean isSubtypeOfParameter(Type type) { + return isSubtypeOf(type.getBound()); + } + + protected final boolean isSubtypeOfAlias(Type type) { + return isSubtypeOf(type.getAliased()); + } + + /** + * Instantiate a tuple but do not reduce to void like TupleType.instantiate would + * if one of the parameters was substituted by void. This is needed for other types + * which use TupleType as an array of Types (i.e. for type parameters, fields and keyword fields) + */ + protected Type instantiateTuple(TupleType t, Map bindings) { + Type[] fChildren = new Type[t.getArity()]; + for (int i = t.fFieldTypes.length - 1; i >= 0; i--) { + fChildren[i] = t.getFieldType(i).instantiate(bindings); + } + + return TypeFactory.getInstance().getFromCache(new TupleType(fChildren)); + } + + abstract protected boolean isSubtypeOfReal(Type type); + abstract protected boolean isSubtypeOfInteger(Type type); + abstract protected boolean isSubtypeOfRational(Type type); + abstract protected boolean isSubtypeOfList(Type type); + abstract protected boolean isSubtypeOfMap(Type type); + abstract protected boolean isSubtypeOfNumber(Type type); + abstract protected boolean isSubtypeOfSet(Type type); + abstract protected boolean isSubtypeOfSourceLocation(Type type); + abstract protected boolean isSubtypeOfString(Type type); + abstract protected boolean isSubtypeOfNode(Type type); + abstract protected boolean isSubtypeOfConstructor(Type type); + abstract protected boolean isSubtypeOfAbstractData(Type type); + abstract protected boolean isSubtypeOfTuple(Type type); + abstract protected boolean isSubtypeOfFunction(Type type); + abstract protected boolean isSubtypeOfValue(Type type); + abstract protected boolean isSubtypeOfVoid(Type type); + abstract protected boolean isSubtypeOfBool(Type type); + abstract protected boolean isSubtypeOfExternal(Type type); + abstract protected boolean isSubtypeOfDateTime(Type type); + + abstract protected boolean intersectsWithReal(Type type); + abstract protected boolean intersectsWithInteger(Type type); + abstract protected boolean intersectsWithRational(Type type); + abstract protected boolean intersectsWithList(Type type); + abstract protected boolean intersectsWithMap(Type type); + abstract protected boolean intersectsWithNumber(Type type); + abstract protected boolean intersectsWithSet(Type type); + abstract protected boolean intersectsWithSourceLocation(Type type); + abstract protected boolean intersectsWithString(Type type); + abstract protected boolean intersectsWithNode(Type type); + abstract protected boolean intersectsWithConstructor(Type type); + abstract protected boolean intersectsWithAbstractData(Type type); + abstract protected boolean intersectsWithTuple(Type type); + abstract protected boolean intersectsWithFunction(Type type); + abstract protected boolean intersectsWithValue(Type type); + abstract protected boolean intersectsWithVoid(Type type); + abstract protected boolean intersectsWithBool(Type type); + protected boolean intersectsWithExternal(Type type) { + // delegate to the external type always + return type.intersects(this); + } + abstract protected boolean intersectsWithDateTime(Type type); + + protected Type lubWithAlias(Type type) { + return lub(type.getAliased()); + } + + protected Type lubWithParameter(Type type) { + if (type == this) { + return this; + } + + return lub(type.getBound()); + } + + abstract protected Type lubWithReal(Type type) ; + abstract protected Type lubWithInteger(Type type) ; + abstract protected Type lubWithRational(Type type) ; + abstract protected Type lubWithList(Type type) ; + abstract protected Type lubWithMap(Type type) ; + abstract protected Type lubWithNumber(Type type) ; + abstract protected Type lubWithSet(Type type) ; + abstract protected Type lubWithSourceLocation(Type type) ; + abstract protected Type lubWithString(Type type) ; + abstract protected Type lubWithNode(Type type) ; + abstract protected Type lubWithConstructor(Type type) ; + abstract protected Type lubWithAbstractData(Type type) ; + abstract protected Type lubWithTuple(Type type) ; + abstract protected Type lubWithFunction(Type type) ; + abstract protected Type lubWithValue(Type type) ; + abstract protected Type lubWithVoid(Type type) ; + abstract protected Type lubWithBool(Type type) ; + abstract protected Type lubWithDateTime(Type type) ; + + protected Type glbWithAlias(Type type) { + return glb(type.getAliased()); + } + + protected Type glbWithParameter(Type type) { + if (type == this) { + return this; + } + + return glb(type.getBound()); + } + + abstract protected Type glbWithReal(Type type) ; + abstract protected Type glbWithInteger(Type type) ; + abstract protected Type glbWithRational(Type type) ; + abstract protected Type glbWithList(Type type) ; + abstract protected Type glbWithMap(Type type) ; + abstract protected Type glbWithNumber(Type type) ; + abstract protected Type glbWithSet(Type type) ; + abstract protected Type glbWithSourceLocation(Type type) ; + abstract protected Type glbWithString(Type type) ; + abstract protected Type glbWithNode(Type type) ; + abstract protected Type glbWithConstructor(Type type) ; + abstract protected Type glbWithAbstractData(Type type) ; + abstract protected Type glbWithTuple(Type type) ; + abstract protected Type glbWithFunction(Type type) ; + abstract protected Type glbWithValue(Type type) ; + abstract protected Type glbWithVoid(Type type) ; + abstract protected Type glbWithBool(Type type) ; + abstract protected Type glbWithDateTime(Type type) ; + + /** + * This makes sure that lubbing can be done by the external type whether + * or not it is the initial receiver or the second parameter to lub. + */ + protected Type lubWithExternal(Type type) { + // the external type should be the receiver + return lub(type); + } + + protected Type glbWithExternal(Type type) { + // the external type should be the receiver + return glb(type); + } + + /** + * Generate a random value which is guaranteed to have a type that is + * a (non-strict) sub-type of the receiver. + * + * @param random pass in reused Random instance for better random uniformity between calls to this method. + * @param vf IValueFactory to use when building values + * @param store TypeStore to lookup constructors and fields in + * @param typeParameters will be filled with the inferred (least-upper-bound) type for every open type parameter as a side-effect. + * @param maxDepth how deeply to generate recursive values + * @param maxWidth how wide collections and fixed-width data-types should be (maximally) + * @return + */ + abstract public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, int maxDepth, int maxWidth); +} diff --git a/src/main/java/io/usethesource/vallang/type/TypeFactory.java b/src/main/java/io/usethesource/vallang/type/TypeFactory.java index fa347f04a..4a0952ff6 100644 --- a/src/main/java/io/usethesource/vallang/type/TypeFactory.java +++ b/src/main/java/io/usethesource/vallang/type/TypeFactory.java @@ -6,10 +6,10 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Robert Fuhrer (rfuhrer@watson.ibm.com) - * Jurgen Vinju (jurgen@vinju.org) - * Paul Klint (Paul.Klint@cwi.nl) - * Anya Helene Bagge (anya@ii.uib.no) + * Robert Fuhrer (rfuhrer@watson.ibm.com) + * Jurgen Vinju (jurgen@vinju.org) + * Paul Klint (Paul.Klint@cwi.nl) + * Anya Helene Bagge (anya@ii.uib.no) *******************************************************************************/ package io.usethesource.vallang.type; @@ -55,842 +55,842 @@ * methods of Type can be used in conjunction with a reference to an * {@link IValueFactory} to produce {@link IValue}'s of a certain type. *

- * + * * @see {@link Type} and {@link IValueFactory} for more information. */ public class TypeFactory { - /** - * Caches all types to implement canonicalization - */ - private final HashConsingMap fCache = new WeakReferenceHashConsingMap<>(32*1024, (int)TimeUnit.MINUTES.toSeconds(30)); + /** + * Caches all types to implement canonicalization + */ + private final HashConsingMap fCache = new WeakReferenceHashConsingMap<>(32*1024, (int)TimeUnit.MINUTES.toSeconds(30)); private volatile @MonotonicNonNull TypeValues typeValues; // lazy initialize - - private static class InstanceHolder { - public static final TypeFactory sInstance = new TypeFactory(); - } - - private TypeFactory() { } - - public static TypeFactory getInstance() { - return InstanceHolder.sInstance; - } - - @Override - public String toString() { - return "TF"; - } - - public Type randomType(TypeStore store, RandomTypesConfig config) { + + private static class InstanceHolder { + public static final TypeFactory sInstance = new TypeFactory(); + } + + private TypeFactory() { } + + public static TypeFactory getInstance() { + return InstanceHolder.sInstance; + } + + @Override + public String toString() { + return "TF"; + } + + public Type randomType(TypeStore store, RandomTypesConfig config) { return cachedTypeValues().randomType(store, config); } - - public Type randomType(TypeStore typeStore) { - return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(new Random())); - } - public Type randomType(TypeStore typeStore, int depth) { - return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(new Random()).maxDepth(depth)); - } + public Type randomType(TypeStore typeStore) { + return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(new Random())); + } + + public Type randomType(TypeStore typeStore, int depth) { + return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(new Random()).maxDepth(depth)); + } + + public Type randomType(TypeStore typeStore, Random r, int depth) { + return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(r).maxDepth(depth)); + } + + + + /** + * construct the value type, which is the top type of the type hierarchy + * representing all possible values. + * + * @return a unique reference to the value type + */ + public Type valueType() { + return ValueType.getInstance(); + } + + /** + * construct the void type, which is the bottom of the type hierarchy, + * representing no values at all. + * + * @return a unique reference to the void type + */ + public Type voidType() { + return VoidType.getInstance(); + } + + /*package*/ Type getFromCache(Type t) { + return fCache.get(t); + } + + /** + * Construct a new type. + * + * @return a reference to the unique integer type of the PDB. + */ + public Type integerType() { + return IntegerType.getInstance(); + } + + /** + * Construct a new type. + * + * @return a reference to the unique number type of the PDB. + */ + public Type numberType() { + return NumberType.getInstance(); + } + + /** + * Construct a new type. + * + * @return a reference to the unique double type of the PDB. + */ + public Type realType() { + return RealType.getInstance(); + } + + /** + * Construct a new type. + * + * @return a reference to the unique rational type of the PDB. + */ + public Type rationalType() { + return RationalType.getInstance(); + } + + /** + * Construct a new bool type + * + * @return a reference to the unique boolean type of the PDB. + */ + public Type boolType() { + return BoolType.getInstance(); + } + + /** + * Retrieves an older equal externalType from the cache, or stores a new + * external type if it does not exist. + * + * @param externalType + * @return an object equal to externalType but possibly older + */ + public Type externalType(Type externalType) { + assert !isNull(externalType) : "external type cannot be null"; + return getFromCache(externalType); + } + + /** + * Construct a new type. + * + * @return a reference to the unique string type of the PDB. + */ + public Type stringType() { + return StringType.getInstance(); + } + + /** + * Construct a new type. + * + * @return a reference to the unique sourceLocation type of the PDB. + */ + public Type sourceLocationType() { + return SourceLocationType.getInstance(); + } + + /** + * Construct a new type. + * + * @return a reference to the unique datetime type of the PDB. + */ + public Type dateTimeType() { + return DateTimeType.getInstance(); + } + + private TupleType getOrCreateTuple(Type[] fieldTypes) { + return (TupleType) getFromCache(new TupleType(fieldTypes)); + } + + /** + * Construct a tuple type. + * + * @return a reference to the unique empty tuple type. + */ + public Type tupleEmpty() { + return getFromCache(new TupleType(new Type[0])); + } + + /** + * Construct a tuple type. Note that if you pass an array, this array should + * NEVER be modified after or serious breakage will occur. + * + * @param fieldTypes + * a list of field types in order of appearance. + * @return a tuple type or `void` in case one of the field types was void + */ + public Type tupleType(Type... fieldTypes) { + assert !anyNull(fieldTypes) : "tuple field types should not be null"; + + // tuple values with elements of type void (like tuple[void,void]) + // can not exist, so the type that represents that empty set of values is `void`, + // canonically. Without this canonicalization, type instantiation of + // types such as rel[&T, &Y] for empty sets would return rel[void, void] = set[tuple[void,void]] + // instead of the correct `set[void]`, also pattern matching and equality would fail seemingly + // randomly on empty relations depending on how they've been instantiated. + for (Type elem : fieldTypes) { + if (elem.isBottom()) { + return elem; + } + } + + return getFromCache(new TupleType(fieldTypes)); + } + + /** + * Construct a labeled tuple type. Note that if you pass an array, this array + * should NEVER be modified after or serious breakage will occur. + * + * @param fieldTypesAndLabel + * an array of field types, where each field type of type @{link + * Type} is immediately followed by a field label of type @{link + * String}. + * @return a tuple type + * @throws FactTypeDeclarationException + * when one of the labels is not a proper identifier or when the + * argument array does not contain alternating types and labels. + */ + @Deprecated + public Type tupleType(Object... fieldTypesAndLabels) throws FactTypeDeclarationException { + if (fieldTypesAndLabels.length == 0) { + return tupleEmpty(); + } + + int N = fieldTypesAndLabels.length; + int arity = N / 2; + Type[] protoFieldTypes = new Type[arity]; + String[] protoFieldNames = new String[arity]; + for (int i = 0; i < N; i += 2) { + int pos = i / 2; + if (fieldTypesAndLabels[i] == null || fieldTypesAndLabels[i + 1] == null) { + throw new NullPointerException(); + } + try { + protoFieldTypes[pos] = (Type) fieldTypesAndLabels[i]; + if (protoFieldTypes[pos].isBottom()) { + // if one of the fields is void, then the entire tuple could + // never be instantiated and thus its the void type (the empty set of + // values) that represents it canonically: + return voidType(); + } + } catch (ClassCastException e) { + throw new IllegalFieldTypeException(pos, fieldTypesAndLabels[i], e); + } + try { + String name = (String) fieldTypesAndLabels[i + 1]; + if (!isIdentifier(name)) { + throw new IllegalIdentifierException(name); + } + protoFieldNames[pos] = name; + } catch (ClassCastException e) { + throw new IllegalFieldNameException(pos, fieldTypesAndLabels[i + 1], e); + } + } + + return getFromCache(new TupleTypeWithFieldNames(protoFieldTypes, protoFieldNames)); + } + + /** + * Construct a tuple type. The length of the types and labels arrays should be + * equal. + * + * @param types + * the types of the fields + * @param labels + * the labels of the fields (in respective order) + * @return a tuple type + */ + @Deprecated + public Type tupleType(Type[] types, String[] labels) { + assert !anyNull(types) : "tuples types should not contain nulls"; + assert !anyNull(labels) : "label types should not contain nulls"; + assert types.length == labels.length; + + if (types.length == 0) { + return tupleEmpty(); + } + + // if one of the elements is of type void, then a tuple can never + // be instantiated of this type and thus void is the type to represent it: + for (Type elem : types) { + if (elem.isBottom()) { + return voidType(); + } + } + + return getFromCache(new TupleTypeWithFieldNames(types, labels)); + } + + /** + * Construct a tuple type. + * + * @param fieldTypes + * an array of field types in order of appearance. The array is + * copied. + * @return a tuple type + */ + public Type tupleType(IValue... elements) { + assert !anyNull(elements) : "tuple type elements should not contain any nulls"; + int N = elements.length; + Type[] fieldTypes = new Type[N]; + for (int i = N - 1; i >= 0; i--) { + fieldTypes[i] = elements[i].getType(); + } + return getOrCreateTuple(fieldTypes); + } + + /** + * Construct a function type by composing it from a return type and two tuple types + * for the arguments and the keyword parameters. These respective tuples must not + * have had any void parameters, otherwise this function will throw an exception. + * + * @param returnType + * @param argumentTypesTuple + * @param keywordParameterTypesTuple + * @return + */ + + public Type functionType(Type returnType, Type argumentTypesTuple, Type keywordParameterTypesTuple) { + if (argumentTypesTuple.isBottom()) { + throw new IllegalArgumentException("argumentTypes must be a proper tuple type (without any void fields)"); + } + + if (keywordParameterTypesTuple.isBottom()) { + throw new IllegalArgumentException("keywordParameterTypes must be a tuple type (without any void fields)"); + } - public Type randomType(TypeStore typeStore, Random r, int depth) { - return cachedTypeValues().randomType(typeStore, RandomTypesConfig.defaultConfig(r).maxDepth(depth)); - } + return getFromCache(new FunctionType(returnType, (TupleType) argumentTypesTuple, (TupleType) keywordParameterTypesTuple)); + } + + /** + * Construct a function type with labeled parameter and keyword field types + */ + public Type functionType(Type returnType, Type[] argumentTypes, String[] argumentLabels, Type[] keywordParameterTypes, String[] keywordParameterLabels) { + assert !anyNull(argumentTypes) : "argument types should not be null"; + assert !anyNull(argumentLabels) : "argument labels should not contain nulls"; + assert !anyNull(keywordParameterTypes) : "keyword parameter types should not contain nulls"; + assert !anyNull(keywordParameterLabels) : "keyword parameter types should not contain nulls"; + return getFromCache(new FunctionType(returnType, + (TupleType) getFromCache(new TupleTypeWithFieldNames(argumentTypes, argumentLabels)), + (TupleType) getFromCache(new TupleTypeWithFieldNames(keywordParameterTypes, keywordParameterLabels)) + )); + } - - /** - * construct the value type, which is the top type of the type hierarchy - * representing all possible values. - * - * @return a unique reference to the value type - */ - public Type valueType() { - return ValueType.getInstance(); - } - - /** - * construct the void type, which is the bottom of the type hierarchy, - * representing no values at all. - * - * @return a unique reference to the void type - */ - public Type voidType() { - return VoidType.getInstance(); - } - - /*package*/ Type getFromCache(Type t) { - return fCache.get(t); - } - - /** - * Construct a new type. - * - * @return a reference to the unique integer type of the PDB. - */ - public Type integerType() { - return IntegerType.getInstance(); - } - - /** - * Construct a new type. - * - * @return a reference to the unique number type of the PDB. - */ - public Type numberType() { - return NumberType.getInstance(); - } - - /** - * Construct a new type. - * - * @return a reference to the unique double type of the PDB. - */ - public Type realType() { - return RealType.getInstance(); - } - - /** - * Construct a new type. - * - * @return a reference to the unique rational type of the PDB. - */ - public Type rationalType() { - return RationalType.getInstance(); - } - - /** - * Construct a new bool type - * - * @return a reference to the unique boolean type of the PDB. - */ - public Type boolType() { - return BoolType.getInstance(); - } - - /** - * Retrieves an older equal externalType from the cache, or stores a new - * external type if it does not exist. - * - * @param externalType - * @return an object equal to externalType but possibly older - */ - public Type externalType(Type externalType) { - assert !isNull(externalType) : "external type cannot be null"; - return getFromCache(externalType); - } - - /** - * Construct a new type. - * - * @return a reference to the unique string type of the PDB. - */ - public Type stringType() { - return StringType.getInstance(); - } - - /** - * Construct a new type. - * - * @return a reference to the unique sourceLocation type of the PDB. - */ - public Type sourceLocationType() { - return SourceLocationType.getInstance(); - } - - /** - * Construct a new type. - * - * @return a reference to the unique datetime type of the PDB. - */ - public Type dateTimeType() { - return DateTimeType.getInstance(); - } - - private TupleType getOrCreateTuple(Type[] fieldTypes) { - return (TupleType) getFromCache(new TupleType(fieldTypes)); - } - - /** - * Construct a tuple type. - * - * @return a reference to the unique empty tuple type. - */ - public Type tupleEmpty() { - return getFromCache(new TupleType(new Type[0])); - } - - /** - * Construct a tuple type. Note that if you pass an array, this array should - * NEVER be modified after or serious breakage will occur. - * - * @param fieldTypes - * a list of field types in order of appearance. - * @return a tuple type or `void` in case one of the field types was void - */ - public Type tupleType(Type... fieldTypes) { - assert !anyNull(fieldTypes) : "tuple field types should not be null"; - - // tuple values with elements of type void (like tuple[void,void]) - // can not exist, so the type that represents that empty set of values is `void`, - // canonically. Without this canonicalization, type instantiation of - // types such as rel[&T, &Y] for empty sets would return rel[void, void] = set[tuple[void,void]] - // instead of the correct `set[void]`, also pattern matching and equality would fail seemingly - // randomly on empty relations depending on how they've been instantiated. - for (Type elem : fieldTypes) { - if (elem.isBottom()) { - return elem; - } - } - - return getFromCache(new TupleType(fieldTypes)); - } - - /** - * Construct a labeled tuple type. Note that if you pass an array, this array - * should NEVER be modified after or serious breakage will occur. - * - * @param fieldTypesAndLabel - * an array of field types, where each field type of type @{link - * Type} is immediately followed by a field label of type @{link - * String}. - * @return a tuple type - * @throws FactTypeDeclarationException - * when one of the labels is not a proper identifier or when the - * argument array does not contain alternating types and labels. - */ - @Deprecated - public Type tupleType(Object... fieldTypesAndLabels) throws FactTypeDeclarationException { - if (fieldTypesAndLabels.length == 0) { - return tupleEmpty(); - } - - int N = fieldTypesAndLabels.length; - int arity = N / 2; - Type[] protoFieldTypes = new Type[arity]; - String[] protoFieldNames = new String[arity]; - for (int i = 0; i < N; i += 2) { - int pos = i / 2; - if (fieldTypesAndLabels[i] == null || fieldTypesAndLabels[i + 1] == null) { - throw new NullPointerException(); - } - try { - protoFieldTypes[pos] = (Type) fieldTypesAndLabels[i]; - if (protoFieldTypes[pos].isBottom()) { - // if one of the fields is void, then the entire tuple could - // never be instantiated and thus its the void type (the empty set of - // values) that represents it canonically: - return voidType(); - } - } catch (ClassCastException e) { - throw new IllegalFieldTypeException(pos, fieldTypesAndLabels[i], e); - } - try { - String name = (String) fieldTypesAndLabels[i + 1]; - if (!isIdentifier(name)) { - throw new IllegalIdentifierException(name); - } - protoFieldNames[pos] = name; - } catch (ClassCastException e) { - throw new IllegalFieldNameException(pos, fieldTypesAndLabels[i + 1], e); - } - } - - return getFromCache(new TupleTypeWithFieldNames(protoFieldTypes, protoFieldNames)); - } - - /** - * Construct a tuple type. The length of the types and labels arrays should be - * equal. - * - * @param types - * the types of the fields - * @param labels - * the labels of the fields (in respective order) - * @return a tuple type - */ - @Deprecated - public Type tupleType(Type[] types, String[] labels) { - assert !anyNull(types) : "tuples types should not contain nulls"; - assert !anyNull(labels): "label types should not contain nulls"; - assert types.length == labels.length; - - if (types.length == 0) { - return tupleEmpty(); + * Construct a function type with unlabeled parameter and keyword field types + */ + public Type functionType(Type returnType, Type[] argumentTypes, Type[] keywordParameterTypes) { + assert !anyNull(argumentTypes) : "argument types should not be null"; + assert !anyNull(keywordParameterTypes) : "keyword parameter types should not contain nulls"; + return getFromCache(new FunctionType(returnType, + (TupleType) getFromCache(new TupleType(argumentTypes)), + (TupleType) getFromCache(new TupleType(keywordParameterTypes)) + )); } - - // if one of the elements is of type void, then a tuple can never - // be instantiated of this type and thus void is the type to represent it: - for (Type elem : types) { - if (elem.isBottom()) { - return voidType(); + + /** + * Construct a set type + * + * @param eltType + * the type of elements in the set + * @return a set type + */ + public Type setType(Type eltType) { + assert !isNull(eltType) : "set type should not be null"; + return getFromCache(new SetType(eltType)); + } + + public Type relTypeFromTuple(Type tupleType) { + assert !isNull(tupleType) : "rel type should not be null"; + return setType(tupleType); + } + + public Type lrelTypeFromTuple(Type tupleType) { + assert !isNull(tupleType) : "lrel type should not be null"; + + return listType(tupleType); + } + + /** + * Construct a relation type. + * + * @param fieldTypes + * the types of the fields of the relation + * @return a relation type + */ + public Type relType(Type... fieldTypes) { + assert !anyNull(fieldTypes) : "rel types should not contain nulls"; + return setType(tupleType(fieldTypes)); + } + + /** + * Construct a relation type. + * + * @param fieldTypes + * the types of the fields of the relation + * @return a relation type + */ + @Deprecated + public Type relType(Object... fieldTypesAndLabels) { + return setType(tupleType(fieldTypesAndLabels)); + } + + /** + * Construct a list relation type. + * + * @param fieldTypes + * the types of the fields of the relation + * @return a list relation type + */ + public Type lrelType(Type... fieldTypes) { + assert !anyNull(fieldTypes) : "lrel types should not contain nulls"; + return listType(tupleType(fieldTypes)); + } + + /** + * Construct a list relation type. + * + * @param fieldTypes + * the types of the fields of the relation + * @return a list relation type + */ + @Deprecated + public Type lrelType(Object... fieldTypesAndLabels) { + return lrelTypeFromTuple(tupleType(fieldTypesAndLabels)); + } + + /** + * Construct an alias type. The alias may be parameterized to make an abstract + * alias. Each ParameterType embedded in the aliased type should occur in the + * list of parameters. + * + * @param store + * to store the declared alias in + * @param name + * the name of the type + * @param aliased + * the type it should be an alias for + * @param parameters + * a list of type parameters for this alias + * @return an alias type + * @throws FactTypeDeclarationException + * if a type with the same name but a different supertype was + * defined earlier as a named type of a AbstractDataType. + */ + public Type aliasType(TypeStore store, String name, Type aliased, Type... parameters) + throws FactTypeDeclarationException { + assert !isNull(store) : "alias store should not be null"; + assert !isNull(name) : "alias name should not be null"; + assert !isNull(aliased) : "alias aliased should not be null"; + assert !anyNull(parameters): "alias parameters should not be null"; + + Type paramType; + if (parameters.length == 0) { + paramType = voidType(); + } else { + paramType = tupleType(parameters); + } + + return aliasTypeFromTuple(store, name, aliased, paramType); + } + + public Type aliasTypeFromTuple(TypeStore store, String name, Type aliased, Type params) + throws FactTypeDeclarationException { + assert !isNull(store) : "alias store should not be null"; + assert !isNull(name) : "alias name should not be null"; + assert !isNull(aliased) : "alias aliased should not be null"; + assert !isNull(params): "alias params should not be null"; + + if (!isIdentifier(name)) { + throw new IllegalIdentifierException(name); + } + + if (aliased == null) { + throw new NullTypeException(); + } + + Type result = getFromCache(new AliasType(name, aliased, params)); + store.declareAlias(result); + return result; + } + + public Type nodeType() { + return NodeType.getInstance(); + } + + /** + * Construct a @{link AbstractDataType}, which is a kind of tree node. Each + * kind of tree node may have different alternatives, which are + * ConstructorTypes. A @{link ConstructorType} is always a sub-type of a + * AbstractDataType. A AbstractDataType is always a sub type of value. + * + * @param store + * to store the declared adt in + * @param name + * the name of the abstract data-type + * @param parameters + * array of type parameters + * @return a AbstractDataType + * @throws IllegalIdentifierException + */ + public Type abstractDataType(TypeStore store, String name, Type... parameters) throws FactTypeDeclarationException { + assert !isNull(store) : "adt store should not be null"; + assert !isNull(name) : "adt name should not be null"; + assert !anyNull(parameters) : "adt parameters should not contain a null"; + + Type paramType = voidType(); + if (parameters.length != 0) { + paramType = tupleType(parameters); + } + + return abstractDataTypeFromTuple(store, name, paramType); + } + + public Type abstractDataTypeFromTuple(TypeStore store, String name, Type params) throws FactTypeDeclarationException { + assert !isNull(store) : "adt store should not be null"; + assert !isNull(name) : "adt name should not be null"; + assert !isNull(params): "adt params should not be null"; + + if (!isIdentifier(name)) { + throw new IllegalIdentifierException(name); + } + Type result = getFromCache(new AbstractDataType(name, params)); + + if (!params.equivalent(voidType()) && params.getArity() > 0) { + if (params.getFieldType(0).isOpen()) { // parametrized and uninstantiated + // adts should be stored + store.declareAbstractDataType(result); + } + } else { // not parametrized + store.declareAbstractDataType(result); } + + return result; } - - return getFromCache(new TupleTypeWithFieldNames(types, labels)); - } - - /** - * Construct a tuple type. - * - * @param fieldTypes - * an array of field types in order of appearance. The array is - * copied. - * @return a tuple type - */ - public Type tupleType(IValue... elements) { - assert !anyNull(elements) : "tuple type elements should not contain any nulls"; - int N = elements.length; - Type[] fieldTypes = new Type[N]; - for (int i = N - 1; i >= 0; i--) { - fieldTypes[i] = elements[i].getType(); - } - return getOrCreateTuple(fieldTypes); - } - - /** - * Construct a function type by composing it from a return type and two tuple types - * for the arguments and the keyword parameters. These respective tuples must not - * have had any void parameters, otherwise this function will throw an exception. - * - * @param returnType - * @param argumentTypesTuple - * @param keywordParameterTypesTuple - * @return - */ - - public Type functionType(Type returnType, Type argumentTypesTuple, Type keywordParameterTypesTuple) { - if (argumentTypesTuple.isBottom()) { - throw new IllegalArgumentException("argumentTypes must be a proper tuple type (without any void fields)"); - } - - if (keywordParameterTypesTuple.isBottom()) { - throw new IllegalArgumentException("keywordParameterTypes must be a tuple type (without any void fields)"); - } - - return getFromCache(new FunctionType(returnType, (TupleType) argumentTypesTuple, (TupleType) keywordParameterTypesTuple)); - } - - /** - * Construct a function type with labeled parameter and keyword field types - */ - public Type functionType(Type returnType, Type[] argumentTypes, String[] argumentLabels, Type[] keywordParameterTypes, String[] keywordParameterLabels) { - assert !anyNull(argumentTypes) : "argument types should not be null"; - assert !anyNull(argumentLabels) : "argument labels should not contain nulls"; - assert !anyNull(keywordParameterTypes) : "keyword parameter types should not contain nulls"; - assert !anyNull(keywordParameterLabels) : "keyword parameter types should not contain nulls"; - return getFromCache(new FunctionType(returnType, - (TupleType) getFromCache(new TupleTypeWithFieldNames(argumentTypes, argumentLabels)), - (TupleType) getFromCache(new TupleTypeWithFieldNames(keywordParameterTypes, keywordParameterLabels)) - )); - } - - /** - * Construct a function type with unlabeled parameter and keyword field types - */ - public Type functionType(Type returnType, Type[] argumentTypes, Type[] keywordParameterTypes) { - assert !anyNull(argumentTypes) : "argument types should not be null"; - assert !anyNull(keywordParameterTypes) : "keyword parameter types should not contain nulls"; - return getFromCache(new FunctionType(returnType, - (TupleType) getFromCache(new TupleType(argumentTypes)), - (TupleType) getFromCache(new TupleType(keywordParameterTypes)) - )); - } - - /** - * Construct a set type - * - * @param eltType - * the type of elements in the set - * @return a set type - */ - public Type setType(Type eltType) { - assert !isNull(eltType) : "set type should not be null"; - return getFromCache(new SetType(eltType)); - } - - public Type relTypeFromTuple(Type tupleType) { - assert !isNull(tupleType) : "rel type should not be null"; - return setType(tupleType); - } - - public Type lrelTypeFromTuple(Type tupleType) { - assert !isNull(tupleType) : "lrel type should not be null"; - - return listType(tupleType); - } - - /** - * Construct a relation type. - * - * @param fieldTypes - * the types of the fields of the relation - * @return a relation type - */ - public Type relType(Type... fieldTypes) { - assert !anyNull(fieldTypes) : "rel types should not contain nulls"; - return setType(tupleType(fieldTypes)); - } - - /** - * Construct a relation type. - * - * @param fieldTypes - * the types of the fields of the relation - * @return a relation type - */ - @Deprecated - public Type relType(Object... fieldTypesAndLabels) { - return setType(tupleType(fieldTypesAndLabels)); - } - - /** - * Construct a list relation type. - * - * @param fieldTypes - * the types of the fields of the relation - * @return a list relation type - */ - public Type lrelType(Type... fieldTypes) { - assert !anyNull(fieldTypes) : "lrel types should not contain nulls"; - return listType(tupleType(fieldTypes)); - } - - /** - * Construct a list relation type. - * - * @param fieldTypes - * the types of the fields of the relation - * @return a list relation type - */ - @Deprecated - public Type lrelType(Object... fieldTypesAndLabels) { - return lrelTypeFromTuple(tupleType(fieldTypesAndLabels)); - } - - /** - * Construct an alias type. The alias may be parameterized to make an abstract - * alias. Each ParameterType embedded in the aliased type should occur in the - * list of parameters. - * - * @param store - * to store the declared alias in - * @param name - * the name of the type - * @param aliased - * the type it should be an alias for - * @param parameters - * a list of type parameters for this alias - * @return an alias type - * @throws FactTypeDeclarationException - * if a type with the same name but a different supertype was - * defined earlier as a named type of a AbstractDataType. - */ - public Type aliasType(TypeStore store, String name, Type aliased, Type... parameters) - throws FactTypeDeclarationException { - assert !isNull(store) : "alias store should not be null"; - assert !isNull(name) : "alias name should not be null"; - assert !isNull(aliased) : "alias aliased should not be null"; - assert !anyNull(parameters): "alias parameters should not be null"; - - Type paramType; - if (parameters.length == 0) { - paramType = voidType(); - } else { - paramType = tupleType(parameters); - } - - return aliasTypeFromTuple(store, name, aliased, paramType); - } - - public Type aliasTypeFromTuple(TypeStore store, String name, Type aliased, Type params) - throws FactTypeDeclarationException { - assert !isNull(store) : "alias store should not be null"; - assert !isNull(name) : "alias name should not be null"; - assert !isNull(aliased) : "alias aliased should not be null"; - assert !isNull(params): "alias params should not be null"; - - if (!isIdentifier(name)) { - throw new IllegalIdentifierException(name); - } - - if (aliased == null) { - throw new NullTypeException(); - } - - Type result = getFromCache(new AliasType(name, aliased, params)); - store.declareAlias(result); - return result; - } - - public Type nodeType() { - return NodeType.getInstance(); - } - - /** - * Construct a @{link AbstractDataType}, which is a kind of tree node. Each - * kind of tree node may have different alternatives, which are - * ConstructorTypes. A @{link ConstructorType} is always a sub-type of a - * AbstractDataType. A AbstractDataType is always a sub type of value. - * - * @param store - * to store the declared adt in - * @param name - * the name of the abstract data-type - * @param parameters - * array of type parameters - * @return a AbstractDataType - * @throws IllegalIdentifierException - */ - public Type abstractDataType(TypeStore store, String name, Type... parameters) throws FactTypeDeclarationException { - assert !isNull(store) : "adt store should not be null"; - assert !isNull(name) : "adt name should not be null"; - assert !anyNull(parameters) : "adt parameters should not contain a null"; - - Type paramType = voidType(); - if (parameters.length != 0) { - paramType = tupleType(parameters); - } - - return abstractDataTypeFromTuple(store, name, paramType); - } - - public Type abstractDataTypeFromTuple(TypeStore store, String name, Type params) throws FactTypeDeclarationException { - assert !isNull(store) : "adt store should not be null"; - assert !isNull(name) : "adt name should not be null"; - assert !isNull(params): "adt params should not be null"; - - if (!isIdentifier(name)) { - throw new IllegalIdentifierException(name); - } - Type result = getFromCache(new AbstractDataType(name, params)); - - if (!params.equivalent(voidType()) && params.getArity() > 0) { - if (params.getFieldType(0).isOpen()) { // parametrized and uninstantiated - // adts should be stored - store.declareAbstractDataType(result); - } - } else { // not parametrized - store.declareAbstractDataType(result); - } - - return result; - } - - /** - * Make a new constructor type. A constructor type extends an abstract data - * type such that it represents more values. - * - * @param store - * to store the declared constructor in - * @param adt - * the AbstractDataType this constructor builds - * @param name - * the name of the node type - * @param children - * the types of the children of the tree node type - * @return a tree node type - * @throws IllegalIdentifierException - * , UndeclaredAbstractDataTypeException, - * RedeclaredFieldNameException, RedeclaredConstructorException - */ - public Type constructorFromTuple(TypeStore store, Type adt, String name, Type tupleType) throws FactTypeDeclarationException { - assert !isNull(store) : "constructor store should not be null"; - assert !isNull(adt): "constructor adt should not be null"; - assert !isNull(name) : "constructor name should not be null"; - assert !isNull(tupleType) : "constructor type should not be null"; - - if (!isIdentifier(name)) { - throw new IllegalIdentifierException(name); - } - - Type result = getFromCache(new ConstructorType(name, tupleType, adt)); - - Type params = adt.getTypeParameters(); - - if (!params.equivalent(voidType())) { - if (params.isOpen()) { // only parametrized and not instantiated types - // should be stored - store.declareConstructor(result); - } - } else { - store.declareConstructor(result); - } - - return result; - } - - /** - * Make a new constructor type. A constructor type extends an abstract data - * type such that it represents more values. Note that if you pass an array - * for the children parameter, this array should NEVER be modified after or - * serious breakage will occur. - * - * @param store - * to store the declared constructor in - * @param adt - * the adt this constructor builds - * @param name - * the name of the node type - * @param children - * the types of the children of the tree node type - * @return a tree node type - */ - public Type constructor(TypeStore store, Type adt, String name, Type... children) throws FactTypeDeclarationException { - return constructorFromTuple(store, adt, name, tupleType(children)); - } - - /** - * Make a new constructor type. A constructor type extends an abstract data - * type such that it represents more values. - * - * @param store - * to store the declared constructor in - * @param nodeType - * the type of node this constructor builds - * @param name - * the name of the node type - * @param children - * the types of the children of the tree node type - * @return a tree node type - */ - public Type constructor(TypeStore store, Type nodeType, String name, Object... childrenAndLabels) - throws FactTypeDeclarationException { - return constructorFromTuple(store, nodeType, name, tupleType(childrenAndLabels)); - } - - /** - * Construct a list type - * - * @param elementType - * the type of the elements in the list - * @return a list type - */ - public Type listType(Type elementType) { - assert !isNull(elementType) : "list type should not be null"; - return getFromCache(new ListType(elementType)); - } - - /** - * Construct a map type - * - * @param key - * the type of the keys in the map - * @param value - * the type of the values in the map - * @return a map type - */ - public Type mapType(Type key, Type value) { - assert !isNull(key) : "map key type should not be null"; - assert !isNull(value) : "map key type should not be null"; - return getFromCache(new MapType(key, value)); - } - - public Type mapTypeFromTuple(Type fields) { - assert !isNull(fields) : "map tuple type should not be null"; - - if (fields.isBottom()) { + + /** + * Make a new constructor type. A constructor type extends an abstract data + * type such that it represents more values. + * + * @param store + * to store the declared constructor in + * @param adt + * the AbstractDataType this constructor builds + * @param name + * the name of the node type + * @param children + * the types of the children of the tree node type + * @return a tree node type + * @throws IllegalIdentifierException + * , UndeclaredAbstractDataTypeException, + * RedeclaredFieldNameException, RedeclaredConstructorException + */ + public Type constructorFromTuple(TypeStore store, Type adt, String name, Type tupleType) throws FactTypeDeclarationException { + assert !isNull(store) : "constructor store should not be null"; + assert !isNull(adt): "constructor adt should not be null"; + assert !isNull(name) : "constructor name should not be null"; + assert !isNull(tupleType) : "constructor type should not be null"; + + if (!isIdentifier(name)) { + throw new IllegalIdentifierException(name); + } + + Type result = getFromCache(new ConstructorType(name, tupleType, adt)); + + Type params = adt.getTypeParameters(); + + if (!params.equivalent(voidType())) { + if (params.isOpen()) { // only parametrized and not instantiated types + // should be stored + store.declareConstructor(result); + } + } else { + store.declareConstructor(result); + } + + return result; + } + + /** + * Make a new constructor type. A constructor type extends an abstract data + * type such that it represents more values. Note that if you pass an array + * for the children parameter, this array should NEVER be modified after or + * serious breakage will occur. + * + * @param store + * to store the declared constructor in + * @param adt + * the adt this constructor builds + * @param name + * the name of the node type + * @param children + * the types of the children of the tree node type + * @return a tree node type + */ + public Type constructor(TypeStore store, Type adt, String name, Type... children) throws FactTypeDeclarationException { + return constructorFromTuple(store, adt, name, tupleType(children)); + } + + /** + * Make a new constructor type. A constructor type extends an abstract data + * type such that it represents more values. + * + * @param store + * to store the declared constructor in + * @param nodeType + * the type of node this constructor builds + * @param name + * the name of the node type + * @param children + * the types of the children of the tree node type + * @return a tree node type + */ + public Type constructor(TypeStore store, Type nodeType, String name, Object... childrenAndLabels) + throws FactTypeDeclarationException { + return constructorFromTuple(store, nodeType, name, tupleType(childrenAndLabels)); + } + + /** + * Construct a list type + * + * @param elementType + * the type of the elements in the list + * @return a list type + */ + public Type listType(Type elementType) { + assert !isNull(elementType) : "list type should not be null"; + return getFromCache(new ListType(elementType)); + } + + /** + * Construct a map type + * + * @param key + * the type of the keys in the map + * @param value + * the type of the values in the map + * @return a map type + */ + public Type mapType(Type key, Type value) { + assert !isNull(key) : "map key type should not be null"; + assert !isNull(value) : "map key type should not be null"; + return getFromCache(new MapType(key, value)); + } + + public Type mapTypeFromTuple(Type fields) { + assert !isNull(fields) : "map tuple type should not be null"; + + if (fields.isBottom()) { return mapType(voidType(), voidType()); } - - if (!fields.isFixedWidth()) { - throw new UnsupportedOperationException("fields argument should be a tuple. not " + fields); - } - if (fields.getArity() < 2) { - throw new IndexOutOfBoundsException(); - } - if (fields.hasFieldNames()) { - return mapType(fields.getFieldType(0), Objects.requireNonNull(fields.getFieldName(0)), fields.getFieldType(1), Objects.requireNonNull(fields.getFieldName(1))); - } else { - return mapType(fields.getFieldType(0), fields.getFieldType(1)); - } - } - - public Type mapType(Type key, String keyLabel, Type value, String valueLabel) { - assert !isNull(key) : "map key type should not be null"; - assert !isNull(value) : "map key type should not be null"; - if ((keyLabel != null && valueLabel == null) || (valueLabel != null && keyLabel == null)) { - throw new IllegalArgumentException("Key and value labels must both be non-null or null: " + keyLabel + ", " - + valueLabel); - } - return getFromCache(new MapTypeWithFieldNames(key, keyLabel, value, valueLabel)); - } - - /** - * Construct a type parameter, which can later be instantiated. - * - * @param name - * the name of the type parameter - * @param bound - * the widest type that is acceptable when this type is instantiated - * @return a parameter type - */ - public Type parameterType(String name, Type bound) { - assert !isNull(name) : "parameter name should not be null"; - assert !isNull(bound) : "parameter type should not be null"; - return getFromCache(new ParameterType(name, bound)); - } - - /** - * Reconstruct a type from its symbolic value representation, and if relevant add - * its declaration to the store (for ADTs, constructors and aliases) - * - * @param symbol value representation of a type - * @param store store to put declarations in - * @param grammar function to look up definitions for non-terminal types - * @return a type isomorphic to the given symbolic representation - */ - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return cachedTypeValues().fromSymbol(symbol, store, grammar); - } - - /** + + if (!fields.isFixedWidth()) { + throw new UnsupportedOperationException("fields argument should be a tuple. not " + fields); + } + if (fields.getArity() < 2) { + throw new IndexOutOfBoundsException(); + } + if (fields.hasFieldNames()) { + return mapType(fields.getFieldType(0), Objects.requireNonNull(fields.getFieldName(0)), fields.getFieldType(1), Objects.requireNonNull(fields.getFieldName(1))); + } else { + return mapType(fields.getFieldType(0), fields.getFieldType(1)); + } + } + + public Type mapType(Type key, String keyLabel, Type value, String valueLabel) { + assert !isNull(key) : "map key type should not be null"; + assert !isNull(value) : "map key type should not be null"; + if ((keyLabel != null && valueLabel == null) || (valueLabel != null && keyLabel == null)) { + throw new IllegalArgumentException("Key and value labels must both be non-null or null: " + keyLabel + ", " + + valueLabel); + } + return getFromCache(new MapTypeWithFieldNames(key, keyLabel, value, valueLabel)); + } + + /** + * Construct a type parameter, which can later be instantiated. + * + * @param name + * the name of the type parameter + * @param bound + * the widest type that is acceptable when this type is instantiated + * @return a parameter type + */ + public Type parameterType(String name, Type bound) { + assert !isNull(name) : "parameter name should not be null"; + assert !isNull(bound) : "parameter type should not be null"; + return getFromCache(new ParameterType(name, bound)); + } + + /** + * Reconstruct a type from its symbolic value representation, and if relevant add + * its declaration to the store (for ADTs, constructors and aliases) + * + * @param symbol value representation of a type + * @param store store to put declarations in + * @param grammar function to look up definitions for non-terminal types + * @return a type isomorphic to the given symbolic representation + */ + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + return cachedTypeValues().fromSymbol(symbol, store, grammar); + } + + /** * Represent this type as a value of the abstract data-type "Symbol". As a side-effect * it will also add Production values to the grammar map, including all necessary productions * to build values of the receiver type, transitively. - * - * @param vf valuefactory to use + * + * @param vf valuefactory to use * @param store store to lookup additional necessary definitions in to store in the grammar * @param grammar map to store production values in as a side-effect * @return a value to uniquely represent this type. */ - public IConstructor asSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar) { + public IConstructor asSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar) { return type.asSymbol(vf, store, grammar, new HashSet<>()); } - - /** - * Parsers the serialized representation of types (what is produced by Type.toString()) - * @param Reader reader - * @return - * @throws IOException - */ - public Type fromString(TypeStore store, Reader reader) throws IOException { - return new TypeReader().read(store, reader); - } - - /** - * Construct a type parameter, which can later be instantiated. - * - * @param name - * the name of the type parameter - * @return a parameter type - */ - public Type parameterType(String name) { - assert !isNull(name) : "parameter name should not be null"; - return getFromCache(new ParameterType(name)); - } - - private boolean anyNull(@Nullable Object[] os) { - for (@Nullable Object o: os) { - if (isNull(o)) { - return true; - } - } - return false; - } - - private boolean isNull(@Nullable Object os) { - return Objects.isNull(os); - } - - /** - * Checks to see if a string is a valid PDB type, or field name - * identifier - * - * @param str - * @return true if the string is a valid identifier - */ - public boolean isIdentifier(String str) { - assert !isNull(str) : "str should not be null"; - - int len = str.length(); - if (len == 0) { - return false; - } - - if (!Character.isJavaIdentifierStart(str.charAt(0))) { - return false; - } - - for (int i = len - 1; i > 0; i--) { - char c = str.charAt(i); - if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '-')) { - return false; - } - } - - return true; - } - - public abstract static class TypeReifier { - private final TypeValues cachedSymbols; - - public TypeReifier(TypeValues symbols) { - this.cachedSymbols = symbols; - } - - public TypeValues symbols() { - return cachedSymbols; - } - - public TypeFactory tf() { - return TypeFactory.getInstance(); - } - - - public Set getSymbolConstructorTypes() { - return Collections.singleton(getSymbolConstructorType()); - } - - public abstract Type getSymbolConstructorType(); - - public boolean isRecursive() { - return false; - } - - public abstract Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd); - - public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - // this will work for all nullary type symbols with only one constructor type - return vf.constructor(getSymbolConstructorType()); - } - - public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { - // normally nothing - } - - public abstract Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar); + + /** + * Parsers the serialized representation of types (what is produced by Type.toString()) + * @param Reader reader + * @return + * @throws IOException + */ + public Type fromString(TypeStore store, Reader reader) throws IOException { + return new TypeReader().read(store, reader); + } + + /** + * Construct a type parameter, which can later be instantiated. + * + * @param name + * the name of the type parameter + * @return a parameter type + */ + public Type parameterType(String name) { + assert !isNull(name) : "parameter name should not be null"; + return getFromCache(new ParameterType(name)); + } + + private boolean anyNull(@Nullable Object[] os) { + for (@Nullable Object o: os) { + if (isNull(o)) { + return true; + } + } + return false; + } + + private boolean isNull(@Nullable Object os) { + return Objects.isNull(os); + } + + /** + * Checks to see if a string is a valid PDB type, or field name + * identifier + * + * @param str + * @return true if the string is a valid identifier + */ + public boolean isIdentifier(String str) { + assert !isNull(str) : "str should not be null"; + + int len = str.length(); + if (len == 0) { + return false; + } + + if (!Character.isJavaIdentifierStart(str.charAt(0))) { + return false; + } + + for (int i = len - 1; i > 0; i--) { + char c = str.charAt(i); + if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '-')) { + return false; + } + } + + return true; + } + + public abstract static class TypeReifier { + private final TypeValues cachedSymbols; + + public TypeReifier(TypeValues symbols) { + this.cachedSymbols = symbols; + } + + public TypeValues symbols() { + return cachedSymbols; + } + + public TypeFactory tf() { + return TypeFactory.getInstance(); + } + + + public Set getSymbolConstructorTypes() { + return Collections.singleton(getSymbolConstructorType()); + } + + public abstract Type getSymbolConstructorType(); + + public boolean isRecursive() { + return false; + } + + public abstract Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd); + + public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { + // this will work for all nullary type symbols with only one constructor type + return vf.constructor(getSymbolConstructorType()); + } + + public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set done) { + // normally nothing + } + + public abstract Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar); public String randomLabel(RandomTypesConfig rnd) { return "x" + new BigInteger(32, rnd.getRandom()).toString(32); } - + public Type randomTuple(Supplier next, TypeStore store, RandomTypesConfig rnd) { return new TupleType.Info(cachedSymbols).randomInstance(next, store, rnd); } - + public Type randomTuple(Supplier next, TypeStore store, RandomTypesConfig rnd, int arity) { return new TupleType.Info(cachedSymbols).randomInstance(next, rnd, arity); } - } - - public static class RandomTypesConfig { - private final Random random; - private final int maxDepth; - private final boolean withTypeParameters; - private final boolean withAliases; - private final boolean withTupleFieldNames; - private final boolean withRandomAbstractDatatypes; - - private RandomTypesConfig(Random random) { - this.random = random; - this.maxDepth = 5; - this.withAliases = false; - this.withTupleFieldNames = false; - this.withTypeParameters = false; - this.withRandomAbstractDatatypes = true; - } - - private RandomTypesConfig(Random random, int maxDepth, boolean withTypeParameters, boolean withAliases, boolean withTupleFieldNames, boolean withRandomAbstractDatatypes) { + } + + public static class RandomTypesConfig { + private final Random random; + private final int maxDepth; + private final boolean withTypeParameters; + private final boolean withAliases; + private final boolean withTupleFieldNames; + private final boolean withRandomAbstractDatatypes; + + private RandomTypesConfig(Random random) { + this.random = random; + this.maxDepth = 5; + this.withAliases = false; + this.withTupleFieldNames = false; + this.withTypeParameters = false; + this.withRandomAbstractDatatypes = true; + } + + private RandomTypesConfig(Random random, int maxDepth, boolean withTypeParameters, boolean withAliases, boolean withTupleFieldNames, boolean withRandomAbstractDatatypes) { this.random = random; this.maxDepth = maxDepth; this.withAliases = withAliases; @@ -898,104 +898,104 @@ private RandomTypesConfig(Random random, int maxDepth, boolean withTypeParameter this.withTypeParameters = withTypeParameters; this.withRandomAbstractDatatypes = withRandomAbstractDatatypes; } - - public static RandomTypesConfig defaultConfig(Random random) { - return new RandomTypesConfig(random); - } - - public Random getRandom() { + + public static RandomTypesConfig defaultConfig(Random random) { + return new RandomTypesConfig(random); + } + + public Random getRandom() { return random; } - - public boolean nextBoolean() { - return random.nextBoolean(); - } - - public int nextInt(int bound) { - return random.nextInt(bound); - } - - public boolean isWithAliases() { + + public boolean nextBoolean() { + return random.nextBoolean(); + } + + public int nextInt(int bound) { + return random.nextInt(bound); + } + + public boolean isWithAliases() { return withAliases; } - - public boolean isWithTupleFieldNames() { + + public boolean isWithTupleFieldNames() { return withTupleFieldNames; } - - public boolean isWithTypeParameters() { + + public boolean isWithTypeParameters() { return withTypeParameters; } - - public boolean isWithRandomAbstractDatatypes() { - return withRandomAbstractDatatypes; - } - - public int getMaxDepth() { - return maxDepth; - } - - public RandomTypesConfig maxDepth(int newMaxDepth) { - return new RandomTypesConfig(random, newMaxDepth, withTypeParameters, withAliases, withTupleFieldNames, withRandomAbstractDatatypes); - } - - public RandomTypesConfig withAliases() { - return new RandomTypesConfig(random, maxDepth, withTypeParameters, true, withTupleFieldNames, withRandomAbstractDatatypes); - } - - public RandomTypesConfig withTypeParameters() { - return new RandomTypesConfig(random, maxDepth, true, withAliases, withTupleFieldNames, withRandomAbstractDatatypes); - } - - public RandomTypesConfig withTupleFieldNames() { - return new RandomTypesConfig(random, maxDepth, withTypeParameters, withAliases, true, withRandomAbstractDatatypes); - } - - public RandomTypesConfig withoutRandomAbstractDatatypes() { - return new RandomTypesConfig(random, maxDepth, withTypeParameters, withAliases, withTupleFieldNames, false); - } - } - - public class TypeValues { - private static final String TYPES_CONFIG = "io/usethesource/vallang/type/types.config"; - - private final TypeStore symbolStore = new TypeStore(); - private final Type Symbol = abstractDataType(symbolStore, "Symbol"); - private final Type Symbol_Label = constructor(symbolStore, Symbol, "label", stringType(), "name", Symbol, "symbol"); - - private final Map symbolConstructorTypes = new ConcurrentHashMap<>(); - - private TypeValues() { } - - public Type randomType(TypeStore store, RandomTypesConfig rnd) { - Supplier next = new Supplier() { - int maxTries = rnd.getMaxDepth(); - + + public boolean isWithRandomAbstractDatatypes() { + return withRandomAbstractDatatypes; + } + + public int getMaxDepth() { + return maxDepth; + } + + public RandomTypesConfig maxDepth(int newMaxDepth) { + return new RandomTypesConfig(random, newMaxDepth, withTypeParameters, withAliases, withTupleFieldNames, withRandomAbstractDatatypes); + } + + public RandomTypesConfig withAliases() { + return new RandomTypesConfig(random, maxDepth, withTypeParameters, true, withTupleFieldNames, withRandomAbstractDatatypes); + } + + public RandomTypesConfig withTypeParameters() { + return new RandomTypesConfig(random, maxDepth, true, withAliases, withTupleFieldNames, withRandomAbstractDatatypes); + } + + public RandomTypesConfig withTupleFieldNames() { + return new RandomTypesConfig(random, maxDepth, withTypeParameters, withAliases, true, withRandomAbstractDatatypes); + } + + public RandomTypesConfig withoutRandomAbstractDatatypes() { + return new RandomTypesConfig(random, maxDepth, withTypeParameters, withAliases, withTupleFieldNames, false); + } + } + + public class TypeValues { + private static final String TYPES_CONFIG = "io/usethesource/vallang/type/types.config"; + + private final TypeStore symbolStore = new TypeStore(); + private final Type Symbol = abstractDataType(symbolStore, "Symbol"); + private final Type Symbol_Label = constructor(symbolStore, Symbol, "label", stringType(), "name", Symbol, "symbol"); + + private final Map symbolConstructorTypes = new ConcurrentHashMap<>(); + + private TypeValues() { } + + public Type randomType(TypeStore store, RandomTypesConfig rnd) { + Supplier next = new Supplier() { + int maxTries = rnd.getMaxDepth(); + @Override public Type get() { if (maxTries-- > 0) { - return getRandomType(this, store, rnd); + return getRandomType(this, store, rnd); } else { return getRandomNonRecursiveType(this, store, rnd); } } - }; - - return rnd.getMaxDepth() > 0 ? getRandomType(next, store, rnd) : getRandomNonRecursiveType(next, store, rnd); - } - - private Type getRandomNonRecursiveType(Supplier next, TypeStore store, RandomTypesConfig rnd) { - Iterator it = symbolConstructorTypes.values().iterator(); + }; + + return rnd.getMaxDepth() > 0 ? getRandomType(next, store, rnd) : getRandomNonRecursiveType(next, store, rnd); + } + + private Type getRandomNonRecursiveType(Supplier next, TypeStore store, RandomTypesConfig rnd) { + Iterator it = symbolConstructorTypes.values().iterator(); TypeReifier reifier = it.next(); - + while (it.hasNext()) { reifier = it.next(); if (!reifier.isRecursive()) { break; } } - + if (reifier.isRecursive()) { // TODO: I don't understand this return integerType(); @@ -1008,180 +1008,180 @@ private Type getRandomNonRecursiveType(Supplier next, TypeStore store, Ran private Type getRandomType(Supplier next, TypeStore store, RandomTypesConfig rnd) { TypeReifier[] alts = symbolConstructorTypes.values().toArray(new TypeReifier[0]); TypeReifier selected = alts[Math.max(0, alts.length > 0 ? rnd.nextInt(alts.length) - 1 : 0)]; - + // increase the chance of recursive types while (rnd.nextBoolean() && !selected.isRecursive()) { - selected = alts[Math.max(0, rnd.nextInt(alts.length))]; + selected = alts[Math.max(0, rnd.nextInt(alts.length))]; } - + return selected.randomInstance(next, store, rnd); } public boolean isLabel(IConstructor symbol) { - return symbol.getConstructorType() == Symbol_Label; - } - - public String getLabel(IValue symbol) { - assert symbol instanceof IConstructor && isLabel((IConstructor) symbol); - return ((IString) ((IConstructor) symbol).get("name")).getValue(); - } - - public IConstructor labelSymbol(IValueFactory vf, IConstructor symbol, String label) { - return vf.constructor(Symbol_Label, vf.string(label), symbol); - } - - public IConstructor getLabeledSymbol(IValue symbol) { - assert symbol instanceof IConstructor && isLabel((IConstructor) symbol); - return (IConstructor) ((IConstructor) symbol).get("symbol"); - } - - public Type typeSymbolConstructor(String name, Object... args) { - return constructor(symbolStore, symbolADT(), name, args); - } - - public Type typeProductionConstructor(String name, Object... args) { - return constructor(symbolStore, productionADT(), name, args); - } - - public Type symbolADT() { - return abstractDataType(symbolStore, "Symbol"); - } - - public Type attrADT() { - return abstractDataType(symbolStore, "Attr"); - } - - public Type productionADT() { - return abstractDataType(symbolStore, "Production"); - } - - public void initialize() { - try { - Enumeration resources = checkValidClassLoader(getClass().getClassLoader()).getResources(TYPES_CONFIG); - Collections.list(resources).forEach(f -> loadServices(f)); - } catch (IOException e) { - throw new Error("WARNING: Could not load type kind definitions from " + TYPES_CONFIG, e); - } - } - - private ClassLoader checkValidClassLoader(@Nullable ClassLoader cl) { - if (cl == null) { - throw new Error("Could not find class loader due to bootloader loading of this class"); - } - return cl; - } - - private void loadServices(URL nextElement) { - try { - for (String name : readConfigFile(nextElement)) { - name = name.trim(); - - if (name.startsWith("#") || name.isEmpty()) { - // source code comment - continue; - } - - Class clazz = checkValidClassLoader(Thread.currentThread().getContextClassLoader()).loadClass(name); - Object instance = clazz.getConstructor(TypeValues.class).newInstance(this); - - if (instance instanceof TypeReifier) { - registerTypeInfo((TypeReifier) instance); - } - else { - throw new IllegalArgumentException("WARNING: could not load type info " + name + " because it does not implement TypeFactory.TypeInfo"); - } - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException | IllegalArgumentException | SecurityException | IOException | InvocationTargetException | NoSuchMethodException e) { - throw new IllegalArgumentException("WARNING: could not load type info " + nextElement + " due to " + e.getMessage()); - } - } - - private void registerTypeInfo(TypeReifier instance) { - instance.getSymbolConstructorTypes().forEach(x -> symbolConstructorTypes.put(x, instance)); - } - - private String[] readConfigFile(URL nextElement) throws IOException { - try (Reader in = new InputStreamReader(nextElement.openStream())) { - StringBuilder res = new StringBuilder(); - char[] chunk = new char[1024]; - int read; - while ((read = in.read(chunk, 0, chunk.length)) != -1) { - res.append(chunk, 0, read); - } - return res.toString().split("\n"); - } - } - - /** - * Converts a value representing a type back to a type and as a side-effect declares all necessary - * data-types and constructors in the provided typestore. - * - * @param symbol is a constructor generated earlier by Type.asSymbol - * @param store is the typestore to store ADTs, constructors and kw fields in. - * @param grammar is a lookup function to produce definitions for the types to store in the typestore - * @return the type represented by the value - */ - public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - TypeReifier reifier = symbolConstructorTypes.get(symbol.getConstructorType()); - - if (reifier != null) { - return reifier.fromSymbol(symbol, store, grammar); - } - - throw new IllegalArgumentException("trying to construct a type from an unsupported type symbol: " + symbol + ", with this representation: " + symbol.getConstructorType()); - } - - /** - * Builds a tuple type from a list of reified type symbols (see fromSymbol) - */ - public Type fromSymbols(IList symbols, TypeStore store, Function> grammar) { - boolean allLabels = true; - Type[] types = new Type[symbols.length()]; - String[] labels = new String[symbols.length()]; - - for (int i = 0; i < symbols.length(); i++) { - IConstructor elem = (IConstructor) symbols.get(i); - if (elem.getConstructorType() == Symbol_Label) { - labels[i] = ((IString) elem.get("name")).getValue(); - elem = (IConstructor) elem.get("symbol"); - } - else { - allLabels = false; - } - - types[i] = fromSymbol(elem, store, grammar); - } - - if (allLabels) { - return tupleType(types, labels); - } - else { - return tupleType(types); - } - } - } - - /** - * Converts a value representing a type back to a type. - * @param symbol is a constructor generated earlier by Type.asSymbol - * @return the type represented by the value - */ - public Type fromSymbol(IConstructor symbol) { - return cachedTypeValues().fromSymbol(symbol, new TypeStore(), x -> Collections.emptySet()); - } - - public TypeValues cachedTypeValues() { - var result = typeValues; - if (result == null) { - synchronized(this) { - result = typeValues; - if (result == null) { - result = new TypeValues(); - result.initialize(); - typeValues = result; - } - } - } - return result; - } + return symbol.getConstructorType() == Symbol_Label; + } + + public String getLabel(IValue symbol) { + assert symbol instanceof IConstructor && isLabel((IConstructor) symbol); + return ((IString) ((IConstructor) symbol).get("name")).getValue(); + } + + public IConstructor labelSymbol(IValueFactory vf, IConstructor symbol, String label) { + return vf.constructor(Symbol_Label, vf.string(label), symbol); + } + + public IConstructor getLabeledSymbol(IValue symbol) { + assert symbol instanceof IConstructor && isLabel((IConstructor) symbol); + return (IConstructor) ((IConstructor) symbol).get("symbol"); + } + + public Type typeSymbolConstructor(String name, Object... args) { + return constructor(symbolStore, symbolADT(), name, args); + } + + public Type typeProductionConstructor(String name, Object... args) { + return constructor(symbolStore, productionADT(), name, args); + } + + public Type symbolADT() { + return abstractDataType(symbolStore, "Symbol"); + } + + public Type attrADT() { + return abstractDataType(symbolStore, "Attr"); + } + + public Type productionADT() { + return abstractDataType(symbolStore, "Production"); + } + + public void initialize() { + try { + Enumeration resources = checkValidClassLoader(getClass().getClassLoader()).getResources(TYPES_CONFIG); + Collections.list(resources).forEach(f -> loadServices(f)); + } catch (IOException e) { + throw new Error("WARNING: Could not load type kind definitions from " + TYPES_CONFIG, e); + } + } + + private ClassLoader checkValidClassLoader(@Nullable ClassLoader cl) { + if (cl == null) { + throw new Error("Could not find class loader due to bootloader loading of this class"); + } + return cl; + } + + private void loadServices(URL nextElement) { + try { + for (String name : readConfigFile(nextElement)) { + name = name.trim(); + + if (name.startsWith("#") || name.isEmpty()) { + // source code comment + continue; + } + + Class clazz = checkValidClassLoader(Thread.currentThread().getContextClassLoader()).loadClass(name); + Object instance = clazz.getConstructor(TypeValues.class).newInstance(this); + + if (instance instanceof TypeReifier) { + registerTypeInfo((TypeReifier) instance); + } + else { + throw new IllegalArgumentException("WARNING: could not load type info " + name + " because it does not implement TypeFactory.TypeInfo"); + } + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException | IllegalArgumentException | SecurityException | IOException | InvocationTargetException | NoSuchMethodException e) { + throw new IllegalArgumentException("WARNING: could not load type info " + nextElement + " due to " + e.getMessage()); + } + } + + private void registerTypeInfo(TypeReifier instance) { + instance.getSymbolConstructorTypes().forEach(x -> symbolConstructorTypes.put(x, instance)); + } + + private String[] readConfigFile(URL nextElement) throws IOException { + try (Reader in = new InputStreamReader(nextElement.openStream())) { + StringBuilder res = new StringBuilder(); + char[] chunk = new char[1024]; + int read; + while ((read = in.read(chunk, 0, chunk.length)) != -1) { + res.append(chunk, 0, read); + } + return res.toString().split("\n"); + } + } + + /** + * Converts a value representing a type back to a type and as a side-effect declares all necessary + * data-types and constructors in the provided typestore. + * + * @param symbol is a constructor generated earlier by Type.asSymbol + * @param store is the typestore to store ADTs, constructors and kw fields in. + * @param grammar is a lookup function to produce definitions for the types to store in the typestore + * @return the type represented by the value + */ + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { + TypeReifier reifier = symbolConstructorTypes.get(symbol.getConstructorType()); + + if (reifier != null) { + return reifier.fromSymbol(symbol, store, grammar); + } + + throw new IllegalArgumentException("trying to construct a type from an unsupported type symbol: " + symbol + ", with this representation: " + symbol.getConstructorType()); + } + + /** + * Builds a tuple type from a list of reified type symbols (see fromSymbol) + */ + public Type fromSymbols(IList symbols, TypeStore store, Function> grammar) { + boolean allLabels = true; + Type[] types = new Type[symbols.length()]; + String[] labels = new String[symbols.length()]; + + for (int i = 0; i < symbols.length(); i++) { + IConstructor elem = (IConstructor) symbols.get(i); + if (elem.getConstructorType() == Symbol_Label) { + labels[i] = ((IString) elem.get("name")).getValue(); + elem = (IConstructor) elem.get("symbol"); + } + else { + allLabels = false; + } + + types[i] = fromSymbol(elem, store, grammar); + } + + if (allLabels) { + return tupleType(types, labels); + } + else { + return tupleType(types); + } + } + } + + /** + * Converts a value representing a type back to a type. + * @param symbol is a constructor generated earlier by Type.asSymbol + * @return the type represented by the value + */ + public Type fromSymbol(IConstructor symbol) { + return cachedTypeValues().fromSymbol(symbol, new TypeStore(), x -> Collections.emptySet()); + } + + public TypeValues cachedTypeValues() { + var result = typeValues; + if (result == null) { + synchronized(this) { + result = typeValues; + if (result == null) { + result = new TypeValues(); + result.initialize(); + typeValues = result; + } + } + } + return result; + } } diff --git a/src/main/java/io/usethesource/vallang/type/TypeReader.java b/src/main/java/io/usethesource/vallang/type/TypeReader.java index cf5f2e99b..df2e13158 100644 --- a/src/main/java/io/usethesource/vallang/type/TypeReader.java +++ b/src/main/java/io/usethesource/vallang/type/TypeReader.java @@ -15,7 +15,7 @@ public class TypeReader { private static final char END_OF_ARGUMENTS = ']'; private static final char COMMA_SEPARATOR = ','; private static final TypeFactory types = TypeFactory.getInstance(); - + private TypeStore store = new TypeStore(); // dummy guarantees non-nullness private NoWhiteSpaceReader stream = new NoWhiteSpaceReader(new StringReader("")); // dummy guarantees non-nullness private int current; @@ -42,27 +42,27 @@ private Type readType() throws IOException { String id = readIdentifier(); switch (id) { - case "int" : return types.integerType(); - case "real" : return types.realType(); - case "rat" : return types.rationalType(); - case "num" : return types.numberType(); - case "bool" : return types.boolType(); - case "node" : return types.nodeType(); - case "void" : return types.voidType(); - case "value" : return types.valueType(); - case "loc" : return types.sourceLocationType(); - case "str" : return types.stringType(); - case "datetime" : return types.dateTimeType(); + case "int" : return types.integerType(); + case "real" : return types.realType(); + case "rat" : return types.rationalType(); + case "num" : return types.numberType(); + case "bool" : return types.boolType(); + case "node" : return types.nodeType(); + case "void" : return types.voidType(); + case "value" : return types.valueType(); + case "loc" : return types.sourceLocationType(); + case "str" : return types.stringType(); + case "datetime" : return types.dateTimeType(); } if (current == START_OF_ARGUMENTS) { switch (id) { - case "list" : return readComposite((t) -> types.listType(t.get(0))); - case "set" : return readComposite((t) -> types.setType(t.get(0))); - case "map" : return readComposite((t) -> types.mapType(t.get(0), t.get(1))); - case "tuple" : return readComposite((t) -> types.tupleType(t.toArray(new Type[0]))); - case "rel" : return readComposite((t) -> types.relType(t.toArray(new Type[0]))); - case "lrel" : return readComposite((t) -> types.lrelType(t.toArray(new Type[0]))); + case "list" : return readComposite((t) -> types.listType(t.get(0))); + case "set" : return readComposite((t) -> types.setType(t.get(0))); + case "map" : return readComposite((t) -> types.mapType(t.get(0), t.get(1))); + case "tuple" : return readComposite((t) -> types.tupleType(t.toArray(new Type[0]))); + case "rel" : return readComposite((t) -> types.relType(t.toArray(new Type[0]))); + case "lrel" : return readComposite((t) -> types.lrelType(t.toArray(new Type[0]))); } Type adt = store.lookupAbstractDataType(id); @@ -70,7 +70,7 @@ private Type readType() throws IOException { return readComposite((t) -> types.abstractDataType(store, id, t.toArray(new Type[0]))); } - throw new TypeParseError("undeclared type " + id, new NullPointerException()); + throw new TypeParseError("undeclared type " + id, new NullPointerException()); } else { Type adt = store.lookupAbstractDataType(id); @@ -78,7 +78,7 @@ private Type readType() throws IOException { return adt; } - throw new TypeParseError("undeclared type " + id, new NullPointerException()); + throw new TypeParseError("undeclared type " + id, new NullPointerException()); } } @@ -112,7 +112,7 @@ private String readIdentifier() throws IOException { current = stream.read(); } - while (Character.isJavaIdentifierStart(current) + while (Character.isJavaIdentifierStart(current) || Character.isJavaIdentifierPart(current) || (escaped && current == '-')) { builder.append((char) current); diff --git a/src/main/java/io/usethesource/vallang/type/TypeStore.java b/src/main/java/io/usethesource/vallang/type/TypeStore.java index 996d60400..932fe67bb 100644 --- a/src/main/java/io/usethesource/vallang/type/TypeStore.java +++ b/src/main/java/io/usethesource/vallang/type/TypeStore.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: -* Jurgen Vinju (jurgen@vinju.org) +* Jurgen Vinju (jurgen@vinju.org) *******************************************************************************/ package io.usethesource.vallang.type; @@ -34,888 +34,888 @@ import io.usethesource.vallang.exceptions.UndeclaredAbstractDataTypeException; /** - * This class manages type declarations. It stores declarations of keyword fields, - * type aliases and abstract data-type constructors. - * TypeStores can import others, but the imports are not transitive. - * Cyclic imports are allowed. - *

- * @see {@link TypeFactory}, {@link Type} and {@link IValueFactory} for more information. - */ +* This class manages type declarations. It stores declarations of keyword fields, +* type aliases and abstract data-type constructors. +* TypeStores can import others, but the imports are not transitive. +* Cyclic imports are allowed. +*

+* @see {@link TypeFactory}, {@link Type} and {@link IValueFactory} for more information. +*/ public class TypeStore { - private final TypeFactory factory = TypeFactory.getInstance(); - - private final Map fAliases= new HashMap<>(); - private final Map fADTs= new HashMap<>(); - private final Map> fConstructors = new HashMap<>(); - private final Map> fkeywordParameters = new HashMap<>(); - private final Set fImports = new HashSet<>(); - - /* - * The ADTs for which overloading checking is turned off - * (they play a role in the Rascal bootstrap procedure) - */ - static private final java.util.List IGNORE_OVERLOADING_CHECKS = Arrays.asList( - new String[] {"AType", "Grammar", "RuntimeException", "ModuleStatus"}); - - /** - * A type store that is initially empty and imports the given TypeStores. - * Note that imports are not transitive. - */ - public TypeStore(TypeStore... imports) { + private final TypeFactory factory = TypeFactory.getInstance(); + + private final Map fAliases= new HashMap<>(); + private final Map fADTs= new HashMap<>(); + private final Map> fConstructors = new HashMap<>(); + private final Map> fkeywordParameters = new HashMap<>(); + private final Set fImports = new HashSet<>(); + + /* + * The ADTs for which overloading checking is turned off + * (they play a role in the Rascal bootstrap procedure) + */ + static private final java.util.List IGNORE_OVERLOADING_CHECKS = Arrays.asList( + new String[] {"AType", "Grammar", "RuntimeException", "ModuleStatus"}); + + /** + * A type store that is initially empty and imports the given TypeStores. + * Note that imports are not transitive. + */ + public TypeStore(TypeStore... imports) { for (TypeStore s : imports) { - fImports.add(s); - } - } - - @Override - public String toString() { - return "TypeStore(adts=" + fADTs.size() + ",imports=" + fImports.size() + ")"; - } - - /** - * Retrieves all ADT's declared in this TypeStore. Note that it does - * not return the ADT's of imported TypeStores. - */ - public Collection getAbstractDataTypes() { - return Collections.unmodifiableCollection(fADTs.values()); - } - - /** - * Retrieves all aliases declared in this TypeStore. Note that it does - * not return the aliases of imported TypeStores. - */ - public Collection getAliases() { - return Collections.unmodifiableCollection(fAliases.values()); - } - - /** - * Retrieves all keyword parameters declared in this TypeStore. Note that it does - * not return the keyword parameters of imported TypeStores. - * - * @return a map of types for which keyword parameters are declared to a map of names of these - * keyword parameters to the types of the values that give access to these keyword parameters. - */ - public Map> getKeywordParameters() { - Map> unmodifiableMap = new HashMap<>(); - for (Type key : fkeywordParameters.keySet()) { - unmodifiableMap.put(key, Collections.unmodifiableMap(fkeywordParameters.get(key))); - } - return unmodifiableMap; - } - - /** - * Retrieves all constructors declared in this TypeStore. Note that it does - * not return the constructors of imported TypeStores. - */ - public Collection getConstructors() { - Set result = new HashSet<>(); - for (Set adt : fConstructors.values()) { - result.addAll(adt); - } - return Collections.unmodifiableCollection(result); - } - - /** - * Retrieves all imports declared in this TypeStore. Note that it does - * not return the imports of imported TypeStores. - */ - public Collection getImports() { - return Collections.unmodifiableCollection(fImports); - } - - /** - * Add other stores to the set of imported stores. - * Note that imports are not transitive. - * - * @param stores - */ - public void importStore(TypeStore... stores) { - synchronized(fImports) { - for (TypeStore s : stores) { - doImport(s); - } - } - } - - /** - * Removes a number of stores from the imported stores. The stores to be removed must be reference-equal to some of - * the stores imported by the receiver. - * - * @param stores to be removed - */ - public final void unimportStores(TypeStore... stores) { - synchronized (fImports) { - fImports.removeAll(Arrays.asList(stores)); - } - } - - private void doImport(TypeStore s) { - checkOverlappingAliases(s); - checkConstructorOverloading(s); - - fImports.add(s); - } - - /** - * Blindly copy all declaration of the other store into the receiver. - */ - public void extendStore(TypeStore other) { - synchronized (fAliases) { - fAliases.putAll(other.fAliases); - } - - synchronized (fADTs) { - fADTs.putAll(other.fADTs); - } - - synchronized (fConstructors) { - for (Type type : other.fConstructors.keySet()) { - Set set = fConstructors.get(type); - - if (set == null) { - set = new HashSet<>(); - } - - set.addAll(other.fConstructors.get(type)); - fConstructors.put(type, set); - } - } - - synchronized (fkeywordParameters) { - fkeywordParameters.putAll(other.fkeywordParameters); - } - - synchronized (fImports) { - fImports.addAll(other.fImports); - } - } - - private void checkConstructorOverloading(TypeStore s) { - for (Type type : fADTs.values()) { - if(IGNORE_OVERLOADING_CHECKS.contains(type.getName())) continue; - Type other = s.fADTs.get(type.getName()); - if (other != null && other == type) { - Set signature1 = fConstructors.get(type); - Set signature2 = s.fConstructors.get(type); - - if (signature2 == null || signature1 == null) { - continue; // nothing to check - } - - for (Type alt : signature2) { - Type children = alt.getFieldTypes(); - checkOverloading(signature1, alt.getName(), children); - try { - checkFieldNames(signature1, children); - } - catch (RedeclaredFieldNameException e) { - throw new RedeclaredFieldNameException(e.getFieldName(), - e.getFirstType(), e.getSecondType(), - type); - } - } - - } - } - } - - private void checkOverlappingAliases(TypeStore s) { - synchronized (fAliases) { - for (Type alias : fAliases.values()) { - Type other = s.fAliases.get(alias.getName()); - if (other != null && !other.comparable(alias)) { - throw new FactTypeRedeclaredException(alias.getName(), other); - } - } - } - } - - /** - * @return the singleton instance of the {@link TypeFactory} - */ - public TypeFactory getFactory() { - return factory; - } - - /** - * Declare an alias type. The alias may be parameterized to make an abstract alias. - * Each ParameterType embedded in the aliased type should occur in the list of parameters. - * - * @param alias the alias to declare in this store - * @throws FactTypeRedeclaredException - */ - public void declareAlias(Type alias) throws FactTypeDeclarationException { - synchronized (fADTs) { - synchronized (fAliases) { - String name = alias.getName(); - Type oldAdt = lookupAbstractDataType(name); - if (oldAdt != null) { - throw new FactTypeRedeclaredException(name, oldAdt); - } - - Type oldAlias = lookupAlias(name); - - if (oldAlias != null) { - if (oldAlias == alias || (!alias.isOpen() && alias.isSubtypeOf(oldAlias))) { - // instantiating can be ignored. - return; - } - throw new FactTypeRedeclaredException(name, oldAlias); - } - - fAliases.put(name, alias); - } - } - } - - /** - * Declare a @{link AbstractDataType}, which is a kind of tree node. Each kind of tree node - * may have different alternatives, which are ConstructorTypes. A @{link ConstructorType} is always a - * sub-type of a AbstractDataType. A AbstractDataType is always a sub type of value. - * - * @param adt the abstract data-type to declare in this store - * @throws FactTypeRedeclaredException - */ - public void declareAbstractDataType(Type adt) - throws FactTypeDeclarationException { - synchronized (fADTs) { - synchronized (fAliases) { - synchronized (fConstructors) { - String name = adt.getName(); - Type oldAdt = lookupAbstractDataType(name); - - if (oldAdt != null) { - if (adt.comparable(oldAdt) || oldAdt.isExternalType()) { - return; // paramaterized ADT got instantiated, or a double declaration, so don't store. - } - - throw new FactTypeRedeclaredException(name, oldAdt); - } - - Type oldAlias = lookupAlias(name); - if (oldAlias != null) { - throw new FactTypeRedeclaredException(name, oldAlias); - } - - fADTs.put(name, adt); - - if (fConstructors.get(adt) == null) { - fConstructors.put(adt, new HashSet()); - } - } - } - } - } - - /** - * Declare a new constructor type. A constructor type extends an abstract data type such - * that it represents more values. - * - * @param constructor a constructor type - * @throws UndeclaredAbstractDataTypeException, RedeclaredFieldNameException, RedeclaredConstructorException - */ - public void declareConstructor(Type constructor) throws FactTypeDeclarationException { - synchronized (fADTs) { - synchronized(fConstructors) { - Type adt = constructor.getAbstractDataType(); - - Type other = lookupAbstractDataType(adt.getName()); - if (other == null) { - throw new UndeclaredAbstractDataTypeException(adt); - } - - Set signature = lookupAlternatives(adt); - if (signature == null) { - throw new UndeclaredAbstractDataTypeException(adt); - } - - Type constructor1 = expandAliases(constructor); - if(!constructor.equals(constructor1)){ - constructor = constructor1; - } - if(!IGNORE_OVERLOADING_CHECKS.contains(adt.getName())){ - checkOverloading(signature, constructor.getName(), constructor.getFieldTypes()); - try { - checkFieldNames(signature, constructor.getFieldTypes()); - } - catch (RedeclaredFieldNameException e) { - throw new RedeclaredFieldNameException(e.getFieldName(), - e.getFirstType(), e.getSecondType(), - adt); - } - } - - Set localSignature = fConstructors.get(adt); - if (localSignature == null) { - localSignature = new HashSet<>(); - fConstructors.put(adt, localSignature); - - if (!fADTs.containsKey(adt.getName())) { - fADTs.put(adt.getName(), adt); - } - } - - localSignature.add(constructor); - } - } - } - - private void checkFieldNames(Set signature, Type tupleType) { - if (!tupleType.hasFieldNames()) { - return; - } - - for (Type alt : signature) { - Type altArgs = alt.getFieldTypes(); - if (!altArgs.hasFieldNames()) { - continue; - } - for (int i = tupleType.getArity() - 1; i >= 0; i--) { - Type type = tupleType.getFieldType(i); - String label = Objects.requireNonNull(tupleType.getFieldName(i)); - - for (int j = altArgs.getArity() - 1; j >= 0; j--) { - if (label.equals(altArgs.getFieldName(j))) { - if (!altArgs.getFieldType(j).equivalent(type)) { - throw new RedeclaredFieldNameException(label, type, altArgs.getFieldType(j), tupleType); - } - } - } - } - } - } - - private void checkOverloading(Set signature, String name, Type tupleType) throws FactTypeDeclarationException { - for (Type alt : signature) { - if (alt.getName().equals(name)) { - Type fieldTypes = alt.getFieldTypes(); - if (fieldTypes != tupleType && fieldTypes.comparable(tupleType)) { - throw new RedeclaredConstructorException(name, fieldTypes, tupleType); - } - } - } - } - - /** - * Lookup a AliasType that was declared before by name - * @param name the name of the type to lookup - * @return the AliasType - */ - public @Nullable Type lookupAlias(final String name) { - synchronized (fAliases) { - synchronized (fImports) { - Type result = fAliases.get(name); - - if (result == null) { - for (TypeStore i : fImports) { - result = i.fAliases.get(name); - if (result != null) { - return result; - } - } - } - - return result; - } - } - } - - /** - * Returns all alternative ways of constructing a certain abstract data type. - * - * @param adt - * @return all types that construct the given type - */ - public Set lookupAlternatives(Type adt) { - synchronized (fConstructors) { - synchronized (fImports) { - while (adt.isAliased()) { - adt = adt.getAliased(); - } - - Set result = fConstructors.get(adt); - - if (result == null) { - result = new HashSet<>(); - } - - for (TypeStore s : fImports) { - if (s != this) { - Set imported = s.fConstructors.get(adt); - if (imported != null) { - result.addAll(imported); - } - } - } - - return result; - } - } - } - - /** - * Lookup a ConstructorType by name, and in the context of a certain AbstractDataType - * @param adt the AbstractDataType context - * @param constructorName the name of the ConstructorType - * @return a ConstructorType if it was declared before - * @throws a FactTypeError if the type was not declared before - */ - public Set lookupConstructor(Type adt, String constructorName) throws FactTypeUseException { - synchronized (fConstructors) { - synchronized (fImports) { - while (adt.isAliased()) { - adt = adt.getAliased(); - } - Type parameterizedADT = fADTs.get(adt.getName()); - Set local = parameterizedADT != null ? fConstructors.get(parameterizedADT) : null; - Set result = new HashSet<>(); - - if (local != null) { - for (Type cand : local) { - if (cand.getName().equals(constructorName)) { - result.add(cand); - } - } - } - - for (TypeStore i : fImports) { - local = i.fConstructors.get(adt); - if (local != null) { - for (Type cand : local) { - if (cand.getName().equals(constructorName)) { - result.add(cand); - } - } - } - } - - return result; - } - } - } - - /** - * Lookup a ConstructorType by name, across all AbstractDataTypes and for - * a certain list of argument types. - * - * @param constructorName the name of the ConstructorType - * @param args a tuple type defining the arguments of the constructor - * @return the first constructor that matches - * @throws a FactTypeError if the type was not declared before - */ - public @Nullable Type lookupFirstConstructor(final String cons, final Type args) { - Collection adts = allAbstractDataTypes(); - - for (Type adt : adts) { - Type cand = lookupConstructor(adt, cons, args); - if (cand != null) { - return cand; - } - } - - return null; - } - - private Set allAbstractDataTypes() { - synchronized (fADTs) { - synchronized (fImports) { - Set result = new HashSet<>(); - result.addAll(fADTs.values()); - - for (TypeStore s : fImports) { - result.addAll(s.fADTs.values()); - } - - return result; - } - } - } - - /** - * Lookup a ConstructorType by name, and in the context of a certain AbstractDataType - * for a specific list of argument types. - * - * @param adt the AbstractDataType context - * @param constructorName the name of the ConstructorType - * @return a ConstructorType if it was declared before - * @throws a FactTypeError if the type was not declared before - */ - public @Nullable Type lookupConstructor(Type adt, String cons, Type args) { - Set sig = lookupConstructor(adt, cons); - - if (sig != null) { - for (Type cand : sig) { - if (args.isSubtypeOf(cand.getFieldTypes())) { - return cand; - } - } - } - - return null; - } - - /** - * Retrieve all tree node types for a given constructor name, - * regardless of abstract data-type. - * - * @param constructName the name of the tree node - */ - public Set lookupConstructors(String constructorName) { - synchronized (fConstructors) { - synchronized (fImports) { - Set result = new HashSet<>(); - - for (Set adt : fConstructors.values()) { - for (Type cand : adt) { - String name = cand.getName(); - if (name.equals(constructorName)) { - result.add(cand); - } - } - } - - for (TypeStore i : fImports) { - if (i != this) { - for (Set adt : i.fConstructors.values()) { - for (Type cand : adt) { - String name = cand.getName(); - if (name.equals(constructorName)) { - result.add(cand); - } - } - } - } - } - - return result; - } - } - } - - /** - * See if a certain abstract data-type was declared - * @param name the supposed name of the abstract data-type - * @return null if such type does not exist, or the type if it was declared earlier - */ - public @Nullable Type lookupAbstractDataType(String name) { - synchronized (fADTs) { - synchronized (fImports) { - - Type result = fADTs.get(name); - - if (result != null) { - return result; - } - - for (TypeStore s : fImports) { - result = s.fADTs.get(name); - if (result != null) { - return result; - } - } - - return result; - } - } - } - - /** - * Declare that certain constructor types may have an keyword parameter with a certain - * label. The keyword parameter with that label will have a specific type. Note that we - * do not store keyword parameters directly inside the constructor type because keyword - * parameter can be added externally and constructor types are final (like all other types). - * - * @param onType the constructor type of values that carry this keyword parameter - * @param key the label of the keyword parameter - * @param valueType the type of values that represent the keyword parameter - * @throws IllegalKeywordParameterDeclarationException when an attempt is made to define keyword parameter for anything - * but constructor types - */ - public void declareKeywordParameter(Type onType, String key, Type valueType) { - if (!onType.isConstructor() && !onType.isAbstractData()) { - throw new IllegalKeywordParameterDeclarationException(onType); - } - - onType = expandAliases(onType); - - synchronized (fkeywordParameters) { - Map kwParamsForType = fkeywordParameters.get(onType); - - if (!factory.isIdentifier(key)) { - throw new IllegalIdentifierException(key); - } - - if (kwParamsForType == null) { - kwParamsForType = new HashMap<>(); - fkeywordParameters.put(onType, kwParamsForType); - } - - Map declaredEarlier = getKeywordParameters(onType); - - if (!declaredEarlier.containsKey(key)) { - kwParamsForType.put(key, valueType); - } - else if (!declaredEarlier.get(key).equivalent(valueType)) { - throw new RedeclaredKeywordParameterException(key, declaredEarlier.get(key)); - } - // otherwise its a safe re-declaration and we do nothing - } - } - - // TODO: aliases are right now only expanded in declareConstructor, but this should also be done - // in at least declareAlias, declareAnnotation and declareKeywordParameters. - - @Deprecated - /** - * Aliases are deprecated. When we remove this, everything becomes faster. - * @return - */ - private Type expandAliases(Type type) { - return expandAliases1(type, new HashSet()); - } - - private Type expandAliases1 (Type type, Set seen){ - return type.accept(new ITypeVisitor() { - - @Override - public Type visitReal(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitInteger(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitRational(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitList(Type type) throws RuntimeException { - return factory.listType(expandAliases1(type.getElementType(), seen)); - } - - @Override - public Type visitMap(Type type) throws RuntimeException { - return factory.mapType(expandAliases1(type.getKeyType(), seen), expandAliases1(type.getValueType(), seen)); - } - - @Override - public Type visitNumber(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitAlias(Type type) throws RuntimeException { - String aliasName = type.getName(); - if(seen.contains(aliasName)){ - throw new IllegalIdentifierException("Circular alias definition for: " + aliasName); - } - seen.add(aliasName); - return expandAliases1 (type.getAliased(), seen); - } - - @Override - public Type visitSet(Type type) throws RuntimeException { - return factory.setType(expandAliases1 (type.getElementType(), seen)); - } - - @Override - public Type visitSourceLocation(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitString(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitNode(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitConstructor(Type type) throws RuntimeException { - // TODO: this cache is nasty coupling with TypeFactory, but we - // can not call factory.constructor directly because that would produce - // an infinite recursion. - return factory.getFromCache(new ConstructorType(type.getName(), expandAliases1(type.getFieldTypes(), seen), type.getAbstractDataType())); - } - - @Override - public Type visitAbstractData(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitFunction(Type type) throws RuntimeException { - // this call to getFromCache is nasty coupling with TypeFactory, but we - // can not call factory.constructor directly because that would produce - // an infinite recursion. - return factory.getFromCache(new FunctionType(expandAliases1(type.getReturnType(), seen), (TupleType) expandAliases1(type.getFieldTypes(), seen), (TupleType) expandAliases1(type.getKeywordParameterTypes(), seen))); - } - - @SuppressWarnings("deprecation") + fImports.add(s); + } + } + + @Override + public String toString() { + return "TypeStore(adts=" + fADTs.size() + ",imports=" + fImports.size() + ")"; + } + + /** + * Retrieves all ADT's declared in this TypeStore. Note that it does + * not return the ADT's of imported TypeStores. + */ + public Collection getAbstractDataTypes() { + return Collections.unmodifiableCollection(fADTs.values()); + } + + /** + * Retrieves all aliases declared in this TypeStore. Note that it does + * not return the aliases of imported TypeStores. + */ + public Collection getAliases() { + return Collections.unmodifiableCollection(fAliases.values()); + } + + /** + * Retrieves all keyword parameters declared in this TypeStore. Note that it does + * not return the keyword parameters of imported TypeStores. + * + * @return a map of types for which keyword parameters are declared to a map of names of these + * keyword parameters to the types of the values that give access to these keyword parameters. + */ + public Map> getKeywordParameters() { + Map> unmodifiableMap = new HashMap<>(); + for (Type key : fkeywordParameters.keySet()) { + unmodifiableMap.put(key, Collections.unmodifiableMap(fkeywordParameters.get(key))); + } + return unmodifiableMap; + } + + /** + * Retrieves all constructors declared in this TypeStore. Note that it does + * not return the constructors of imported TypeStores. + */ + public Collection getConstructors() { + Set result = new HashSet<>(); + for (Set adt : fConstructors.values()) { + result.addAll(adt); + } + return Collections.unmodifiableCollection(result); + } + + /** + * Retrieves all imports declared in this TypeStore. Note that it does + * not return the imports of imported TypeStores. + */ + public Collection getImports() { + return Collections.unmodifiableCollection(fImports); + } + + /** + * Add other stores to the set of imported stores. + * Note that imports are not transitive. + * + * @param stores + */ + public void importStore(TypeStore... stores) { + synchronized(fImports) { + for (TypeStore s : stores) { + doImport(s); + } + } + } + + /** + * Removes a number of stores from the imported stores. The stores to be removed must be reference-equal to some of + * the stores imported by the receiver. + * + * @param stores to be removed + */ + public final void unimportStores(TypeStore... stores) { + synchronized (fImports) { + fImports.removeAll(Arrays.asList(stores)); + } + } + + private void doImport(TypeStore s) { + checkOverlappingAliases(s); + checkConstructorOverloading(s); + + fImports.add(s); + } + + /** + * Blindly copy all declaration of the other store into the receiver. + */ + public void extendStore(TypeStore other) { + synchronized (fAliases) { + fAliases.putAll(other.fAliases); + } + + synchronized (fADTs) { + fADTs.putAll(other.fADTs); + } + + synchronized (fConstructors) { + for (Type type : other.fConstructors.keySet()) { + Set set = fConstructors.get(type); + + if (set == null) { + set = new HashSet<>(); + } + + set.addAll(other.fConstructors.get(type)); + fConstructors.put(type, set); + } + } + + synchronized (fkeywordParameters) { + fkeywordParameters.putAll(other.fkeywordParameters); + } + + synchronized (fImports) { + fImports.addAll(other.fImports); + } + } + + private void checkConstructorOverloading(TypeStore s) { + for (Type type : fADTs.values()) { + if(IGNORE_OVERLOADING_CHECKS.contains(type.getName())) continue; + Type other = s.fADTs.get(type.getName()); + if (other != null && other == type) { + Set signature1 = fConstructors.get(type); + Set signature2 = s.fConstructors.get(type); + + if (signature2 == null || signature1 == null) { + continue; // nothing to check + } + + for (Type alt : signature2) { + Type children = alt.getFieldTypes(); + checkOverloading(signature1, alt.getName(), children); + try { + checkFieldNames(signature1, children); + } + catch (RedeclaredFieldNameException e) { + throw new RedeclaredFieldNameException(e.getFieldName(), + e.getFirstType(), e.getSecondType(), + type); + } + } + + } + } + } + + private void checkOverlappingAliases(TypeStore s) { + synchronized (fAliases) { + for (Type alias : fAliases.values()) { + Type other = s.fAliases.get(alias.getName()); + if (other != null && !other.comparable(alias)) { + throw new FactTypeRedeclaredException(alias.getName(), other); + } + } + } + } + + /** + * @return the singleton instance of the {@link TypeFactory} + */ + public TypeFactory getFactory() { + return factory; + } + + /** + * Declare an alias type. The alias may be parameterized to make an abstract alias. + * Each ParameterType embedded in the aliased type should occur in the list of parameters. + * + * @param alias the alias to declare in this store + * @throws FactTypeRedeclaredException + */ + public void declareAlias(Type alias) throws FactTypeDeclarationException { + synchronized (fADTs) { + synchronized (fAliases) { + String name = alias.getName(); + Type oldAdt = lookupAbstractDataType(name); + if (oldAdt != null) { + throw new FactTypeRedeclaredException(name, oldAdt); + } + + Type oldAlias = lookupAlias(name); + + if (oldAlias != null) { + if (oldAlias == alias || (!alias.isOpen() && alias.isSubtypeOf(oldAlias))) { + // instantiating can be ignored. + return; + } + throw new FactTypeRedeclaredException(name, oldAlias); + } + + fAliases.put(name, alias); + } + } + } + + /** + * Declare a @{link AbstractDataType}, which is a kind of tree node. Each kind of tree node + * may have different alternatives, which are ConstructorTypes. A @{link ConstructorType} is always a + * sub-type of a AbstractDataType. A AbstractDataType is always a sub type of value. + * + * @param adt the abstract data-type to declare in this store + * @throws FactTypeRedeclaredException + */ + public void declareAbstractDataType(Type adt) + throws FactTypeDeclarationException { + synchronized (fADTs) { + synchronized (fAliases) { + synchronized (fConstructors) { + String name = adt.getName(); + Type oldAdt = lookupAbstractDataType(name); + + if (oldAdt != null) { + if (adt.comparable(oldAdt) || oldAdt.isExternalType()) { + return; // paramaterized ADT got instantiated, or a double declaration, so don't store. + } + + throw new FactTypeRedeclaredException(name, oldAdt); + } + + Type oldAlias = lookupAlias(name); + if (oldAlias != null) { + throw new FactTypeRedeclaredException(name, oldAlias); + } + + fADTs.put(name, adt); + + if (fConstructors.get(adt) == null) { + fConstructors.put(adt, new HashSet()); + } + } + } + } + } + + /** + * Declare a new constructor type. A constructor type extends an abstract data type such + * that it represents more values. + * + * @param constructor a constructor type + * @throws UndeclaredAbstractDataTypeException, RedeclaredFieldNameException, RedeclaredConstructorException + */ + public void declareConstructor(Type constructor) throws FactTypeDeclarationException { + synchronized (fADTs) { + synchronized(fConstructors) { + Type adt = constructor.getAbstractDataType(); + + Type other = lookupAbstractDataType(adt.getName()); + if (other == null) { + throw new UndeclaredAbstractDataTypeException(adt); + } + + Set signature = lookupAlternatives(adt); + if (signature == null) { + throw new UndeclaredAbstractDataTypeException(adt); + } + + Type constructor1 = expandAliases(constructor); + if(!constructor.equals(constructor1)){ + constructor = constructor1; + } + if(!IGNORE_OVERLOADING_CHECKS.contains(adt.getName())){ + checkOverloading(signature, constructor.getName(), constructor.getFieldTypes()); + try { + checkFieldNames(signature, constructor.getFieldTypes()); + } + catch (RedeclaredFieldNameException e) { + throw new RedeclaredFieldNameException(e.getFieldName(), + e.getFirstType(), e.getSecondType(), + adt); + } + } + + Set localSignature = fConstructors.get(adt); + if (localSignature == null) { + localSignature = new HashSet<>(); + fConstructors.put(adt, localSignature); + + if (!fADTs.containsKey(adt.getName())) { + fADTs.put(adt.getName(), adt); + } + } + + localSignature.add(constructor); + } + } + } + + private void checkFieldNames(Set signature, Type tupleType) { + if (!tupleType.hasFieldNames()) { + return; + } + + for (Type alt : signature) { + Type altArgs = alt.getFieldTypes(); + if (!altArgs.hasFieldNames()) { + continue; + } + for (int i = tupleType.getArity() - 1; i >= 0; i--) { + Type type = tupleType.getFieldType(i); + String label = Objects.requireNonNull(tupleType.getFieldName(i)); + + for (int j = altArgs.getArity() - 1; j >= 0; j--) { + if (label.equals(altArgs.getFieldName(j))) { + if (!altArgs.getFieldType(j).equivalent(type)) { + throw new RedeclaredFieldNameException(label, type, altArgs.getFieldType(j), tupleType); + } + } + } + } + } + } + + private void checkOverloading(Set signature, String name, Type tupleType) throws FactTypeDeclarationException { + for (Type alt : signature) { + if (alt.getName().equals(name)) { + Type fieldTypes = alt.getFieldTypes(); + if (fieldTypes != tupleType && fieldTypes.comparable(tupleType)) { + throw new RedeclaredConstructorException(name, fieldTypes, tupleType); + } + } + } + } + + /** + * Lookup a AliasType that was declared before by name + * @param name the name of the type to lookup + * @return the AliasType + */ + public @Nullable Type lookupAlias(final String name) { + synchronized (fAliases) { + synchronized (fImports) { + Type result = fAliases.get(name); + + if (result == null) { + for (TypeStore i : fImports) { + result = i.fAliases.get(name); + if (result != null) { + return result; + } + } + } + + return result; + } + } + } + + /** + * Returns all alternative ways of constructing a certain abstract data type. + * + * @param adt + * @return all types that construct the given type + */ + public Set lookupAlternatives(Type adt) { + synchronized (fConstructors) { + synchronized (fImports) { + while (adt.isAliased()) { + adt = adt.getAliased(); + } + + Set result = fConstructors.get(adt); + + if (result == null) { + result = new HashSet<>(); + } + + for (TypeStore s : fImports) { + if (s != this) { + Set imported = s.fConstructors.get(adt); + if (imported != null) { + result.addAll(imported); + } + } + } + + return result; + } + } + } + + /** + * Lookup a ConstructorType by name, and in the context of a certain AbstractDataType + * @param adt the AbstractDataType context + * @param constructorName the name of the ConstructorType + * @return a ConstructorType if it was declared before + * @throws a FactTypeError if the type was not declared before + */ + public Set lookupConstructor(Type adt, String constructorName) throws FactTypeUseException { + synchronized (fConstructors) { + synchronized (fImports) { + while (adt.isAliased()) { + adt = adt.getAliased(); + } + Type parameterizedADT = fADTs.get(adt.getName()); + Set local = parameterizedADT != null ? fConstructors.get(parameterizedADT) : null; + Set result = new HashSet<>(); + + if (local != null) { + for (Type cand : local) { + if (cand.getName().equals(constructorName)) { + result.add(cand); + } + } + } + + for (TypeStore i : fImports) { + local = i.fConstructors.get(adt); + if (local != null) { + for (Type cand : local) { + if (cand.getName().equals(constructorName)) { + result.add(cand); + } + } + } + } + + return result; + } + } + } + + /** + * Lookup a ConstructorType by name, across all AbstractDataTypes and for + * a certain list of argument types. + * + * @param constructorName the name of the ConstructorType + * @param args a tuple type defining the arguments of the constructor + * @return the first constructor that matches + * @throws a FactTypeError if the type was not declared before + */ + public @Nullable Type lookupFirstConstructor(final String cons, final Type args) { + Collection adts = allAbstractDataTypes(); + + for (Type adt : adts) { + Type cand = lookupConstructor(adt, cons, args); + if (cand != null) { + return cand; + } + } + + return null; + } + + private Set allAbstractDataTypes() { + synchronized (fADTs) { + synchronized (fImports) { + Set result = new HashSet<>(); + result.addAll(fADTs.values()); + + for (TypeStore s : fImports) { + result.addAll(s.fADTs.values()); + } + + return result; + } + } + } + + /** + * Lookup a ConstructorType by name, and in the context of a certain AbstractDataType + * for a specific list of argument types. + * + * @param adt the AbstractDataType context + * @param constructorName the name of the ConstructorType + * @return a ConstructorType if it was declared before + * @throws a FactTypeError if the type was not declared before + */ + public @Nullable Type lookupConstructor(Type adt, String cons, Type args) { + Set sig = lookupConstructor(adt, cons); + + if (sig != null) { + for (Type cand : sig) { + if (args.isSubtypeOf(cand.getFieldTypes())) { + return cand; + } + } + } + + return null; + } + + /** + * Retrieve all tree node types for a given constructor name, + * regardless of abstract data-type. + * + * @param constructName the name of the tree node + */ + public Set lookupConstructors(String constructorName) { + synchronized (fConstructors) { + synchronized (fImports) { + Set result = new HashSet<>(); + + for (Set adt : fConstructors.values()) { + for (Type cand : adt) { + String name = cand.getName(); + if (name.equals(constructorName)) { + result.add(cand); + } + } + } + + for (TypeStore i : fImports) { + if (i != this) { + for (Set adt : i.fConstructors.values()) { + for (Type cand : adt) { + String name = cand.getName(); + if (name.equals(constructorName)) { + result.add(cand); + } + } + } + } + } + + return result; + } + } + } + + /** + * See if a certain abstract data-type was declared + * @param name the supposed name of the abstract data-type + * @return null if such type does not exist, or the type if it was declared earlier + */ + public @Nullable Type lookupAbstractDataType(String name) { + synchronized (fADTs) { + synchronized (fImports) { + + Type result = fADTs.get(name); + + if (result != null) { + return result; + } + + for (TypeStore s : fImports) { + result = s.fADTs.get(name); + if (result != null) { + return result; + } + } + + return result; + } + } + } + + /** + * Declare that certain constructor types may have an keyword parameter with a certain + * label. The keyword parameter with that label will have a specific type. Note that we + * do not store keyword parameters directly inside the constructor type because keyword + * parameter can be added externally and constructor types are final (like all other types). + * + * @param onType the constructor type of values that carry this keyword parameter + * @param key the label of the keyword parameter + * @param valueType the type of values that represent the keyword parameter + * @throws IllegalKeywordParameterDeclarationException when an attempt is made to define keyword parameter for anything + * but constructor types + */ + public void declareKeywordParameter(Type onType, String key, Type valueType) { + if (!onType.isConstructor() && !onType.isAbstractData()) { + throw new IllegalKeywordParameterDeclarationException(onType); + } + + onType = expandAliases(onType); + + synchronized (fkeywordParameters) { + Map kwParamsForType = fkeywordParameters.get(onType); + + if (!factory.isIdentifier(key)) { + throw new IllegalIdentifierException(key); + } + + if (kwParamsForType == null) { + kwParamsForType = new HashMap<>(); + fkeywordParameters.put(onType, kwParamsForType); + } + + Map declaredEarlier = getKeywordParameters(onType); + + if (!declaredEarlier.containsKey(key)) { + kwParamsForType.put(key, valueType); + } + else if (!declaredEarlier.get(key).equivalent(valueType)) { + throw new RedeclaredKeywordParameterException(key, declaredEarlier.get(key)); + } + // otherwise its a safe re-declaration and we do nothing + } + } + + // TODO: aliases are right now only expanded in declareConstructor, but this should also be done + // in at least declareAlias, declareAnnotation and declareKeywordParameters. + + @Deprecated + /** + * Aliases are deprecated. When we remove this, everything becomes faster. + * @return + */ + private Type expandAliases(Type type) { + return expandAliases1(type, new HashSet()); + } + + private Type expandAliases1 (Type type, Set seen){ + return type.accept(new ITypeVisitor() { + + @Override + public Type visitReal(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitInteger(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitRational(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitList(Type type) throws RuntimeException { + return factory.listType(expandAliases1(type.getElementType(), seen)); + } + + @Override + public Type visitMap(Type type) throws RuntimeException { + return factory.mapType(expandAliases1(type.getKeyType(), seen), expandAliases1(type.getValueType(), seen)); + } + + @Override + public Type visitNumber(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitAlias(Type type) throws RuntimeException { + String aliasName = type.getName(); + if(seen.contains(aliasName)){ + throw new IllegalIdentifierException("Circular alias definition for: " + aliasName); + } + seen.add(aliasName); + return expandAliases1 (type.getAliased(), seen); + } + + @Override + public Type visitSet(Type type) throws RuntimeException { + return factory.setType(expandAliases1 (type.getElementType(), seen)); + } + + @Override + public Type visitSourceLocation(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitString(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitNode(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitConstructor(Type type) throws RuntimeException { + // TODO: this cache is nasty coupling with TypeFactory, but we + // can not call factory.constructor directly because that would produce + // an infinite recursion. + return factory.getFromCache(new ConstructorType(type.getName(), expandAliases1(type.getFieldTypes(), seen), type.getAbstractDataType())); + } + + @Override + public Type visitAbstractData(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitFunction(Type type) throws RuntimeException { + // this call to getFromCache is nasty coupling with TypeFactory, but we + // can not call factory.constructor directly because that would produce + // an infinite recursion. + return factory.getFromCache(new FunctionType(expandAliases1(type.getReturnType(), seen), (TupleType) expandAliases1(type.getFieldTypes(), seen), (TupleType) expandAliases1(type.getKeywordParameterTypes(), seen))); + } + + @SuppressWarnings("deprecation") + @Override + public Type visitTuple(Type type) throws RuntimeException { + int arity = type.getArity(); + Type fieldTypes[] = new Type[arity]; + boolean aliasFound = false; + for(int i = 0; i < arity; i++){ + Type fieldType = type.getFieldType(i); + + if(fieldType.isAliased()){ + aliasFound = true; + AliasType alias = (AliasType) fieldType; + fieldType = alias.getAliased(); + } + + Type newFieldType = expandAliases1(fieldType, seen); + aliasFound |= newFieldType != fieldType; + fieldTypes[i] = newFieldType; + } + + if (aliasFound){ + return type.hasFieldNames() ? factory.tupleType(fieldTypes, type.getFieldNames()) : factory.tupleType(fieldTypes); + } + return type; + } + @Override - public Type visitTuple(Type type) throws RuntimeException { - int arity = type.getArity(); - Type fieldTypes[] = new Type[arity]; - boolean aliasFound = false; - for(int i = 0; i < arity; i++){ - Type fieldType = type.getFieldType(i); - - if(fieldType.isAliased()){ - aliasFound = true; - AliasType alias = (AliasType) fieldType; - fieldType = alias.getAliased(); - } - - Type newFieldType = expandAliases1(fieldType, seen); - aliasFound |= newFieldType != fieldType; - fieldTypes[i] = newFieldType; - } - - if (aliasFound){ - return type.hasFieldNames() ? factory.tupleType(fieldTypes, type.getFieldNames()) : factory.tupleType(fieldTypes); - } - return type; - } - - @Override - public Type visitValue(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitVoid(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitBool(Type type) throws RuntimeException { - return type; - } - - @Override - public Type visitParameter(Type type) throws RuntimeException { - return factory.parameterType(type.getName(), expandAliases1(type.getBound(), seen)); - } - - @Override - public Type visitExternal(Type type) throws RuntimeException { - // TODO: it is unclear how aliases in externalTypes can be expanded in an extensible fashion - // (rather than listing all cases here). - return type; - } - - @Override - public Type visitDateTime(Type type) throws RuntimeException { - return type; - } - - }); - } - - /** - * Locates all declared keyword parameters for a constructor. - * - * @param onType - * @return a map of all keyword parameters declared for the onType constructor - */ - public Map getKeywordParameters(Type onType) { - if (!onType.isConstructor() && !onType.isAbstractData()) { - return Collections.emptyMap(); - } - - onType = expandAliases(onType); - - synchronized(fkeywordParameters) { - synchronized (fImports) { - Map result = new HashMap<>(); - - Map local = fkeywordParameters.get(onType); - if (local != null) { - result.putAll(local); - } - - if (onType.isConstructor()) { - local = fkeywordParameters.get(onType.getAbstractDataType()); - if (local != null) { - result.putAll(local); - } - } - - for (TypeStore s : fImports) { - if (s.fkeywordParameters == null) { - continue; - } - Map here = s.fkeywordParameters.get(onType); - if (here != null) { - result.putAll(here); - } - - if (onType.isConstructor()) { - here = s.fkeywordParameters.get(onType.getAbstractDataType()); - if (here != null) { - result.putAll(here); - } - } - } - - return result; - } - } - } - - /** - * Retrieve the type of values that are declared to be valid for a certain kind of - * keyword parameters on certain kinds of values - * @param onType the constructor type that this keyword parameters can be found on - * @param key the label of the parameter to find the corresponding type of - * @return the type of the requested parameter value or null if none exists - */ - public @Nullable Type getKeywordParameterType(Type onType, String key) { - assert onType.isConstructor() || onType.isAbstractData(); - Map kwParamsFor = getKeywordParameters(onType); - return kwParamsFor != null ? kwParamsFor.get(key) : null; - } - - public boolean hasKeywordParameters(Type onType) { - if (!onType.isConstructor()) { - return false; - } - - synchronized(fkeywordParameters) { - synchronized (fImports) { - Map local = fkeywordParameters.get(onType); - if (local != null && local.size() > 0) { - return true; - } - - for (TypeStore s : fImports) { - if (s.fkeywordParameters == null) { - continue; - } - - Map here = s.fkeywordParameters.get(onType); - if (here != null && here.size() > 0) { - return true; - } - } - - return false; - } - } - } - - public boolean hasKeywordParameter(Type onType, String label) { + public Type visitValue(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitVoid(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitBool(Type type) throws RuntimeException { + return type; + } + + @Override + public Type visitParameter(Type type) throws RuntimeException { + return factory.parameterType(type.getName(), expandAliases1(type.getBound(), seen)); + } + + @Override + public Type visitExternal(Type type) throws RuntimeException { + // TODO: it is unclear how aliases in externalTypes can be expanded in an extensible fashion + // (rather than listing all cases here). + return type; + } + + @Override + public Type visitDateTime(Type type) throws RuntimeException { + return type; + } + + }); + } + + /** + * Locates all declared keyword parameters for a constructor. + * + * @param onType + * @return a map of all keyword parameters declared for the onType constructor + */ + public Map getKeywordParameters(Type onType) { + if (!onType.isConstructor() && !onType.isAbstractData()) { + return Collections.emptyMap(); + } + + onType = expandAliases(onType); + + synchronized(fkeywordParameters) { + synchronized (fImports) { + Map result = new HashMap<>(); + + Map local = fkeywordParameters.get(onType); + if (local != null) { + result.putAll(local); + } + + if (onType.isConstructor()) { + local = fkeywordParameters.get(onType.getAbstractDataType()); + if (local != null) { + result.putAll(local); + } + } + + for (TypeStore s : fImports) { + if (s.fkeywordParameters == null) { + continue; + } + Map here = s.fkeywordParameters.get(onType); + if (here != null) { + result.putAll(here); + } + + if (onType.isConstructor()) { + here = s.fkeywordParameters.get(onType.getAbstractDataType()); + if (here != null) { + result.putAll(here); + } + } + } + + return result; + } + } + } + + /** + * Retrieve the type of values that are declared to be valid for a certain kind of + * keyword parameters on certain kinds of values + * @param onType the constructor type that this keyword parameters can be found on + * @param key the label of the parameter to find the corresponding type of + * @return the type of the requested parameter value or null if none exists + */ + public @Nullable Type getKeywordParameterType(Type onType, String key) { + assert onType.isConstructor() || onType.isAbstractData(); + Map kwParamsFor = getKeywordParameters(onType); + return kwParamsFor != null ? kwParamsFor.get(key) : null; + } + + public boolean hasKeywordParameters(Type onType) { if (!onType.isConstructor()) { return false; } - + + synchronized(fkeywordParameters) { + synchronized (fImports) { + Map local = fkeywordParameters.get(onType); + if (local != null && local.size() > 0) { + return true; + } + + for (TypeStore s : fImports) { + if (s.fkeywordParameters == null) { + continue; + } + + Map here = s.fkeywordParameters.get(onType); + if (here != null && here.size() > 0) { + return true; + } + } + + return false; + } + } + } + + public boolean hasKeywordParameter(Type onType, String label) { + if (!onType.isConstructor()) { + return false; + } + onType = expandAliases(onType); synchronized(fkeywordParameters) { @@ -924,22 +924,22 @@ public boolean hasKeywordParameter(Type onType, String label) { if (local != null && local.containsKey(label)) { return true; } - + local = fkeywordParameters.get(onType.getAbstractDataType()); if (local != null && local.containsKey(label)) { return true; } - + for (TypeStore s : fImports) { if (s.fkeywordParameters == null) { continue; } - + Map here = s.fkeywordParameters.get(onType); if (here != null && here.containsKey(label)) { return true; } - + here = s.fkeywordParameters.get(onType.getAbstractDataType()); if (here != null && here.containsKey(label)) { return true; @@ -951,24 +951,24 @@ public boolean hasKeywordParameter(Type onType, String label) { } } - public @Nullable Type getAlias(String name) { - synchronized (fAliases) { - synchronized (fImports) { - Type result = fAliases.get(name); + public @Nullable Type getAlias(String name) { + synchronized (fAliases) { + synchronized (fImports) { + Type result = fAliases.get(name); - if (result != null) { - return result; - } + if (result != null) { + return result; + } - for (TypeStore s : fImports) { - result = s.fAliases.get(name); - if (result != null) { - return result; - } - } + for (TypeStore s : fImports) { + result = s.fAliases.get(name); + if (result != null) { + return result; + } + } - return null; - } - } - } + return null; + } + } + } } diff --git a/src/main/java/io/usethesource/vallang/type/ValueType.java b/src/main/java/io/usethesource/vallang/type/ValueType.java index 32d8d209b..a84ed3084 100644 --- a/src/main/java/io/usethesource/vallang/type/ValueType.java +++ b/src/main/java/io/usethesource/vallang/type/ValueType.java @@ -27,345 +27,345 @@ import io.usethesource.vallang.type.TypeFactory.TypeValues; /* package */class ValueType extends Type { - - protected static class InstanceHolder { - public static final ValueType sInstance = new ValueType(); - } - - public static ValueType getInstance() { - return InstanceHolder.sInstance; - } - - public static class Info extends TypeFactory.TypeReifier { - public Info(TypeValues symbols) { - super(symbols); - } - - @Override - public Type getSymbolConstructorType() { - return symbols().typeSymbolConstructor("value"); - } - - @Override - public Type fromSymbol(IConstructor symbol, TypeStore store, + + protected static class InstanceHolder { + public static final ValueType sInstance = new ValueType(); + } + + public static ValueType getInstance() { + return InstanceHolder.sInstance; + } + + public static class Info extends TypeFactory.TypeReifier { + public Info(TypeValues symbols) { + super(symbols); + } + + @Override + public Type getSymbolConstructorType() { + return symbols().typeSymbolConstructor("value"); + } + + @Override + public Type fromSymbol(IConstructor symbol, TypeStore store, Function> grammar) { - return getInstance(); - } - - @Override - public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { - return tf().valueType(); - } - } - - - @Override - public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { - return new Info(symbols); - } - - @Override - public String toString() { - return "value"; - } - - /** - * Should never be called, ValueType is a singleton - */ - @Override - public boolean equals(@Nullable Object o) { - return o == ValueType.getInstance(); - } - - @Override - public int hashCode() { - return 2141; - } - - @Override - public T accept(ITypeVisitor visitor) throws E { - return visitor.visitValue(this); - } - - @Override - public Type lub(Type other) { - return other.lubWithValue(this); - } - - @Override - public Type glb(Type type) { - return type.glbWithValue(this); - } - - @Override - public boolean intersects(Type other) { - return other.intersectsWithValue(this); - } - - @Override - public boolean isTop() { - return true; - } - - @Override - protected boolean isSupertypeOf(Type type) { - return type.isSubtypeOfValue(this); - } - - @Override - protected boolean isSubtypeOfValue(Type type) { - return true; - } - - @Override - protected boolean isSubtypeOfReal(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfInteger(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfRational(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfList(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfMap(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfNumber(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfSet(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfSourceLocation(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfString(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfNode(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfConstructor(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfAbstractData(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfTuple(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfFunction(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfVoid(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfBool(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfExternal(Type type) { - return false; - } - - @Override - protected boolean isSubtypeOfDateTime(Type type) { - return false; - } - - @Override - protected Type lubWithValue(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithReal(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithInteger(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithRational(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithList(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithMap(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithNumber(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithSet(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithSourceLocation(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithString(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithNode(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithConstructor(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithAbstractData(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithTuple(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithFunction(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithVoid(Type type) { - /* this is for the semantics of the sub-classes of ValueType - * the lub with void for any type should be that other type - * and not value. - */ - return this; - } - - protected Type lubWithBool(Type type) { - return ValueType.getInstance(); - } - - protected Type lubWithDateTime(Type type) { - return ValueType.getInstance(); - } - - @Override - protected Type glbWithValue(Type type) { - return this; // such that sub-classes do not have to override - } - - protected Type glbWithReal(Type type) { - return type; - } - - protected Type glbWithInteger(Type type) { - return type; - } - - protected Type glbWithRational(Type type) { - return type; - } - - protected Type glbWithList(Type type) { - return type; - } - - protected Type glbWithMap(Type type) { - return type; - } - - protected Type glbWithNumber(Type type) { - return type; - } - - protected Type glbWithRelation(Type type) { - return type; - } - - protected Type glbWithListRelation(Type type) { - return type; - } - - protected Type glbWithSet(Type type) { - return type; - } - - protected Type glbWithSourceLocation(Type type) { - return type; - } - - protected Type glbWithString(Type type) { - return type; - } - - protected Type glbWithNode(Type type) { - return type; - } - - protected Type glbWithConstructor(Type type) { - return type; - } - - protected Type glbWithAbstractData(Type type) { - return type; - } - - protected Type glbWithTuple(Type type) { - return type; - } - - protected Type glbWithFunction(Type type) { - return type; - } - - protected Type glbWithVoid(Type type) { - return type; - } - - protected Type glbWithBool(Type type) { - return type; - } - - protected Type glbWithDateTime(Type type) { - return type; - } - - @Override + return getInstance(); + } + + @Override + public Type randomInstance(Supplier next, TypeStore store, RandomTypesConfig rnd) { + return tf().valueType(); + } + } + + + @Override + public TypeFactory.TypeReifier getTypeReifier(TypeValues symbols) { + return new Info(symbols); + } + + @Override + public String toString() { + return "value"; + } + + /** + * Should never be called, ValueType is a singleton + */ + @Override + public boolean equals(@Nullable Object o) { + return o == ValueType.getInstance(); + } + + @Override + public int hashCode() { + return 2141; + } + + @Override + public T accept(ITypeVisitor visitor) throws E { + return visitor.visitValue(this); + } + + @Override + public Type lub(Type other) { + return other.lubWithValue(this); + } + + @Override + public Type glb(Type type) { + return type.glbWithValue(this); + } + + @Override + public boolean intersects(Type other) { + return other.intersectsWithValue(this); + } + + @Override + public boolean isTop() { + return true; + } + + @Override + protected boolean isSupertypeOf(Type type) { + return type.isSubtypeOfValue(this); + } + + @Override + protected boolean isSubtypeOfValue(Type type) { + return true; + } + + @Override + protected boolean isSubtypeOfReal(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfInteger(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfRational(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfList(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfMap(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfNumber(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfSet(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfSourceLocation(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfString(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfNode(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfConstructor(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfAbstractData(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfTuple(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfFunction(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfVoid(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfBool(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfExternal(Type type) { + return false; + } + + @Override + protected boolean isSubtypeOfDateTime(Type type) { + return false; + } + + @Override + protected Type lubWithValue(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithReal(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithInteger(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithRational(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithList(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithMap(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithNumber(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithSet(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithSourceLocation(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithString(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithNode(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithConstructor(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithAbstractData(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithTuple(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithFunction(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithVoid(Type type) { + /* this is for the semantics of the sub-classes of ValueType + * the lub with void for any type should be that other type + * and not value. + */ + return this; + } + + protected Type lubWithBool(Type type) { + return ValueType.getInstance(); + } + + protected Type lubWithDateTime(Type type) { + return ValueType.getInstance(); + } + + @Override + protected Type glbWithValue(Type type) { + return this; // such that sub-classes do not have to override + } + + protected Type glbWithReal(Type type) { + return type; + } + + protected Type glbWithInteger(Type type) { + return type; + } + + protected Type glbWithRational(Type type) { + return type; + } + + protected Type glbWithList(Type type) { + return type; + } + + protected Type glbWithMap(Type type) { + return type; + } + + protected Type glbWithNumber(Type type) { + return type; + } + + protected Type glbWithRelation(Type type) { + return type; + } + + protected Type glbWithListRelation(Type type) { + return type; + } + + protected Type glbWithSet(Type type) { + return type; + } + + protected Type glbWithSourceLocation(Type type) { + return type; + } + + protected Type glbWithString(Type type) { + return type; + } + + protected Type glbWithNode(Type type) { + return type; + } + + protected Type glbWithConstructor(Type type) { + return type; + } + + protected Type glbWithAbstractData(Type type) { + return type; + } + + protected Type glbWithTuple(Type type) { + return type; + } + + protected Type glbWithFunction(Type type) { + return type; + } + + protected Type glbWithVoid(Type type) { + return type; + } + + protected Type glbWithBool(Type type) { + return type; + } + + protected Type glbWithDateTime(Type type) { + return type; + } + + @Override protected boolean intersectsWithValue(Type type) { return true; // such that sub-classes do not have to override } @@ -428,9 +428,9 @@ protected boolean intersectsWithAbstractData(Type type) { protected boolean intersectsWithTuple(Type type) { return true; - } - - protected boolean intersectsWithFunction(Type type) { + } + + protected boolean intersectsWithFunction(Type type) { return true; } @@ -445,17 +445,17 @@ protected boolean intersectsWithBool(Type type) { protected boolean intersectsWithDateTime(Type type) { return true; } - - @Override - public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, - int maxDepth, int maxWidth) { - Type type; - RandomTypesConfig cfg = RandomTypesConfig.defaultConfig(random).maxDepth(maxDepth).withoutRandomAbstractDatatypes(); - - do { + + @Override + public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map typeParameters, + int maxDepth, int maxWidth) { + Type type; + RandomTypesConfig cfg = RandomTypesConfig.defaultConfig(random).maxDepth(maxDepth).withoutRandomAbstractDatatypes(); + + do { type = TypeFactory.getInstance().randomType(store, cfg); - } while (type.isBottom()); - + } while (type.isBottom()); + return type.randomValue(random, vf, store, typeParameters, maxDepth, maxWidth); - } + } } diff --git a/src/main/java/io/usethesource/vallang/type/VoidType.java b/src/main/java/io/usethesource/vallang/type/VoidType.java index ac40ce1a0..11b2731a7 100644 --- a/src/main/java/io/usethesource/vallang/type/VoidType.java +++ b/src/main/java/io/usethesource/vallang/type/VoidType.java @@ -30,7 +30,7 @@ /** * The void type represents an empty collection of values. I.e. it is a subtype * of all types, the bottom of the type hierarchy. - * + * * This type does not have any values with it naturally and can, for example, be * used to elegantly initialize computations that involve least upper bounds. */ @@ -444,7 +444,7 @@ public boolean intersects(Type other) { // void is the empty type so its intersections are always empty return false; } - + @Override protected Type glbWithReal(Type type) { return this; @@ -545,7 +545,7 @@ public IValue randomValue(Random random, IValueFactory vf, TypeStore store, Map< int maxDepth, int maxWidth) { throw new UnsupportedOperationException("void can not be instantiated"); } - + @Override public boolean isBottom() { return true; diff --git a/src/main/java/io/usethesource/vallang/util/AbstractTypeBag.java b/src/main/java/io/usethesource/vallang/util/AbstractTypeBag.java index c228f3c24..13871baa6 100644 --- a/src/main/java/io/usethesource/vallang/util/AbstractTypeBag.java +++ b/src/main/java/io/usethesource/vallang/util/AbstractTypeBag.java @@ -7,7 +7,7 @@ * * Contributors: * - * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI + * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package io.usethesource.vallang.util; @@ -40,7 +40,7 @@ public abstract class AbstractTypeBag implements Cloneable { public abstract AbstractTypeBag decrease(Type t); public abstract Type lub(); - + public abstract int sum(); public abstract AbstractTypeBag clone(); @@ -133,14 +133,14 @@ public AbstractTypeBag decrease(Type t) { @Override public int sum() { int total = 0; - + for (Entry entry : countMap.entrySet()) { total += entry.getValue(); } - + return total; } - + @Override public Type lub() { if (cachedLub == null) { @@ -178,13 +178,13 @@ public boolean equals(@Nullable Object o) { if (this == o) { return true; } - + if (o == null || getClass() != o.getClass()) { return false; } - + TypeBag typeBag = (TypeBag) o; - + return countMap.equals(typeBag.countMap); } } diff --git a/src/main/java/io/usethesource/vallang/util/HashConsingMap.java b/src/main/java/io/usethesource/vallang/util/HashConsingMap.java index 1dc4ff055..cecdae83f 100644 --- a/src/main/java/io/usethesource/vallang/util/HashConsingMap.java +++ b/src/main/java/io/usethesource/vallang/util/HashConsingMap.java @@ -1,15 +1,15 @@ -/** +/** * Copyright (c) 2017, Davy Landman, SWAT.engineering - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.util; /** @@ -17,12 +17,12 @@ * @author Davy Landman */ public interface HashConsingMap { - /** - * Lookup the hash-consed value for this key (using the hash-code-equals contract for equality). - * - * The containers will take care of multi-threading concerns. - * @param key key to lookup, will either be inserted and returned, or an older reference that is {@link #equals()} to this instance. - * @return a non-null reference to something that is equal to key - */ + /** + * Lookup the hash-consed value for this key (using the hash-code-equals contract for equality). + * + * The containers will take care of multi-threading concerns. + * @param key key to lookup, will either be inserted and returned, or an older reference that is {@link #equals()} to this instance. + * @return a non-null reference to something that is equal to key + */ T get(T key); } diff --git a/src/main/java/io/usethesource/vallang/util/RotatingQueue.java b/src/main/java/io/usethesource/vallang/util/RotatingQueue.java index dc469cdb1..2f349956f 100644 --- a/src/main/java/io/usethesource/vallang/util/RotatingQueue.java +++ b/src/main/java/io/usethesource/vallang/util/RotatingQueue.java @@ -13,99 +13,99 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** - * A simple (fast) queue. - * - * @author Arnold Lankamp - * - * @param The value type. - */ +* A simple (fast) queue. +* +* @author Arnold Lankamp +* +* @param The value type. +*/ public final class RotatingQueue{ - private final static int DEFAULT_CAPACITY = 16; - private final static int DEFAULT_CAPACITY_MASK = DEFAULT_CAPACITY - 1; - + private final static int DEFAULT_CAPACITY = 16; + private final static int DEFAULT_CAPACITY_MASK = DEFAULT_CAPACITY - 1; + private @Nullable T[] queue; private int capacity; private int capacityMask; private int nextPutIndex; private int getIndex; - + /** - * Constructor. - */ + * Constructor. + */ @SuppressWarnings("unchecked") public RotatingQueue(){ - super(); + super(); - capacity = DEFAULT_CAPACITY; - capacityMask = DEFAULT_CAPACITY_MASK; + capacity = DEFAULT_CAPACITY; + capacityMask = DEFAULT_CAPACITY_MASK; - queue = (T[]) new Object[capacity]; + queue = (T[]) new Object[capacity]; - nextPutIndex = 1; - getIndex = 0; + nextPutIndex = 1; + getIndex = 0; } - + private void ensureCapacity(){ - if(nextPutIndex == getIndex){ - int size = capacity; - capacity <<= 1; - capacityMask = capacity - 1; - @SuppressWarnings("unchecked") - T[] newQueue = (T[]) new Object[capacity]; - if(getIndex == 0){ - System.arraycopy(queue, 0, newQueue, 0, queue.length); - - nextPutIndex = size; - }else{ - int numElemsTillEnd = size - getIndex; - System.arraycopy(queue, getIndex, newQueue, 0, numElemsTillEnd); - System.arraycopy(queue, 0, newQueue, numElemsTillEnd, getIndex); - - getIndex = 0; - nextPutIndex = size; - } - - queue = newQueue; + if(nextPutIndex == getIndex){ + int size = capacity; + capacity <<= 1; + capacityMask = capacity - 1; + @SuppressWarnings("unchecked") + T[] newQueue = (T[]) new Object[capacity]; + if(getIndex == 0){ + System.arraycopy(queue, 0, newQueue, 0, queue.length); + + nextPutIndex = size; + }else{ + int numElemsTillEnd = size - getIndex; + System.arraycopy(queue, getIndex, newQueue, 0, numElemsTillEnd); + System.arraycopy(queue, 0, newQueue, numElemsTillEnd, getIndex); + + getIndex = 0; + nextPutIndex = size; } + + queue = newQueue; + } } - + /** - * Enqueues the given element. - * - * @param element - * The element to enqueue. - */ + * Enqueues the given element. + * + * @param element + * The element to enqueue. + */ public void put(T element){ - ensureCapacity(); + ensureCapacity(); - queue[nextPutIndex] = element; + queue[nextPutIndex] = element; - nextPutIndex = (nextPutIndex + 1) & capacityMask; + nextPutIndex = (nextPutIndex + 1) & capacityMask; } - + /** - * Check if the queue contains any elements. - * - * @return True if the queue contains any elements; false otherwise. - */ + * Check if the queue contains any elements. + * + * @return True if the queue contains any elements; false otherwise. + */ public boolean isEmpty(){ - return (nextPutIndex == ((getIndex + 1) & capacityMask)); + return (nextPutIndex == ((getIndex + 1) & capacityMask)); } - + /** - * Returns and removes the next element from the queue. - * - * @return The next element from the queue; null if the queue was empty. - */ + * Returns and removes the next element from the queue. + * + * @return The next element from the queue; null if the queue was empty. + */ public @Nullable T get(){ - if(isEmpty()) { - return null; - } + if(isEmpty()) { + return null; + } - getIndex = (getIndex + 1) & capacityMask; - T element = queue[getIndex]; - queue[getIndex] = null; + getIndex = (getIndex + 1) & capacityMask; + T element = queue[getIndex]; + queue[getIndex] = null; - return element; + return element; } -} \ No newline at end of file +} diff --git a/src/main/java/io/usethesource/vallang/util/SecondsTicker.java b/src/main/java/io/usethesource/vallang/util/SecondsTicker.java index 23e0d89b9..36d89be1d 100644 --- a/src/main/java/io/usethesource/vallang/util/SecondsTicker.java +++ b/src/main/java/io/usethesource/vallang/util/SecondsTicker.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2020, Davy Landman, swat.engineering - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2020, Davy Landman, swat.engineering + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.util; import java.util.concurrent.CompletableFuture; @@ -23,7 +23,7 @@ public class SecondsTicker { private static volatile int tick = 0; - + private static void doTick() { CompletableFuture .delayedExecutor(1, TimeUnit.SECONDS) @@ -35,7 +35,7 @@ private static void doTick() { // start the ticker doTick(); } - + /** * Get a monotonic increasing integer that increments roughly every second */ diff --git a/src/main/java/io/usethesource/vallang/util/ShareableList.java b/src/main/java/io/usethesource/vallang/util/ShareableList.java index 98e2f9fd7..1d1fc6a0f 100644 --- a/src/main/java/io/usethesource/vallang/util/ShareableList.java +++ b/src/main/java/io/usethesource/vallang/util/ShareableList.java @@ -29,663 +29,663 @@ * -reverse * Additionally both cloning this list as the sublist operation are relatively cheap, * (two simple arraycopies). - * + * * @author Arnold Lankamp * * @param * The element type. */ public class ShareableList implements Iterable<@NonNull E>{ - private final static int INITIAL_LOG_SIZE = 2; - - private int frontCapacity; - private @Nullable E[] frontData; - private int frontIndex; - - private int backCapacity; - private @Nullable E[] backData; - private int backIndex; - - /** - * Default constructor - */ - @SuppressWarnings("unchecked") + private final static int INITIAL_LOG_SIZE = 2; + + private int frontCapacity; + private @Nullable E[] frontData; + private int frontIndex; + + private int backCapacity; + private @Nullable E[] backData; + private int backIndex; + + /** + * Default constructor + */ + @SuppressWarnings("unchecked") public ShareableList(){ - super(); - - frontCapacity = 1 << INITIAL_LOG_SIZE; - frontData = (E[]) new Object[frontCapacity]; - frontIndex = 0; - - backCapacity = 1 << INITIAL_LOG_SIZE; - backData = (E[]) new Object[backCapacity]; - backIndex = 0; - } - - /** - * Copy constructor. - * - * @param shareableList - * The list to copy. - */ - public ShareableList(ShareableList shareableList){ - super(); - - frontCapacity = shareableList.frontCapacity; - frontData = shareableList.frontData.clone(); - frontIndex = shareableList.frontIndex; - - backCapacity = shareableList.backCapacity; - backData = shareableList.backData.clone(); - backIndex = shareableList.backIndex; - } - - /** - * SubList copy constructor. - * - * @param shareableList - * The list to copy. - * @param offset - * The start index of the sublist. - * @param length - * The length of the sublist. - */ - @SuppressWarnings("unchecked") + super(); + + frontCapacity = 1 << INITIAL_LOG_SIZE; + frontData = (E[]) new Object[frontCapacity]; + frontIndex = 0; + + backCapacity = 1 << INITIAL_LOG_SIZE; + backData = (E[]) new Object[backCapacity]; + backIndex = 0; + } + + /** + * Copy constructor. + * + * @param shareableList + * The list to copy. + */ + public ShareableList(ShareableList shareableList){ + super(); + + frontCapacity = shareableList.frontCapacity; + frontData = shareableList.frontData.clone(); + frontIndex = shareableList.frontIndex; + + backCapacity = shareableList.backCapacity; + backData = shareableList.backData.clone(); + backIndex = shareableList.backIndex; + } + + /** + * SubList copy constructor. + * + * @param shareableList + * The list to copy. + * @param offset + * The start index of the sublist. + * @param length + * The length of the sublist. + */ + @SuppressWarnings("unchecked") protected ShareableList(ShareableList shareableList, int offset, int length){ - super(); - - int backStartIndex = shareableList.backIndex - offset; - if(backStartIndex <= 0){// Front only - backIndex = 0; - backCapacity = 2; - backData = (E[]) new Object[backCapacity]; - - int frontStartIndex = -backStartIndex; - - frontIndex = length; - frontCapacity = closestPowerOfTwo(length); - frontData = (E[]) new Object[frontCapacity]; - System.arraycopy(shareableList.frontData, frontStartIndex, frontData, 0, length); - }else{ - if((offset + length) <= shareableList.backIndex){ // Back only - backIndex = length; - backCapacity = closestPowerOfTwo(length); - backData = (E[]) new Object[backCapacity]; - System.arraycopy(shareableList.backData, backStartIndex - length, backData, 0, length); - - frontIndex = 0; - frontCapacity = 2; - frontData = (E[]) new Object[frontCapacity]; - }else{ // Front and Back overlap - backIndex = backStartIndex; - backCapacity = closestPowerOfTwo(backStartIndex); - backData = (E[]) new Object[backCapacity]; - System.arraycopy(shareableList.backData, 0, backData, 0, backStartIndex); - - int frontLength = length - backStartIndex; - - frontIndex = frontLength; - frontCapacity = closestPowerOfTwo(frontLength); - frontData = (E[]) new Object[frontCapacity]; - System.arraycopy(shareableList.frontData, 0, frontData, 0, frontLength); - } - } - } - - private static int closestPowerOfTwo(int v){ - // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - if(v <= 2){ - return 2; - } - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return v + 1; - } - - /** - * Removes all the elements from this list. - */ - @SuppressWarnings("unchecked") + super(); + + int backStartIndex = shareableList.backIndex - offset; + if(backStartIndex <= 0){// Front only + backIndex = 0; + backCapacity = 2; + backData = (E[]) new Object[backCapacity]; + + int frontStartIndex = -backStartIndex; + + frontIndex = length; + frontCapacity = closestPowerOfTwo(length); + frontData = (E[]) new Object[frontCapacity]; + System.arraycopy(shareableList.frontData, frontStartIndex, frontData, 0, length); + }else{ + if((offset + length) <= shareableList.backIndex){ // Back only + backIndex = length; + backCapacity = closestPowerOfTwo(length); + backData = (E[]) new Object[backCapacity]; + System.arraycopy(shareableList.backData, backStartIndex - length, backData, 0, length); + + frontIndex = 0; + frontCapacity = 2; + frontData = (E[]) new Object[frontCapacity]; + }else{ // Front and Back overlap + backIndex = backStartIndex; + backCapacity = closestPowerOfTwo(backStartIndex); + backData = (E[]) new Object[backCapacity]; + System.arraycopy(shareableList.backData, 0, backData, 0, backStartIndex); + + int frontLength = length - backStartIndex; + + frontIndex = frontLength; + frontCapacity = closestPowerOfTwo(frontLength); + frontData = (E[]) new Object[frontCapacity]; + System.arraycopy(shareableList.frontData, 0, frontData, 0, frontLength); + } + } + } + + private static int closestPowerOfTwo(int v){ + // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + if(v <= 2){ + return 2; + } + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return v + 1; + } + + /** + * Removes all the elements from this list. + */ + @SuppressWarnings("unchecked") public void clear(){ - frontCapacity = 1 << INITIAL_LOG_SIZE; - frontData = (E[]) new Object[frontCapacity]; - frontIndex = 0; - - backCapacity = 1 << INITIAL_LOG_SIZE; - backData = (E[]) new Object[backCapacity]; - backIndex = 0; - } - - /** - * Calling this will guarantee that there is enough space for the next single element insert. - */ - private void ensureFrontCapacity(){ - if(frontCapacity == frontIndex){ - frontCapacity <<= 1; - @SuppressWarnings("unchecked") + frontCapacity = 1 << INITIAL_LOG_SIZE; + frontData = (E[]) new Object[frontCapacity]; + frontIndex = 0; + + backCapacity = 1 << INITIAL_LOG_SIZE; + backData = (E[]) new Object[backCapacity]; + backIndex = 0; + } + + /** + * Calling this will guarantee that there is enough space for the next single element insert. + */ + private void ensureFrontCapacity(){ + if(frontCapacity == frontIndex){ + frontCapacity <<= 1; + @SuppressWarnings("unchecked") E[] newFrontData = (E[]) new Object[frontCapacity]; - System.arraycopy(frontData, 0, newFrontData, 0, frontData.length); - frontData = newFrontData; - } - } - - /** - * Calling this will guarantee that there is enough space for the next single element append. - */ - private void ensureBackCapacity(){ - if(backCapacity == backIndex){ - backCapacity <<= 1; - @SuppressWarnings("unchecked") + System.arraycopy(frontData, 0, newFrontData, 0, frontData.length); + frontData = newFrontData; + } + } + + /** + * Calling this will guarantee that there is enough space for the next single element append. + */ + private void ensureBackCapacity(){ + if(backCapacity == backIndex){ + backCapacity <<= 1; + @SuppressWarnings("unchecked") E[] newBackData = (E[]) new Object[backCapacity]; - System.arraycopy(backData, 0, newBackData, 0, backData.length); - backData = newBackData; - } - } - - /** - * Calling this will guarantee that there is enough space for the next batch of inserted elements. - * - * @param nrOfElements - * The amount of free space that is required. - */ - private void ensureFrontBulkCapacity(int nrOfElements){ - int requiredCapacity = frontIndex + nrOfElements; - if(frontCapacity <= requiredCapacity){ - do{ - frontCapacity <<= 1; - }while(frontCapacity <= requiredCapacity); - - @SuppressWarnings("unchecked") + System.arraycopy(backData, 0, newBackData, 0, backData.length); + backData = newBackData; + } + } + + /** + * Calling this will guarantee that there is enough space for the next batch of inserted elements. + * + * @param nrOfElements + * The amount of free space that is required. + */ + private void ensureFrontBulkCapacity(int nrOfElements){ + int requiredCapacity = frontIndex + nrOfElements; + if(frontCapacity <= requiredCapacity){ + do{ + frontCapacity <<= 1; + }while(frontCapacity <= requiredCapacity); + + @SuppressWarnings("unchecked") E[] newFrontData = (E[]) new Object[frontCapacity]; - System.arraycopy(frontData, 0, newFrontData, 0, frontData.length); - frontData = newFrontData; - } - } - - /** - * Calling this will guarantee that there is enough space for the next batch of appended elements. - * - * @param nrOfElements - * The amount of free space that is required. - */ - private void ensureBackBulkCapacity(int nrOfElements){ - int requiredCapacity = backIndex + nrOfElements; - - if(backCapacity <= requiredCapacity){ - do{ - backCapacity <<= 1; - }while(backCapacity <= requiredCapacity); - - @SuppressWarnings("unchecked") + System.arraycopy(frontData, 0, newFrontData, 0, frontData.length); + frontData = newFrontData; + } + } + + /** + * Calling this will guarantee that there is enough space for the next batch of appended elements. + * + * @param nrOfElements + * The amount of free space that is required. + */ + private void ensureBackBulkCapacity(int nrOfElements){ + int requiredCapacity = backIndex + nrOfElements; + + if(backCapacity <= requiredCapacity){ + do{ + backCapacity <<= 1; + }while(backCapacity <= requiredCapacity); + + @SuppressWarnings("unchecked") E[] newBackData = (E[]) new Object[backCapacity]; - System.arraycopy(backData, 0, newBackData, 0, backData.length); - backData = newBackData; - } - } - - /** - * Appends the given element to the end of this list. - * - * @param element - * The element to append. - */ - public void append(E element){ - ensureFrontCapacity(); - - frontData[frontIndex++] = element; - } - - /** - * Appends the given batch of element to the end of this list. - * - * @param elements - * The batch of elements to append. - */ - public void appendAll(E[] elements){ - int nrOfElements = elements.length; - - ensureFrontBulkCapacity(nrOfElements); - - System.arraycopy(elements, 0, frontData, frontIndex, nrOfElements); - frontIndex += nrOfElements; - } - - /** - * Appends the indicated range of elements from the given batch of elements to the end of this - * list. - * - * @param elements - * The batch that contains the elements to append. - * @param offset - * The position in the given batch to start at. - * @param length - * The number of elements from the given batch to append. - */ - public void appendAllAt(E[] elements, int offset, int length){ - if(offset < 0) throw new IllegalArgumentException("Offset must be > 0."); - if((offset + length) > elements.length) throw new IllegalArgumentException("(offset + length) must be <= elements.length."); - - ensureFrontBulkCapacity(length); - - System.arraycopy(elements, offset, frontData, frontIndex, length); - frontIndex += length; - } - - /** - * Inserts the given element to the start of this list. - * - * @param element - * The element to insert. - */ - public void insert(E element){ - ensureBackCapacity(); - - backData[backIndex++] = element; - } - - /** - * Inserts the given batch of elements to the start of this list. - * - * @param elements - * The batch of elements to insert. - */ - public void insertAll(E[] elements){ - int nrOfElements = elements.length; - - ensureBackBulkCapacity(nrOfElements); - - for(int i = nrOfElements - 1; i >= 0; i--){ - backData[backIndex++] = elements[i]; - } - } - - /** - * Inserts the given element at the indicated position in this list. - * - * @param index - * The index to insert the element at. - * @param element - * The element to insert. - */ - public void insertAt(int index, E element){ - int realIndex = index - backIndex; - if(realIndex >= 0){ - ensureFrontCapacity(); - - if(realIndex > frontIndex) throw new ArrayIndexOutOfBoundsException(index+" > the the current size of the list ("+size()+")"); - - int elementsToMove = frontIndex - realIndex; - System.arraycopy(frontData, realIndex, frontData, realIndex + 1, elementsToMove); - frontData[realIndex] = element; - frontIndex++; - }else{ - ensureBackCapacity(); - - realIndex = 0 - realIndex; - - if(realIndex > backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); - - int elementsToMove = backIndex - realIndex; - System.arraycopy(backData, realIndex, backData, realIndex + 1, elementsToMove); - backData[realIndex] = element; - backIndex++; - } - } - - /** - * Replaces the element at the indicated position in this list by the given element. - * - * @param index - * The index to replace the element at. - * @param element - * The element to place at the indicated position. - * @return The element that was located at the indicated position prior to the execution of this - * operation. - */ - public E set(int index, E element){ - int realIndex = index - backIndex; - if(realIndex >= 0){ - if(realIndex >= frontIndex) throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); - - E oldElement = frontData[realIndex]; - frontData[realIndex] = element; - return nonNull(oldElement); - } - - realIndex = -1 - realIndex; - - if(realIndex >= backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); - - E oldElement = backData[realIndex]; - backData[realIndex] = element; - - return nonNull(oldElement); - } - - private E nonNull(@Nullable E result) { - if (result == null) { - throw new RuntimeException("Internal error, value that should never be null, is null"); - } - return result; - } - - /** - * Retrieves the element at the indicated position from this list. - * - * @param index - * The position to retrieve the element from. - * @return The retrieved element. - */ - public E get(int index){ - int realIndex = index - backIndex; - if(realIndex >= 0){ - if(realIndex >= frontIndex) { - throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); - } - - return nonNull(frontData[realIndex]); - } - - realIndex = -1 - realIndex; - - if (realIndex >= backIndex) { - throw new ArrayIndexOutOfBoundsException(index+" < 0"); - } - - return nonNull(backData[realIndex]); - } - - /** - * Removes the element at the indicated position from this list. - * - * @param index - * The position to remove the element from. - * @return The element that was located at the indicated position prior to the execution of - * this operation. - */ - public E remove(int index){ - int realIndex = index - backIndex; - if(realIndex >= 0){ - if (realIndex >= frontIndex) { - throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); - } - - E oldElement = nonNull(frontData[realIndex]); - - int elementsToMove = --frontIndex - realIndex; - if (elementsToMove > 0) { - System.arraycopy(frontData, realIndex + 1, frontData, realIndex, elementsToMove); - } - frontData[frontIndex] = null; // Remove the 'old' reference at the end of the array. - - return oldElement; - } - - realIndex = -1 - realIndex; - - if(realIndex >= backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); - - E oldElement = nonNull(backData[realIndex]); - - int elementsToMove = --backIndex - realIndex; - if (elementsToMove > 0) { - System.arraycopy(backData, realIndex + 1, backData, realIndex, elementsToMove); - } - backData[backIndex] = null; // Remove the 'old' reference at the end of the array. - - return oldElement; - } - - /** - * Constructs a sublist of this list. - * - * @param offset - * The offset to start at. - * @param length - * The number of elements. - * @return The constructed sublist. - */ - public ShareableList subList(int offset, int length){ - if(offset < 0) { - throw new IndexOutOfBoundsException("Offset may not be smaller then 0."); - } - if(length < 0) { - throw new IndexOutOfBoundsException("Length may not be smaller then 0."); - } - if((offset + length) > size()) { - throw new IndexOutOfBoundsException("'offset + length' may not be larger then 'list.size()'"); - } - - return new ShareableList<>(this, offset, length); - } - - /** - * Reverses the order of the elements in this list. - * - * @return A reference to this list. - */ - public ShareableList reverse(){ - int tempCapacity = frontCapacity; - @Nullable E[] tempData = frontData; - int tempIndex = frontIndex; - - frontCapacity = backCapacity; - frontData = backData; - frontIndex = backIndex; - - backCapacity = tempCapacity; - backData = tempData; - backIndex = tempIndex; - - return this; - } - - /** - * Returns the number of elements that are currently present in this list. - * - * @return The number of elements that are currently present in this list. - */ - public int size(){ - return (frontIndex + backIndex); - } - - /** - * Checks whether or not this list is empty. - * - * @return True if this list is empty; false otherwise. - */ - public boolean isEmpty(){ - return (size() == 0); - } - - /** - * Constructs an iterator for this list. - * - * @return An iterator for this list. - * - * @see java.lang.Iterable#iterator() - */ - public Iterator<@NonNull E> iterator(){ - return new ListIterator(this); - } - - /** - * Computes the current hash code of this list. - * - * @return The current hash code of this list. - * - * @see java.lang.Object#hashCode() - */ - public int hashCode(){ - int hash = 0; - - Iterator<@NonNull E> iterator = iterator(); - while(iterator.hasNext()){ - E element = iterator.next(); - hash = (hash << 1) ^ element.hashCode(); - } - - return hash; - } - - /** - * Check whether or not the current content of this list is equal to that of the given object / list. - * - * @return True if the content of this list is equal to the given object / list. - * - * @see java.lang.Object#equals(Object) - */ - public boolean equals(@Nullable Object o){ - if (o == null) { - return false; - } - - if (o.getClass() == getClass()) { - ShareableList other = (ShareableList) o; - - if (other.size() == size()) { - if (isEmpty()) { - return true; // No need to check if the lists are empty. - } - - Iterator<@NonNull E> thisIterator = iterator(); - Iterator<@NonNull ?> otherIterator = other.iterator(); - - while (thisIterator.hasNext()) { - if (!thisIterator.next().equals(otherIterator.next())) { - return false; - } - } - return true; - } - } - - return false; - } - - /** - * Prints the internal representation of this list to a string. - * - * @see java.lang.Object#toString() - */ - public String toString(){ - StringBuilder buffer = new StringBuilder(); - - buffer.append('['); - - Iterator iterator = iterator(); - if(iterator.hasNext()){ - E element = iterator.next(); - buffer.append(element); - - while(iterator.hasNext()){ - element = iterator.next(); - - buffer.append(','); - buffer.append(element); - } - } - - buffer.append(']'); - - return buffer.toString(); - } - - /** - * Iterator for this list. - * - * @author Arnold Lankamp - * - * @param - * The element type. - */ - private static class ListIterator implements Iterator<@NonNull E>{ - private final ShareableList shareableList; - - private int currentIndex; - private boolean front; - - /** - * Constructor. - * - * @param shareableList - * The list to iterator over. - */ - public ListIterator(ShareableList shareableList){ - super(); - - this.shareableList = shareableList; - - currentIndex = shareableList.backIndex - 1; - front = false; - if (currentIndex < 0) { - currentIndex = 0; - front = true; - } - } - - private @NonNull E nonNull(@Nullable E result) { - if (result == null) { - throw new RuntimeException("Internal error, value that should never be null, is null"); - } - return result; - } - - /** - * Check whether or not there are more elements in this iteration. - * - * @return True if there are more element in this iteration. - * - * @see java.util.Iterator#hasNext() - */ - public boolean hasNext(){ - return front ? (currentIndex < shareableList.frontIndex) : (currentIndex >= 0); - } - - /** - * Returns the next element in this iteration. - * - * @return The next element in this iteration. - * @throws java.util.NoSuchElementException - * Thrown when there are no more elements in this iteration when calling this - * method. - * - * @see java.util.Iterator#next() - */ - public @NonNull E next(){ - if(!hasNext()) { - throw new NoSuchElementException("There are no more elements in this iteration."); - } - - E element; - - if (front) { - element = nonNull(shareableList.frontData[currentIndex++]); - } else { - element = nonNull(shareableList.backData[currentIndex--]); - - if(currentIndex == -1){ - front = true; - currentIndex = 0; - } - } - - return element; - } - - /** - * This iterator does not support removal. - * - * @throws java.lang.UnsupportedOperationException - * - * @see java.util.Iterator#remove() - */ - public void remove(){ - throw new UnsupportedOperationException("This iterator doesn't support removal."); - } - } + System.arraycopy(backData, 0, newBackData, 0, backData.length); + backData = newBackData; + } + } + + /** + * Appends the given element to the end of this list. + * + * @param element + * The element to append. + */ + public void append(E element){ + ensureFrontCapacity(); + + frontData[frontIndex++] = element; + } + + /** + * Appends the given batch of element to the end of this list. + * + * @param elements + * The batch of elements to append. + */ + public void appendAll(E[] elements){ + int nrOfElements = elements.length; + + ensureFrontBulkCapacity(nrOfElements); + + System.arraycopy(elements, 0, frontData, frontIndex, nrOfElements); + frontIndex += nrOfElements; + } + + /** + * Appends the indicated range of elements from the given batch of elements to the end of this + * list. + * + * @param elements + * The batch that contains the elements to append. + * @param offset + * The position in the given batch to start at. + * @param length + * The number of elements from the given batch to append. + */ + public void appendAllAt(E[] elements, int offset, int length){ + if(offset < 0) throw new IllegalArgumentException("Offset must be > 0."); + if((offset + length) > elements.length) throw new IllegalArgumentException("(offset + length) must be <= elements.length."); + + ensureFrontBulkCapacity(length); + + System.arraycopy(elements, offset, frontData, frontIndex, length); + frontIndex += length; + } + + /** + * Inserts the given element to the start of this list. + * + * @param element + * The element to insert. + */ + public void insert(E element){ + ensureBackCapacity(); + + backData[backIndex++] = element; + } + + /** + * Inserts the given batch of elements to the start of this list. + * + * @param elements + * The batch of elements to insert. + */ + public void insertAll(E[] elements){ + int nrOfElements = elements.length; + + ensureBackBulkCapacity(nrOfElements); + + for(int i = nrOfElements - 1; i >= 0; i--){ + backData[backIndex++] = elements[i]; + } + } + + /** + * Inserts the given element at the indicated position in this list. + * + * @param index + * The index to insert the element at. + * @param element + * The element to insert. + */ + public void insertAt(int index, E element){ + int realIndex = index - backIndex; + if(realIndex >= 0){ + ensureFrontCapacity(); + + if(realIndex > frontIndex) throw new ArrayIndexOutOfBoundsException(index+" > the the current size of the list ("+size()+")"); + + int elementsToMove = frontIndex - realIndex; + System.arraycopy(frontData, realIndex, frontData, realIndex + 1, elementsToMove); + frontData[realIndex] = element; + frontIndex++; + }else{ + ensureBackCapacity(); + + realIndex = 0 - realIndex; + + if(realIndex > backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); + + int elementsToMove = backIndex - realIndex; + System.arraycopy(backData, realIndex, backData, realIndex + 1, elementsToMove); + backData[realIndex] = element; + backIndex++; + } + } + + /** + * Replaces the element at the indicated position in this list by the given element. + * + * @param index + * The index to replace the element at. + * @param element + * The element to place at the indicated position. + * @return The element that was located at the indicated position prior to the execution of this + * operation. + */ + public E set(int index, E element){ + int realIndex = index - backIndex; + if(realIndex >= 0){ + if(realIndex >= frontIndex) throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); + + E oldElement = frontData[realIndex]; + frontData[realIndex] = element; + return nonNull(oldElement); + } + + realIndex = -1 - realIndex; + + if(realIndex >= backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); + + E oldElement = backData[realIndex]; + backData[realIndex] = element; + + return nonNull(oldElement); + } + + private E nonNull(@Nullable E result) { + if (result == null) { + throw new RuntimeException("Internal error, value that should never be null, is null"); + } + return result; + } + + /** + * Retrieves the element at the indicated position from this list. + * + * @param index + * The position to retrieve the element from. + * @return The retrieved element. + */ + public E get(int index){ + int realIndex = index - backIndex; + if(realIndex >= 0){ + if(realIndex >= frontIndex) { + throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); + } + + return nonNull(frontData[realIndex]); + } + + realIndex = -1 - realIndex; + + if (realIndex >= backIndex) { + throw new ArrayIndexOutOfBoundsException(index+" < 0"); + } + + return nonNull(backData[realIndex]); + } + + /** + * Removes the element at the indicated position from this list. + * + * @param index + * The position to remove the element from. + * @return The element that was located at the indicated position prior to the execution of + * this operation. + */ + public E remove(int index){ + int realIndex = index - backIndex; + if(realIndex >= 0){ + if (realIndex >= frontIndex) { + throw new ArrayIndexOutOfBoundsException(index+" >= the current size of the list ("+size()+")"); + } + + E oldElement = nonNull(frontData[realIndex]); + + int elementsToMove = --frontIndex - realIndex; + if (elementsToMove > 0) { + System.arraycopy(frontData, realIndex + 1, frontData, realIndex, elementsToMove); + } + frontData[frontIndex] = null; // Remove the 'old' reference at the end of the array. + + return oldElement; + } + + realIndex = -1 - realIndex; + + if(realIndex >= backIndex) throw new ArrayIndexOutOfBoundsException(index+" < 0"); + + E oldElement = nonNull(backData[realIndex]); + + int elementsToMove = --backIndex - realIndex; + if (elementsToMove > 0) { + System.arraycopy(backData, realIndex + 1, backData, realIndex, elementsToMove); + } + backData[backIndex] = null; // Remove the 'old' reference at the end of the array. + + return oldElement; + } + + /** + * Constructs a sublist of this list. + * + * @param offset + * The offset to start at. + * @param length + * The number of elements. + * @return The constructed sublist. + */ + public ShareableList subList(int offset, int length){ + if(offset < 0) { + throw new IndexOutOfBoundsException("Offset may not be smaller then 0."); + } + if(length < 0) { + throw new IndexOutOfBoundsException("Length may not be smaller then 0."); + } + if((offset + length) > size()) { + throw new IndexOutOfBoundsException("'offset + length' may not be larger then 'list.size()'"); + } + + return new ShareableList<>(this, offset, length); + } + + /** + * Reverses the order of the elements in this list. + * + * @return A reference to this list. + */ + public ShareableList reverse(){ + int tempCapacity = frontCapacity; + @Nullable E[] tempData = frontData; + int tempIndex = frontIndex; + + frontCapacity = backCapacity; + frontData = backData; + frontIndex = backIndex; + + backCapacity = tempCapacity; + backData = tempData; + backIndex = tempIndex; + + return this; + } + + /** + * Returns the number of elements that are currently present in this list. + * + * @return The number of elements that are currently present in this list. + */ + public int size(){ + return (frontIndex + backIndex); + } + + /** + * Checks whether or not this list is empty. + * + * @return True if this list is empty; false otherwise. + */ + public boolean isEmpty(){ + return (size() == 0); + } + + /** + * Constructs an iterator for this list. + * + * @return An iterator for this list. + * + * @see java.lang.Iterable#iterator() + */ + public Iterator<@NonNull E> iterator(){ + return new ListIterator(this); + } + + /** + * Computes the current hash code of this list. + * + * @return The current hash code of this list. + * + * @see java.lang.Object#hashCode() + */ + public int hashCode(){ + int hash = 0; + + Iterator<@NonNull E> iterator = iterator(); + while(iterator.hasNext()){ + E element = iterator.next(); + hash = (hash << 1) ^ element.hashCode(); + } + + return hash; + } + + /** + * Check whether or not the current content of this list is equal to that of the given object / list. + * + * @return True if the content of this list is equal to the given object / list. + * + * @see java.lang.Object#equals(Object) + */ + public boolean equals(@Nullable Object o){ + if (o == null) { + return false; + } + + if (o.getClass() == getClass()) { + ShareableList other = (ShareableList) o; + + if (other.size() == size()) { + if (isEmpty()) { + return true; // No need to check if the lists are empty. + } + + Iterator<@NonNull E> thisIterator = iterator(); + Iterator<@NonNull ?> otherIterator = other.iterator(); + + while (thisIterator.hasNext()) { + if (!thisIterator.next().equals(otherIterator.next())) { + return false; + } + } + return true; + } + } + + return false; + } + + /** + * Prints the internal representation of this list to a string. + * + * @see java.lang.Object#toString() + */ + public String toString(){ + StringBuilder buffer = new StringBuilder(); + + buffer.append('['); + + Iterator iterator = iterator(); + if(iterator.hasNext()){ + E element = iterator.next(); + buffer.append(element); + + while(iterator.hasNext()){ + element = iterator.next(); + + buffer.append(','); + buffer.append(element); + } + } + + buffer.append(']'); + + return buffer.toString(); + } + + /** + * Iterator for this list. + * + * @author Arnold Lankamp + * + * @param + * The element type. + */ + private static class ListIterator implements Iterator<@NonNull E>{ + private final ShareableList shareableList; + + private int currentIndex; + private boolean front; + + /** + * Constructor. + * + * @param shareableList + * The list to iterator over. + */ + public ListIterator(ShareableList shareableList){ + super(); + + this.shareableList = shareableList; + + currentIndex = shareableList.backIndex - 1; + front = false; + if (currentIndex < 0) { + currentIndex = 0; + front = true; + } + } + + private @NonNull E nonNull(@Nullable E result) { + if (result == null) { + throw new RuntimeException("Internal error, value that should never be null, is null"); + } + return result; + } + + /** + * Check whether or not there are more elements in this iteration. + * + * @return True if there are more element in this iteration. + * + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext(){ + return front ? (currentIndex < shareableList.frontIndex) : (currentIndex >= 0); + } + + /** + * Returns the next element in this iteration. + * + * @return The next element in this iteration. + * @throws java.util.NoSuchElementException + * Thrown when there are no more elements in this iteration when calling this + * method. + * + * @see java.util.Iterator#next() + */ + public @NonNull E next(){ + if(!hasNext()) { + throw new NoSuchElementException("There are no more elements in this iteration."); + } + + E element; + + if (front) { + element = nonNull(shareableList.frontData[currentIndex++]); + } else { + element = nonNull(shareableList.backData[currentIndex--]); + + if(currentIndex == -1){ + front = true; + currentIndex = 0; + } + } + + return element; + } + + /** + * This iterator does not support removal. + * + * @throws java.lang.UnsupportedOperationException + * + * @see java.util.Iterator#remove() + */ + public void remove(){ + throw new UnsupportedOperationException("This iterator doesn't support removal."); + } + } } diff --git a/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java b/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java index 0bb159d43..140c07a78 100644 --- a/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java +++ b/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java @@ -1,15 +1,15 @@ -/** +/** * Copyright (c) 2017, Davy Landman, SWAT.engineering -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ package io.usethesource.vallang.util; import java.lang.ref.Reference; @@ -29,7 +29,7 @@ * A Hash Consing implementation that uses weak references for old entries, to clear memory in case values are not needed anymore. * It is safe to use in a multi-threaded context, and will always return the same reference, even in a race between multiple threads. *

-* +* * @author Davy Landman */ public class WeakReferenceHashConsingMap implements HashConsingMap { @@ -40,17 +40,17 @@ public class WeakReferenceHashConsingMap implements H */ private static class WeakReferenceWrap extends WeakReference { private final int hash; - + public WeakReferenceWrap(T referent, int hash, ReferenceQueue cleared) { super(referent, cleared); this.hash = hash; } - + @Override public int hashCode() { return hash; } - + @Override public boolean equals(@Nullable Object obj) { if (obj == this) { @@ -107,29 +107,29 @@ public boolean equals(@Nullable Object obj) { } - - /** + + /** * We keep the most recently used entries in a simple open addressing map for quick access * In case of hash collisions, the entry is overwritten, which doesn't matter too much * The cleanup happens in a side thread. - * - * Note that even though everything is using atomic operations, + * + * Note that even though everything is using atomic operations, * threads can have different views on the contents of the hotEntries array. * This is not a problem, as it acts like a thread local LRU in that case. - * + * * The coldEntries is the only map that should keep the state consistent across threads. */ private final HotEntry[] hotEntries; private final int mask; - /** + /** * All entries are also stored in a WeakReference, this helps with clearing memory * if entries are not referenced anymore */ - private final ReferenceQueue queue = new ReferenceQueue<>(); + private final ReferenceQueue queue = new ReferenceQueue<>(); private final Map> coldEntries; - - + + public WeakReferenceHashConsingMap() { this(16, (int)TimeUnit.MINUTES.toSeconds(30)); } @@ -141,17 +141,17 @@ public WeakReferenceHashConsingMap(int size, int demoteAfterSeconds) { } // size should be a power of two size = Integer.highestOneBit(size - 1) << 1; - hotEntries = new HotEntry[size]; + hotEntries = new HotEntry[size]; this.mask = size - 1; coldEntries = new ConcurrentHashMap<>(size); - + cleanup(demoteAfterSeconds, hotEntries, coldEntries, queue); } - - + + private static void cleanup(int demoteAfterSeconds, @Nullable HotEntry[] hotEntries, Map> coldEntries, - ReferenceQueue queue) { + ReferenceQueue queue) { try { final int now = SecondsTicker.current(); for (int i = 0; i < hotEntries.length; i++) { @@ -197,7 +197,7 @@ public T get(T key) { return hotEntry.value; } - // fast path, it' already in cold, + // fast path, it' already in cold, // we avoid making a new weak reference just for search var fastGet = coldEntries.get(new LookupKey<>(key, hash)); T result = fastGet == null ? null : fastGet.get(); diff --git a/src/main/java/io/usethesource/vallang/visitors/BottomUpTransformer.java b/src/main/java/io/usethesource/vallang/visitors/BottomUpTransformer.java index e266cd75a..b4a627549 100644 --- a/src/main/java/io/usethesource/vallang/visitors/BottomUpTransformer.java +++ b/src/main/java/io/usethesource/vallang/visitors/BottomUpTransformer.java @@ -26,75 +26,75 @@ import io.usethesource.vallang.IValueFactory; /** - * This visitor will apply another visitor in a bottom-up fashion to an IValue + * This visitor will apply another visitor in a bottom-up fashion to an IValue * */ public class BottomUpTransformer extends VisitorAdapter { - protected IValueFactory fFactory; - - public BottomUpTransformer(IValueVisitor visitor, IValueFactory factory) { - super(visitor); - this.fFactory = factory; - } - - @Override - public IValue visitNode(INode o) throws E { - for (int i = 0; i < o.arity(); i++) { - o = o.set(i, o.get(i).accept(this)); - } - return fVisitor.visitNode(o); - } - - @Override - public IValue visitConstructor(IConstructor o) throws E { - for (int i = 0; i < o.arity(); i++) { - o = o.set(i, o.get(i).accept(this)); - } - - return fVisitor.visitConstructor(o); - } - - @Override - public IValue visitList(IList o) throws E { - IListWriter w = fFactory.listWriter(); - for (IValue elem : o) { - w.append(elem.accept(this)); - } - - return fVisitor.visitList(w.done()); - } - - @Override - public IValue visitSet(ISet o) throws E { - ISetWriter w = fFactory.setWriter(); - for (IValue elem : o) { - w.insert(elem.accept(this)); - } - - return fVisitor.visitSet(w.done()); - } - - @Override - public IValue visitMap(IMap o) throws E { - IMapWriter w = fFactory.mapWriter(); - for (Entry entry : (Iterable>) () -> o.entryIterator()) { - w.put(entry.getKey().accept(this), entry.getValue().accept(this)); - } - - return fVisitor.visitMap(w.done()); - } - - @Override - public IValue visitTuple(ITuple o) throws E { - for (int i = 0; i < o.arity(); i++) { - o = o.set(i, o.get(i).accept(this)); - } - - return fVisitor.visitTuple(o); - } - - @Override - public IValue visitExternal(IExternalValue externalValue) throws E { - return fVisitor.visitExternal(externalValue); - } + protected IValueFactory fFactory; + + public BottomUpTransformer(IValueVisitor visitor, IValueFactory factory) { + super(visitor); + this.fFactory = factory; + } + + @Override + public IValue visitNode(INode o) throws E { + for (int i = 0; i < o.arity(); i++) { + o = o.set(i, o.get(i).accept(this)); + } + return fVisitor.visitNode(o); + } + + @Override + public IValue visitConstructor(IConstructor o) throws E { + for (int i = 0; i < o.arity(); i++) { + o = o.set(i, o.get(i).accept(this)); + } + + return fVisitor.visitConstructor(o); + } + + @Override + public IValue visitList(IList o) throws E { + IListWriter w = fFactory.listWriter(); + for (IValue elem : o) { + w.append(elem.accept(this)); + } + + return fVisitor.visitList(w.done()); + } + + @Override + public IValue visitSet(ISet o) throws E { + ISetWriter w = fFactory.setWriter(); + for (IValue elem : o) { + w.insert(elem.accept(this)); + } + + return fVisitor.visitSet(w.done()); + } + + @Override + public IValue visitMap(IMap o) throws E { + IMapWriter w = fFactory.mapWriter(); + for (Entry entry : (Iterable>) () -> o.entryIterator()) { + w.put(entry.getKey().accept(this), entry.getValue().accept(this)); + } + + return fVisitor.visitMap(w.done()); + } + + @Override + public IValue visitTuple(ITuple o) throws E { + for (int i = 0; i < o.arity(); i++) { + o = o.set(i, o.get(i).accept(this)); + } + + return fVisitor.visitTuple(o); + } + + @Override + public IValue visitExternal(IExternalValue externalValue) throws E { + return fVisitor.visitExternal(externalValue); + } } diff --git a/src/main/java/io/usethesource/vallang/visitors/BottomUpVisitor.java b/src/main/java/io/usethesource/vallang/visitors/BottomUpVisitor.java index 3657bf7ef..a708f1f54 100644 --- a/src/main/java/io/usethesource/vallang/visitors/BottomUpVisitor.java +++ b/src/main/java/io/usethesource/vallang/visitors/BottomUpVisitor.java @@ -27,76 +27,76 @@ import io.usethesource.vallang.IValueFactory; /** - * This visitor will apply another visitor in a bottom-up fashion to an IValue + * This visitor will apply another visitor in a bottom-up fashion to an IValue * */ public class BottomUpVisitor extends VisitorAdapter { - protected IValueFactory fFactory; - - public BottomUpVisitor(IValueVisitor visitor, IValueFactory factory) { - super(visitor); - this.fFactory = factory; - } - - @Override - public T visitNode(INode o) throws E { - for (int i = 0; i < o.arity(); i++) { - o.get(i).accept(this); - } - - return fVisitor.visitNode(o); - } - - public T visitConstructor(IConstructor o) throws E { - for (int i = 0; i < o.arity(); i++) { - o.get(i).accept(this); - } - - return fVisitor.visitConstructor(o); - } - - @Override - public T visitList(IList o) throws E { - IListWriter w = fFactory.listWriter(); - for (IValue elem : o) { - elem.accept(this); - } - - return fVisitor.visitList(w.done()); - } - - @Override - public T visitSet(ISet o) throws E { - ISetWriter w = fFactory.setWriter(); - for (IValue elem : o) { - elem.accept(this); - } - - return fVisitor.visitSet(w.done()); - } - - @Override - public T visitMap(IMap o) throws E { - IMapWriter w = fFactory.mapWriter(); - - for (Entry entry : (Iterable>) () -> o.entryIterator()) { - entry.getKey().accept(this); - entry.getValue().accept(this); - } - - return fVisitor.visitMap(w.done()); - } - - @Override - public T visitTuple(ITuple o) throws E { - for (int i = 0; i < o.arity(); i++) { - o.get(i).accept(this); - } - - return fVisitor.visitTuple(o); - } - - public T visitExternal(IExternalValue externalValue) throws E { - return fVisitor.visitExternal(externalValue); - } + protected IValueFactory fFactory; + + public BottomUpVisitor(IValueVisitor visitor, IValueFactory factory) { + super(visitor); + this.fFactory = factory; + } + + @Override + public T visitNode(INode o) throws E { + for (int i = 0; i < o.arity(); i++) { + o.get(i).accept(this); + } + + return fVisitor.visitNode(o); + } + + public T visitConstructor(IConstructor o) throws E { + for (int i = 0; i < o.arity(); i++) { + o.get(i).accept(this); + } + + return fVisitor.visitConstructor(o); + } + + @Override + public T visitList(IList o) throws E { + IListWriter w = fFactory.listWriter(); + for (IValue elem : o) { + elem.accept(this); + } + + return fVisitor.visitList(w.done()); + } + + @Override + public T visitSet(ISet o) throws E { + ISetWriter w = fFactory.setWriter(); + for (IValue elem : o) { + elem.accept(this); + } + + return fVisitor.visitSet(w.done()); + } + + @Override + public T visitMap(IMap o) throws E { + IMapWriter w = fFactory.mapWriter(); + + for (Entry entry : (Iterable>) () -> o.entryIterator()) { + entry.getKey().accept(this); + entry.getValue().accept(this); + } + + return fVisitor.visitMap(w.done()); + } + + @Override + public T visitTuple(ITuple o) throws E { + for (int i = 0; i < o.arity(); i++) { + o.get(i).accept(this); + } + + return fVisitor.visitTuple(o); + } + + public T visitExternal(IExternalValue externalValue) throws E { + return fVisitor.visitExternal(externalValue); + } } diff --git a/src/main/java/io/usethesource/vallang/visitors/IValueVisitor.java b/src/main/java/io/usethesource/vallang/visitors/IValueVisitor.java index cc5cec8ad..d1c00e0ac 100644 --- a/src/main/java/io/usethesource/vallang/visitors/IValueVisitor.java +++ b/src/main/java/io/usethesource/vallang/visitors/IValueVisitor.java @@ -29,18 +29,18 @@ import io.usethesource.vallang.ITuple; public interface IValueVisitor { - public R visitString(IString o) throws E; - public R visitReal(IReal o) throws E; - public R visitRational(IRational o) throws E; - public R visitList(IList o) throws E; - public R visitSet(ISet o) throws E; - public R visitSourceLocation(ISourceLocation o) throws E; - public R visitTuple(ITuple o) throws E; - public R visitNode(INode o) throws E; - public R visitConstructor(IConstructor o) throws E; - public R visitInteger(IInteger o) throws E; - public R visitMap(IMap o) throws E; - public R visitBoolean(IBool boolValue) throws E; - public R visitExternal(IExternalValue externalValue) throws E; - public R visitDateTime(IDateTime o) throws E; + public R visitString(IString o) throws E; + public R visitReal(IReal o) throws E; + public R visitRational(IRational o) throws E; + public R visitList(IList o) throws E; + public R visitSet(ISet o) throws E; + public R visitSourceLocation(ISourceLocation o) throws E; + public R visitTuple(ITuple o) throws E; + public R visitNode(INode o) throws E; + public R visitConstructor(IConstructor o) throws E; + public R visitInteger(IInteger o) throws E; + public R visitMap(IMap o) throws E; + public R visitBoolean(IBool boolValue) throws E; + public R visitExternal(IExternalValue externalValue) throws E; + public R visitDateTime(IDateTime o) throws E; } diff --git a/src/main/java/io/usethesource/vallang/visitors/IdentityVisitor.java b/src/main/java/io/usethesource/vallang/visitors/IdentityVisitor.java index 6ef56fc4e..2d38faf2c 100644 --- a/src/main/java/io/usethesource/vallang/visitors/IdentityVisitor.java +++ b/src/main/java/io/usethesource/vallang/visitors/IdentityVisitor.java @@ -29,76 +29,76 @@ /** * This abstract class does nothing except implementing identity. Extend it * to easily implement a visitor that visits selected types of IValues. - * + * */ public abstract class IdentityVisitor implements IValueVisitor { @Override - public IValue visitReal(IReal o) throws E{ - return o; - } + public IValue visitReal(IReal o) throws E{ + return o; + } @Override - public IValue visitInteger(IInteger o) throws E{ - return o; - } + public IValue visitInteger(IInteger o) throws E{ + return o; + } @Override - public IValue visitRational(IRational o) throws E{ - return o; - } + public IValue visitRational(IRational o) throws E{ + return o; + } @Override - public IValue visitList(IList o) throws E{ - return o; - } + public IValue visitList(IList o) throws E{ + return o; + } @Override - public IValue visitMap(IMap o) throws E{ - return o; - } + public IValue visitMap(IMap o) throws E{ + return o; + } @Override - public IValue visitSet(ISet o) throws E{ - return o; - } + public IValue visitSet(ISet o) throws E{ + return o; + } @Override - public IValue visitSourceLocation(ISourceLocation o) throws E{ - return o; - } + public IValue visitSourceLocation(ISourceLocation o) throws E{ + return o; + } @Override - public IValue visitString(IString o) throws E{ - return o; - } + public IValue visitString(IString o) throws E{ + return o; + } @Override - public IValue visitNode(INode o) throws E{ - return o; - } - + public IValue visitNode(INode o) throws E{ + return o; + } + @Override - public IValue visitConstructor(IConstructor o) throws E { - return o; - } + public IValue visitConstructor(IConstructor o) throws E { + return o; + } @Override - public IValue visitTuple(ITuple o) throws E{ - return o; - } - + public IValue visitTuple(ITuple o) throws E{ + return o; + } + @Override - public IValue visitBoolean(IBool o) throws E { - return o; - } - + public IValue visitBoolean(IBool o) throws E { + return o; + } + @Override - public IValue visitExternal(IExternalValue o) throws E { - return o; - } - + public IValue visitExternal(IExternalValue o) throws E { + return o; + } + @Override - public IValue visitDateTime(IDateTime o) throws E { - return o; - } + public IValue visitDateTime(IDateTime o) throws E { + return o; + } } diff --git a/src/main/java/io/usethesource/vallang/visitors/NullVisitor.java b/src/main/java/io/usethesource/vallang/visitors/NullVisitor.java index 09082d088..0365c3dc7 100644 --- a/src/main/java/io/usethesource/vallang/visitors/NullVisitor.java +++ b/src/main/java/io/usethesource/vallang/visitors/NullVisitor.java @@ -30,76 +30,76 @@ /** * This abstract class does nothing except returning null. Extend it * to easily implement a visitor that visits selected types of IValues. - * + * */ public abstract class NullVisitor<@Nullable T, E extends Throwable> implements IValueVisitor { @Override - public T visitReal(IReal o) throws E { - return null; - } + public T visitReal(IReal o) throws E { + return null; + } @Override - public T visitInteger(IInteger o) throws E { - return null; - } + public T visitInteger(IInteger o) throws E { + return null; + } @Override - public T visitRational(IRational o) throws E { - return null; - } + public T visitRational(IRational o) throws E { + return null; + } @Override - public T visitList(IList o) throws E { - return null; - } + public T visitList(IList o) throws E { + return null; + } @Override - public T visitMap(IMap o) throws E { - return null; - } + public T visitMap(IMap o) throws E { + return null; + } @Override - public T visitSet(ISet o) throws E { - return null; - } - - @Override - public T visitSourceLocation(ISourceLocation o) throws E { - return null; - } - - @Override - public T visitString(IString o) throws E { - return null; - } - - @Override - public T visitNode(INode o) throws E { - return null; - } - - @Override - public T visitConstructor(IConstructor o) throws E { - return null; - } - - @Override - public T visitTuple(ITuple o) throws E { - return null; - } - - @Override - public T visitBoolean(IBool boolValue) throws E { - return null; - } - - @Override - public T visitExternal(IExternalValue externalValue) throws E { - return null; - } - - @Override - public T visitDateTime(IDateTime o) throws E { - return null; - } + public T visitSet(ISet o) throws E { + return null; + } + + @Override + public T visitSourceLocation(ISourceLocation o) throws E { + return null; + } + + @Override + public T visitString(IString o) throws E { + return null; + } + + @Override + public T visitNode(INode o) throws E { + return null; + } + + @Override + public T visitConstructor(IConstructor o) throws E { + return null; + } + + @Override + public T visitTuple(ITuple o) throws E { + return null; + } + + @Override + public T visitBoolean(IBool boolValue) throws E { + return null; + } + + @Override + public T visitExternal(IExternalValue externalValue) throws E { + return null; + } + + @Override + public T visitDateTime(IDateTime o) throws E { + return null; + } } diff --git a/src/main/java/io/usethesource/vallang/visitors/ValueStreams.java b/src/main/java/io/usethesource/vallang/visitors/ValueStreams.java index 6cb06710a..87d85e62b 100644 --- a/src/main/java/io/usethesource/vallang/visitors/ValueStreams.java +++ b/src/main/java/io/usethesource/vallang/visitors/ValueStreams.java @@ -48,7 +48,7 @@ public static Stream bottomup(IValue val) { public static Stream topdown(IValue val) { return val.accept(new TopDown()); } - + /** * Breadth-first top-down traversal, left-to-right * @param val @@ -56,24 +56,24 @@ public static Stream topdown(IValue val) { */ public static Stream topdownbf(IValue val) { Deque queue = new ArrayDeque<>(); - + queue.add(val); - + return topdownbf(queue); } - + private static Stream topdownbf(Deque queue) { if (queue.isEmpty()) { return Stream.empty(); } - + IValue val = queue.remove(); val.accept(new QueueChildren(queue)); return Stream.concat(Stream.of(val), topdownbf(queue)); } - + /** * Breadth-first bottom-up traversal, right-to-left * @param val @@ -83,16 +83,16 @@ public static Stream bottomupbf(IValue val) { Deque queue = new ArrayDeque<>(); Deque stack = new ArrayDeque<>(); queue.add(val); - + while (!queue.isEmpty()) { val = queue.remove(); stack.push(val); val.accept(new QueueChildren(queue)); } - + return stack.stream(); } - + private static abstract class Single implements IValueVisitor, RuntimeException> { @Override public Stream visitNode(INode o) { @@ -164,7 +164,7 @@ public Stream visitDateTime(IDateTime o) { return Stream.of(o); } } - + private static class BottomUp extends Single { @Override public Stream visitNode(INode o) { @@ -220,39 +220,39 @@ public Stream visitNode(INode o) { StreamSupport.stream(o.getChildren().spliterator(), false).flatMap(c -> c.accept(this)) ); } - + @Override public Stream visitList(IList o) { return Stream.concat(Stream.of(o), o.stream().flatMap(c -> c.accept(this)) ); } - + @Override public Stream visitSet(ISet o) { return Stream.concat(Stream.of(o), o.stream().flatMap(c -> c.accept(this)) ); } - + @Override public Stream visitTuple(ITuple o) { return Stream.concat(Stream.of(o), StreamSupport.stream(o.spliterator(), false).flatMap(c -> c.accept(this)) ); } - + @Override public Stream visitConstructor(IConstructor o) { return Stream.concat(Stream.of(o), StreamSupport.stream(o.getChildren().spliterator(), false) ); } - + @Override public Stream visitMap(IMap o) { Iterable> it = (Iterable>) () -> o.entryIterator(); - + return Stream.concat(Stream.of(o), StreamSupport.stream(it.spliterator(), false).flatMap(e -> { return Stream.of(e.getKey(), e.getValue()).flatMap(c -> c.accept(this)); @@ -263,11 +263,11 @@ public Stream visitMap(IMap o) { private static class QueueChildren extends NullVisitor { private final Deque queue; - + public QueueChildren(Deque queue) { this.queue = queue; } - + @Override public Void visitList(IList o) throws RuntimeException { o.stream().forEach((e) -> queue.add(e)); @@ -300,12 +300,12 @@ public Void visitConstructor(IConstructor o) throws RuntimeException { @Override public Void visitMap(IMap o) throws RuntimeException { Iterable> it = (Iterable>) () -> o.entryIterator(); - + StreamSupport.stream(it.spliterator(), false).forEach(e -> { queue.add(e.getKey()); queue.add(e.getValue()); }); - + return null; } } diff --git a/src/main/java/io/usethesource/vallang/visitors/VisitorAdapter.java b/src/main/java/io/usethesource/vallang/visitors/VisitorAdapter.java index a0372120c..ab1939145 100644 --- a/src/main/java/io/usethesource/vallang/visitors/VisitorAdapter.java +++ b/src/main/java/io/usethesource/vallang/visitors/VisitorAdapter.java @@ -30,79 +30,79 @@ * */ public abstract class VisitorAdapter implements IValueVisitor { - protected IValueVisitor fVisitor; - - public VisitorAdapter(IValueVisitor visitor) { - this.fVisitor = visitor; - } - - @Override - public T visitReal(IReal o) throws E { - return fVisitor.visitReal(o); - } - - @Override - public T visitInteger(IInteger o) throws E { - return fVisitor.visitInteger(o); - } - - @Override - public T visitRational(IRational o) throws E { - return fVisitor.visitRational(o); - } - - @Override - public T visitList(IList o) throws E { - return fVisitor.visitList(o); - } - - @Override - public T visitMap(IMap o) throws E { - return fVisitor.visitMap(o); - } - - @Override - public T visitSet(ISet o) throws E { - return fVisitor.visitSet(o); - } - - @Override - public T visitSourceLocation(ISourceLocation o) throws E { - return fVisitor.visitSourceLocation(o); - } - - @Override - public T visitString(IString o) throws E { - return fVisitor.visitString(o); - } - - @Override - public T visitNode(INode o) throws E { - return fVisitor.visitNode(o); - } - - @Override - public T visitConstructor(IConstructor o) throws E { - return fVisitor.visitConstructor(o); - } - - @Override - public T visitTuple(ITuple o) throws E { - return fVisitor.visitTuple(o); - } - - @Override - public T visitBoolean(IBool o) throws E { - return fVisitor.visitBoolean(o); - } - - @Override - public T visitDateTime(IDateTime o) throws E { - return fVisitor.visitDateTime(o); - } - - @Override - public T visitExternal(IExternalValue externalValue) throws E { - return fVisitor.visitExternal(externalValue); - } + protected IValueVisitor fVisitor; + + public VisitorAdapter(IValueVisitor visitor) { + this.fVisitor = visitor; + } + + @Override + public T visitReal(IReal o) throws E { + return fVisitor.visitReal(o); + } + + @Override + public T visitInteger(IInteger o) throws E { + return fVisitor.visitInteger(o); + } + + @Override + public T visitRational(IRational o) throws E { + return fVisitor.visitRational(o); + } + + @Override + public T visitList(IList o) throws E { + return fVisitor.visitList(o); + } + + @Override + public T visitMap(IMap o) throws E { + return fVisitor.visitMap(o); + } + + @Override + public T visitSet(ISet o) throws E { + return fVisitor.visitSet(o); + } + + @Override + public T visitSourceLocation(ISourceLocation o) throws E { + return fVisitor.visitSourceLocation(o); + } + + @Override + public T visitString(IString o) throws E { + return fVisitor.visitString(o); + } + + @Override + public T visitNode(INode o) throws E { + return fVisitor.visitNode(o); + } + + @Override + public T visitConstructor(IConstructor o) throws E { + return fVisitor.visitConstructor(o); + } + + @Override + public T visitTuple(ITuple o) throws E { + return fVisitor.visitTuple(o); + } + + @Override + public T visitBoolean(IBool o) throws E { + return fVisitor.visitBoolean(o); + } + + @Override + public T visitDateTime(IDateTime o) throws E { + return fVisitor.visitDateTime(o); + } + + @Override + public T visitExternal(IExternalValue externalValue) throws E { + return fVisitor.visitExternal(externalValue); + } } diff --git a/src/test/java/io/usethesource/vallang/TypeConfig.java b/src/test/java/io/usethesource/vallang/TypeConfig.java index 7b2ae0f4d..641d61d6f 100644 --- a/src/test/java/io/usethesource/vallang/TypeConfig.java +++ b/src/test/java/io/usethesource/vallang/TypeConfig.java @@ -14,6 +14,6 @@ public enum Option { TUPLE_FIELDNAMES, ALL } - + Option[] value(); } diff --git a/src/test/java/io/usethesource/vallang/ValueProvider.java b/src/test/java/io/usethesource/vallang/ValueProvider.java index fa556058a..4e42a6b09 100644 --- a/src/test/java/io/usethesource/vallang/ValueProvider.java +++ b/src/test/java/io/usethesource/vallang/ValueProvider.java @@ -45,29 +45,29 @@ *
  • ISourceLocation
  • *
  • IDateTime
  • *
  • Type
  • - * + * *

    If the class under test has a static field called "store" of type TypeStore, then this * typestore will be passed to all parameters of type TypeStore instead of a fresh/empty TypeStore.

    - * + * *

    If a parameter of a method under test is annotated with \@ExpectedType("type") like so: *

    \@ParameterizedTest \@ArgumentsSource(ValueProvider.class)
      *      public void myTest(\@ExpectedType("set[int]") ISet set) ...
    - * + * * , then the ValueProvider will generate only instances which have as run-time type a - * sub-type of the specified expected type.

    - * - *

    + * sub-type of the specified expected type.

    + * + *

    * If a method under test is annotated with \@ArgumentsSeed(long) then that seed is used to * generate the stream of argument lists for the given method

    - * + * *

    If a parameter of a method under test is annotate with \@GivenValue("expression") then * instead of a random parameter, the value expression is parsed as an IValue and passed as given parameter. * The parser respects the current TypeStore as well as optional \@ExpectedType annotations on the same parameter.

    - * - *

    If a parameter of a method under test of type {@link Type} is annotated with \@TypeConfig then the + * + *

    If a parameter of a method under test of type {@link Type} is annotated with \@TypeConfig then the * random type generator is configurated using that annotation. For example: * \@TypeConfig(Option.All) will activate type aliases, open type parameters and field names for tuples.

    - * + * *

    If a method under test is annotated with \@ArgumentsMaxDepth(int), then none of the random parameters * will be nested deeper than the given number. \@ArgumentsMaxWidth(int) has a similar meaning but for the width * of tuples, lists, maps, and sets.

    @@ -78,22 +78,22 @@ public class ValueProvider implements ArgumentsProvider { private static final @Nullable String seedProperty; private static final long seed; private static final Random rnd; - + static { - seedProperty = System.getProperty("vallang.test.seed"); - if (seedProperty != null) { - System.err.println("Current random seed is computed from -Dvallang.test.seed=" + seedProperty); - seed = hashSeed(seedProperty); - rnd = new Random(seed); - } - else { - seed = new Random().nextLong(); - rnd = new Random(seed); - } - - System.err.println("Current random seed is: " + seed); + seedProperty = System.getProperty("vallang.test.seed"); + if (seedProperty != null) { + System.err.println("Current random seed is computed from -Dvallang.test.seed=" + seedProperty); + seed = hashSeed(seedProperty); + rnd = new Random(seed); + } + else { + seed = new Random().nextLong(); + rnd = new Random(seed); + } + + System.err.println("Current random seed is: " + seed); } - + /** * We use this to accidentally generate arguments which are the same as the previous * once in a while: @@ -103,34 +103,34 @@ public class ValueProvider implements ArgumentsProvider { /** * Every vallang test is run using all implementations of IValueFactory. */ - private static final IValueFactory[] factories = { - io.usethesource.vallang.impl.reference.ValueFactory.getInstance(), + private static final IValueFactory[] factories = { + io.usethesource.vallang.impl.reference.ValueFactory.getInstance(), io.usethesource.vallang.impl.persistent.ValueFactory.getInstance() }; - + /** * This trivial class helps with streaming generated test inputs, and some other stuff. */ private static class Tuple { public A a; public B b; - + public Tuple(A a, B b) { this.a = a; this.b = b; } - + public static Tuple of(C c, D d) { return new Tuple<>(c, d); } } - + /** * Maps Java class literals of sub-types of IValue to the corresponding function which will * generate a (random) instance of a type that all instances of such Java classes could have. * Only composite types will actually be random. */ - private static final Map, BiFunction> types = + private static final Map, BiFunction> types = Stream., BiFunction>>of( Tuple.of(IInteger.class, (ts, n) -> tf.integerType()), Tuple.of(IDateTime.class, (ts, n) -> tf.dateTimeType()), @@ -148,12 +148,12 @@ public static Tuple of(C c, D d) { Tuple.of(IMap.class, (ts, n) -> tf.mapType(tf.randomType(ts), tf.randomType(ts))), Tuple.of(IConstructor.class, (ts, n) -> randomADT(ts, n)) ).collect(Collectors.toMap(t -> t.a, t -> t.b)); - - + + @Override public Stream provideArguments(ExtensionContext context) { Method method = context.getTestMethod().get(); - + /* * If only factories and typestores are arguments, we generate as many tests as we have * value factory implementations (2). For the IValue argument we generate 100 tests and for @@ -162,7 +162,7 @@ public Stream provideArguments(ExtensionContext context) { long valueArity = Arrays.stream(method.getParameterTypes()).filter(x -> IValue.class.isAssignableFrom(x) || Type.class.isAssignableFrom(x)).count() - Arrays.stream(method.getParameters()).filter(x -> x.getAnnotation(GivenValue.class) != null).count(); int numberOfTests = Math.max(1, 100 * (int) Math.pow(10, valueArity - 1)); - + ArgumentsSeed argSeed = method.getAnnotation(ArgumentsSeed.class); if (argSeed != null) { rnd.setSeed(argSeed.value()); @@ -170,14 +170,14 @@ public Stream provideArguments(ExtensionContext context) { else { rnd.setSeed(seed); } - + return Stream.of( - factories[0], + factories[0], factories[1] ).flatMap(vf -> // all parameters share the same factory generateTypeStore(context).flatMap(ts -> Stream.iterate(arguments(method, vf, ts), p -> arguments(method, vf, ts)).limit(numberOfTests) - ) + ) ); } @@ -188,7 +188,7 @@ private static Type randomADT(TypeStore ts, ExpectedType n) { return result; } } - + Collection allADTs = ts.getAbstractDataTypes(); if (!allADTs.isEmpty()) { @@ -211,29 +211,29 @@ private static Type randomADT(TypeStore ts, ExpectedType n) { */ private Arguments arguments(Method method, IValueFactory vf, TypeStore ts) { previous = null; // never reuse arguments from a previous instance - - + + ArgumentsMaxDepth depth = method.getAnnotation(ArgumentsMaxDepth.class); ArgumentsMaxWidth width = method.getAnnotation(ArgumentsMaxWidth.class); - + TypeStore tsp = new TypeStore(); tsp.extendStore(ts); - + return Arguments.of( Arrays.stream(method.getParameters()).map( cl -> argument( - vf, - tsp, - cl.getType(), - cl.getAnnotation(ExpectedType.class), + vf, + tsp, + cl.getType(), + cl.getAnnotation(ExpectedType.class), cl.getAnnotation(GivenValue.class), first(method.getAnnotation(TypeConfig.class), cl.getAnnotation(TypeConfig.class)), depth != null ? depth.value() : 5, width != null ? width.value() : 10 )).toArray().clone() - ); + ); } - + private TypeConfig first(TypeConfig first, TypeConfig second) { if (first != null) { return first; @@ -250,8 +250,8 @@ private static long hashSeed(String string) { } return h; } - - + + /** * Generate an argument to a vallang test function. `cls` can be any sub-type of IValue, * or TypeStore or IValueFactory. @@ -274,7 +274,7 @@ private Object argument(IValueFactory vf, TypeStore ts, Class cls, @Nullable System.err.println("[WARNING] failed to parse given value: " + givenValue.value()); } } - + if (cls.isAssignableFrom(IValueFactory.class)) { return vf; } @@ -307,42 +307,42 @@ else if (Random.class.isAssignableFrom(cls)) { private RandomTypesConfig configureRandomTypes(TypeConfig typeConfig, int depth) { RandomTypesConfig tc = RandomTypesConfig.defaultConfig(rnd).maxDepth(depth); - + if (typeConfig != null) { for (TypeConfig.Option p : typeConfig.value()) { switch (p) { - case ALIASES: - tc = tc.withAliases(); - break; - case TUPLE_FIELDNAMES: - tc = tc.withTupleFieldNames(); - break; - case TYPE_PARAMETERS: - tc = tc.withTypeParameters(); - break; - case ALL: - tc = tc.withAliases().withTupleFieldNames().withTypeParameters(); - break; + case ALIASES: + tc = tc.withAliases(); + break; + case TUPLE_FIELDNAMES: + tc = tc.withTupleFieldNames(); + break; + case TYPE_PARAMETERS: + tc = tc.withTypeParameters(); + break; + case ALL: + tc = tc.withAliases().withTupleFieldNames().withTypeParameters(); + break; } } } - + return tc; } - + /** * Generate a random IValue instance - * + * * @param vf the valuefactory/randomgenerator to use * @param ts the TypeStore to draw ADT constructors from * @param cl the `cl` (sub-type of `IValue`) to be assignable to - * @param noAnnotations + * @param noAnnotations * @return an instance assignable to `cl` */ private IValue generateValue(IValueFactory vf, TypeStore ts, Class cl, @Nullable ExpectedType expected, int depth, int width) { Type expectedType = tf.voidType(); - + // this should terminate through random selection. // only tuple types with nested void arguments can reduce to void. int i = 0; @@ -360,16 +360,16 @@ private IValue generateValue(IValueFactory vf, TypeStore ts, Class tf.valueType()) - .apply(ts, expected); + .apply(ts, expected); } } - + assert !expectedType.isBottom() : cl + " generated void type?"; if (previous != null && rnd.nextInt(4) == 0 && previous.getType().isSubtypeOf(expectedType)) { return rnd.nextBoolean() ? previous : reinstantiate(vf, ts, previous); } - + return (previous = expectedType.randomValue(rnd, vf, ts, new HashMap<>(), depth, width)); } @@ -380,7 +380,7 @@ private IValue generateValue(IValueFactory vf, TypeStore ts, Class generateTypeStore(ExtensionContext context) { return Stream.of(new TypeStore()); } } -} \ No newline at end of file +} diff --git a/src/test/java/io/usethesource/vallang/basic/BasicValueSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/BasicValueSmokeTest.java index 343e37ae4..572cea691 100644 --- a/src/test/java/io/usethesource/vallang/basic/BasicValueSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/BasicValueSmokeTest.java @@ -33,509 +33,509 @@ public final class BasicValueSmokeTest { - protected void assertEqual(IValue l, IValue r) { - assertTrue(l.equals(r), () -> "Expected " + l + " got " + r); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRationalToReal(IValueFactory vf) { - assertTrue(vf.rational(1, 4).toReal(3).equals(vf.real(0.25))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testBrokenGetURI(IValueFactory vf) { - try { - - // PathURI - ISourceLocation loc1 = vf.sourceLocation("UJ", "", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); - assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc1.toString()); - - // PathAuthorityURI - ISourceLocation loc2 = vf.sourceLocation("UJ", "UK", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); - assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc2.toString()); - - // PathAuthorityURI - ISourceLocation loc3 = vf.sourceLocation("UJ", "UK", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); - assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc3.toString()); - // QueryURI - ISourceLocation loc4 = vf.sourceLocation("UJ", "", "", "bla=𒉻𒂮𠇯", ""); - assertEquals("|UJ:///?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc4.toString()); - - // QueryAuthorityURI - ISourceLocation loc5 = vf.sourceLocation("UJ", "UK", "", "bla=𒉻𒂮𠇯", ""); - assertEquals("|UJ://UK?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc5.toString()); - - // QueryPathURI - ISourceLocation loc6 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯", "bla=𒉻𒂮𠇯", ""); - assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc6.toString()); - - // QueryPathAuthorityURI - ISourceLocation loc7 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯", "bla=𒉻𒂮𠇯", ""); - assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc7.toString()); - - // FragmentURI - ISourceLocation loc8 = vf.sourceLocation("UJ", "", "","", "𒉻𒂮𠇯"); - assertEquals("|UJ:///#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc8.toString()); - - // FragmentAuthorityURI - ISourceLocation loc9 = vf.sourceLocation("UJ", "UK", "","", "𒉻𒂮𠇯"); - assertEquals("|UJ://UK#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc9.toString()); - - // FragmentPathURI - ISourceLocation loc10 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯","", "𒉻𒂮𠇯"); - assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc10.toString()); - - // FragmentPathAuthorityURI - ISourceLocation loc11 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯","", "𒉻𒂮𠇯"); - assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc11.toString()); - - // FragmentQueryURI - ISourceLocation loc12 = vf.sourceLocation("UJ", "", "","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); - assertEquals("|UJ:///?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc12.toString()); - - // FragmentQueryAuthorityURI - ISourceLocation loc13 = vf.sourceLocation("UJ", "UK", "","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); - assertEquals("|UJ://UK?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc13.toString()); - - // FragmentQueryPathURI - ISourceLocation loc14 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); - assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc14.toString()); - - // FragmentQueryPathAuthorityURI - ISourceLocation loc15 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); - assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc15.toString()); - } catch (URISyntaxException e) { - fail(e.getMessage()); + protected void assertEqual(IValue l, IValue r) { + assertTrue(l.equals(r), () -> "Expected " + l + " got " + r); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRationalToReal(IValueFactory vf) { + assertTrue(vf.rational(1, 4).toReal(3).equals(vf.real(0.25))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testBrokenGetURI(IValueFactory vf) { + try { + + // PathURI + ISourceLocation loc1 = vf.sourceLocation("UJ", "", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); + assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc1.toString()); + + // PathAuthorityURI + ISourceLocation loc2 = vf.sourceLocation("UJ", "UK", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); + assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc2.toString()); + + // PathAuthorityURI + ISourceLocation loc3 = vf.sourceLocation("UJ", "UK", "/pkZ/T5/17152/7/𒉻𒂮𠇯"); + assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc3.toString()); + // QueryURI + ISourceLocation loc4 = vf.sourceLocation("UJ", "", "", "bla=𒉻𒂮𠇯", ""); + assertEquals("|UJ:///?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc4.toString()); + + // QueryAuthorityURI + ISourceLocation loc5 = vf.sourceLocation("UJ", "UK", "", "bla=𒉻𒂮𠇯", ""); + assertEquals("|UJ://UK?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc5.toString()); + + // QueryPathURI + ISourceLocation loc6 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯", "bla=𒉻𒂮𠇯", ""); + assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc6.toString()); + + // QueryPathAuthorityURI + ISourceLocation loc7 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯", "bla=𒉻𒂮𠇯", ""); + assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc7.toString()); + + // FragmentURI + ISourceLocation loc8 = vf.sourceLocation("UJ", "", "","", "𒉻𒂮𠇯"); + assertEquals("|UJ:///#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc8.toString()); + + // FragmentAuthorityURI + ISourceLocation loc9 = vf.sourceLocation("UJ", "UK", "","", "𒉻𒂮𠇯"); + assertEquals("|UJ://UK#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc9.toString()); + + // FragmentPathURI + ISourceLocation loc10 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯","", "𒉻𒂮𠇯"); + assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc10.toString()); + + // FragmentPathAuthorityURI + ISourceLocation loc11 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯","", "𒉻𒂮𠇯"); + assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc11.toString()); + + // FragmentQueryURI + ISourceLocation loc12 = vf.sourceLocation("UJ", "", "","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); + assertEquals("|UJ:///?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc12.toString()); + + // FragmentQueryAuthorityURI + ISourceLocation loc13 = vf.sourceLocation("UJ", "UK", "","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); + assertEquals("|UJ://UK?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc13.toString()); + + // FragmentQueryPathURI + ISourceLocation loc14 = vf.sourceLocation("UJ", "", "pkZ/T5/17152/7/𒉻𒂮𠇯","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); + assertEquals("|UJ:///pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc14.toString()); + + // FragmentQueryPathAuthorityURI + ISourceLocation loc15 = vf.sourceLocation("UJ", "UK", "pkZ/T5/17152/7/𒉻𒂮𠇯","bla=𒉻𒂮𠇯", "𒉻𒂮𠇯"); + assertEquals("|UJ://UK/pkZ/T5/17152/7/%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF?bla=%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF#%F0%92%89%BB%F0%92%82%AE%F0%A0%87%AF|", loc15.toString()); + } catch (URISyntaxException e) { + fail(e.getMessage()); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSourceLocations(IValueFactory vf) { + assertThrows(URISyntaxException.class, () -> vf.sourceLocation(null, null, null), "empty scheme"); + assertThrows(URISyntaxException.class, () -> vf.sourceLocation("", null, null), "empty scheme"); + assertDoesNotThrow(() -> vf.sourceLocation("valid+sch.em-e", null, null), "valid scheme"); + assertThrows(URISyntaxException.class, () -> vf.sourceLocation("invalid?scheme", null, null), "invalid scheme"); + assertThrows(URISyntaxException.class, () -> vf.sourceLocation("🍝", null, null), "invalid scheme"); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringRepresentation(IValueFactory vf) { + assertTrue(vf.string("\uD83C\uDF5D").equals(vf.string("🍝"))); + assertTrue(vf.string(new String(Character.toChars(0x1F35D))).equals(vf.string("🍝"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRascalIssue1192(IValueFactory vf) { + assertTrue(vf.integer("-2147483648").subtract(vf.integer("2147483648")).equals(vf.integer("-4294967296"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringLength(IValueFactory vf) { + assertTrue(vf.string("\uD83C\uDF5D").length() == 1); + assertTrue(vf.string("\uD83C\uDF5D\uD83C\uDF5D").length() == 2); + assertTrue(vf.string("🍝").length() == 1); + assertTrue(vf.string("🍝🍝").length() == 2); + assertTrue(vf.string("é").length() == 1); + assertTrue(vf.string("").length() == 0); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringReverse(IValueFactory vf) { + assertTrue(vf.string("").reverse().equals(vf.string(""))); + assertTrue(vf.string("🍝").reverse().equals(vf.string("🍝"))); + assertTrue(vf.string("🍝🍝").reverse().equals(vf.string("🍝🍝"))); + assertTrue(vf.string("🍝x🍝").reverse().equals(vf.string("🍝x🍝"))); + assertTrue(vf.string("🍝🍞").reverse().getValue().equals("🍞🍝")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringSubString(IValueFactory vf) { + assertTrue(vf.string("").substring(0, 0).equals(vf.string(""))); + assertTrue(vf.string("🍝").substring(0, 1).equals(vf.string("🍝"))); + assertTrue(vf.string("🍝🍝").substring(0, 1).equals(vf.string("🍝"))); + assertTrue(vf.string("🍝x🍝").substring(1, 2).equals(vf.string("x"))); + assertTrue(vf.string("🍝x🍝").substring(1, 3).equals(vf.string("x🍝"))); + } + + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringWrite(IValueFactory vf) { + Random rnd = new Random(); + + for (int i = 0; i < 1000; i++) { + IString testString = vf.string(RandomUtil.string(rnd, rnd.nextInt(200))); + StringWriter w = new StringWriter(); + try { + testString.write(w); + } catch (IOException e) { + fail(e.getMessage()); + } + + assertEqual(testString, vf.string(w.toString())); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringEmptyWrite(IValueFactory vf) { + IString testString = vf.string(""); + StringWriter w = new StringWriter(); + try { + testString.write(w); + } catch (IOException e) { + fail(e.getMessage()); + } + + assertEqual(testString, vf.string("")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringCharAt(IValueFactory vf) { + assertTrue(vf.string("🍝").charAt(0) == 0x1F35D); + assertTrue(vf.string("🍝🍞").charAt(1) == 0x1F35E); + assertTrue(vf.string("🍝x🍝").charAt(1) == 'x'); + assertTrue(vf.string("🍝x🍞").charAt(2) == 0x1F35E); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringConcat(IValueFactory vf) { + assertTrue(vf.string("").concat(vf.string("")).equals(vf.string(""))); + assertTrue(vf.string("x").concat(vf.string("y")).equals(vf.string("xy"))); + assertTrue(vf.string("🍝").concat(vf.string("y")).equals(vf.string("🍝y"))); + assertTrue(vf.string("x").concat(vf.string("🍝")).equals(vf.string("x🍝"))); + assertTrue(vf.string("🍝").concat(vf.string("🍝")).equals(vf.string("🍝🍝"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringReplace(IValueFactory vf) { + assertTrue(vf.string("").replace(0, 1, 0, vf.string("x")).equals(vf.string("x"))); + assertTrue(vf.string("x").replace(0, 1, 0, vf.string("")).equals(vf.string("x"))); + assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); + assertTrue(vf.string("xy").replace(1, 1, 0, vf.string("p")).equals(vf.string("xp"))); + assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("pq")).equals(vf.string("pqy"))); + assertTrue(vf.string("xy").replace(1, 1, 0, vf.string("pq")).equals(vf.string("xqp"))); + assertTrue(vf.string("xy").replace(0, 1, 0, vf.string("pq")).equals(vf.string("pqxy"))); + assertTrue(vf.string("xy").replace(1, 1, 1, vf.string("pq")).equals(vf.string("xpqy"))); + + assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); + assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p")).equals(vf.string("🍝p"))); + assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("🍝")).equals(vf.string("🍝y"))); + assertTrue(vf.string("").replace(0, 1, 0, vf.string("🍝")).equals(vf.string("🍝"))); + assertTrue(vf.string("🍝").replace(0, 1, 0, vf.string("")).equals(vf.string("🍝"))); + assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); + assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p")).equals(vf.string("🍝p"))); + assertTrue(vf.string("x🍝").replace(0, 1, 1, vf.string("p")).equals(vf.string("p🍝"))); + assertTrue(vf.string("x🍝").replace(1, 1, 0, vf.string("p")).equals(vf.string("xp"))); + assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p🍝")).equals(vf.string("p🍝y"))); + assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p🍝")).equals(vf.string("🍝🍝p"))); + assertTrue(vf.string("🍝y").replace(0, 1, 0, vf.string("🍝q")).equals(vf.string("🍝q🍝y"))); + assertTrue(vf.string("x🍝").replace(1, 1, 1, vf.string("🍝q")).equals(vf.string("x🍝q🍝"))); + assertTrue(vf.string("🍝y🍝").replace(1, 1, 2, vf.string("🍝")).equals(vf.string("🍝🍝🍝"))); + } + + private static final String[] commonNewlines = new String[] { "\n"}; + + private void checkIndent(IValueFactory vf, String indent, String newline, boolean indentFirstLine, String... lines) { + StringBuilder unindented = new StringBuilder(); + StringBuilder indented = new StringBuilder(); + StringBuilder indentedTwice = new StringBuilder(); + IString concatTree = vf.string(""); + + boolean first = true; + for (String l : lines) { + unindented.append(l); + unindented.append(newline); + + concatTree = concatTree.concat(vf.string(l)); + concatTree = concatTree.concat(vf.string(newline)); + + if (indentFirstLine || !first) { + indented.append(indent); + } + indented.append(l); + indented.append(newline); + + if (indentFirstLine || !first) { + indentedTwice.append("first" + indent); + indentedTwice.append(indent); + } + + indentedTwice.append(l); + indentedTwice.append(newline); + + first = false; + } + + // remove empty line indentations + String expected = indented.toString(); + String expectedTwice = indentedTwice.toString(); + + IString indentedDirect = vf.string(unindented.toString()).indent(vf.string(indent), indentFirstLine); + IString indentedConcatTree = concatTree.indent(vf.string(indent), indentFirstLine); + + IString indentedDirectTwice = indentedDirect.indent(vf.string("first" + indent), indentFirstLine); + IString indentedConcatTreeTwice = indentedConcatTree.indent(vf.string("first" + indent), indentFirstLine); + + // basic tests showing lazy versus eager indentation should have the same semantics: + assertEquals(expected, indentedDirect.getValue()); + assertEquals(expected, indentedConcatTree.getValue()); + assertSimilarIteration(vf.string(expected), indentedDirect); + assertEqualLength(vf.string(expected), indentedDirect); + assertSimilarIteration(vf.string(expected), indentedConcatTree); + assertEqualLength(vf.string(expected), indentedConcatTree); + assertSimilarIteration(indentedDirect, indentedConcatTree); + assertEqualLength(indentedDirect, indentedConcatTree); + assertEqual(indentedDirect, indentedConcatTree); + assertEquals(indentedDirect.hashCode(), indentedConcatTree.hashCode()); + + // these modify internal structure as a side-effect, so after this we test the above again! + assertEqualCharAt(vf.string(expected), indentedDirect); + assertEqualSubstring(vf.string(expected), indentedDirect); + assertEqualLength(vf.string(expected), indentedDirect); + + // retest after internal structure modifications + assertEquals(expected, indentedDirect.getValue()); + assertEquals(expected, indentedConcatTree.getValue()); + assertSimilarIteration(vf.string(expected), indentedDirect); + assertSimilarIteration(vf.string(expected), indentedConcatTree); + assertSimilarIteration(indentedDirect, indentedConcatTree); + assertEqual(indentedDirect, indentedConcatTree); + assertEquals(indentedDirect.hashCode(), indentedConcatTree.hashCode()); + + // basic tests showing lazy versus eager indentation should have the same semantics: + assertEquals(expectedTwice, indentedDirectTwice.getValue()); + assertEquals(expectedTwice, indentedConcatTreeTwice.getValue()); + assertSimilarIteration(vf.string(expectedTwice), indentedDirectTwice); + assertSimilarIteration(vf.string(expectedTwice), indentedConcatTreeTwice); + assertEqual(indentedDirectTwice, indentedConcatTreeTwice); + assertSimilarIteration(indentedDirectTwice, indentedConcatTreeTwice); + assertEquals(indentedDirectTwice.hashCode(), indentedConcatTreeTwice.hashCode()); + + // these modify internal structure as a side-effect, so after this we test the above again! + assertEqualCharAt(vf.string(expectedTwice), indentedDirectTwice); + assertEqualSubstring(vf.string(expectedTwice), indentedDirectTwice); + assertEqualLength(vf.string(expectedTwice), indentedDirectTwice); + assertEqualCharAt(vf.string(expectedTwice), indentedConcatTreeTwice); + assertEqualSubstring(vf.string(expectedTwice), indentedConcatTreeTwice); + assertEqualLength(vf.string(expectedTwice), indentedConcatTreeTwice); + assertEqualCharAt(indentedDirectTwice, indentedConcatTreeTwice); + assertEqualSubstring(indentedDirectTwice, indentedConcatTreeTwice); + assertEqualLength(indentedDirectTwice, indentedConcatTreeTwice); + + // retest after internal structure modifications + assertEquals(expectedTwice, indentedDirectTwice.getValue()); + assertEquals(expectedTwice, indentedConcatTreeTwice.getValue()); + assertSimilarIteration(vf.string(expectedTwice), indentedDirectTwice); + assertSimilarIteration(vf.string(expectedTwice), indentedConcatTreeTwice); + assertEqual(indentedDirectTwice, indentedConcatTreeTwice); + assertSimilarIteration(indentedDirectTwice, indentedConcatTreeTwice); + assertEquals(indentedDirectTwice.hashCode(), indentedConcatTreeTwice.hashCode()); + } + + private void assertEqualCharAt(IString one, IString two) { + assertEquals(one, two); + + for (int i = 0; i < one.length(); i++) { + assertEquals(one.charAt(i), two.charAt(i)); + } + } + + private void assertEqualSubstring(IString one, IString two) { + assertEqual(one, two); + + Random rnd = new Random(); + for (int c = 0; c < 10; c++) { + int j = rnd.nextInt(one.length()); + + if (j > 0) { + int i = rnd.nextInt(j); + + assertEquals(one.substring(i,j), two.substring(i,j)); + } + } + } + + private static void assertEqualLength(IString ref, IString target) { + assertEquals(ref.length(), target.length()); + } + + private static void assertSimilarIteration(IString ref, IString target) { + OfInt refIterator = ref.iterator(); + OfInt targetIterator = target.iterator(); + + for (int i = 0; refIterator.hasNext(); i++) { + assertTrue(targetIterator.hasNext()); + int a = refIterator.nextInt(); + int b = targetIterator.nextInt(); + + if (a != b) { + fail("string iterators produce different values at index " + i + " (" + a + " != " + b + ")"); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringIndent(IValueFactory vf) { + for (boolean firstLine : new Boolean[] { true, false}) { + for (String nl: commonNewlines) { + checkIndent(vf, " ", nl, firstLine, "a", "b", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "b", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "", "", "c"); + checkIndent(vf, " ", nl, firstLine, "a", "b", "c"); + checkIndent(vf, " ", nl, firstLine, " abcdef", " bcdefg", " cdefgh"); + checkIndent(vf, " ", nl, firstLine, "🍝", " b", " c"); + + // these are some hard tests containing spurious carriage return characters: + checkIndent(vf, "\t", nl, firstLine, "a", "\r", "", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "", "\r", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "", "\r\r\r", "c"); + checkIndent(vf, "\t", nl, firstLine, "a\r", "", "c"); + checkIndent(vf, "\t", nl, firstLine, "a", "", "\rc"); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringIndentRandomDefault(IValueFactory vf) { + Random rnd = new Random(); + for (String nl: commonNewlines) { + String[] randomLines = new String[10]; + for (int n = 0; n < randomLines.length; n++) { + String newString = RandomUtil.string(rnd, rnd.nextInt(200)); + newString = newString.replaceAll("[\\r\\n]", "_"); + randomLines[n] = newString; + } + + StringValue.resetMaxUnbalance(); + StringValue.resetMaxFlatString(); + + for (boolean first : new Boolean[] { true, true} ) { + for (int n = 0; n < 20; n++) { + checkIndent(vf, Pattern.quote(RandomUtil.string(rnd, rnd.nextInt(20)).replaceAll("\n", "_")), nl, first, randomLines); + } + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringIndentRandomShortConcats(IValueFactory vf) { + Random rnd = new Random(); + for (String nl: commonNewlines) { + String[] randomLines = new String[10]; + for (int n = 0; n < randomLines.length; n++) { + String newString = RandomUtil.string(rnd, rnd.nextInt(200)); + for (String newL : commonNewlines) { + newString = newString.replaceAll(Pattern.quote(newL), "_"); + } + randomLines[n] = newString; + } + + try { + StringValue.setMaxFlatString(5); + StringValue.setMaxUnbalance(5); + for (int n = 0; n < 20; n++) { + checkIndent(vf, Pattern.quote(RandomUtil.string(rnd, rnd.nextInt(20)).replaceAll("\n", "_")), nl, true, randomLines); + } + } + finally { + StringValue.resetMaxUnbalance(); + StringValue.resetMaxFlatString(); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntAddition(IValueFactory vf) { + assertTrue(vf.integer(1).add(vf.integer(1)).equals(vf.integer(2))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testReal(IValueFactory vf) { + assertTrue(vf.real("1.5").floor().equals(vf.real("1"))); + assertTrue(vf.real("1.5").round().equals(vf.real("2"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testNumberSubTypes(TypeFactory tf) { + assertTrue(tf.integerType().isSubtypeOf(tf.numberType())); + assertFalse(tf.numberType().isSubtypeOf(tf.integerType())); + assertTrue(tf.realType().isSubtypeOf(tf.numberType())); + assertFalse(tf.numberType().isSubtypeOf(tf.realType())); + assertTrue(tf.rationalType().isSubtypeOf(tf.numberType())); + assertFalse(tf.numberType().isSubtypeOf(tf.rationalType())); + + assertTrue(tf.integerType().lub(tf.realType()).equivalent(tf.numberType())); + assertTrue(tf.integerType().lub(tf.rationalType()).equivalent(tf.numberType())); + assertTrue(tf.integerType().lub(tf.numberType()).equivalent(tf.numberType())); + assertTrue(tf.realType().lub(tf.numberType()).equivalent(tf.numberType())); + assertTrue(tf.rationalType().lub(tf.integerType()).equivalent(tf.numberType())); + assertTrue(tf.rationalType().lub(tf.realType()).equivalent(tf.numberType())); + assertTrue(tf.rationalType().lub(tf.numberType()).equivalent(tf.numberType())); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testNumberArithmatic(IValueFactory vf) { + INumber i1 = vf.integer(1); + INumber i2 = vf.integer(2); + INumber r1 = vf.real(1.0); + INumber r2 = vf.real(2.0); + INumber q1 = vf.rational(1, 1); + INumber q2 = vf.rational(2, 1); + + assertEqual(i1.add(i2), vf.integer(3)); + assertEqual(i1.add(r2), vf.real(3)); + assertEqual(i1.add(q2), vf.rational(3, 1)); + assertEqual(q1.add(i2), vf.rational(3, 1)); + assertEqual(q1.add(q2), vf.rational(3, 1)); + assertEqual(r1.add(r2), vf.real(3)); + assertEqual(r1.add(i2), vf.real(3)); + assertEqual(r1.add(q2), vf.real(3)); + + assertEqual(i1.subtract(i2), vf.integer(-1)); + assertEqual(i1.subtract(r2), vf.real(-1)); + assertEqual(r1.subtract(r2), vf.real(-1)); + assertEqual(r1.subtract(i2), vf.real(-1)); + assertEqual(q1.subtract(q2), vf.rational(-1, 1)); + assertEqual(q1.subtract(r2), vf.real(-1)); + assertEqual(q1.subtract(i2), vf.rational(-1, 1)); + + IInteger i5 = vf.integer(5); + assertEqual(i5.divide(i2, 80 * 80), vf.real(2.5)); + assertEqual(r1.subtract(q2), vf.real(-1)); + assertEqual(i5.divide(i2.toRational()), vf.rational(5, 2)); + + assertEqual(vf.integer(0), vf.integer(0).abs()); + assertEqual(vf.rational(0, 1), vf.rational(0, 1).abs()); + assertEqual(vf.real(0), vf.real(0).abs()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testPreciseRealDivision(IValueFactory vf) { + IReal e100 = vf.real("1E100"); + IReal maxDiff = vf.real("1E-6300"); + IReal r9 = vf.real("9"); + assertTrue(e100.subtract(e100.divide(r9, 80 * 80).multiply(r9)).lessEqual(maxDiff).getValue()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testDateTimeLongConversion(IValueFactory vf) { + long l = 1156521600000L; + IDateTime dt = vf.datetime(l); + assertEqual(dt, vf.datetime(dt.getInstant())); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testDateTimeLongConversionWithTimezone(IValueFactory vf) { + IDateTime dt = vf.datetime(2014, 10, 13, 10, 7, 50, 1, 7, 0); + assertEqual(dt, + vf.datetime(dt.getInstant(), dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes())); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLocationTop(IValueFactory vf) throws URISyntaxException { + ISourceLocation l = vf.sourceLocation("tmp", "", "/file.txt"); + assertTrue(l.top() == l); + + ISourceLocation m = vf.sourceLocation(l, 10, 20); + assertEquals(m.top(), l); } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSourceLocations(IValueFactory vf) { - assertThrows(URISyntaxException.class, () -> vf.sourceLocation(null, null, null), "empty scheme"); - assertThrows(URISyntaxException.class, () -> vf.sourceLocation("", null, null), "empty scheme"); - assertDoesNotThrow(() -> vf.sourceLocation("valid+sch.em-e", null, null), "valid scheme"); - assertThrows(URISyntaxException.class, () -> vf.sourceLocation("invalid?scheme", null, null), "invalid scheme"); - assertThrows(URISyntaxException.class, () -> vf.sourceLocation("🍝", null, null), "invalid scheme"); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringRepresentation(IValueFactory vf) { - assertTrue(vf.string("\uD83C\uDF5D").equals(vf.string("🍝"))); - assertTrue(vf.string(new String(Character.toChars(0x1F35D))).equals(vf.string("🍝"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRascalIssue1192(IValueFactory vf) { - assertTrue(vf.integer("-2147483648").subtract(vf.integer("2147483648")).equals(vf.integer("-4294967296"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringLength(IValueFactory vf) { - assertTrue(vf.string("\uD83C\uDF5D").length() == 1); - assertTrue(vf.string("\uD83C\uDF5D\uD83C\uDF5D").length() == 2); - assertTrue(vf.string("🍝").length() == 1); - assertTrue(vf.string("🍝🍝").length() == 2); - assertTrue(vf.string("é").length() == 1); - assertTrue(vf.string("").length() == 0); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringReverse(IValueFactory vf) { - assertTrue(vf.string("").reverse().equals(vf.string(""))); - assertTrue(vf.string("🍝").reverse().equals(vf.string("🍝"))); - assertTrue(vf.string("🍝🍝").reverse().equals(vf.string("🍝🍝"))); - assertTrue(vf.string("🍝x🍝").reverse().equals(vf.string("🍝x🍝"))); - assertTrue(vf.string("🍝🍞").reverse().getValue().equals("🍞🍝")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringSubString(IValueFactory vf) { - assertTrue(vf.string("").substring(0, 0).equals(vf.string(""))); - assertTrue(vf.string("🍝").substring(0, 1).equals(vf.string("🍝"))); - assertTrue(vf.string("🍝🍝").substring(0, 1).equals(vf.string("🍝"))); - assertTrue(vf.string("🍝x🍝").substring(1, 2).equals(vf.string("x"))); - assertTrue(vf.string("🍝x🍝").substring(1, 3).equals(vf.string("x🍝"))); - } - - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringWrite(IValueFactory vf) { - Random rnd = new Random(); - - for (int i = 0; i < 1000; i++) { - IString testString = vf.string(RandomUtil.string(rnd, rnd.nextInt(200))); - StringWriter w = new StringWriter(); - try { - testString.write(w); - } catch (IOException e) { - fail(e.getMessage()); - } - - assertEqual(testString, vf.string(w.toString())); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringEmptyWrite(IValueFactory vf) { - IString testString = vf.string(""); - StringWriter w = new StringWriter(); - try { - testString.write(w); - } catch (IOException e) { - fail(e.getMessage()); - } - - assertEqual(testString, vf.string("")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringCharAt(IValueFactory vf) { - assertTrue(vf.string("🍝").charAt(0) == 0x1F35D); - assertTrue(vf.string("🍝🍞").charAt(1) == 0x1F35E); - assertTrue(vf.string("🍝x🍝").charAt(1) == 'x'); - assertTrue(vf.string("🍝x🍞").charAt(2) == 0x1F35E); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringConcat(IValueFactory vf) { - assertTrue(vf.string("").concat(vf.string("")).equals(vf.string(""))); - assertTrue(vf.string("x").concat(vf.string("y")).equals(vf.string("xy"))); - assertTrue(vf.string("🍝").concat(vf.string("y")).equals(vf.string("🍝y"))); - assertTrue(vf.string("x").concat(vf.string("🍝")).equals(vf.string("x🍝"))); - assertTrue(vf.string("🍝").concat(vf.string("🍝")).equals(vf.string("🍝🍝"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringReplace(IValueFactory vf) { - assertTrue(vf.string("").replace(0, 1, 0, vf.string("x")).equals(vf.string("x"))); - assertTrue(vf.string("x").replace(0, 1, 0, vf.string("")).equals(vf.string("x"))); - assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); - assertTrue(vf.string("xy").replace(1, 1, 0, vf.string("p")).equals(vf.string("xp"))); - assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("pq")).equals(vf.string("pqy"))); - assertTrue(vf.string("xy").replace(1, 1, 0, vf.string("pq")).equals(vf.string("xqp"))); - assertTrue(vf.string("xy").replace(0, 1, 0, vf.string("pq")).equals(vf.string("pqxy"))); - assertTrue(vf.string("xy").replace(1, 1, 1, vf.string("pq")).equals(vf.string("xpqy"))); - - assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); - assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p")).equals(vf.string("🍝p"))); - assertTrue(vf.string("xy").replace(0, 1, 1, vf.string("🍝")).equals(vf.string("🍝y"))); - assertTrue(vf.string("").replace(0, 1, 0, vf.string("🍝")).equals(vf.string("🍝"))); - assertTrue(vf.string("🍝").replace(0, 1, 0, vf.string("")).equals(vf.string("🍝"))); - assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p")).equals(vf.string("py"))); - assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p")).equals(vf.string("🍝p"))); - assertTrue(vf.string("x🍝").replace(0, 1, 1, vf.string("p")).equals(vf.string("p🍝"))); - assertTrue(vf.string("x🍝").replace(1, 1, 0, vf.string("p")).equals(vf.string("xp"))); - assertTrue(vf.string("🍝y").replace(0, 1, 1, vf.string("p🍝")).equals(vf.string("p🍝y"))); - assertTrue(vf.string("🍝y").replace(1, 1, 0, vf.string("p🍝")).equals(vf.string("🍝🍝p"))); - assertTrue(vf.string("🍝y").replace(0, 1, 0, vf.string("🍝q")).equals(vf.string("🍝q🍝y"))); - assertTrue(vf.string("x🍝").replace(1, 1, 1, vf.string("🍝q")).equals(vf.string("x🍝q🍝"))); - assertTrue(vf.string("🍝y🍝").replace(1, 1, 2, vf.string("🍝")).equals(vf.string("🍝🍝🍝"))); - } - - private static final String[] commonNewlines = new String[] { "\n"}; - - private void checkIndent(IValueFactory vf, String indent, String newline, boolean indentFirstLine, String... lines) { - StringBuilder unindented = new StringBuilder(); - StringBuilder indented = new StringBuilder(); - StringBuilder indentedTwice = new StringBuilder(); - IString concatTree = vf.string(""); - - boolean first = true; - for (String l : lines) { - unindented.append(l); - unindented.append(newline); - - concatTree = concatTree.concat(vf.string(l)); - concatTree = concatTree.concat(vf.string(newline)); - - if (indentFirstLine || !first) { - indented.append(indent); - } - indented.append(l); - indented.append(newline); - - if (indentFirstLine || !first) { - indentedTwice.append("first" + indent); - indentedTwice.append(indent); - } - - indentedTwice.append(l); - indentedTwice.append(newline); - - first = false; - } - - // remove empty line indentations - String expected = indented.toString(); - String expectedTwice = indentedTwice.toString(); - - IString indentedDirect = vf.string(unindented.toString()).indent(vf.string(indent), indentFirstLine); - IString indentedConcatTree = concatTree.indent(vf.string(indent), indentFirstLine); - - IString indentedDirectTwice = indentedDirect.indent(vf.string("first" + indent), indentFirstLine); - IString indentedConcatTreeTwice = indentedConcatTree.indent(vf.string("first" + indent), indentFirstLine); - - // basic tests showing lazy versus eager indentation should have the same semantics: - assertEquals(expected, indentedDirect.getValue()); - assertEquals(expected, indentedConcatTree.getValue()); - assertSimilarIteration(vf.string(expected), indentedDirect); - assertEqualLength(vf.string(expected), indentedDirect); - assertSimilarIteration(vf.string(expected), indentedConcatTree); - assertEqualLength(vf.string(expected), indentedConcatTree); - assertSimilarIteration(indentedDirect, indentedConcatTree); - assertEqualLength(indentedDirect, indentedConcatTree); - assertEqual(indentedDirect, indentedConcatTree); - assertEquals(indentedDirect.hashCode(), indentedConcatTree.hashCode()); - - // these modify internal structure as a side-effect, so after this we test the above again! - assertEqualCharAt(vf.string(expected), indentedDirect); - assertEqualSubstring(vf.string(expected), indentedDirect); - assertEqualLength(vf.string(expected), indentedDirect); - - // retest after internal structure modifications - assertEquals(expected, indentedDirect.getValue()); - assertEquals(expected, indentedConcatTree.getValue()); - assertSimilarIteration(vf.string(expected), indentedDirect); - assertSimilarIteration(vf.string(expected), indentedConcatTree); - assertSimilarIteration(indentedDirect, indentedConcatTree); - assertEqual(indentedDirect, indentedConcatTree); - assertEquals(indentedDirect.hashCode(), indentedConcatTree.hashCode()); - - // basic tests showing lazy versus eager indentation should have the same semantics: - assertEquals(expectedTwice, indentedDirectTwice.getValue()); - assertEquals(expectedTwice, indentedConcatTreeTwice.getValue()); - assertSimilarIteration(vf.string(expectedTwice), indentedDirectTwice); - assertSimilarIteration(vf.string(expectedTwice), indentedConcatTreeTwice); - assertEqual(indentedDirectTwice, indentedConcatTreeTwice); - assertSimilarIteration(indentedDirectTwice, indentedConcatTreeTwice); - assertEquals(indentedDirectTwice.hashCode(), indentedConcatTreeTwice.hashCode()); - - // these modify internal structure as a side-effect, so after this we test the above again! - assertEqualCharAt(vf.string(expectedTwice), indentedDirectTwice); - assertEqualSubstring(vf.string(expectedTwice), indentedDirectTwice); - assertEqualLength(vf.string(expectedTwice), indentedDirectTwice); - assertEqualCharAt(vf.string(expectedTwice), indentedConcatTreeTwice); - assertEqualSubstring(vf.string(expectedTwice), indentedConcatTreeTwice); - assertEqualLength(vf.string(expectedTwice), indentedConcatTreeTwice); - assertEqualCharAt(indentedDirectTwice, indentedConcatTreeTwice); - assertEqualSubstring(indentedDirectTwice, indentedConcatTreeTwice); - assertEqualLength(indentedDirectTwice, indentedConcatTreeTwice); - - // retest after internal structure modifications - assertEquals(expectedTwice, indentedDirectTwice.getValue()); - assertEquals(expectedTwice, indentedConcatTreeTwice.getValue()); - assertSimilarIteration(vf.string(expectedTwice), indentedDirectTwice); - assertSimilarIteration(vf.string(expectedTwice), indentedConcatTreeTwice); - assertEqual(indentedDirectTwice, indentedConcatTreeTwice); - assertSimilarIteration(indentedDirectTwice, indentedConcatTreeTwice); - assertEquals(indentedDirectTwice.hashCode(), indentedConcatTreeTwice.hashCode()); - } - - private void assertEqualCharAt(IString one, IString two) { - assertEquals(one, two); - - for (int i = 0; i < one.length(); i++) { - assertEquals(one.charAt(i), two.charAt(i)); - } - } - - private void assertEqualSubstring(IString one, IString two) { - assertEqual(one, two); - - Random rnd = new Random(); - for (int c = 0; c < 10; c++) { - int j = rnd.nextInt(one.length()); - - if (j > 0) { - int i = rnd.nextInt(j); - - assertEquals(one.substring(i,j), two.substring(i,j)); - } - } - } - - private static void assertEqualLength(IString ref, IString target) { - assertEquals(ref.length(), target.length()); - } - - private static void assertSimilarIteration(IString ref, IString target) { - OfInt refIterator = ref.iterator(); - OfInt targetIterator = target.iterator(); - - for (int i = 0; refIterator.hasNext(); i++) { - assertTrue(targetIterator.hasNext()); - int a = refIterator.nextInt(); - int b = targetIterator.nextInt(); - - if (a != b) { - fail("string iterators produce different values at index " + i + " (" + a + " != " + b + ")"); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringIndent(IValueFactory vf) { - for (boolean firstLine : new Boolean[] { true, false}) { - for (String nl: commonNewlines) { - checkIndent(vf, " ", nl, firstLine, "a", "b", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "b", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "", "", "c"); - checkIndent(vf, " ", nl, firstLine, "a", "b", "c"); - checkIndent(vf, " ", nl, firstLine, " abcdef", " bcdefg", " cdefgh"); - checkIndent(vf, " ", nl, firstLine, "🍝", " b", " c"); - - // these are some hard tests containing spurious carriage return characters: - checkIndent(vf, "\t", nl, firstLine, "a", "\r", "", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "", "\r", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "", "\r\r\r", "c"); - checkIndent(vf, "\t", nl, firstLine, "a\r", "", "c"); - checkIndent(vf, "\t", nl, firstLine, "a", "", "\rc"); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringIndentRandomDefault(IValueFactory vf) { - Random rnd = new Random(); - for (String nl: commonNewlines) { - String[] randomLines = new String[10]; - for (int n = 0; n < randomLines.length; n++) { - String newString = RandomUtil.string(rnd, rnd.nextInt(200)); - newString = newString.replaceAll("[\\r\\n]", "_"); - randomLines[n] = newString; - } - - StringValue.resetMaxUnbalance(); - StringValue.resetMaxFlatString(); - - for (boolean first : new Boolean[] { true, true} ) { - for (int n = 0; n < 20; n++) { - checkIndent(vf, Pattern.quote(RandomUtil.string(rnd, rnd.nextInt(20)).replaceAll("\n", "_")), nl, first, randomLines); - } - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringIndentRandomShortConcats(IValueFactory vf) { - Random rnd = new Random(); - for (String nl: commonNewlines) { - String[] randomLines = new String[10]; - for (int n = 0; n < randomLines.length; n++) { - String newString = RandomUtil.string(rnd, rnd.nextInt(200)); - for (String newL : commonNewlines) { - newString = newString.replaceAll(Pattern.quote(newL), "_"); - } - randomLines[n] = newString; - } - - try { - StringValue.setMaxFlatString(5); - StringValue.setMaxUnbalance(5); - for (int n = 0; n < 20; n++) { - checkIndent(vf, Pattern.quote(RandomUtil.string(rnd, rnd.nextInt(20)).replaceAll("\n", "_")), nl, true, randomLines); - } - } - finally { - StringValue.resetMaxUnbalance(); - StringValue.resetMaxFlatString(); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntAddition(IValueFactory vf) { - assertTrue(vf.integer(1).add(vf.integer(1)).equals(vf.integer(2))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testReal(IValueFactory vf) { - assertTrue(vf.real("1.5").floor().equals(vf.real("1"))); - assertTrue(vf.real("1.5").round().equals(vf.real("2"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testNumberSubTypes(TypeFactory tf) { - assertTrue(tf.integerType().isSubtypeOf(tf.numberType())); - assertFalse(tf.numberType().isSubtypeOf(tf.integerType())); - assertTrue(tf.realType().isSubtypeOf(tf.numberType())); - assertFalse(tf.numberType().isSubtypeOf(tf.realType())); - assertTrue(tf.rationalType().isSubtypeOf(tf.numberType())); - assertFalse(tf.numberType().isSubtypeOf(tf.rationalType())); - - assertTrue(tf.integerType().lub(tf.realType()).equivalent(tf.numberType())); - assertTrue(tf.integerType().lub(tf.rationalType()).equivalent(tf.numberType())); - assertTrue(tf.integerType().lub(tf.numberType()).equivalent(tf.numberType())); - assertTrue(tf.realType().lub(tf.numberType()).equivalent(tf.numberType())); - assertTrue(tf.rationalType().lub(tf.integerType()).equivalent(tf.numberType())); - assertTrue(tf.rationalType().lub(tf.realType()).equivalent(tf.numberType())); - assertTrue(tf.rationalType().lub(tf.numberType()).equivalent(tf.numberType())); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testNumberArithmatic(IValueFactory vf) { - INumber i1 = vf.integer(1); - INumber i2 = vf.integer(2); - INumber r1 = vf.real(1.0); - INumber r2 = vf.real(2.0); - INumber q1 = vf.rational(1, 1); - INumber q2 = vf.rational(2, 1); - - assertEqual(i1.add(i2), vf.integer(3)); - assertEqual(i1.add(r2), vf.real(3)); - assertEqual(i1.add(q2), vf.rational(3, 1)); - assertEqual(q1.add(i2), vf.rational(3, 1)); - assertEqual(q1.add(q2), vf.rational(3, 1)); - assertEqual(r1.add(r2), vf.real(3)); - assertEqual(r1.add(i2), vf.real(3)); - assertEqual(r1.add(q2), vf.real(3)); - - assertEqual(i1.subtract(i2), vf.integer(-1)); - assertEqual(i1.subtract(r2), vf.real(-1)); - assertEqual(r1.subtract(r2), vf.real(-1)); - assertEqual(r1.subtract(i2), vf.real(-1)); - assertEqual(q1.subtract(q2), vf.rational(-1, 1)); - assertEqual(q1.subtract(r2), vf.real(-1)); - assertEqual(q1.subtract(i2), vf.rational(-1, 1)); - - IInteger i5 = vf.integer(5); - assertEqual(i5.divide(i2, 80 * 80), vf.real(2.5)); - assertEqual(r1.subtract(q2), vf.real(-1)); - assertEqual(i5.divide(i2.toRational()), vf.rational(5, 2)); - - assertEqual(vf.integer(0), vf.integer(0).abs()); - assertEqual(vf.rational(0, 1), vf.rational(0, 1).abs()); - assertEqual(vf.real(0), vf.real(0).abs()); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testPreciseRealDivision(IValueFactory vf) { - IReal e100 = vf.real("1E100"); - IReal maxDiff = vf.real("1E-6300"); - IReal r9 = vf.real("9"); - assertTrue(e100.subtract(e100.divide(r9, 80 * 80).multiply(r9)).lessEqual(maxDiff).getValue()); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testDateTimeLongConversion(IValueFactory vf) { - long l = 1156521600000L; - IDateTime dt = vf.datetime(l); - assertEqual(dt, vf.datetime(dt.getInstant())); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testDateTimeLongConversionWithTimezone(IValueFactory vf) { - IDateTime dt = vf.datetime(2014, 10, 13, 10, 7, 50, 1, 7, 0); - assertEqual(dt, - vf.datetime(dt.getInstant(), dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes())); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLocationTop(IValueFactory vf) throws URISyntaxException { - ISourceLocation l = vf.sourceLocation("tmp", "", "/file.txt"); - assertTrue(l.top() == l); - - ISourceLocation m = vf.sourceLocation(l, 10, 20); - assertEquals(m.top(), l); - } } diff --git a/src/test/java/io/usethesource/vallang/basic/BigDecimalCalculationSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/BigDecimalCalculationSmokeTest.java index 5892f0f05..53275ad61 100644 --- a/src/test/java/io/usethesource/vallang/basic/BigDecimalCalculationSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/BigDecimalCalculationSmokeTest.java @@ -18,186 +18,186 @@ public final class BigDecimalCalculationSmokeTest { - private static void assertClose(INumber param, IReal actual, double expected) { - assertClose(param, actual, expected, 6); - } + private static void assertClose(INumber param, IReal actual, double expected) { + assertClose(param, actual, expected, 6); + } - private static void assertClose(INumber param, IReal actual, double expected, - int significantDigits) { - long order = 0; + private static void assertClose(INumber param, IReal actual, double expected, + int significantDigits) { + long order = 0; - if (Math.abs(expected) > 0.00001) { - order = Math.round(Math.floor(Math.log10(Math.abs(expected)))); - } + if (Math.abs(expected) > 0.00001) { + order = Math.round(Math.floor(Math.log10(Math.abs(expected)))); + } - double maxError = Math.pow(10, order - significantDigits); + double maxError = Math.pow(10, order - significantDigits); - assertTrue(Math.abs(actual.doubleValue() - expected) < maxError, () -> "failed for " + param + " real:" + actual + " double: " + expected); - } + assertTrue(Math.abs(actual.doubleValue() - expected) < maxError, () -> "failed for " + param + " real:" + actual + " double: " + expected); + } - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSinComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(-100); - IReal stop = start.negate(); - IReal increments = vf.real("0.1"); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.sin(vf.getPrecision()), Math.sin(param.doubleValue())); + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSinComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(-100); + IReal stop = start.negate(); + IReal increments = vf.real("0.1"); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.sin(vf.getPrecision()), Math.sin(param.doubleValue())); + } } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testCosComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(-100); - IReal stop = start.negate(); - IReal increments = vf.real("0.1"); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.cos(vf.getPrecision()), Math.cos(param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testCosComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(-100); + IReal stop = start.negate(); + IReal increments = vf.real("0.1"); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.cos(vf.getPrecision()), Math.cos(param.doubleValue())); + } } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testTanComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.pi(vf.getPrecision()).divide(vf.real(2.0), vf.getPrecision()).negate(); - IReal stop = start.negate(); - IReal increments = vf.real("0.01"); - - // around pi/2 tan is undefined so we skip checking around that. - start = start.add(increments); - stop = stop.subtract(increments); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.tan(vf.getPrecision()), Math.tan(param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testTanComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.pi(vf.getPrecision()).divide(vf.real(2.0), vf.getPrecision()).negate(); + IReal stop = start.negate(); + IReal increments = vf.real("0.01"); + + // around pi/2 tan is undefined so we skip checking around that. + start = start.add(increments); + stop = stop.subtract(increments); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.tan(vf.getPrecision()), Math.tan(param.doubleValue())); + } } - } - - private static double log2(double x) { - return Math.log(x) / Math.log(2); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLog2ComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(0); - IReal stop = vf.real(100); - IReal increments = vf.real("0.1"); - start = start.add(increments); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.log(vf.integer(2), vf.getPrecision()), log2(param.doubleValue())); + + private static double log2(double x) { + return Math.log(x) / Math.log(2); } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLog10ComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(0); - IReal stop = vf.real(100); - IReal increments = vf.real("0.1"); - start = start.add(increments); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.log(vf.integer(10), vf.getPrecision()), - Math.log10(param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLog2ComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(0); + IReal stop = vf.real(100); + IReal increments = vf.real("0.1"); + start = start.add(increments); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.log(vf.integer(2), vf.getPrecision()), log2(param.doubleValue())); + } } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLnComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(0); - IReal stop = vf.real(100); - IReal increments = vf.real("0.1"); - start = start.add(increments); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.ln(vf.getPrecision()), Math.log(param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLog10ComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(0); + IReal stop = vf.real(100); + IReal increments = vf.real("0.1"); + start = start.add(increments); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.log(vf.integer(10), vf.getPrecision()), + Math.log10(param.doubleValue())); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLnComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(0); + IReal stop = vf.real(100); + IReal increments = vf.real("0.1"); + start = start.add(increments); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.ln(vf.getPrecision()), Math.log(param.doubleValue())); + } } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testPowAllNumbers(IValueFactory vf) { - IReal start = vf.real(-10); - IReal stop = start.negate(); - IReal increments = vf.real("0.1"); - IReal x = vf.pi(10); - - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, x.pow(param, vf.getPrecision()), - Math.pow(x.doubleValue(), param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testPowAllNumbers(IValueFactory vf) { + IReal start = vf.real(-10); + IReal stop = start.negate(); + IReal increments = vf.real("0.1"); + IReal x = vf.pi(10); + + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, x.pow(param, vf.getPrecision()), + Math.pow(x.doubleValue(), param.doubleValue())); + } } - } - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testPowNaturalNumbers(IValueFactory vf) { - IInteger start = vf.integer(-10); - IInteger stop = start.negate(); - IInteger increments = vf.integer(1); - IReal x = vf.pi(10); + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testPowNaturalNumbers(IValueFactory vf) { + IInteger start = vf.integer(-10); + IInteger stop = start.negate(); + IInteger increments = vf.integer(1); + IReal x = vf.pi(10); - for (IInteger param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, x.pow(param), Math.pow(x.doubleValue(), param.doubleValue())); + for (IInteger param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, x.pow(param), Math.pow(x.doubleValue(), param.doubleValue())); + } } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testExpComparableToFloatingPoint(IValueFactory vf) { - IReal start = vf.real(-100); - IReal stop = start.negate(); - IReal increments = vf.real("0.1"); - for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { - assertClose(param, param.exp(vf.getPrecision()), Math.exp(param.doubleValue())); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testExpComparableToFloatingPoint(IValueFactory vf) { + IReal start = vf.real(-100); + IReal stop = start.negate(); + IReal increments = vf.real("0.1"); + for (IReal param = start; !stop.less(param).getValue(); param = param.add(increments)) { + assertClose(param, param.exp(vf.getPrecision()), Math.exp(param.doubleValue())); + } } - } - private void assertTakesLessThan(final int seconds, String call, final Runnable x) { - final Semaphore done = new Semaphore(0); - Thread t = new Thread(new Runnable() { - @Override - public void run() { + private void assertTakesLessThan(final int seconds, String call, final Runnable x) { + final Semaphore done = new Semaphore(0); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + x.run(); + } finally { + done.release(); + } + } + }); try { - x.run(); - } finally { - done.release(); + t.start(); + if (!done.tryAcquire(seconds, TimeUnit.SECONDS)) { + t.interrupt(); + fail(call + " took more than 2 second."); + } + } catch (InterruptedException e) { } - } - }); - try { - t.start(); - if (!done.tryAcquire(seconds, TimeUnit.SECONDS)) { - t.interrupt(); - fail(call + " took more than 2 second."); - } - } catch (InterruptedException e) { } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testExpPerformance(IValueFactory vf) { - // exp(x) is small for negative x - IReal start = vf.pi(20).multiply(vf.real(10)); - IReal stop = start.subtract(start.multiply(vf.real(100))); - IReal increments = vf.real(1); - for (IReal param = start; stop.less(param).getValue(); param = param.subtract(increments)) { - final IReal currentParam = param; - assertTakesLessThan(2, "exp(" + param + ")", new Runnable() { - @Override - public void run() { - currentParam.exp(vf.getPrecision()); + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testExpPerformance(IValueFactory vf) { + // exp(x) is small for negative x + IReal start = vf.pi(20).multiply(vf.real(10)); + IReal stop = start.subtract(start.multiply(vf.real(100))); + IReal increments = vf.real(1); + for (IReal param = start; stop.less(param).getValue(); param = param.subtract(increments)) { + final IReal currentParam = param; + assertTakesLessThan(2, "exp(" + param + ")", new Runnable() { + @Override + public void run() { + currentParam.exp(vf.getPrecision()); + } + }); } - }); + } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLnPerformance(IValueFactory vf) { - // ln(x) is small for low x - IReal start = vf.pi(50).multiply(vf.real(10).pow(vf.integer(8))); - IReal stop = start.divide(vf.real(10).pow(vf.integer(30)), vf.getPrecision()); - IReal increments = vf.real(10); - for (IReal param = start; stop.less(param).getValue(); param = - param.divide(increments, vf.getPrecision())) { - final IReal currentParam = param; - assertTakesLessThan(2, "ln(" + param + ")", new Runnable() { - @Override - public void run() { - currentParam.ln(vf.getPrecision()); + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLnPerformance(IValueFactory vf) { + // ln(x) is small for low x + IReal start = vf.pi(50).multiply(vf.real(10).pow(vf.integer(8))); + IReal stop = start.divide(vf.real(10).pow(vf.integer(30)), vf.getPrecision()); + IReal increments = vf.real(10); + for (IReal param = start; stop.less(param).getValue(); param = + param.divide(increments, vf.getPrecision())) { + final IReal currentParam = param; + assertTakesLessThan(2, "ln(" + param + ")", new Runnable() { + @Override + public void run() { + currentParam.ln(vf.getPrecision()); + } + }); } - }); } - } } diff --git a/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java index 8aec7ce7b..af7dbb180 100644 --- a/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java @@ -95,9 +95,9 @@ public void close() throws IOException { @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRegression40(IValueFactory vf, TypeStore store, - @GivenValue("twotups(<\\true(),twotups(,,),twotups(,)>)>,,,<\\true(),couples([])>),not(\\true())>),and(or([\\true()]),twotups(,))>)") - @ExpectedType("Boolean") + public void testRegression40(IValueFactory vf, TypeStore store, + @GivenValue("twotups(<\\true(),twotups(,,),twotups(,)>)>,,,<\\true(),couples([])>),not(\\true())>),and(or([\\true()]),twotups(,))>)") + @ExpectedType("Boolean") IConstructor t) throws FactTypeUseException, IOException { ioRoundTrip(vf, store, t); } @@ -106,12 +106,12 @@ public void testRegression40(IValueFactory vf, TypeStore store, public void testDateTimeIO(IValueFactory vf, TypeStore ts, IDateTime value) throws IOException { ioRoundTrip(vf, ts, value); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRegression42_2(IValueFactory vf, TypeStore store, @GivenValue("(\"\"():4,\"\"():3)") IValue v) throws IOException { ioRoundTrip(vf, store, v); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testSmallBinaryFileIO(IValueFactory vf, TypeStore ts, IValue value) throws IOException { ioRoundTripFile(vf, ts, value); @@ -166,7 +166,7 @@ public void testSmallRandomTypesIO(IValueFactory vf, TypeStore ts, Type tp) thro iopRoundTrip(vf, ts, tp); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @ArgumentsMaxDepth(12) @ArgumentsMaxWidth(6) public void testDeepRandomValuesIO(IValueFactory vf, TypeStore ts, IValue val) throws IOException { try { @@ -175,14 +175,14 @@ public void testDeepRandomValuesIO(IValueFactory vf, TypeStore ts, IValue val) t catch (Throwable e) { System.err.println("Deep random value failed, now trying to find the simplest sub-term which causes the failure..."); // Now we've found a bug in a (probably) very, very complex value. - // Usually it has several megabytes of random data. + // Usually it has several megabytes of random data. // We try to find a minimal sub-value which still fails somehow by // visiting each sub-term and running the test again on this. // The first sub-term to fail is reported via the AssertionFailed exception. // If only the big original term fails after all, then the BottomUp strategy - // will try that (its the last value of the stream) and fail again in + // will try that (its the last value of the stream) and fail again in // the same way as above. ValueStreams.bottomupbf(val).forEach(v -> { try { @@ -226,7 +226,7 @@ public void iopRoundTrip(IValueFactory vf, TypeStore ts, Type tp) throws IOExcep try (IWireOutputStream w = new BinaryWireOutputStream(buffer, 1000)) { IValueWriter.write(w, vf, WindowSizes.SMALL_WINDOW, tp); } - + try (IWireInputStream read = new BinaryWireInputStream(new ByteArrayInputStream(buffer.toByteArray()))) { Type result = IValueReader.readType(read, vf, () -> ts); @@ -239,7 +239,7 @@ public void iopRoundTrip(IValueFactory vf, TypeStore ts, Type tp) throws IOExcep } private final CompressionRate[] RATES_TO_TESTS = {CompressionRate.Normal, CompressionRate.Extreme, CompressionRate.None, CompressionRate.NoSharing}; - + private void ioRoundTrip(IValueFactory vf, TypeStore ts, IValue value) throws IOException { for (var rate: RATES_TO_TESTS) { try { @@ -260,15 +260,15 @@ private void ioRoundTrip(IValueFactory vf, TypeStore ts, IValue value, IValueOut IValue result = read.read(); if (!value.equals(result)) { String message = "Not equal: \n\t" + value + " : " + value.getType() + "( " + value.getClass() + ")" - + "\n\t" + result + " : " + result.getType() + "( " + result.getClass() + ")"; + + "\n\t" + result + " : " + result.getType() + "( " + result.getClass() + ")"; System.err.println("Test fail:"); System.err.println(message); System.err.flush(); fail(message); } else if (value.getType() != result.getType()) { - String message = "Type's not equal:\n\t" + value.getType() - + "\n\t" + result.getType(); + String message = "Type's not equal:\n\t" + value.getType() + + "\n\t" + result.getType(); System.err.println(message); fail(message); } @@ -276,8 +276,8 @@ else if (value instanceof IConstructor) { Type expectedConstructorType = ((IConstructor)value).getConstructorType(); Type returnedConstructorType = ((IConstructor)result).getConstructorType(); if (expectedConstructorType != returnedConstructorType) { - String message = "Constructor Type's not equal:\n\t" + expectedConstructorType - + "\n\t" + returnedConstructorType; + String message = "Constructor Type's not equal:\n\t" + expectedConstructorType + + "\n\t" + returnedConstructorType; System.err.println(message); fail(message); @@ -308,7 +308,7 @@ private void ioRoundTripFile(IValueFactory vf, TypeStore ts, IValue value, IValu IValue result = read.read(); if (!value.equals(result)) { String message = "Not equal: size: " + fileSize +") \n\t" + value + " : " + value.getType() + "( " + value.getClass() + ")" - + "\n\t" + result + " : " + result.getType() + "( " + result.getClass() + ")"; + + "\n\t" + result + " : " + result.getType() + "( " + result.getClass() + ")"; System.err.println(message); fail(message); } @@ -340,7 +340,7 @@ private void ioRoundTripFile2(IValueFactory vf, TypeStore ts, IValue value, IVal IValue result = read.read(); if (!value.equals(result)) { String message = "Not equal: (size: " + fileSize +") \n\t" + value + " : " + value.getType() - + "\n\t" + result + " : " + result.getType(); + + "\n\t" + result + " : " + result.getType(); System.err.println(message); fail(message); } diff --git a/src/test/java/io/usethesource/vallang/basic/BooleanStoreProvider.java b/src/test/java/io/usethesource/vallang/basic/BooleanStoreProvider.java index 2b623c269..3bf17da44 100644 --- a/src/test/java/io/usethesource/vallang/basic/BooleanStoreProvider.java +++ b/src/test/java/io/usethesource/vallang/basic/BooleanStoreProvider.java @@ -6,20 +6,20 @@ public class BooleanStoreProvider { - public static TypeStore store = new TypeStore(); - private static TypeFactory tf = TypeFactory.getInstance(); - protected static Type Boolean = tf.abstractDataType(store, "Boolean"); + public static TypeStore store = new TypeStore(); + private static TypeFactory tf = TypeFactory.getInstance(); + protected static Type Boolean = tf.abstractDataType(store, "Boolean"); - protected static Type Name = tf.abstractDataType(store, "Name"); - protected static Type True = tf.constructor(store, Boolean, "true"); - - protected static Type False = tf.constructor(store, Boolean, "false"); - protected static Type And = tf.constructor(store, Boolean, "and", Boolean, Boolean); - protected static Type Or = tf.constructor(store, Boolean, "or", tf.listType(Boolean)); - protected static Type Not = tf.constructor(store, Boolean, "not", Boolean); - protected static Type TwoTups = tf.constructor(store, Boolean, "twotups", - tf.tupleType(Boolean, Boolean), tf.tupleType(Boolean, Boolean)); - protected static Type NameNode = tf.constructor(store, Name, "name", tf.stringType()); - protected static Type Friends = tf.constructor(store, Boolean, "friends", tf.listType(Name)); - protected static Type Couples = tf.constructor(store, Boolean, "couples", tf.lrelType(Name, Name)); + protected static Type Name = tf.abstractDataType(store, "Name"); + protected static Type True = tf.constructor(store, Boolean, "true"); + + protected static Type False = tf.constructor(store, Boolean, "false"); + protected static Type And = tf.constructor(store, Boolean, "and", Boolean, Boolean); + protected static Type Or = tf.constructor(store, Boolean, "or", tf.listType(Boolean)); + protected static Type Not = tf.constructor(store, Boolean, "not", Boolean); + protected static Type TwoTups = tf.constructor(store, Boolean, "twotups", + tf.tupleType(Boolean, Boolean), tf.tupleType(Boolean, Boolean)); + protected static Type NameNode = tf.constructor(store, Name, "name", tf.stringType()); + protected static Type Friends = tf.constructor(store, Boolean, "friends", tf.listType(Name)); + protected static Type Couples = tf.constructor(store, Boolean, "couples", tf.lrelType(Name, Name)); } diff --git a/src/test/java/io/usethesource/vallang/basic/ConcurrentTests.java b/src/test/java/io/usethesource/vallang/basic/ConcurrentTests.java index 256e9bdaf..356bd754b 100644 --- a/src/test/java/io/usethesource/vallang/basic/ConcurrentTests.java +++ b/src/test/java/io/usethesource/vallang/basic/ConcurrentTests.java @@ -16,7 +16,7 @@ import io.usethesource.vallang.type.TypeStore; public class ConcurrentTests { - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void parallelRandomGenerators(IValueFactory vf) throws InterruptedException, BrokenBarrierException, TimeoutException { int cores = Math.max(2, Runtime.getRuntime().availableProcessors()); diff --git a/src/test/java/io/usethesource/vallang/basic/EqualitySmokeTest.java b/src/test/java/io/usethesource/vallang/basic/EqualitySmokeTest.java index 8df3c4567..008e54c82 100644 --- a/src/test/java/io/usethesource/vallang/basic/EqualitySmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/EqualitySmokeTest.java @@ -1,201 +1,201 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IConstructor; -import io.usethesource.vallang.IMapWriter; -import io.usethesource.vallang.INode; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; -import io.usethesource.vallang.type.TypeStore; - -public final class EqualitySmokeTest { - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInteger(IValueFactory vf) { - assertTrue(vf.integer(0).equals(vf.integer(0))); - assertFalse(vf.integer(0).equals(vf.integer(1))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testDouble(IValueFactory vf) { - assertTrue(vf.real(0.0).equals(vf.real(0.0))); - assertTrue(vf.real(1.0).equals(vf.real(1.00000))); - assertFalse(vf.real(0.0).equals(vf.real(1.0))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testString(IValueFactory vf) { - assertTrue(vf.string("").equals(vf.string(""))); - assertTrue(vf.string("a").equals(vf.string("a"))); - assertFalse(vf.string("a").equals(vf.string("b"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEmptyCollectionsAreVoid(IValueFactory vf, TypeFactory tf) { - assertTrue(vf.list().getElementType().isSubtypeOf(tf.voidType())); - assertTrue(vf.set().getElementType().isSubtypeOf(tf.voidType())); - assertTrue(vf.map().getKeyType().isSubtypeOf(tf.voidType())); - assertTrue(vf.map().getValueType().isSubtypeOf(tf.voidType())); - - assertTrue(vf.listWriter().done().getElementType().isSubtypeOf(tf.voidType())); - assertTrue(vf.setWriter().done().getElementType().isSubtypeOf(tf.voidType())); - assertTrue(vf.mapWriter().done().getKeyType().isSubtypeOf(tf.voidType())); - assertTrue(vf.mapWriter().done().getValueType().isSubtypeOf(tf.voidType())); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testList(IValueFactory vf) { - assertTrue(vf.list().equals(vf.list()), "empty lists are always equal"); - - assertTrue(vf.list(vf.integer(1)).equals(vf.list(vf.integer(1)))); - assertFalse(vf.list(vf.integer(1)).equals(vf.list(vf.integer(0)))); - - assertTrue(vf.list(vf.list()).equals(vf.list(vf.list()))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSet(IValueFactory vf) { - assertTrue(vf.set().equals(vf.set()), "empty sets are always equal"); - - assertTrue(vf.set(vf.integer(1)).equals(vf.set(vf.integer(1)))); - assertFalse(vf.set(vf.integer(1)).equals(vf.set(vf.integer(0)))); - - assertTrue(vf.set(vf.set()).equals(vf.set(vf.set()))); - } - - /** - * Documenting the current relationship between Node and Constructor in terms of equality and hash - * codes. - */ - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testConstructorIsEqualToConstructor(IValueFactory vf, TypeFactory tf) { - final INode n = vf.node("constructorComparableName", vf.integer(1), vf.integer(2)); - - final TypeStore ts = new TypeStore(); - final Type adtType = tf.abstractDataType(ts, "adtTypeNameThatIsIgnored"); - final Type constructorType = tf.constructor(ts, adtType, "constructorComparableName", - tf.integerType(), tf.integerType()); - - final IConstructor c = vf.constructor(constructorType, vf.integer(1), vf.integer(2)); - - // they are not the same - assertFalse(n.equals(c)); - assertFalse(c.equals(n)); - /* - * TODO: what is the general contract between equals() and hashCode()? - */ - assertFalse(n.hashCode() == c.hashCode()); - - // unidirectional: n -> c = false - assertFalse(n.equals(c)); - - // unidirectional: c -> n = false - assertFalse(c.equals(n)); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testNodeMatch(IValueFactory vf) { - final INode n = vf.node("hello"); - final INode m = n.asWithKeywordParameters().setParameter("x", vf.integer(0)); - - assertFalse(n.equals(m)); - assertFalse(m.equals(n)); - assertTrue(n.match(m)); - assertTrue(m.match(n)); - assertFalse(m.equals(n)); - assertFalse(n.equals(m)); - - final INode a = vf.node("hello", vf.string("bye")); - final INode b = a.asWithKeywordParameters().setParameter("x", vf.integer(0)); - - assertFalse(a.equals(b)); - assertFalse(b.equals(a)); - assertTrue(a.match(b)); - assertTrue(b.match(a)); - assertTrue(a.match(a)); - assertTrue(b.match(b)); - assertFalse(b.equals(a)); - assertFalse(a.equals(b)); - - assertTrue(vf.list(a).match(vf.list(b))); - assertTrue(vf.list(b).match(vf.list(a))); - assertTrue(vf.set(a).match(vf.set(b))); - assertTrue(vf.set(b).match(vf.set(a))); - assertTrue(vf.tuple(a).match(vf.tuple(b))); - assertTrue(vf.tuple(b).match(vf.tuple(a))); - - final IMapWriter map1 = vf.mapWriter(); - final IMapWriter map2 = vf.mapWriter(); - map1.put(a, vf.integer(0)); - map2.put(b, vf.integer(0)); - assertTrue(map1.done().match(map2.done())); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testConstructorMatch(IValueFactory vf, TypeFactory tf) { - final TypeStore store = new TypeStore(); - final Type Hello = tf.abstractDataType(store, "Hello"); - final Type Cons = tf.constructor(store, Hello, "bye"); - store.declareKeywordParameter(Cons, "x", tf.integerType()); - - final IConstructor n = vf.constructor(Cons); - final IConstructor m = n.asWithKeywordParameters().setParameter("x", vf.integer(0)); - - assertFalse(n.equals(m)); - assertFalse(m.equals(n)); - assertTrue(n.match(m)); - assertTrue(m.match(n)); - assertTrue(n.match(n)); - assertTrue(m.match(m)); - assertFalse(m.equals(n)); - assertFalse(n.equals(m)); - - Type AR = tf.constructor(store, Hello, "aurevoir", tf.stringType(), "greeting"); - store.declareKeywordParameter(AR, "x", tf.integerType()); - - final IConstructor a = vf.constructor(AR, vf.string("bye")); - final IConstructor b = a.asWithKeywordParameters().setParameter("x", vf.integer(0)); - - assertFalse(a.equals(b)); - assertFalse(b.equals(a)); - assertTrue(a.match(b)); - assertTrue(b.match(a)); - assertTrue(a.match(a)); - assertTrue(b.match(b)); - assertFalse(b.equals(a)); - assertFalse(a.equals(b)); - - assertTrue(vf.list(a).match(vf.list(b))); - assertTrue(vf.list(b).match(vf.list(a))); - assertTrue(vf.set(a).match(vf.set(b))); - assertTrue(vf.set(b).match(vf.set(a))); - assertTrue(vf.tuple(a).match(vf.tuple(b))); - assertTrue(vf.tuple(b).match(vf.tuple(a))); - - final IMapWriter map1 = vf.mapWriter(); - final IMapWriter map2 = vf.mapWriter(); - map1.put(a, vf.integer(0)); - map2.put(b, vf.integer(0)); - assertTrue(map1.done().match(map2.done())); - - } -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IMapWriter; +import io.usethesource.vallang.INode; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; +import io.usethesource.vallang.type.TypeStore; + +public final class EqualitySmokeTest { + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInteger(IValueFactory vf) { + assertTrue(vf.integer(0).equals(vf.integer(0))); + assertFalse(vf.integer(0).equals(vf.integer(1))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testDouble(IValueFactory vf) { + assertTrue(vf.real(0.0).equals(vf.real(0.0))); + assertTrue(vf.real(1.0).equals(vf.real(1.00000))); + assertFalse(vf.real(0.0).equals(vf.real(1.0))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testString(IValueFactory vf) { + assertTrue(vf.string("").equals(vf.string(""))); + assertTrue(vf.string("a").equals(vf.string("a"))); + assertFalse(vf.string("a").equals(vf.string("b"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEmptyCollectionsAreVoid(IValueFactory vf, TypeFactory tf) { + assertTrue(vf.list().getElementType().isSubtypeOf(tf.voidType())); + assertTrue(vf.set().getElementType().isSubtypeOf(tf.voidType())); + assertTrue(vf.map().getKeyType().isSubtypeOf(tf.voidType())); + assertTrue(vf.map().getValueType().isSubtypeOf(tf.voidType())); + + assertTrue(vf.listWriter().done().getElementType().isSubtypeOf(tf.voidType())); + assertTrue(vf.setWriter().done().getElementType().isSubtypeOf(tf.voidType())); + assertTrue(vf.mapWriter().done().getKeyType().isSubtypeOf(tf.voidType())); + assertTrue(vf.mapWriter().done().getValueType().isSubtypeOf(tf.voidType())); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testList(IValueFactory vf) { + assertTrue(vf.list().equals(vf.list()), "empty lists are always equal"); + + assertTrue(vf.list(vf.integer(1)).equals(vf.list(vf.integer(1)))); + assertFalse(vf.list(vf.integer(1)).equals(vf.list(vf.integer(0)))); + + assertTrue(vf.list(vf.list()).equals(vf.list(vf.list()))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSet(IValueFactory vf) { + assertTrue(vf.set().equals(vf.set()), "empty sets are always equal"); + + assertTrue(vf.set(vf.integer(1)).equals(vf.set(vf.integer(1)))); + assertFalse(vf.set(vf.integer(1)).equals(vf.set(vf.integer(0)))); + + assertTrue(vf.set(vf.set()).equals(vf.set(vf.set()))); + } + + /** + * Documenting the current relationship between Node and Constructor in terms of equality and hash + * codes. + */ + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testConstructorIsEqualToConstructor(IValueFactory vf, TypeFactory tf) { + final INode n = vf.node("constructorComparableName", vf.integer(1), vf.integer(2)); + + final TypeStore ts = new TypeStore(); + final Type adtType = tf.abstractDataType(ts, "adtTypeNameThatIsIgnored"); + final Type constructorType = tf.constructor(ts, adtType, "constructorComparableName", + tf.integerType(), tf.integerType()); + + final IConstructor c = vf.constructor(constructorType, vf.integer(1), vf.integer(2)); + + // they are not the same + assertFalse(n.equals(c)); + assertFalse(c.equals(n)); + /* + * TODO: what is the general contract between equals() and hashCode()? + */ + assertFalse(n.hashCode() == c.hashCode()); + + // unidirectional: n -> c = false + assertFalse(n.equals(c)); + + // unidirectional: c -> n = false + assertFalse(c.equals(n)); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testNodeMatch(IValueFactory vf) { + final INode n = vf.node("hello"); + final INode m = n.asWithKeywordParameters().setParameter("x", vf.integer(0)); + + assertFalse(n.equals(m)); + assertFalse(m.equals(n)); + assertTrue(n.match(m)); + assertTrue(m.match(n)); + assertFalse(m.equals(n)); + assertFalse(n.equals(m)); + + final INode a = vf.node("hello", vf.string("bye")); + final INode b = a.asWithKeywordParameters().setParameter("x", vf.integer(0)); + + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + assertTrue(a.match(b)); + assertTrue(b.match(a)); + assertTrue(a.match(a)); + assertTrue(b.match(b)); + assertFalse(b.equals(a)); + assertFalse(a.equals(b)); + + assertTrue(vf.list(a).match(vf.list(b))); + assertTrue(vf.list(b).match(vf.list(a))); + assertTrue(vf.set(a).match(vf.set(b))); + assertTrue(vf.set(b).match(vf.set(a))); + assertTrue(vf.tuple(a).match(vf.tuple(b))); + assertTrue(vf.tuple(b).match(vf.tuple(a))); + + final IMapWriter map1 = vf.mapWriter(); + final IMapWriter map2 = vf.mapWriter(); + map1.put(a, vf.integer(0)); + map2.put(b, vf.integer(0)); + assertTrue(map1.done().match(map2.done())); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testConstructorMatch(IValueFactory vf, TypeFactory tf) { + final TypeStore store = new TypeStore(); + final Type Hello = tf.abstractDataType(store, "Hello"); + final Type Cons = tf.constructor(store, Hello, "bye"); + store.declareKeywordParameter(Cons, "x", tf.integerType()); + + final IConstructor n = vf.constructor(Cons); + final IConstructor m = n.asWithKeywordParameters().setParameter("x", vf.integer(0)); + + assertFalse(n.equals(m)); + assertFalse(m.equals(n)); + assertTrue(n.match(m)); + assertTrue(m.match(n)); + assertTrue(n.match(n)); + assertTrue(m.match(m)); + assertFalse(m.equals(n)); + assertFalse(n.equals(m)); + + Type AR = tf.constructor(store, Hello, "aurevoir", tf.stringType(), "greeting"); + store.declareKeywordParameter(AR, "x", tf.integerType()); + + final IConstructor a = vf.constructor(AR, vf.string("bye")); + final IConstructor b = a.asWithKeywordParameters().setParameter("x", vf.integer(0)); + + assertFalse(a.equals(b)); + assertFalse(b.equals(a)); + assertTrue(a.match(b)); + assertTrue(b.match(a)); + assertTrue(a.match(a)); + assertTrue(b.match(b)); + assertFalse(b.equals(a)); + assertFalse(a.equals(b)); + + assertTrue(vf.list(a).match(vf.list(b))); + assertTrue(vf.list(b).match(vf.list(a))); + assertTrue(vf.set(a).match(vf.set(b))); + assertTrue(vf.set(b).match(vf.set(a))); + assertTrue(vf.tuple(a).match(vf.tuple(b))); + assertTrue(vf.tuple(b).match(vf.tuple(a))); + + final IMapWriter map1 = vf.mapWriter(); + final IMapWriter map2 = vf.mapWriter(); + map1.put(a, vf.integer(0)); + map2.put(b, vf.integer(0)); + assertTrue(map1.done().match(map2.done())); + + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/IoSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/IoSmokeTest.java index af5d4aa5d..dff7f2154 100644 --- a/src/test/java/io/usethesource/vallang/basic/IoSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/IoSmokeTest.java @@ -1,140 +1,140 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation. - * 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: - * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - - *******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.Map; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IConstructor; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.io.StandardTextReader; -import io.usethesource.vallang.io.StandardTextWriter; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; -import io.usethesource.vallang.type.TypeStore; - -public class IoSmokeTest extends BooleanStoreProvider { - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testToString(IValueFactory vf) throws FactTypeUseException, IOException { - StandardTextReader reader = new StandardTextReader(); - TypeFactory TF = TypeFactory.getInstance(); - - // there are specialized implementations for different sizes of constructors. - // each must have a specialized toString implementation to work correctly. - - TypeStore store = new TypeStore(); - Type A = TF.abstractDataType(store, "A"); - - Type[] examples = new Type[] { - TF.constructor(store, A, "x1", TF.integerType(), "a1"), - TF.constructor(store, A, "x2", TF.integerType(), "a1", TF.integerType(), "a2"), - TF.constructor(store, A, "x3", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3"), - TF.constructor(store, A, "x4", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4"), - TF.constructor(store, A, "x5", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5"), - TF.constructor(store, A, "x6", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6"), - TF.constructor(store, A, "x7", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6", TF.integerType(), "a7"), - TF.constructor(store, A, "x8", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6", TF.integerType(), "a7", TF.integerType(), "a8"), - }; - - for (int i = 0; i < 8; i++) { - IValue[] kids = new IValue[examples[i].getArity()]; - for (int k = 0; k < examples[i].getArity(); k++) { - kids[k] = vf.integer(k); - } - IConstructor cons = vf.constructor(examples[i], kids); - String string = cons.toString(); - IValue result = reader.read(vf, store, A, new StringReader(string)); - - assertEquals(result, cons); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testParametrizedDataType(IValueFactory vf, TypeFactory tf, TypeStore store) throws FactTypeUseException, IOException { - Type T = tf.parameterType("T"); - Type MaybeT = tf.abstractDataType(store, "Maybe", T); - Type just = tf.constructor(store, MaybeT, "just", T, "t"); - Type MaybeInt = MaybeT.instantiate(Map.of(T, tf.integerType())); - Type B = tf.abstractDataType(store, "B"); - Type f = tf.constructor(store, B, "f", MaybeInt); - - StandardTextReader reader = new StandardTextReader(); - - IValue s = reader.read(vf, store, B, new StringReader("f(just(1))")); - assertEquals(vf.constructor(f, vf.constructor(just, vf.integer(1))), s); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStandardReader(IValueFactory vf) throws FactTypeUseException, IOException { - StandardTextReader reader = new StandardTextReader(); - - IValue s = reader.read(vf, new StringReader("\"a b c\"")); - assertEquals(s, vf.string("a b c")); - - IValue v = reader.read(vf, new StringReader("\"f\"(\"a b c\")")); - assertEquals(v, vf.node("f", vf.string("a b c"))); - - IValue vv = reader.read(vf, new StringReader("\"f\"(\"a b c\", x=1)")); - assertEquals(vv, vf.node("f", vf.string("a b c")).asWithKeywordParameters().setParameter("x", vf.integer(1))); - - IValue vvv = reader.read(vf, store, Boolean, new StringReader("\\true(x=1)")); - assertEquals(vvv, vf.constructor(True).asWithKeywordParameters().setParameter("x", vf.integer(1))); - - IValue r = reader.read(vf, new StringReader("[1.7976931348623157E+308]")); - assertEquals(r, vf.list(vf.real("1.7976931348623157E+308"))); - - IValue m = reader.read(vf, new StringReader("()")); - assertEquals(m, vf.mapWriter().done()); - - IValue t = reader.read(vf, new StringReader("<()>")); - assertEquals(t, vf.tuple(vf.mapWriter().done())); - - StringWriter w = new StringWriter(); - new StandardTextWriter().write(vf.tuple(), w); - IValue u = reader.read(vf, new StringReader(w.toString())); - assertEquals(u, vf.tuple()); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLegacyAnnotationTextReaderNode(IValueFactory vf) throws FactTypeUseException, IOException { - String input = "\"node\"()[@anno=2]"; - StandardTextReader reader = new StandardTextReader(); - IValue s = reader.read(vf, new StringReader(input)); - - assertEquals(s.asWithKeywordParameters().getParameter("anno"), vf.integer(2)); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLegacyAnnotationTextReaderConstructor(IValueFactory vf, TypeFactory tf, TypeStore store) throws FactTypeUseException, IOException { - Type A = tf.abstractDataType(store, "A"); - tf.constructor(store, A, "a"); - store.declareKeywordParameter(A, "anno", tf.integerType()); - - String input = "a()[@anno=2]"; - StandardTextReader reader = new StandardTextReader(); - IValue s = reader.read(vf, store, A, new StringReader(input)); - - assertEquals(s.asWithKeywordParameters().getParameter("anno"), vf.integer(2)); - } -} +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation. + * 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: + * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + + *******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Map; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.io.StandardTextReader; +import io.usethesource.vallang.io.StandardTextWriter; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; +import io.usethesource.vallang.type.TypeStore; + +public class IoSmokeTest extends BooleanStoreProvider { + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testToString(IValueFactory vf) throws FactTypeUseException, IOException { + StandardTextReader reader = new StandardTextReader(); + TypeFactory TF = TypeFactory.getInstance(); + + // there are specialized implementations for different sizes of constructors. + // each must have a specialized toString implementation to work correctly. + + TypeStore store = new TypeStore(); + Type A = TF.abstractDataType(store, "A"); + + Type[] examples = new Type[] { + TF.constructor(store, A, "x1", TF.integerType(), "a1"), + TF.constructor(store, A, "x2", TF.integerType(), "a1", TF.integerType(), "a2"), + TF.constructor(store, A, "x3", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3"), + TF.constructor(store, A, "x4", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4"), + TF.constructor(store, A, "x5", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5"), + TF.constructor(store, A, "x6", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6"), + TF.constructor(store, A, "x7", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6", TF.integerType(), "a7"), + TF.constructor(store, A, "x8", TF.integerType(), "a1", TF.integerType(), "a2", TF.integerType(), "a3", TF.integerType(), "a4", TF.integerType(), "a5", TF.integerType(), "a6", TF.integerType(), "a7", TF.integerType(), "a8"), + }; + + for (int i = 0; i < 8; i++) { + IValue[] kids = new IValue[examples[i].getArity()]; + for (int k = 0; k < examples[i].getArity(); k++) { + kids[k] = vf.integer(k); + } + IConstructor cons = vf.constructor(examples[i], kids); + String string = cons.toString(); + IValue result = reader.read(vf, store, A, new StringReader(string)); + + assertEquals(result, cons); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testParametrizedDataType(IValueFactory vf, TypeFactory tf, TypeStore store) throws FactTypeUseException, IOException { + Type T = tf.parameterType("T"); + Type MaybeT = tf.abstractDataType(store, "Maybe", T); + Type just = tf.constructor(store, MaybeT, "just", T, "t"); + Type MaybeInt = MaybeT.instantiate(Map.of(T, tf.integerType())); + Type B = tf.abstractDataType(store, "B"); + Type f = tf.constructor(store, B, "f", MaybeInt); + + StandardTextReader reader = new StandardTextReader(); + + IValue s = reader.read(vf, store, B, new StringReader("f(just(1))")); + assertEquals(vf.constructor(f, vf.constructor(just, vf.integer(1))), s); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStandardReader(IValueFactory vf) throws FactTypeUseException, IOException { + StandardTextReader reader = new StandardTextReader(); + + IValue s = reader.read(vf, new StringReader("\"a b c\"")); + assertEquals(s, vf.string("a b c")); + + IValue v = reader.read(vf, new StringReader("\"f\"(\"a b c\")")); + assertEquals(v, vf.node("f", vf.string("a b c"))); + + IValue vv = reader.read(vf, new StringReader("\"f\"(\"a b c\", x=1)")); + assertEquals(vv, vf.node("f", vf.string("a b c")).asWithKeywordParameters().setParameter("x", vf.integer(1))); + + IValue vvv = reader.read(vf, store, Boolean, new StringReader("\\true(x=1)")); + assertEquals(vvv, vf.constructor(True).asWithKeywordParameters().setParameter("x", vf.integer(1))); + + IValue r = reader.read(vf, new StringReader("[1.7976931348623157E+308]")); + assertEquals(r, vf.list(vf.real("1.7976931348623157E+308"))); + + IValue m = reader.read(vf, new StringReader("()")); + assertEquals(m, vf.mapWriter().done()); + + IValue t = reader.read(vf, new StringReader("<()>")); + assertEquals(t, vf.tuple(vf.mapWriter().done())); + + StringWriter w = new StringWriter(); + new StandardTextWriter().write(vf.tuple(), w); + IValue u = reader.read(vf, new StringReader(w.toString())); + assertEquals(u, vf.tuple()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLegacyAnnotationTextReaderNode(IValueFactory vf) throws FactTypeUseException, IOException { + String input = "\"node\"()[@anno=2]"; + StandardTextReader reader = new StandardTextReader(); + IValue s = reader.read(vf, new StringReader(input)); + + assertEquals(s.asWithKeywordParameters().getParameter("anno"), vf.integer(2)); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLegacyAnnotationTextReaderConstructor(IValueFactory vf, TypeFactory tf, TypeStore store) throws FactTypeUseException, IOException { + Type A = tf.abstractDataType(store, "A"); + tf.constructor(store, A, "a"); + store.declareKeywordParameter(A, "anno", tf.integerType()); + + String input = "a()[@anno=2]"; + StandardTextReader reader = new StandardTextReader(); + IValue s = reader.read(vf, store, A, new StringReader(input)); + + assertEquals(s.asWithKeywordParameters().getParameter("anno"), vf.integer(2)); + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/LazyStringOperationsTest.java b/src/test/java/io/usethesource/vallang/basic/LazyStringOperationsTest.java index bc98fe5d0..02fb70ee0 100644 --- a/src/test/java/io/usethesource/vallang/basic/LazyStringOperationsTest.java +++ b/src/test/java/io/usethesource/vallang/basic/LazyStringOperationsTest.java @@ -20,7 +20,7 @@ public final class LazyStringOperationsTest { - private final Random rnd = new Random(); + private final Random rnd = new Random(); private IString example2(final IValueFactory vf) { return vf.string("abcdef\nxyz").indent(vf.string("123"), true); @@ -30,228 +30,228 @@ private IString example1(final IValueFactory vf) { return vf.string("ab").concat(vf.string("cd")).concat(vf.string("ef")).concat(vf.string("gh")); } - private IString genString(IValueFactory vf, int max) { - return vf.string(RandomUtil.string(rnd, rnd.nextInt(max))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRandomHashcodeEquals(IValueFactory vf) { - for (int count = 0; count < 50; count++) { - int loops = 100 + rnd.nextInt(250); - - try { - StringValue.setMaxFlatString(3); - StringValue.setMaxUnbalance(5); - StringBuilder b = new StringBuilder(); - IString concat = genString(vf, 25); - b.append(concat.getValue()); - - for (int i = 0; i < loops; i++) { - IString next = genString(vf, 25); - concat = concat.concat(next); - b.append(next.getValue()); - } - - IString single = vf.string(b.toString()); - - assertTrue(single.hashCode() == concat.hashCode()); - assertTrue(single.equals(concat)); - assertTrue(concat.equals(single)); - } finally { - StringValue.resetMaxFlatString(); - StringValue.resetMaxUnbalance(); - } - } - } - - protected TypeFactory tf = TypeFactory.getInstance(); - - protected void assertEqual(IValue l, IValue r) { - assertTrue(l.equals(r), () -> "Expected " + l + " got " + r); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringLength(IValueFactory vf) { - assertTrue(example1(vf).substring(0, 0).length() == 0); - assertTrue(example1(vf).substring(0, 1).length() == 1); - assertTrue(example1(vf).substring(0, 2).length() == 2); - assertTrue(example1(vf).substring(0, 3).length() == 3); - assertTrue(example1(vf).substring(0, 4).length() == 4); - assertTrue(example1(vf).substring(0, 5).length() == 5); - assertTrue(example1(vf).substring(0, 6).length() == 6); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEquals(IValueFactory vf) { - try { - StringValue.setMaxFlatString(1); - StringValue.setMaxUnbalance(1); - - IString x = example1(vf); - IString y = vf.string("abcdefgh"); - IString z = vf.string("abcdefgi"); - - assertTrue(x.hashCode() == y.hashCode()); - assertTrue(x.equals(y)); - assertTrue(y.equals(x)); - assertTrue(!z.equals(x)); - assertTrue(x.substring(0, 0).equals(vf.string(""))); - } finally { - StringValue.resetMaxFlatString(); - StringValue.resetMaxUnbalance(); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEqualsUnicode(IValueFactory vf) { - try { - StringValue.setMaxFlatString(1); - StringValue.setMaxUnbalance(1); - - IString x = vf.string("a🍕b").concat(vf.string("c🍕d")).concat(vf.string("e🍕f")).concat(vf.string("g🍕h")); - IString y = vf.string("a🍕bc🍕de🍕fg🍕h"); - - assertTrue(x.hashCode() == y.hashCode()); - assertTrue(x.equals(y)); - assertTrue(y.equals(x)); - assertTrue(x.substring(0, 0).equals(vf.string(""))); - } finally { - StringValue.resetMaxFlatString(); - StringValue.resetMaxUnbalance(); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testConcat(IValueFactory vf) { - assertTrue(example1(vf) - .equals(example1(vf))); - assertTrue(example1(vf) - .equals(vf.string("ab").concat(vf.string("cd")).concat(vf.string("ef").concat(vf.string("gh"))))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringCharAt(IValueFactory vf) { - assertTrue(example2(vf).charAt(0) == '1'); - assertTrue(example2(vf).charAt(1) == '2'); - assertTrue(example2(vf).charAt(2) == '3'); - assertTrue(example2(vf).charAt(3) == 'a'); - assertTrue(example2(vf).charAt(4) == 'b'); - assertTrue(example2(vf).charAt(5) == 'c'); - assertTrue(example2(vf).charAt(6) == 'd'); - assertTrue(example2(vf).charAt(7) == 'e'); - assertTrue(example2(vf).charAt(8) == 'f'); - assertTrue(example2(vf).charAt(9) == '\n'); - assertTrue(example2(vf).charAt(10) == '1'); - assertTrue(example2(vf).charAt(11) == '2'); - assertTrue(example2(vf).charAt(12) == '3'); - assertTrue(example2(vf).charAt(13) == 'x'); - assertTrue(example2(vf).charAt(14) == 'y'); - assertTrue(example2(vf).charAt(15) == 'z'); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringSubString(IValueFactory vf) { - assertEqual(example2(vf).substring(0, 1), vf.string("1")); - assertEqual(example2(vf).substring(0, 2), vf.string("12")); - assertEqual(example2(vf).substring(0, 3), vf.string("123")); - assertEqual(example2(vf).substring(0, 4), vf.string("123a")); - assertEqual(example2(vf).substring(0, 5), vf.string("123ab")); - assertEqual(example2(vf).substring(0, 6), vf.string("123abc")); - assertEqual(example2(vf).substring(0, 7), vf.string("123abcd")); - assertEqual(example2(vf).substring(0, 8), vf.string("123abcde")); - assertEqual(example2(vf).substring(0, 9), vf.string("123abcdef")); - assertEqual(example2(vf).substring(0, 10), vf.string("123abcdef\n")); - assertEqual(example2(vf).substring(0, 11), vf.string("123abcdef\n1")); - assertEqual(example2(vf).substring(0, 12), vf.string("123abcdef\n12")); - assertEqual(example2(vf).substring(0, 13), vf.string("123abcdef\n123")); - assertEqual(example2(vf).substring(0, 14), vf.string("123abcdef\n123x")); - assertEqual(example2(vf).substring(0, 15), vf.string("123abcdef\n123xy")); - assertEqual(example2(vf).substring(0, 16), vf.string("123abcdef\n123xyz")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testStringReplace(IValueFactory vf) { - int n = 10; - StringValue.setMaxFlatString(1); - StringValue.setMaxUnbalance(0); - String[] s = { "a", "b", "c", "d", "e", "f", "g", "h" }; - IString str = vf.string(s[0]); - for (int i = 1; i < n; i++) { - str = str.concat(vf.string(s[i % 8])); - // result = vf.string(s[i%8]).concat(result); - } - // System.out.println(example.replace(4, 1, 4, vf.string("x")).getValue()); - assertEqual(example1(vf).replace(0, 1, 0, vf.string("x")), vf.string("xabcdefgh")); - assertEqual(example1(vf).replace(1, 1, 1, vf.string("x")), vf.string("axbcdefgh")); - assertEqual(example1(vf).replace(2, 1, 2, vf.string("x")), vf.string("abxcdefgh")); - assertEqual(example1(vf).replace(3, 1, 3, vf.string("x")), vf.string("abcxdefgh")); - assertEqual(example1(vf).replace(4, 1, 4, vf.string("x")), vf.string("abcdxefgh")); - assertEqual(example1(vf).replace(5, 1, 5, vf.string("x")), vf.string("abcdexfgh")); - assertEqual(example1(vf).replace(6, 1, 6, vf.string("x")), vf.string("abcdefxgh")); - assertEqual(str.replace(6, 1, 6, vf.string("x").concat(vf.string("y"))), - vf.string("abcdefxygh").concat(str.substring(8))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void neverRunOutOfStack(IValueFactory vf) { - int outofStack = 100000; - - // first we have to know for sure that we would run out of stack with @see - // outOfStack iterations: - try { - StringValue.setMaxFlatString(1); - StringValue.setMaxUnbalance(Integer.MAX_VALUE); - - IString v = vf.string("x"); - for (int i = 0; i < outofStack; i++) { - v = v.concat(vf.string("-" + i)); - } - - try { - v.write(new StringWriter()); - fail("this should run out of stack"); - } catch (StackOverflowError e) { - // yes, that is what is expected - } catch (IOException e) { + private IString genString(IValueFactory vf, int max) { + return vf.string(RandomUtil.string(rnd, rnd.nextInt(max))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRandomHashcodeEquals(IValueFactory vf) { + for (int count = 0; count < 50; count++) { + int loops = 100 + rnd.nextInt(250); + + try { + StringValue.setMaxFlatString(3); + StringValue.setMaxUnbalance(5); + StringBuilder b = new StringBuilder(); + IString concat = genString(vf, 25); + b.append(concat.getValue()); + + for (int i = 0; i < loops; i++) { + IString next = genString(vf, 25); + concat = concat.concat(next); + b.append(next.getValue()); + } + + IString single = vf.string(b.toString()); + + assertTrue(single.hashCode() == concat.hashCode()); + assertTrue(single.equals(concat)); + assertTrue(concat.equals(single)); + } finally { + StringValue.resetMaxFlatString(); + StringValue.resetMaxUnbalance(); + } + } + } + + protected TypeFactory tf = TypeFactory.getInstance(); + + protected void assertEqual(IValue l, IValue r) { + assertTrue(l.equals(r), () -> "Expected " + l + " got " + r); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringLength(IValueFactory vf) { + assertTrue(example1(vf).substring(0, 0).length() == 0); + assertTrue(example1(vf).substring(0, 1).length() == 1); + assertTrue(example1(vf).substring(0, 2).length() == 2); + assertTrue(example1(vf).substring(0, 3).length() == 3); + assertTrue(example1(vf).substring(0, 4).length() == 4); + assertTrue(example1(vf).substring(0, 5).length() == 5); + assertTrue(example1(vf).substring(0, 6).length() == 6); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEquals(IValueFactory vf) { + try { + StringValue.setMaxFlatString(1); + StringValue.setMaxUnbalance(1); + + IString x = example1(vf); + IString y = vf.string("abcdefgh"); + IString z = vf.string("abcdefgi"); + + assertTrue(x.hashCode() == y.hashCode()); + assertTrue(x.equals(y)); + assertTrue(y.equals(x)); + assertTrue(!z.equals(x)); + assertTrue(x.substring(0, 0).equals(vf.string(""))); + } finally { + StringValue.resetMaxFlatString(); + StringValue.resetMaxUnbalance(); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEqualsUnicode(IValueFactory vf) { + try { + StringValue.setMaxFlatString(1); + StringValue.setMaxUnbalance(1); + + IString x = vf.string("a🍕b").concat(vf.string("c🍕d")).concat(vf.string("e🍕f")).concat(vf.string("g🍕h")); + IString y = vf.string("a🍕bc🍕de🍕fg🍕h"); + + assertTrue(x.hashCode() == y.hashCode()); + assertTrue(x.equals(y)); + assertTrue(y.equals(x)); + assertTrue(x.substring(0, 0).equals(vf.string(""))); + } finally { + StringValue.resetMaxFlatString(); + StringValue.resetMaxUnbalance(); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testConcat(IValueFactory vf) { + assertTrue(example1(vf) + .equals(example1(vf))); + assertTrue(example1(vf) + .equals(vf.string("ab").concat(vf.string("cd")).concat(vf.string("ef").concat(vf.string("gh"))))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringCharAt(IValueFactory vf) { + assertTrue(example2(vf).charAt(0) == '1'); + assertTrue(example2(vf).charAt(1) == '2'); + assertTrue(example2(vf).charAt(2) == '3'); + assertTrue(example2(vf).charAt(3) == 'a'); + assertTrue(example2(vf).charAt(4) == 'b'); + assertTrue(example2(vf).charAt(5) == 'c'); + assertTrue(example2(vf).charAt(6) == 'd'); + assertTrue(example2(vf).charAt(7) == 'e'); + assertTrue(example2(vf).charAt(8) == 'f'); + assertTrue(example2(vf).charAt(9) == '\n'); + assertTrue(example2(vf).charAt(10) == '1'); + assertTrue(example2(vf).charAt(11) == '2'); + assertTrue(example2(vf).charAt(12) == '3'); + assertTrue(example2(vf).charAt(13) == 'x'); + assertTrue(example2(vf).charAt(14) == 'y'); + assertTrue(example2(vf).charAt(15) == 'z'); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringSubString(IValueFactory vf) { + assertEqual(example2(vf).substring(0, 1), vf.string("1")); + assertEqual(example2(vf).substring(0, 2), vf.string("12")); + assertEqual(example2(vf).substring(0, 3), vf.string("123")); + assertEqual(example2(vf).substring(0, 4), vf.string("123a")); + assertEqual(example2(vf).substring(0, 5), vf.string("123ab")); + assertEqual(example2(vf).substring(0, 6), vf.string("123abc")); + assertEqual(example2(vf).substring(0, 7), vf.string("123abcd")); + assertEqual(example2(vf).substring(0, 8), vf.string("123abcde")); + assertEqual(example2(vf).substring(0, 9), vf.string("123abcdef")); + assertEqual(example2(vf).substring(0, 10), vf.string("123abcdef\n")); + assertEqual(example2(vf).substring(0, 11), vf.string("123abcdef\n1")); + assertEqual(example2(vf).substring(0, 12), vf.string("123abcdef\n12")); + assertEqual(example2(vf).substring(0, 13), vf.string("123abcdef\n123")); + assertEqual(example2(vf).substring(0, 14), vf.string("123abcdef\n123x")); + assertEqual(example2(vf).substring(0, 15), vf.string("123abcdef\n123xy")); + assertEqual(example2(vf).substring(0, 16), vf.string("123abcdef\n123xyz")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testStringReplace(IValueFactory vf) { + int n = 10; + StringValue.setMaxFlatString(1); + StringValue.setMaxUnbalance(0); + String[] s = { "a", "b", "c", "d", "e", "f", "g", "h" }; + IString str = vf.string(s[0]); + for (int i = 1; i < n; i++) { + str = str.concat(vf.string(s[i % 8])); + // result = vf.string(s[i%8]).concat(result); + } + // System.out.println(example.replace(4, 1, 4, vf.string("x")).getValue()); + assertEqual(example1(vf).replace(0, 1, 0, vf.string("x")), vf.string("xabcdefgh")); + assertEqual(example1(vf).replace(1, 1, 1, vf.string("x")), vf.string("axbcdefgh")); + assertEqual(example1(vf).replace(2, 1, 2, vf.string("x")), vf.string("abxcdefgh")); + assertEqual(example1(vf).replace(3, 1, 3, vf.string("x")), vf.string("abcxdefgh")); + assertEqual(example1(vf).replace(4, 1, 4, vf.string("x")), vf.string("abcdxefgh")); + assertEqual(example1(vf).replace(5, 1, 5, vf.string("x")), vf.string("abcdexfgh")); + assertEqual(example1(vf).replace(6, 1, 6, vf.string("x")), vf.string("abcdefxgh")); + assertEqual(str.replace(6, 1, 6, vf.string("x").concat(vf.string("y"))), + vf.string("abcdefxygh").concat(str.substring(8))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void neverRunOutOfStack(IValueFactory vf) { + int outofStack = 100000; + + // first we have to know for sure that we would run out of stack with @see + // outOfStack iterations: + try { + StringValue.setMaxFlatString(1); + StringValue.setMaxUnbalance(Integer.MAX_VALUE); + + IString v = vf.string("x"); + for (int i = 0; i < outofStack; i++) { + v = v.concat(vf.string("-" + i)); + } + + try { + v.write(new StringWriter()); + fail("this should run out of stack"); + } catch (StackOverflowError e) { + // yes, that is what is expected + } catch (IOException e) { // TODO Auto-generated catch block - fail("unexpected IO:" + e); + fail("unexpected IO:" + e); + } + } finally { + StringValue.resetMaxFlatString(); + StringValue.resetMaxUnbalance(); + } + + // then, with the maxFlatString and Unbalance parameters reset, we should _not_ + // run out of stack anymore: + IString v = vf.string("x"); + for (int i = 0; i < outofStack; i++) { + v = v.concat(vf.string("-" + i)); + } + + try { + new StringWriter().write(v.toString()); // do not remove this, this is the test + assertTrue(true); + } catch (StackOverflowError e) { + fail("the tree balancer should have avoided a stack overflow"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIndent(IValueFactory vf) { + assertEqual(vf.string("\naap").indent(vf.string("123"), true), vf.string("123\n123aap")); + } + + IString simulateOld(IValueFactory vf, String string, String indent) { + StringBuffer buf = new StringBuffer(); + String[] strings = string.split("\n"); + for (int i = 0; i < strings.length; i++) { + buf.append(indent); + buf.append(strings[i]); + + if (i != strings.length - 1 || string.charAt(string.length() - 1) == '\n') { + buf.append('\n'); } - } finally { - StringValue.resetMaxFlatString(); - StringValue.resetMaxUnbalance(); - } - - // then, with the maxFlatString and Unbalance parameters reset, we should _not_ - // run out of stack anymore: - IString v = vf.string("x"); - for (int i = 0; i < outofStack; i++) { - v = v.concat(vf.string("-" + i)); - } - - try { - new StringWriter().write(v.toString()); // do not remove this, this is the test - assertTrue(true); - } catch (StackOverflowError e) { - fail("the tree balancer should have avoided a stack overflow"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIndent(IValueFactory vf) { - assertEqual(vf.string("\naap").indent(vf.string("123"), true), vf.string("123\n123aap")); - } - - IString simulateOld(IValueFactory vf, String string, String indent) { - StringBuffer buf = new StringBuffer(); - String[] strings = string.split("\n"); - for (int i = 0; i < strings.length; i++) { - buf.append(indent); - buf.append(strings[i]); - - if (i != strings.length - 1 || string.charAt(string.length() - 1) == '\n') { - buf.append('\n'); - } - } - return vf.string(buf.toString()); - } + } + return vf.string(buf.toString()); + } } diff --git a/src/test/java/io/usethesource/vallang/basic/ListRelationSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/ListRelationSmokeTest.java index 78914fdbc..42d8b47af 100644 --- a/src/test/java/io/usethesource/vallang/basic/ListRelationSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/ListRelationSmokeTest.java @@ -1,518 +1,516 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Iterator; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IList; -import io.usethesource.vallang.IListWriter; -import io.usethesource.vallang.ITuple; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; - -public class ListRelationSmokeTest { - - private IValue[] integers(IValueFactory vf) { - IValue[] integers = new IValue[5]; - - for (int i = 0; i < integers.length; i++) { - integers[i] = vf.integer(i); - } - - return integers; - } - - private IValue[] doubles(IValueFactory vf) { - IValue[] doubles = new IValue[10]; - - for (int i = 0; i < doubles.length; i++) { - doubles[i] = vf.real(i); - } - - return doubles; - } - - - private ITuple[] integerTuples(IValueFactory vf) { - IValue[] integers = integers(vf); - ITuple[] integerTuples = new ITuple[integers.length * integers.length]; - - for (int i = 0; i < integers.length; i++) { - for (int j = 0; j < integers.length; j++) { - ITuple t = vf.tuple(integers[i], integers[j]); - integerTuples[i * integers.length + j] = t; - } - } - - return integerTuples; - } - - private ITuple[] doubleTuples(IValueFactory vf) { - IValue[] integers = doubles(vf); - ITuple[] integerTuples = new ITuple[integers.length * integers.length]; - - for (int i = 0; i < integers.length; i++) { - for (int j = 0; j < integers.length; j++) { - ITuple t = vf.tuple(integers[i], integers[j]); - integerTuples[i * integers.length + j] = t; - } - } - - return integerTuples; - } - - private IList listOfIntegers(IValueFactory vf) { - IListWriter lw = vf.listWriter(); - - for (IValue i : integers(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private IList listOfDoubles(IValueFactory vf) { - IListWriter lw = vf.listWriter(); - - for (IValue i : doubles(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private IList integerListRelation(IValueFactory vf) { - IListWriter lw = vf.listWriter(); - - for (IValue i : integerTuples(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private IList doubleListRelation(IValueFactory vf) { - IListWriter lw = vf.listWriter(); - - for (IValue i : doubleTuples(vf)) { - lw.append(i); - } - - return lw.done(); - } - - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIsEmpty(IValueFactory vf) { - if (integerListRelation(vf).isEmpty()) { - fail("integerRelation is not empty"); - } - - if (!vf.list().isEmpty()) { - fail("this relation should be empty"); - } - - IList emptyRel = vf.list(); - if (!emptyRel.isEmpty()) { - fail("empty relation is not empty?"); - } - if (!emptyRel.getType().isListRelation()) { - fail("empty relation should have relation type"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSize(IValueFactory vf) { - if (integerListRelation(vf).length() != integerTuples(vf).length) { - fail("relation size is not correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testArity(IValueFactory vf) { - if (integerListRelation(vf).asRelation().arity() != 2) { - fail("arity should be 2"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductIRelation(IValueFactory vf) { - IList prod = integerListRelation(vf).product(integerListRelation(vf)); - - if (prod.asRelation().arity() != 2) { - fail("arity of product should be 2"); - } - - if (prod.length() != integerListRelation(vf).length() * integerListRelation(vf).length()) { - fail("size of product should be square of size of integerRelation"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductIList(IValueFactory vf) { - IList prod = integerListRelation(vf).product(listOfIntegers(vf)); - - if (prod.asRelation().arity() != 2) { - fail("arity of product should be 2"); - } - - if (prod.length() != integerListRelation(vf).length() * listOfIntegers(vf).length()) { - fail("size of product should be square of size of integerRelation"); - } - } - -// @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void xtestClosure(IValueFactory vf) { - try { - if (!integerListRelation(vf).asRelation().closure().equals(integerListRelation(vf))) { - fail("closure adds extra tuples?"); - } - } catch (FactTypeUseException e) { - fail("integerRelation is reflexive, so why an error?"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); - IList rel = vf.list(t1); - - rel.asRelation().closure(); - } catch (FactTypeUseException e) { - fail("reflexivity with subtyping is allowed"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); - ITuple t2 = vf.tuple(integers(vf)[1], integers(vf)[2]); - ITuple t3 = vf.tuple(integers(vf)[2], integers(vf)[3]); - ITuple t4 = vf.tuple(integers(vf)[0], integers(vf)[2]); - ITuple t5 = vf.tuple(integers(vf)[1], integers(vf)[3]); - ITuple t6 = vf.tuple(integers(vf)[0], integers(vf)[3]); - - IList test = vf.list(t1, t2, t3); - IList closed = test.asRelation().closure(); - - if (closed.asRelation().arity() != test.asRelation().arity()) { - fail("closure should produce relations of same arity"); - } - - if (closed.length() != 6) { - fail("closure contains too few elements"); - } - - if (!closed.intersect(test).equals(test)) { - fail("closure should contain all original elements"); - } - - if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) { - fail("closure does not contain required elements"); - } - - } catch (FactTypeUseException e) { - fail("this should all be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testCompose(IValueFactory vf) { - try { - IList comp = integerListRelation(vf).asRelation().compose(integerListRelation(vf).asRelation()); - - if (comp.asRelation().arity() != integerListRelation(vf).asRelation().arity() * 2 - 2) { - fail( - "composition is a product with the last column of the first relation and the first column of the last relation removed"); - } - - if (comp.length() != integerListRelation(vf).length() * integers(vf).length) { - fail("number of expected tuples is off"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); - ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); - ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); - IList rel1 = vf.list(t1, t2, t3); - - ITuple t4 = vf.tuple(doubles(vf)[0], integers(vf)[0]); - ITuple t5 = vf.tuple(doubles(vf)[1], integers(vf)[1]); - ITuple t6 = vf.tuple(doubles(vf)[2], integers(vf)[2]); - IList rel2 = vf.list(t4, t5, t6); - - ITuple t7 = vf.tuple(integers(vf)[0], integers(vf)[0]); - ITuple t8 = vf.tuple(integers(vf)[1], integers(vf)[1]); - ITuple t9 = vf.tuple(integers(vf)[2], integers(vf)[2]); - IList rel3 = vf.list(t7, t8, t9); - - IList comp = rel1.asRelation().compose(rel2.asRelation()); - - if (!comp.equals(rel3)) { - fail("composition does not produce expected result"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testContains(IValueFactory vf) { - try { - for (ITuple t : integerTuples(vf)) { - if (!integerListRelation(vf).contains(t)) { - fail("contains returns false instead of true"); - } - } - } catch (FactTypeUseException e) { - fail("this should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInsert(IValueFactory vf) { - try { - // IList rel = integerListRelation(vf).insert(vf.tuple(vf.integer(0),vf.integer(0))); - // - // if (!rel.equals(integerListRelation)) { - // fail("insert into a relation of an existing tuple should not change the relation"); - // } - - IListWriter relw3 = vf.listWriter(); - relw3.insertAll(integerListRelation(vf)); - IList rel3 = relw3.done(); - - final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100)); - IList rel4 = rel3.insert(tuple); - - if (rel4.length() != integerListRelation(vf).length() + 1) { - fail("insert failed"); - } - - if (!rel4.contains(tuple)) { - fail("insert failed"); - } - - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntersectIRelation(IValueFactory vf) { - IList empty1 = vf.list(); - IList empty2 = vf.list(); - - try { - final IList intersection = empty1.intersect(empty2); - if (!intersection.isEmpty()) { - fail("empty intersection failed"); - } - - Type type = intersection.getType(); - if (!type.getFieldType(0).isBottom()) { - fail("intersection should produce lub types"); - } - } catch (FactTypeUseException e) { - fail("intersecting types which have a lub should be possible"); - } - - try { - if (!integerListRelation(vf).intersect(doubleListRelation(vf)).isEmpty()) { - fail("non-intersecting relations should produce empty intersections"); - } - - IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - IList threeFourFive = vf.list(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - IList result = vf.list(integerTuples(vf)[2]); - - if (!oneTwoThree.intersect(threeFourFive).equals(result)) { - fail("intersection failed"); - } - if (!threeFourFive.intersect(oneTwoThree).equals(result)) { - fail("intersection should be commutative"); - } - - if (!oneTwoThree.intersect(vf.list()) - .isEmpty()) { - fail("intersection with empty set should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntersectIList(IValueFactory vf) { - IList empty1 = vf.list(); - IList empty2 = vf.list(); - - try { - final IList intersection = empty1.intersect(empty2); - if (!intersection.isEmpty()) { - fail("empty intersection failed"); - } - - Type type = intersection.getType(); - if (!type.getFieldType(0).isBottom()) { - fail("empty intersection should produce void type"); - } - } catch (FactTypeUseException e) { - fail("intersecting types which have a lub should be possible"); - } - - try { - if (!integerListRelation(vf).intersect(doubleListRelation(vf)).isEmpty()) { - fail("non-intersecting relations should produce empty intersections"); - } - - IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - IList threeFourFive = vf.list(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - IList result = vf.list(integerTuples(vf)[2]); - - if (!oneTwoThree.intersect(threeFourFive).equals(result)) { - fail("intersection failed"); - } - if (!threeFourFive.intersect(oneTwoThree).equals(result)) { - fail("intersection should be commutative"); - } - - if (!oneTwoThree.intersect(vf.list()) - .isEmpty()) { - fail("intersection with empty list should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testConcatIListRelation(IValueFactory vf) { - IList empty1 = vf.list(); - IList empty2 = vf.list(); - - try { - final IList concat = (IList) empty1.concat(empty2); - if (!concat.isEmpty()) { - fail("empty concat failed"); - } - - Type type = concat.getType(); - if (!type.getFieldType(0).isBottom()) { - fail("concat should produce void type"); - } - } catch (FactTypeUseException e) { - fail("concat types which have a lub should be possible"); - } - - try { - if (integerListRelation(vf).concat(doubleListRelation(vf)).length() != integerListRelation(vf).length() - + doubleListRelation(vf).length()) { - fail( - "non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); - } - - IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - IList threeFourFive = vf.list(integerTuples(vf)[3], integerTuples(vf)[4]); - IList result1 = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], - integerTuples(vf)[3], integerTuples(vf)[4]); - IList result2 = vf.list(integerTuples(vf)[3], integerTuples(vf)[4], integerTuples(vf)[0], - integerTuples(vf)[1], integerTuples(vf)[2]); - - if (!oneTwoThree.concat(threeFourFive).equals(result1)) { - fail("concat 1 failed"); - } - if (!threeFourFive.concat(oneTwoThree).equals(result2)) { - fail("concat 2 failed"); - } - - if (!oneTwoThree.concat(vf.list()) - .equals(oneTwoThree)) { - fail("concat with empty set should produce same set"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIterator(IValueFactory vf) { - try { - Iterator it = integerListRelation(vf).iterator(); - - int i; - for (i = 0; it.hasNext(); i++) { - ITuple t = (ITuple) it.next(); - - if (!integerListRelation(vf).contains(t)) { - fail("iterator produces strange elements?"); - } - } - - if (i != integerListRelation(vf).length()) { - fail("iterator skipped elements"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testCarrier(IValueFactory vf, TypeFactory tf) { - IList carrier = integerListRelation(vf).asRelation().carrier(); - - if (!carrier.equals(listOfIntegers(vf))) { - fail("carrier should be equal to this set"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); - ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); - ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); - IList rel1 = vf.list(t1, t2, t3); - - IList carrier1 = rel1.asRelation().carrier(); - - if (carrier1.getElementType() != tf.numberType()) { - fail("expected number type on carrier"); - } - - if (carrier1.length() != 6) { - fail("carrier does not contain all elements"); - } - - if (carrier1.intersect(listOfIntegers(vf)).length() != 3) { - fail("integers should be in there still"); - } - - if (carrier1.intersect(listOfDoubles(vf)).length() != 3) { - fail("doubles should be in there still"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - } -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Iterator; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IList; +import io.usethesource.vallang.IListWriter; +import io.usethesource.vallang.ITuple; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; + +public class ListRelationSmokeTest { + + private IValue[] integers(IValueFactory vf) { + IValue[] integers = new IValue[5]; + + for (int i = 0; i < integers.length; i++) { + integers[i] = vf.integer(i); + } + + return integers; + } + + private IValue[] doubles(IValueFactory vf) { + IValue[] doubles = new IValue[10]; + + for (int i = 0; i < doubles.length; i++) { + doubles[i] = vf.real(i); + } + + return doubles; + } + + + private ITuple[] integerTuples(IValueFactory vf) { + IValue[] integers = integers(vf); + ITuple[] integerTuples = new ITuple[integers.length * integers.length]; + + for (int i = 0; i < integers.length; i++) { + for (int j = 0; j < integers.length; j++) { + ITuple t = vf.tuple(integers[i], integers[j]); + integerTuples[i * integers.length + j] = t; + } + } + + return integerTuples; + } + + private ITuple[] doubleTuples(IValueFactory vf) { + IValue[] integers = doubles(vf); + ITuple[] integerTuples = new ITuple[integers.length * integers.length]; + + for (int i = 0; i < integers.length; i++) { + for (int j = 0; j < integers.length; j++) { + ITuple t = vf.tuple(integers[i], integers[j]); + integerTuples[i * integers.length + j] = t; + } + } + + return integerTuples; + } + + private IList listOfIntegers(IValueFactory vf) { + IListWriter lw = vf.listWriter(); + + for (IValue i : integers(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private IList listOfDoubles(IValueFactory vf) { + IListWriter lw = vf.listWriter(); + + for (IValue i : doubles(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private IList integerListRelation(IValueFactory vf) { + IListWriter lw = vf.listWriter(); + + for (IValue i : integerTuples(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private IList doubleListRelation(IValueFactory vf) { + IListWriter lw = vf.listWriter(); + + for (IValue i : doubleTuples(vf)) { + lw.append(i); + } + + return lw.done(); + } + + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIsEmpty(IValueFactory vf) { + if (integerListRelation(vf).isEmpty()) { + fail("integerRelation is not empty"); + } + + if (!vf.list().isEmpty()) { + fail("this relation should be empty"); + } + + IList emptyRel = vf.list(); + if (!emptyRel.isEmpty()) { + fail("empty relation is not empty?"); + } + if (!emptyRel.getType().isListRelation()) { + fail("empty relation should have relation type"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSize(IValueFactory vf) { + if (integerListRelation(vf).length() != integerTuples(vf).length) { + fail("relation size is not correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testArity(IValueFactory vf) { + if (integerListRelation(vf).asRelation().arity() != 2) { + fail("arity should be 2"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductIRelation(IValueFactory vf) { + IList prod = integerListRelation(vf).product(integerListRelation(vf)); + + if (prod.asRelation().arity() != 2) { + fail("arity of product should be 2"); + } + + if (prod.length() != integerListRelation(vf).length() * integerListRelation(vf).length()) { + fail("size of product should be square of size of integerRelation"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductIList(IValueFactory vf) { + IList prod = integerListRelation(vf).product(listOfIntegers(vf)); + + if (prod.asRelation().arity() != 2) { + fail("arity of product should be 2"); + } + + if (prod.length() != integerListRelation(vf).length() * listOfIntegers(vf).length()) { + fail("size of product should be square of size of integerRelation"); + } + } + + // @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void xtestClosure(IValueFactory vf) { + try { + if (!integerListRelation(vf).asRelation().closure().equals(integerListRelation(vf))) { + fail("closure adds extra tuples?"); + } + } catch (FactTypeUseException e) { + fail("integerRelation is reflexive, so why an error?"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); + IList rel = vf.list(t1); + + rel.asRelation().closure(); + } catch (FactTypeUseException e) { + fail("reflexivity with subtyping is allowed"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); + ITuple t2 = vf.tuple(integers(vf)[1], integers(vf)[2]); + ITuple t3 = vf.tuple(integers(vf)[2], integers(vf)[3]); + ITuple t4 = vf.tuple(integers(vf)[0], integers(vf)[2]); + ITuple t5 = vf.tuple(integers(vf)[1], integers(vf)[3]); + ITuple t6 = vf.tuple(integers(vf)[0], integers(vf)[3]); + + IList test = vf.list(t1, t2, t3); + IList closed = test.asRelation().closure(); + + if (closed.asRelation().arity() != test.asRelation().arity()) { + fail("closure should produce relations of same arity"); + } + + if (closed.length() != 6) { + fail("closure contains too few elements"); + } + + if (!closed.intersect(test).equals(test)) { + fail("closure should contain all original elements"); + } + + if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) { + fail("closure does not contain required elements"); + } + + } catch (FactTypeUseException e) { + fail("this should all be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testCompose(IValueFactory vf) { + try { + IList comp = integerListRelation(vf).asRelation().compose(integerListRelation(vf).asRelation()); + + if (comp.asRelation().arity() != integerListRelation(vf).asRelation().arity() * 2 - 2) { + fail("composition is a product with the last column of the first relation and the first column of the last relation removed"); + } + + if (comp.length() != integerListRelation(vf).length() * integers(vf).length) { + fail("number of expected tuples is off"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); + ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); + ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); + IList rel1 = vf.list(t1, t2, t3); + + ITuple t4 = vf.tuple(doubles(vf)[0], integers(vf)[0]); + ITuple t5 = vf.tuple(doubles(vf)[1], integers(vf)[1]); + ITuple t6 = vf.tuple(doubles(vf)[2], integers(vf)[2]); + IList rel2 = vf.list(t4, t5, t6); + + ITuple t7 = vf.tuple(integers(vf)[0], integers(vf)[0]); + ITuple t8 = vf.tuple(integers(vf)[1], integers(vf)[1]); + ITuple t9 = vf.tuple(integers(vf)[2], integers(vf)[2]); + IList rel3 = vf.list(t7, t8, t9); + + IList comp = rel1.asRelation().compose(rel2.asRelation()); + + if (!comp.equals(rel3)) { + fail("composition does not produce expected result"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testContains(IValueFactory vf) { + try { + for (ITuple t : integerTuples(vf)) { + if (!integerListRelation(vf).contains(t)) { + fail("contains returns false instead of true"); + } + } + } catch (FactTypeUseException e) { + fail("this should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInsert(IValueFactory vf) { + try { + // IList rel = integerListRelation(vf).insert(vf.tuple(vf.integer(0),vf.integer(0))); + // + // if (!rel.equals(integerListRelation)) { + // fail("insert into a relation of an existing tuple should not change the relation"); + // } + + IListWriter relw3 = vf.listWriter(); + relw3.insertAll(integerListRelation(vf)); + IList rel3 = relw3.done(); + + final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100)); + IList rel4 = rel3.insert(tuple); + + if (rel4.length() != integerListRelation(vf).length() + 1) { + fail("insert failed"); + } + + if (!rel4.contains(tuple)) { + fail("insert failed"); + } + + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntersectIRelation(IValueFactory vf) { + IList empty1 = vf.list(); + IList empty2 = vf.list(); + + try { + final IList intersection = empty1.intersect(empty2); + if (!intersection.isEmpty()) { + fail("empty intersection failed"); + } + + Type type = intersection.getType(); + if (!type.getFieldType(0).isBottom()) { + fail("intersection should produce lub types"); + } + } catch (FactTypeUseException e) { + fail("intersecting types which have a lub should be possible"); + } + + try { + if (!integerListRelation(vf).intersect(doubleListRelation(vf)).isEmpty()) { + fail("non-intersecting relations should produce empty intersections"); + } + + IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + IList threeFourFive = vf.list(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + IList result = vf.list(integerTuples(vf)[2]); + + if (!oneTwoThree.intersect(threeFourFive).equals(result)) { + fail("intersection failed"); + } + if (!threeFourFive.intersect(oneTwoThree).equals(result)) { + fail("intersection should be commutative"); + } + + if (!oneTwoThree.intersect(vf.list()) + .isEmpty()) { + fail("intersection with empty set should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntersectIList(IValueFactory vf) { + IList empty1 = vf.list(); + IList empty2 = vf.list(); + + try { + final IList intersection = empty1.intersect(empty2); + if (!intersection.isEmpty()) { + fail("empty intersection failed"); + } + + Type type = intersection.getType(); + if (!type.getFieldType(0).isBottom()) { + fail("empty intersection should produce void type"); + } + } catch (FactTypeUseException e) { + fail("intersecting types which have a lub should be possible"); + } + + try { + if (!integerListRelation(vf).intersect(doubleListRelation(vf)).isEmpty()) { + fail("non-intersecting relations should produce empty intersections"); + } + + IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + IList threeFourFive = vf.list(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + IList result = vf.list(integerTuples(vf)[2]); + + if (!oneTwoThree.intersect(threeFourFive).equals(result)) { + fail("intersection failed"); + } + if (!threeFourFive.intersect(oneTwoThree).equals(result)) { + fail("intersection should be commutative"); + } + + if (!oneTwoThree.intersect(vf.list()) + .isEmpty()) { + fail("intersection with empty list should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testConcatIListRelation(IValueFactory vf) { + IList empty1 = vf.list(); + IList empty2 = vf.list(); + + try { + final IList concat = (IList) empty1.concat(empty2); + if (!concat.isEmpty()) { + fail("empty concat failed"); + } + + Type type = concat.getType(); + if (!type.getFieldType(0).isBottom()) { + fail("concat should produce void type"); + } + } catch (FactTypeUseException e) { + fail("concat types which have a lub should be possible"); + } + + try { + if (integerListRelation(vf).concat(doubleListRelation(vf)).length() != integerListRelation(vf).length() + + doubleListRelation(vf).length()) { + fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); + } + + IList oneTwoThree = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + IList threeFourFive = vf.list(integerTuples(vf)[3], integerTuples(vf)[4]); + IList result1 = vf.list(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], + integerTuples(vf)[3], integerTuples(vf)[4]); + IList result2 = vf.list(integerTuples(vf)[3], integerTuples(vf)[4], integerTuples(vf)[0], + integerTuples(vf)[1], integerTuples(vf)[2]); + + if (!oneTwoThree.concat(threeFourFive).equals(result1)) { + fail("concat 1 failed"); + } + if (!threeFourFive.concat(oneTwoThree).equals(result2)) { + fail("concat 2 failed"); + } + + if (!oneTwoThree.concat(vf.list()) + .equals(oneTwoThree)) { + fail("concat with empty set should produce same set"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIterator(IValueFactory vf) { + try { + Iterator it = integerListRelation(vf).iterator(); + + int i; + for (i = 0; it.hasNext(); i++) { + ITuple t = (ITuple) it.next(); + + if (!integerListRelation(vf).contains(t)) { + fail("iterator produces strange elements?"); + } + } + + if (i != integerListRelation(vf).length()) { + fail("iterator skipped elements"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testCarrier(IValueFactory vf, TypeFactory tf) { + IList carrier = integerListRelation(vf).asRelation().carrier(); + + if (!carrier.equals(listOfIntegers(vf))) { + fail("carrier should be equal to this set"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); + ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); + ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); + IList rel1 = vf.list(t1, t2, t3); + + IList carrier1 = rel1.asRelation().carrier(); + + if (carrier1.getElementType() != tf.numberType()) { + fail("expected number type on carrier"); + } + + if (carrier1.length() != 6) { + fail("carrier does not contain all elements"); + } + + if (carrier1.intersect(listOfIntegers(vf)).length() != 3) { + fail("integers should be in there still"); + } + + if (carrier1.intersect(listOfDoubles(vf)).length() != 3) { + fail("doubles should be in there still"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/ListSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/ListSmokeTest.java index 716f76ad6..0bdb86903 100644 --- a/src/test/java/io/usethesource/vallang/basic/ListSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/ListSmokeTest.java @@ -1,350 +1,350 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation. - * 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: - * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - - *******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Random; -import java.util.Set; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IList; -import io.usethesource.vallang.IListWriter; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.TypeFactory; - -public final class ListSmokeTest { - - private IValue[] integers(IValueFactory vf) { - IValue[] integers = new IValue[20]; - - for (int i = 0; i < integers.length; i++) { - integers[i] = vf.integer(i); - } - - return integers; - } - - private IList integersList(IValueFactory vf) { - IListWriter lw = vf.listWriter(); - - for (IValue i : integers(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private IList emptyIntegerList(IValueFactory vf) { - return vf.list(); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testGetElementType(IValueFactory vf, TypeFactory tf) { - if (!integersList(vf).getElementType().isSubtypeOf(tf.integerType())) { - fail("funny getElementType"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testAppend(IValueFactory vf, TypeFactory tf) { - try { - IValue newValue = vf.integer(integers(vf).length); - IList longer = integersList(vf).append(newValue); - - if (longer.length() != integersList(vf).length() + 1) { - fail("append failed"); - } - - if (!longer.get(integersList(vf).length()).equals(newValue)) { - fail("element was not appended"); - } - - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - try { - if (!integersList(vf).append(vf.real(2)).getElementType().equivalent(tf.numberType())) { - fail("append should lub the element type"); - } - } catch (FactTypeUseException e) { - // this should happen - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testGet(IValueFactory vf) { - for (int i = 0; i < integers(vf).length; i++) { - if (!integersList(vf).get(i).equals(integers(vf)[i])) { - fail("get failed"); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInsert(IValueFactory vf, TypeFactory tf) { - try { - IValue newValue = vf.integer(integers(vf).length); - IList longer = integersList(vf).insert(newValue); - - if (longer.length() != integersList(vf).length() + 1) { - fail("append failed"); - } - - if (!longer.get(0).equals(newValue)) { - fail("element was not insrrted"); - } - - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - try { - if (!integersList(vf).insert(vf.real(2)).getElementType().equivalent(tf.numberType())) { - fail("insert should lub the element type"); - } - } catch (FactTypeUseException e) { - // this should happen - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testLength(IValueFactory vf) { - if (vf.list().length() != 0) { - fail("empty list should be size 0"); - } - - if (integersList(vf).length() != integers(vf).length) { - fail("length does not count amount of elements"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testReverse(IValueFactory vf) { - IList reverse = integersList(vf).reverse(); - - if (reverse.getType() != integersList(vf).getType()) { - fail("reverse should keep type"); - } - - if (reverse.length() != integersList(vf).length()) { - fail("length of reverse is different"); - } - - for (int i = 0; i < integers(vf).length; i++) { - if (!reverse.get(i).equals(integers(vf)[integers(vf).length - i - 1])) { - fail("reverse did something funny: " + reverse + " is not reverse of " + integersList(vf)); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testShuffle(IValueFactory vf) { - IList shuffle = integersList(vf).shuffle(new Random()); - - if (shuffle.getType() != integersList(vf).getType()) { - fail("shuffle should keep type"); - } - - if (shuffle.length() != integersList(vf).length()) { - fail("length after shuffle is different"); - } - } - - // doesn't completly test distribution, but at least protects against some cases - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testShuffleFirstLast(IValueFactory vf) { - Set first = new HashSet<>(); - Set last = new HashSet<>(); - Random r = new Random(); - for (int i = 0; i < 20 * integersList(vf).length(); i++) { - IList shuffled = integersList(vf).shuffle(r); - first.add(shuffled.get(0)); - last.add(shuffled.get(shuffled.length() - 1)); - } - for (IValue v : integersList(vf)) { - if (!first.contains(v)) { - fail("The shuffle doesn't shuffle the first index correctly"); - } - if (!last.contains(v)) { - fail("The shuffle doesn't shuffle the last index correctly"); - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testReverseEmpty(IValueFactory vf) { - IList reverse = emptyIntegerList(vf).reverse(); - - if (reverse.getType() != emptyIntegerList(vf).getType()) { - fail("reverse should keep type"); - } - - if (reverse.length() != emptyIntegerList(vf).length()) { - fail("length of reverse is different"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIterator(IValueFactory vf) { - Iterator it = integersList(vf).iterator(); - - int i; - for (i = 0; it.hasNext(); i++) { - IValue v = it.next(); - if (!v.equals(integers(vf)[i])) { - fail("iterator does not iterate in order"); - } - } - } - - // NOTE: This is not a very good test, but sufficient for it's purpose. - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSubList(IValueFactory vf) { - // Front - IListWriter flw = vf.listWriter(); - for (int i = 0; i < 20; i++) { - flw.append(vf.integer(i)); - } - IList fList = flw.done(); - - // Back - IListWriter blw = vf.listWriter(); - for (int i = 19; i >= 0; i--) { - blw.insert(vf.integer(i)); - } - IList bList = blw.done(); - - // Overlap - IListWriter olw = vf.listWriter(); - for (int i = 9; i >= 0; i--) { - olw.insert(vf.integer(i)); - } - for (int i = 10; i < 20; i++) { - olw.append(vf.integer(i)); - } - IList oList = olw.done(); - - IList fSubList = fList.sublist(0, 5); - IList bSubList = bList.sublist(0, 5); - IList oSubList = oList.sublist(0, 5); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(1, 5); - bSubList = bList.sublist(1, 5); - oSubList = oList.sublist(1, 5); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(0, 15); - bSubList = bList.sublist(0, 15); - oSubList = oList.sublist(0, 15); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(1, 15); - bSubList = bList.sublist(1, 15); - oSubList = oList.sublist(1, 15); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(5, 5); - bSubList = bList.sublist(5, 5); - oSubList = oList.sublist(5, 5); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(5, 10); - bSubList = bList.sublist(5, 10); - oSubList = oList.sublist(5, 10); - checkSubListEquality(fSubList, bSubList, oSubList); - - fSubList = fList.sublist(15, 5); - bSubList = bList.sublist(15, 5); - oSubList = oList.sublist(15, 5); - checkSubListEquality(fSubList, bSubList, oSubList); - } - - private static void checkSubListEquality(IList fList, IList bList, IList oList) { - if (!fList.equals(bList) || !bList.equals(oList)) - fail("IList#subList is broken: " + fList + " " + bList + " " + oList); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIsSubListOf(IValueFactory vf) { - IListWriter w = vf.listWriter(); - - for (int i = integers(vf).length - 1; i >= 0; i -= 2) { - w.insert(vf.integer(i)); - } - - IList even = w.done(); - - w = vf.listWriter(); - - for (int i = integers(vf).length - 2; i >= 0; i -= 2) { - w.insert(vf.integer(i)); - } - - IList odd = w.done(); - if (!integersList(vf).isSubListOf(integersList(vf))) - fail("integerList should be sublist of integerList"); - if (!even.isSubListOf(integersList(vf))) - fail("even should be sublist of integerList"); - if (!odd.isSubListOf(integersList(vf))) - fail("odd should be sublist of integerList"); - - if (integersList(vf).isSubListOf(even)) - fail("integerList cannot be sublist of even"); - if (integersList(vf).isSubListOf(odd)) - fail("integerList cannot be sublist of odd"); - if (even.isSubListOf(odd)) - fail("even cannot be sublist of odd"); - if (odd.isSubListOf(even)) - fail("odd cannot be sublist of even"); - - IList L123 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3]); - IList L918273 = - vf.list(integers(vf)[9], integers(vf)[1], integers(vf)[8], integers(vf)[2], integers(vf)[7], integers(vf)[3]); - IList L918372 = - vf.list(integers(vf)[9], integers(vf)[1], integers(vf)[8], integers(vf)[3], integers(vf)[7], integers(vf)[2]); - - if (!L123.isSubListOf(L918273)) - fail("123 is sublist of 918273"); - if (L123.isSubListOf(L918372)) - fail("123 is not a sublist of 918372"); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSubtract(IValueFactory vf) { - IList L12312 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3], integers(vf)[1], integers(vf)[2]); - IList L123 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3]); - IList L12 = vf.list(integers(vf)[1], integers(vf)[2]); - IList L321321 = - vf.list(integers(vf)[3], integers(vf)[2], integers(vf)[1], integers(vf)[3], integers(vf)[2], integers(vf)[1]); - - if (!checkListEquality(L12312.subtract(L123), L12)) - fail("12312 subtract 123 should be 12"); - if (!L12312.subtract(L321321).isEmpty()) - fail("12312 subtract 123213213 should be empty"); - } - - private boolean checkListEquality(IList lst1, IList lst2) { - return lst1.isSubListOf(lst2) && lst2.isSubListOf(lst2); - - } -} +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation. + * 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: + * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + + *******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Random; +import java.util.Set; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IList; +import io.usethesource.vallang.IListWriter; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.TypeFactory; + +public final class ListSmokeTest { + + private IValue[] integers(IValueFactory vf) { + IValue[] integers = new IValue[20]; + + for (int i = 0; i < integers.length; i++) { + integers[i] = vf.integer(i); + } + + return integers; + } + + private IList integersList(IValueFactory vf) { + IListWriter lw = vf.listWriter(); + + for (IValue i : integers(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private IList emptyIntegerList(IValueFactory vf) { + return vf.list(); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testGetElementType(IValueFactory vf, TypeFactory tf) { + if (!integersList(vf).getElementType().isSubtypeOf(tf.integerType())) { + fail("funny getElementType"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testAppend(IValueFactory vf, TypeFactory tf) { + try { + IValue newValue = vf.integer(integers(vf).length); + IList longer = integersList(vf).append(newValue); + + if (longer.length() != integersList(vf).length() + 1) { + fail("append failed"); + } + + if (!longer.get(integersList(vf).length()).equals(newValue)) { + fail("element was not appended"); + } + + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + try { + if (!integersList(vf).append(vf.real(2)).getElementType().equivalent(tf.numberType())) { + fail("append should lub the element type"); + } + } catch (FactTypeUseException e) { + // this should happen + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testGet(IValueFactory vf) { + for (int i = 0; i < integers(vf).length; i++) { + if (!integersList(vf).get(i).equals(integers(vf)[i])) { + fail("get failed"); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInsert(IValueFactory vf, TypeFactory tf) { + try { + IValue newValue = vf.integer(integers(vf).length); + IList longer = integersList(vf).insert(newValue); + + if (longer.length() != integersList(vf).length() + 1) { + fail("append failed"); + } + + if (!longer.get(0).equals(newValue)) { + fail("element was not insrrted"); + } + + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + try { + if (!integersList(vf).insert(vf.real(2)).getElementType().equivalent(tf.numberType())) { + fail("insert should lub the element type"); + } + } catch (FactTypeUseException e) { + // this should happen + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testLength(IValueFactory vf) { + if (vf.list().length() != 0) { + fail("empty list should be size 0"); + } + + if (integersList(vf).length() != integers(vf).length) { + fail("length does not count amount of elements"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testReverse(IValueFactory vf) { + IList reverse = integersList(vf).reverse(); + + if (reverse.getType() != integersList(vf).getType()) { + fail("reverse should keep type"); + } + + if (reverse.length() != integersList(vf).length()) { + fail("length of reverse is different"); + } + + for (int i = 0; i < integers(vf).length; i++) { + if (!reverse.get(i).equals(integers(vf)[integers(vf).length - i - 1])) { + fail("reverse did something funny: " + reverse + " is not reverse of " + integersList(vf)); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testShuffle(IValueFactory vf) { + IList shuffle = integersList(vf).shuffle(new Random()); + + if (shuffle.getType() != integersList(vf).getType()) { + fail("shuffle should keep type"); + } + + if (shuffle.length() != integersList(vf).length()) { + fail("length after shuffle is different"); + } + } + + // doesn't completly test distribution, but at least protects against some cases + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testShuffleFirstLast(IValueFactory vf) { + Set first = new HashSet<>(); + Set last = new HashSet<>(); + Random r = new Random(); + for (int i = 0; i < 20 * integersList(vf).length(); i++) { + IList shuffled = integersList(vf).shuffle(r); + first.add(shuffled.get(0)); + last.add(shuffled.get(shuffled.length() - 1)); + } + for (IValue v : integersList(vf)) { + if (!first.contains(v)) { + fail("The shuffle doesn't shuffle the first index correctly"); + } + if (!last.contains(v)) { + fail("The shuffle doesn't shuffle the last index correctly"); + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testReverseEmpty(IValueFactory vf) { + IList reverse = emptyIntegerList(vf).reverse(); + + if (reverse.getType() != emptyIntegerList(vf).getType()) { + fail("reverse should keep type"); + } + + if (reverse.length() != emptyIntegerList(vf).length()) { + fail("length of reverse is different"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIterator(IValueFactory vf) { + Iterator it = integersList(vf).iterator(); + + int i; + for (i = 0; it.hasNext(); i++) { + IValue v = it.next(); + if (!v.equals(integers(vf)[i])) { + fail("iterator does not iterate in order"); + } + } + } + + // NOTE: This is not a very good test, but sufficient for it's purpose. + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSubList(IValueFactory vf) { + // Front + IListWriter flw = vf.listWriter(); + for (int i = 0; i < 20; i++) { + flw.append(vf.integer(i)); + } + IList fList = flw.done(); + + // Back + IListWriter blw = vf.listWriter(); + for (int i = 19; i >= 0; i--) { + blw.insert(vf.integer(i)); + } + IList bList = blw.done(); + + // Overlap + IListWriter olw = vf.listWriter(); + for (int i = 9; i >= 0; i--) { + olw.insert(vf.integer(i)); + } + for (int i = 10; i < 20; i++) { + olw.append(vf.integer(i)); + } + IList oList = olw.done(); + + IList fSubList = fList.sublist(0, 5); + IList bSubList = bList.sublist(0, 5); + IList oSubList = oList.sublist(0, 5); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(1, 5); + bSubList = bList.sublist(1, 5); + oSubList = oList.sublist(1, 5); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(0, 15); + bSubList = bList.sublist(0, 15); + oSubList = oList.sublist(0, 15); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(1, 15); + bSubList = bList.sublist(1, 15); + oSubList = oList.sublist(1, 15); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(5, 5); + bSubList = bList.sublist(5, 5); + oSubList = oList.sublist(5, 5); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(5, 10); + bSubList = bList.sublist(5, 10); + oSubList = oList.sublist(5, 10); + checkSubListEquality(fSubList, bSubList, oSubList); + + fSubList = fList.sublist(15, 5); + bSubList = bList.sublist(15, 5); + oSubList = oList.sublist(15, 5); + checkSubListEquality(fSubList, bSubList, oSubList); + } + + private static void checkSubListEquality(IList fList, IList bList, IList oList) { + if (!fList.equals(bList) || !bList.equals(oList)) + fail("IList#subList is broken: " + fList + " " + bList + " " + oList); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIsSubListOf(IValueFactory vf) { + IListWriter w = vf.listWriter(); + + for (int i = integers(vf).length - 1; i >= 0; i -= 2) { + w.insert(vf.integer(i)); + } + + IList even = w.done(); + + w = vf.listWriter(); + + for (int i = integers(vf).length - 2; i >= 0; i -= 2) { + w.insert(vf.integer(i)); + } + + IList odd = w.done(); + if (!integersList(vf).isSubListOf(integersList(vf))) + fail("integerList should be sublist of integerList"); + if (!even.isSubListOf(integersList(vf))) + fail("even should be sublist of integerList"); + if (!odd.isSubListOf(integersList(vf))) + fail("odd should be sublist of integerList"); + + if (integersList(vf).isSubListOf(even)) + fail("integerList cannot be sublist of even"); + if (integersList(vf).isSubListOf(odd)) + fail("integerList cannot be sublist of odd"); + if (even.isSubListOf(odd)) + fail("even cannot be sublist of odd"); + if (odd.isSubListOf(even)) + fail("odd cannot be sublist of even"); + + IList L123 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3]); + IList L918273 = + vf.list(integers(vf)[9], integers(vf)[1], integers(vf)[8], integers(vf)[2], integers(vf)[7], integers(vf)[3]); + IList L918372 = + vf.list(integers(vf)[9], integers(vf)[1], integers(vf)[8], integers(vf)[3], integers(vf)[7], integers(vf)[2]); + + if (!L123.isSubListOf(L918273)) + fail("123 is sublist of 918273"); + if (L123.isSubListOf(L918372)) + fail("123 is not a sublist of 918372"); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSubtract(IValueFactory vf) { + IList L12312 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3], integers(vf)[1], integers(vf)[2]); + IList L123 = vf.list(integers(vf)[1], integers(vf)[2], integers(vf)[3]); + IList L12 = vf.list(integers(vf)[1], integers(vf)[2]); + IList L321321 = + vf.list(integers(vf)[3], integers(vf)[2], integers(vf)[1], integers(vf)[3], integers(vf)[2], integers(vf)[1]); + + if (!checkListEquality(L12312.subtract(L123), L12)) + fail("12312 subtract 123 should be 12"); + if (!L12312.subtract(L321321).isEmpty()) + fail("12312 subtract 123213213 should be empty"); + } + + private boolean checkListEquality(IList lst1, IList lst2) { + return lst1.isSubListOf(lst2) && lst2.isSubListOf(lst2); + + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/MapSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/MapSmokeTest.java index f79cf0ba9..fa44f1da0 100644 --- a/src/test/java/io/usethesource/vallang/basic/MapSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/MapSmokeTest.java @@ -52,7 +52,7 @@ enum Kind { private IMap[] testMaps(IValueFactory vf) { IMap empty = vf.mapWriter().done(); - IMap[] testMaps = new IMap[] {empty, + IMap[] testMaps = new IMap[] {empty, empty.put(vf.string("Bergen"), vf.string("Amsterdam")), empty.put(vf.string("Bergen"), vf.string("Amsterdam")) .put(vf.string("Mango"), vf.string("Yummy")), @@ -72,7 +72,7 @@ private IMap[] testMaps(IValueFactory vf) { private StringPair[] keyValues(IValueFactory vf) { String[] strings = new String[] {"Bergen", "Amsterdam", "Frankfurt", "Helsinki", "Moscow", - "Rainy", "Cold", "Mango", "Banana", "Sweet", "Yummy"}; + "Rainy", "Cold", "Mango", "Banana", "Sweet", "Yummy"}; List list1 = Arrays.asList(strings); List list2 = Arrays.asList(strings); Collections.shuffle(list1); diff --git a/src/test/java/io/usethesource/vallang/basic/RegressionTest.java b/src/test/java/io/usethesource/vallang/basic/RegressionTest.java index e8ace3f01..c2cefbe8c 100644 --- a/src/test/java/io/usethesource/vallang/basic/RegressionTest.java +++ b/src/test/java/io/usethesource/vallang/basic/RegressionTest.java @@ -21,14 +21,14 @@ public class RegressionTest { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testConstructorEquality(IValueFactory vf, TypeFactory tf) throws Exception { - final TypeStore ts = new TypeStore(); - final Type adtType = tf.abstractDataType(ts, "n"); - final Type c0Type = tf.constructor (ts, adtType, "c"); - final Type c1Type = tf.constructor (ts, adtType, "c1", tf.integerType()); + final TypeStore ts = new TypeStore(); + final Type adtType = tf.abstractDataType(ts, "n"); + final Type c0Type = tf.constructor (ts, adtType, "c"); + final Type c1Type = tf.constructor (ts, adtType, "c1", tf.integerType()); - final IConstructor c0Normal = vf.constructor(c0Type); final IConstructor c0WithKWParams = vf.constructor(c0Type).asWithKeywordParameters().setParameters(Collections.emptyMap()); + final IConstructor c0Normal = vf.constructor(c0Type); final IConstructor c0WithKWParams = vf.constructor(c0Type).asWithKeywordParameters().setParameters(Collections.emptyMap()); - final IConstructor c1Normal = vf.constructor(c1Type, vf.integer(1)); + final IConstructor c1Normal = vf.constructor(c1Type, vf.integer(1)); final IConstructor c1WithKWParams = vf.constructor(c1Type, vf.integer(1)).asWithKeywordParameters().setParameters(Collections.emptyMap()); assertTrue(c0WithKWParams.equals(c0Normal)); @@ -36,7 +36,7 @@ public void testConstructorEquality(IValueFactory vf, TypeFactory tf) throws Exc assertTrue(c1WithKWParams.equals(c1Normal)); assertTrue(c1Normal.equals(c1WithKWParams)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRegression42_cause(IValueFactory vf, TypeStore store, @GivenValue("(\"\"():4,\"\"():3)") IValue v, @GivenValue("(\"\"():4,\"\"():3)") IValue u) throws IOException { assertTrue(v.equals(u)); diff --git a/src/test/java/io/usethesource/vallang/basic/RelationSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/RelationSmokeTest.java index ace10f668..e45ccba2e 100644 --- a/src/test/java/io/usethesource/vallang/basic/RelationSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/RelationSmokeTest.java @@ -1,641 +1,636 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Iterator; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.ISet; -import io.usethesource.vallang.ISetWriter; -import io.usethesource.vallang.ITuple; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; - -public final class RelationSmokeTest { - - private IValue[] integers(IValueFactory vf) { - IValue[] integers = new IValue[5]; - - for (int i = 0; i < integers.length; i++) { - integers[i] = vf.integer(i); - } - - return integers; - } - - private IValue[] doubles(IValueFactory vf) { - IValue[] doubles = new IValue[10]; - - for (int i = 0; i < doubles.length; i++) { - doubles[i] = vf.real(i); - } - - return doubles; - } - - - private ITuple[] integerTuples(IValueFactory vf) { - IValue[] integers = integers(vf); - ITuple[] integerTuples = new ITuple[integers.length * integers.length]; - - for (int i = 0; i < integers.length; i++) { - for (int j = 0; j < integers.length; j++) { - ITuple t = vf.tuple(integers[i], integers[j]); - integerTuples[i * integers.length + j] = t; - } - } - - return integerTuples; - } - - private ITuple[] doubleTuples(IValueFactory vf) { - IValue[] integers = doubles(vf); - ITuple[] integerTuples = new ITuple[integers.length * integers.length]; - - for (int i = 0; i < integers.length; i++) { - for (int j = 0; j < integers.length; j++) { - ITuple t = vf.tuple(integers[i], integers[j]); - integerTuples[i * integers.length + j] = t; - } - } - - return integerTuples; - } - - private ISet setOfIntegers(IValueFactory vf) { - ISetWriter lw = vf.setWriter(); - - for (IValue i : integers(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private ISet setOfDoubles(IValueFactory vf) { - ISetWriter lw = vf.setWriter(); - - for (IValue i : doubles(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private ISet integerRelation(IValueFactory vf) { - ISetWriter lw = vf.setWriter(); - - for (IValue i : integerTuples(vf)) { - lw.append(i); - } - - return lw.done(); - } - - private ISet doubleRelation(IValueFactory vf) { - ISetWriter lw = vf.setWriter(); - - for (IValue i : doubleTuples(vf)) { - lw.append(i); - } - - return lw.done(); - } - - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIsEmpty(IValueFactory vf) { - if (integerRelation(vf).isEmpty()) { - fail("integerRelation is not empty"); - } - - if (!vf.set().isEmpty()) { - fail("this relation should be empty"); - } - - ISet emptyRel = vf.set(); - if (!emptyRel.isEmpty()) { - fail("empty relation is not empty?"); - } - if (!emptyRel.getType().isRelation()) { - fail("empty relation should have relation type"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSize(IValueFactory vf) { - if (integerRelation(vf).size() != integerTuples(vf).length) { - fail("relation size is not correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testArity(IValueFactory vf) { - if (integerRelation(vf).asRelation().arity() != 2) { - fail("arity should be 2"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductIRelation(IValueFactory vf) { - ISet prod = integerRelation(vf).product(integerRelation(vf)); - - if (prod.asRelation().arity() != 2) { - fail("arity of product should be 2"); - } - - if (prod.size() != integerRelation(vf).size() * integerRelation(vf).size()) { - fail("size of product should be square of size of integerRelation"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductISet(IValueFactory vf) { - ISet prod = integerRelation(vf).product(setOfIntegers(vf)); - - if (prod.asRelation().arity() != 2) { - fail("arity of product should be 2"); - } - - if (prod.size() != integerRelation(vf).size() * setOfIntegers(vf).size()) { - fail("size of product should be square of size of integerRelation"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testClosureFailureOnIrreflexiveRelation(IValueFactory vf) { - // rascal>{<"",{}>}+ - // java.lang.AssertionError - // (internal error) - // at $shell$(|main://$shell$|) - // java.lang.AssertionError - // at io.usethesource.vallang.impl.persistent.PersistentHashIndexedBinaryRelation.(PersistentHashIndexedBinaryRelation.java:74) - // at io.usethesource.vallang.impl.persistent.PersistentSetFactory.from(PersistentSetFactory.java:67) - // at io.usethesource.vallang.impl.persistent.PersistentHashIndexedBinaryRelation.closure(PersistentHashIndexedBinaryRelation.java:573) - ISet input = vf.set(vf.tuple(vf.string(""), vf.set())); - - assertTrue(input.asRelation().closure().equals(input)); - } - - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testClosure(IValueFactory vf) { - try { - if (!integerRelation(vf).asRelation().closure().equals(integerRelation(vf))) { - fail("closure adds extra tuples?"); - } - } catch (FactTypeUseException e) { - fail("integerRelation is reflexive, so why an error?"); - } - - try { - ISet rel = vf.set(); - rel.asRelation().closure(); - } catch (FactTypeUseException e) { - fail("reflexivity with subtyping is allowed"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); - ITuple t2 = vf.tuple(integers(vf)[1], integers(vf)[2]); - ITuple t3 = vf.tuple(integers(vf)[2], integers(vf)[3]); - ITuple t4 = vf.tuple(integers(vf)[0], integers(vf)[2]); - ITuple t5 = vf.tuple(integers(vf)[1], integers(vf)[3]); - ITuple t6 = vf.tuple(integers(vf)[0], integers(vf)[3]); - - ISet test = vf.set(t1, t2, t3); - ISet closed = test.asRelation().closure(); - - if (closed.asRelation().arity() != test.asRelation().arity()) { - fail("closure should produce relations of same arity"); - } - - if (closed.size() != 6) { - fail("closure contains too few elements"); - } - - if (!closed.intersect(test).equals(test)) { - fail("closure should contain all original elements"); - } - - if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) { - fail("closure does not contain required elements"); - } - - } catch (FactTypeUseException e) { - fail("this should all be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testCompose(IValueFactory vf) { - try { - ISet comp = integerRelation(vf).asRelation().compose(integerRelation(vf).asRelation()); - - if (comp.asRelation().arity() != integerRelation(vf).asRelation().arity() * 2 - 2) { - fail( - "composition is a product with the last column of the first relation and the first column of the last relation removed"); - } - - if (comp.size() != integerRelation(vf).size()) { - fail("numner of expected tuples is off"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); - ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); - ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); - ISet rel1 = vf.set(t1, t2, t3); - - ITuple t4 = vf.tuple(doubles(vf)[0], integers(vf)[0]); - ITuple t5 = vf.tuple(doubles(vf)[1], integers(vf)[1]); - ITuple t6 = vf.tuple(doubles(vf)[2], integers(vf)[2]); - ISet rel2 = vf.set(t4, t5, t6); - - ITuple t7 = vf.tuple(integers(vf)[0], integers(vf)[0]); - ITuple t8 = vf.tuple(integers(vf)[1], integers(vf)[1]); - ITuple t9 = vf.tuple(integers(vf)[2], integers(vf)[2]); - ISet rel3 = vf.set(t7, t8, t9); - assertTrue(vf - .set(vf.tuple(doubles(vf)[0], doubles(vf)[0])).asRelation().compose(rel1.asRelation()).isEmpty(), - "Non-comparable types should yield empty composition result."); - ISet comp = rel1.asRelation().compose(rel2.asRelation()); - - if (!comp.equals(rel3)) { - fail("composition does not produce expected result"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testContains(IValueFactory vf) { - try { - for (ITuple t : integerTuples(vf)) { - if (!integerRelation(vf).contains(t)) { - fail("contains returns false instead of true"); - } - } - } catch (FactTypeUseException e) { - fail("this should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInsert(IValueFactory vf) { - try { - ISet rel = integerRelation(vf).insert(vf.tuple(vf.integer(0), vf.integer(0))); - - if (!rel.equals(integerRelation(vf))) { - fail("insert into a relation of an existing tuple should not change the relation"); - } - - ISetWriter relw3 = vf.setWriter(); - relw3.insertAll(integerRelation(vf)); - ISet rel3 = relw3.done(); - - final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100)); - ISet rel4 = rel3.insert(tuple); - - if (rel4.size() != integerRelation(vf).size() + 1) { - fail("insert failed"); - } - - if (!rel4.contains(tuple)) { - fail("insert failed"); - } - - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntersectIRelation(IValueFactory vf) { - - try { - if (!integerRelation(vf).intersect(doubleRelation(vf)).isEmpty()) { - fail("non-intersecting relations should produce empty intersections"); - } - - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result = vf.set(integerTuples(vf)[2]); - - if (!oneTwoThree.intersect(threeFourFive).equals(result)) { - fail("intersection failed"); - } - if (!threeFourFive.intersect(oneTwoThree).equals(result)) { - fail("intersection should be commutative"); - } - - if (!oneTwoThree.intersect(vf.set()) - .isEmpty()) { - fail("intersection with empty set should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntersectISet(IValueFactory vf, TypeFactory tf) { - ISet empty1 = vf.set(); - ISet empty2 = vf.set(); - - try { - final ISet intersection = empty1.intersect(empty2); - if (!intersection.isEmpty()) { - fail("empty intersection failed"); - } - - Type type = intersection.getType(); - if (!type.getFieldType(0).isSubtypeOf(tf.numberType())) { - fail("intersection should produce lub types"); - } - } catch (FactTypeUseException e) { - fail("intersecting types which have a lub should be possible"); - } - - try { - if (!integerRelation(vf).intersect(doubleRelation(vf)).isEmpty()) { - fail("non-intersecting relations should produce empty intersections"); - } - - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result = vf.set(integerTuples(vf)[2]); - - if (!oneTwoThree.intersect(threeFourFive).equals(result)) { - fail("intersection failed"); - } - if (!threeFourFive.intersect(oneTwoThree).equals(result)) { - fail("intersection should be commutative"); - } - - if (!oneTwoThree.intersect(vf.set()) - .isEmpty()) { - fail("intersection with empty set should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSubtractIRelation(IValueFactory vf) { - ISet empty1 = vf.set(); - ISet empty2 = vf.set(); - - try { - final ISet diff = empty1.subtract(empty2); - if (!diff.isEmpty()) { - fail("empty diff failed"); - } - - } catch (FactTypeUseException e) { - fail("subtracting types which have a lub should be possible"); - } - - try { - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result1 = vf.set(integerTuples(vf)[0], integerTuples(vf)[1]); - ISet result2 = vf.set(integerTuples(vf)[3], integerTuples(vf)[4]); - - if (!oneTwoThree.subtract(threeFourFive).equals(result1)) { - fail("subtraction failed"); - } - if (!threeFourFive.subtract(oneTwoThree).equals(result2)) { - fail("subtraction failed"); - } - - ISet empty3 = vf.set(); - if (!empty3.subtract(threeFourFive).isEmpty()) { - fail("subtracting from empty set should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSubtractISet(IValueFactory vf) { - ISet empty1 = vf.set(); - ISet empty2 = vf.set(); - - try { - final ISet diff = empty1.subtract(empty2); - if (!diff.isEmpty()) { - fail("empty diff failed"); - } - - } catch (FactTypeUseException e) { - fail("subtracting types which have a lub should be possible"); - } - - try { - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result1 = vf.set(integerTuples(vf)[0], integerTuples(vf)[1]); - - if (!oneTwoThree.subtract(threeFourFive).equals(result1)) { - fail("subtraction failed"); - } - - ISet empty3 = vf.set(); - if (!empty3.subtract(threeFourFive).isEmpty()) { - fail("subtracting from empty set should produce empty"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testUnionIRelation(IValueFactory vf) { - try { - if (integerRelation(vf).union(doubleRelation(vf)).size() != integerRelation(vf).size() - + doubleRelation(vf).size()) { - fail( - "non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); - } - - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], integerTuples(vf)[3], - integerTuples(vf)[4]); - - if (!oneTwoThree.union(threeFourFive).equals(result)) { - fail("union failed"); - } - if (!threeFourFive.union(oneTwoThree).equals(result)) { - fail("union should be commutative"); - } - - if (!oneTwoThree.union(vf.set()) - .equals(oneTwoThree)) { - fail("union with empty set should produce same set"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEmptySetIsARelation(IValueFactory vf) { - assertTrue(vf.set().getType().isRelation()); - - ISet r = vf.set().insert(vf.tuple(vf.integer(1), vf.integer(2))); - r = r.subtract(r); - assertTrue(r.getType().isRelation()); - - ISet s = vf.set().insert(vf.integer(1)); - s = s.subtract(s); - assertTrue(s.getType().isRelation()); // yes really! - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testUnionISet(IValueFactory vf) { - try { - if (integerRelation(vf).union(doubleRelation(vf)).size() != integerRelation(vf).size() - + doubleRelation(vf).size()) { - fail( - "non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); - } - - ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); - ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); - ISet result = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], integerTuples(vf)[3], - integerTuples(vf)[4]); - - if (!oneTwoThree.union(threeFourFive).equals(result)) { - fail("union failed"); - } - if (!threeFourFive.union(oneTwoThree).equals(result)) { - fail("union should be commutative"); - } - - if (!oneTwoThree.union(vf.set()) - .equals(oneTwoThree)) { - fail("union with empty set should produce same set"); - } - - } catch (FactTypeUseException e) { - fail("the above should all be type safe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIterator(IValueFactory vf) { - try { - Iterator it = integerRelation(vf).iterator(); - - int i; - for (i = 0; it.hasNext(); i++) { - ITuple t = (ITuple) it.next(); - - if (!integerRelation(vf).contains(t)) { - fail("iterator produces strange elements?"); - } - } - - if (i != integerRelation(vf).size()) { - fail("iterator skipped elements"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testCarrier(IValueFactory vf, TypeFactory tf) { - ISet carrier = integerRelation(vf).asRelation().carrier(); - - if (!carrier.equals(setOfIntegers(vf))) { - fail("carrier should be equal to this set"); - } - - try { - ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); - ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); - ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); - ISet rel1 = vf.set(t1, t2, t3); - - ISet carrier1 = rel1.asRelation().carrier(); - - if (carrier1.getElementType() != tf.numberType()) { - fail("expected number type on carrier"); - } - - if (carrier1.size() != 6) { - fail("carrier does not contain all elements"); - } - - if (carrier1.intersect(setOfIntegers(vf)).size() != 3) { - fail("integers should be in there still"); - } - - if (carrier1.intersect(setOfDoubles(vf)).size() != 3) { - fail("doubles should be in there still"); - } - } catch (FactTypeUseException e) { - fail("the above should be type correct"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIndex(IValueFactory vf) { - testIndex(integerRelation(vf)); - testIndex(doubleRelation(vf)); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEmptyIndex(IValueFactory vf) { - assertTrue(integerRelation(vf).asRelation().index(vf.integer(integers(vf).length + 1)).isEmpty()); - } - - private void testIndex(ISet targetRel) { - for (IValue key: targetRel.asRelation().domain()) { - ISet values = targetRel.asRelation().index(key); - for (IValue val : targetRel) { - ITuple t = (ITuple) val; - if (t.get(0).equals(key)) { - assertTrue(values.contains(t.get(1))); - values = values.delete(t.get(1)); - } - } - assertTrue(values.isEmpty()); - } - } -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Iterator; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.ISet; +import io.usethesource.vallang.ISetWriter; +import io.usethesource.vallang.ITuple; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; + +public final class RelationSmokeTest { + + private IValue[] integers(IValueFactory vf) { + IValue[] integers = new IValue[5]; + + for (int i = 0; i < integers.length; i++) { + integers[i] = vf.integer(i); + } + + return integers; + } + + private IValue[] doubles(IValueFactory vf) { + IValue[] doubles = new IValue[10]; + + for (int i = 0; i < doubles.length; i++) { + doubles[i] = vf.real(i); + } + + return doubles; + } + + + private ITuple[] integerTuples(IValueFactory vf) { + IValue[] integers = integers(vf); + ITuple[] integerTuples = new ITuple[integers.length * integers.length]; + + for (int i = 0; i < integers.length; i++) { + for (int j = 0; j < integers.length; j++) { + ITuple t = vf.tuple(integers[i], integers[j]); + integerTuples[i * integers.length + j] = t; + } + } + + return integerTuples; + } + + private ITuple[] doubleTuples(IValueFactory vf) { + IValue[] integers = doubles(vf); + ITuple[] integerTuples = new ITuple[integers.length * integers.length]; + + for (int i = 0; i < integers.length; i++) { + for (int j = 0; j < integers.length; j++) { + ITuple t = vf.tuple(integers[i], integers[j]); + integerTuples[i * integers.length + j] = t; + } + } + + return integerTuples; + } + + private ISet setOfIntegers(IValueFactory vf) { + ISetWriter lw = vf.setWriter(); + + for (IValue i : integers(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private ISet setOfDoubles(IValueFactory vf) { + ISetWriter lw = vf.setWriter(); + + for (IValue i : doubles(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private ISet integerRelation(IValueFactory vf) { + ISetWriter lw = vf.setWriter(); + + for (IValue i : integerTuples(vf)) { + lw.append(i); + } + + return lw.done(); + } + + private ISet doubleRelation(IValueFactory vf) { + ISetWriter lw = vf.setWriter(); + + for (IValue i : doubleTuples(vf)) { + lw.append(i); + } + + return lw.done(); + } + + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIsEmpty(IValueFactory vf) { + if (integerRelation(vf).isEmpty()) { + fail("integerRelation is not empty"); + } + + if (!vf.set().isEmpty()) { + fail("this relation should be empty"); + } + + ISet emptyRel = vf.set(); + if (!emptyRel.isEmpty()) { + fail("empty relation is not empty?"); + } + if (!emptyRel.getType().isRelation()) { + fail("empty relation should have relation type"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSize(IValueFactory vf) { + if (integerRelation(vf).size() != integerTuples(vf).length) { + fail("relation size is not correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testArity(IValueFactory vf) { + if (integerRelation(vf).asRelation().arity() != 2) { + fail("arity should be 2"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductIRelation(IValueFactory vf) { + ISet prod = integerRelation(vf).product(integerRelation(vf)); + + if (prod.asRelation().arity() != 2) { + fail("arity of product should be 2"); + } + + if (prod.size() != integerRelation(vf).size() * integerRelation(vf).size()) { + fail("size of product should be square of size of integerRelation"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductISet(IValueFactory vf) { + ISet prod = integerRelation(vf).product(setOfIntegers(vf)); + + if (prod.asRelation().arity() != 2) { + fail("arity of product should be 2"); + } + + if (prod.size() != integerRelation(vf).size() * setOfIntegers(vf).size()) { + fail("size of product should be square of size of integerRelation"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testClosureFailureOnIrreflexiveRelation(IValueFactory vf) { + // rascal>{<"",{}>}+ + // java.lang.AssertionError + // (internal error) + // at $shell$(|main://$shell$|) + // java.lang.AssertionError + // at io.usethesource.vallang.impl.persistent.PersistentHashIndexedBinaryRelation.(PersistentHashIndexedBinaryRelation.java:74) + // at io.usethesource.vallang.impl.persistent.PersistentSetFactory.from(PersistentSetFactory.java:67) + // at io.usethesource.vallang.impl.persistent.PersistentHashIndexedBinaryRelation.closure(PersistentHashIndexedBinaryRelation.java:573) + ISet input = vf.set(vf.tuple(vf.string(""), vf.set())); + + assertTrue(input.asRelation().closure().equals(input)); + } + + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testClosure(IValueFactory vf) { + try { + if (!integerRelation(vf).asRelation().closure().equals(integerRelation(vf))) { + fail("closure adds extra tuples?"); + } + } catch (FactTypeUseException e) { + fail("integerRelation is reflexive, so why an error?"); + } + + try { + ISet rel = vf.set(); + rel.asRelation().closure(); + } catch (FactTypeUseException e) { + fail("reflexivity with subtyping is allowed"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], integers(vf)[1]); + ITuple t2 = vf.tuple(integers(vf)[1], integers(vf)[2]); + ITuple t3 = vf.tuple(integers(vf)[2], integers(vf)[3]); + ITuple t4 = vf.tuple(integers(vf)[0], integers(vf)[2]); + ITuple t5 = vf.tuple(integers(vf)[1], integers(vf)[3]); + ITuple t6 = vf.tuple(integers(vf)[0], integers(vf)[3]); + + ISet test = vf.set(t1, t2, t3); + ISet closed = test.asRelation().closure(); + + if (closed.asRelation().arity() != test.asRelation().arity()) { + fail("closure should produce relations of same arity"); + } + + if (closed.size() != 6) { + fail("closure contains too few elements"); + } + + if (!closed.intersect(test).equals(test)) { + fail("closure should contain all original elements"); + } + + if (!closed.contains(t4) || !closed.contains(t5) || !closed.contains(t6)) { + fail("closure does not contain required elements"); + } + + } catch (FactTypeUseException e) { + fail("this should all be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testCompose(IValueFactory vf) { + try { + ISet comp = integerRelation(vf).asRelation().compose(integerRelation(vf).asRelation()); + + if (comp.asRelation().arity() != integerRelation(vf).asRelation().arity() * 2 - 2) { + fail("composition is a product with the last column of the first relation and the first column of the last relation removed"); + } + + if (comp.size() != integerRelation(vf).size()) { + fail("numner of expected tuples is off"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); + ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); + ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); + ISet rel1 = vf.set(t1, t2, t3); + + ITuple t4 = vf.tuple(doubles(vf)[0], integers(vf)[0]); + ITuple t5 = vf.tuple(doubles(vf)[1], integers(vf)[1]); + ITuple t6 = vf.tuple(doubles(vf)[2], integers(vf)[2]); + ISet rel2 = vf.set(t4, t5, t6); + + ITuple t7 = vf.tuple(integers(vf)[0], integers(vf)[0]); + ITuple t8 = vf.tuple(integers(vf)[1], integers(vf)[1]); + ITuple t9 = vf.tuple(integers(vf)[2], integers(vf)[2]); + ISet rel3 = vf.set(t7, t8, t9); + assertTrue(vf + .set(vf.tuple(doubles(vf)[0], doubles(vf)[0])).asRelation().compose(rel1.asRelation()).isEmpty(), + "Non-comparable types should yield empty composition result."); + ISet comp = rel1.asRelation().compose(rel2.asRelation()); + + if (!comp.equals(rel3)) { + fail("composition does not produce expected result"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testContains(IValueFactory vf) { + try { + for (ITuple t : integerTuples(vf)) { + if (!integerRelation(vf).contains(t)) { + fail("contains returns false instead of true"); + } + } + } catch (FactTypeUseException e) { + fail("this should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInsert(IValueFactory vf) { + try { + ISet rel = integerRelation(vf).insert(vf.tuple(vf.integer(0), vf.integer(0))); + + if (!rel.equals(integerRelation(vf))) { + fail("insert into a relation of an existing tuple should not change the relation"); + } + + ISetWriter relw3 = vf.setWriter(); + relw3.insertAll(integerRelation(vf)); + ISet rel3 = relw3.done(); + + final ITuple tuple = vf.tuple(vf.integer(100), vf.integer(100)); + ISet rel4 = rel3.insert(tuple); + + if (rel4.size() != integerRelation(vf).size() + 1) { + fail("insert failed"); + } + + if (!rel4.contains(tuple)) { + fail("insert failed"); + } + + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntersectIRelation(IValueFactory vf) { + + try { + if (!integerRelation(vf).intersect(doubleRelation(vf)).isEmpty()) { + fail("non-intersecting relations should produce empty intersections"); + } + + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result = vf.set(integerTuples(vf)[2]); + + if (!oneTwoThree.intersect(threeFourFive).equals(result)) { + fail("intersection failed"); + } + if (!threeFourFive.intersect(oneTwoThree).equals(result)) { + fail("intersection should be commutative"); + } + + if (!oneTwoThree.intersect(vf.set()) + .isEmpty()) { + fail("intersection with empty set should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntersectISet(IValueFactory vf, TypeFactory tf) { + ISet empty1 = vf.set(); + ISet empty2 = vf.set(); + + try { + final ISet intersection = empty1.intersect(empty2); + if (!intersection.isEmpty()) { + fail("empty intersection failed"); + } + + Type type = intersection.getType(); + if (!type.getFieldType(0).isSubtypeOf(tf.numberType())) { + fail("intersection should produce lub types"); + } + } catch (FactTypeUseException e) { + fail("intersecting types which have a lub should be possible"); + } + + try { + if (!integerRelation(vf).intersect(doubleRelation(vf)).isEmpty()) { + fail("non-intersecting relations should produce empty intersections"); + } + + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result = vf.set(integerTuples(vf)[2]); + + if (!oneTwoThree.intersect(threeFourFive).equals(result)) { + fail("intersection failed"); + } + if (!threeFourFive.intersect(oneTwoThree).equals(result)) { + fail("intersection should be commutative"); + } + + if (!oneTwoThree.intersect(vf.set()) + .isEmpty()) { + fail("intersection with empty set should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSubtractIRelation(IValueFactory vf) { + ISet empty1 = vf.set(); + ISet empty2 = vf.set(); + + try { + final ISet diff = empty1.subtract(empty2); + if (!diff.isEmpty()) { + fail("empty diff failed"); + } + + } catch (FactTypeUseException e) { + fail("subtracting types which have a lub should be possible"); + } + + try { + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result1 = vf.set(integerTuples(vf)[0], integerTuples(vf)[1]); + ISet result2 = vf.set(integerTuples(vf)[3], integerTuples(vf)[4]); + + if (!oneTwoThree.subtract(threeFourFive).equals(result1)) { + fail("subtraction failed"); + } + if (!threeFourFive.subtract(oneTwoThree).equals(result2)) { + fail("subtraction failed"); + } + + ISet empty3 = vf.set(); + if (!empty3.subtract(threeFourFive).isEmpty()) { + fail("subtracting from empty set should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSubtractISet(IValueFactory vf) { + ISet empty1 = vf.set(); + ISet empty2 = vf.set(); + + try { + final ISet diff = empty1.subtract(empty2); + if (!diff.isEmpty()) { + fail("empty diff failed"); + } + + } catch (FactTypeUseException e) { + fail("subtracting types which have a lub should be possible"); + } + + try { + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result1 = vf.set(integerTuples(vf)[0], integerTuples(vf)[1]); + + if (!oneTwoThree.subtract(threeFourFive).equals(result1)) { + fail("subtraction failed"); + } + + ISet empty3 = vf.set(); + if (!empty3.subtract(threeFourFive).isEmpty()) { + fail("subtracting from empty set should produce empty"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testUnionIRelation(IValueFactory vf) { + try { + if (integerRelation(vf).union(doubleRelation(vf)).size() != integerRelation(vf).size() + + doubleRelation(vf).size()) { + fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); + } + + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], integerTuples(vf)[3], + integerTuples(vf)[4]); + + if (!oneTwoThree.union(threeFourFive).equals(result)) { + fail("union failed"); + } + if (!threeFourFive.union(oneTwoThree).equals(result)) { + fail("union should be commutative"); + } + + if (!oneTwoThree.union(vf.set()) + .equals(oneTwoThree)) { + fail("union with empty set should produce same set"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEmptySetIsARelation(IValueFactory vf) { + assertTrue(vf.set().getType().isRelation()); + + ISet r = vf.set().insert(vf.tuple(vf.integer(1), vf.integer(2))); + r = r.subtract(r); + assertTrue(r.getType().isRelation()); + + ISet s = vf.set().insert(vf.integer(1)); + s = s.subtract(s); + assertTrue(s.getType().isRelation()); // yes really! + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testUnionISet(IValueFactory vf) { + try { + if (integerRelation(vf).union(doubleRelation(vf)).size() != integerRelation(vf).size() + + doubleRelation(vf).size()) { + fail("non-intersecting non-intersectiopn relations should produce relation that is the sum of the sizes"); + } + + ISet oneTwoThree = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2]); + ISet threeFourFive = vf.set(integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + ISet result = vf.set(integerTuples(vf)[0], integerTuples(vf)[1], integerTuples(vf)[2], integerTuples(vf)[3], integerTuples(vf)[4]); + + if (!oneTwoThree.union(threeFourFive).equals(result)) { + fail("union failed"); + } + if (!threeFourFive.union(oneTwoThree).equals(result)) { + fail("union should be commutative"); + } + + if (!oneTwoThree.union(vf.set()).equals(oneTwoThree)) { + fail("union with empty set should produce same set"); + } + + } catch (FactTypeUseException e) { + fail("the above should all be type safe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIterator(IValueFactory vf) { + try { + Iterator it = integerRelation(vf).iterator(); + + int i; + for (i = 0; it.hasNext(); i++) { + ITuple t = (ITuple) it.next(); + + if (!integerRelation(vf).contains(t)) { + fail("iterator produces strange elements?"); + } + } + + if (i != integerRelation(vf).size()) { + fail("iterator skipped elements"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testCarrier(IValueFactory vf, TypeFactory tf) { + ISet carrier = integerRelation(vf).asRelation().carrier(); + + if (!carrier.equals(setOfIntegers(vf))) { + fail("carrier should be equal to this set"); + } + + try { + ITuple t1 = vf.tuple(integers(vf)[0], doubles(vf)[0]); + ITuple t2 = vf.tuple(integers(vf)[1], doubles(vf)[1]); + ITuple t3 = vf.tuple(integers(vf)[2], doubles(vf)[2]); + ISet rel1 = vf.set(t1, t2, t3); + + ISet carrier1 = rel1.asRelation().carrier(); + + if (carrier1.getElementType() != tf.numberType()) { + fail("expected number type on carrier"); + } + + if (carrier1.size() != 6) { + fail("carrier does not contain all elements"); + } + + if (carrier1.intersect(setOfIntegers(vf)).size() != 3) { + fail("integers should be in there still"); + } + + if (carrier1.intersect(setOfDoubles(vf)).size() != 3) { + fail("doubles should be in there still"); + } + } catch (FactTypeUseException e) { + fail("the above should be type correct"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIndex(IValueFactory vf) { + testIndex(integerRelation(vf)); + testIndex(doubleRelation(vf)); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEmptyIndex(IValueFactory vf) { + assertTrue(integerRelation(vf).asRelation().index(vf.integer(integers(vf).length + 1)).isEmpty()); + } + + private void testIndex(ISet targetRel) { + for (IValue key: targetRel.asRelation().domain()) { + ISet values = targetRel.asRelation().index(key); + for (IValue val : targetRel) { + ITuple t = (ITuple) val; + if (t.get(0).equals(key)) { + assertTrue(values.contains(t.get(1))); + values = values.delete(t.get(1)); + } + } + assertTrue(values.isEmpty()); + } + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/SetSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/SetSmokeTest.java index f372ab501..d327eddf1 100644 --- a/src/test/java/io/usethesource/vallang/basic/SetSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/SetSmokeTest.java @@ -1,357 +1,357 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Iterator; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.ISet; -import io.usethesource.vallang.ISetWriter; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.TypeFactory; - -public final class SetSmokeTest { - - private IValue[] integers(IValueFactory vf) { - IValue[] integers = new IValue[100]; - - for (int i = 0; i < integers.length; i++) { - integers[i] = vf.integer(i); - } - - return integers; - } - - private IValue[] doubles(IValueFactory vf) { - IValue[] integers = new IValue[100]; - - for (int i = 0; i < integers.length; i++) { - integers[i] = vf.real(i); - } - - return integers; - } - - private ISet integerUniverse(IValueFactory vf) { - ISetWriter w = vf.setWriter(); - - for (IValue i : integers(vf)) { - w.insert(i); - } - - return w.done(); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInsert(IValueFactory vf) { - ISet set1 = vf.set(); - ISet set2; - - try { - set2 = set1.insert(integers(vf)[0]); - - if (set2.size() != 1) { - fail("insertion failed"); - } - - if (!set2.contains(integers(vf)[0])) { - fail("insertion failed"); - } - - } catch (FactTypeUseException e1) { - fail("type checking error:" + e1); - } - - ISetWriter numberSet = vf.setWriter(); - - try { - numberSet.insert(integers(vf)[0]); - numberSet.insert(doubles(vf)[0]); - } catch (FactTypeUseException e) { - fail("should be able to insert subtypes:" + e); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testEmpty(IValueFactory vf) { - ISet emptySet = vf.set(); - if (!emptySet.isEmpty()) { - fail("empty set is not empty?"); - } - - if (!emptySet.getType().isRelation()) { - fail("empty set should have relation type (yes really!)"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testContains(IValueFactory vf) { - ISet set1 = vf.set(integers(vf)[0], integers(vf)[1]); - - try { - set1.contains(integers(vf)[0]); - } catch (FactTypeUseException e) { - fail("should be able to check for containment of integers"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIntersect(IValueFactory vf) { - ISet set1 = vf.set(); - ISet set2 = vf.set(); - ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); - ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); - ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); - - try { - if (!set1.intersect(set2).isEmpty()) { - fail("intersect of empty sets"); - } - - if (!set1.intersect(set3).isEmpty()) { - fail("intersect with empty set"); - } - - if (!set3.intersect(set1).isEmpty()) { - fail("insersect with empty set"); - } - - if (set3.intersect(set4).size() != 1) { - fail("insersect failed"); - } - - if (!set4.intersect(set3).contains(integers(vf)[2])) { - fail("intersect failed"); - } - - if (set4.intersect(set5).size() != 2) { - fail("insersect failed"); - } - - if (!set5.intersect(set4).contains(integers(vf)[3]) - || !set5.intersect(set4).contains(integers(vf)[4])) { - fail("intersect failed"); - } - - if (!set5.intersect(set3).isEmpty()) { - fail("non-intersection sets"); - } - - } catch (FactTypeUseException et) { - fail("this shouls all be typesafe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIsEmpty(IValueFactory vf) { - if (integerUniverse(vf).isEmpty()) { - fail("an empty universe is not so cosy"); - } - - if (!vf.set().isEmpty()) { - fail("what's in an empty set?"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSize(IValueFactory vf) { - if (vf.set().size() != 0) { - fail("empty sets have size 0"); - } - - if (vf.set(integers(vf)[0]).size() != 1) { - fail("singleton set should have size 1"); - } - - if (integerUniverse(vf).size() != integers(vf).length) { - fail("weird size of universe"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSubtract(IValueFactory vf) { - ISet set1 = vf.set(); - ISet set2 = vf.set(); - ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); - ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); - ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); - - try { - if (!set1.subtract(set2).isEmpty()) { - fail("subtract of empty sets"); - } - - if (!set1.subtract(set3).isEmpty()) { - fail("subtract with empty set"); - } - - if (!set3.subtract(set1).equals(set3)) { - fail("subtract with empty set"); - } - - if (!set1.subtract(set3).equals(set1)) { - fail("subtract with empty set"); - } - - if (set3.subtract(set4).size() != 2) { - fail("subtract failed"); - } - - if (set4.subtract(set3).contains(integers(vf)[2])) { - fail("subtract failed"); - } - - if (set4.subtract(set5).size() != 1) { - fail("insersect failed"); - } - - if (set5.subtract(set4).contains(integers(vf)[3]) || set5.subtract(set4).contains(integers(vf)[4])) { - fail("subtract failed"); - } - - } catch (FactTypeUseException et) { - fail("this shouls all be typesafe"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testUnion(IValueFactory vf) { - ISet set1 = vf.set(); - ISet set2 = vf.set(); - ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); - ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); - ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); - - try { - if (!set1.union(set2).isEmpty()) { - fail("union of empty sets"); - } - - if (!set1.union(set3).equals(set3)) { - fail("union with empty set"); - } - - if (!set3.union(set1).equals(set3)) { - fail("union with empty set"); - } - - if (!set1.union(set3).equals(set3)) { - fail("union with empty set"); - } - - if (set3.union(set4).size() != 5) { - fail("union failed"); - } - - if (!set4.union(set3).contains(integers(vf)[0]) || !set4.union(set3).contains(integers(vf)[1]) - || !set4.union(set3).contains(integers(vf)[2]) || !set4.union(set3).contains(integers(vf)[3]) - || !set4.union(set3).contains(integers(vf)[4])) { - fail("union failed"); - } - - if (set4.union(set5).size() != 4) { - fail("union failed"); - } - - } catch (FactTypeUseException et) { - fail("this shouls all be typesafe"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testIterator(IValueFactory vf) { - try { - Iterator it = integerUniverse(vf).iterator(); - int i; - for (i = 0; it.hasNext(); i++) { - if (!integerUniverse(vf).contains(it.next())) { - fail("iterator produces something weird"); - } - } - if (i != integerUniverse(vf).size()) { - fail("iterator did not iterate over everything"); - } - } catch (FactTypeUseException e) { - fail("should be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testGetElementType(IValueFactory vf) { - if (!integerUniverse(vf).getElementType().isInteger()) { - fail("elementType is broken"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductISet(IValueFactory vf) { - ISet test = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2], integers(vf)[3]); - ISet prod = test.product(test); - - if (prod.asRelation().arity() != 2) { - fail("product's arity should be 2"); - } - - if (prod.size() != test.size() * test.size()) { - fail("product's size should be square of size"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testProductIRelation(IValueFactory vf) { - ISet test = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2], integers(vf)[3]); - ISet prod = test.product(test); - ISet prod2 = test.product(prod); - - if (prod2.asRelation().arity() != 2) { - fail("product's arity should be 2"); - } - - if (prod2.size() != test.size() * prod.size()) { - fail("product's size should be multiplication of arguments' sizes"); - } - - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testTypeDoubleInsertOneRemoveWithSet(IValueFactory vf, TypeFactory tf) { - ISet set1 = vf.set().insert(doubles(vf)[0]).insert(integers(vf)[0]).insert(integers(vf)[0]); - ISet set2 = set1.delete(integers(vf)[0]); - - assertEquals(tf.realType(), set2.getElementType()); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testTypeDoubleInsertOneRemoveWithSetWriter(IValueFactory vf, TypeFactory tf) { - ISetWriter w = vf.setWriter(); - w.insert(doubles(vf)[0]); - w.insert(integers(vf)[0]); - w.insert(integers(vf)[0]); - ISet set1 = w.done(); - ISet set2 = set1.delete(integers(vf)[0]); - - assertEquals(tf.realType(), set2.getElementType()); - } - -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Iterator; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.ISet; +import io.usethesource.vallang.ISetWriter; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.TypeFactory; + +public final class SetSmokeTest { + + private IValue[] integers(IValueFactory vf) { + IValue[] integers = new IValue[100]; + + for (int i = 0; i < integers.length; i++) { + integers[i] = vf.integer(i); + } + + return integers; + } + + private IValue[] doubles(IValueFactory vf) { + IValue[] integers = new IValue[100]; + + for (int i = 0; i < integers.length; i++) { + integers[i] = vf.real(i); + } + + return integers; + } + + private ISet integerUniverse(IValueFactory vf) { + ISetWriter w = vf.setWriter(); + + for (IValue i : integers(vf)) { + w.insert(i); + } + + return w.done(); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInsert(IValueFactory vf) { + ISet set1 = vf.set(); + ISet set2; + + try { + set2 = set1.insert(integers(vf)[0]); + + if (set2.size() != 1) { + fail("insertion failed"); + } + + if (!set2.contains(integers(vf)[0])) { + fail("insertion failed"); + } + + } catch (FactTypeUseException e1) { + fail("type checking error:" + e1); + } + + ISetWriter numberSet = vf.setWriter(); + + try { + numberSet.insert(integers(vf)[0]); + numberSet.insert(doubles(vf)[0]); + } catch (FactTypeUseException e) { + fail("should be able to insert subtypes:" + e); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testEmpty(IValueFactory vf) { + ISet emptySet = vf.set(); + if (!emptySet.isEmpty()) { + fail("empty set is not empty?"); + } + + if (!emptySet.getType().isRelation()) { + fail("empty set should have relation type (yes really!)"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testContains(IValueFactory vf) { + ISet set1 = vf.set(integers(vf)[0], integers(vf)[1]); + + try { + set1.contains(integers(vf)[0]); + } catch (FactTypeUseException e) { + fail("should be able to check for containment of integers"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIntersect(IValueFactory vf) { + ISet set1 = vf.set(); + ISet set2 = vf.set(); + ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); + ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); + ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); + + try { + if (!set1.intersect(set2).isEmpty()) { + fail("intersect of empty sets"); + } + + if (!set1.intersect(set3).isEmpty()) { + fail("intersect with empty set"); + } + + if (!set3.intersect(set1).isEmpty()) { + fail("insersect with empty set"); + } + + if (set3.intersect(set4).size() != 1) { + fail("insersect failed"); + } + + if (!set4.intersect(set3).contains(integers(vf)[2])) { + fail("intersect failed"); + } + + if (set4.intersect(set5).size() != 2) { + fail("insersect failed"); + } + + if (!set5.intersect(set4).contains(integers(vf)[3]) + || !set5.intersect(set4).contains(integers(vf)[4])) { + fail("intersect failed"); + } + + if (!set5.intersect(set3).isEmpty()) { + fail("non-intersection sets"); + } + + } catch (FactTypeUseException et) { + fail("this shouls all be typesafe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIsEmpty(IValueFactory vf) { + if (integerUniverse(vf).isEmpty()) { + fail("an empty universe is not so cosy"); + } + + if (!vf.set().isEmpty()) { + fail("what's in an empty set?"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSize(IValueFactory vf) { + if (vf.set().size() != 0) { + fail("empty sets have size 0"); + } + + if (vf.set(integers(vf)[0]).size() != 1) { + fail("singleton set should have size 1"); + } + + if (integerUniverse(vf).size() != integers(vf).length) { + fail("weird size of universe"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSubtract(IValueFactory vf) { + ISet set1 = vf.set(); + ISet set2 = vf.set(); + ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); + ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); + ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); + + try { + if (!set1.subtract(set2).isEmpty()) { + fail("subtract of empty sets"); + } + + if (!set1.subtract(set3).isEmpty()) { + fail("subtract with empty set"); + } + + if (!set3.subtract(set1).equals(set3)) { + fail("subtract with empty set"); + } + + if (!set1.subtract(set3).equals(set1)) { + fail("subtract with empty set"); + } + + if (set3.subtract(set4).size() != 2) { + fail("subtract failed"); + } + + if (set4.subtract(set3).contains(integers(vf)[2])) { + fail("subtract failed"); + } + + if (set4.subtract(set5).size() != 1) { + fail("insersect failed"); + } + + if (set5.subtract(set4).contains(integers(vf)[3]) || set5.subtract(set4).contains(integers(vf)[4])) { + fail("subtract failed"); + } + + } catch (FactTypeUseException et) { + fail("this shouls all be typesafe"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testUnion(IValueFactory vf) { + ISet set1 = vf.set(); + ISet set2 = vf.set(); + ISet set3 = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2]); + ISet set4 = vf.set(integers(vf)[2], integers(vf)[3], integers(vf)[4]); + ISet set5 = vf.set(integers(vf)[3], integers(vf)[4], integers(vf)[5]); + + try { + if (!set1.union(set2).isEmpty()) { + fail("union of empty sets"); + } + + if (!set1.union(set3).equals(set3)) { + fail("union with empty set"); + } + + if (!set3.union(set1).equals(set3)) { + fail("union with empty set"); + } + + if (!set1.union(set3).equals(set3)) { + fail("union with empty set"); + } + + if (set3.union(set4).size() != 5) { + fail("union failed"); + } + + if (!set4.union(set3).contains(integers(vf)[0]) || !set4.union(set3).contains(integers(vf)[1]) + || !set4.union(set3).contains(integers(vf)[2]) || !set4.union(set3).contains(integers(vf)[3]) + || !set4.union(set3).contains(integers(vf)[4])) { + fail("union failed"); + } + + if (set4.union(set5).size() != 4) { + fail("union failed"); + } + + } catch (FactTypeUseException et) { + fail("this shouls all be typesafe"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testIterator(IValueFactory vf) { + try { + Iterator it = integerUniverse(vf).iterator(); + int i; + for (i = 0; it.hasNext(); i++) { + if (!integerUniverse(vf).contains(it.next())) { + fail("iterator produces something weird"); + } + } + if (i != integerUniverse(vf).size()) { + fail("iterator did not iterate over everything"); + } + } catch (FactTypeUseException e) { + fail("should be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testGetElementType(IValueFactory vf) { + if (!integerUniverse(vf).getElementType().isInteger()) { + fail("elementType is broken"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductISet(IValueFactory vf) { + ISet test = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2], integers(vf)[3]); + ISet prod = test.product(test); + + if (prod.asRelation().arity() != 2) { + fail("product's arity should be 2"); + } + + if (prod.size() != test.size() * test.size()) { + fail("product's size should be square of size"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testProductIRelation(IValueFactory vf) { + ISet test = vf.set(integers(vf)[0], integers(vf)[1], integers(vf)[2], integers(vf)[3]); + ISet prod = test.product(test); + ISet prod2 = test.product(prod); + + if (prod2.asRelation().arity() != 2) { + fail("product's arity should be 2"); + } + + if (prod2.size() != test.size() * prod.size()) { + fail("product's size should be multiplication of arguments' sizes"); + } + + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testTypeDoubleInsertOneRemoveWithSet(IValueFactory vf, TypeFactory tf) { + ISet set1 = vf.set().insert(doubles(vf)[0]).insert(integers(vf)[0]).insert(integers(vf)[0]); + ISet set2 = set1.delete(integers(vf)[0]); + + assertEquals(tf.realType(), set2.getElementType()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testTypeDoubleInsertOneRemoveWithSetWriter(IValueFactory vf, TypeFactory tf) { + ISetWriter w = vf.setWriter(); + w.insert(doubles(vf)[0]); + w.insert(integers(vf)[0]); + w.insert(integers(vf)[0]); + ISet set1 = w.done(); + ISet set2 = set1.delete(integers(vf)[0]); + + assertEquals(tf.realType(), set2.getElementType()); + } + +} diff --git a/src/test/java/io/usethesource/vallang/basic/StreamCollectorTest.java b/src/test/java/io/usethesource/vallang/basic/StreamCollectorTest.java index e71d4774b..a9d746cf1 100644 --- a/src/test/java/io/usethesource/vallang/basic/StreamCollectorTest.java +++ b/src/test/java/io/usethesource/vallang/basic/StreamCollectorTest.java @@ -19,13 +19,13 @@ public void listCollector(IValueFactory vf, @ExpectedType("list[int]") IList ele IList l = elems.stream().collect(vf.listWriter()); assertEquals(l, elems); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void setCollector(IValueFactory vf, @ExpectedType("set[int]") ISet elems) { ISet l = elems.stream().collect(vf.setWriter()); assertEquals(l, elems); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void mapCollector(IValueFactory vf, @ExpectedType("map[int,int]") IMap elems) { IMap l = elems.stream().collect(vf.mapWriter()); diff --git a/src/test/java/io/usethesource/vallang/basic/StreamTest.java b/src/test/java/io/usethesource/vallang/basic/StreamTest.java index 4f82aa680..8d13b43f1 100644 --- a/src/test/java/io/usethesource/vallang/basic/StreamTest.java +++ b/src/test/java/io/usethesource/vallang/basic/StreamTest.java @@ -26,21 +26,21 @@ public void bottomup(IValueFactory vf, @GivenValue(TREE) IValue v, @GivenValue(B assertEquals(answer, numbers); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void topdown(IValueFactory vf, @GivenValue(TREE) IValue v, @GivenValue(TOPDOWN) IValue answer) { IList numbers = ValueStreams.topdown(v).map((n) -> vf.string(((INode) n).getName())).collect(vf.listWriter()); assertEquals(answer, numbers); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void topdownBreadthFirst(IValueFactory vf, @GivenValue(TREE) IValue v, @GivenValue(TOPDOWNBREADTHFIRST) IValue answer) { IList numbers = ValueStreams.topdownbf(v).map((n) -> vf.string(((INode) n).getName())).collect(vf.listWriter()); assertEquals(answer, numbers); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void bottomupBreadthFirst(IValueFactory vf, @GivenValue(TREE) IValue v, @GivenValue(BOTTOMUPBREADTHFIRST) IValue answer) { IList numbers = ValueStreams.bottomupbf(v).map((n) -> vf.string(((INode) n).getName())).collect(vf.listWriter()); diff --git a/src/test/java/io/usethesource/vallang/basic/TypeFactorySmokeTest.java b/src/test/java/io/usethesource/vallang/basic/TypeFactorySmokeTest.java index 7620e0e71..ba8a2bc25 100644 --- a/src/test/java/io/usethesource/vallang/basic/TypeFactorySmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/TypeFactorySmokeTest.java @@ -1,563 +1,563 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.io.StringReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeDeclarationException; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.Type; -import io.usethesource.vallang.type.TypeFactory; -import io.usethesource.vallang.type.TypeStore; - -public final class TypeFactorySmokeTest { - - private static TypeFactory ft = TypeFactory.getInstance(); - - private static Type[] types = new Type[] { ft.integerType(), ft.realType(), ft.sourceLocationType(), ft.valueType(), - ft.listType(ft.integerType()), ft.setType(ft.realType()) }; - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testGetInstance() { - if (TypeFactory.getInstance() != ft) { - fail("getInstance did not return the same reference"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testParametrizedAbstractDatatypeArityInvariant(TypeStore store) { - Type param = ft.parameterType("T"); - Type adt = ft.abstractDataType(store, "Test", ft.tupleType(param)); - Map bindings = new HashMap<>(); - bindings.put(param, ft.voidType()); - Type instant = adt.instantiate(bindings); - - assertTrue(instant.isParameterized()); - assertFalse(instant.getTypeParameters().isBottom()); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testValueType() { - if (ft.valueType() != ft.valueType()) { - fail("valueType should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testIntegerType() { - if (ft.integerType() != ft.integerType()) { - fail("integerType should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testDoubleType() { - if (ft.realType() != ft.realType()) { - fail("doubleType should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testStringType() { - if (ft.stringType() != ft.stringType()) { - fail("stringType should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testSourceLocationType() { - if (ft.sourceLocationType() != ft.sourceLocationType()) { - fail("sourceLocationType should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfType() { - Type t = ft.tupleType(types[0]); - - if (t != ft.tupleType(types[0])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 1); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeType() { - Type t = ft.tupleType(types[0], types[1]); - - if (t != ft.tupleType(types[0], types[1])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 2); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeTypeType() { - Type t = ft.tupleType(types[0], types[1], types[2]); - - if (t != ft.tupleType(types[0], types[1], types[2])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 3); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeTypeTypeType() { - Type t = ft.tupleType(types[0], types[1], types[2], types[3]); - - if (t != ft.tupleType(types[0], types[1], types[2], types[3])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 4); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeTypeTypeTypeType() { - Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4]); - - if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 5); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeTypeTypeTypeTypeType() { - Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5]); - - if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 6); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfTypeTypeTypeTypeTypeTypeType() { - Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5]); - - if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5])) { - fail("tuple types should be canonical"); - } - - checkTupleTypeOf(t, 6); - } - - private void checkTupleTypeOf(Type t, int width) { - - if (t.getArity() != width) { - fail("tuple arity broken"); - } - - for (int i = 0; i < t.getArity(); i++) { - if (t.getFieldType(i) != types[i % types.length]) { - fail("Tuple field type unexpected"); - } - } - } - - private void checkRelationTypeOf(Type t, int width) { - - if (t.getArity() != width) { - fail("relation arity broken"); - } - - for (int i = 0; i < t.getArity(); i++) { - if (t.getFieldType(i) != types[i % types.length]) { - fail("Relation field type unexpected"); - } - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeOfIValueArray(IValueFactory vf) { - // a and b shadow the 'types' field - try { - @SuppressWarnings("deprecation") - IValue[] a = new IValue[] { vf.integer(1), vf.real(1.0), - vf.sourceLocation(new URI("file://bla"), 0, 0, 0, 0, 0, 0) }; - @SuppressWarnings("deprecation") - IValue[] b = new IValue[] { vf.integer(1), vf.real(1.0), - vf.sourceLocation(new URI("file://bla"), 0, 0, 0, 0, 0, 0) }; - Type t = ft.tupleType(a); - - if (t != ft.tupleType(b)) { - fail("tuples should be canonical"); - } - - checkTupleTypeOf(t, 3); - } catch (URISyntaxException e) { - fail(e.toString()); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testSetTypeOf() { - Type type = ft.setType(ft.integerType()); - - if (type != ft.setType(ft.integerType())) { - fail("set should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeType() { - try { - TypeStore store = new TypeStore(); - Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - // note that the declared type of namedType needs to be Type - Type type = ft.relTypeFromTuple(namedType); - - Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - - if (type != ft.relTypeFromTuple(namedType2)) { - fail("relation types should be canonical"); - } - - if (type.getFieldType(0) != ft.integerType() && type.getFieldType(1) != ft.integerType()) { - fail("relation should mimick tuple field types"); - } - } catch (FactTypeUseException e) { - fail("type error for correct relation"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testListRelTypeType() { - try { - TypeStore store = new TypeStore(); - Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - // note that the declared type of namedType needs to be Type - Type type = ft.lrelTypeFromTuple(namedType); - - Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - - if (type != ft.lrelTypeFromTuple(namedType2)) { - fail("list relation types should be canonical"); - } - - if (type.getFieldType(0) != ft.integerType() && type.getFieldType(1) != ft.integerType()) { - fail("list relation should mimick tuple field types"); - } - } catch (FactTypeUseException e) { - fail("type error for correct list relation"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeNamedType() { - try { - TypeStore store = new TypeStore(); - Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - // note that the declared type of namedType needs to be AliasType - Type type = ft.relTypeFromTuple(namedType); - - Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - - if (type != ft.relTypeFromTuple(namedType2)) { - fail("relation types should be canonical"); - } - } catch (FactTypeUseException e) { - fail("type error for correct relation"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testListRelTypeNamedType() { - try { - TypeStore store = new TypeStore(); - Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - // note that the declared type of namedType needs to be AliasType - Type type = ft.lrelTypeFromTuple(namedType); - - Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); - - if (type != ft.lrelTypeFromTuple(namedType2)) { - fail("list relation types should be canonical"); - } - } catch (FactTypeUseException e) { - fail("type error for correct list relation"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeTupleType() { - Type tupleType = ft.tupleType(ft.integerType(), ft.integerType()); - // note that the declared type of tupleType needs to be TupleType - Type type = ft.relTypeFromTuple(tupleType); - - Type tupleType2 = ft.tupleType(ft.integerType(), ft.integerType()); - - if (type != ft.relTypeFromTuple(tupleType2)) { - fail("relation types should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testListRelTypeTupleType() { - Type tupleType = ft.tupleType(ft.integerType(), ft.integerType()); - // note that the declared type of tupleType needs to be TupleType - Type type = ft.lrelTypeFromTuple(tupleType); - - Type tupleType2 = ft.tupleType(ft.integerType(), ft.integerType()); - - if (type != ft.lrelTypeFromTuple(tupleType2)) { - fail("list relation types should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfType() { - Type type = ft.relType(types[0]); - - if (type != ft.relType(types[0])) { - fail("relation types should be canonical"); - } - - checkRelationTypeOf(type, 1); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeType() { - Type type = ft.relType(types[0], types[1]); - - if (type != ft.relType(types[0], types[1])) { - fail("relation types should be canonical"); - } - - checkRelationTypeOf(type, 2); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeTypeType() { - Type type = ft.relType(types[0], types[1], types[2]); - - if (type != ft.relType(types[0], types[1], types[2])) { - fail("relation types should be canonical"); - } - - checkRelationTypeOf(type, 3); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeTypeTypeType() { - Type type = ft.relType(types[0], types[1], types[2], types[3]); - - if (type != ft.relType(types[0], types[1], types[2], types[3])) { - fail("relation types should be canonical"); - } - checkRelationTypeOf(type, 4); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeTypeTypeTypeType() { - Type type = ft.relType(types[0], types[1], types[2], types[3], types[4]); - - if (type != ft.relType(types[0], types[1], types[2], types[3], types[4])) { - fail("relation types should be canonical"); - } - checkRelationTypeOf(type, 5); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeTypeTypeTypeTypeType() { - Type type = ft.relType(types[0], types[1], types[2], types[3], types[4], types[5]); - - if (type != ft.relType(types[0], types[1], types[2], types[3], types[4], types[5])) { - fail("relation types should be canonical"); - } - checkRelationTypeOf(type, 6); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testRelTypeOfTypeTypeTypeTypeTypeTypeType() { - Type type = ft.relType(types[0], types[1], types[2], types[3], types[4], types[5]); - - if (type != ft.relType(types[0], types[1], types[2], types[3], types[4], types[5])) { - fail("relation types should be canonical"); - } - checkRelationTypeOf(type, 6); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testNamedType() { - try { - TypeStore ts = new TypeStore(); - Type t1 = ft.aliasType(ts, "myType", ft.integerType()); - Type t2 = ft.aliasType(ts, "myType", ft.integerType()); - - if (t1 != t2) { - fail("named types should be canonical"); - } - - try { - ft.aliasType(ts, "myType", ft.realType()); - fail("Should not be allowed to redeclare a type name"); - } catch (FactTypeDeclarationException e) { - // this should happen - } - } catch (FactTypeDeclarationException e) { - fail("the above should be type correct"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testListType() { - Type t1 = ft.listType(ft.integerType()); - Type t2 = ft.listType(ft.integerType()); - - if (t1 != t2) { - fail("named types should be canonical"); - } - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testFunctionLub(TypeFactory tf) { - Type t1 = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType(), tf.integerType()), tf.tupleEmpty()); - Type t2 = tf.functionType(tf.integerType(), tf.tupleType(tf.rationalType(), tf.rationalType()), - tf.tupleEmpty()); - - // if the arity is the same, the lub is still a function type (for computing the - // types of overloaded functions) - assertTrue(!t1.lub(t2).isTop()); - assertTrue(t1.getArity() == t1.lub(t2).getArity()); - - // but if its not the same, then we default to value, because we don't know how - // to call a function with different amounts of parameters - Type t3 = tf.functionType(tf.integerType(), tf.tupleType(tf.stringType()), tf.tupleEmpty()); - assertTrue(t1.lub(t3).isTop()); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testHigherOrderSelfMatchOfFunctionType(TypeFactory tf) { - Type returnType = tf.parameterType("Ret"); - Type arg1 = tf.parameterType("Arg1"); - Type arg2 = tf.parameterType("Arg2"); - // &Ret curried(&Arg2 arg2) - Type curriedFunction = tf.functionType(returnType, tf.tupleType(arg2), tf.tupleEmpty()); - // &Ret func (&Arg1 arg1, &Arg2 arg2) - Type parameterFunction = tf.functionType(returnType, tf.tupleType(arg1, arg2), tf.tupleEmpty()); - // &Ret (&Arg2) curry (&Return (&Arg1, &Arg2) func, &Arg1 arg1) - Type curry = tf.functionType(curriedFunction, tf.tupleType(parameterFunction, arg1), tf.tupleEmpty()); - - // First we rename the type parameters for the purpose of parameter hygiene: - Map renamings = new HashMap<>(); - curry.match(tf.voidType(), renamings); - - for (Type key : renamings.keySet()) { - renamings.put(key, tf.parameterType(key.getName() + "'")); - } - - Type renamedCurry = curry.instantiate(renamings); - - // now we self apply the curry function with an add function - Type addFunction = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType(), tf.integerType()), - tf.tupleEmpty()); - Type curriedAdd = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType()), tf.tupleEmpty()); - Type curriedCurryReturn = tf.functionType(curriedAdd, tf.tupleType(tf.integerType()), tf.tupleEmpty()); - - // the goal is to arrive at a binding of &Ret to an instantiated int (int) - // curried function, via parameter matching - Type actualParameterTypes = tf.tupleType(renamedCurry, addFunction); - Type formalParameterTypes = curry.getFieldTypes(); - - Map bindings = new HashMap<>(); - - // this is where the bug was/is. - // applying curry(curry, add) should give `int(int arg2) (int arg1)` as a return - // type. - formalParameterTypes.match(actualParameterTypes, bindings); - - // instead we get the uninstantiated version &Ret' (&Arg2') (&Arg1') - assertTrue(curry.getReturnType().instantiate(bindings) == curriedCurryReturn); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testUnificationOfNestedNonLinearTypeParameters(TypeFactory tf, TypeStore store) throws IOException { - Type formals = tf.fromString(store, new StringReader("tuple[lrel[&T0,&T1],set[&T0]]")); - Type actuals = tf.fromString(store, new StringReader("tuple[lrel[int,int],set[void]]")); - Type T0 = tf.parameterType("T0"); - Type T0expected = tf.integerType().lub(tf.voidType()); - - Map bindings = new HashMap<>(); - formals.match(actuals, bindings); - - assertTrue(T0expected == bindings.get(T0)); - } - - @ParameterizedTest - @ArgumentsSource(ValueProvider.class) - public void testTupleTypeMatchAndInstantiateMustPreserveLabels(TypeFactory tf) throws IOException { - Type unlabeled = tf.listType(tf.tupleType(tf.integerType(), tf.integerType())); - Type labeled = tf.listType(tf.tupleType(tf.parameterType("T0"), "first", tf.parameterType("T1"), "second")); - - Map bindings = new HashMap<>(); - labeled.match(unlabeled, bindings); - - assertTrue(labeled.instantiate(bindings).getElementType().hasFieldNames()); - } -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeDeclarationException; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.Type; +import io.usethesource.vallang.type.TypeFactory; +import io.usethesource.vallang.type.TypeStore; + +public final class TypeFactorySmokeTest { + + private static TypeFactory ft = TypeFactory.getInstance(); + + private static Type[] types = new Type[] { ft.integerType(), ft.realType(), ft.sourceLocationType(), ft.valueType(), + ft.listType(ft.integerType()), ft.setType(ft.realType()) }; + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testGetInstance() { + if (TypeFactory.getInstance() != ft) { + fail("getInstance did not return the same reference"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testParametrizedAbstractDatatypeArityInvariant(TypeStore store) { + Type param = ft.parameterType("T"); + Type adt = ft.abstractDataType(store, "Test", ft.tupleType(param)); + Map bindings = new HashMap<>(); + bindings.put(param, ft.voidType()); + Type instant = adt.instantiate(bindings); + + assertTrue(instant.isParameterized()); + assertFalse(instant.getTypeParameters().isBottom()); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testValueType() { + if (ft.valueType() != ft.valueType()) { + fail("valueType should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testIntegerType() { + if (ft.integerType() != ft.integerType()) { + fail("integerType should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testDoubleType() { + if (ft.realType() != ft.realType()) { + fail("doubleType should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testStringType() { + if (ft.stringType() != ft.stringType()) { + fail("stringType should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testSourceLocationType() { + if (ft.sourceLocationType() != ft.sourceLocationType()) { + fail("sourceLocationType should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfType() { + Type t = ft.tupleType(types[0]); + + if (t != ft.tupleType(types[0])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 1); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeType() { + Type t = ft.tupleType(types[0], types[1]); + + if (t != ft.tupleType(types[0], types[1])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 2); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeTypeType() { + Type t = ft.tupleType(types[0], types[1], types[2]); + + if (t != ft.tupleType(types[0], types[1], types[2])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 3); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeTypeTypeType() { + Type t = ft.tupleType(types[0], types[1], types[2], types[3]); + + if (t != ft.tupleType(types[0], types[1], types[2], types[3])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 4); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeTypeTypeTypeType() { + Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4]); + + if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 5); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeTypeTypeTypeTypeType() { + Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5]); + + if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 6); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfTypeTypeTypeTypeTypeTypeType() { + Type t = ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5]); + + if (t != ft.tupleType(types[0], types[1], types[2], types[3], types[4], types[5])) { + fail("tuple types should be canonical"); + } + + checkTupleTypeOf(t, 6); + } + + private void checkTupleTypeOf(Type t, int width) { + + if (t.getArity() != width) { + fail("tuple arity broken"); + } + + for (int i = 0; i < t.getArity(); i++) { + if (t.getFieldType(i) != types[i % types.length]) { + fail("Tuple field type unexpected"); + } + } + } + + private void checkRelationTypeOf(Type t, int width) { + + if (t.getArity() != width) { + fail("relation arity broken"); + } + + for (int i = 0; i < t.getArity(); i++) { + if (t.getFieldType(i) != types[i % types.length]) { + fail("Relation field type unexpected"); + } + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeOfIValueArray(IValueFactory vf) { + // a and b shadow the 'types' field + try { + @SuppressWarnings("deprecation") + IValue[] a = new IValue[] { vf.integer(1), vf.real(1.0), + vf.sourceLocation(new URI("file://bla"), 0, 0, 0, 0, 0, 0) }; + @SuppressWarnings("deprecation") + IValue[] b = new IValue[] { vf.integer(1), vf.real(1.0), + vf.sourceLocation(new URI("file://bla"), 0, 0, 0, 0, 0, 0) }; + Type t = ft.tupleType(a); + + if (t != ft.tupleType(b)) { + fail("tuples should be canonical"); + } + + checkTupleTypeOf(t, 3); + } catch (URISyntaxException e) { + fail(e.toString()); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testSetTypeOf() { + Type type = ft.setType(ft.integerType()); + + if (type != ft.setType(ft.integerType())) { + fail("set should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeType() { + try { + TypeStore store = new TypeStore(); + Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + // note that the declared type of namedType needs to be Type + Type type = ft.relTypeFromTuple(namedType); + + Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + + if (type != ft.relTypeFromTuple(namedType2)) { + fail("relation types should be canonical"); + } + + if (type.getFieldType(0) != ft.integerType() && type.getFieldType(1) != ft.integerType()) { + fail("relation should mimick tuple field types"); + } + } catch (FactTypeUseException e) { + fail("type error for correct relation"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testListRelTypeType() { + try { + TypeStore store = new TypeStore(); + Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + // note that the declared type of namedType needs to be Type + Type type = ft.lrelTypeFromTuple(namedType); + + Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + + if (type != ft.lrelTypeFromTuple(namedType2)) { + fail("list relation types should be canonical"); + } + + if (type.getFieldType(0) != ft.integerType() && type.getFieldType(1) != ft.integerType()) { + fail("list relation should mimick tuple field types"); + } + } catch (FactTypeUseException e) { + fail("type error for correct list relation"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeNamedType() { + try { + TypeStore store = new TypeStore(); + Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + // note that the declared type of namedType needs to be AliasType + Type type = ft.relTypeFromTuple(namedType); + + Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + + if (type != ft.relTypeFromTuple(namedType2)) { + fail("relation types should be canonical"); + } + } catch (FactTypeUseException e) { + fail("type error for correct relation"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testListRelTypeNamedType() { + try { + TypeStore store = new TypeStore(); + Type namedType = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + // note that the declared type of namedType needs to be AliasType + Type type = ft.lrelTypeFromTuple(namedType); + + Type namedType2 = ft.aliasType(store, "myTuple", ft.tupleType(ft.integerType(), ft.integerType())); + + if (type != ft.lrelTypeFromTuple(namedType2)) { + fail("list relation types should be canonical"); + } + } catch (FactTypeUseException e) { + fail("type error for correct list relation"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeTupleType() { + Type tupleType = ft.tupleType(ft.integerType(), ft.integerType()); + // note that the declared type of tupleType needs to be TupleType + Type type = ft.relTypeFromTuple(tupleType); + + Type tupleType2 = ft.tupleType(ft.integerType(), ft.integerType()); + + if (type != ft.relTypeFromTuple(tupleType2)) { + fail("relation types should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testListRelTypeTupleType() { + Type tupleType = ft.tupleType(ft.integerType(), ft.integerType()); + // note that the declared type of tupleType needs to be TupleType + Type type = ft.lrelTypeFromTuple(tupleType); + + Type tupleType2 = ft.tupleType(ft.integerType(), ft.integerType()); + + if (type != ft.lrelTypeFromTuple(tupleType2)) { + fail("list relation types should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfType() { + Type type = ft.relType(types[0]); + + if (type != ft.relType(types[0])) { + fail("relation types should be canonical"); + } + + checkRelationTypeOf(type, 1); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeType() { + Type type = ft.relType(types[0], types[1]); + + if (type != ft.relType(types[0], types[1])) { + fail("relation types should be canonical"); + } + + checkRelationTypeOf(type, 2); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeTypeType() { + Type type = ft.relType(types[0], types[1], types[2]); + + if (type != ft.relType(types[0], types[1], types[2])) { + fail("relation types should be canonical"); + } + + checkRelationTypeOf(type, 3); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeTypeTypeType() { + Type type = ft.relType(types[0], types[1], types[2], types[3]); + + if (type != ft.relType(types[0], types[1], types[2], types[3])) { + fail("relation types should be canonical"); + } + checkRelationTypeOf(type, 4); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeTypeTypeTypeType() { + Type type = ft.relType(types[0], types[1], types[2], types[3], types[4]); + + if (type != ft.relType(types[0], types[1], types[2], types[3], types[4])) { + fail("relation types should be canonical"); + } + checkRelationTypeOf(type, 5); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeTypeTypeTypeTypeType() { + Type type = ft.relType(types[0], types[1], types[2], types[3], types[4], types[5]); + + if (type != ft.relType(types[0], types[1], types[2], types[3], types[4], types[5])) { + fail("relation types should be canonical"); + } + checkRelationTypeOf(type, 6); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testRelTypeOfTypeTypeTypeTypeTypeTypeType() { + Type type = ft.relType(types[0], types[1], types[2], types[3], types[4], types[5]); + + if (type != ft.relType(types[0], types[1], types[2], types[3], types[4], types[5])) { + fail("relation types should be canonical"); + } + checkRelationTypeOf(type, 6); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testNamedType() { + try { + TypeStore ts = new TypeStore(); + Type t1 = ft.aliasType(ts, "myType", ft.integerType()); + Type t2 = ft.aliasType(ts, "myType", ft.integerType()); + + if (t1 != t2) { + fail("named types should be canonical"); + } + + try { + ft.aliasType(ts, "myType", ft.realType()); + fail("Should not be allowed to redeclare a type name"); + } catch (FactTypeDeclarationException e) { + // this should happen + } + } catch (FactTypeDeclarationException e) { + fail("the above should be type correct"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testListType() { + Type t1 = ft.listType(ft.integerType()); + Type t2 = ft.listType(ft.integerType()); + + if (t1 != t2) { + fail("named types should be canonical"); + } + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testFunctionLub(TypeFactory tf) { + Type t1 = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType(), tf.integerType()), tf.tupleEmpty()); + Type t2 = tf.functionType(tf.integerType(), tf.tupleType(tf.rationalType(), tf.rationalType()), + tf.tupleEmpty()); + + // if the arity is the same, the lub is still a function type (for computing the + // types of overloaded functions) + assertTrue(!t1.lub(t2).isTop()); + assertTrue(t1.getArity() == t1.lub(t2).getArity()); + + // but if its not the same, then we default to value, because we don't know how + // to call a function with different amounts of parameters + Type t3 = tf.functionType(tf.integerType(), tf.tupleType(tf.stringType()), tf.tupleEmpty()); + assertTrue(t1.lub(t3).isTop()); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testHigherOrderSelfMatchOfFunctionType(TypeFactory tf) { + Type returnType = tf.parameterType("Ret"); + Type arg1 = tf.parameterType("Arg1"); + Type arg2 = tf.parameterType("Arg2"); + // &Ret curried(&Arg2 arg2) + Type curriedFunction = tf.functionType(returnType, tf.tupleType(arg2), tf.tupleEmpty()); + // &Ret func (&Arg1 arg1, &Arg2 arg2) + Type parameterFunction = tf.functionType(returnType, tf.tupleType(arg1, arg2), tf.tupleEmpty()); + // &Ret (&Arg2) curry (&Return (&Arg1, &Arg2) func, &Arg1 arg1) + Type curry = tf.functionType(curriedFunction, tf.tupleType(parameterFunction, arg1), tf.tupleEmpty()); + + // First we rename the type parameters for the purpose of parameter hygiene: + Map renamings = new HashMap<>(); + curry.match(tf.voidType(), renamings); + + for (Type key : renamings.keySet()) { + renamings.put(key, tf.parameterType(key.getName() + "'")); + } + + Type renamedCurry = curry.instantiate(renamings); + + // now we self apply the curry function with an add function + Type addFunction = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType(), tf.integerType()), + tf.tupleEmpty()); + Type curriedAdd = tf.functionType(tf.integerType(), tf.tupleType(tf.integerType()), tf.tupleEmpty()); + Type curriedCurryReturn = tf.functionType(curriedAdd, tf.tupleType(tf.integerType()), tf.tupleEmpty()); + + // the goal is to arrive at a binding of &Ret to an instantiated int (int) + // curried function, via parameter matching + Type actualParameterTypes = tf.tupleType(renamedCurry, addFunction); + Type formalParameterTypes = curry.getFieldTypes(); + + Map bindings = new HashMap<>(); + + // this is where the bug was/is. + // applying curry(curry, add) should give `int(int arg2) (int arg1)` as a return + // type. + formalParameterTypes.match(actualParameterTypes, bindings); + + // instead we get the uninstantiated version &Ret' (&Arg2') (&Arg1') + assertTrue(curry.getReturnType().instantiate(bindings) == curriedCurryReturn); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testUnificationOfNestedNonLinearTypeParameters(TypeFactory tf, TypeStore store) throws IOException { + Type formals = tf.fromString(store, new StringReader("tuple[lrel[&T0,&T1],set[&T0]]")); + Type actuals = tf.fromString(store, new StringReader("tuple[lrel[int,int],set[void]]")); + Type T0 = tf.parameterType("T0"); + Type T0expected = tf.integerType().lub(tf.voidType()); + + Map bindings = new HashMap<>(); + formals.match(actuals, bindings); + + assertTrue(T0expected == bindings.get(T0)); + } + + @ParameterizedTest + @ArgumentsSource(ValueProvider.class) + public void testTupleTypeMatchAndInstantiateMustPreserveLabels(TypeFactory tf) throws IOException { + Type unlabeled = tf.listType(tf.tupleType(tf.integerType(), tf.integerType())); + Type labeled = tf.listType(tf.tupleType(tf.parameterType("T0"), "first", tf.parameterType("T1"), "second")); + + Map bindings = new HashMap<>(); + labeled.match(unlabeled, bindings); + + assertTrue(labeled.instantiate(bindings).getElementType().hasFieldNames()); + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/ValueFactorySmokeTest.java b/src/test/java/io/usethesource/vallang/basic/ValueFactorySmokeTest.java index f560533f5..736ceee7d 100644 --- a/src/test/java/io/usethesource/vallang/basic/ValueFactorySmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/ValueFactorySmokeTest.java @@ -1,295 +1,294 @@ -/******************************************************************************* -* Copyright (c) 2007 IBM Corporation. -* 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: -* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation - -*******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.stream.Stream; - -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.IList; -import io.usethesource.vallang.IReal; -import io.usethesource.vallang.ISet; -import io.usethesource.vallang.ITuple; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.type.TypeFactory; -import io.usethesource.vallang.type.TypeStore; - -public final class ValueFactorySmokeTest { - private TypeFactory ft = TypeFactory.getInstance(); - - public static class ValueFactoryAndIntegersProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - io.usethesource.vallang.impl.reference.ValueFactory.getInstance(), - io.usethesource.vallang.impl.persistent.ValueFactory.getInstance() - ).map(vf -> { - Stream integers = Stream.iterate(0, i -> i + 1).map(j -> vf.integer(j)).limit(100); - return Arguments.of(vf, integers.toArray(IInteger[]::new)); - }); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRelationNamedType(IValueFactory vf) { - try { - ISet r = vf.set(); - - if (!r.getType().isRelation()) { - fail("relation does not have a relation type"); - } - } catch (FactTypeUseException e) { - fail("type error on the construction of a valid relation: " + e); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRealZeroDotFromString(IValueFactory vf) { - assertTrue(vf.real("0.").equals(vf.real("0"))); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testZeroRealRepresentation(IValueFactory vf) { - IReal real = vf.real("0"); - - assertTrue(real.toString().equals("0.")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRelationTupleType(IValueFactory vf) { - ISet r = vf.set(); - - if (r.size() != 0) { - fail("empty set is not empty"); - } - - if (!r.getType().isSubtypeOf(ft.relTypeFromTuple(ft.tupleType(ft.integerType())))) { - fail("should be a rel of unary int tuples"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testRelationWith(IValueFactory vf) { - ISet[] relations = new ISet[7]; - ITuple[] tuples = new ITuple[7]; - - for (int i = 0; i < 7; i++) { - tuples[i] = vf.tuple(vf.integer(i), vf.real(i)); - } - - try { - relations[0] = vf.set(tuples[0]); - relations[1] = vf.set(tuples[0], tuples[1]); - relations[2] = vf.set(tuples[0], tuples[1], tuples[2]); - relations[3] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3]); - relations[4] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4]); - relations[5] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4], tuples[5]); - relations[6] = - vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4], tuples[5], tuples[6]); - - for (int i = 0; i < 7; i++) { - for (int j = 0; j < i; j++) { - if (!relations[i].contains(tuples[j])) { - fail("tuple creation is weird"); - } - } - } - } catch (FactTypeUseException e) { - System.err.println(e); - fail("this should all be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSetNamedType(IValueFactory vf) { - ISet l; - try { - TypeStore typeStore = new TypeStore(); - l = vf.set(vf.integer(1)); - - if (!l.getType() - .isSubtypeOf(ft.aliasType(typeStore, "mySet", ft.setType(ft.integerType())))) { - fail("named types should be aliases"); - } - - if (!l.getElementType().isSubtypeOf(ft.integerType())) { - fail("elements should be integers"); - } - - if (l.size() != 1) { - fail("??"); - } - } catch (FactTypeUseException e1) { - fail("this was a correct type"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testSetType(IValueFactory vf) { - ISet s = vf.set(); - - if (s.size() != 0) { - fail("empty set is not empty"); - } - - if (!s.getType().isSubtypeOf(ft.setType(ft.realType()))) { - fail("should be a list of reals"); - } - - if (!s.getElementType().isSubtypeOf(ft.realType())) { - fail("should be a list of reals"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) - public void testSetWith(IValueFactory vf, IInteger[] integers) { - ISet[] sets = new ISet[7]; - - sets[0] = vf.set(integers[0]); - sets[1] = vf.set(integers[0], integers[1]); - sets[2] = vf.set(integers[0], integers[1], integers[2]); - sets[3] = vf.set(integers[0], integers[1], integers[2], integers[3]); - sets[4] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4]); - sets[5] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); - sets[6] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5], - integers[6]); - - try { - for (int i = 0; i < 7; i++) { - for (int j = 0; j <= i; j++) { - if (!sets[i].contains(integers[j])) { - fail("set creation is weird"); - } - } - for (int j = 8; j < 100; j++) { - if (sets[i].contains(integers[j])) { - fail("set creation contains weird values"); - } - } - } - } catch (FactTypeUseException e) { - System.err.println(e); - fail("this should all be type correct"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testListNamedType(IValueFactory vf) { - IList l; - try { - TypeStore ts = new TypeStore(); - l = vf.list(vf.integer(1)); - - if (!l.getType().isSubtypeOf(ft.aliasType(ts, "myList", ft.listType(ft.integerType())))) { - fail("named types should be aliases"); - } - - if (!l.getElementType().isSubtypeOf(ft.integerType())) { - fail("elements should be integers"); - } - - if (l.length() != 1) { - fail("???"); - } - } catch (FactTypeUseException e1) { - fail("this was a correct type"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testListType(IValueFactory vf) { - IList l = vf.list(); - - if (l.length() != 0) { - fail("empty list is not empty"); - } - - if (!l.getElementType().isSubtypeOf(ft.realType())) { - fail("should be a list of reals"); - } - } - - @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) - public void testListWith(IValueFactory vf, IInteger[] integers) { - IList[] lists = new IList[7]; - - lists[0] = vf.list(integers[0]); - lists[1] = vf.list(integers[0], integers[1]); - lists[2] = vf.list(integers[0], integers[1], integers[2]); - lists[3] = vf.list(integers[0], integers[1], integers[2], integers[3]); - lists[4] = vf.list(integers[0], integers[1], integers[2], integers[3], integers[4]); - lists[5] = - vf.list(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); - lists[6] = vf.list(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5], - integers[6]); - - for (int i = 0; i < 7; i++) { - for (int j = 0; j <= i; j++) { - if (lists[i].get(j) != integers[j]) { - fail("list creation is weird"); - } - } - } - - } - - @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) - public void testTupleIValue(IValueFactory vf, IInteger[] integers) { - ITuple[] tuples = new ITuple[7]; - - tuples[0] = vf.tuple(integers[0]); - tuples[1] = vf.tuple(integers[0], integers[1]); - tuples[2] = vf.tuple(integers[0], integers[1], integers[2]); - tuples[3] = vf.tuple(integers[0], integers[1], integers[2], integers[3]); - tuples[4] = vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4]); - tuples[5] = - vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); - tuples[6] = vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4], - integers[5], integers[6]); - - for (int i = 0; i < 7; i++) { - for (int j = 0; j <= i; j++) { - if (tuples[i].get(j) != integers[j]) { - fail("tuple creation is weird"); - } - } - } - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testInteger(IValueFactory vf) { - assertTrue(vf.integer(42).toString().equals("42")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testDubble(IValueFactory vf) { - assertTrue(vf.real(84.5).toString().equals("84.5")); - } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testString(IValueFactory vf) { - assertTrue(vf.string("hello").getValue().equals("hello")); - assertTrue(vf.string(0x1F35D).getValue().equals("🍝")); - assertTrue(vf.string(new int[] {0x1F35D, 0x1F35D}).getValue().equals("🍝🍝")); - } -} +/******************************************************************************* +* Copyright (c) 2007 IBM Corporation. +* 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: +* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation + +*******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.IInteger; +import io.usethesource.vallang.IList; +import io.usethesource.vallang.IReal; +import io.usethesource.vallang.ISet; +import io.usethesource.vallang.ITuple; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.type.TypeFactory; +import io.usethesource.vallang.type.TypeStore; + +public final class ValueFactorySmokeTest { + private TypeFactory ft = TypeFactory.getInstance(); + + public static class ValueFactoryAndIntegersProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + io.usethesource.vallang.impl.reference.ValueFactory.getInstance(), + io.usethesource.vallang.impl.persistent.ValueFactory.getInstance() + ).map(vf -> { + Stream integers = Stream.iterate(0, i -> i + 1).map(j -> vf.integer(j)).limit(100); + return Arguments.of(vf, integers.toArray(IInteger[]::new)); + }); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRelationNamedType(IValueFactory vf) { + try { + ISet r = vf.set(); + + if (!r.getType().isRelation()) { + fail("relation does not have a relation type"); + } + } catch (FactTypeUseException e) { + fail("type error on the construction of a valid relation: " + e); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRealZeroDotFromString(IValueFactory vf) { + assertTrue(vf.real("0.").equals(vf.real("0"))); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testZeroRealRepresentation(IValueFactory vf) { + IReal real = vf.real("0"); + + assertTrue(real.toString().equals("0.")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRelationTupleType(IValueFactory vf) { + ISet r = vf.set(); + + if (r.size() != 0) { + fail("empty set is not empty"); + } + + if (!r.getType().isSubtypeOf(ft.relTypeFromTuple(ft.tupleType(ft.integerType())))) { + fail("should be a rel of unary int tuples"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testRelationWith(IValueFactory vf) { + ISet[] relations = new ISet[7]; + ITuple[] tuples = new ITuple[7]; + + for (int i = 0; i < 7; i++) { + tuples[i] = vf.tuple(vf.integer(i), vf.real(i)); + } + + try { + relations[0] = vf.set(tuples[0]); + relations[1] = vf.set(tuples[0], tuples[1]); + relations[2] = vf.set(tuples[0], tuples[1], tuples[2]); + relations[3] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3]); + relations[4] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4]); + relations[5] = vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4], tuples[5]); + relations[6] = + vf.set(tuples[0], tuples[1], tuples[2], tuples[3], tuples[4], tuples[5], tuples[6]); + + for (int i = 0; i < 7; i++) { + for (int j = 0; j < i; j++) { + if (!relations[i].contains(tuples[j])) { + fail("tuple creation is weird"); + } + } + } + } catch (FactTypeUseException e) { + System.err.println(e); + fail("this should all be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSetNamedType(IValueFactory vf) { + ISet l; + try { + TypeStore typeStore = new TypeStore(); + l = vf.set(vf.integer(1)); + + if (!l.getType().isSubtypeOf(ft.aliasType(typeStore, "mySet", ft.setType(ft.integerType())))) { + fail("named types should be aliases"); + } + + if (!l.getElementType().isSubtypeOf(ft.integerType())) { + fail("elements should be integers"); + } + + if (l.size() != 1) { + fail("??"); + } + } catch (FactTypeUseException e1) { + fail("this was a correct type"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSetType(IValueFactory vf) { + ISet s = vf.set(); + + if (s.size() != 0) { + fail("empty set is not empty"); + } + + if (!s.getType().isSubtypeOf(ft.setType(ft.realType()))) { + fail("should be a list of reals"); + } + + if (!s.getElementType().isSubtypeOf(ft.realType())) { + fail("should be a list of reals"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) + public void testSetWith(IValueFactory vf, IInteger[] integers) { + ISet[] sets = new ISet[7]; + + sets[0] = vf.set(integers[0]); + sets[1] = vf.set(integers[0], integers[1]); + sets[2] = vf.set(integers[0], integers[1], integers[2]); + sets[3] = vf.set(integers[0], integers[1], integers[2], integers[3]); + sets[4] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4]); + sets[5] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); + sets[6] = vf.set(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5], + integers[6]); + + try { + for (int i = 0; i < 7; i++) { + for (int j = 0; j <= i; j++) { + if (!sets[i].contains(integers[j])) { + fail("set creation is weird"); + } + } + for (int j = 8; j < 100; j++) { + if (sets[i].contains(integers[j])) { + fail("set creation contains weird values"); + } + } + } + } catch (FactTypeUseException e) { + System.err.println(e); + fail("this should all be type correct"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testListNamedType(IValueFactory vf) { + IList l; + try { + TypeStore ts = new TypeStore(); + l = vf.list(vf.integer(1)); + + if (!l.getType().isSubtypeOf(ft.aliasType(ts, "myList", ft.listType(ft.integerType())))) { + fail("named types should be aliases"); + } + + if (!l.getElementType().isSubtypeOf(ft.integerType())) { + fail("elements should be integers"); + } + + if (l.length() != 1) { + fail("???"); + } + } catch (FactTypeUseException e1) { + fail("this was a correct type"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testListType(IValueFactory vf) { + IList l = vf.list(); + + if (l.length() != 0) { + fail("empty list is not empty"); + } + + if (!l.getElementType().isSubtypeOf(ft.realType())) { + fail("should be a list of reals"); + } + } + + @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) + public void testListWith(IValueFactory vf, IInteger[] integers) { + IList[] lists = new IList[7]; + + lists[0] = vf.list(integers[0]); + lists[1] = vf.list(integers[0], integers[1]); + lists[2] = vf.list(integers[0], integers[1], integers[2]); + lists[3] = vf.list(integers[0], integers[1], integers[2], integers[3]); + lists[4] = vf.list(integers[0], integers[1], integers[2], integers[3], integers[4]); + lists[5] = + vf.list(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); + lists[6] = vf.list(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5], + integers[6]); + + for (int i = 0; i < 7; i++) { + for (int j = 0; j <= i; j++) { + if (lists[i].get(j) != integers[j]) { + fail("list creation is weird"); + } + } + } + + } + + @ParameterizedTest @ArgumentsSource(ValueFactoryAndIntegersProvider.class) + public void testTupleIValue(IValueFactory vf, IInteger[] integers) { + ITuple[] tuples = new ITuple[7]; + + tuples[0] = vf.tuple(integers[0]); + tuples[1] = vf.tuple(integers[0], integers[1]); + tuples[2] = vf.tuple(integers[0], integers[1], integers[2]); + tuples[3] = vf.tuple(integers[0], integers[1], integers[2], integers[3]); + tuples[4] = vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4]); + tuples[5] = + vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4], integers[5]); + tuples[6] = vf.tuple(integers[0], integers[1], integers[2], integers[3], integers[4], + integers[5], integers[6]); + + for (int i = 0; i < 7; i++) { + for (int j = 0; j <= i; j++) { + if (tuples[i].get(j) != integers[j]) { + fail("tuple creation is weird"); + } + } + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testInteger(IValueFactory vf) { + assertTrue(vf.integer(42).toString().equals("42")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testDubble(IValueFactory vf) { + assertTrue(vf.real(84.5).toString().equals("84.5")); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testString(IValueFactory vf) { + assertTrue(vf.string("hello").getValue().equals("hello")); + assertTrue(vf.string(0x1F35D).getValue().equals("🍝")); + assertTrue(vf.string(new int[] {0x1F35D, 0x1F35D}).getValue().equals("🍝🍝")); + } +} diff --git a/src/test/java/io/usethesource/vallang/basic/XMLSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/XMLSmokeTest.java index 75c6537f7..efa154db7 100644 --- a/src/test/java/io/usethesource/vallang/basic/XMLSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/XMLSmokeTest.java @@ -1,54 +1,54 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation. - * 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 Vinju - - *******************************************************************************/ - -package io.usethesource.vallang.basic; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ArgumentsSource; - -import io.usethesource.vallang.ExpectedType; -import io.usethesource.vallang.IConstructor; -import io.usethesource.vallang.IValue; -import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.ValueProvider; -import io.usethesource.vallang.exceptions.UnsupportedTypeException; -import io.usethesource.vallang.io.XMLReader; -import io.usethesource.vallang.io.XMLWriter; -import io.usethesource.vallang.type.TypeStore; - -public class XMLSmokeTest extends BooleanStoreProvider { - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) - @Disabled("XML writer fails on empty strings and empty lists") - public void testXMLWriter(IValueFactory vf, TypeStore ts, @ExpectedType("Boolean") IConstructor val) throws IOException { - StringWriter buffer = new StringWriter(); - XMLWriter testWriter = new XMLWriter(); - XMLReader testReader = new XMLReader(); - - try { - testWriter.write(val, buffer); - IValue result = testReader.read(vf, ts, val.getType(), new StringReader(buffer.toString())); - assertEquals(val, result); - } - catch (UnsupportedTypeException e) { - // this happens because the XML support does not offer serialization of all types - } - } - -} +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation. + * 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 Vinju + + *******************************************************************************/ + +package io.usethesource.vallang.basic; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import io.usethesource.vallang.ExpectedType; +import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.ValueProvider; +import io.usethesource.vallang.exceptions.UnsupportedTypeException; +import io.usethesource.vallang.io.XMLReader; +import io.usethesource.vallang.io.XMLWriter; +import io.usethesource.vallang.type.TypeStore; + +public class XMLSmokeTest extends BooleanStoreProvider { + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + @Disabled("XML writer fails on empty strings and empty lists") + public void testXMLWriter(IValueFactory vf, TypeStore ts, @ExpectedType("Boolean") IConstructor val) throws IOException { + StringWriter buffer = new StringWriter(); + XMLWriter testWriter = new XMLWriter(); + XMLReader testReader = new XMLReader(); + + try { + testWriter.write(val, buffer); + IValue result = testReader.read(vf, ts, val.getType(), new StringReader(buffer.toString())); + assertEquals(val, result); + } + catch (UnsupportedTypeException e) { + // this happens because the XML support does not offer serialization of all types + } + } + +} diff --git a/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java b/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java index c2c8dd600..8bd2a64a6 100644 --- a/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java +++ b/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java @@ -22,7 +22,7 @@ class FileChannelOutputStreamTest { System.err.println(e); } targetFile = file; - } + } private FileChannel openWriteChannel() throws IOException { return FileChannel.open(targetFile, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); @@ -31,7 +31,7 @@ private FileChannel openWriteChannel() throws IOException { private FileChannel openReadChannel() throws IOException { return FileChannel.open(targetFile, StandardOpenOption.READ); } - + @Test void testSimpleWrite() throws IOException { roundTripChannel(new byte[][]{{42}}); @@ -101,5 +101,5 @@ private void writeChannelInBulk(byte[][] buffers) throws IOException { } } } - + } diff --git a/src/test/java/io/usethesource/vallang/io/LinearCircularLookupWindowTest.java b/src/test/java/io/usethesource/vallang/io/LinearCircularLookupWindowTest.java index 2fe0b6674..3826fe7dc 100644 --- a/src/test/java/io/usethesource/vallang/io/LinearCircularLookupWindowTest.java +++ b/src/test/java/io/usethesource/vallang/io/LinearCircularLookupWindowTest.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io; import io.usethesource.vallang.io.binary.util.LinearCircularLookupWindow; diff --git a/src/test/java/io/usethesource/vallang/io/StacklessStructuredVisitorTest.java b/src/test/java/io/usethesource/vallang/io/StacklessStructuredVisitorTest.java index 0d0475429..8de5e1cfc 100644 --- a/src/test/java/io/usethesource/vallang/io/StacklessStructuredVisitorTest.java +++ b/src/test/java/io/usethesource/vallang/io/StacklessStructuredVisitorTest.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -67,7 +67,7 @@ public void nodeWithAnnotations(IValueFactory vf) { public void listWithTwoElements(IValueFactory vf) { testVisitStructure(vf.list(vf.string("a"), vf.list())); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void correctOrderSmallValues(IValueFactory vf) { for (IValue v: RandomValues.getTestValues(vf)) { @@ -81,7 +81,7 @@ public void correctOrderSmallValuesSkipping(IValueFactory vf) { testVisitStructureSkipped(v); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void randomValuesCorrect(IValueFactory vf) { TypeStore ts = new TypeStore(); @@ -101,21 +101,21 @@ public void randomValuesCorrectSkipping(IValueFactory vf) { } } - private static class CollectAll implements StructuredIValueVisitor { - - public List result = new ArrayList<>(); - - @Override - public void enterNamedValues(String[] names, int numberOfNestedValues) { - result.add(Arrays.toString(names)); - result.add(numberOfNestedValues); - } - - @Override - public void leaveNamedValue() { + private static class CollectAll implements StructuredIValueVisitor { + + public List result = new ArrayList<>(); + + @Override + public void enterNamedValues(String[] names, int numberOfNestedValues) { + result.add(Arrays.toString(names)); + result.add(numberOfNestedValues); + } + + @Override + public void leaveNamedValue() { result.add("leave"); - } - + } + @Override public boolean enterConstructor(IConstructor cons, int children) throws RuntimeException { result.add(cons); @@ -233,15 +233,15 @@ public void visitBoolean(IBool boolValue) throws RuntimeException { public void visitDateTime(IDateTime o) throws RuntimeException { result.add(o); } - } - - private static class CollectAllSkipping extends CollectAll { - @Override - public boolean enterList(IList lst, int children) throws RuntimeException { - super.enterList(lst, children); - return false; - } - } + } + + private static class CollectAllSkipping extends CollectAll { + @Override + public boolean enterList(IList lst, int children) throws RuntimeException { + super.enterList(lst, children); + return false; + } + } private void testVisitStructure(IValue val) { CollectAll expected = new CollectAll(); diff --git a/src/test/java/io/usethesource/vallang/io/TrackReadsTestBase.java b/src/test/java/io/usethesource/vallang/io/TrackReadsTestBase.java index 43928c431..5a8589554 100644 --- a/src/test/java/io/usethesource/vallang/io/TrackReadsTestBase.java +++ b/src/test/java/io/usethesource/vallang/io/TrackReadsTestBase.java @@ -40,7 +40,7 @@ public void getPreviousAfterCircleing() { w.read(d); assertSame(c, w.lookBack(1)); } - + @Test public void testLargeReads() { Object[] elements = new Object[10000];; diff --git a/src/test/java/io/usethesource/vallang/io/TrackWritesTestBase.java b/src/test/java/io/usethesource/vallang/io/TrackWritesTestBase.java index 2d4801d99..1e7efd48d 100644 --- a/src/test/java/io/usethesource/vallang/io/TrackWritesTestBase.java +++ b/src/test/java/io/usethesource/vallang/io/TrackWritesTestBase.java @@ -27,7 +27,7 @@ public void canFindOldObject() { w.write(b); assertEquals(1, w.howLongAgo(a)); } - + @Test public void canFindObjectAtEdge() { Object a = new Object(); @@ -56,7 +56,7 @@ public void dropsObject() { assertEquals(1, w.howLongAgo(c)); assertEquals(0, w.howLongAgo(d)); } - + @Test public void dropsMany() { Object a = new Object(); @@ -76,7 +76,7 @@ public void dropsMany() { assertEquals(1, w.howLongAgo(c)); assertEquals(0, w.howLongAgo(d)); } - + @Test public void randomTest() { Object[] elements = new Object[1000];; diff --git a/src/test/java/io/usethesource/vallang/io/ZstdWrappingStreamsTest.java b/src/test/java/io/usethesource/vallang/io/ZstdWrappingStreamsTest.java index 958034d35..ebee9dae3 100644 --- a/src/test/java/io/usethesource/vallang/io/ZstdWrappingStreamsTest.java +++ b/src/test/java/io/usethesource/vallang/io/ZstdWrappingStreamsTest.java @@ -24,7 +24,7 @@ import io.usethesource.vallang.io.binary.util.FileChannelDirectOutputStream; public class ZstdWrappingStreamsTest { - + private static File getTempFile(String name) throws IOException { File result = File.createTempFile(ZstdWrappingStreamsTest.class.getName(), "temp-file-" + name); result.deleteOnExit(); @@ -36,37 +36,37 @@ public void writeSmallFile() throws IOException { try { writeCompressed(temp, getRandomBytes(10)); assertNotEquals(0, Files.size(temp.toPath())); - } + } finally { temp.delete(); } } - + @Test public void writeLargeFile() throws IOException { File temp = getTempFile("large"); try { writeCompressed(temp, getRandomBytes(10_000)); assertNotEquals(0, Files.size(temp.toPath())); - } + } finally { temp.delete(); } } - + @Test public void writeHugeFile() throws IOException { File temp = getTempFile("large"); try { writeCompressed(temp, getRandomBytes(8_000_000)); assertNotEquals(0, Files.size(temp.toPath())); - } + } finally { temp.delete(); } } - + @Test public void roundTripSmallFile() throws IOException { roundTrip(getRandomBytes(10)); @@ -76,12 +76,12 @@ public void roundTripSmallFile() throws IOException { public void roundTripLargeFile() throws IOException { roundTrip(getRandomBytes(10_000)); } - + @Test public void roundTripHugeFile() throws IOException { roundTrip(getRandomBytes(8_000_000)); } - + @Test public void roundTripRandomSizes() throws IOException { Random r = new Random(); @@ -89,15 +89,15 @@ public void roundTripRandomSizes() throws IOException { roundTrip(getRandomBytes(1 + r.nextInt(1_000_000))); } } - + @Test public void roundTripSmallSizes() throws IOException { for (int i = 1; i < 100; i++) { roundTrip(getRandomBytes(i)); } } - - @Test + + @Test public void multiThreadedWrite() throws Throwable { int THREADS = 100; final Collection fails = new ConcurrentLinkedDeque<>(); @@ -111,14 +111,14 @@ public void multiThreadedWrite() throws Throwable { byte[] bytes = getRandomBytes(1 + r.nextInt(255)); startRunning.acquire(); roundTrip(bytes); - } + } catch (Throwable t) { fails.add(t); } finally { doneRunning.release(); } - + }).start(); } startRunning.release(THREADS); @@ -134,20 +134,20 @@ private byte[] getRandomBytes(int size) { r.nextBytes(data); return data; } - + private void roundTrip(byte[] data) throws IOException { File temp = getTempFile("roundtrip"); try { writeCompressed(temp, data); byte[] data2 = readCompressed(temp); assertArrayEquals(data, data2); - + temp.delete(); writeCompressedOneBytePerTime(temp, data); data2 = readCompressed(temp); assertArrayEquals(data, data2); - } + } finally { temp.delete(); } @@ -159,7 +159,7 @@ private void writeCompressedOneBytePerTime(File temp, byte[] data) throws IOExce stream.write(b); } } - + } private void writeCompressed(File temp, byte[] data) throws IOException { try (DelayedZstdOutputStream stream = new DelayedZstdOutputStream(new FileChannelDirectOutputStream(FileChannel.open(temp.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE), 10), 1, 3)) { @@ -167,7 +167,7 @@ private void writeCompressed(File temp, byte[] data) throws IOException { stream.write(data); } } - + private byte[] readCompressed(File temp) throws IOException { try (FileChannelDirectInputStream raw = new FileChannelDirectInputStream(FileChannel.open(temp.toPath(), StandardOpenOption.READ))) { if (raw.read() == 0) { @@ -180,7 +180,7 @@ private byte[] readCompressed(File temp) throws IOException { } } } - + private byte[] getBytes(InputStream raw) throws IOException { ByteBuffer lengthBuffer = ByteBuffer.allocate(4); lengthBuffer.put((byte)raw.read()); diff --git a/src/test/java/io/usethesource/vallang/io/reference/ReferenceStructuredIValueVisitor.java b/src/test/java/io/usethesource/vallang/io/reference/ReferenceStructuredIValueVisitor.java index 6bcb8039f..ce2241397 100644 --- a/src/test/java/io/usethesource/vallang/io/reference/ReferenceStructuredIValueVisitor.java +++ b/src/test/java/io/usethesource/vallang/io/reference/ReferenceStructuredIValueVisitor.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.io.reference; import java.util.AbstractMap; @@ -129,8 +129,8 @@ public Void visitNode(INode o) throws E { visit.enterNodeKeywordParameters(); visitNamedValues(params); } - } - + } + visit.leaveNode(o); } return null; @@ -144,7 +144,7 @@ private void visitNamedValues(Map.Immutable namedValues) throws Entry param = iterator.next(); reverseEntries.add(0, new AbstractMap.SimpleImmutableEntry(param.getKey(), param.getValue())); } - + visit.enterNamedValues(reverseEntries.stream().map(e -> e.getKey()).toArray(i -> new String[i]), namedValues.size()); for (Entry ent: reverseEntries) { ent.getValue().accept(this); @@ -168,8 +168,8 @@ public Void visitConstructor(IConstructor o) throws E { visit.enterConstructorKeywordParameters(); visitNamedValues(params); } - } - + } + visit.leaveConstructor(o); } return null; @@ -197,9 +197,9 @@ public Void visitDateTime(IDateTime o) throws E { visit.visitDateTime(o); return null; } - + }); - + } } diff --git a/src/test/java/io/usethesource/vallang/issues/RegressionTests.java b/src/test/java/io/usethesource/vallang/issues/RegressionTests.java index 19ba0c6cf..d58fc1bdc 100644 --- a/src/test/java/io/usethesource/vallang/issues/RegressionTests.java +++ b/src/test/java/io/usethesource/vallang/issues/RegressionTests.java @@ -28,17 +28,17 @@ public class RegressionTests { @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void iTupleCastExceptionsInEquals(IValueFactory vf, + public void iTupleCastExceptionsInEquals(IValueFactory vf, @GivenValue("{<5,0>,<1330107671,7>,<0,0>}") ISet rel, @GivenValue("{6,-1426731573,0}") ISet set) { - // these calls would throw ClassCastExceptions because the + // these calls would throw ClassCastExceptions because the // receiver or the argument was specialized as a binary relation // and contained tuples, while the other was not. Still a cast to // ITuple was performed. - + // To trigger the bug both sets had to be of equal arity, // to avoid short-circuiting the equality check on that. - + if (!rel.isEmpty() && !set.isEmpty()) { assertTrue(!rel.equals(set)); assertTrue(!set.equals(rel)); @@ -52,24 +52,24 @@ void toStringSourceLocationEqualsTextWriter(IValueFactory vf, ISourceLocation lo writer.write(loc, target); assertEquals(target.toString(), loc.toString()); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) void keywordFieldsMakeConstructorsDifferent(IValueFactory vf, TypeFactory tf, TypeStore store) { - Type X = tf.abstractDataType(store, "X"); - Type cons = tf.constructor(store, X, "x"); - store.declareKeywordParameter(X, "name", tf.stringType()); - - IConstructor cons1 = vf.constructor(cons).asWithKeywordParameters().setParameter("name", vf.string("paul")); - IConstructor cons2 = vf.constructor(cons).asWithKeywordParameters().setParameter("name", vf.string("jurgen")); - - assertFalse(cons1.equals(cons2)); + Type X = tf.abstractDataType(store, "X"); + Type cons = tf.constructor(store, X, "x"); + store.declareKeywordParameter(X, "name", tf.stringType()); + + IConstructor cons1 = vf.constructor(cons).asWithKeywordParameters().setParameter("name", vf.string("paul")); + IConstructor cons2 = vf.constructor(cons).asWithKeywordParameters().setParameter("name", vf.string("jurgen")); + + assertFalse(cons1.equals(cons2)); } - + private IString readString(IValueFactory valueFactory, TypeStore typeStore, String s) throws IOException { Reader reader = new StringReader(s); StandardTextReader textReader = new StandardTextReader(); return (IString) textReader.read(valueFactory, typeStore, TypeFactory.getInstance().stringType(), reader); - + } @ParameterizedTest @ArgumentsSource(ValueProvider.class) diff --git a/src/test/java/io/usethesource/vallang/specification/IMapTests.java b/src/test/java/io/usethesource/vallang/specification/IMapTests.java index b7e20866f..c63c5f6df 100644 --- a/src/test/java/io/usethesource/vallang/specification/IMapTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IMapTests.java @@ -24,17 +24,17 @@ public void canonicalEmptyMap(IValueFactory vf, @ExpectedType("map[value,value]" for (IValue key : m) { m = m.removeKey(key); } - + assertTrue(m.isEmpty()); assertTrue(m.equals(vf.map())); } - - + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void lubInvariant(TypeFactory tf, @ExpectedType("map[value,value]") IMap m) { Type keyLub = tf.voidType(); Type valueLub = tf.voidType(); - + for (Entry entry : (Iterable>) () -> m.entryIterator()) { keyLub = keyLub.lub(entry.getKey().getType()); valueLub = valueLub.lub(entry.getValue().getType()); @@ -42,7 +42,7 @@ public void lubInvariant(TypeFactory tf, @ExpectedType("map[value,value]") IMap assertEquals(tf.mapType(keyLub, valueLub), m.getType()); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void lubInvariantAfterRemoveKey(TypeFactory tf, @ExpectedType("map[int,int]") IMap m) { for (IValue key : m) { @@ -50,12 +50,12 @@ public void lubInvariantAfterRemoveKey(TypeFactory tf, @ExpectedType("map[int,in lubInvariant(tf, m); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsKey(@ExpectedType("map[value,value]") IMap m, IValue key1, IValue key2) { IValue value = key1; IMap m2 = m.put(key1, value); - + if (key1.equals(key2)) { assertEquals(m2.get(key2), value); } @@ -66,12 +66,12 @@ else if (!m.containsKey(key2)) { assertEquals(m2.size(), m2.put(key2, value).size()); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsKeyLocs(@ExpectedType("map[loc,loc]") IMap m, ISourceLocation key1, ISourceLocation key2) { IValue value = key1; IMap m2 = m.put(key1, value); - + if (key1.equals(key2)) { assertEquals(m2.get(key2), value); } @@ -83,7 +83,7 @@ else if (!m.containsKey(key2)) { } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void lubInvariantAfterRemoveKeyLoc(TypeFactory tf, @ExpectedType("map[loc,loc]") IMap m) { for (IValue key : m) { @@ -91,17 +91,17 @@ public void lubInvariantAfterRemoveKeyLoc(TypeFactory tf, @ExpectedType("map[loc lubInvariant(tf, m); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void mapIsVoidAfterAllRemoved(TypeFactory tf, IMap m) { IMap copy = m; for (IValue key : m) { copy = copy.removeKey(key); } - + // this failed due to issue #55 but only if the random generator // accidentally adds two of the same key/value pairs to the map assertTrue(copy.getKeyType() == tf.voidType()); assertTrue(copy.getValueType() == tf.voidType()); } - } +} diff --git a/src/test/java/io/usethesource/vallang/specification/INumberTests.java b/src/test/java/io/usethesource/vallang/specification/INumberTests.java index 014109ad2..509556d59 100644 --- a/src/test/java/io/usethesource/vallang/specification/INumberTests.java +++ b/src/test/java/io/usethesource/vallang/specification/INumberTests.java @@ -20,7 +20,7 @@ public class INumberTests { protected static final int PRECISION = 100; - + IInteger INT_ONE(IValueFactory vf) { return vf.integer(1); } @@ -44,27 +44,27 @@ IReal REAL_ONE(IValueFactory vf) { IReal REAL_ZERO(IValueFactory vf) { return vf.real(0.0); } - + /** For approximate equality of reals a ~= b: - * this is the max allowable ratio of (a-b) to max(a,b) - */ + * this is the max allowable ratio of (a-b) to max(a,b) + */ IReal MAX_ERROR_RATIO(IValueFactory vf) { - return vf.real(1e-15); + return vf.real(1e-15); } - + double DOUBLE_MAX_ERROR_RATIO() { return 1e-10; } - + // this is the max allowed difference between a and b IReal EPSILON(IValueFactory vf) { return vf.real(1e-10); } - + double DOUBLE_EPSILON() { return 1e-10; } - + protected void assertEqual(IValue l, IValue r) { Assertions.assertTrue(l.equals(r), "Expected " + l + " got " + r); } @@ -82,11 +82,11 @@ protected void assertEqualNumber(String message, INumber l, INumber r) { } /** - * Test that the difference between two reals is insignificant. - */ + * Test that the difference between two reals is insignificant. + */ protected void assertApprox(IValueFactory vf, IReal l, IReal r) { Assertions.assertTrue(approxEqual(vf, l, r), "Expected ~" + l + " got " + r + " (diff magnitude " - + ((IReal) l.subtract(r).abs()).scale() + ")"); + + ((IReal) l.subtract(r).abs()).scale() + ")"); } protected void assertApprox(double l, double r) { @@ -95,7 +95,7 @@ protected void assertApprox(double l, double r) { protected void assertApprox(String message, IValueFactory vf, IReal l, IReal r) { Assertions.assertTrue(approxEqual(vf, l, r), message + ": Expected ~" + l + " got " + r + " (diff magnitude " - + ((IReal) l.subtract(r).abs()).scale() + ")"); + + ((IReal) l.subtract(r).abs()).scale() + ")"); } protected void assertApprox(String message, double l, double r) { @@ -103,8 +103,8 @@ protected void assertApprox(String message, double l, double r) { } /** - * @return true if the two arguments are approximately equal - */ + * @return true if the two arguments are approximately equal + */ protected boolean approxEqual(IValueFactory vf, IReal l, IReal r) { if (l.equals(r)) return true; // really equal @@ -126,8 +126,8 @@ protected boolean approxEqual(IValueFactory vf, IReal l, IReal r) { } /** - * @return true if the two arguments are approximately equal - */ + * @return true if the two arguments are approximately equal + */ protected boolean approxEqual(double l, double r) { if (l == r) return true; // really equal @@ -153,245 +153,245 @@ protected void assertEqual(Type l, Type r) { public void divByZero(IValueFactory vf, INumber a) { Assertions.assertThrows(ArithmeticException.class, () -> a.divide(vf.integer(0), 10)); } - + /** - * Relationship between compare() and the comparison functions, and between the various - * comparisons. - */ + * Relationship between compare() and the comparison functions, and between the various + * comparisons. + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testCompare(INumber a, INumber b) { - int cmp = a.compare(b); - assertEquals(cmp == 0, b.compare(a) == 0); // negating and comparing directly isn't safe - assertEquals(cmp < 0, b.compare(a) > 0); - assertEquals(cmp > 0, b.compare(a) < 0); - assertEquals(cmp < 0, a.less(b).getValue()); - assertEquals(cmp > 0, a.greater(b).getValue()); - assertEquals(cmp == 0, a.equal(b).getValue()); - assertEquals(cmp <= 0, a.less(b).getValue() || a.equal(b).getValue()); - assertEquals(cmp >= 0, a.greater(b).getValue() || a.equal(b).getValue()); - - assertEquals(a.less(b), b.greater(a)); - assertEquals(a.greaterEqual(b), b.lessEqual(a)); - assertEquals(a.lessEqual(b).getValue(), a.less(b).getValue() || a.equal(b).getValue()); - assertEquals(a.greaterEqual(b).getValue(), a.greater(b).getValue() || a.equal(b).getValue()); - - assertEquals(a.less(b).getValue() || a.greater(b).getValue(), !a.equal(b).getValue()); - assertEquals(a.equal(b).getValue(), b.equal(a).getValue()); - assertTrue(a.equal(a).getValue()); - - if (a.equals(b) && a.getType() == b.getType()) { - assertEquals( a.hashCode(), b.hashCode(), "" + a + ".hashCode() != " + b + ".hashCode()"); - - if (!(a instanceof IReal || b instanceof IReal) && a.getType().equivalent(b.getType())) { - assertEquals(a.toString(), b.toString(), "" + a + ".toString() != " + b + ".toString()"); + int cmp = a.compare(b); + assertEquals(cmp == 0, b.compare(a) == 0); // negating and comparing directly isn't safe + assertEquals(cmp < 0, b.compare(a) > 0); + assertEquals(cmp > 0, b.compare(a) < 0); + assertEquals(cmp < 0, a.less(b).getValue()); + assertEquals(cmp > 0, a.greater(b).getValue()); + assertEquals(cmp == 0, a.equal(b).getValue()); + assertEquals(cmp <= 0, a.less(b).getValue() || a.equal(b).getValue()); + assertEquals(cmp >= 0, a.greater(b).getValue() || a.equal(b).getValue()); + + assertEquals(a.less(b), b.greater(a)); + assertEquals(a.greaterEqual(b), b.lessEqual(a)); + assertEquals(a.lessEqual(b).getValue(), a.less(b).getValue() || a.equal(b).getValue()); + assertEquals(a.greaterEqual(b).getValue(), a.greater(b).getValue() || a.equal(b).getValue()); + + assertEquals(a.less(b).getValue() || a.greater(b).getValue(), !a.equal(b).getValue()); + assertEquals(a.equal(b).getValue(), b.equal(a).getValue()); + assertTrue(a.equal(a).getValue()); + + if (a.equals(b) && a.getType() == b.getType()) { + assertEquals( a.hashCode(), b.hashCode(), "" + a + ".hashCode() != " + b + ".hashCode()"); + + if (!(a instanceof IReal || b instanceof IReal) && a.getType().equivalent(b.getType())) { + assertEquals(a.toString(), b.toString(), "" + a + ".toString() != " + b + ".toString()"); + } } - } - if (a.getType().equivalent(b.getType())) { - INumber c = b.abs(); - // add/subtract a non-negative number gives a greater/smaller or equal result - Assertions.assertTrue(a.add(c).greaterEqual(a).getValue(), "" + a + " + " + c + " >= " + a); - Assertions.assertTrue(a.add(c.negate()).lessEqual(a).getValue(), "" + a + " + -" + c + " >= " + a); - } + if (a.getType().equivalent(b.getType())) { + INumber c = b.abs(); + // add/subtract a non-negative number gives a greater/smaller or equal result + Assertions.assertTrue(a.add(c).greaterEqual(a).getValue(), "" + a + " + " + c + " >= " + a); + Assertions.assertTrue(a.add(c.negate()).lessEqual(a).getValue(), "" + a + " + -" + c + " >= " + a); + } } /** - * Closure: These operations should yield a result of the same type. - */ + * Closure: These operations should yield a result of the same type. + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testClosure(INumber a, INumber b) { - if (a.signum() == 0 && b.signum() == 0) - a.signum(); - if (a.getType().equivalent(b.getType())) { - assertEqual(a.getType(), a.add(b).getType()); - assertEqual(a.getType(), a.multiply(b).getType()); - assertEqual(a.getType(), a.subtract(b).getType()); - assertEqual(a.getType(), a.abs().getType()); - assertEqual(a.getType(), a.negate().getType()); - } + if (a.signum() == 0 && b.signum() == 0) + a.signum(); + if (a.getType().equivalent(b.getType())) { + assertEqual(a.getType(), a.add(b).getType()); + assertEqual(a.getType(), a.multiply(b).getType()); + assertEqual(a.getType(), a.subtract(b).getType()); + assertEqual(a.getType(), a.abs().getType()); + assertEqual(a.getType(), a.negate().getType()); + } } /** - * Associativity: addition and multiplication - * - * (Possibly not strictly true for reals.) - */ + * Associativity: addition and multiplication + * + * (Possibly not strictly true for reals.) + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testAssociativity(INumber a, INumber b, INumber c) { - if (!(a instanceof IReal || b instanceof IReal || c instanceof IReal)) { - assertEqualNumber(a.add(b.add(c)), a.add(b).add(c)); - assertEqualNumber(a.multiply(b.multiply(c)), a.multiply(b).multiply(c)); - } + if (!(a instanceof IReal || b instanceof IReal || c instanceof IReal)) { + assertEqualNumber(a.add(b.add(c)), a.add(b).add(c)); + assertEqualNumber(a.multiply(b.multiply(c)), a.multiply(b).multiply(c)); + } } /** - * Commutativity: addition and multiplication - */ + * Commutativity: addition and multiplication + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testCommutativity(INumber a, INumber b) { - assertEqualNumber(a.toString() + " + " + b.toString(), a.add(b), b.add(a)); - assertEqualNumber(a.toString() + " * " + b.toString(), a.multiply(b), b.multiply(a)); + assertEqualNumber(a.toString() + " + " + b.toString(), a.add(b), b.add(a)); + assertEqualNumber(a.toString() + " * " + b.toString(), a.multiply(b), b.multiply(a)); } /** - * 0 or 1 are identities for all the binary ops - */ + * 0 or 1 are identities for all the binary ops + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testIdentity(IValueFactory vf, INumber a) { - assertEqualNumber(a, a.add(INT_ZERO(vf))); - assertEqualNumber(a, a.multiply(INT_ONE(vf))); - assertEqualNumber(a, a.subtract(INT_ZERO(vf))); - if (a instanceof IInteger) - assertEqualNumber(a, ((IInteger) a).divide(INT_ONE(vf))); - if (a instanceof IRational) - assertEqualNumber(a, ((IRational) a).divide(RAT_ONE(vf))); - if (a instanceof IReal) - assertEqualNumber(a, ((IReal) a).divide(REAL_ONE(vf), ((IReal) a).precision())); + assertEqualNumber(a, a.add(INT_ZERO(vf))); + assertEqualNumber(a, a.multiply(INT_ONE(vf))); + assertEqualNumber(a, a.subtract(INT_ZERO(vf))); + if (a instanceof IInteger) + assertEqualNumber(a, ((IInteger) a).divide(INT_ONE(vf))); + if (a instanceof IRational) + assertEqualNumber(a, ((IRational) a).divide(RAT_ONE(vf))); + if (a instanceof IReal) + assertEqualNumber(a, ((IReal) a).divide(REAL_ONE(vf), ((IReal) a).precision())); } /** - * Subtraction is inverse of addition. Division is inverse of non-integer multiplication. - */ + * Subtraction is inverse of addition. Division is inverse of non-integer multiplication. + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testInverse(IValueFactory vf, INumber a) { - if (a instanceof IInteger) { - IInteger i = (IInteger) a; - assertEqualNumber(INT_ZERO(vf), i.add(i.negate())); - assertEqualNumber(INT_ZERO(vf), i.subtract(i)); - if (i.signum() != 0) { - assertEqualNumber(INT_ONE(vf), i.divide(i)); + if (a instanceof IInteger) { + IInteger i = (IInteger) a; + assertEqualNumber(INT_ZERO(vf), i.add(i.negate())); + assertEqualNumber(INT_ZERO(vf), i.subtract(i)); + if (i.signum() != 0) { + assertEqualNumber(INT_ONE(vf), i.divide(i)); + } } - } - if (a instanceof IRational) { - IRational r = (IRational) a; - assertEqualNumber(RAT_ZERO(vf), r.add(r.negate())); - assertEqualNumber(RAT_ZERO(vf), r.subtract(r)); - if (r.signum() != 0) { - assertEqualNumber(RAT_ONE(vf), r.divide(r)); - assertEqualNumber(RAT_ONE(vf), r.multiply(RAT_ONE(vf).divide(r))); + if (a instanceof IRational) { + IRational r = (IRational) a; + assertEqualNumber(RAT_ZERO(vf), r.add(r.negate())); + assertEqualNumber(RAT_ZERO(vf), r.subtract(r)); + if (r.signum() != 0) { + assertEqualNumber(RAT_ONE(vf), r.divide(r)); + assertEqualNumber(RAT_ONE(vf), r.multiply(RAT_ONE(vf).divide(r))); + } } - } - if (a instanceof IReal) { - IReal r = (IReal) a; - // this should hold: - assertEqualNumber(REAL_ZERO(vf), r.add(r.negate())); - // this one only approximately - try { - assertApprox(vf, REAL_ONE(vf), r.divide(r, 80)); - assertApprox(vf, REAL_ONE(vf), r.multiply(REAL_ONE(vf).divide(r, 80))); - } catch (ArithmeticException e) { - // ignore division by zero + if (a instanceof IReal) { + IReal r = (IReal) a; + // this should hold: + assertEqualNumber(REAL_ZERO(vf), r.add(r.negate())); + // this one only approximately + try { + assertApprox(vf, REAL_ONE(vf), r.divide(r, 80)); + assertApprox(vf, REAL_ONE(vf), r.multiply(REAL_ONE(vf).divide(r, 80))); + } catch (ArithmeticException e) { + // ignore division by zero + } } - } } /** - * Multiplication distributes over addition. - * - * (Possibly not strictly true for reals.) - */ + * Multiplication distributes over addition. + * + * (Possibly not strictly true for reals.) + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testDistributivity(INumber a, INumber b, INumber c) { - if (!(a instanceof IReal || b instanceof IReal || c instanceof IReal)) { - assertEqualNumber(String.format("a=%s, b=%s, c=%s", a.toString(), b.toString(), c.toString()), - a.multiply(b.add(c)), a.multiply(b).add(a.multiply(c))); - } else { - // assertApprox(String.format("a=%s, b=%s, c=%s", a.toString(), b.toString(), c.toString()), - // a.multiply(b.add(c)).toReal(), a.multiply(b).add(a.multiply(c)).toReal()); - } + if (!(a instanceof IReal || b instanceof IReal || c instanceof IReal)) { + assertEqualNumber(String.format("a=%s, b=%s, c=%s", a.toString(), b.toString(), c.toString()), + a.multiply(b.add(c)), a.multiply(b).add(a.multiply(c))); + } else { + // assertApprox(String.format("a=%s, b=%s, c=%s", a.toString(), b.toString(), c.toString()), + // a.multiply(b.add(c)).toReal(), a.multiply(b).add(a.multiply(c)).toReal()); + } } /** - * This may not be strictly true for reals. - */ + * This may not be strictly true for reals. + */ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testTransitivity(INumber a, INumber b, INumber c) { - if (a.equal(b).getValue() && b.equal(c).getValue()) - Assertions.assertTrue(a.equal(c).getValue(), "" + a + " == " + b + " == " + c); - if (a.lessEqual(b).getValue() && b.lessEqual(c).getValue()) - Assertions.assertTrue(a.lessEqual(c).getValue(), "" + a + " <= " + b + " <= " + c); + if (a.equal(b).getValue() && b.equal(c).getValue()) + Assertions.assertTrue(a.equal(c).getValue(), "" + a + " == " + b + " == " + c); + if (a.lessEqual(b).getValue() && b.lessEqual(c).getValue()) + Assertions.assertTrue(a.lessEqual(c).getValue(), "" + a + " <= " + b + " <= " + c); } @SuppressWarnings("unlikely-arg-type") @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testNoEqualInt(IInteger i) { - assertFalse(i.toReal(PRECISION).equals(i)); - assertTrue(i.toReal(PRECISION).equal(i).getValue()); - assertFalse(i.toRational().equals(i)); - assertTrue(i.toRational().equal(i).getValue()); + assertFalse(i.toReal(PRECISION).equals(i)); + assertTrue(i.toReal(PRECISION).equal(i).getValue()); + assertFalse(i.toRational().equals(i)); + assertTrue(i.toRational().equal(i).getValue()); } @SuppressWarnings("unlikely-arg-type") @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testNoEqualRat(IRational i) { - assertFalse(i.toReal(PRECISION).equals(i)); - assertTrue(i.toReal(PRECISION).equal(i).getValue()); - assertFalse(i.toInteger().equals(i)); + assertFalse(i.toReal(PRECISION).equals(i)); + assertTrue(i.toReal(PRECISION).equal(i).getValue()); + assertFalse(i.toInteger().equals(i)); } @SuppressWarnings("unlikely-arg-type") @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testNoEqualReal(IReal i) { - assertFalse(i.toInteger().equals(i)); + assertFalse(i.toInteger().equals(i)); } /** - * Check that behavour of add/subtract/multiply/divide of integers is approximately the same as - * for reals - **/ + * Check that behavour of add/subtract/multiply/divide of integers is approximately the same as + * for reals + **/ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRationalBehavior(IValueFactory vf, IRational a, IRational b) { - assertEqualNumber(a, a.add(b).subtract(b)); - assertEqualNumber(a, a.subtract(b).add(b)); - if (b.signum() != 0) { - assertEqualNumber(a, a.divide(b).multiply(b)); - assertEqualNumber(a, a.multiply(b).divide(b)); - } - assertEqualNumber(a, a.negate().negate()); - assertEqualNumber(a, a.abs().multiply(vf.integer(a.signum()))); - assertEqualNumber(a, a.numerator().toRational().divide(a.denominator().toRational())); - - assertApprox(a.doubleValue() + b.doubleValue(), a.add(b).doubleValue()); - assertApprox(a.doubleValue() - b.doubleValue(), a.subtract(b).doubleValue()); - assertApprox(a.doubleValue() * b.doubleValue(), a.multiply(b).doubleValue()); - try { - assertApprox(a.doubleValue() / b.doubleValue(), a.divide(b).doubleValue()); - } catch (ArithmeticException e) { - } + assertEqualNumber(a, a.add(b).subtract(b)); + assertEqualNumber(a, a.subtract(b).add(b)); + if (b.signum() != 0) { + assertEqualNumber(a, a.divide(b).multiply(b)); + assertEqualNumber(a, a.multiply(b).divide(b)); + } + assertEqualNumber(a, a.negate().negate()); + assertEqualNumber(a, a.abs().multiply(vf.integer(a.signum()))); + assertEqualNumber(a, a.numerator().toRational().divide(a.denominator().toRational())); + + assertApprox(a.doubleValue() + b.doubleValue(), a.add(b).doubleValue()); + assertApprox(a.doubleValue() - b.doubleValue(), a.subtract(b).doubleValue()); + assertApprox(a.doubleValue() * b.doubleValue(), a.multiply(b).doubleValue()); + try { + assertApprox(a.doubleValue() / b.doubleValue(), a.divide(b).doubleValue()); + } catch (ArithmeticException e) { + } } /** - * Check various behaviour + Check that behavour of add/subtract/multiply of rationals is the same - * as that for reals and rationals. - **/ + * Check various behaviour + Check that behavour of add/subtract/multiply of rationals is the same + * as that for reals and rationals. + **/ @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testIntegerBehavior(IValueFactory vf, IInteger a, IInteger b) { - assertEqualNumber(a, a.add(b).subtract(b)); - assertEqualNumber(a, a.subtract(b).add(b)); - if (b.signum() != 0) { - assertEqualNumber(a, a.divide(b).multiply(b).add(a.remainder(b))); - assertEqualNumber(a, a.multiply(b).divide(b)); - } - assertEqualNumber(a, a.negate().negate()); - assertEqualNumber(a, a.abs().multiply(vf.integer(a.signum()))); - if (b.signum() != 0) - assertTrue(a.mod(b.abs()).less(b.abs()).getValue()); - - // check vs. rational - assertEqualNumber(a.toRational().add(b.toRational()).toInteger(), a.add(b)); - assertEqualNumber(a.toRational().subtract(b.toRational()).toInteger(), a.subtract(b)); - assertEqualNumber(a.toRational().multiply(b.toRational()).toInteger(), a.multiply(b)); + assertEqualNumber(a, a.add(b).subtract(b)); + assertEqualNumber(a, a.subtract(b).add(b)); + if (b.signum() != 0) { + assertEqualNumber(a, a.divide(b).multiply(b).add(a.remainder(b))); + assertEqualNumber(a, a.multiply(b).divide(b)); + } + assertEqualNumber(a, a.negate().negate()); + assertEqualNumber(a, a.abs().multiply(vf.integer(a.signum()))); + if (b.signum() != 0) + assertTrue(a.mod(b.abs()).less(b.abs()).getValue()); + + // check vs. rational + assertEqualNumber(a.toRational().add(b.toRational()).toInteger(), a.add(b)); + assertEqualNumber(a.toRational().subtract(b.toRational()).toInteger(), a.subtract(b)); + assertEqualNumber(a.toRational().multiply(b.toRational()).toInteger(), a.multiply(b)); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRealBehavior(IValueFactory vf, IReal a, IReal b) { - assertApprox(vf, a, a.add(b).subtract(b)); - assertApprox(vf, a, a.subtract(b).add(b)); - try { - assertApprox(vf, a, a.divide(b, PRECISION).multiply(b)); - assertApprox(vf, a, a.multiply(b).divide(b, PRECISION)); - } catch (ArithmeticException e) { - } - assertEqualNumber(a, a.negate().negate()); + assertApprox(vf, a, a.add(b).subtract(b)); + assertApprox(vf, a, a.subtract(b).add(b)); + try { + assertApprox(vf, a, a.divide(b, PRECISION).multiply(b)); + assertApprox(vf, a, a.multiply(b).divide(b, PRECISION)); + } catch (ArithmeticException e) { + } + assertEqualNumber(a, a.negate().negate()); } } diff --git a/src/test/java/io/usethesource/vallang/specification/IRelationTests.java b/src/test/java/io/usethesource/vallang/specification/IRelationTests.java index c15e3b3ea..5812e108b 100644 --- a/src/test/java/io/usethesource/vallang/specification/IRelationTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IRelationTests.java @@ -26,36 +26,36 @@ public class IRelationTests { public void listRelationProjectOrder(IValueFactory vf, @ExpectedType("lrel[int,int]") IList l) { Iterator original = l.iterator(); Iterator projected = l.asRelation().project(1,0).iterator(); - + while (original.hasNext()) { if (!projected.hasNext()) { fail("projected list should be equal length"); } - + ITuple one = (ITuple) original.next(); ITuple two = (ITuple) projected.next(); - + assertEquals(one.select(1,0), two, "elements should appear in original order"); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void transReflexiveClosure( - @GivenValue("{<1,2>, <2,3>, <3,4>}") ISet src, + @GivenValue("{<1,2>, <2,3>, <3,4>}") ISet src, @GivenValue("{<1,2>, <2,3>, <3,4>, <1, 3>, <2, 4>, <1, 4>, <1, 1>, <2, 2>, <3, 3>, <4, 4>}") ISet result) { assertEquals(src.asRelation().closureStar(), result); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void transClosure(@ExpectedType("rel[int,int]") ISet src) { assertEquals(src.asRelation().closure().intersect(src), src); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void transClosureLocs(@ExpectedType("rel[loc,loc]") ISet src) { assertEquals(src.asRelation().closure().intersect(src), src); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void deepClosure(IValueFactory vf) { IValue prev = vf.integer(0); @@ -124,34 +124,34 @@ private ISet slowClosure(IValueFactory vf, IRelation r) { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void carrierForTriples(@ExpectedType("rel[int,int,int]") ISet src) { ISet carrier = src.asRelation().carrier(); - + for (int i = 0; i < 3; i++) { ISet column = src.asRelation().project(i); assertTrue(column.isSubsetOf(carrier)); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsKeyLocs(IValueFactory vf, @ExpectedType("rel[loc,loc]") ISet m, ISourceLocation key1, ISourceLocation key2) { IValue value = key1; ITuple key1Tuple = vf.tuple(key1, value); ISet m2 = m.insert(key1Tuple); - + if (key1.equals(key2)) { assertTrue(m2.asRelation().index(key2).contains(value)); } else { ITuple key2Tuple = vf.tuple(key2, value); - + if (!m.asRelation().domain().contains(key2)) { assertEquals(m2.size() + 1, m2.insert(key2Tuple).size()); } } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsKeyLocFailure(IValueFactory vf, @GivenValue("{<|CwRj:///28030|,|KYs:///xr197/75|>,<|R:///|,|IkdM:///35/IR/72852/SYGC/C17|>,<|IhL:///dim/74/8b/65/xQgoC/0Rm#1|,|Q://45511U|>,<|Joq:///df/hh|,|dr:///u97|>}") ISet m, @GivenValue("|oWxyV:///29/956|") ISourceLocation key1, @GivenValue("|R:///|") ISourceLocation key2) { - equalsIsKeyLocs(vf, m, key1, key2); + equalsIsKeyLocs(vf, m, key1, key2); } } diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index 7f25da238..43e86f0c6 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -33,22 +33,22 @@ import io.usethesource.vallang.type.TypeStore; public class IValueTests { - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsReflexive(IValue val) { assertEquals(val, val); } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsCommutative(IValue val1, IValue val2) { assertTrue(!val1.equals(val2) || val2.equals(val1)); } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void equalsIsTransitive(IValue val1, IValue val2, IValue val3) { assertTrue(!(val1.equals(val2) && val2.equals(val3)) || val1.equals(val3)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testHashCodeContract(IValue val1, IValue val2) { if (val1.equals(val2)) { @@ -56,7 +56,7 @@ public void testHashCodeContract(IValue val1, IValue val2) { } assertTrue(!val1.equals(val2) || val1.hashCode() == val2.hashCode()); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintContract(IValue val1, IValue val2) { @@ -82,9 +82,9 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, // copied the implementation of IntegerValue.hashCode here // because this is now officially a contract. int hash = integer.intValue() ^ 0x85ebca6b; - hash ^= hash >>> 13; - hash *= 0x5bd1e995; - hash ^= hash >>> 15; + hash ^= hash >>> 13; + hash *= 0x5bd1e995; + hash ^= hash >>> 15; assertEquals(hash, integer.getMatchFingerprint()); } @@ -92,7 +92,7 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityStringDoNotChangeTheTest(IString string) { - assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); + assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); // we copied the generic hashCode implementation here, to check the contract. int h = 0; @@ -119,7 +119,7 @@ public void testFingerprintStabilityRealDoNotChangeTheTest(IReal real) { assertEquals(real.hashCode() == 0 ? "real".hashCode() : real.hashCode(), real.getMatchFingerprint()); } - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityRationalDoNotChangeTheTest(IRational rational) { assertEquals(rational.hashCode(), rational.getMatchFingerprint()); } @@ -156,7 +156,7 @@ public void testFingerprintAllMapsTheSameDoNotChangeTheTest(IMap map1, IMap map2 @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityTupleDoNotChangeTheTest(ITuple tuple) { - assertEquals("tuple".hashCode() + tuple.arity(), tuple.getMatchFingerprint()); + assertEquals("tuple".hashCode() + tuple.arity(), tuple.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -167,15 +167,15 @@ public void testFingerprintEqualArityTuplesTheSameDoNotChangeTheTest(ITuple tupl } @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) { - assertEquals(node.hashCode(), node.getMatchFingerprint()); + public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) { + assertEquals(node.hashCode(), node.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { - assertEquals(node.getName().hashCode() == 0 - ? "node".hashCode() + 131 * node.arity() - : node.getName().hashCode() + 131 * node.arity(), node.getMatchFingerprint()); + public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { + assertEquals(node.getName().hashCode() == 0 + ? "node".hashCode() + 131 * node.arity() + : node.getName().hashCode() + 131 * node.arity(), node.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -186,7 +186,7 @@ public void testFingerprintEqualArityNodesTheSameDoNotChangeTheTest(INode node1, } @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testFingerprintStabilityNodesMatchConstructorsDoNotChangeTheTest(IValueFactory vf, IConstructor constructor) { + public void testFingerprintStabilityNodesMatchConstructorsDoNotChangeTheTest(IValueFactory vf, IConstructor constructor) { assertEquals( constructor.getMatchFingerprint(), vf.node(constructor.getName(), StreamSupport.stream(constructor.getChildren().spliterator(), false).toArray(IValue[]::new)).getMatchFingerprint() @@ -195,7 +195,7 @@ public void testFingerprintStabilityNodesMatchConstructorsDoNotChangeTheTest(IVa @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityConstructorDoNotChangeTheTest(IConstructor constructor) { - assertEquals(constructor.getName().hashCode() + 131 * constructor.arity(), constructor.getMatchFingerprint()); + assertEquals(constructor.getName().hashCode() + 131 * constructor.arity(), constructor.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -205,15 +205,15 @@ public void testFingerprintEqualArityConstructorsTheSameDoNotChangeTheTest(ICons } } - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testWysiwyg(IValueFactory vf, TypeStore store, IValue val) throws FactTypeUseException, IOException { StandardTextReader reader = new StandardTextReader(); String string = val.toString(); IValue result = reader.read(vf, store, val.getType(), new StringReader(string)); assertEquals(val, result, "reading back " + val + " produced something different"); } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testWysiwygConstructors(IValueFactory vf, TypeStore store, IConstructor val) throws FactTypeUseException, IOException { // constructors go wrong more often, this test makes sure we generate more random examples. testWysiwyg(vf, store, val); @@ -225,17 +225,17 @@ public void testIsomorphicText(IValue val1, IValue val2) throws FactTypeUseExcep if (val1.equals(val2)) { assertEquals(val1.toString(), val2.toString(), val1.toString() + " and " + val2.toString() + " should look the same because they are equal."); } - + if (val1.toString().equals(val2.toString())) { assertEquals(val1, val2, val1.toString() + " and " + val2.toString() + "should be equal because they look the same."); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testToStringIsStandardardTextWriter(IValueFactory vf, IValue val) throws FactTypeUseException, IOException { assertEquals(val.toString(), StandardTextWriter.valueToString(val), "toString of " + val + " is not equal to the standard notation"); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testNoValueInstancesShouldEverHaveFieldNamesInTheirDynamicTypes(IValue val) { assertFalse(val.getType().hasFieldNames()); diff --git a/src/test/java/io/usethesource/vallang/specification/ListTests.java b/src/test/java/io/usethesource/vallang/specification/ListTests.java index 689c022f8..904468010 100644 --- a/src/test/java/io/usethesource/vallang/specification/ListTests.java +++ b/src/test/java/io/usethesource/vallang/specification/ListTests.java @@ -14,18 +14,18 @@ public class ListTests { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void intersectionOrder( - @GivenValue("[1,2,3,4,5]") IList l1, + @GivenValue("[1,2,3,4,5]") IList l1, @GivenValue("[5,3,1]") IList l2, @GivenValue("[1,3,5]") IList result - ) { + ) { assertEquals(l1.intersect(l2), result); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void concatLength(@ExpectedType("list[num]") IList l1, @ExpectedType("list[num]") IList l2) { assertEquals(l1.concat(l2).length(), l1.length() + l2.length()); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void iterationOrder(@ExpectedType("list[num]") IList l1) { int i = 0; diff --git a/src/test/java/io/usethesource/vallang/specification/SetTests.java b/src/test/java/io/usethesource/vallang/specification/SetTests.java index 5a872862b..0e99ad830 100644 --- a/src/test/java/io/usethesource/vallang/specification/SetTests.java +++ b/src/test/java/io/usethesource/vallang/specification/SetTests.java @@ -21,17 +21,17 @@ public class SetTests { public void idempotence( @ExpectedType("set[int]") ISet set, IInteger i) { assertEquals(set.insert(i), set.insert(i).insert(i)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void idempotenceWithLoc( @ExpectedType("set[loc]") ISet set, ISourceLocation i) { assertEquals(set.insert(i), set.insert(i).insert(i)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void insertion( @ExpectedType("set[real]") ISet set, IInteger i) { assertEquals(set.insert(i).size(), set.size() + 1); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void removal(Random rnd, IValueFactory vf, @ExpectedType("set[int]") ISet set) { if (set.isEmpty()) { @@ -43,13 +43,13 @@ public void removal(Random rnd, IValueFactory vf, @ExpectedType("set[int]") ISet assertEquals(smaller.size() + 1, set.size()); assertTrue(!smaller.contains(elem)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void removalLocations(Random rnd, @ExpectedType("set[loc]") ISet set, ISourceLocation i) { if (set.isEmpty()) { return; } - + int index = rnd.nextInt(set.size()); IValue elem = set.stream().skip(index).findFirst().get(); ISet smaller = set.delete(elem); diff --git a/src/test/java/io/usethesource/vallang/specification/TypeTest.java b/src/test/java/io/usethesource/vallang/specification/TypeTest.java index 0ba79af3f..a0f65f248 100644 --- a/src/test/java/io/usethesource/vallang/specification/TypeTest.java +++ b/src/test/java/io/usethesource/vallang/specification/TypeTest.java @@ -33,7 +33,7 @@ public class TypeTest { public void randomTypeGeneratorTestIfTypeStoreContainsGeneratedTypes(TypeStore store, Type t) { assertTrue(t.isAbstractData() ? store.lookupAbstractDataType(t.getName()) != null : true); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void isomorphicStringTest(TypeFactory tf, TypeStore store, Type t) throws IOException { // no support for parameter types, aliases and tuple field names yet @@ -45,13 +45,13 @@ public void canonicalTypes(TypeFactory tf, Type t, Type u) { if (t.equals(u)) { assertTrue(t == u); } - + if (t == u) { assertTrue(t.equals(u)); assertTrue(u.equals(t)); } } - + @SuppressWarnings("deprecation") public void emptyTupleNeverHasLabels(TypeFactory tf) { assertFalse(tf.tupleType(new Object[0]).hasFieldNames()); @@ -60,13 +60,13 @@ public void emptyTupleNeverHasLabels(TypeFactory tf) { assertTrue(tf.tupleEmpty() == tf.tupleType(new Object[0])); assertTrue(tf.tupleEmpty() == tf.tupleType(new Type[0], new String[0])); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig(Option.ALL) public void covariance(TypeFactory tf, Type t, Type u) { if (!t.comparable(u)) { return; } - + if (t.isSubtypeOf(u)) { assertTrue(tf.listType(t).isSubtypeOf(tf.listType(u))); assertTrue(tf.setType(t).isSubtypeOf(tf.setType(u))); @@ -78,36 +78,36 @@ else if (u.isSubtypeOf(t)) { covariance(tf, u, t); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void voidIsBottom(TypeFactory tf, Type t) { assertTrue(tf.voidType().isSubtypeOf(t)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void valueIsTop(TypeFactory tf, Type t) { assertTrue(t.isSubtypeOf(tf.valueType())); } - - @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig(Option.ALL) + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig(Option.ALL) public void subtypeIsReflexive(Type t) { assertTrue(t.isSubtypeOf(t)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig(Option.ALL) public void equalsReflective(Type t) { assertTrue(t.equals(t)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig({Option.ALIASES, Option.TUPLE_FIELDNAMES}) public void subtypeIsTransitive(Type t, Type u, Type v) { - // because type parameters are variant in both directions they are excluded + // because type parameters are variant in both directions they are excluded if (t.isSubtypeOf(u) && u.isSubtypeOf(v)) { assertTrue(t.isSubtypeOf(v)); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) @TypeConfig(Option.ALL) public void subtypeIsAntiCommutative(Type t, Type u) { @@ -115,37 +115,37 @@ public void subtypeIsAntiCommutative(Type t, Type u) { assertTrue(!u.isStrictSubtypeOf(t)); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void aliasInstantiationSharingIsGuaranteed(TypeFactory tf, TypeStore store, Type t) { Type tp = tf.parameterType("T"); Map bindings = Collections.singletonMap(tp, t); - + Type alias = tf.aliasType(store, "A", tf.listType(tp), tp); assertTrue(alias.instantiate(bindings) == alias.instantiate(bindings)); - + alias = tf.aliasType(store, "B", tf.setType(tp), tp); assertTrue(alias.instantiate(bindings) == alias.instantiate(bindings)); - + alias = tf.aliasType(store, "C", tf.mapType(tp, tp), tp); assertTrue(alias.instantiate(bindings) == alias.instantiate(bindings)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void aliasInstantiationKeepsLabels(TypeFactory tf, TypeStore store, Type t, Type u) { Type T = tf.parameterType("T"); Type U = tf.parameterType("U"); Map bindings = Stream.of(new AbstractMap.SimpleEntry<>(T,t), new AbstractMap.SimpleEntry<>(U,u)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - + Type alias = tf.aliasType(store, "A", tf.mapType(T, "x", U, "y"), T, U); assertTrue(alias.instantiate(bindings) == alias.instantiate(bindings)); assertTrue(alias.getAliased().instantiate(bindings).hasFieldNames()); - + @SuppressWarnings("deprecation") Type alias2 = tf.aliasType(store, "B", tf.relType(T, "x", U, "y"), T, U); assertTrue(alias2.instantiate(bindings) == alias2.instantiate(bindings)); - + for (Type b : bindings.values()) { if (b.isBottom()) { return; // then the tuple type will reduce to void and we have nothing to check. @@ -153,7 +153,7 @@ public void aliasInstantiationKeepsLabels(TypeFactory tf, TypeStore store, Type } assertTrue(alias2.getAliased().instantiate(bindings).hasFieldNames()); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testRelations(Type t) { if (t.isSet() && t.getElementType().isTuple() && !t.isRelation()) { @@ -190,10 +190,10 @@ public void testParameterizedAlias(TypeFactory ft, TypeStore ts) { assertTrue(relType.match(instanceDiGraph, bindings)); assertTrue(bindings.get(T) == ft.integerType()); - // before instantiation, the parameterized type rel[&T, &T] + // before instantiation, the parameterized type rel[&T, &T] // could be instantiated later by rel[int, int] assertTrue(DiGraph.isSubtypeOf(IntInstance)); - + // the generic graph is also always a sub-type of the most general instantiation assertTrue(DiGraph.isSubtypeOf(ValueInstance)); @@ -264,7 +264,7 @@ public void testVoidProblem1(TypeFactory ft) { assertFalse(ft.relType(ft.voidType()).isSubtypeOf(ft.voidType())); assertFalse(ft.mapType(ft.voidType(), ft.voidType()).isSubtypeOf(ft.voidType())); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testTupleWithVoidIsVoid(TypeFactory ft) { assertTrue(ft.tupleType(ft.voidType()).isSubtypeOf(ft.voidType())); @@ -333,7 +333,7 @@ public void orderedGlb(Type t1, Type t2) { } } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void lubWithVoid(TypeFactory tf, Type t) { assertTrue(tf.voidType().lub(t) == t); @@ -409,11 +409,11 @@ public void testMatchAndInstantiate(TypeFactory ft, TypeStore store) { Type adtX = ft.abstractDataType(store, "A", X); bindings.put(X, ft.voidType()); assertTrue(adtX.instantiate(bindings).isSubtypeOf(adtX)); - + bindings.put(X, ft.integerType()); assertTrue(adtX.instantiate(bindings).isSubtypeOf(adtX)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testAlias(TypeFactory ft) { Type alias = ft.aliasType(new TypeStore(), "myValue", ft.valueType()); @@ -421,7 +421,7 @@ public void testAlias(TypeFactory ft) { assertTrue(alias.isSubtypeOf(ft.valueType())); assertTrue(ft.valueType().isSubtypeOf(alias)); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void allComparableTypesIntersect(Type t, Type u) { if (!t.isBottom() && !u.isBottom() && t.comparable(u)) { @@ -430,7 +430,7 @@ public void allComparableTypesIntersect(Type t, Type u) { } } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void intersectionIsCommutative(Type t, Type u) { if (t.intersects(u)) { @@ -439,49 +439,49 @@ public void intersectionIsCommutative(Type t, Type u) { } } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void intersectionIsReflexive(Type t) { if (!t.isBottom() && !t.intersects(t)) { fail("intersection should be reflexive: " + t); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void nothingIntersectsVoid(TypeFactory tf, Type t) { if (t.intersects(tf.voidType())) { fail("intersect with void?"); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void everythingIntersectsValue(TypeFactory tf, Type t) { if (!t.isBottom() && !t.intersects(tf.valueType())) { fail("does not intersect with value?"); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void intersectionIsNonVoidGreatestLowerBound(Type t, Type u) { // t /\ u != {} <==> glb(t, u) != void - + if (t.intersects(u)) { if(t.glb(u).isBottom()) { fail("glb should not be bottom for intersecting types:" + t + ", " + u + ": glb is " + t.glb(u)); } } - + if (!t.glb(u).isBottom()) { assertTrue(t.intersects(u)); } } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void collectionTypesAlwaysIntersect(TypeFactory tf, Type t, Type u) { assertTrue(tf.setType(t).intersects(tf.setType(u))); assertTrue(tf.listType(t).intersects(tf.listType(u))); } - + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void mapTypesAlwaysIntersect(TypeFactory tf, Type t, Type u) { assertTrue(tf.mapType(t, u).intersects(tf.mapType(u, t))); diff --git a/src/test/java/io/usethesource/vallang/specification/package-info.java b/src/test/java/io/usethesource/vallang/specification/package-info.java index 57f738f56..a57e5f075 100644 --- a/src/test/java/io/usethesource/vallang/specification/package-info.java +++ b/src/test/java/io/usethesource/vallang/specification/package-info.java @@ -1,7 +1,7 @@ /** * work in progress: migrating random tests in Junit4 + homemade axiom based setup to this package * where we use JUnit 5 Parametrized tests instead. - * + * * TODO: run tests for both implementations of IValueFactory somehow */ package io.usethesource.vallang.specification; diff --git a/src/test/java/io/usethesource/vallang/util/RandomValues.java b/src/test/java/io/usethesource/vallang/util/RandomValues.java index 65b7baa9c..c9d36b698 100644 --- a/src/test/java/io/usethesource/vallang/util/RandomValues.java +++ b/src/test/java/io/usethesource/vallang/util/RandomValues.java @@ -1,15 +1,15 @@ -/** - * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/** + * Copyright (c) 2016, Davy Landman, Centrum Wiskunde & Informatica (CWI) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.util; import java.util.Random; @@ -21,53 +21,53 @@ import io.usethesource.vallang.type.TypeStore; public class RandomValues { - private static TypeStore ts = new TypeStore(); - private static TypeFactory tf = TypeFactory.getInstance(); - private static Type Boolean = tf.abstractDataType(ts,"Boolean"); + private static TypeStore ts = new TypeStore(); + private static TypeFactory tf = TypeFactory.getInstance(); + private static Type Boolean = tf.abstractDataType(ts,"Boolean"); - private static Type Name = tf.abstractDataType(ts,"Name"); + private static Type Name = tf.abstractDataType(ts,"Name"); private static Type True = tf.constructor(ts,Boolean, "true"); private static Type False= tf.constructor(ts,Boolean, "false"); - private static Type And= tf.constructor(ts,Boolean, "and", Boolean, Boolean); - private static Type Or= tf.constructor(ts,Boolean, "or", tf.listType(Boolean)); - private static Type Not= tf.constructor(ts,Boolean, "not", Boolean); - private static Type TwoTups = tf.constructor(ts,Boolean, "twotups", tf.tupleType(Boolean, Boolean), tf.tupleType(Boolean, Boolean)); - private static Type NameNode = tf.constructor(ts,Name, "name", tf.stringType()); - private static Type Friends = tf.constructor(ts,Boolean, "friends", tf.listType(Name)); - private static Type Couples = tf.constructor(ts,Boolean, "couples", tf.listType(tf.tupleType(Name, Name))); - static { - ts.declareKeywordParameter(Name, "moreName", Name); - ts.declareKeywordParameter(Name, "listName", tf.listType(Name)); - ts.declareKeywordParameter(Name, "anyValue", tf.valueType()); - } + private static Type And= tf.constructor(ts,Boolean, "and", Boolean, Boolean); + private static Type Or= tf.constructor(ts,Boolean, "or", tf.listType(Boolean)); + private static Type Not= tf.constructor(ts,Boolean, "not", Boolean); + private static Type TwoTups = tf.constructor(ts,Boolean, "twotups", tf.tupleType(Boolean, Boolean), tf.tupleType(Boolean, Boolean)); + private static Type NameNode = tf.constructor(ts,Name, "name", tf.stringType()); + private static Type Friends = tf.constructor(ts,Boolean, "friends", tf.listType(Name)); + private static Type Couples = tf.constructor(ts,Boolean, "couples", tf.listType(tf.tupleType(Name, Name))); + static { + ts.declareKeywordParameter(Name, "moreName", Name); + ts.declareKeywordParameter(Name, "listName", tf.listType(Name)); + ts.declareKeywordParameter(Name, "anyValue", tf.valueType()); + } + + private static IValue name(IValueFactory vf, String n){ + return vf.constructor(NameNode, vf.string(n)); + } - private static IValue name(IValueFactory vf, String n){ - return vf.constructor(NameNode, vf.string(n)); - } - public static IValue[] getTestValues(IValueFactory vf) { - return new IValue[] { - vf.constructor(True), - vf.constructor(And, vf.constructor(True), vf.constructor(False)), - vf.constructor(Not, vf.constructor(And, vf.constructor(True), vf.constructor(False))), - vf.constructor(TwoTups, vf.tuple(vf.constructor(True), vf.constructor(False)),vf.tuple(vf.constructor(True), vf.constructor(False))), - vf.constructor(Or, vf.list(vf.constructor(True), vf.constructor(False), vf.constructor(True))), - vf.constructor(Friends, vf.list(name(vf, "Hans").asWithKeywordParameters().setParameter("listName", vf.list(name(vf,"Hansie"))), name(vf, "Bob"))), - vf.constructor(Couples, vf.list(vf.tuple(name(vf, "A"), name(vf, "B")), vf.tuple(name(vf, "C"), name(vf, "D")))), - vf.integer(0), - vf.integer(1), - vf.integer(-1), - vf.string("🍝"), - vf.integer(Integer.MAX_VALUE), - vf.integer(Integer.MIN_VALUE), - vf.integer(new byte[]{(byte)0xfe, (byte)0xdc, (byte)0xba, (byte)0x98, (byte)0x76, (byte)0x54}), - }; - }; - - public static Type addNameType(TypeStore t) { - t.extendStore(ts); - return Name; - } + return new IValue[] { + vf.constructor(True), + vf.constructor(And, vf.constructor(True), vf.constructor(False)), + vf.constructor(Not, vf.constructor(And, vf.constructor(True), vf.constructor(False))), + vf.constructor(TwoTups, vf.tuple(vf.constructor(True), vf.constructor(False)),vf.tuple(vf.constructor(True), vf.constructor(False))), + vf.constructor(Or, vf.list(vf.constructor(True), vf.constructor(False), vf.constructor(True))), + vf.constructor(Friends, vf.list(name(vf, "Hans").asWithKeywordParameters().setParameter("listName", vf.list(name(vf,"Hansie"))), name(vf, "Bob"))), + vf.constructor(Couples, vf.list(vf.tuple(name(vf, "A"), name(vf, "B")), vf.tuple(name(vf, "C"), name(vf, "D")))), + vf.integer(0), + vf.integer(1), + vf.integer(-1), + vf.string("🍝"), + vf.integer(Integer.MAX_VALUE), + vf.integer(Integer.MIN_VALUE), + vf.integer(new byte[]{(byte)0xfe, (byte)0xdc, (byte)0xba, (byte)0x98, (byte)0x76, (byte)0x54}), + }; + }; + + public static Type addNameType(TypeStore t) { + t.extendStore(ts); + return Name; + } public static IValue generate(Type tp, TypeStore ts, IValueFactory vf, Random rand, int maxDepth) { return tp.randomValue(rand, vf, ts, null, maxDepth, maxDepth * 2); diff --git a/src/test/java/io/usethesource/vallang/util/WeakHashConsingMapTest.java b/src/test/java/io/usethesource/vallang/util/WeakHashConsingMapTest.java index d3880e719..739e3e429 100644 --- a/src/test/java/io/usethesource/vallang/util/WeakHashConsingMapTest.java +++ b/src/test/java/io/usethesource/vallang/util/WeakHashConsingMapTest.java @@ -1,15 +1,15 @@ -/** +/** * Copyright (c) 2017, Davy Landman, SWAT.engineering - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package io.usethesource.vallang.util; import static org.junit.jupiter.api.Assertions.assertSame; @@ -41,14 +41,14 @@ private static class ThreadCount_CollisionCount_TestMapProvider implements Argum public Stream provideArguments(ExtensionContext context) throws Exception { int[] threads = new int[] { 1, 8 }; int[] collisions = new int[] { 1, 4 }; - return Arrays.stream(threads).boxed().flatMap(thr -> - Arrays.stream(collisions).boxed().flatMap(col -> + return Arrays.stream(threads).boxed().flatMap(thr -> + Arrays.stream(collisions).boxed().flatMap(col -> Stream.of(Arguments.of(thr, col, new WeakReferenceHashConsingMap(16, 1))) ) ); } } - + /** * Class that allows fine grained control on the equality contract and makes it easier to control hash collisions */ @@ -121,8 +121,8 @@ public void looseReference(int threads, int collisions, WeakReferenceHashConsing System.gc(); Thread.sleep(1100); // wait for the GC to finish and the cleanup to have been run while (ref.get() != null) { - System.gc(); - Thread.sleep(100); // wait for the GC to finish and the cleanup to have been run + System.gc(); + Thread.sleep(100); // wait for the GC to finish and the cleanup to have been run } // a new reference, the target should not have kept the old reference @@ -138,7 +138,7 @@ public void storeManyObjects(int threads, int collisions, WeakReferenceHashConsi objects.add(new FixedHashEquals(i, i)); } - // store them + // store them for (FixedHashEquals o : objects) { assertSame(o, target.get(o)); } @@ -157,7 +157,7 @@ private static int weakenHash(int hash, int maxEntries) { public void storeManyObjectsAndLooseThem(int threads, int collisions, WeakReferenceHashConsingMap target) throws CloneNotSupportedException, InterruptedException { FixedHashEquals[] objects = createTestObjects(1024*1024, collisions); - // store them + // store them for (FixedHashEquals o : objects) { assertSame(o, target.get(o)); } @@ -186,7 +186,7 @@ public void storeManyObjectsAndLooseThem(int threads, int collisions, WeakRefere public void storeManyObjectsAndQueryThem(int threads, int collisions, WeakReferenceHashConsingMap target) throws InterruptedException, CloneNotSupportedException { FixedHashEquals[] objects = createTestObjects(1024*1024, collisions); - // store them + // store them for (FixedHashEquals o : objects) { assertSame(o, target.get(o)); } @@ -210,7 +210,7 @@ private FixedHashEquals[] createTestObjects(int size, int collisions) { public void clearMostAndQueryRest(int threads, int collisions, WeakReferenceHashConsingMap target) throws InterruptedException, CloneNotSupportedException { FixedHashEquals[] objects = createTestObjects(1024*1024, collisions); - // store them + // store them for (FixedHashEquals o : objects) { assertSame(o, target.get(o)); } @@ -227,14 +227,14 @@ public void clearMostAndQueryRest(int threads, int collisions, WeakReferenceHash } } - private static class Tuple { - public final X x; - public final Y y; - public Tuple(X x, Y y) { - this.x = x; - this.y = y; - } - } + private static class Tuple { + public final X x; + public final Y y; + public Tuple(X x, Y y) { + this.x = x; + this.y = y; + } + } /** * Test many concurrent threads putting in the same object, and getting the same one out of there @@ -297,7 +297,7 @@ public void multithreadedAccess(int threads, int collisions, WeakReferenceHashCo /** * Generate enough data to trigger at least 10 resize events. Then have multiple threads all inserting every object exacty once. - * + * * Then query the cache from all threads to see if they are all in there (but take a clone of the object, to make sure we are getting the one we expected, and not the one we just passed in */ @ParameterizedTest @ArgumentsSource(ThreadCount_CollisionCount_TestMapProvider.class) @@ -319,7 +319,7 @@ public void multithreadedNothingIsLostDuringResizes(int threads, int collisions, final List mySlice = objects.subList(i*chunkSize, (i + 1) * chunkSize); new Thread(() -> { - boolean awaitQuerySend = false; + boolean awaitQuerySend = false; try { startRunning.await(); for (FixedHashEquals o : mySlice) { @@ -340,12 +340,12 @@ public void multithreadedNothingIsLostDuringResizes(int threads, int collisions, } catch (InterruptedException | BrokenBarrierException e) { } finally { - if (!awaitQuerySend) { - try { - startQuerying.await(); - } catch (InterruptedException | BrokenBarrierException e) { - } - } + if (!awaitQuerySend) { + try { + startQuerying.await(); + } catch (InterruptedException | BrokenBarrierException e) { + } + } doneRunning.release(); } }).start(); @@ -358,7 +358,7 @@ public void multithreadedNothingIsLostDuringResizes(int threads, int collisions, assertSame(first.x, first.y); } } - + /** * Add a lot of data, causing multiple resizes. Then clear almost all, and see if after the cleanup of the collection has happened, if ones that were left over, still return the same value. */ @@ -379,7 +379,7 @@ public void nothingIsLostDuringGCCollects(int threads, int collisions, WeakRefer for (FixedHashEquals o : objects) { - assertSame(o, target.get(o)); + assertSame(o, target.get(o)); } objects.clear(); @@ -387,7 +387,7 @@ public void nothingIsLostDuringGCCollects(int threads, int collisions, WeakRefer Thread.sleep(1100); for (FixedHashEquals o : toKeep) { - assertSame(o, target.get(o.clone())); + assertSame(o, target.get(o.clone())); } } @@ -420,7 +420,7 @@ public void multithreadedNothingIsLostDuringGCCollects(int threads, int collisio for (int i = 0; i < threads; i++) { List mySlice = objects.subList(i*chunkSize, (i + 1) * chunkSize); new Thread(() -> { - boolean awaitQuerySend = false; + boolean awaitQuerySend = false; try { startRunning.await(); for (FixedHashEquals o : mySlice) { @@ -442,12 +442,12 @@ public void multithreadedNothingIsLostDuringGCCollects(int threads, int collisio } catch (InterruptedException | BrokenBarrierException e) { } finally { - if (!awaitQuerySend) { - try { - startQuerying.await(); - } catch (InterruptedException | BrokenBarrierException e) { - } - } + if (!awaitQuerySend) { + try { + startQuerying.await(); + } catch (InterruptedException | BrokenBarrierException e) { + } + } doneRunning.release(); } }).start(); @@ -467,8 +467,8 @@ public void multithreadedNothingIsLostDuringGCCollects(int threads, int collisio } /** - * Test the first two guarantee: for every get there is only one result, across threads. - * + * Test the first two guarantee: for every get there is only one result, across threads. + * * We test this by inserting clones of the same objects (in the same sequnce) from a lot of threads, and then check if only one result was returned */ @ParameterizedTest @ArgumentsSource(ThreadCount_CollisionCount_TestMapProvider.class) @@ -509,7 +509,7 @@ public void insertMultipleCopiesAllReturnSameInstance(int threads, int collision else { seen.put(e, e); } - + } } }