From 069e234be185230d0cf9f077903989431975484b Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 6 Oct 2023 13:47:39 +0200 Subject: [PATCH 01/12] added IValue.getPatternMatchFingerprint() that simulates rascal-core:TopLevelType.getFingerprint(v) exactly for the value kinds we have in vallang --- .../io/usethesource/vallang/IConstructor.java | 8 ++++++++ .../io/usethesource/vallang/IExternalValue.java | 6 ++++++ src/main/java/io/usethesource/vallang/IList.java | 6 ++++++ src/main/java/io/usethesource/vallang/IMap.java | 5 +++++ src/main/java/io/usethesource/vallang/INode.java | 6 ++++++ src/main/java/io/usethesource/vallang/ISet.java | 5 +++++ .../java/io/usethesource/vallang/IString.java | 1 + .../java/io/usethesource/vallang/ITuple.java | 5 +++++ .../java/io/usethesource/vallang/IValue.java | 16 ++++++++++++++++ 9 files changed, 58 insertions(+) diff --git a/src/main/java/io/usethesource/vallang/IConstructor.java b/src/main/java/io/usethesource/vallang/IConstructor.java index 305eca659..2070bbea4 100644 --- a/src/main/java/io/usethesource/vallang/IConstructor.java +++ b/src/main/java/io/usethesource/vallang/IConstructor.java @@ -25,6 +25,14 @@ */ public interface IConstructor extends INode { + @Override + default int getPatternMatchFingerprint() { + return getName().hashCode() << 2 + arity(); + + // TODO: this would distinguish more constructors based on incomparable argument types: + // return getUninstantiatedConstructorType().hashCode(); + } + /** * @return the specific ConstructorType of this constructor */ diff --git a/src/main/java/io/usethesource/vallang/IExternalValue.java b/src/main/java/io/usethesource/vallang/IExternalValue.java index f36780542..84382e8d1 100644 --- a/src/main/java/io/usethesource/vallang/IExternalValue.java +++ b/src/main/java/io/usethesource/vallang/IExternalValue.java @@ -37,6 +37,12 @@ * 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 getPatternMatchFingerprint(); /** * @return an ExternalType diff --git a/src/main/java/io/usethesource/vallang/IList.java b/src/main/java/io/usethesource/vallang/IList.java index 496e232d8..edb0429e2 100644 --- a/src/main/java/io/usethesource/vallang/IList.java +++ b/src/main/java/io/usethesource/vallang/IList.java @@ -22,6 +22,12 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IList extends ICollection { + + @Override + default int getPatternMatchFingerprint() { + return 3322014; // "list".hashCode() + } + /** * @return the number of elements in the list */ diff --git a/src/main/java/io/usethesource/vallang/IMap.java b/src/main/java/io/usethesource/vallang/IMap.java index 46b31371f..212028602 100644 --- a/src/main/java/io/usethesource/vallang/IMap.java +++ b/src/main/java/io/usethesource/vallang/IMap.java @@ -26,6 +26,11 @@ public interface IMap extends ICollection { + @Override + default int getPatternMatchFingerprint() { + return 107868; // "map".hashCode() + } + /** * Adds a new entry to the map, mapping the key to value. If the * key existed before, the old value will be lost. diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index bfe51cdbf..12f2522c6 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -30,6 +30,12 @@ * it recursively. */ public interface INode extends IValue, Iterable { + + @Override + default int getPatternMatchFingerprint() { + return getName().hashCode() << 2 + arity(); + } + /** * Get a child * @param i the zero based index of the child diff --git a/src/main/java/io/usethesource/vallang/ISet.java b/src/main/java/io/usethesource/vallang/ISet.java index 3fd05cf88..d58ad2851 100644 --- a/src/main/java/io/usethesource/vallang/ISet.java +++ b/src/main/java/io/usethesource/vallang/ISet.java @@ -21,6 +21,11 @@ public interface ISet extends ICollection { + @Override + default int getPatternMatchFingerprint() { + return 113762; // "set".hashCode() + } + /** * Add an element to the set. * @param element diff --git a/src/main/java/io/usethesource/vallang/IString.java b/src/main/java/io/usethesource/vallang/IString.java index 8198be0e9..a900405d8 100644 --- a/src/main/java/io/usethesource/vallang/IString.java +++ b/src/main/java/io/usethesource/vallang/IString.java @@ -19,6 +19,7 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IString extends IValue, Iterable { + /** * @return the Java string that this string represents */ diff --git a/src/main/java/io/usethesource/vallang/ITuple.java b/src/main/java/io/usethesource/vallang/ITuple.java index 35d01645c..fc791ca39 100644 --- a/src/main/java/io/usethesource/vallang/ITuple.java +++ b/src/main/java/io/usethesource/vallang/ITuple.java @@ -16,6 +16,11 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface ITuple extends Iterable, IValue { + @Override + default int getPatternMatchFingerprint() { + return 442900256 /* "tuple".hashCode() << 2 */ + arity(); + } + /** * Retrieve the given field at the given index. * diff --git a/src/main/java/io/usethesource/vallang/IValue.java b/src/main/java/io/usethesource/vallang/IValue.java index 1af86064c..9679fd014 100644 --- a/src/main/java/io/usethesource/vallang/IValue.java +++ b/src/main/java/io/usethesource/vallang/IValue.java @@ -28,6 +28,22 @@ public interface IValue { * @return the {@link Type} of a value */ public Type getType(); + + /** + * This method is used exclusively by code generated by the Rascal compiler, + * 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() + * * distinguishes maximally between different kinds of values + * * never makes the same or similar value have a different fingerprint + */ + default int getPatternMatchFingerprint() { + return hashCode(); + } /** * Execute the {@link IValueVisitor} on the current node From 1789dec5b18f884722deedd35ff771ca5cf79a76 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 6 Oct 2023 14:09:21 +0200 Subject: [PATCH 02/12] added hashCode contract for getPatternMatchFingerprint and stability tests --- .../vallang/specification/IValueTests.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index 32b49d94f..f07643367 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -11,6 +11,15 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import io.usethesource.vallang.IConstructor; +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.IString; +import io.usethesource.vallang.ITuple; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; import io.usethesource.vallang.ValueProvider; @@ -44,6 +53,31 @@ 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) { + if (val1.equals(val2)) { + assertEquals(val1.getPatternMatchFingerprint(), val2.getPatternMatchFingerprint(), "" + val1.toString() + " and " + val2.toString() + " are equal but do not have the same fingerprint?"); + } + assertTrue(!val1.equals(val2) || val1.getPatternMatchFingerprint() == val2.getPatternMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStability(IInteger integer, IString string, IReal real, IRational rational, IList list, ISet set, IMap map, ITuple tuple, IConstructor constructor, INode node) { + // if we really want to change these codes, we should be aware that we are breaking all previously compiled and released Rascal code. + + assertEquals(integer.hashCode(), integer.getPatternMatchFingerprint()); + assertEquals(string.hashCode(), string.getPatternMatchFingerprint()); + assertEquals(real.hashCode(), real.getPatternMatchFingerprint()); + assertEquals(rational.hashCode(), rational.getPatternMatchFingerprint()); + assertEquals("list".hashCode(), list.getPatternMatchFingerprint()); + assertEquals("set".hashCode(), set.getPatternMatchFingerprint()); + assertEquals("map".hashCode(), map.getPatternMatchFingerprint()); + assertEquals("tuple".hashCode() << 2 + tuple.arity(), tuple.getPatternMatchFingerprint()); + assertEquals(constructor.getName().hashCode() << 2 + constructor.arity(), constructor.getPatternMatchFingerprint()); + assertEquals(node.getName().hashCode() << 2 + node.arity(), node.getPatternMatchFingerprint()); + } + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testWysiwyg(IValueFactory vf, TypeStore store, IValue val) throws FactTypeUseException, IOException { StandardTextReader reader = new StandardTextReader(); From 46fb81b59a9743e95c3251d539f108546aa9847c Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 10 Oct 2023 09:20:29 +0200 Subject: [PATCH 03/12] added a lot more tests and fixed some issues triggered by those tests --- .../java/io/usethesource/vallang/IBool.java | 10 ++ .../io/usethesource/vallang/IConstructor.java | 2 +- .../usethesource/vallang/IExternalValue.java | 2 +- .../io/usethesource/vallang/IInteger.java | 10 ++ .../java/io/usethesource/vallang/IList.java | 2 +- .../java/io/usethesource/vallang/IMap.java | 2 +- .../java/io/usethesource/vallang/INode.java | 6 +- .../java/io/usethesource/vallang/IReal.java | 6 + .../java/io/usethesource/vallang/ISet.java | 2 +- .../java/io/usethesource/vallang/IString.java | 10 ++ .../java/io/usethesource/vallang/ITuple.java | 2 +- .../java/io/usethesource/vallang/IValue.java | 14 ++- .../usethesource/vallang/ValueProvider.java | 20 ++- .../vallang/specification/IValueTests.java | 115 +++++++++++++++--- 14 files changed, 179 insertions(+), 24 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/IBool.java b/src/main/java/io/usethesource/vallang/IBool.java index 21e6e47ac..1b7ac29ae 100644 --- a/src/main/java/io/usethesource/vallang/IBool.java +++ b/src/main/java/io/usethesource/vallang/IBool.java @@ -13,6 +13,16 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IBool extends IValue { + @Override + default int getMatchFingerprint() { + if (getValue()) { + return 3569038; /* "true".hashCode() */ + } + else { + return 97196323; /* "false".hashCode() */ + } + } + boolean getValue(); String getStringRepresentation(); IBool and(IBool other); diff --git a/src/main/java/io/usethesource/vallang/IConstructor.java b/src/main/java/io/usethesource/vallang/IConstructor.java index 2070bbea4..e0b3d00c9 100644 --- a/src/main/java/io/usethesource/vallang/IConstructor.java +++ b/src/main/java/io/usethesource/vallang/IConstructor.java @@ -26,7 +26,7 @@ public interface IConstructor extends INode { @Override - default int getPatternMatchFingerprint() { + default int getMatchFingerprint() { return getName().hashCode() << 2 + arity(); // TODO: this would distinguish more constructors based on incomparable argument types: diff --git a/src/main/java/io/usethesource/vallang/IExternalValue.java b/src/main/java/io/usethesource/vallang/IExternalValue.java index 84382e8d1..193641392 100644 --- a/src/main/java/io/usethesource/vallang/IExternalValue.java +++ b/src/main/java/io/usethesource/vallang/IExternalValue.java @@ -42,7 +42,7 @@ public interface IExternalValue extends IValue { * instead of returning `IValue.hashCode()` automatically. */ @Override - int getPatternMatchFingerprint(); + int getMatchFingerprint(); /** * @return an ExternalType diff --git a/src/main/java/io/usethesource/vallang/IInteger.java b/src/main/java/io/usethesource/vallang/IInteger.java index 2f4756ee3..5fd7e6d63 100644 --- a/src/main/java/io/usethesource/vallang/IInteger.java +++ b/src/main/java/io/usethesource/vallang/IInteger.java @@ -15,6 +15,16 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IInteger extends INumber { + @Override + default int getMatchFingerprint() { + if (signum() == 0) { + return 104431; /* "int".hashCode() */ + } + else { + return hashCode(); + } + } + /** * @return this + other; */ diff --git a/src/main/java/io/usethesource/vallang/IList.java b/src/main/java/io/usethesource/vallang/IList.java index edb0429e2..7335d7554 100644 --- a/src/main/java/io/usethesource/vallang/IList.java +++ b/src/main/java/io/usethesource/vallang/IList.java @@ -24,7 +24,7 @@ public interface IList extends ICollection { @Override - default int getPatternMatchFingerprint() { + default int getMatchFingerprint() { return 3322014; // "list".hashCode() } diff --git a/src/main/java/io/usethesource/vallang/IMap.java b/src/main/java/io/usethesource/vallang/IMap.java index 212028602..5af85c1cd 100644 --- a/src/main/java/io/usethesource/vallang/IMap.java +++ b/src/main/java/io/usethesource/vallang/IMap.java @@ -27,7 +27,7 @@ public interface IMap extends ICollection { @Override - default int getPatternMatchFingerprint() { + default int getMatchFingerprint() { return 107868; // "map".hashCode() } diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index 12f2522c6..7b8b0993c 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -32,8 +32,10 @@ public interface INode extends IValue, Iterable { @Override - default int getPatternMatchFingerprint() { - return getName().hashCode() << 2 + arity(); + default int getMatchFingerprint() { + int hash = getName().hashCode(); + + return hash == 0 ? 3386882 /* node.hashCode() */ + arity() : hash << 2 + arity(); } /** diff --git a/src/main/java/io/usethesource/vallang/IReal.java b/src/main/java/io/usethesource/vallang/IReal.java index 6e4711085..346dff40c 100644 --- a/src/main/java/io/usethesource/vallang/IReal.java +++ b/src/main/java/io/usethesource/vallang/IReal.java @@ -16,6 +16,12 @@ import io.usethesource.vallang.visitors.IValueVisitor; public interface IReal extends INumber { + @Override + default int getMatchFingerprint() { + int hash = hashCode(); + return hash == 0 ? 3496350 /* real.hashCode() */ : hash; + } + /** * @return this + other; */ diff --git a/src/main/java/io/usethesource/vallang/ISet.java b/src/main/java/io/usethesource/vallang/ISet.java index d58ad2851..851585369 100644 --- a/src/main/java/io/usethesource/vallang/ISet.java +++ b/src/main/java/io/usethesource/vallang/ISet.java @@ -22,7 +22,7 @@ public interface ISet extends ICollection { @Override - default int getPatternMatchFingerprint() { + default int getMatchFingerprint() { return 113762; // "set".hashCode() } diff --git a/src/main/java/io/usethesource/vallang/IString.java b/src/main/java/io/usethesource/vallang/IString.java index a900405d8..924790be7 100644 --- a/src/main/java/io/usethesource/vallang/IString.java +++ b/src/main/java/io/usethesource/vallang/IString.java @@ -20,6 +20,16 @@ public interface IString extends IValue, Iterable { + @Override + default int getMatchFingerprint() { + if (length() == 0) { + return 114225; /* "str".hashCode() */ + } + else { + return hashCode(); + } + } + /** * @return the Java string that this string represents */ diff --git a/src/main/java/io/usethesource/vallang/ITuple.java b/src/main/java/io/usethesource/vallang/ITuple.java index fc791ca39..97ee8f015 100644 --- a/src/main/java/io/usethesource/vallang/ITuple.java +++ b/src/main/java/io/usethesource/vallang/ITuple.java @@ -17,7 +17,7 @@ public interface ITuple extends Iterable, IValue { @Override - default int getPatternMatchFingerprint() { + default int getMatchFingerprint() { return 442900256 /* "tuple".hashCode() << 2 */ + arity(); } diff --git a/src/main/java/io/usethesource/vallang/IValue.java b/src/main/java/io/usethesource/vallang/IValue.java index 9679fd014..861ec5264 100644 --- a/src/main/java/io/usethesource/vallang/IValue.java +++ b/src/main/java/io/usethesource/vallang/IValue.java @@ -41,10 +41,22 @@ public interface IValue { * * distinguishes maximally between different kinds of values * * never makes the same or similar value have a different fingerprint */ - default int getPatternMatchFingerprint() { + 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 + * * is guaranteed to be the same for every IValue + */ + default int getDefaultMatchFingerprint() { + return 0; + } + /** * Execute the {@link IValueVisitor} on the current node * diff --git a/src/test/java/io/usethesource/vallang/ValueProvider.java b/src/test/java/io/usethesource/vallang/ValueProvider.java index 6331dfcba..56f9a7562 100644 --- a/src/test/java/io/usethesource/vallang/ValueProvider.java +++ b/src/test/java/io/usethesource/vallang/ValueProvider.java @@ -337,8 +337,26 @@ private RandomTypesConfig configureRandomTypes(TypeConfig typeConfig, int depth) * @return an instance assignable to `cl` */ private IValue generateValue(IValueFactory vf, TypeStore ts, Class cl, ExpectedType expected, int depth, int width) { - Type expectedType = expected != null ? readType(ts, expected) : types.getOrDefault(cl, (x, n) -> tf.valueType()).apply(ts, expected); + Type expectedType = tf.voidType(); + + // this should terminate through random selection. + // only tuple types with nested void arguments can reduce to void. + int i = 0; + while (expectedType.isBottom() && i++ < 1000) { + if (expected != null) { + expectedType = readType(ts, expected); + break; + } + else { + expectedType = types + .getOrDefault(cl, (x, n) -> tf.valueType()) + .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); } diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index f07643367..fae9818f3 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -18,6 +19,7 @@ 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; @@ -57,25 +59,110 @@ public void testHashCodeContract(IValue val1, IValue val2) { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintContract(IValue val1, IValue val2) { if (val1.equals(val2)) { - assertEquals(val1.getPatternMatchFingerprint(), val2.getPatternMatchFingerprint(), "" + val1.toString() + " and " + val2.toString() + " are equal but do not have the same fingerprint?"); + assertEquals(val1.getMatchFingerprint(), val2.getMatchFingerprint(), "" + val1.toString() + " and " + val2.toString() + " are equal but do not have the same fingerprint?"); } - assertTrue(!val1.equals(val2) || val1.getPatternMatchFingerprint() == val2.getPatternMatchFingerprint()); + assertTrue(!val1.equals(val2) || val1.getMatchFingerprint() == val2.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testFingerprintStability(IInteger integer, IString string, IReal real, IRational rational, IList list, ISet set, IMap map, ITuple tuple, IConstructor constructor, INode node) { - // if we really want to change these codes, we should be aware that we are breaking all previously compiled and released Rascal code. + public void testDefaultFingerprintContracts(IValue val1) { + assertEquals(val1.getDefaultMatchFingerprint(), 0); - assertEquals(integer.hashCode(), integer.getPatternMatchFingerprint()); - assertEquals(string.hashCode(), string.getPatternMatchFingerprint()); - assertEquals(real.hashCode(), real.getPatternMatchFingerprint()); - assertEquals(rational.hashCode(), rational.getPatternMatchFingerprint()); - assertEquals("list".hashCode(), list.getPatternMatchFingerprint()); - assertEquals("set".hashCode(), set.getPatternMatchFingerprint()); - assertEquals("map".hashCode(), map.getPatternMatchFingerprint()); - assertEquals("tuple".hashCode() << 2 + tuple.arity(), tuple.getPatternMatchFingerprint()); - assertEquals(constructor.getName().hashCode() << 2 + constructor.arity(), constructor.getPatternMatchFingerprint()); - assertEquals(node.getName().hashCode() << 2 + node.arity(), node.getPatternMatchFingerprint()); + if (val1.getMatchFingerprint() == 0) { + System.err.println(val1 + " has a 0 fingerprint?"); + } + assertNotEquals(val1.getDefaultMatchFingerprint(), val1.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, IInteger integer) { + assertEquals(integer.equals(vf.integer(0)) ? "int".hashCode() : integer.hashCode(), integer.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityStringDoNotChangeTheTest(IString string) { + assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityRealDoNotChangeTheTest(IReal real) { + assertEquals(real.hashCode() == 0 ? "real".hashCode() : real.hashCode(), real.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityRationalDoNotChangeTheTest(IRational rational) { + assertEquals(rational.hashCode(), rational.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityListDoNotChangeTheTest(IList list) { + assertEquals("list".hashCode(), list.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintAllListsTheSameDoNotChangeTheTest(IList list1, IList list2) { + assertEquals(list1.getMatchFingerprint(), list2.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilitySetDoNotChangeTheTest(ISet set) { + assertEquals("set".hashCode(), set.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintAllSetsTheSameDoNotChangeTheTest(ISet set1, ISet set2) { + assertEquals(set1.getMatchFingerprint(), set2.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityMapDoNotChangeTheTest(IMap map) { + assertEquals("map".hashCode(), map.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintAllMapsTheSameDoNotChangeTheTest(IMap map1, IMap map2) { + assertEquals(map1.getMatchFingerprint(), map2.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityTupleDoNotChangeTheTest(ITuple tuple) { + assertEquals("tuple".hashCode() << 2 + tuple.arity(), tuple.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintEqualArityTuplesTheSameDoNotChangeTheTest(ITuple tuple1, ITuple tuple2) { + if (tuple1.arity() == tuple2.arity()) { + assertEquals(tuple1.getMatchFingerprint(), tuple2.getMatchFingerprint()); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) { + assertEquals(node.hashCode(), node.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { + assertEquals(node.hashCode() == 0 ? "node".hashCode() << 2 + node.arity() : node.hashCode() << 2 + node.arity(), node.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintEqualArityNodesTheSameDoNotChangeTheTest(INode node1, INode node2) { + if (node1.arity() == node2.arity()) { + assertEquals(node1.getMatchFingerprint(), node2.getMatchFingerprint()); + } + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityRationalDoNotChangeTheTest(IConstructor constructor) { + assertEquals(constructor.getName().hashCode() << 2 + constructor.arity(), constructor.getMatchFingerprint()); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintEqualArityConstructorsTheSameDoNotChangeTheTest(IConstructor node1, IConstructor node2) { + if (node1.arity() == node2.arity()) { + assertEquals(node1.getMatchFingerprint(), node2.getMatchFingerprint()); + } } @ParameterizedTest @ArgumentsSource(ValueProvider.class) From ec32c78b9a182f735013283977c499cceea4587d Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 10 Oct 2023 09:26:15 +0200 Subject: [PATCH 04/12] removed unused field --- .../usethesource/vallang/util/WeakReferenceHashConsingMap.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java b/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java index cb35a0cec..c4a6c6d63 100644 --- a/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java +++ b/src/main/java/io/usethesource/vallang/util/WeakReferenceHashConsingMap.java @@ -121,7 +121,6 @@ public boolean equals(@Nullable Object obj) { */ private final HotEntry[] hotEntries; private final int mask; - private final int expireAfter; /** * All entries are also stored in a WeakReference, this helps with clearing memory @@ -143,7 +142,6 @@ public WeakReferenceHashConsingMap(int size, int demoteAfterSeconds) { size = Integer.highestOneBit(size - 1) << 1; hotEntries = new HotEntry[size]; this.mask = size - 1; - this.expireAfter = demoteAfterSeconds; coldEntries = new ConcurrentHashMap<>(size); From 4506b14235e45fb9a2363dde6fa684e91e675058 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 10 Oct 2023 09:26:25 +0200 Subject: [PATCH 05/12] minor cleanup --- src/main/java/io/usethesource/vallang/IValue.java | 2 +- .../persistent/PersistentHashIndexedBinaryRelation.java | 1 - .../usethesource/vallang/specification/IValueTests.java | 8 ++------ .../io/usethesource/vallang/specification/SetTests.java | 2 -- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/IValue.java b/src/main/java/io/usethesource/vallang/IValue.java index 861ec5264..ba4674b51 100644 --- a/src/main/java/io/usethesource/vallang/IValue.java +++ b/src/main/java/io/usethesource/vallang/IValue.java @@ -53,7 +53,7 @@ default int getMatchFingerprint() { * * is guaranteed to be constant * * is guaranteed to be the same for every IValue */ - default int getDefaultMatchFingerprint() { + static int getDefaultMatchFingerprint() { return 0; } 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 136a39567..ad71af116 100644 --- a/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java +++ b/src/main/java/io/usethesource/vallang/impl/persistent/PersistentHashIndexedBinaryRelation.java @@ -38,7 +38,6 @@ import io.usethesource.vallang.ISetWriter; import io.usethesource.vallang.ITuple; import io.usethesource.vallang.IValue; -import io.usethesource.vallang.exceptions.IllegalOperationException; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.util.AbstractTypeBag; diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index fae9818f3..ef01c947b 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -66,12 +66,8 @@ public void testFingerprintContract(IValue val1, IValue val2) { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testDefaultFingerprintContracts(IValue val1) { - assertEquals(val1.getDefaultMatchFingerprint(), 0); - - if (val1.getMatchFingerprint() == 0) { - System.err.println(val1 + " has a 0 fingerprint?"); - } - assertNotEquals(val1.getDefaultMatchFingerprint(), val1.getMatchFingerprint()); + assertEquals(IValue.getDefaultMatchFingerprint(), 0); + assertNotEquals(IValue.getDefaultMatchFingerprint(), val1.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) diff --git a/src/test/java/io/usethesource/vallang/specification/SetTests.java b/src/test/java/io/usethesource/vallang/specification/SetTests.java index f316be2e6..5a872862b 100644 --- a/src/test/java/io/usethesource/vallang/specification/SetTests.java +++ b/src/test/java/io/usethesource/vallang/specification/SetTests.java @@ -4,8 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Random; -import java.util.stream.StreamSupport; - import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; From 970b1e7527544026109a46ae8c11b576f26a8e36 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sat, 14 Oct 2023 15:00:45 +0200 Subject: [PATCH 06/12] working towards aligning the spec with the impl --- src/main/java/io/usethesource/vallang/INode.java | 2 +- .../vallang/specification/IValueTests.java | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index 7b8b0993c..b66981885 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -35,7 +35,7 @@ public interface INode extends IValue, Iterable { default int getMatchFingerprint() { int hash = getName().hashCode(); - return hash == 0 ? 3386882 /* node.hashCode() */ + arity() : hash << 2 + arity(); + return hash == 0 ? 13547528 /* "node".hashCode() << 2*/ + arity() : hash << 2 + arity(); } /** diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index ef01c947b..3ef4fe98e 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -73,11 +73,19 @@ public void testDefaultFingerprintContracts(IValue val1) { @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, IInteger integer) { assertEquals(integer.equals(vf.integer(0)) ? "int".hashCode() : integer.hashCode(), integer.getMatchFingerprint()); + + // this should stay or we have to make sure that the fingerprint works like that again + // if it changes + if (integer.less(vf.integer(Integer.MAX_VALUE)).getValue()) { + assertEquals(integer.intValue(), integer.hashCode()); + } } @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityStringDoNotChangeTheTest(IString string) { assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); + + } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -122,7 +130,7 @@ public void testFingerprintAllMapsTheSameDoNotChangeTheTest(IMap map1, IMap map2 @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityTupleDoNotChangeTheTest(ITuple tuple) { - assertEquals("tuple".hashCode() << 2 + tuple.arity(), tuple.getMatchFingerprint()); + assertEquals(("tuple".hashCode() << 2) + tuple.arity(), tuple.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -139,12 +147,12 @@ public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { - assertEquals(node.hashCode() == 0 ? "node".hashCode() << 2 + node.arity() : node.hashCode() << 2 + node.arity(), node.getMatchFingerprint()); + assertEquals(node.hashCode() == 0 ? ("node".hashCode() << 2) + node.arity() : (node.getName().hashCode() << 2) + node.arity(), node.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintEqualArityNodesTheSameDoNotChangeTheTest(INode node1, INode node2) { - if (node1.arity() == node2.arity()) { + if (node1.arity() == node2.arity() && node1.getName().equals(node2.getName())) { assertEquals(node1.getMatchFingerprint(), node2.getMatchFingerprint()); } } From 13eaa4a8b89984ff02bc80e0fb19692c98926c8c Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sun, 15 Oct 2023 16:17:19 +0200 Subject: [PATCH 07/12] clarified computation with brackets and fixed node specification --- src/main/java/io/usethesource/vallang/INode.java | 2 +- .../usethesource/vallang/specification/IValueTests.java | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index b66981885..c103461b2 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -35,7 +35,7 @@ public interface INode extends IValue, Iterable { default int getMatchFingerprint() { int hash = getName().hashCode(); - return hash == 0 ? 13547528 /* "node".hashCode() << 2*/ + arity() : hash << 2 + arity(); + return hash == 0 ? 13547528 /* "node".hashCode() << 2*/ + arity() : (hash << 2) + arity(); } /** diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index 3ef4fe98e..62b044eb4 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -76,7 +76,7 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, // this should stay or we have to make sure that the fingerprint works like that again // if it changes - if (integer.less(vf.integer(Integer.MAX_VALUE)).getValue()) { + if (!integer.equals(vf.integer(0)) && integer.less(vf.integer(Integer.MAX_VALUE)).getValue() && integer.greater(vf.integer(Integer.MIN_VALUE)).getValue()) { assertEquals(integer.intValue(), integer.hashCode()); } } @@ -85,7 +85,7 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, public void testFingerprintStabilityStringDoNotChangeTheTest(IString string) { assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); - + } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -147,7 +147,9 @@ public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { - assertEquals(node.hashCode() == 0 ? ("node".hashCode() << 2) + node.arity() : (node.getName().hashCode() << 2) + node.arity(), node.getMatchFingerprint()); + assertEquals(node.getName().hashCode() == 0 + ? ("node".hashCode() << 2) + node.arity() + : (node.getName().hashCode() << 2) + node.arity(), node.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) From b915d3ccabc6cdcb6eecc74f2a22b937c2551774 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sun, 15 Oct 2023 16:25:36 +0200 Subject: [PATCH 08/12] all tests succeed now --- .../vallang/impl/primitive/IntegerValue.java | 1 + .../usethesource/vallang/specification/IValueTests.java | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) 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 2178c16b6..d2bce4b20 100644 --- a/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java +++ b/src/main/java/io/usethesource/vallang/impl/primitive/IntegerValue.java @@ -519,6 +519,7 @@ else if (isRationalType(other)) { } } + @Override public int hashCode(){ int h = value ^ 0x85ebca6b; // based on the final Avalanching phase of MurmurHash2 diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index 62b044eb4..ff489d360 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -77,7 +77,14 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, // this should stay or we have to make sure that the fingerprint works like that again // if it changes if (!integer.equals(vf.integer(0)) && integer.less(vf.integer(Integer.MAX_VALUE)).getValue() && integer.greater(vf.integer(Integer.MIN_VALUE)).getValue()) { - assertEquals(integer.intValue(), integer.hashCode()); + // 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; + + assertEquals(hash, integer.getMatchFingerprint()); } } From 84dcfbeada0289a873253cc9348b2c63118c6caf Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sun, 15 Oct 2023 16:44:47 +0200 Subject: [PATCH 09/12] added string hashcode contract --- .../vallang/specification/IValueTests.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index ff489d360..dc7518a08 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.StringReader; +import java.util.PrimitiveIterator.OfInt; +import java.util.function.IntConsumer; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -92,7 +94,24 @@ public void testFingerprintStabilityIntegersDoNotChangeTheTest(IValueFactory vf, public void testFingerprintStabilityStringDoNotChangeTheTest(IString string) { assertEquals(string.length() == 0 ? "str".hashCode() : string.hashCode(), string.getMatchFingerprint()); + // we copied the generic hashCode implementation here, to check the contract. + int h = 0; + OfInt it = string.iterator(); + while (it.hasNext()) { + int c = it.nextInt(); + + if (!Character.isBmpCodePoint(c)) { + h = 31 * h + Character.highSurrogate(c); + h = 31 * h + Character.lowSurrogate(c); + } else { + h = 31 * h + ((char) c); + } + } + + if (string.length() != 0) { + assertEquals(h, string.getMatchFingerprint()); + } } @ParameterizedTest @ArgumentsSource(ValueProvider.class) From 5e8e4d0e24c344ba291e3f25ae1ba3ae5cf1bb20 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 17 Oct 2023 09:32:05 +0200 Subject: [PATCH 10/12] nodes must have the same fingerprint as constructors if the name and arities are equal --- .../vallang/specification/IValueTests.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/test/java/io/usethesource/vallang/specification/IValueTests.java b/src/test/java/io/usethesource/vallang/specification/IValueTests.java index dc7518a08..c3d23d869 100644 --- a/src/test/java/io/usethesource/vallang/specification/IValueTests.java +++ b/src/test/java/io/usethesource/vallang/specification/IValueTests.java @@ -9,6 +9,8 @@ import java.io.StringReader; import java.util.PrimitiveIterator.OfInt; import java.util.function.IntConsumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; @@ -175,7 +177,7 @@ public void testFingerprintStabilityNodeDoNotChangeTheTest(ISourceLocation node) public void testFingerprintStabilityNodeDoNotChangeTheTest(INode node) { assertEquals(node.getName().hashCode() == 0 ? ("node".hashCode() << 2) + node.arity() - : (node.getName().hashCode() << 2) + node.arity(), node.getMatchFingerprint()); + : node.getName().hashCode() + 131 * node.arity(), node.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) @@ -186,8 +188,16 @@ public void testFingerprintEqualArityNodesTheSameDoNotChangeTheTest(INode node1, } @ParameterizedTest @ArgumentsSource(ValueProvider.class) - public void testFingerprintStabilityRationalDoNotChangeTheTest(IConstructor constructor) { - assertEquals(constructor.getName().hashCode() << 2 + constructor.arity(), constructor.getMatchFingerprint()); + public void testFingerprintStabilityNodesMatchConstructorsDoNotChangeTheTest(IValueFactory vf, IConstructor constructor) { + assertEquals( + constructor.getMatchFingerprint(), + vf.node(constructor.getName(), StreamSupport.stream(constructor.getChildren().spliterator(), false).toArray(IValue[]::new)).getMatchFingerprint() + ); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testFingerprintStabilityConstructorDoNotChangeTheTest(IConstructor constructor) { + assertEquals(constructor.getName().hashCode() + 131 * constructor.arity(), constructor.getMatchFingerprint()); } @ParameterizedTest @ArgumentsSource(ValueProvider.class) From 81059524621aa6b5853e8cfbcb83a9fb09dad6ac Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 17 Oct 2023 09:32:35 +0200 Subject: [PATCH 11/12] changed fingerprints of nodes and constructors to not shift the string anymore but multiply and add the arities --- src/main/java/io/usethesource/vallang/IConstructor.java | 5 +---- src/main/java/io/usethesource/vallang/INode.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/usethesource/vallang/IConstructor.java b/src/main/java/io/usethesource/vallang/IConstructor.java index e0b3d00c9..13566ca61 100644 --- a/src/main/java/io/usethesource/vallang/IConstructor.java +++ b/src/main/java/io/usethesource/vallang/IConstructor.java @@ -27,10 +27,7 @@ public interface IConstructor extends INode { @Override default int getMatchFingerprint() { - return getName().hashCode() << 2 + arity(); - - // TODO: this would distinguish more constructors based on incomparable argument types: - // return getUninstantiatedConstructorType().hashCode(); + return getName().hashCode() + 131 * arity(); } /** diff --git a/src/main/java/io/usethesource/vallang/INode.java b/src/main/java/io/usethesource/vallang/INode.java index c103461b2..623e8732d 100644 --- a/src/main/java/io/usethesource/vallang/INode.java +++ b/src/main/java/io/usethesource/vallang/INode.java @@ -35,7 +35,7 @@ public interface INode extends IValue, Iterable { default int getMatchFingerprint() { int hash = getName().hashCode(); - return hash == 0 ? 13547528 /* "node".hashCode() << 2*/ + arity() : (hash << 2) + arity(); + return hash == 0 ? 13547528 /* "node".hashCode() << 2*/ + arity() : hash + 131 * arity(); } /** From c883dbd7e7fea3ea68833033701bc1a4b9c6e587 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 17 Oct 2023 09:40:42 +0200 Subject: [PATCH 12/12] bumped vallang to 1.0.0-SNAPSHOT due to the new hard and leaky contract of IValue.getMatchFingerprint --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 069667698..501c061b3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.usethesource vallang - 0.15.2-SNAPSHOT + 1.0.0-SNAPSHOT jar