diff --git a/.gitignore b/.gitignore index aa5a1da..2a926e3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ java.hprof.txt *.log # Dependencies -/deps/ \ No newline at end of file +/deps/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..39217e7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2015, Nicolas LAURENT +All rights reserved. + +(BSD 3-Clause License) + +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. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +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. \ No newline at end of file diff --git a/library.mk b/library.mk new file mode 100644 index 0000000..8391acf --- /dev/null +++ b/library.mk @@ -0,0 +1,127 @@ +o?=dev +LIBS?= +OUTDIR?=out/$o +MVN_OUTPUT?=deps/fetched + +ifeq ($(OS),Windows_NT) + SEP=; +else + SEP=: +endif + +ifeq ($o,debug) + DEBUG=-g +else ifeq ($o,opti) + DEBUG=-g:none +endif + +define MANUAL_TEXT +build + + Compiles all java files in 'src', as well as all java files in the + directories listed in the LIBS variable. + + The generated class files are put in the output directory. This + directory can be set via the OUTDIR variable and default to 'out/$o'. + + 'o' is the build type variable. Setting this to 'debug' will cause local + variables to be included in the class files debug information. Using + 'opti' will disable *all* debugging information. Defaults to 'dev'. + +clean + + Deletes OUTDIR. Recall OUTDIR default to 'out/$o', and 'o' is the build + type variable. + +run + + Runs the class indicate in variable 't' (e.g. 'my.pkg.Main'), passing + the variable 'a' as argument (optional). + +trace + + Same as 'run', but uses hprof to benchmark the CPU use of the program. + The results are stored in the file 'java.hprof.txt'. + + For more info: + https://docs.oracle.com/javase/8/docs/technotes/guides/ + troubleshoot/tooldescr008.html + +fetch + + Fetches the maven artifact (e.g. jar file) specified in the 'a' variable, in + Gradle format. It does not fetch the dependencies of the artifact + transitively. + + The downloaded files are put in the directory indicated by the + MVN_OUTPUT variable, defaulting to 'deps/fetched'. + +fetchpom + + Fetches all the jar dependencies listed in 'deps.xml' and fetches their + dependencies transitively. + + The downloaded files are put in '$MVN_OUTPUT/jar', where MVN_OUTPUT is a + variable defaulting to 'deps/fetched'. + +fetchdev + + Fetches the sources and javadoc artifacts corresponding to the jars + listed in 'deps.xml' and their transitive dependencies. + + The downloaded files are put in '$MVN_OUTPUT/src' and '$MVN_OUTPUT/jdoc', + where MVN_OUTPUT is a variable defaulting to 'deps/fetched'. + +endef + +# NOTE(norswap): no idea why this voodoo dance works, but naive attempts were +# unsuccessful. Kudos http://stackoverflow.com/questions/7281395 + +export MANUAL=$(MANUAL_TEXT) + +help: + @echo "$$MANUAL" + +# NOTE(norswap): The quotes around "deps/*" are necessary to avoid shell +# wildcard expansion. The wildcard must be processed by javac. + +build: + mkdir -p $(OUTDIR) + cp -R resources/* $(OUTDIR) + javac -Xlint:unchecked $(DEBUG) -d $(OUTDIR) -cp "deps/*" `find src $(LIBS) -name *.java` + +clean: + rm -rf $(OUTDIR) + +run: + java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" $t $a + +trace: + java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" -agentlib:hprof=cpu=samples $t $a + +fetch: + mkdir -p $(MVN_OUTPUT) + mvn org.apache.maven.plugins:maven-dependency-plugin:2.10:get \ + -DrepoUrl=http://repo1.maven.org/maven2/ \ + -Ddest=$(MVN_OUTPUT) + -Dartifact=$a + +fetchpom: + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/jar + +fetchdev: + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/jdoc -Dclassifier=sources + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/src -Dclassifier=javadoc + +.PHONY: \ + help \ + build \ + clean \ + run \ + trace \ + fetch \ + fetchpom \ + fetchdev diff --git a/libs/java_utils/.gitignore b/libs/java_utils/.gitignore new file mode 100644 index 0000000..aa5a1da --- /dev/null +++ b/libs/java_utils/.gitignore @@ -0,0 +1,14 @@ +# IntelliJ IDEA +/.idea/ +*.iml + +# Mac +.DS_Store + +# Output +/out +java.hprof.txt +*.log + +# Dependencies +/deps/ \ No newline at end of file diff --git a/libs/java_utils/library.mk b/libs/java_utils/library.mk new file mode 100644 index 0000000..8391acf --- /dev/null +++ b/libs/java_utils/library.mk @@ -0,0 +1,127 @@ +o?=dev +LIBS?= +OUTDIR?=out/$o +MVN_OUTPUT?=deps/fetched + +ifeq ($(OS),Windows_NT) + SEP=; +else + SEP=: +endif + +ifeq ($o,debug) + DEBUG=-g +else ifeq ($o,opti) + DEBUG=-g:none +endif + +define MANUAL_TEXT +build + + Compiles all java files in 'src', as well as all java files in the + directories listed in the LIBS variable. + + The generated class files are put in the output directory. This + directory can be set via the OUTDIR variable and default to 'out/$o'. + + 'o' is the build type variable. Setting this to 'debug' will cause local + variables to be included in the class files debug information. Using + 'opti' will disable *all* debugging information. Defaults to 'dev'. + +clean + + Deletes OUTDIR. Recall OUTDIR default to 'out/$o', and 'o' is the build + type variable. + +run + + Runs the class indicate in variable 't' (e.g. 'my.pkg.Main'), passing + the variable 'a' as argument (optional). + +trace + + Same as 'run', but uses hprof to benchmark the CPU use of the program. + The results are stored in the file 'java.hprof.txt'. + + For more info: + https://docs.oracle.com/javase/8/docs/technotes/guides/ + troubleshoot/tooldescr008.html + +fetch + + Fetches the maven artifact (e.g. jar file) specified in the 'a' variable, in + Gradle format. It does not fetch the dependencies of the artifact + transitively. + + The downloaded files are put in the directory indicated by the + MVN_OUTPUT variable, defaulting to 'deps/fetched'. + +fetchpom + + Fetches all the jar dependencies listed in 'deps.xml' and fetches their + dependencies transitively. + + The downloaded files are put in '$MVN_OUTPUT/jar', where MVN_OUTPUT is a + variable defaulting to 'deps/fetched'. + +fetchdev + + Fetches the sources and javadoc artifacts corresponding to the jars + listed in 'deps.xml' and their transitive dependencies. + + The downloaded files are put in '$MVN_OUTPUT/src' and '$MVN_OUTPUT/jdoc', + where MVN_OUTPUT is a variable defaulting to 'deps/fetched'. + +endef + +# NOTE(norswap): no idea why this voodoo dance works, but naive attempts were +# unsuccessful. Kudos http://stackoverflow.com/questions/7281395 + +export MANUAL=$(MANUAL_TEXT) + +help: + @echo "$$MANUAL" + +# NOTE(norswap): The quotes around "deps/*" are necessary to avoid shell +# wildcard expansion. The wildcard must be processed by javac. + +build: + mkdir -p $(OUTDIR) + cp -R resources/* $(OUTDIR) + javac -Xlint:unchecked $(DEBUG) -d $(OUTDIR) -cp "deps/*" `find src $(LIBS) -name *.java` + +clean: + rm -rf $(OUTDIR) + +run: + java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" $t $a + +trace: + java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" -agentlib:hprof=cpu=samples $t $a + +fetch: + mkdir -p $(MVN_OUTPUT) + mvn org.apache.maven.plugins:maven-dependency-plugin:2.10:get \ + -DrepoUrl=http://repo1.maven.org/maven2/ \ + -Ddest=$(MVN_OUTPUT) + -Dartifact=$a + +fetchpom: + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/jar + +fetchdev: + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/jdoc -Dclassifier=sources + mvn dependency:copy-dependencies -f deps.xml \ + -DoutputDirectory=$(MVN_OUTPUT)/src -Dclassifier=javadoc + +.PHONY: \ + help \ + build \ + clean \ + run \ + trace \ + fetch \ + fetchpom \ + fetchdev diff --git a/libs/java_utils/makefile b/libs/java_utils/makefile new file mode 100644 index 0000000..ec32334 --- /dev/null +++ b/libs/java_utils/makefile @@ -0,0 +1 @@ +include library.mk diff --git a/libs/java_utils/src/com/norswap/util/Array.java b/libs/java_utils/src/com/norswap/util/Array.java new file mode 100644 index 0000000..f0151db --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/Array.java @@ -0,0 +1,805 @@ +package com.norswap.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.RandomAccess; +import java.util.function.Function; + +/** + * A dynamic array to serve as substitute to ArrayList. + * + * The idea to to be able to implement functions not implemented by ArrayList, such as {@link + * #truncate}. + * + * But mostly, I did it for fun. + * + * Future plans: + * - implement Deque + */ +public final class Array implements List, RandomAccess, Cloneable +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static int DEFAULT_SIZE = 4; + public static double GROWTH_FACTOR = 2.0f; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + private Object[] array; + private int next; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public Array(T[] array, int next) + { + this.array = array; + this.next = next; + } + + public Array(T... items) + { + this.array = items; + this.next = items.length; + } + + public Array(int size) + { + array = new Object[size]; + } + + public Array() + { + array = new Object[DEFAULT_SIZE]; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static Array fromItem(T item) + { + return new Array<>((T) item); + } + + public static Array fromArray(T[] array) + { + return new Array<>((T[]) array); + } + + public static Array fromUnsafe(Object[] array) + { + Array out = new Array<>(); + out.array = array; + out.next = array.length; + return out; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public boolean isEmpty() + { + return next == 0; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public int size() + { + return next; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // INSERTIONS + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean add(T t) + { + if (next == array.length) + { + growCapacity(array.length + 1); + } + + array[next++] = t; + + return true; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void add(int index, T element) + { + if (next == array.length) + { + growCapacity(array.length + 1); + } + + System.arraycopy(array, index, array, index + 1, next - index - 1); + array[index] = element; + next++; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public T get(int index) + { + return Caster.cast(array[index]); + } + + // --------------------------------------------------------------------------------------------- + + @Override + public T set(int index, T t) + { + @SuppressWarnings("unchecked") + T element = (T) array[index]; + array[index] = t; + return t; + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@inheritDoc} + *

+ * If {@code collection} is null, it will be treated as empty. + */ + @Override + public boolean addAll(Collection collection) + { + int size = next; + if (collection != null) + { + collection.forEach(this::add); + } + return size != next; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean addAll(int index, Collection c) + { + int csize = c.size(); + + if (array.length < next + csize) + { + growCapacity(next + csize); + } + + System.arraycopy(array, index, array, index + csize, next - index - 1); + + int i = index; + for (T t: c) + { + array[i++] = t; + } + + return csize != 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // NEW OPERATIONS + + // --------------------------------------------------------------------------------------------- + + public void growSize(int size) + { + if (array.length < size) { + growCapacity(size); + } + + next = size; + } + + // --------------------------------------------------------------------------------------------- + + public void growCapacity(int capacity) + { + int size = array.length; + + if (size < capacity) + { + while (size < capacity) + { + size = (int) (size * GROWTH_FACTOR); + } + + array = Arrays.copyOf(array, size); + } + } + + // --------------------------------------------------------------------------------------------- + + public void truncate(int size) + { + for (int i = size; i < next; ++i) + { + array[i] = null; + } + + if (size < next) + { + next = size; + } + } + + // --------------------------------------------------------------------------------------------- + + public void push(T t) + { + add(t); + } + + // --------------------------------------------------------------------------------------------- + + public T pop() + { + return Caster.cast(array[--next]); + } + + // --------------------------------------------------------------------------------------------- + + public T popOrNull() + { + return next == 0 ? null : pop(); + } + + // --------------------------------------------------------------------------------------------- + + public T popOr(T t) + { + return next == 0 ? t : pop(); + } + + // --------------------------------------------------------------------------------------------- + + public T peek() + { + return Caster.cast(array[next - 1]); + } + + // --------------------------------------------------------------------------------------------- + + public T peekOrNull() + { + return next == 0 ? null : peek(); + } + + // --------------------------------------------------------------------------------------------- + + public T peekOr(T t) + { + return next == 0 ? t : peek(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // REMOVALS + + // --------------------------------------------------------------------------------------------- + + @Override + public T remove(int index) + { + @SuppressWarnings("unchecked") + T item = (T) array[index]; + System.arraycopy(array, index + 1, array, index, next - index - 1); + --next; + return item; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean remove(Object t) + { + for (int i = 0; i < next; ++i) + { + if (array[i].equals(t)) + { + remove(i); + return true; + } + } + + return false; + } + + // --------------------------------------------------------------------------------------------- + + public boolean removeFromEnd(T t) + { + for (int i = next - 1; i >= 0; --i) + { + if (array[i].equals(t)) + { + remove(i); + return true; + } + } + + return false; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean removeAll(Collection c) + { + int size = next; + c.forEach(this::remove); + return size != next; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean retainAll(Collection c) + { + int size = next; + + for (int i = 0; i < next; ++i) + { + if (!c.contains(array[i])) + { + remove(i--); + } + } + + return size != next; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void clear() + { + truncate(0); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // MISC + + // --------------------------------------------------------------------------------------------- + + @Override + public int indexOf(Object t) + { + for (int i = 0; i < next; ++i) + { + if (t == null ? array[i] == null : t.equals(array[i])) + { + return i; + } + } + + return -1; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public int lastIndexOf(Object t) + { + for (int i = next - 1; i >= 0; --i) + { + if (t == null ? array[i] == null : t.equals(array[i])) + { + return i; + } + } + + return -1; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean contains(Object t) + { + return indexOf(Caster.cast(t)) >= 0; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public boolean containsAll(Collection c) + { + for (Object o: c) + { + if (!contains(o)) { + return false; + } + } + + return true; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public List subList(int fromIndex, int toIndex) + { + throw new UnsupportedOperationException("Array doesn't support sublist for now"); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // ITERATORS + + // --------------------------------------------------------------------------------------------- + + private class ArrayIterator implements ListIterator + { + int index; + int direction; + + @Override + public boolean hasNext() + { + return index < next; + } + + @Override + @SuppressWarnings("unchecked") + public T next() + { + direction = 1; + return (T) array[index++]; + } + + @Override + public boolean hasPrevious() + { + return index > 0; + } + + @Override + @SuppressWarnings("unchecked") + public T previous() + { + direction = -1; + return (T) array[--index]; + } + + @Override + public int nextIndex() + { + return index; + } + + @Override + public int previousIndex() + { + return index - 1; + } + + @Override + public void remove() + { + if (direction > 0) + { + Array.this.remove(index - 1); + --index; + } + else if (direction < 0) + { + Array.this.remove(index); + } + else { + throw new IllegalStateException( + "Calling remove twice, or after add, or before calling next."); + } + + direction = 0; + } + + @Override + public void set(T t) + { + if (direction > 0) + { + array[index - 1] = t; + } + else if (direction < 0) + { + array[index] = t; + } + else { + throw new IllegalStateException( + "Calling set after remove or add, or before calling next."); + } + } + + @Override + public void add(T t) + { + Array.this.add(index, t); + ++index; + direction = 0; + } + } + + // --------------------------------------------------------------------------------------------- + + private final class ReverseArrayIterator extends ArrayIterator + { + { + index = next - 1; + } + + @Override + public boolean hasNext() + { + return super.hasPrevious(); + } + + @Override + public T next() + { + return super.previous(); + } + + @Override + public boolean hasPrevious() + { + return super.hasNext(); + } + + @Override + public T previous() + { + return super.next(); + } + + @Override + public int nextIndex() + { + return super.previousIndex(); + } + + @Override + public int previousIndex() + { + return super.nextIndex(); + } + + @Override + public void add(T t) + { + Array.this.add(index, t); + // ++index; // remove this from superclass to satisfy method contract + direction = 0; + } + } + + // --------------------------------------------------------------------------------------------- + + @Override + public Iterator iterator() + { + return new ArrayIterator(); + } + + // --------------------------------------------------------------------------------------------- + + @Override + public ListIterator listIterator() + { + return new ArrayIterator(); + } + + // --------------------------------------------------------------------------------------------- + + @Override + public ListIterator listIterator(int index) + { + ArrayIterator out = new ArrayIterator(); + out.index = index; + return out; + } + + // --------------------------------------------------------------------------------------------- + + public Iterable reverseIterable() + { + return this::reverseIterator; + } + + // --------------------------------------------------------------------------------------------- + + public ListIterator reverseIterator() + { + return new ReverseArrayIterator(); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // MAP METHODS + + // TODO offer a map view on this collection + + public boolean containsValue(Object value) + { + return contains(value); + } + + public boolean containsKey(Object key) + { + return (int) key < next; + } + + public T get(Object key) + { + return get((int) key); + } + + public T put(Integer key, T value) + { + if (next <= key) + { + growSize(key + 1); + } + + return set(key, value); + } + + public Collection values() + { + return this; + } + + /* TODO + + @Override + + + @Override + public Set> entrySet() + { + return null; + } + + @Override + public Set keySet() + { + return null; + } + + @Override + public void putAll(Map m) + { + + } + */ + + //////////////////////////////////////////////////////////////////////////////////////////////// + // TO ARRAY + + // --------------------------------------------------------------------------------------------- + + public T[] toArray(Function supplier) + { + T[] out = supplier.apply(next); + System.arraycopy(array, 0, out, 0, next); + return out; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public Object[] toArray() + { + Object[] out = new Object[next]; + System.arraycopy(array, 0, out, 0, next); + return out; + } + + // --------------------------------------------------------------------------------------------- + + @Override + @SuppressWarnings("unchecked") + public U[] toArray(U[] out) + { + if (out.length < next) + { + out = (U[]) + java.lang.reflect.Array.newInstance(out.getClass().getComponentType(), next); + } + + System.arraycopy(array, 0, out, 0, next); + + if (out.length != next) + { + out[next] = null; + } + + return out; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public String toString() + { + StringBuilder b = new StringBuilder(); + b.append("["); + + for (int i = 0; i < next; ++i) + { + b.append(array[i]); + b.append(", "); + } + + if (next > 0) + { + b.setLength(b.length() - 2); + } + + b.append("]"); + return b.toString(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + @SuppressWarnings({"unchecked", "CloneDoesntCallSuperClone"}) + public Array clone() + { + return new Array(array.clone(), next); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public boolean equals(Object o) + { + // part auto-generated, part lifted from Arrays.equals + + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + Array array1 = (Array) o; + + if (next != array1.next) + return false; + + for (int i = 0; i < next; ++i) + { + Object o1 = array[i]; + Object o2 = array1.array[i]; + + if (!(o1==null ? o2==null : o1.equals(o2))) + return false; + } + + return true; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public int hashCode() + { + // lifted from Arrays.hashCode + + int result = 1; + + for (T t: this) + { + result = 31 * result + (t == null ? 0 : t.hashCode()); + } + + return result; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/util/Caster.java b/libs/java_utils/src/com/norswap/util/Caster.java similarity index 56% rename from src/com/norswap/autumn/util/Caster.java rename to libs/java_utils/src/com/norswap/util/Caster.java index c947dc2..57aa84e 100644 --- a/src/com/norswap/autumn/util/Caster.java +++ b/libs/java_utils/src/com/norswap/util/Caster.java @@ -1,7 +1,9 @@ -package com.norswap.autumn.util; +package com.norswap.util; public final class Caster { + //////////////////////////////////////////////////////////////////////////////////////////////// + /** * Unchecked and type-inferenced cast that doesn't incur a unchecked cast warning, nor the * run-time overhead of type checking. @@ -11,4 +13,6 @@ public static T cast(Object obj) { return (T) obj; } + + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/libs/java_utils/src/com/norswap/util/Counter.java b/libs/java_utils/src/com/norswap/util/Counter.java new file mode 100644 index 0000000..037fd80 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/Counter.java @@ -0,0 +1,30 @@ +package com.norswap.util; + +/** + * A simple modifiable counter for use inside forEach loops and the such. + *

+ * e.g.: + *

+ *      Counter c = new Counter();
+ *      Arrays.stream(array).forEach(x -> c.i++);
+ * 
+ */ +public class Counter +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public int i; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public Counter() {} + + // --------------------------------------------------------------------------------------------- + + public Counter(int i) + { + this.i = i; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/util/DeepCopy.java b/libs/java_utils/src/com/norswap/util/DeepCopy.java similarity index 79% rename from src/com/norswap/autumn/util/DeepCopy.java rename to libs/java_utils/src/com/norswap/util/DeepCopy.java index 22437bb..758d158 100644 --- a/src/com/norswap/autumn/util/DeepCopy.java +++ b/libs/java_utils/src/com/norswap/util/DeepCopy.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.lang.reflect.Array; import java.util.function.Function; @@ -58,6 +58,27 @@ static T clone(T t) } } + // --------------------------------------------------------------------------------------------- + + /** + * Sometimes, it is useful to clone array one level-deep (i.e. clone the array itself than + * replace each of its elements by their clones). + * + * This is different from a deep copy: a deep copy will continue to recurse over the members of + * the array elements. + */ + static T[] deepClone(T[] array) + { + T[] out = array.clone(); + + for (int i = 0; i < array.length; ++i) + { + out[i] = clone(array[i]); + } + + return out; + } + //////////////////////////////////////////////////////////////////////////////////////////////// class NotSupported extends RuntimeException {} diff --git a/src/com/norswap/autumn/util/Exceptions.java b/libs/java_utils/src/com/norswap/util/Exceptions.java similarity index 99% rename from src/com/norswap/autumn/util/Exceptions.java rename to libs/java_utils/src/com/norswap/util/Exceptions.java index f60c74b..6c0ca17 100644 --- a/src/com/norswap/autumn/util/Exceptions.java +++ b/libs/java_utils/src/com/norswap/util/Exceptions.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.util.function.Function; import java.util.function.Supplier; diff --git a/libs/java_utils/src/com/norswap/util/FlagFactory.java b/libs/java_utils/src/com/norswap/util/FlagFactory.java new file mode 100644 index 0000000..fc0baa4 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/FlagFactory.java @@ -0,0 +1,38 @@ +package com.norswap.util; + +/** + * Instances sequentially generate all 1-bit flags for 32-bit or 64-bit integers. + * (From the least-significant bit flag to the most-significant bit flag) + */ +public class FlagFactory +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + private int next; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public int next() + { + if (next >= 32) + { + throw new RuntimeException("Flag space (32 flags) exhausted."); + } + + return 1 << next++; + } + + // --------------------------------------------------------------------------------------------- + + public long next64() + { + if (next >= 64) + { + throw new RuntimeException("Flag space (64 flags) exhausted."); + } + + return 1L << next++; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/util/Glob.java b/libs/java_utils/src/com/norswap/util/Glob.java similarity index 69% rename from src/com/norswap/autumn/util/Glob.java rename to libs/java_utils/src/com/norswap/util/Glob.java index 63c75ec..9d06e52 100644 --- a/src/com/norswap/autumn/util/Glob.java +++ b/libs/java_utils/src/com/norswap/util/Glob.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.io.IOException; import java.nio.file.FileSystem; @@ -10,15 +10,18 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.List; -public class Glob +public final class Glob { + //////////////////////////////////////////////////////////////////////////////////////////////// + /** - * Returns a list of all the paths that match the given glob pattern within the given directory - * (see syntax here in the doc of {@link FileSystem#getPathMatcher} -- the "glob:" part - * should be omitted). + * Returns a list of all the paths that match the given glob pattern within the given directory. + * The patter syntax is described in the doc of {@link FileSystem#getPathMatcher} -- + * the "glob:" part should be omitted. */ - public static Iterable glob(String pattern, Path directory) throws IOException + public static List glob(String pattern, Path directory) throws IOException { PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern); @@ -47,4 +50,6 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce return result; } + + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/libs/java_utils/src/com/norswap/util/HandleFactory.java b/libs/java_utils/src/com/norswap/util/HandleFactory.java new file mode 100644 index 0000000..10f1e40 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/HandleFactory.java @@ -0,0 +1,89 @@ +package com.norswap.util; + +/** + * A generator of unique handles (int or long). + * + * A handle factory is parameterized by a (start, end, stride) triplet. The handles are allocated + * in the [start, end[ range; unless end is 0, in which case the range extends up to limit of the + * integer type being used. In any case, the range never wraps around. + * + * The stride is the amount by which to increment the handle each time. Using a stride is + * interesting when taking the remainder of a handle in order to store it in a linear-addressing + * hash map (as is done in {@link com.norswap.util.HandleMap}). Sequential handles are often used + * together; using a stride produces holes in the table that avoid probing too far ahead for an + * empty slot. It is recommended to use an odd stride (3 is a typical value). + */ +public final class HandleFactory +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public final long start; + public final long end; + public final int stride; + + private long next; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Allocates handles on the given range with the given stride. + * If end is 0, the range extends to the end of the integer range. + */ + public HandleFactory(int start, int end, int stride) + { + this.start = start; + this.end = end; + this.stride = stride; + this.next = start - stride; + } + + // --------------------------------------------------------------------------------------------- + + /** + * Allocates handles on the whole integer range with the given stride. + */ + public HandleFactory(int stride) + { + this(0, 0, stride); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Allocates handles on the whole integer range with a stride of 1. + */ + public HandleFactory() + { + this(0, 0, 1); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public int next() + { + if (end > 0 && next >= end - stride || next >= Integer.MAX_VALUE - stride) + { + throw new RuntimeException( + "Handle space (2^32 handles / stride (" + stride + ")) exhausted."); + } + + next += stride; + return (int) next; + } + + // --------------------------------------------------------------------------------------------- + + public long next64() + { + if (end > 0 && next >= end - stride || next >= Long.MAX_VALUE - stride) + { + throw new RuntimeException( + "Handle space (2^64 handles / stride (" + stride + ")) exhausted."); + } + + next += stride; + return next; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/util/HandleMap.java b/libs/java_utils/src/com/norswap/util/HandleMap.java similarity index 99% rename from src/com/norswap/autumn/util/HandleMap.java rename to libs/java_utils/src/com/norswap/util/HandleMap.java index 11e6e08..9fbeed9 100644 --- a/src/com/norswap/autumn/util/HandleMap.java +++ b/libs/java_utils/src/com/norswap/util/HandleMap.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; public final class HandleMap implements DeepCopy { diff --git a/libs/java_utils/src/com/norswap/util/IO.java b/libs/java_utils/src/com/norswap/util/IO.java new file mode 100644 index 0000000..1c4cc9e --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/IO.java @@ -0,0 +1,26 @@ +package com.norswap.util; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +public final class IO +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Reads a complete file and returns its contents as a string. + */ + public static String readFile(String file) + { + try { + return new String(Files.readAllBytes(Paths.get(file))); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/util/MultiMap.java b/libs/java_utils/src/com/norswap/util/MultiMap.java similarity index 98% rename from src/com/norswap/autumn/util/MultiMap.java rename to libs/java_utils/src/com/norswap/util/MultiMap.java index c100213..b63beec 100644 --- a/src/com/norswap/autumn/util/MultiMap.java +++ b/libs/java_utils/src/com/norswap/util/MultiMap.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.util.Collections; import java.util.HashMap; diff --git a/src/com/norswap/autumn/util/MultiSet.java b/libs/java_utils/src/com/norswap/util/MultiSet.java similarity index 97% rename from src/com/norswap/autumn/util/MultiSet.java rename to libs/java_utils/src/com/norswap/util/MultiSet.java index c5d0c2a..f3175aa 100644 --- a/src/com/norswap/autumn/util/MultiSet.java +++ b/libs/java_utils/src/com/norswap/util/MultiSet.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.util.HashMap; diff --git a/src/com/norswap/autumn/util/Pair.java b/libs/java_utils/src/com/norswap/util/Pair.java similarity index 96% rename from src/com/norswap/autumn/util/Pair.java rename to libs/java_utils/src/com/norswap/util/Pair.java index cb5a275..44d816d 100644 --- a/src/com/norswap/autumn/util/Pair.java +++ b/libs/java_utils/src/com/norswap/util/Pair.java @@ -1,5 +1,8 @@ -package com.norswap.autumn.util; +package com.norswap.util; +/** + * A pair of items. + */ public class Pair implements Cloneable { //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/util/Streams.java b/libs/java_utils/src/com/norswap/util/Streams.java similarity index 93% rename from src/com/norswap/autumn/util/Streams.java rename to libs/java_utils/src/com/norswap/util/Streams.java index 06ab0b6..e407c83 100644 --- a/src/com/norswap/autumn/util/Streams.java +++ b/libs/java_utils/src/com/norswap/util/Streams.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; import java.util.stream.Stream; import java.util.stream.StreamSupport; diff --git a/src/com/norswap/autumn/util/StringEscape.java b/libs/java_utils/src/com/norswap/util/StringEscape.java similarity index 99% rename from src/com/norswap/autumn/util/StringEscape.java rename to libs/java_utils/src/com/norswap/util/StringEscape.java index a920798..8d70961 100644 --- a/src/com/norswap/autumn/util/StringEscape.java +++ b/libs/java_utils/src/com/norswap/util/StringEscape.java @@ -1,4 +1,4 @@ -package com.norswap.autumn.util; +package com.norswap.util; public final class StringEscape { diff --git a/libs/java_utils/src/com/norswap/util/Strings.java b/libs/java_utils/src/com/norswap/util/Strings.java new file mode 100644 index 0000000..dca4183 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/Strings.java @@ -0,0 +1,9 @@ +package com.norswap.util; + +public final class Strings +{ + public static String times(int n, String string) + { + return new String(new char[n]).replace("\0", string); + } +} diff --git a/libs/java_utils/src/com/norswap/util/Two.java b/libs/java_utils/src/com/norswap/util/Two.java new file mode 100644 index 0000000..4d6335c --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/Two.java @@ -0,0 +1,12 @@ +package com.norswap.util; + +/** + * A pair of items of the same type. + */ +public class Two extends Pair +{ + public Two(T one, T two) + { + super(one, two); + } +} diff --git a/libs/java_utils/src/com/norswap/util/graph_visit/GraphTransformer.java b/libs/java_utils/src/com/norswap/util/graph_visit/GraphTransformer.java new file mode 100644 index 0000000..04d22b5 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/graph_visit/GraphTransformer.java @@ -0,0 +1,84 @@ +package com.norswap.util.graph_visit; + +import com.norswap.util.slot.Slot; + +import java.util.HashMap; +import java.util.function.Function; + +/** + * A graph transformer is a graph visitor which transforms its graph (using the slots mechanism). To + * that effect it defines one abstract method ({@link #transform}) which is called from {@link + * #afterChild} and {@link #afterRoot} to effect the change. + *

+ * You can override all the graph visitor callbacks, but you should always call the super method + * within your overrides. + *

+ * The {@link GraphTransformer.Unique} nested class adds an additional feature: the transformation + * of each node is computed exactly once and then cached, meaning that only one transformation will + * be performed, even if the node has multiple parents. + */ +public abstract class GraphTransformer extends GraphVisitor +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static GraphTransformer from(Function f, GraphWalker walker) + { + return new GraphTransformer(walker) + { + @Override + public Node transform(Node node) + { + return f.apply(node); + } + }; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public GraphTransformer(GraphWalker walker) + { + super(walker); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static abstract class Unique extends GraphTransformer + { + private HashMap transformations = new HashMap<>(); + + public Unique(GraphWalker walker) + { + super(walker); + } + + @Override + public final Node transform(Node node) + { + return transformations.computeIfAbsent(node, this::doTransform); + } + + protected abstract Node doTransform(Node node); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public abstract Node transform(Node node); + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void afterChild(Node parent, Slot slot, NodeState state) + { + slot.set(transform(slot.get())); + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void afterRoot(Slot slot, NodeState state) + { + slot.set(transform(slot.get())); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/libs/java_utils/src/com/norswap/util/graph_visit/GraphVisitor.java b/libs/java_utils/src/com/norswap/util/graph_visit/GraphVisitor.java new file mode 100644 index 0000000..0f68dc5 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/graph_visit/GraphVisitor.java @@ -0,0 +1,195 @@ +package com.norswap.util.graph_visit; + +import com.norswap.util.Array; +import com.norswap.util.slot.ListSlot; +import com.norswap.util.slot.SelfSlot; +import com.norswap.util.slot.Slot; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.norswap.util.graph_visit.NodeState.*; + +/** + * A graph visit defines a visit of a graph made of nodes with type {@code Node}. + *

+ * The visit is defined via a set of callbacks invoked at various point of the visit, namely {@link + * #before}, {@link #afterChild}, {@link #after}, {@link #afterRoot} and {@link #conclude}. + *

+ * Lookup the documentation of {@link NodeState} to understand this parameter in the callbacks. + *

+ * Some of the callback's parameter are wrapped in a {@link Slot} object. A slot combines a way to + * retrieve a node with a consumer of node. In general a slot is meant as an assignable location. It + * enables modifying the the graph in-place, or building a copy of the graph on the fly. + *

+ * The visit is started by calling {@link #visit(Node)} (single root) or {@link + * #visit(Collection)} (multiple roots). It is also possible to perform incremental visits by + * repeatedly calling the {@link #partialVisit} methods. In the case of an incremental visit, {@link + * #conclude} must be called manually. + *

+ * A visitor is parameterized by a {@link GraphWalker} which indicates what the children of a node + * are (i.e. the nodes connected to links outgoing from the node) and optionally how to modify the + * graph (by supplying appropriate slot objects). + */ +public abstract class GraphVisitor +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public final GraphWalker walker; + + private Map states = new HashMap<>(); + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public GraphVisitor(GraphWalker walker) + { + this.walker = walker; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Called when a node is visited, before attempting to visit its children. + *

+ * This method has no state parameter, because its value would always be {@code FIRST_VISIT}. + */ + public void before(Node node) {} + + // --------------------------------------------------------------------------------------------- + + /** + * Called after attempting to visit each child of {@code parent}. + * The child is held in {@code slot}. + * The slot can be used to replace this child within its parent. + */ + public void afterChild(Node parent, Slot slot, NodeState state) {} + + // --------------------------------------------------------------------------------------------- + + /** + * Called after we have attempted to visit all the children of the node. + *

+ * Possible values for {@code state}: {@code FIRST_VISIT}, {@code FIRST_VISIT_CYCLIC}, {@code + * FIRST_VISIT_CUTOFF}. + */ + public void after(Node node, List> children, NodeState state) {} + + // --------------------------------------------------------------------------------------------- + + /** + * Called after attempting to visit a root node. + * The node is held in the slot, which can used to replace the root node. + *

+ * Possible values for {@code state}: all except {@code CUTOFF}. + */ + public void afterRoot(Slot slot, NodeState state) {} + + // --------------------------------------------------------------------------------------------- + + /** + * Called after the walk has concluded (all the roots have been visited). If you are performing + * an incremental walk, you must call this method yourself. + */ + public void conclude() {} + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public final Node visit(Node node) + { + Slot out = partialVisit(node); + conclude(); + states = null; + return out.get(); + } + + // --------------------------------------------------------------------------------------------- + + public final Collection visit(Collection nodes) + { + Collection out = partialVisit(nodes); + conclude(); + states = null; + return out; + } + + // --------------------------------------------------------------------------------------------- + + public final Slot partialVisit(Node node) + { + Slot slot = new SelfSlot<>(node); + afterRoot(slot, walk(node)); + return slot; + } + + // --------------------------------------------------------------------------------------------- + + public final Collection partialVisit(Collection nodes) + { + Array container = new Array<>(nodes.size()); + + int i = 0; + for (Node node: nodes) + { + afterRoot(new ListSlot<>(container, i++).set(node), walk(node)); + } + + return container; + } + + // --------------------------------------------------------------------------------------------- + + private NodeState walk(Node node) + { + switch (states.getOrDefault(node, FIRST_VISIT)) + { + case FIRST_VISIT: + states.put(node, CUTOFF); + break; + + // Don't enter the node twice. + + case CUTOFF: + states.put(node, FIRST_VISIT_CUTOFF); + return CUTOFF; + + case FIRST_VISIT_CYCLIC: + states.put(node, FIRST_VISIT_CUTOFF); + return CUTOFF; + + case FIRST_VISIT_CUTOFF: + return CUTOFF; + + case VISITED: + return VISITED; + } + + before(node); + + List> children = walker.children(node, this); + + boolean cyclic = false; + + for (Slot child: children) + { + NodeState childState = walk(child.get()); + cyclic = cyclic || childState == FIRST_VISIT_CYCLIC || childState == FIRST_VISIT_CUTOFF; + afterChild(node, child, childState); + } + + NodeState out = states.get(node); + + if (out == CUTOFF) + { + out = cyclic ? FIRST_VISIT_CYCLIC : FIRST_VISIT; + } + + after(node, children, out); + states.put(node, VISITED); + + return out; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/libs/java_utils/src/com/norswap/util/graph_visit/GraphWalker.java b/libs/java_utils/src/com/norswap/util/graph_visit/GraphWalker.java new file mode 100644 index 0000000..bbc91c1 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/graph_visit/GraphWalker.java @@ -0,0 +1,18 @@ +package com.norswap.util.graph_visit; + +import com.norswap.util.slot.Slot; + +import java.util.List; + +/** + * Indicates how to acquire the children of a node; i.e. the nodes connected to links outgoing from + * the node. + *

+ * It is also responsible of indicating how graph transformations are to be done (if any) by + * wrapping the nodes in adequate slot objects. + */ +@FunctionalInterface +public interface GraphWalker +{ + List> children(Node node, GraphVisitor visitor); +} diff --git a/libs/java_utils/src/com/norswap/util/graph_visit/NodeState.java b/libs/java_utils/src/com/norswap/util/graph_visit/NodeState.java new file mode 100644 index 0000000..a5c415b --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/graph_visit/NodeState.java @@ -0,0 +1,38 @@ +package com.norswap.util.graph_visit; + +/** + * Possible states of a node in a graph being visited, whenever a method of {@link GraphVisitor} is + * called. + *

+ * Conceptually, {@link #FIRST_VISIT_CUTOFF} implies {@link #FIRST_VISIT_CYCLIC}, which implies + * {@link #FIRST_VISIT}. The most specific version is always used. + */ +public enum NodeState +{ + /** + * The node has just been visited for the first time. + */ + FIRST_VISIT, + + /** + * The node has just been visited for the first time, and it is part of at least one cycle. + */ + FIRST_VISIT_CYCLIC, + + /** + * The node has just been visited for the first time, and it is part of at least one cycle. + * One or more of these cycles was cutoff at this node during the walk. + */ + FIRST_VISIT_CUTOFF, + + /** + * The node has already been visited earlier in the walk. + */ + VISITED, + + /** + * The node is currently being visited. This means we have encountered a cycle in the graph + * and that have fully walked this cycle. + */ + CUTOFF +} diff --git a/libs/java_utils/src/com/norswap/util/lambda/F0.java b/libs/java_utils/src/com/norswap/util/lambda/F0.java new file mode 100644 index 0000000..4eb9f2a --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/lambda/F0.java @@ -0,0 +1,8 @@ +package com.norswap.util.lambda; + +import java.util.function.Supplier; + +@FunctionalInterface +public interface F0 extends Supplier +{ +} diff --git a/libs/java_utils/src/com/norswap/util/lambda/F1.java b/libs/java_utils/src/com/norswap/util/lambda/F1.java new file mode 100644 index 0000000..c401309 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/lambda/F1.java @@ -0,0 +1,12 @@ +package com.norswap.util.lambda; + +import java.util.function.Function; + +@FunctionalInterface +public interface F1 extends Function +{ + default F0 curry(T t) + { + return () -> apply(t); + } +} diff --git a/libs/java_utils/src/com/norswap/util/lambda/F2.java b/libs/java_utils/src/com/norswap/util/lambda/F2.java new file mode 100644 index 0000000..0133f97 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/lambda/F2.java @@ -0,0 +1,17 @@ +package com.norswap.util.lambda; + +import java.util.function.BiFunction; + +@FunctionalInterface +public interface F2 extends BiFunction +{ + default F1 curry(T1 t1) + { + return x -> apply(t1, x); + } + + default F1 curry2(T2 t2) + { + return x -> apply(x, t2); + } +} diff --git a/libs/java_utils/src/com/norswap/util/lambda/F3.java b/libs/java_utils/src/com/norswap/util/lambda/F3.java new file mode 100644 index 0000000..3d86b5d --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/lambda/F3.java @@ -0,0 +1,22 @@ +package com.norswap.util.lambda; + +@FunctionalInterface +public interface F3 +{ + R apply(T1 t1, T2 t2, T3 t3); + + default F2 curry(T1 t1) + { + return (x, y) -> apply(t1, x, y); + } + + default F2 curry2(T2 t2) + { + return (x, y) -> apply(x, t2, y); + } + + default F2 curry3(T3 t3) + { + return (x, y) -> apply(x, y, t3); + } +} \ No newline at end of file diff --git a/libs/java_utils/src/com/norswap/util/lambda/F4.java b/libs/java_utils/src/com/norswap/util/lambda/F4.java new file mode 100644 index 0000000..d7d3c7c --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/lambda/F4.java @@ -0,0 +1,27 @@ +package com.norswap.util.lambda; + +@FunctionalInterface +public interface F4 +{ + R apply(T1 t1, T2 t2, T3 t3, T4 t4); + + default F3 curry(T1 t1) + { + return (x, y, z) -> apply(t1, x, y, z); + } + + default F3 curry2(T2 t2) + { + return (x, y, z) -> apply(x, t2, y, z); + } + + default F3 curry3(T3 t3) + { + return (x, y, z) -> apply(x, y, t3, z); + } + + default F3 curry4(T4 t4) + { + return (x, y, z) -> apply(x, y, z, t4); + } +} diff --git a/libs/java_utils/src/com/norswap/util/slot/ArraySlot.java b/libs/java_utils/src/com/norswap/util/slot/ArraySlot.java new file mode 100644 index 0000000..3b53d7e --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/slot/ArraySlot.java @@ -0,0 +1,29 @@ +package com.norswap.util.slot; + +/** + * * A slot corresponding to an array position. + */ +public class ArraySlot implements Slot +{ + public final T[] array; + public final int index; + + public ArraySlot(T[] list, int index) + { + this.array = list; + this.index = index; + } + + @Override + public Slot set(T t) + { + array[index] = t; + return this; + } + + @Override + public T get() + { + return array[index]; + } +} diff --git a/libs/java_utils/src/com/norswap/util/slot/ImmutableSlot.java b/libs/java_utils/src/com/norswap/util/slot/ImmutableSlot.java new file mode 100644 index 0000000..b18a7a3 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/slot/ImmutableSlot.java @@ -0,0 +1,26 @@ +package com.norswap.util.slot; + +/** + * A immutable (non-settable) slot. + */ +public class ImmutableSlot implements Slot +{ + T t; + + public ImmutableSlot(T t) + { + this.t = t; + } + + @Override + public Slot set(T t) + { + throw new UnsupportedOperationException("Trying to set an immutable slot."); + } + + @Override + public T get() + { + return t; + } +} diff --git a/libs/java_utils/src/com/norswap/util/slot/ListSlot.java b/libs/java_utils/src/com/norswap/util/slot/ListSlot.java new file mode 100644 index 0000000..32055c2 --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/slot/ListSlot.java @@ -0,0 +1,31 @@ +package com.norswap.util.slot; + +import java.util.List; + +/** + * A slot corresponding to a list position. + */ +public final class ListSlot implements Slot +{ + public final List list; + public final int index; + + public ListSlot(List list, int index) + { + this.list = list; + this.index = index; + } + + @Override + public Slot set(T t) + { + list.set(index, t); + return this; + } + + @Override + public T get() + { + return list.get(index); + } +} diff --git a/libs/java_utils/src/com/norswap/util/slot/SelfSlot.java b/libs/java_utils/src/com/norswap/util/slot/SelfSlot.java new file mode 100644 index 0000000..e270a2c --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/slot/SelfSlot.java @@ -0,0 +1,28 @@ +package com.norswap.util.slot; + +/** + * A slot that encapsulates its value. + * This is classic indirection. + */ +public class SelfSlot implements Slot +{ + private T t; + + public SelfSlot(T t) + { + this.t = t; + } + + @Override + public Slot set(T t) + { + this.t = t; + return this; + } + + @Override + public T get() + { + return t; + } +} diff --git a/libs/java_utils/src/com/norswap/util/slot/Slot.java b/libs/java_utils/src/com/norswap/util/slot/Slot.java new file mode 100644 index 0000000..83238aa --- /dev/null +++ b/libs/java_utils/src/com/norswap/util/slot/Slot.java @@ -0,0 +1,10 @@ +package com.norswap.util.slot; + +/** + * A slot is an assignable location for a value of type T. + */ +public interface Slot +{ + Slot set(T t); + T get(); +} diff --git a/makefile b/makefile index f851d22..8956473 100644 --- a/makefile +++ b/makefile @@ -1,47 +1,3 @@ -# NOTE(norswap): The quotes around "deps/*" are necessary to avoid shell -# wildcard expansion. The wildcard must be processed by javac. - t?=com.norswap.autumn.test.Main -o?=build -a?= - -OUTDIR=out/$o -DEBUG= - -ifeq ($(OS),Windows_NT) - SEP=; -else - SEP=: -endif - -ifeq ($o,debug) - DEBUG=-g -else ifeq ($o,opti) - DEBUG=-g:none -endif - -build: outdir - cp -R resources/* $(OUTDIR) - javac -Xlint:unchecked $(DEBUG) -d $(OUTDIR) -cp "deps/*" `find src -name *.java` - -run: - java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" $t $a - -debug: - java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" com.norswap.autumn.parsing.debug.GUI $a - -trace: - java -cp "$(OUTDIR)$(SEP)deps/*$(SEP)$(OUTDIR)/resources" -agentlib:hprof=cpu=samples $t $a - -clean: - rm -rf $(OUTDIR) - -outdir: - mkdir -p $(OUTDIR) - -.PHONY: \ - build \ - clean \ - run \ - trace \ - outdir +LIBS=libs/java_utils/src +include library.mk diff --git a/resources/debugger/firebug-lite.js b/resources/debugger/firebug-lite.js index cf75aab..890e2b4 100644 --- a/resources/debugger/firebug-lite.js +++ b/resources/debugger/firebug-lite.js @@ -1832,8 +1832,7 @@ var firebug = { }, mouse:function(_event){ with(firebug){ - - // TODO: xxxpedro + if(d.inspector.enabled){ var target; var borderInspector = el.borderInspector.environment.getElement(); diff --git a/resources/debugger/jquery.js b/resources/debugger/jquery.js index eed1777..0108454 100644 --- a/resources/debugger/jquery.js +++ b/resources/debugger/jquery.js @@ -3716,7 +3716,7 @@ var data_user = new Data(); // 2. Improve the module's maintainability by reducing the storage // paths to a single mechanism. // 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 4. _Never_ expose "private" data to user code // 5. Avoid exposing implementation details on user objects (eg. expando properties) // 6. Provide a clear path for implementation upgrade to WeakMap in 2014 @@ -3765,8 +3765,7 @@ jQuery.extend({ data_user.remove( elem, name ); }, - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to data_priv methods, these can be deprecated. + _data: function( elem, name, data ) { return data_priv.access( elem, name, data ); }, diff --git a/src/com/norswap/autumn/Autumn.java b/src/com/norswap/autumn/Autumn.java new file mode 100644 index 0000000..03d6eb9 --- /dev/null +++ b/src/com/norswap/autumn/Autumn.java @@ -0,0 +1,284 @@ +package com.norswap.autumn; + +import com.norswap.autumn.parsing.config.DefaultErrorHandler; +import com.norswap.autumn.parsing.config.DefaultMemoHandler; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.config.ErrorStrategy; +import com.norswap.autumn.parsing.ParseException; +import com.norswap.autumn.parsing.ParseResult; +import com.norswap.autumn.parsing.Parser; +import com.norswap.autumn.parsing.config.MemoStrategy; +import com.norswap.autumn.parsing.config.ParserConfiguration; +import com.norswap.autumn.parsing.Source; +import com.norswap.autumn.parsing.Whitespace; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.autumn.parsing.graph.Printer; +import com.norswap.autumn.parsing.graph.Replacer; +import com.norswap.autumn.parsing.graph.LeftRecursionDetector; +import com.norswap.autumn.parsing.graph.ReferenceResolver; +import com.norswap.autumn.parsing.support.GrammarCompiler; +import com.norswap.autumn.parsing.support.GrammarGrammar; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; + +public class Autumn +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * {@code parseSource(grammarFromFile(grammarFile), Source.fromFile(string), ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseString(String grammarFile, String string) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), Source.fromFile(string), ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammarFromFile(grammarFile), Source.fromFile(string), config)} + */ + public static ParseResult parseString(String grammarFile, String string, ParserConfiguration config) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), Source.fromFile(string), config); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammar, Source.fromString(string), ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseString(Grammar grammar, String string) + { + return parseSource(grammar, Source.fromString(string), ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammar, Source.fromString(string), config)} + */ + public static ParseResult parseString(Grammar grammar, String string, ParserConfiguration config) + { + return parseSource(grammar, Source.fromString(string), config); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * {@code parseSource(grammarFromFile(grammarFile), Source.fromFile(inputFile), ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseFile(String grammarFile, String inputFile) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), Source.fromFile(inputFile), ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammarFromFile(grammarFile), Source.fromFile(inputFile), config)} + */ + public static ParseResult parseFile(String grammarFile, String inputFile, ParserConfiguration config) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), Source.fromFile(inputFile), config); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammar, Source.fromFile(inputFile), ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseFile(Grammar grammar, String inputFile) + throws IOException + { + return parseSource(grammar, Source.fromFile(inputFile), ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammar, Source.fromFile(inputFile), config)} + */ + public static ParseResult parseFile(Grammar grammar, String inputFile, ParserConfiguration config) + throws IOException + { + return parseSource(grammar, Source.fromFile(inputFile), config); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * {@code parseSource(grammarFromFile(grammarFile), source, ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseSource(String grammarFile, Source source) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), source, ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammarFromFile(grammarFile), source, config)} + */ + public static ParseResult parseSource(String grammarFile, Source source, ParserConfiguration config) + throws IOException + { + return parseSource(grammarFromFile(grammarFile), source, config); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code parseSource(grammar, source, ParserConfiguration.DEFAULT)} + */ + public static ParseResult parseSource(Grammar grammar, Source source) + { + return parseSource(grammar, source, ParserConfiguration.DEFAULT); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Parse the given source, using the given grammar and the given parser configuration. + * + * TODO + */ + public static ParseResult parseSource(Grammar grammar, Source source, ParserConfiguration config) + { + return Parser.parse(grammar, source, config); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * {@code return grammarFromSource(Source.fromFile(grammarFile));} + */ + public static Grammar grammarFromFile(String grammarFile) throws IOException + { + return grammarFromSource(Source.fromFile(grammarFile)); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code return grammarFromSource(Source.fromString(grammarString));} + */ + public static Grammar grammarFromString(String grammarString) + { + return grammarFromSource(Source.fromString(grammarString)); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Parses and compiles the grammar specification contained in the passed source. + * + * TODO exceptions + */ + public static Grammar grammarFromSource(Source source) + { + ParseResult result = Parser.parse(GrammarGrammar.grammar, source); + + if (!result.matched) + { + throw new ParseException(result.error); + } + else + { + return GrammarCompiler.compile(result.tree); + } + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code return grammarFromExpression(pe, Collections.emptyList(), whitespace, true);} + */ + public static Grammar grammarFromExpression(ParsingExpression pe, ParsingExpression whitespace) + { + return grammarFromExpression(pe, Collections.emptyList(), whitespace, true, true); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code return grammarFromExpression(pe, Collections.emptyList(), Whitespace.DEFAULT(), true);} + */ + public static Grammar grammarFromExpression(ParsingExpression pe) + { + return grammarFromExpression(pe, Collections.emptyList(), Whitespace.DEFAULT(), true, true); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Make a new grammar given a root, a collection of rules, a whitespace expression and an + * indication whether to match whitespace at the start of the input. + *

+ * The rule set can be empty. The semantics are the same whether the rule set include the root + * and the whitespace expression (or either) or not. + * + * TODO preprocess in grammar + */ + public static Grammar grammarFromExpression( + ParsingExpression root, + Collection rules, + ParsingExpression whitespace, + boolean processLeadingWhitespace, + boolean preprocess) + { + Grammar grammar = new Grammar(root, rules, whitespace, processLeadingWhitespace); + + if (preprocess) + { + grammar.walk(new ReferenceResolver()); + + LeftRecursionDetector detector = new LeftRecursionDetector(grammar); + grammar.walk(detector); + + grammar.walk(new Replacer(detector.leftRecursives)); + } + + return grammar; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * {@code return new ParserConfiguration(errorStrat, DefaultMemoizationStrategy::new);} + */ + public static ParserConfiguration configuration(ErrorStrategy errorStrat) + { + return new ParserConfiguration(errorStrat, DefaultMemoHandler::new); + } + + // --------------------------------------------------------------------------------------------- + + /** + * {@code return new ParserConfiguration(DefaultErrorHandler::new, memoStrat);} + */ + public static ParserConfiguration configuration(MemoStrategy memoStrat) + { + return new ParserConfiguration(DefaultErrorHandler::new, memoStrat); + } + + // --------------------------------------------------------------------------------------------- + + /** + * Make a new configuration using the supplied error handling strategy and memoization strategy. + * This configuration can be shared between parsers. + */ + public static ParserConfiguration configuration(ErrorStrategy errorStrat, MemoStrategy memoStrat) + { + return new ParserConfiguration(errorStrat, memoStrat); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/ErrorHandler.java b/src/com/norswap/autumn/parsing/ErrorHandler.java deleted file mode 100644 index 1571579..0000000 --- a/src/com/norswap/autumn/parsing/ErrorHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.norswap.autumn.parsing; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -public interface ErrorHandler -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Indicates that the given expression failed with the given state. - */ - void handle(ParsingExpression pe, ParseState state); - - // --------------------------------------------------------------------------------------------- - - void reportErrors(Parser parser); - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/Grammar.java b/src/com/norswap/autumn/parsing/Grammar.java new file mode 100644 index 0000000..6b81995 --- /dev/null +++ b/src/com/norswap/autumn/parsing/Grammar.java @@ -0,0 +1,163 @@ +package com.norswap.autumn.parsing; + +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.autumn.parsing.graph.NullabilityCalculator; +import com.norswap.util.graph_visit.GraphVisitor; +import com.norswap.util.slot.Slot; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A user-facing representation of the grammar, which is the union of a parsing + * expression and some options. + * + * Convenient factory methods are available in class {@link Autumn}. + */ +public final class Grammar +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + private ParsingExpression root; + + private ParsingExpression whitespace; + + private boolean processLeadingWhitespace; + + private Collection rules; + + private Map rulesByName; + + private NullabilityCalculator nullabilityCalculator; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * See the documentation of getters. + * + * {@code rules} is the set of rules in the grammar (including the root), can be null if + * only the root is to be considered. + */ + public Grammar( + ParsingExpression root, + Collection rules, + ParsingExpression whitespace, + boolean processLeadingWhitespace) + { + this.root = root; + this.rules = rules == null ? Collections.emptyList() : rules; + this.whitespace = whitespace; + this.processLeadingWhitespace = processLeadingWhitespace; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * The parsing expression that defines the grammar. + */ + public ParsingExpression root() + { + return root; + } + + // --------------------------------------------------------------------------------------------- + + /** + * The parsing expression to use as whitespace (used for whitespace expressions, and after + * token expressions). + */ + public ParsingExpression whitespace() + { + return whitespace; + } + + // --------------------------------------------------------------------------------------------- + + /** + * Whether leading whitespace should be skipped when parsing. + */ + public boolean processLeadingWhitespace() + { + return processLeadingWhitespace; + } + + // --------------------------------------------------------------------------------------------- + + /** + * The rules contained within the grammar. These usually have a name, and usually include the + * root (and sometimes the whitespace); but those are not absolute requirements. This is never + * null be can be empty. + * + * For grammar created from grammar files, these are all the rules defined within the grammar + * file (so there won't be a rule for the whitespace if the default whitespace specification is + * used). + */ + public Collection rules() + { + return rules; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Returns the rule with the given name, if any, null otherwise. + */ + public ParsingExpression getRule(String name) + { + if (rules == null) + { + return null; + } + + if (rulesByName == null) + { + rulesByName = new HashMap<>(); + + rules.forEach( + pe -> { + String key = pe.name(); + + if (key != null) + { + rulesByName.put(pe.name(), pe); + } + }); + } + + return rulesByName.get(name); + } + + // --------------------------------------------------------------------------------------------- + + public Grammar walk(GraphVisitor visitor) + { + Slot newRoot = visitor.partialVisit(root); + Collection newRules = visitor.partialVisit(rules); + Slot newWhitespace = visitor.partialVisit(whitespace); + + visitor.conclude(); + + root = newRoot.get(); + rules = newRules; + whitespace = newWhitespace.get(); + return this; + } + + // --------------------------------------------------------------------------------------------- + + public boolean isNullable(ParsingExpression pe) + { + if (nullabilityCalculator == null) + { + nullabilityCalculator = new NullabilityCalculator(this); + walk(nullabilityCalculator); + } + + return nullabilityCalculator.isNullable(pe); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/IncrementalReferenceResolver.java b/src/com/norswap/autumn/parsing/IncrementalReferenceResolver.java index 27970dd..7fb6657 100644 --- a/src/com/norswap/autumn/parsing/IncrementalReferenceResolver.java +++ b/src/com/norswap/autumn/parsing/IncrementalReferenceResolver.java @@ -2,8 +2,8 @@ import com.norswap.autumn.parsing.expressions.Reference; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; -import com.norswap.autumn.util.Caster; +import com.norswap.util.Array; +import com.norswap.util.Caster; import java.util.HashSet; diff --git a/src/com/norswap/autumn/parsing/MemoizationStrategy.java b/src/com/norswap/autumn/parsing/MemoizationStrategy.java deleted file mode 100644 index 99e6560..0000000 --- a/src/com/norswap/autumn/parsing/MemoizationStrategy.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.norswap.autumn.parsing; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -public interface MemoizationStrategy -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - void memoize(ParsingExpression pe, ParseState state, OutputChanges changes); - - // --------------------------------------------------------------------------------------------- - - /** - * Return a memoized changeset; or null if no such changeset has been memoized. - */ - OutputChanges get(ParsingExpression pe, ParseState state); - - // --------------------------------------------------------------------------------------------- - - /** - * Called to indicate that all memoized changesets between the start of the input and the - * indicated position will no longer be needed; they can thus be released. - */ - void cut(int position); - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/OutputChanges.java b/src/com/norswap/autumn/parsing/OutputChanges.java index 21cc80d..e5b5708 100644 --- a/src/com/norswap/autumn/parsing/OutputChanges.java +++ b/src/com/norswap/autumn/parsing/OutputChanges.java @@ -1,9 +1,7 @@ package com.norswap.autumn.parsing; -import com.norswap.autumn.util.Array; -import com.norswap.autumn.util.HandleMap; - -import java.util.function.Supplier; +import com.norswap.util.Array; +import com.norswap.util.HandleMap; public final class OutputChanges { @@ -11,7 +9,7 @@ public final class OutputChanges public int end; public int blackEnd; - public ParseTree tree; + public Array children; public Array cuts; public HandleMap ext; @@ -37,14 +35,12 @@ public OutputChanges(ParseState state) { this.end = state.end; this.blackEnd = state.blackEnd; - this.tree = new ParseTree(); + this.children = new Array<>(); this.cuts = new Array<>(); - Supplier x = "x"::toString; - for (int i = state.treeChildrenCount; i < state.tree.childrenCount(); ++i) { - this.tree.add(state.tree.children.get(i)); + this.children.add(state.tree.children.get(i)); } for (int i = state.cutsCount; i < state.cuts.size(); ++i) @@ -60,9 +56,9 @@ public void mergeInto(ParseState state) state.end = end; state.blackEnd = blackEnd; - if (tree != null) + if (children != null) { - state.tree.add(tree); + state.tree.addAll(children); } if (cuts != null) diff --git a/src/com/norswap/autumn/parsing/ParseError.java b/src/com/norswap/autumn/parsing/ParseError.java new file mode 100644 index 0000000..bb22d92 --- /dev/null +++ b/src/com/norswap/autumn/parsing/ParseError.java @@ -0,0 +1,19 @@ +package com.norswap.autumn.parsing; + +/** + * Encapsulate error information about the parse. + * + * A parse error may contain information about multiple errors. It may also refer to a successful + * parse (since errors are par for the course when parsing, they just cause backtracking). + * + * Implementations of this class can supply a wide variety of information, but the primary goal + * should be to help the programmer find and fix errors by supplying an helpful error message. + */ +public interface ParseError +{ + /** + * A message fit to be displayed to the user, detailing (some of) the error(s) that occured + * during the parse, and optionally hints about how to fix or diagnose them. + */ + String message(); +} diff --git a/src/com/norswap/autumn/parsing/ParseException.java b/src/com/norswap/autumn/parsing/ParseException.java new file mode 100644 index 0000000..6fd4aa0 --- /dev/null +++ b/src/com/norswap/autumn/parsing/ParseException.java @@ -0,0 +1,20 @@ +package com.norswap.autumn.parsing; + +/** + * TODO + */ +public final class ParseException extends RuntimeException +{ + public final ParseError error; + + public ParseException(ParseError error) + { + this.error = error; + } + + @Override + public String getMessage() + { + return error.message(); + } +} diff --git a/src/com/norswap/autumn/parsing/ParseResult.java b/src/com/norswap/autumn/parsing/ParseResult.java new file mode 100644 index 0000000..7f13fb3 --- /dev/null +++ b/src/com/norswap/autumn/parsing/ParseResult.java @@ -0,0 +1,60 @@ +package com.norswap.autumn.parsing; + +import com.norswap.util.HandleMap; + +/** + * [Immutable] The user-facing result of a parse. + */ +public final class ParseResult +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Whether the parse succeeded matching the whole input. + */ + public final boolean matched; + + /** + * Whether the parse succeeded matching a prefix (or all) of the input. + */ + public final boolean succeeded; + + /** + * The input position where the match ends. Equal to the input size if {@code matched}, + * undefined if {@code !succeeded}. + */ + public final int endPosition; + + /** + * The generated parse tree, or null if {@code !succeeded}. If you do not specify any captures + * in the grammar, this tree is empty when the parse succeeds. + */ + public final ParseTree tree; + + /** + * Additional, user-defined results. + */ + public final HandleMap ext; + + /** + * If {@code !matched}, holds error information and diagnostic about the parse. + * Undefined otherwise. + */ + public final ParseError error; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + ParseResult( + boolean matched, boolean succeeded, int endPosition, ParseTree tree, + HandleMap ext, ParseError error) + { + this.matched = matched; + this.succeeded = succeeded; + this.endPosition = endPosition; + this.tree = tree; + this.ext = ext; + this.error = error; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/ParseState.java b/src/com/norswap/autumn/parsing/ParseState.java index 6f87027..bc1a2a6 100644 --- a/src/com/norswap/autumn/parsing/ParseState.java +++ b/src/com/norswap/autumn/parsing/ParseState.java @@ -1,8 +1,8 @@ package com.norswap.autumn.parsing; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; -import com.norswap.autumn.util.HandleMap; +import com.norswap.util.Array; +import com.norswap.util.HandleMap; import static com.norswap.autumn.parsing.Registry.*; // PSF_* @@ -17,6 +17,9 @@ public final class ParseState public int flags; public Array seeds; + public String accessor; + public Array tags; + // output public int end; public int blackEnd; @@ -35,6 +38,7 @@ static ParseState root() ParseState root = new ParseState(); root.end = 0; root.blackEnd = 0; + root.tags = new Array<>(); root.cuts = new Array<>(); root.ext = new HandleMap(); return root; @@ -55,6 +59,8 @@ public ParseState(ParseState parent) this.precedence = parent.precedence; this.seeds = parent.seeds; this.flags = parent.flags; + this.accessor = parent.accessor; + this.tags = parent.tags; this.end = parent.end; this.blackEnd = parent.blackEnd; this.tree = parent.tree; @@ -130,7 +136,6 @@ public void advance() if (end > start) { seeds = null; - clearFlags(PSF_DONT_MEMOIZE_POSITION); } start = end; @@ -214,16 +219,9 @@ public void forbidMemoization() // --------------------------------------------------------------------------------------------- - public void forbidMemoizationAtPosition() - { - setFlags(PSF_DONT_MEMOIZE_POSITION); - } - - // --------------------------------------------------------------------------------------------- - public boolean isMemoizationForbidden() { - return hasFlagsSet(PSF_DONT_MEMOIZE | PSF_DONT_MEMOIZE_POSITION); + return hasFlagsSet(PSF_DONT_MEMOIZE); } // --------------------------------------------------------------------------------------------- @@ -240,6 +238,20 @@ public boolean isErrorRecordingForbidden() return hasFlagsSet(PSF_DONT_RECORD_ERRORS); } + // --------------------------------------------------------------------------------------------- + + public void setGroupingCapture() + { + setFlags(PSF_GROUPING_CAPTURE); + } + + // --------------------------------------------------------------------------------------------- + + public boolean isCaptureGrouping() + { + return hasFlagsSet(PSF_GROUPING_CAPTURE); + } + //////////////////////////////////////////////////////////////////////////////////////////////// // Generic Flag Manipulation Functions //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/ParseTree.java b/src/com/norswap/autumn/parsing/ParseTree.java index b2f4894..f78e85e 100644 --- a/src/com/norswap/autumn/parsing/ParseTree.java +++ b/src/com/norswap/autumn/parsing/ParseTree.java @@ -1,42 +1,43 @@ package com.norswap.autumn.parsing; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; +import com.norswap.util.Strings; import java.util.Collections; import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; -/** - * - name != null && !grouped : normal node - * - name != null && grouped : group capture - * - name == null : container - */ public final class ParseTree implements Iterable { //////////////////////////////////////////////////////////////////////////////////////////////// - public String name; + public String accessor; public String value; + public boolean group; + public Array tags; public Array children; - public boolean grouped; //////////////////////////////////////////////////////////////////////////////////////////////// - public ParseTree(){} + public ParseTree() {} - public ParseTree(String name) + public ParseTree(String accessor, Array tags, boolean group) { - this.name = name; + this.accessor = accessor; + this.tags = tags; + this.group = group; } //////////////////////////////////////////////////////////////////////////////////////////////// public int childrenCount() { - return children == null - ? 0 - : children.size(); + return children == null ? 0 : children.size(); } + // --------------------------------------------------------------------------------------------- + void truncateChildren(int childrenCount) { children.truncate(childrenCount); @@ -51,44 +52,19 @@ public void add(ParseTree child) children = new Array<>(); } - if (child.name == null) - { - if (child.children != null) - { - children.addAll(child.children); - } - } - else - { - children.add(child); - } + children.add(child); } // --------------------------------------------------------------------------------------------- - public void addGrouped(ParseTree child) + public void addAll(Iterable children) { - if (children == null) - { - children = new Array<>(); - } - - ParseTree container = getOrNull(child.name); - - if (container == null) - { - container = new ParseTree(child.name); - container.grouped = true; - container.children = new Array<>(); - children.add(container); - } - - container.children.add(child); + children.forEach(this::add); } // --------------------------------------------------------------------------------------------- - public ParseTree getOrNull(String name) + public ParseTree getOrNull(String accessor) { if (children == null) { @@ -97,7 +73,7 @@ public ParseTree getOrNull(String name) for (ParseTree child: children) { - if (name.equals(child.name)) + if (accessor.equals(child.accessor)) { return child; } @@ -108,14 +84,14 @@ public ParseTree getOrNull(String name) // --------------------------------------------------------------------------------------------- - public ParseTree get(String name) + public ParseTree get(String accessor) { - ParseTree node = getOrNull(name); + ParseTree node = getOrNull(accessor); if (node == null) { throw new RuntimeException( - "Node \"" + this.name + "\" doesn't have a child named \"" + name + "\""); + "Node \"" + this.accessor + "\" doesn't have a child named \"" + accessor + "\""); } return node; @@ -123,14 +99,14 @@ public ParseTree get(String name) // --------------------------------------------------------------------------------------------- - public String value(String name) + public String value(String accessor) { - ParseTree node = get(name); + ParseTree node = get(accessor); if (node.value == null) { throw new RuntimeException( - "Node \"" + name + "\" under node \"" + this.name + "\" doesn't have a value."); + "Node \"" + accessor + "\" under node \"" + this.accessor + "\" doesn't have a value."); } return node.value; @@ -138,33 +114,32 @@ public String value(String name) // --------------------------------------------------------------------------------------------- - public ParseTree group(String name) + public List group(String accessor) { - ParseTree node = get(name); + Array group = new Array<>(); - if (!node.grouped) + for (ParseTree child: children) { - throw new RuntimeException( - "Node \"" + name + "\" under node \"" + this.name + "\" isn't a group."); + if (accessor.equals(child.accessor)) + { + if (!child.group) + { + throw new RuntimeException( + "Node " + child.info() + " under node " + info() + " doesn't belong to a group."); + } + + group.add(child); + } } - return node; + return group; } // --------------------------------------------------------------------------------------------- public ParseTree child() { - if (children == null || children.size() == 0) - { - throw new RuntimeException("Node \"" + name + "\" doesn't have children."); - } - else if (children.size() != 1) - { - throw new RuntimeException("Node \"" + name + "\" has more than one child."); - } - - return children.get(0); + return child(0); } // --------------------------------------------------------------------------------------------- @@ -174,7 +149,7 @@ public ParseTree child(int i) if (children == null || children.size() <= i) { throw new RuntimeException( - "Node \"" + name + "\" doesn't have a child with index: " + i); + "Node " + info() + " doesn't have a child with index: " + i); } return children.get(i); @@ -182,22 +157,67 @@ public ParseTree child(int i) // --------------------------------------------------------------------------------------------- - public boolean has(String name) + public boolean has(String accessor) { - return getOrNull(name) != null; + return getOrNull(accessor) != null; + } + + // --------------------------------------------------------------------------------------------- + + public Iterable tagged(String tag) + { + // TODO array filter function + + return children.stream() + .filter(child -> child.hasTag(tag)) + .collect(Collectors.toCollection(() -> new Array<>())); + } + + // --------------------------------------------------------------------------------------------- + + public ParseTree tagged1(String tag) + { + for (ParseTree child: children) + { + if (child.hasTag(tag)) + { + return child; + } + } + + return null; + } + + // --------------------------------------------------------------------------------------------- + + public boolean hasTag(String tag) + { + return tags != null && tags.contains(tag); } //////////////////////////////////////////////////////////////////////////////////////////////// + public String info() + { + return String.format("[%s%s%s]", + accessor != null ? accessor : "", + accessor != null && tags != null ? " / " : "", + tags != null ? tags : ""); + } + + // --------------------------------------------------------------------------------------------- + @Override public String toString() { StringBuilder builder = new StringBuilder(); + int trailing = 0; - if (name != null) + if (accessor != null) { - builder.append(name); + builder.append(accessor); builder.append(": "); + trailing = 2; } if (children != null && !children.isEmpty()) @@ -215,19 +235,41 @@ public String toString() builder.setLength(builder.length() - 2); } - builder.append("]"); + builder.append("] "); + trailing = 1; } - else if (value != null) + + if (value != null) { - builder.append("\""); + builder.append(" \""); builder.append(value); - builder.append("\""); + builder.append("\" "); + trailing = 1; } - else if (name != null) + + if (tags != null && !tags.isEmpty()) { - builder.setLength(builder.length() - 2); + builder.append(" ("); + + for (String tag: tags) + { + builder.append(tag); + builder.append(", "); + } + + if (tags.size() > 0) + { + builder.setLength(builder.length() - 2); + } + + builder.append(") "); + trailing = 1; + } - else + + builder.setLength(builder.length() - trailing); + + if (trailing == 0) { builder.append("[]"); } @@ -248,30 +290,42 @@ public String toTreeString() public void toTreeString(StringBuilder builder, int depth) { - builder.append(new String(new char[depth]).replace("\0", "-|")); - builder.append(name != null ? name : "container"); - builder.append("\n"); + builder.append(Strings.times(depth, "-|")); - if (grouped) + if (accessor != null) { - int i = 0; - for (ParseTree child: children) + builder.append(accessor); + + if (tags == null && value != null) + { + builder.append(" - "); + } + else if (tags != null) { - builder.append(new String(new char[depth + 1]).replace("\0", "-|")); builder.append(" "); - builder.append(i); - builder.append("\n"); + } + } - if (child.children != null) - for (ParseTree grandChild: child.children) - { - grandChild.toTreeString(builder, depth + 2); - } + if (tags != null) + { + builder.append(tags); - ++i; + if (value != null) + { + builder.append(" - "); } } - else if (children != null) + + if (value != null) + { + builder.append("\""); + builder.append(value); + builder.append("\""); + } + + builder.append("\n"); + + if (children != null) { for (ParseTree child: children) { @@ -295,7 +349,7 @@ public Iterator iterator() @Override public boolean equals(Object o) { - // mostly auto-generated; modified to accept null children == empty children + // mostly auto-generated; reformated & modified to accept null == empty if (this == o) return true; @@ -303,20 +357,28 @@ public boolean equals(Object o) if (o == null || getClass() != o.getClass()) return false; - ParseTree parseTree = (ParseTree) o; + ParseTree pt = (ParseTree) o; + + if (group != pt.group) + return false; + + if (accessor != null ? !accessor.equals(pt.accessor) : pt.accessor != null) + return false; - if (grouped != parseTree.grouped) + if (value != null ? !value.equals(pt.value) : pt.value != null) return false; - if (name != null ? !name.equals(parseTree.name) : parseTree.name != null) + if (tags != null + ? !tags.equals(pt.tags) + : (pt.tags != null && !pt.tags.isEmpty())) return false; - if (value != null ? !value.equals(parseTree.value) : parseTree.value != null) + if (children != null + ? !children.equals(pt.children) + : (pt.children != null && !pt.children.isEmpty())) return false; - return children == null - ? parseTree.children == null || parseTree.children.isEmpty() - : children.equals(parseTree.children); + return true; } // --------------------------------------------------------------------------------------------- @@ -324,12 +386,13 @@ public boolean equals(Object o) @Override public int hashCode() { - // mostly auto-generated; modified to accept null children == empty children + // mostly auto-generated; reformated & modified to accept null empty - int result = name != null ? name.hashCode() : 0; + int result = accessor != null ? accessor.hashCode() : 0; result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + (tags == null || tags.isEmpty() ? 0 : tags.hashCode()); result = 31 * result + (children == null || children.isEmpty() ? 0 : children.hashCode()); - result = 31 * result + (grouped ? 1 : 0); + result = 31 * result + (group ? 1 : 0); return result; } diff --git a/src/com/norswap/autumn/parsing/Parser.java b/src/com/norswap/autumn/parsing/Parser.java index e4d810f..7cfc8c8 100644 --- a/src/com/norswap/autumn/parsing/Parser.java +++ b/src/com/norswap/autumn/parsing/Parser.java @@ -1,16 +1,21 @@ package com.norswap.autumn.parsing; +import com.norswap.autumn.parsing.config.ErrorHandler; +import com.norswap.autumn.parsing.config.MemoHandler; +import com.norswap.autumn.parsing.config.ParserConfiguration; import com.norswap.autumn.parsing.expressions.ExpressionCluster; import com.norswap.autumn.parsing.expressions.LeftRecursive; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; -import com.norswap.autumn.util.HandleMap; +import com.norswap.util.Array; +import com.norswap.util.HandleMap; public final class Parser { //////////////////////////////////////////////////////////////////////////////////////////////// - private Source source; + private Grammar grammar; + + public final Source source; public CharSequence text; @@ -33,26 +38,36 @@ public final class Parser public final ParsingExpression whitespace; - public final MemoizationStrategy memoizationStrategy; + public final MemoHandler memoHandler; public final boolean processLeadingWhitespace; //////////////////////////////////////////////////////////////////////////////////////////////// - public Parser(Source source, ParserConfiguration config) + public static ParseResult parse(Grammar grammar, Source source) { - this.source = source; - this.text = source.text(); + return new Parser(grammar, source, ParserConfiguration.DEFAULT).parse(grammar.root()); + } - this.errorHandler = config.errorHandler.get(); - this.whitespace = config.whitespace.get(); - this.memoizationStrategy = config.memoizationStrategy.get(); - this.processLeadingWhitespace = config.processLeadingWhitespace; + // --------------------------------------------------------------------------------------------- + + public static ParseResult parse(Grammar grammar, Source source, ParserConfiguration config) + { + return new Parser(grammar, source, config).parse(grammar.root()); } - public Parser(Source source) + //////////////////////////////////////////////////////////////////////////////////////////////// + + public Parser(Grammar grammar, Source source, ParserConfiguration config) { - this(source, ParserConfiguration.DEFAULT); + this.grammar = grammar; + this.source = source; + this.text = source.text(); + + this.errorHandler = config.errorHandler.get(); + this.memoHandler = config.memoizationStrategy.get(); + this.whitespace = grammar.whitespace(); + this.processLeadingWhitespace = grammar.processLeadingWhitespace(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -61,18 +76,20 @@ public Parser(Source source) * Use the parser to match its source text to the given parsing expression. * * After calling this method, the parse tree resulting from the parse can be retrieved via - * {@link #tree()}. + * {@blink #tree()}. * * If the parse failed ({@code failed() == true}) or a partial match ({@code - * matchedWholeSource() == false}), errors can be reported with {@link #report()}. + * matchedWholeSource() == false}), errors can be reported with report(). + * + * TODO change */ - public void parse(ParsingExpression pe) + public ParseResult parse(ParsingExpression pe) { this.blocked = new Array<>(); this.minPrecedence = new Array<>(); ParseState rootState = ParseState.root(); - rootState.tree = tree = new ParseTree(); + rootState.tree = tree = new ParseTree(null, null, false); if (processLeadingWhitespace) { @@ -90,62 +107,9 @@ public void parse(ParsingExpression pe) { rootState.resetAllOutput(); } - } - - //---------------------------------------------------------------------------------------------- - - /** - * Report the outcome of the parse (success or failure) on System.err and in case of failure, - * the errors recorded during the parse. The reporting method for the errors is up to the - * {@link ErrorHandler}. - */ - public void report() - { - if (succeeded()) - { - System.err.println("The parse succeeded."); - } - else - { - System.err.println("The parse failed."); - errorHandler.reportErrors(this); - } - } - - //---------------------------------------------------------------------------------------------- - - public Source source() - { - return source; - } - - //---------------------------------------------------------------------------------------------- - - public ParseTree tree() - { - return tree; - } - - //---------------------------------------------------------------------------------------------- - - public boolean succeeded() - { - return endPosition == source.length(); - } - - //---------------------------------------------------------------------------------------------- - - public boolean failed() - { - return endPosition != source.length(); - } - - //---------------------------------------------------------------------------------------------- - - public int endPosition() - { - return endPosition; + // TODO + return new ParseResult(endPosition == source.length(), endPosition >= 0, endPosition, tree, null, errorHandler.error(source)); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/ParserConfiguration.java b/src/com/norswap/autumn/parsing/ParserConfiguration.java deleted file mode 100644 index 35567d5..0000000 --- a/src/com/norswap/autumn/parsing/ParserConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.norswap.autumn.parsing; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.ReferenceResolver; - -import java.util.function.Supplier; - -public final class ParserConfiguration -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * The configuration a Parser will use by default if a configuration is not set explicitly. - */ - public static final ParserConfiguration DEFAULT = new ParserConfiguration(); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public Supplier errorHandler = DefaultErrorHandler::new; - - public Supplier whitespace = () -> - ReferenceResolver.resolve(Whitespace.whitespace.deepCopy()); - - public Supplier memoizationStrategy = DefaultMemoizationStrategy::new; - - public boolean processLeadingWhitespace = true; - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/ParsingExpressionFactory.java b/src/com/norswap/autumn/parsing/ParsingExpressionFactory.java index 9d18d80..cd48a73 100644 --- a/src/com/norswap/autumn/parsing/ParsingExpressionFactory.java +++ b/src/com/norswap/autumn/parsing/ParsingExpressionFactory.java @@ -1,12 +1,12 @@ package com.norswap.autumn.parsing; import com.norswap.autumn.parsing.expressions.*; +import com.norswap.autumn.parsing.expressions.ExpressionCluster.Group; import com.norswap.autumn.parsing.expressions.Whitespace; -import com.norswap.autumn.parsing.expressions.ExpressionCluster.Operand; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.util.Array; import java.util.Arrays; -import java.util.stream.Collectors; import static com.norswap.autumn.parsing.Registry.*; // PEF_* @@ -19,35 +19,154 @@ public static Any any() return new Any(); } - public static Capture capture(String captureName, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Capture capture(ParsingExpression operand) + { + return capture(false, operand); + } + + // --------------------------------------------------------------------------------------------- + + public static Capture captureText(ParsingExpression operand) + { + return capture(true, operand); + } + + // --------------------------------------------------------------------------------------------- + + public static Capture capture(boolean captureText, ParsingExpression operand) { Capture result = new Capture(); - result.name = captureName; result.operand = operand; + result.setFlags(PEF_CAPTURE | (captureText ? PEF_CAPTURE_TEXT : 0)); return result; } - public static Capture captureGrouped(String captureName, ParsingExpression operand) + // TODO start compat + + // --------------------------------------------------------------------------------------------- + + public static Capture capture(String accessor, ParsingExpression operand) { - Capture result = capture(captureName, operand); - result.flags |= PEF_CAPTURE_GROUPED; + Capture result = capture(false, operand); + result.accessor = accessor; return result; } - public static Capture captureText(String captureName, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Capture captureText(String accessor, ParsingExpression operand) { - Capture result = capture(captureName, operand); - result.flags |= PEF_CAPTURE_TEXT; + Capture result = capture(true, operand); + result.accessor = accessor; return result; } - public static Capture captureTextGrouped(String captureName, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Capture captureGrouped(String accessor, ParsingExpression operand) { - Capture result = capture(captureName, operand); - result.flags |= PEF_CAPTURE_TEXT | PEF_CAPTURE_GROUPED; + Capture result = capture(accessor, operand); + result.setFlags(PEF_CAPTURE_GROUPED); return result; } + // --------------------------------------------------------------------------------------------- + + public static Capture captureTextGrouped(String accessor, ParsingExpression operand) + { + Capture result = captureText(accessor, operand); + result.setFlags(PEF_CAPTURE_GROUPED); + return result; + } + + // --------------------------------------------------------------------------------------------- + + public static Capture capture(String accessor, Array tags, ParsingExpression operand) + { + Capture result = capture(false, operand); + result.accessor = accessor; + result.tags = tags == null || tags.isEmpty() ? null : tags; + return result; + } + + // --------------------------------------------------------------------------------------------- + + public static Capture captureText(String accessor, Array tags, ParsingExpression operand) + { + Capture result = capture(true, operand); + result.accessor = accessor; + result.tags = tags == null || tags.isEmpty() ? null : tags; + return result; + } + + // --------------------------------------------------------------------------------------------- + + public static Array tags(String... tags) + { + return new Array<>(tags); + } + + // TODO end compat + + // --------------------------------------------------------------------------------------------- + + public static Capture accessor$(String accessor, ParsingExpression operand) + { + if (operand instanceof Capture) + { + Capture c2 = (Capture) operand; + c2.accessor = accessor; + // TODO what should be done in those cases? + //c2.clearFlags(PEF_CAPTURE_GROUPED); + return c2; + } + + Capture result = new Capture(); + result.operand = operand; + result.accessor = accessor; + return result; + } + + // --------------------------------------------------------------------------------------------- + + public static Capture tag$(String tag, ParsingExpression operand) + { + if (operand instanceof Capture) + { + Capture c2 = (Capture) operand; + c2.addTag(tag); + return c2; + } + + Capture result = new Capture(); + result.operand = operand; + result.tags = new Array<>(tag); + return result; + } + + // --------------------------------------------------------------------------------------------- + + public static Capture group$(String accessor, ParsingExpression operand) + { + if (operand instanceof Capture) + { + Capture c2 = (Capture) operand; + c2.accessor = accessor; + c2.flags |= PEF_CAPTURE_GROUPED; + return c2; + } + + Capture result = new Capture(); + result.operand = operand; + result.accessor = accessor; + result.flags |= PEF_CAPTURE_GROUPED; + return result; + } + + // --------------------------------------------------------------------------------------------- + public static CharRange charRange(char start, char end) { CharRange result = new CharRange(); @@ -56,6 +175,8 @@ public static CharRange charRange(char start, char end) return result; } + // --------------------------------------------------------------------------------------------- + public static CharSet charSet(char[] chars) { CharSet result = new CharSet(); @@ -63,11 +184,15 @@ public static CharSet charSet(char[] chars) return result; } + // --------------------------------------------------------------------------------------------- + public static CharSet charSet(String chars) { return charSet(chars.toCharArray()); } + // --------------------------------------------------------------------------------------------- + public static Choice choice(ParsingExpression... operands) { Choice result = new Choice(); @@ -75,6 +200,8 @@ public static Choice choice(ParsingExpression... operands) return result; } + // --------------------------------------------------------------------------------------------- + public static Cut cut(String cutName) { Cut result = new Cut(); @@ -82,6 +209,8 @@ public static Cut cut(String cutName) return result; } + // --------------------------------------------------------------------------------------------- + public static Cuttable cuttable(String name, ParsingExpression... operands) { Cuttable result = new Cuttable(); @@ -90,6 +219,8 @@ public static Cuttable cuttable(String name, ParsingExpression... operands) return result; } + // --------------------------------------------------------------------------------------------- + public static Dumb dumb(ParsingExpression operand) { Dumb result = new Dumb(); @@ -97,90 +228,106 @@ public static Dumb dumb(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression dumb(ParsingExpression... seq) { return dumb(sequence(seq)); } - public static ExpressionCluster cluster(Operand... operands) - { - // Partition the alternates by precedence and sort in descending order of precedence. - // Within each group, the order of alternates is preserved. + // --------------------------------------------------------------------------------------------- - Operand[][] groups = Arrays.stream(operands) - .collect(Collectors.groupingBy(o -> o.precedence)) - .entrySet() - .stream() - .sorted((x, y) -> y.getKey() - x.getKey()) - .map(e -> e - .getValue() - .stream() - .toArray(Operand[]::new)) - .toArray(Operand[][]::new); + public static ExpressionCluster cluster(Group... groups) + { + ExpressionCluster result = new ExpressionCluster(); - Operand[][] recursiveGroups = Arrays.stream(groups) - .map(group -> Arrays.stream(group) - .filter(op -> op.leftRecursive) - .toArray(Operand[]::new)) - .toArray(Operand[][]::new); + // Sort in decreasing order of precedence. + Arrays.sort(groups, (g1, g2) -> g2.precedence - g1.precedence); - ExpressionCluster result = new ExpressionCluster(); result.groups = groups; - result.recursiveGroups = recursiveGroups; return result; } - public static DropPrecedence exprDropPrecedence(ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static WithMinPrecedence exprDropPrecedence(ParsingExpression operand) + { + return exprWithMinPrecedence(0, operand); + } + + // --------------------------------------------------------------------------------------------- + + public static WithMinPrecedence exprDropPrecedence(ParsingExpression... seq) { - DropPrecedence result = new DropPrecedence(); + return exprWithMinPrecedence(0, sequence(seq)); + } + + // --------------------------------------------------------------------------------------------- + + public static WithMinPrecedence exprWithMinPrecedence(int minPrecedence, ParsingExpression operand) + { + WithMinPrecedence result = new WithMinPrecedence(); result.operand = operand; + result.minPrecedence = minPrecedence; return result; } - public static DropPrecedence exprDropPrecedence(ParsingExpression... seq) + // --------------------------------------------------------------------------------------------- + + public static WithMinPrecedence exprWithMinPrecedence(int minPrecedence, ParsingExpression... seq) { - return exprDropPrecedence(sequence(seq)); + return exprWithMinPrecedence(minPrecedence, sequence(seq)); } - public static ExpressionCluster.Operand exprAlt(int precedence, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Group group(int precedence, boolean leftRecursive, boolean leftAssociative, ParsingExpression... alternates) { - Operand op = new Operand(); - op.operand = operand; - op.precedence = precedence; - return op; + Group group = new Group(); + group.precedence = precedence; + group.leftRecursive = leftRecursive; + group.leftAssociative = leftAssociative; + group.operands = alternates; + return group; } - public static ExpressionCluster.Operand exprLeftRecur(int precedence, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Group group(int precedence, ParsingExpression... alternates) { - Operand op = new Operand(); - op.operand = operand; - op.precedence = precedence; - op.leftRecursive = true; - return op; + return group(precedence, false, false, alternates); } - public static ExpressionCluster.Operand exprLeftAssoc(int precedence, ParsingExpression operand) + // --------------------------------------------------------------------------------------------- + + public static Group groupLeftRec(int precedence, ParsingExpression... alternates) { - Operand op = new Operand(); - op.operand = operand; - op.precedence = precedence; - op.leftRecursive = true; - op.leftAssociative = true; - return op; + return group(precedence, true, false, alternates); } + // --------------------------------------------------------------------------------------------- + + public static Group groupLeftAssoc(int precedence, ParsingExpression... alternates) + { + return group(precedence, true, true, alternates); + } + + // --------------------------------------------------------------------------------------------- + public static Filter filter( ParsingExpression[] allowed, ParsingExpression[] forbidden, ParsingExpression cluster) { Filter filter = new Filter(); - filter.allowed = allowed; - filter.forbidden = forbidden; + filter.allowed = allowed != null ? allowed : new ParsingExpression[0]; + filter.forbidden = forbidden != null ? forbidden : new ParsingExpression[0]; filter.operand = cluster; return filter; } + // --------------------------------------------------------------------------------------------- + /** * Use to create the allowed and forbidden parameters to {@link #filter}. */ @@ -189,6 +336,8 @@ public static Filter filter( return exprs; } + // --------------------------------------------------------------------------------------------- + public static Literal literal(String string) { Literal result = new Literal(); @@ -196,6 +345,8 @@ public static Literal literal(String string) return result; } + // --------------------------------------------------------------------------------------------- + public static LeftRecursive leftAssociative(ParsingExpression operand) { LeftRecursive result = new LeftRecursive(); @@ -204,11 +355,15 @@ public static LeftRecursive leftAssociative(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static LeftRecursive leftAssociative(ParsingExpression... seq) { return leftAssociative(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static LeftRecursive leftRecursive(ParsingExpression operand) { LeftRecursive result = new LeftRecursive(); @@ -216,11 +371,15 @@ public static LeftRecursive leftRecursive(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static LeftRecursive leftRecursive(ParsingExpression... seq) { return leftRecursive(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static LongestMatch longestMatch(ParsingExpression... operands) { LongestMatch result = new LongestMatch(); @@ -228,6 +387,8 @@ public static LongestMatch longestMatch(ParsingExpression... operands) return result; } + // --------------------------------------------------------------------------------------------- + public static Lookahead lookahead(ParsingExpression operand) { Lookahead result = new Lookahead(); @@ -235,11 +396,15 @@ public static Lookahead lookahead(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Lookahead lookahead(ParsingExpression... seq) { return lookahead(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Memo memo(ParsingExpression operand) { Memo result = new Memo(); @@ -247,11 +412,15 @@ public static Memo memo(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression memo(ParsingExpression... seq) { return memo(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Not not(ParsingExpression operand) { Not result = new Not(); @@ -259,11 +428,15 @@ public static Not not(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Not not(ParsingExpression... seq) { return not(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Precedence noPrecedence(ParsingExpression operand) { Precedence result = new Precedence(); @@ -272,11 +445,15 @@ public static Precedence noPrecedence(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Precedence noPrecedence(ParsingExpression... seq) { return noPrecedence(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static OneMore oneMore(ParsingExpression operand) { OneMore result = new OneMore(); @@ -284,11 +461,15 @@ public static OneMore oneMore(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static OneMore oneMore(ParsingExpression... seq) { return oneMore(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Optional optional(ParsingExpression operand) { Optional result = new Optional(); @@ -296,11 +477,15 @@ public static Optional optional(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Optional optional(ParsingExpression... seq) { return optional(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Precedence precedence(int precedence, ParsingExpression operand) { Precedence result = new Precedence(); @@ -309,6 +494,8 @@ public static Precedence precedence(int precedence, ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Reference reference(String target) { Reference result = new Reference(); @@ -316,6 +503,8 @@ public static Reference reference(String target) return result; } + // --------------------------------------------------------------------------------------------- + public static Sequence sequence(ParsingExpression... operands) { Sequence result = new Sequence(); @@ -323,6 +512,8 @@ public static Sequence sequence(ParsingExpression... operands) return result; } + // --------------------------------------------------------------------------------------------- + public static Token token(ParsingExpression operand) { Token result = new Token(); @@ -330,16 +521,22 @@ public static Token token(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static Token token(ParsingExpression... seq) { return token(sequence(seq)); } + // --------------------------------------------------------------------------------------------- + public static Whitespace whitespace() { return new Whitespace(); } + // --------------------------------------------------------------------------------------------- + public static ZeroMore zeroMore(ParsingExpression operand) { ZeroMore result = new ZeroMore(); @@ -347,6 +544,8 @@ public static ZeroMore zeroMore(ParsingExpression operand) return result; } + // --------------------------------------------------------------------------------------------- + public static ZeroMore zeroMore(ParsingExpression... seq) { return zeroMore(sequence(seq)); @@ -359,21 +558,29 @@ public static ParsingExpression notCharSet(String chars) return sequence(not(charSet(chars)), any()); } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression until(ParsingExpression op1, ParsingExpression op2) { return sequence(zeroMore(not(op2), op1), op2); } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression aloUntil(ParsingExpression op1, ParsingExpression op2) { return sequence(oneMore(not(op2), op1), op2); } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression separated(ParsingExpression op, ParsingExpression sep) { return optional(op, zeroMore(sep, op)); } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression aloSeparated(ParsingExpression op, ParsingExpression sep) { return sequence(op, zeroMore(sep, op)); @@ -387,12 +594,16 @@ public static ParsingExpression aloSeparated(ParsingExpression op, ParsingExpres return pe; } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression named$(String name, ParsingExpression pe) { pe.setName(name); return pe; } + // --------------------------------------------------------------------------------------------- + public static ParsingExpression recursive$(String name, ParsingExpression pe) { pe.setName(name); diff --git a/src/com/norswap/autumn/parsing/Registry.java b/src/com/norswap/autumn/parsing/Registry.java index 2afcdee..ae3802b 100644 --- a/src/com/norswap/autumn/parsing/Registry.java +++ b/src/com/norswap/autumn/parsing/Registry.java @@ -1,7 +1,7 @@ package com.norswap.autumn.parsing; -import com.norswap.autumn.util.FlagFactory; -import com.norswap.autumn.util.HandleFactory; +import com.norswap.util.FlagFactory; +import com.norswap.util.HandleFactory; /** * The registry manages flags and handle spaces for the parser. @@ -54,6 +54,12 @@ public final class Registry public static final int PEF_ERROR_RECORDING = ParsingExpressionFlagsFactory.next(); + /** + * (For {@code Capture} only) Indicates a capture should be performed. + */ + public static final int PEF_CAPTURE + = ParsingExpressionFlagsFactory.next(); + /** * (For {@code Capture} only) Indicates the matched text should be captured. */ @@ -61,8 +67,8 @@ public final class Registry = ParsingExpressionFlagsFactory.next(); /** - * (For {@code Capture} only) Indicates that tree nodes resulting from this capture should be - * grouped together under a tree node sporting the capture name. + * (For {@code Capture} only) Indicates that captures should be added to a group corresponding + * to their accessor. */ public static final int PEF_CAPTURE_GROUPED = ParsingExpressionFlagsFactory.next(); @@ -84,16 +90,16 @@ public final class Registry = ParseStateFlagsFactory.next(); /** - * Indicates that we shouldn't memoize any expression at the current position. + * Indicates that we shouldn't record errors when sub-expressions of the expression + * associated with this parse state fail to parse. */ - public static final int PSF_DONT_MEMOIZE_POSITION + public static final int PSF_DONT_RECORD_ERRORS = ParseStateFlagsFactory.next(); /** - * Indicates that we shouldn't record errors when sub-expressions of the expression - * associated with this parse state fail to parse. + * Indicates that captures should be added to a group corresponding to their accessor. */ - public static final int PSF_DONT_RECORD_ERRORS + public static final int PSF_GROUPING_CAPTURE = ParseStateFlagsFactory.next(); //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/Whitespace.java b/src/com/norswap/autumn/parsing/Whitespace.java index d68eb7e..57d0648 100644 --- a/src/com/norswap/autumn/parsing/Whitespace.java +++ b/src/com/norswap/autumn/parsing/Whitespace.java @@ -5,12 +5,17 @@ import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; /** - * This class exposes the default whitespace expression ({@link #whitespace}) as well as a few of - * its sub-expressions that can be useful when building custom whitespace expressions. + * This class exposes a few handy whitespace parsing expression; foremost amongst which is the + * default whitespace expression ({@link #DEFAULT()}). + *

+ * The parsing expression returned by the methods of this class are unique (i.e. they can be + * freely modified) but they contain unresolved references! */ public final class Whitespace { - public static final ParsingExpression + //////////////////////////////////////////////////////////////////////////////////////////////// + + private static final ParsingExpression EOF = named$("EOF", not(any())), @@ -41,6 +46,70 @@ public final class Whitespace whitespaceChars, lineComment, blockComment))) + ; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * The default whitespace. This is roughly similar to the whitespace accepted by C/Java/C# etc. + * It does however allow for nested block comments, and forbids weird whitespace characters + * such as the vertical tab. + */ + public static ParsingExpression DEFAULT() + { + return whitespace.deepCopy(); + } + + // --------------------------------------------------------------------------------------------- + + /** + * An expression that matches the end of the input (EOF = End Of File). + */ + public static ParsingExpression EOF() + { + return EOF.deepCopy(); + } + + // --------------------------------------------------------------------------------------------- + + /** + * An expression that matches the end of a line (newline or EOF) (EOL = End Of Line). + */ + public static ParsingExpression EOL() + { + return EOL.deepCopy(); + } + + // --------------------------------------------------------------------------------------------- + + /** + * An expression that matches a line (// ...) comment. + */ + public static ParsingExpression lineComment() + { + return lineComment.deepCopy(); + } + + // --------------------------------------------------------------------------------------------- + + /** + * An expression that matches a block (/** ... */) comment. + * Block comments can be nested. + */ + public static ParsingExpression blockComment() + { + return blockComment.deepCopy(); + } + + // --------------------------------------------------------------------------------------------- + + /** + * An expression that matches whitespace characters (space, tabs & newlines). + */ + public static ParsingExpression whitespaceChars() + { + return whitespaceChars.deepCopy(); + } - ; + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/parsing/DefaultErrorHandler.java b/src/com/norswap/autumn/parsing/config/DefaultErrorHandler.java similarity index 66% rename from src/com/norswap/autumn/parsing/DefaultErrorHandler.java rename to src/com/norswap/autumn/parsing/config/DefaultErrorHandler.java index cbf9362..9772c16 100644 --- a/src/com/norswap/autumn/parsing/DefaultErrorHandler.java +++ b/src/com/norswap/autumn/parsing/config/DefaultErrorHandler.java @@ -1,19 +1,22 @@ -package com.norswap.autumn.parsing; +package com.norswap.autumn.parsing.config; +import com.norswap.autumn.parsing.ParseError; +import com.norswap.autumn.parsing.ParseState; +import com.norswap.autumn.parsing.Source; import com.norswap.autumn.parsing.expressions.Token; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; import static com.norswap.autumn.parsing.Registry.PEF_ERROR_RECORDING; import static com.norswap.autumn.parsing.Registry.PSH_STACK_TRACE; /** - * The default error handling strategy consist of reporting the error(s) occuring at the farthest - * error positions, under the assumption that the parse that makes the most progress is the - * "most correct". - * - * This strategy only considers errors that result from a failure to match a parsing expression - * marked as "error-recording" or as a token. + * The default error handling strategy consist of keeping only the error(s) occuring at the farthest + * error positions, under the assumption that the parse that makes the most progress is the "most + * correct". + *

+ * This strategy only considers failures to match "error-recording" parsing expression, as well as + * tokens. */ public final class DefaultErrorHandler implements ErrorHandler { @@ -54,30 +57,34 @@ public void handle(ParsingExpression pe, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void reportErrors(Parser parser) + public ParseError error(Source source) { - System.err.println( - "The parser failed to match any of the following expressions at position " - + parser.source().position(farthestErrorPosition) + ":"); + StringBuilder builder = new StringBuilder(); + + builder.append("The parser failed to match any of the following expressions at position " + + source.position(farthestErrorPosition) + ":\n"); for (int i = 0; i < farthestExpressions.size(); ++i) { - System.err.println(farthestExpressions.get(i)); + builder.append(farthestExpressions.get(i)); + builder.append("\n"); Array stackTrace = stackTraces.get(i); if (stackTrace != null) { - System.err.println("stack trace: "); + builder.append("stack trace: \n"); for (ParsingExpression pe: stackTrace.reverseIterable()) { - System.err.println(pe); + builder.append(pe); + builder.append("\n"); } - - System.err.println(""); } } + + String message = builder.toString(); + return () -> message; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/DefaultMemoizationStrategy.java b/src/com/norswap/autumn/parsing/config/DefaultMemoHandler.java similarity index 93% rename from src/com/norswap/autumn/parsing/DefaultMemoizationStrategy.java rename to src/com/norswap/autumn/parsing/config/DefaultMemoHandler.java index b4de580..caf3978 100644 --- a/src/com/norswap/autumn/parsing/DefaultMemoizationStrategy.java +++ b/src/com/norswap/autumn/parsing/config/DefaultMemoHandler.java @@ -1,15 +1,17 @@ -package com.norswap.autumn.parsing; +package com.norswap.autumn.parsing.config; +import com.norswap.autumn.parsing.OutputChanges; +import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; /** * The default memoization strategy memoizes every changeset that it is asked to. - * - * It is implement an open-addressing (position -> node) map. Each node includes the position and + *

+ * It is implement as an open-addressing (position -> node) map. Each node includes the position and * memoized expression. Multiple nodes changesets for the same position are linked together using * their {@code next} field. New changesets are put at the front of this list. */ -public final class DefaultMemoizationStrategy implements MemoizationStrategy +public final class DefaultMemoHandler implements MemoHandler { //////////////////////////////////////////////////////////////////////////////////////////////// @@ -27,7 +29,7 @@ public final class DefaultMemoizationStrategy implements MemoizationStrategy //////////////////////////////////////////////////////////////////////////////////////////////// - private static class MemoNode + private static final class MemoNode { int position; ParsingExpression pe; diff --git a/src/com/norswap/autumn/parsing/config/ErrorHandler.java b/src/com/norswap/autumn/parsing/config/ErrorHandler.java new file mode 100644 index 0000000..3b59df9 --- /dev/null +++ b/src/com/norswap/autumn/parsing/config/ErrorHandler.java @@ -0,0 +1,26 @@ +package com.norswap.autumn.parsing.config; + +import com.norswap.autumn.parsing.ParseError; +import com.norswap.autumn.parsing.ParseState; +import com.norswap.autumn.parsing.Source; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; + +/** + * The error handler is called by the parser whenever a parsing expression fails to match. + *

+ * The role of the error handler is to record information about these failures and extract meaning + * for them; for instance by determining which failures were meaningful if the parse fails. + */ +public interface ErrorHandler +{ + /** + * Indicates that the given expression failed with the given state. + */ + void handle(ParsingExpression pe, ParseState state); + + /** + * Return error information about the parse. + * The source object can be used to translate the input positions. + */ + ParseError error(Source source); +} diff --git a/src/com/norswap/autumn/parsing/config/ErrorStrategy.java b/src/com/norswap/autumn/parsing/config/ErrorStrategy.java new file mode 100644 index 0000000..fa5d8ed --- /dev/null +++ b/src/com/norswap/autumn/parsing/config/ErrorStrategy.java @@ -0,0 +1,14 @@ +package com.norswap.autumn.parsing.config; + +import java.util.function.Supplier; + +/** + * An error strategy is a supplier of error handlers. + *

+ * Error handlers have state, using a strategy instead allows {@link ParserConfiguration} to be + * reusable. + */ +@FunctionalInterface +public interface ErrorStrategy extends Supplier +{ +} diff --git a/src/com/norswap/autumn/parsing/config/MemoHandler.java b/src/com/norswap/autumn/parsing/config/MemoHandler.java new file mode 100644 index 0000000..273d2cc --- /dev/null +++ b/src/com/norswap/autumn/parsing/config/MemoHandler.java @@ -0,0 +1,45 @@ +package com.norswap.autumn.parsing.config; + +import com.norswap.autumn.parsing.OutputChanges; +import com.norswap.autumn.parsing.ParseState; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; + +/** + * The memoization handler is called each time we want to memoize the result of a parsing expression + * invocation; or when we want to retrieve such a result. + *

+ * An invocation is characterized by the parsing expression as well as the parsing state at the time + * of invocation. Traditionally, memoization only takes the input position into account. + * However, if some state is able to modify the result of the invocation, it must either be taken + * into account by the memoization handler; or memoization must be disabled while this state is in + * effect. Otherwise, correctness is no longer guaranteed. + *

+ * The "results" we allude to are saved as changesets ({@link OutputChanges}) that describe the + * difference in the parse state before/after the invocation. + */ +public interface MemoHandler +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Memoize a changeset for the given parsing expression and state. + */ + void memoize(ParsingExpression pe, ParseState state, OutputChanges changeset); + + // --------------------------------------------------------------------------------------------- + + /** + * Return a memoized changeset; or null if no such changeset has been memoized. + */ + OutputChanges get(ParsingExpression pe, ParseState state); + + // --------------------------------------------------------------------------------------------- + + /** + * Called to indicate that all memoized changesets between the start of the input and the + * indicated position will no longer be needed; they can thus be released. + */ + void cut(int position); + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/config/MemoStrategy.java b/src/com/norswap/autumn/parsing/config/MemoStrategy.java new file mode 100644 index 0000000..64b939d --- /dev/null +++ b/src/com/norswap/autumn/parsing/config/MemoStrategy.java @@ -0,0 +1,14 @@ +package com.norswap.autumn.parsing.config; + +import java.util.function.Supplier; + +/** + * A memoization strategy is a supplier of memoization handlers. + *

+ * Memoization handlers have state, using a strategy instead allows {@link ParserConfiguration} to + * be reusable. + */ +@FunctionalInterface +public interface MemoStrategy extends Supplier +{ +} diff --git a/src/com/norswap/autumn/parsing/config/ParserConfiguration.java b/src/com/norswap/autumn/parsing/config/ParserConfiguration.java new file mode 100644 index 0000000..ba1197c --- /dev/null +++ b/src/com/norswap/autumn/parsing/config/ParserConfiguration.java @@ -0,0 +1,34 @@ +package com.norswap.autumn.parsing.config; + +import java.util.function.Supplier; + +/** + * [Immutable] The parser configuration allows the user to configure operational details of the + * parse, such as how errors and memoization are handled. + */ +public final class ParserConfiguration +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * The default configuration uses {@link DefaultErrorHandler} and {@link DefaultMemoHandler}. + */ + public static final ParserConfiguration DEFAULT + = new ParserConfiguration(DefaultErrorHandler::new, DefaultMemoHandler::new); + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public final Supplier errorHandler; + + public final Supplier memoizationStrategy; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public ParserConfiguration(Supplier errorHandler, Supplier memoizationStrategy) + { + this.errorHandler = errorHandler; + this.memoizationStrategy = memoizationStrategy; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/debug/Breakpoint.java b/src/com/norswap/autumn/parsing/debug/Breakpoint.java index 07356ff..bbbfac8 100644 --- a/src/com/norswap/autumn/parsing/debug/Breakpoint.java +++ b/src/com/norswap/autumn/parsing/debug/Breakpoint.java @@ -31,9 +31,9 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { - operand.toString(builder); + operand.appendTo(builder); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/debug/Debugger.java b/src/com/norswap/autumn/parsing/debug/Debugger.java index 8f5c566..1ceb3b1 100644 --- a/src/com/norswap/autumn/parsing/debug/Debugger.java +++ b/src/com/norswap/autumn/parsing/debug/Debugger.java @@ -1,10 +1,12 @@ package com.norswap.autumn.parsing.debug; +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; -import com.norswap.autumn.parsing.Parser; +import com.norswap.autumn.parsing.Source; import com.norswap.autumn.parsing.TextPosition; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; import javafx.application.Platform; import netscape.javascript.JSObject; @@ -24,9 +26,9 @@ private static class StackFrame //////////////////////////////////////////////////////////////////////////////////////////////// - Parser parser; + Grammar grammar; - ParsingExpression[] grammar; + Source source; JSObject jsWindow; @@ -34,7 +36,7 @@ private static class StackFrame private boolean blocked = false; - private Object lock = new Object(); + private final Object lock = new Object(); private boolean step = true; @@ -42,7 +44,7 @@ private static class StackFrame public void start() { - parser.parse(grammar[0]); + Autumn.parseSource(grammar, source); } // --------------------------------------------------------------------------------------------- @@ -53,7 +55,7 @@ public void pushFrame(ParsingExpression pe, ParseState state) frame.pe = pe; frame.state = state; stack.push(frame); - TextPosition pos = parser.source().position(state.start); + TextPosition pos = source.position(state.start); Platform.runLater(() -> { jsWindow.call("pushFrame", new Object[]{pe.toString(), pos.line, pos.column, state.start}); @@ -101,12 +103,7 @@ public void resume() protected boolean doSuspend(Breakpoint bp, ParseState state) { - if (step) - { - return true; - } - - return false; + return step; } // --------------------------------------------------------------------------------------------- diff --git a/src/com/norswap/autumn/parsing/debug/GUI.java b/src/com/norswap/autumn/parsing/debug/GUI.java index 78fd37f..dd2764b 100644 --- a/src/com/norswap/autumn/parsing/debug/GUI.java +++ b/src/com/norswap/autumn/parsing/debug/GUI.java @@ -1,12 +1,10 @@ package com.norswap.autumn.parsing.debug; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.ParserConfiguration; +import com.norswap.autumn.Autumn; import com.norswap.autumn.parsing.Source; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.FunctionalTransformer; -import com.norswap.autumn.parsing.support.GrammarDriver; -import com.norswap.autumn.util.Exceptions; +import com.norswap.autumn.parsing.graph.Walks; +import com.norswap.util.graph_visit.GraphTransformer; import javafx.application.Application; import javafx.concurrent.Worker; import javafx.scene.Scene; @@ -30,27 +28,26 @@ public class GUI extends Application public static void main(String[] args) throws IOException { String grammarFile = "src/com/norswap/autumn/test/grammars/Java8.autumn"; - DEBUGGER.grammar = FunctionalTransformer.apply( - GrammarDriver.compile(grammarFile), - pe -> { - Breakpoint out = new Breakpoint(); - out.operand = pe; - return out; - }, - true); - - file = "src/com/norswap/autumn/parsing/Parser.java"; + + DEBUGGER.grammar = Autumn.grammarFromFile(grammarFile) + .walk(GraphTransformer.from(GUI::transform, Walks.inPlace)); + + DEBUGGER.source = Source.fromFile("src/com/norswap/autumn/parsing/Parser.java"); launch(args); } + public static ParsingExpression transform(ParsingExpression pe) + { + Breakpoint out = new Breakpoint(); + out.operand = pe; + return out; + } + //////////////////////////////////////////////////////////////////////////////////////////////// @Override public void start(Stage primaryStage) { - DEBUGGER.parser = - new Parser(Exceptions.swallow(() -> Source.fromFile(file)), new ParserConfiguration()); - WebView root = new WebView(); WebEngine engine = root.getEngine(); @@ -58,7 +55,7 @@ public void start(Stage primaryStage) ClassLoader.getSystemResource("debugger/debugger.html").toExternalForm()); JSBridge bridge = new JSBridge(); - bridge._text = DEBUGGER.parser.text.toString(); + bridge._text = DEBUGGER.source.text().toString(); engine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -> diff --git a/src/com/norswap/autumn/parsing/debug/JSBridge.java b/src/com/norswap/autumn/parsing/debug/JSBridge.java index 693b012..613c171 100644 --- a/src/com/norswap/autumn/parsing/debug/JSBridge.java +++ b/src/com/norswap/autumn/parsing/debug/JSBridge.java @@ -44,7 +44,7 @@ public String subTextFrom(int from) public String lineAndColumn(int position) { - TextPosition tpos = DEBUGGER.parser.source().position(position); + TextPosition tpos = DEBUGGER.source.position(position); return tpos.line + "," + tpos.column; } @@ -52,7 +52,7 @@ public String lineAndColumn(int position) public int fileOffset(int line, int column) { - return DEBUGGER.parser.source().fileOffset(line, column); + return DEBUGGER.source.fileOffset(line, column); } // --------------------------------------------------------------------------------------------- diff --git a/src/com/norswap/autumn/parsing/expressions/Any.java b/src/com/norswap/autumn/parsing/expressions/Any.java index d1844eb..f72e8d6 100644 --- a/src/com/norswap/autumn/parsing/expressions/Any.java +++ b/src/com/norswap/autumn/parsing/expressions/Any.java @@ -41,7 +41,7 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("any()"); } diff --git a/src/com/norswap/autumn/parsing/expressions/Capture.java b/src/com/norswap/autumn/parsing/expressions/Capture.java index 3b041ac..f0efcb0 100644 --- a/src/com/norswap/autumn/parsing/expressions/Capture.java +++ b/src/com/norswap/autumn/parsing/expressions/Capture.java @@ -4,78 +4,142 @@ import com.norswap.autumn.parsing.ParseTree; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; +import com.norswap.util.Array; -import static com.norswap.autumn.parsing.Registry.*; // PEF_* +import static com.norswap.autumn.parsing.Registry.*; // PEF_* PSF_* /** * Invokes its operand on the input, succeeding if the operand does, with the same end position. - * - * On success, adds a new child node to the current parse tree node whose name is {@link #name}. - * This node becomes the current parse tree node for the invocation of the operand. + *

+ * This either specify the capture of its operand or alters the effect of captures occuring during + * the invocation of its operand by modifying the parse state. + *

+ * For these captures, the accessor will be {@link #accessor} or {@link ParseState#accessor} (which + * overrides the former). The tags will be the union of {@link #tags} and {@link ParseState#tags}. + * If {@link #shouldGroup}, the capture will belong to a group of captures with the same accessor. + *

+ * Capture specifications do not accumulate: after a capture is performed, the {@link + * ParseState#accessor} and {@link ParseState#tags} are reset for the children of the captured + * expression. + *

+ * If {@link #shouldCapture}, adds a new child node to the current parse tree node. This node + * becomes the current parse tree node for the invocation of the operand. If {@link + * #shouldCaptureText}, the text matching the captured expression will be saved. */ public final class Capture extends UnaryParsingExpression { //////////////////////////////////////////////////////////////////////////////////////////////// - public String name; + public String accessor; + public Array tags; //////////////////////////////////////////////////////////////////////////////////////////////// @Override public void parse(Parser parser, ParseState state) { - ParseTree oldTree = state.tree; - ParseTree newTree = new ParseTree(name); - int oldCount = state.treeChildrenCount; + int oldFlags = state.flags; + String oldAccessor = state.accessor; - state.tree = newTree; - state.treeChildrenCount = 0; + if (shouldGroup()) + { + state.setGroupingCapture(); + } - operand.parse(parser, state); + if (state.accessor == null) + { + state.accessor = accessor; + } - state.tree = oldTree; - state.treeChildrenCount = oldCount; + int oldTagsCount = state.tags.size(); + state.tags.addAll(tags); - if (state.succeeded()) + if (!shouldCapture()) { - if (isCaptureGrouped()) - { - oldTree.addGrouped(newTree); - } - else + operand.parse(parser, state); + } + else + { + ParseTree oldTree = state.tree; + + ParseTree newTree = new ParseTree( + state.accessor, + state.tags != null && !state.tags.isEmpty() + ? state.tags.clone() + : null, + state.isCaptureGrouping()); + + int oldCount = state.treeChildrenCount; + Array oldTags = state.tags; + + state.accessor = null; + state.tags = new Array<>(); + state.tree = newTree; + state.treeChildrenCount = 0; + + operand.parse(parser, state); + + state.tags = oldTags; + state.tree = oldTree; + state.treeChildrenCount = oldCount; + + if (state.succeeded()) { oldTree.add(newTree); - } - if (shouldCaptureText()) - { - newTree.value = parser.text - .subSequence(state.start, state.blackEnd) - .toString(); + if (shouldCaptureText()) + { + newTree.value = parser.text + .subSequence(state.start, state.blackEnd) + .toString(); + } } } + + state.flags = oldFlags; + state.accessor = oldAccessor; + state.tags.truncate(oldTagsCount); + } + + // --------------------------------------------------------------------------------------------- + + public void addTag(String tag) + { + if (tags == null) + { + tags = new Array<>(); + } + + tags.add(tag); } // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public String ownPrintableData() { - builder.append("capture(\""); - builder.append(name); - builder.append("\", "); - operand.toString(builder); - builder.append(")"); + return String.format("accessor: %s, tags: %s, capture: %s", + accessor, tags, + shouldCaptureText() ? "text" : shouldGroup() ? "group" : shouldCapture()); } //////////////////////////////////////////////////////////////////////////////////////////////// + public boolean shouldCapture() + { + return (flags & PEF_CAPTURE) != 0; + } + + // --------------------------------------------------------------------------------------------- + public boolean shouldCaptureText() { return (flags & PEF_CAPTURE_TEXT) != 0; } - public boolean isCaptureGrouped() + // --------------------------------------------------------------------------------------------- + + public boolean shouldGroup() { return (flags & PEF_CAPTURE_GROUPED) != 0; } diff --git a/src/com/norswap/autumn/parsing/expressions/CharRange.java b/src/com/norswap/autumn/parsing/expressions/CharRange.java index 91906d6..94916ea 100644 --- a/src/com/norswap/autumn/parsing/expressions/CharRange.java +++ b/src/com/norswap/autumn/parsing/expressions/CharRange.java @@ -51,7 +51,7 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("charRange("); builder.append(start); @@ -60,5 +60,13 @@ public void appendTo(StringBuilder builder) builder.append(")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return toString(); + } + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/parsing/expressions/CharSet.java b/src/com/norswap/autumn/parsing/expressions/CharSet.java index 03e232e..ccea45c 100644 --- a/src/com/norswap/autumn/parsing/expressions/CharSet.java +++ b/src/com/norswap/autumn/parsing/expressions/CharSet.java @@ -3,7 +3,7 @@ import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.StringEscape; +import com.norswap.util.StringEscape; /** * Attempts to match the next input character to a range of characters. @@ -58,12 +58,20 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("charSet(\""); builder.append(StringEscape.escape(new String(chars))); builder.append("\")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return toString(); + } + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/parsing/expressions/Choice.java b/src/com/norswap/autumn/parsing/expressions/Choice.java index e0d8688..04638b7 100644 --- a/src/com/norswap/autumn/parsing/expressions/Choice.java +++ b/src/com/norswap/autumn/parsing/expressions/Choice.java @@ -1,10 +1,11 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.NaryParsingExpression; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Invokes all its operands at its initial input position, until one succeeds. @@ -58,7 +59,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return operands; } @@ -66,7 +67,7 @@ public ParsingExpression[] firsts() // --------------------------------------------------------------------------------------------- @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.any(this, operands); } diff --git a/src/com/norswap/autumn/parsing/expressions/Cut.java b/src/com/norswap/autumn/parsing/expressions/Cut.java index 3014506..e261a43 100644 --- a/src/com/norswap/autumn/parsing/expressions/Cut.java +++ b/src/com/norswap/autumn/parsing/expressions/Cut.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** @@ -31,17 +32,25 @@ public void parse(Parser parser, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("cut(\""); builder.append(name); builder.append("\")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return "name: " + name; + } + //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/Cuttable.java b/src/com/norswap/autumn/parsing/expressions/Cuttable.java index d06763e..9410b55 100644 --- a/src/com/norswap/autumn/parsing/expressions/Cuttable.java +++ b/src/com/norswap/autumn/parsing/expressions/Cuttable.java @@ -1,10 +1,11 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.NaryParsingExpression; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; public final class Cuttable extends NaryParsingExpression { @@ -59,7 +60,7 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("cuttable("); builder.append("\""); @@ -68,7 +69,7 @@ public void appendTo(StringBuilder builder) for (ParsingExpression operand: operands) { - operand.toString(builder); + operand.appendTo(builder); builder.append(", "); } @@ -77,10 +78,18 @@ public void appendTo(StringBuilder builder) builder.append(")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return toString(); + } + //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.any(this, operands); } @@ -88,7 +97,7 @@ public Nullability nullability() // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return operands; } diff --git a/src/com/norswap/autumn/parsing/expressions/DropPrecedence.java b/src/com/norswap/autumn/parsing/expressions/DropPrecedence.java deleted file mode 100644 index 358ea79..0000000 --- a/src/com/norswap/autumn/parsing/expressions/DropPrecedence.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.norswap.autumn.parsing.expressions; - -import com.norswap.autumn.parsing.ParseState; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; - -public final class DropPrecedence extends UnaryParsingExpression -{ - @Override - public void parse(Parser parser, ParseState state) - { - int minPrecedence = parser.minPrecedence(); - parser.setMinPrecedence(0); - operand.parse(parser, state); - parser.setMinPrecedence(minPrecedence); - } -} diff --git a/src/com/norswap/autumn/parsing/expressions/ExpressionCluster.java b/src/com/norswap/autumn/parsing/expressions/ExpressionCluster.java index 2f3c463..cf267e8 100644 --- a/src/com/norswap/autumn/parsing/expressions/ExpressionCluster.java +++ b/src/com/norswap/autumn/parsing/expressions/ExpressionCluster.java @@ -1,11 +1,13 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.OutputChanges; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; +import com.norswap.autumn.parsing.expressions.common.NaryParsingExpression; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; -import com.norswap.autumn.util.DeepCopy; +import com.norswap.autumn.parsing.graph.Nullability; +import com.norswap.util.DeepCopy; import java.util.Arrays; @@ -22,55 +24,38 @@ public final static class PrecedenceEntry //////////////////////////////////////////////////////////////////////////////////////////////// - // TODO use this? - public final static class Group implements DeepCopy + public final static class Group extends NaryParsingExpression { public int precedence; public boolean leftRecursive; public boolean leftAssociative; - public ParsingExpression[] operands; @Override - public Group deepCopy() + public void parse(Parser parser, ParseState state) { - Group copy = DeepCopy.clone(this); - copy.operands = DeepCopy.of(operands, ParsingExpression[]::new); - return copy; + throw new Error("The parse method of " + getClass().getName() + + " is not supposed to be called."); } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public final static class Operand implements DeepCopy - { - public ParsingExpression operand; - public int precedence; - public boolean leftRecursive; - public boolean leftAssociative; - @Override - public Operand deepCopy() + public String ownPrintableData() { - Operand copy = DeepCopy.clone(this); - copy.operand = operand.deepCopy(); - return copy; + return "precedence: " + precedence + ", " + + (leftAssociative + ? "associative" + : leftRecursive + ? "recursive" + : ""); } } //////////////////////////////////////////////////////////////////////////////////////////////// - /* - * Each sub-array is a group that holds alternates of similar precedence. The array is sorted - * in order of decreasing precedence. - */ - public Operand[][] groups; - /** - * Each sub-array is a sub-group of the corresponding group in {@link #groups}, holding only - * the left-recursive operands. + * Each groups holds alternates of similar precedence. The array is sorted + * in order of decreasing precedence. */ - public Operand[][] recursiveGroups; + public Group[] groups; //////////////////////////////////////////////////////////////////////////////////////////////// @@ -87,7 +72,7 @@ public void parse(Parser parser, ParseState state) if (changes != null) { - // If this cluster is already in the process of being parsed at this position; use + // If this cluster is already in the process of being parsed at this position, use // the seed value. changes.mergeInto(state); @@ -100,27 +85,23 @@ public void parse(Parser parser, ParseState state) // Because of precedence, memoized results might not be correct (might have been obtained // with another precedence). - final int oldFlags = state.flags; state.forbidMemoization(); + // Get minimum precedence if we're already parsing this cluster (else it's 0). final int minPrecedence = parser.enterPrecedence(this, state.start, 0); // Used to sometimes inhibit error reporting. boolean report = true; - for (int i = 0; i < groups.length; ++i) + for (Group group : groups) { - Operand[] group = groups[i], recursiveGroup = recursiveGroups[i]; - - int groupPrecedence = group[0].precedence; - // This condition, coupled with the subsequent {@link Parser#setMinPrecedence} call, // blocks recursion into alternates of lower precedence. It also blocks recursion into - // alternates of the same precedence if the current alternate is left-associative; in + // alternates of the same precedence if the current alternate is left-associative, in // order to prevent right-recursion (left-recursion is handled via the seed). - if (groupPrecedence < minPrecedence) + if (group.precedence < minPrecedence) { if (changes.failed()) { @@ -137,26 +118,25 @@ public void parse(Parser parser, ParseState state) break; } - parser.setMinPrecedence( - groupPrecedence + (group[0].leftAssociative ? 1 : 0)); + parser.setMinPrecedence(group.precedence + (group.leftAssociative ? 1 : 0)); while (true) { OutputChanges oldChanges = changes; - for (Operand operand: group) + for (ParsingExpression operand: group.operands) { - operand.operand.parse(parser, state); + operand.parse(parser, state); if (state.end > changes.end - || groupPrecedence > changesPrecedence && state.end != -1) + || group.precedence > changesPrecedence && state.end != -1) { // The seed was grown, try to grow it again starting from the first // recursive rule. - parser.clusterAlternate = operand.operand; + parser.clusterAlternate = operand; changes = new OutputChanges(state); - changesPrecedence = groupPrecedence; + changesPrecedence = group.precedence; state.setSeed(changes); state.resetAllOutput(); break; @@ -179,7 +159,9 @@ public void parse(Parser parser, ParseState state) } // Non-left recursive rules will not yield longer matches, so no use trying them. - group = recursiveGroup; + if (!group.leftRecursive) { + break; + } } } @@ -197,13 +179,13 @@ public void parse(Parser parser, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("expr("); for (ParsingExpression operand: children()) { - operand.toString(builder); + operand.appendTo(builder); builder.append(", "); } @@ -221,8 +203,7 @@ public void appendTo(StringBuilder builder) public ParsingExpression[] children() { return Arrays.stream(groups) - .flatMap(Arrays::stream) - .map(o -> o.operand) + .flatMap(g -> Arrays.stream(g.operands)) .toArray(ParsingExpression[]::new); } @@ -233,15 +214,15 @@ public void setChild(int position, ParsingExpression pe) { int pos = 0; - for (Operand[] group : groups) + for (Group group: groups) { - if (position < pos + group.length) + if (position < pos + group.operands.length) { - group[position - pos].operand = pe; + group.operands[position - pos] = pe; return; } - pos += group.length; + pos += group.operands.length; } throw new RuntimeException( @@ -251,39 +232,39 @@ public void setChild(int position, ParsingExpression pe) // --------------------------------------------------------------------------------------------- @Override - public ExpressionCluster deepCopy() + public ExpressionCluster clone() { - ExpressionCluster copy = (ExpressionCluster) super.deepCopy(); - - copy.groups = new Operand[groups.length][]; - copy.recursiveGroups = new Operand[groups.length][]; + ExpressionCluster clone = (ExpressionCluster) super.clone(); + clone.groups = DeepCopy.deepClone(groups); + return clone; + } - for (int i = 0; i < groups.length; ++i) - { - copy.groups[i] = DeepCopy.of(groups[i], Operand[]::new); - copy.recursiveGroups[i] = DeepCopy.of(recursiveGroups[i], Operand[]::new); - } + // --------------------------------------------------------------------------------------------- + @Override + public ExpressionCluster deepCopy() + { + ExpressionCluster copy = (ExpressionCluster) super.deepCopy(); + copy.groups = DeepCopy.of(groups); return copy; } //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { - return Nullability.any(this, firsts()); + return Nullability.any(this, firsts(grammar)); } // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return Arrays.stream(groups) - .flatMap(Arrays::stream) - .filter(o -> !o.leftRecursive) - .map(o -> o.operand) + .filter(g -> !g.leftRecursive) + .flatMap(g -> Arrays.stream(g.operands)) .toArray(ParsingExpression[]::new); } diff --git a/src/com/norswap/autumn/parsing/expressions/Filter.java b/src/com/norswap/autumn/parsing/expressions/Filter.java index d538ec4..4090a0e 100644 --- a/src/com/norswap/autumn/parsing/expressions/Filter.java +++ b/src/com/norswap/autumn/parsing/expressions/Filter.java @@ -4,7 +4,7 @@ import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; import java.util.Arrays; import java.util.stream.Stream; @@ -63,17 +63,26 @@ public void parse(Parser parser, ParseState state) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("filter("); - builder.append(new Array<>(allowed)); + builder.append(Array.fromArray(allowed)); builder.append(","); - builder.append(new Array<>(forbidden)); + builder.append(Array.fromArray(forbidden)); builder.append(","); - operand.toString(builder); + operand.appendTo(builder); builder.append(")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return "allowed: " + allowed.length + ", forbidden: " + forbidden.length; + } + + // --------------------------------------------------------------------------------------------- @Override diff --git a/src/com/norswap/autumn/parsing/expressions/LeftRecursive.java b/src/com/norswap/autumn/parsing/expressions/LeftRecursive.java index b12618a..ee7479c 100644 --- a/src/com/norswap/autumn/parsing/expressions/LeftRecursive.java +++ b/src/com/norswap/autumn/parsing/expressions/LeftRecursive.java @@ -3,7 +3,6 @@ import com.norswap.autumn.parsing.OutputChanges; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; public final class LeftRecursive extends UnaryParsingExpression @@ -48,7 +47,7 @@ else if (leftAssociative && parser.isBlocked(this)) // with {@link ParseInput#advance()}. int oldFlags = state.flags; - state.forbidMemoizationAtPosition(); + state.forbidMemoization(); // Keep parsing the operand, as long as long as the seed keeps growing. @@ -68,7 +67,6 @@ else if (leftAssociative && parser.isBlocked(this)) changes = new OutputChanges(state); state.setSeed(changes); state.resetAllOutput(); - state.forbidMemoizationAtPosition(); } } @@ -94,12 +92,21 @@ else if (leftAssociative && parser.isBlocked(this)) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append(leftAssociative ? "leftAssociative" : "leftRecursive("); - operand.toString(builder); + operand.appendTo(builder); builder.append(")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return leftAssociative ? "left-associative" : ""; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/parsing/expressions/Literal.java b/src/com/norswap/autumn/parsing/expressions/Literal.java index 85e45f3..1b0d423 100644 --- a/src/com/norswap/autumn/parsing/expressions/Literal.java +++ b/src/com/norswap/autumn/parsing/expressions/Literal.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Attempt to match a literal string to the input. @@ -66,17 +67,25 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("\""); builder.append(string); builder.append("\""); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return string; + } + //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.bool(this, string.isEmpty()); } diff --git a/src/com/norswap/autumn/parsing/expressions/LongestMatch.java b/src/com/norswap/autumn/parsing/expressions/LongestMatch.java index b615cde..7969ed9 100644 --- a/src/com/norswap/autumn/parsing/expressions/LongestMatch.java +++ b/src/com/norswap/autumn/parsing/expressions/LongestMatch.java @@ -1,11 +1,12 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.NaryParsingExpression; import com.norswap.autumn.parsing.OutputChanges; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Invokes all its operands at its initial input position. @@ -67,7 +68,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.any(this, operands); } @@ -75,7 +76,7 @@ public Nullability nullability() // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return operands; } diff --git a/src/com/norswap/autumn/parsing/expressions/Lookahead.java b/src/com/norswap/autumn/parsing/expressions/Lookahead.java index 07675c8..2de96c6 100644 --- a/src/com/norswap/autumn/parsing/expressions/Lookahead.java +++ b/src/com/norswap/autumn/parsing/expressions/Lookahead.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Invokes its operand on the input, then resets the input to its initial position. @@ -44,7 +45,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/Memo.java b/src/com/norswap/autumn/parsing/expressions/Memo.java index 3ccc6aa..9051d72 100644 --- a/src/com/norswap/autumn/parsing/expressions/Memo.java +++ b/src/com/norswap/autumn/parsing/expressions/Memo.java @@ -18,7 +18,7 @@ public void parse(Parser parser, ParseState state) return; } - OutputChanges changes = parser.memoizationStrategy.get(this, state); + OutputChanges changes = parser.memoHandler.get(this, state); if (changes != null) { @@ -27,7 +27,7 @@ public void parse(Parser parser, ParseState state) } operand.parse(parser, state); - parser.memoizationStrategy.memoize(operand, state, new OutputChanges(state)); + parser.memoHandler.memoize(operand, state, new OutputChanges(state)); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/expressions/Not.java b/src/com/norswap/autumn/parsing/expressions/Not.java index 2a7914d..d3c7bdc 100644 --- a/src/com/norswap/autumn/parsing/expressions/Not.java +++ b/src/com/norswap/autumn/parsing/expressions/Not.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Invokes its operand on the input, then resets the input to its initial position. @@ -50,7 +51,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/Optional.java b/src/com/norswap/autumn/parsing/expressions/Optional.java index 0837a2b..53ba8d4 100644 --- a/src/com/norswap/autumn/parsing/expressions/Optional.java +++ b/src/com/norswap/autumn/parsing/expressions/Optional.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Invokes its operand on the input. @@ -43,7 +44,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/Precedence.java b/src/com/norswap/autumn/parsing/expressions/Precedence.java index 3b80695..13e1794 100644 --- a/src/com/norswap/autumn/parsing/expressions/Precedence.java +++ b/src/com/norswap/autumn/parsing/expressions/Precedence.java @@ -50,7 +50,7 @@ public void parse(Parser parser, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { if (precedence == NONE) { @@ -63,9 +63,17 @@ public void appendTo(StringBuilder builder) builder.append(", "); } - operand.toString(builder); + operand.appendTo(builder); builder.append(")"); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return String.valueOf(precedence); + } + //////////////////////////////////////////////////////////////////////////////////////////////// } \ No newline at end of file diff --git a/src/com/norswap/autumn/parsing/expressions/Reference.java b/src/com/norswap/autumn/parsing/expressions/Reference.java index 5b8b1b3..935c1dd 100644 --- a/src/com/norswap/autumn/parsing/expressions/Reference.java +++ b/src/com/norswap/autumn/parsing/expressions/Reference.java @@ -1,10 +1,11 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; -import com.norswap.autumn.util.Array; +import com.norswap.autumn.parsing.graph.Nullability; +import com.norswap.util.Array; /** @@ -35,15 +36,23 @@ public void parse(Parser parser, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append(target); } + // --------------------------------------------------------------------------------------------- + + @Override + public String ownPrintableData() + { + return target; + } + //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { throw new UnsupportedOperationException( "Trying to get the nullability of: " + target); @@ -52,7 +61,7 @@ public Nullability nullability() // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { throw new UnsupportedOperationException( "Trying to get the FIRST set of: " + target); diff --git a/src/com/norswap/autumn/parsing/expressions/Sequence.java b/src/com/norswap/autumn/parsing/expressions/Sequence.java index 5eda59a..3698ff4 100644 --- a/src/com/norswap/autumn/parsing/expressions/Sequence.java +++ b/src/com/norswap/autumn/parsing/expressions/Sequence.java @@ -1,12 +1,12 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.NaryParsingExpression; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.FirstCalculator; -import com.norswap.autumn.parsing.graph.nullability.Nullability; -import com.norswap.autumn.util.Array; +import com.norswap.autumn.parsing.graph.Nullability; +import com.norswap.util.Array; /** * Invokes all its operands sequentially over the input, until one fails. Each operand is @@ -65,7 +65,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.all(this, operands); } @@ -73,7 +73,7 @@ public Nullability nullability() // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { ParsingExpression pe; int i = 0; @@ -83,7 +83,7 @@ public ParsingExpression[] firsts() pe = operands[i++]; array.add(pe); } - while (i < operands.length && FirstCalculator.nullCalc.isNullable(pe)); + while (i < operands.length && grammar.isNullable(pe)); return array.toArray(ParsingExpression[]::new); } diff --git a/src/com/norswap/autumn/parsing/expressions/Whitespace.java b/src/com/norswap/autumn/parsing/expressions/Whitespace.java index 72d1622..f879660 100644 --- a/src/com/norswap/autumn/parsing/expressions/Whitespace.java +++ b/src/com/norswap/autumn/parsing/expressions/Whitespace.java @@ -1,13 +1,13 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.ParserConfiguration; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** - * Invokes {@link ParserConfiguration#whitespace} at its start position. + * Invokes {@link Parser#whitespace} at its start position. * * Always succeeds. * @@ -31,7 +31,7 @@ public void parse(Parser parser, ParseState state) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { builder.append("whitespace"); } @@ -39,7 +39,7 @@ public void appendTo(StringBuilder builder) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/WithMinPrecedence.java b/src/com/norswap/autumn/parsing/expressions/WithMinPrecedence.java new file mode 100644 index 0000000..b253486 --- /dev/null +++ b/src/com/norswap/autumn/parsing/expressions/WithMinPrecedence.java @@ -0,0 +1,33 @@ +package com.norswap.autumn.parsing.expressions; + +import com.norswap.autumn.parsing.ParseState; +import com.norswap.autumn.parsing.Parser; +import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; + +public final class WithMinPrecedence extends UnaryParsingExpression +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public int minPrecedence; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void parse(Parser parser, ParseState state) + { + int oldMinPrecedence = parser.minPrecedence(); + parser.setMinPrecedence(this.minPrecedence); + operand.parse(parser, state); + parser.setMinPrecedence(oldMinPrecedence); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public String ownPrintableData() + { + return "minPrecedence: " + minPrecedence; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/expressions/ZeroMore.java b/src/com/norswap/autumn/parsing/expressions/ZeroMore.java index 4c42268..859d617 100644 --- a/src/com/norswap/autumn/parsing/expressions/ZeroMore.java +++ b/src/com/norswap/autumn/parsing/expressions/ZeroMore.java @@ -1,9 +1,10 @@ package com.norswap.autumn.parsing.expressions; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.UnaryParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.Nullability; +import com.norswap.autumn.parsing.graph.Nullability; /** * Repeatedly invokes its operand over the input, until it fails. Each invocation occurs at @@ -57,7 +58,7 @@ public int parseDumb(Parser parser, int position) //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.yes(this); } diff --git a/src/com/norswap/autumn/parsing/expressions/common/InstrumentedExpression.java b/src/com/norswap/autumn/parsing/expressions/common/InstrumentedExpression.java index 56a6fc4..a19efc7 100644 --- a/src/com/norswap/autumn/parsing/expressions/common/InstrumentedExpression.java +++ b/src/com/norswap/autumn/parsing/expressions/common/InstrumentedExpression.java @@ -14,9 +14,9 @@ public int parseDumb(Parser parser, int position) // --------------------------------------------------------------------------------------------- @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { - operand.toString(builder); + operand.appendTo(builder); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/expressions/common/NaryParsingExpression.java b/src/com/norswap/autumn/parsing/expressions/common/NaryParsingExpression.java index ae1cafa..8692d6b 100644 --- a/src/com/norswap/autumn/parsing/expressions/common/NaryParsingExpression.java +++ b/src/com/norswap/autumn/parsing/expressions/common/NaryParsingExpression.java @@ -1,6 +1,6 @@ package com.norswap.autumn.parsing.expressions.common; -import com.norswap.autumn.util.DeepCopy; +import com.norswap.util.DeepCopy; /** * Base implementation for parsing expression with an array of operands. @@ -14,10 +14,10 @@ public abstract class NaryParsingExpression extends ParsingExpression //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { String name = this.getClass().getSimpleName(); - name = name.substring(0,1).toLowerCase() + name.substring(1).toLowerCase(); + name = name.substring(0,1).toLowerCase() + name.substring(1); builder.append(name); builder.append("("); @@ -26,7 +26,7 @@ public void appendTo(StringBuilder builder) { for (ParsingExpression operand: operands) { - operand.toString(builder); + operand.appendTo(builder); builder.append(", "); } @@ -54,6 +54,16 @@ public void setChild(int position, ParsingExpression pe) // --------------------------------------------------------------------------------------------- + @Override + public NaryParsingExpression clone() + { + NaryParsingExpression clone = (NaryParsingExpression) super.clone(); + clone.operands = operands.clone(); + return clone; + } + + // --------------------------------------------------------------------------------------------- + @Override public NaryParsingExpression deepCopy() { diff --git a/src/com/norswap/autumn/parsing/expressions/common/ParsingExpression.java b/src/com/norswap/autumn/parsing/expressions/common/ParsingExpression.java index 5979e43..8902e3f 100644 --- a/src/com/norswap/autumn/parsing/expressions/common/ParsingExpression.java +++ b/src/com/norswap/autumn/parsing/expressions/common/ParsingExpression.java @@ -1,13 +1,14 @@ package com.norswap.autumn.parsing.expressions.common; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.Registry; -import com.norswap.autumn.parsing.graph.nullability.Nullability; -import com.norswap.autumn.util.Caster; -import com.norswap.autumn.util.DeepCopy; -import com.norswap.autumn.util.Exceptions; -import com.norswap.autumn.util.HandleMap; +import com.norswap.autumn.parsing.graph.Nullability; +import com.norswap.util.Caster; +import com.norswap.util.DeepCopy; +import com.norswap.util.Exceptions; +import com.norswap.util.HandleMap; /** * A parsing expression is matched to the source text by recursively invoking the {@link #parse} @@ -37,7 +38,7 @@ public abstract class ParsingExpression implements DeepCopy public int parseDumb(Parser parser, int position) { throw new UnsupportedOperationException( - "Parsing expression class " + "Parsing expression [" + this + "] of class " + this.getClass().getSimpleName() + " doesn't support dumb parsing."); } @@ -56,19 +57,16 @@ public int parseDumb(Parser parser, int position) public final String toString() { StringBuilder builder = new StringBuilder(); - toString(builder); + appendTo(builder); return builder.toString(); } // --------------------------------------------------------------------------------------------- /** - * Similar to {@code builder.append(this.toString())}. - * {@link #toString} uses this method internally. - * - * Implemented by writing the name if there is one or else by calling {@link #appendTo}. + * {@code builder.append(this.toString())} */ - public final void toString(StringBuilder builder) + public final void appendTo(StringBuilder builder) { String name = name(); @@ -78,7 +76,7 @@ public final void toString(StringBuilder builder) } else { - appendTo(builder); + appendContentTo(builder); } } @@ -88,10 +86,10 @@ public final void toString(StringBuilder builder) * Like {@link #toString()}, but never writes the name of an expression instead of its content. * As a result, this *can not* be used to print recursive expressions. */ - public final String toStringFull() + public final String toContentString() { StringBuilder builder = new StringBuilder(); - appendTo(builder); + appendContentTo(builder); return builder.toString(); } @@ -99,11 +97,25 @@ public final String toStringFull() /** * Appends a string representation of this expression (but never its name) to the builder. + *

+ * Called by {@link #toString()} and {@link #appendTo(StringBuilder)} if the expression isn't + * named; and by {@link #toContentString()}. + */ + public abstract void appendContentTo(StringBuilder builder); + + // --------------------------------------------------------------------------------------------- + + /** + * Returns a string containing information about the expression that isn't contained in its + * type or its children. */ - public abstract void appendTo(StringBuilder builder); + public String ownPrintableData() + { + return ""; + } //////////////////////////////////////////////////////////////////////////////////////////////// - // TREE WALKING + // GRAPH WALKING // --------------------------------------------------------------------------------------------- @@ -142,14 +154,14 @@ public final void setName(String name) //////////////////////////////////////////////////////////////////////////////////////////////// // PROPERTIES - public Nullability nullability() + public Nullability nullability(Grammar grammar) { return Nullability.no(this); } // --------------------------------------------------------------------------------------------- - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return new ParsingExpression[0]; } diff --git a/src/com/norswap/autumn/parsing/expressions/common/UnaryParsingExpression.java b/src/com/norswap/autumn/parsing/expressions/common/UnaryParsingExpression.java index 400aaac..a8406b9 100644 --- a/src/com/norswap/autumn/parsing/expressions/common/UnaryParsingExpression.java +++ b/src/com/norswap/autumn/parsing/expressions/common/UnaryParsingExpression.java @@ -1,8 +1,7 @@ package com.norswap.autumn.parsing.expressions.common; -import com.norswap.autumn.parsing.graph.nullability.Nullability; - -import java.util.stream.Stream; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.graph.Nullability; /** * Base implementation for parsing expression with a single operand. @@ -38,19 +37,29 @@ public void setChild(int position, ParsingExpression pe) * operand between parens. */ @Override - public void appendTo(StringBuilder builder) + public void appendContentTo(StringBuilder builder) { String name = this.getClass().getSimpleName(); name = name.substring(0,1).toLowerCase() + name.substring(1); builder.append(name); builder.append("("); - operand.toString(builder); + operand.appendTo(builder); builder.append(")"); } //////////////////////////////////////////////////////////////////////////////////////////////// + @Override + public UnaryParsingExpression clone() + { + UnaryParsingExpression clone = (UnaryParsingExpression) super.clone(); + clone.operand = operand.clone(); + return clone; + } + + // --------------------------------------------------------------------------------------------- + @Override public UnaryParsingExpression deepCopy() { @@ -62,7 +71,7 @@ public UnaryParsingExpression deepCopy() //////////////////////////////////////////////////////////////////////////////////////////////// @Override - public Nullability nullability() + public Nullability nullability(Grammar grammar) { if (operand == null) { @@ -75,7 +84,7 @@ public Nullability nullability() // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression[] firsts() + public ParsingExpression[] firsts(Grammar grammar) { return new ParsingExpression[]{operand}; } diff --git a/src/com/norswap/autumn/parsing/expressions/instrument/StackTrace.java b/src/com/norswap/autumn/parsing/expressions/instrument/StackTrace.java index 2115398..a5b38bb 100644 --- a/src/com/norswap/autumn/parsing/expressions/instrument/StackTrace.java +++ b/src/com/norswap/autumn/parsing/expressions/instrument/StackTrace.java @@ -4,7 +4,7 @@ import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.InstrumentedExpression; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; import static com.norswap.autumn.parsing.Registry.PSH_STACK_TRACE; diff --git a/src/com/norswap/autumn/parsing/expressions/instrument/Trace.java b/src/com/norswap/autumn/parsing/expressions/instrument/Trace.java index 1a8332f..d6c5ed0 100644 --- a/src/com/norswap/autumn/parsing/expressions/instrument/Trace.java +++ b/src/com/norswap/autumn/parsing/expressions/instrument/Trace.java @@ -3,6 +3,7 @@ import com.norswap.autumn.parsing.ParseState; import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.InstrumentedExpression; +import com.norswap.util.Strings; import static com.norswap.autumn.parsing.Registry.PH_DEPTH; @@ -20,7 +21,7 @@ public void parse(Parser parser, ParseState state) parser.ext.set(PH_DEPTH, depth = 0); } - System.err.println(new String(new char[depth]).replace("\0", "-|") + operand); + System.err.println(Strings.times(depth, "-|") + operand); parser.ext.set(PH_DEPTH, depth + 1); operand.parse(parser, state); diff --git a/src/com/norswap/autumn/parsing/graph/Slot.java b/src/com/norswap/autumn/parsing/graph/ChildSlot.java similarity index 52% rename from src/com/norswap/autumn/parsing/graph/Slot.java rename to src/com/norswap/autumn/parsing/graph/ChildSlot.java index 9739242..8f4b581 100644 --- a/src/com/norswap/autumn/parsing/graph/Slot.java +++ b/src/com/norswap/autumn/parsing/graph/ChildSlot.java @@ -1,27 +1,53 @@ package com.norswap.autumn.parsing.graph; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.util.slot.Slot; /** - * Represents an assignable parsing expression slot (a child) in another parsing expression. + * A slot corresponding to an indexed child of a parsing expression. */ -public final class Slot +public class ChildSlot implements Slot { //////////////////////////////////////////////////////////////////////////////////////////////// - public final ParsingExpression pe; - public final int index; + /** + * A read-only child slot ({@link #set} is a no-op). + */ + public static final class ReadOnly extends ChildSlot + { + public ReadOnly(ParsingExpression pe, int index) + { + super(pe, index); + } - //////////////////////////////////////////////////////////////////////////////////////////////// + @Override + public Slot set(ParsingExpression child) + { + return this; + } + } - public Slot(ParsingExpression pe, int index) + public ChildSlot(ParsingExpression pe, int index) { this.pe = pe; this.index = index; } + @Override + public Slot set(ParsingExpression child) + { + pe.setChild(index, child); + return this; + } + //////////////////////////////////////////////////////////////////////////////////////////////// + public final ParsingExpression pe; + public final int index; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override public ParsingExpression get() { return pe.children()[index]; @@ -29,9 +55,10 @@ public ParsingExpression get() // --------------------------------------------------------------------------------------------- - public void set(ParsingExpression child) + @Override + public String toString() { - pe.setChild(index, child); + return "child [" + index + "] of " + pe; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/graph/ExpressionGraphTransformer.java b/src/com/norswap/autumn/parsing/graph/ExpressionGraphTransformer.java deleted file mode 100644 index 28ba5b5..0000000 --- a/src/com/norswap/autumn/parsing/graph/ExpressionGraphTransformer.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.norswap.autumn.parsing.graph; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * An expression graph walker that transforms an expression as it walks it. - * - * After each child has been walked, it is replaced by the result of calling {@link #transform} - * with it as the parameter. - * - * If {@link #unique} is set, {@link #transform} will only be called once on every expression, - * and the result will be cached, to be reused whenever the expression is encountered again. Note - * that if you intend to modify the named alternates of an expression cluster, you *must* use - * this option, otherwise you won't work in filters anymore. - * - * If you want to pass the transformation function as a lambda, see {@link FunctionalTransformer}. - */ -public abstract class ExpressionGraphTransformer extends ExpressionGraphWalker -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - public final boolean unique; - - private Map transformations; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public ExpressionGraphTransformer(boolean unique) - { - this.unique = unique; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public abstract ParsingExpression transform(ParsingExpression pe); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Apply the transformation to all expressions reachable through {@code pe}, and returns the - * transformation of {@code pe}. - */ - protected ParsingExpression apply(ParsingExpression pe) - { - if (unique) { - transformations = new HashMap<>(); - } - - walk(pe); - ParsingExpression out = transform(pe); - transformations = null; - return out; - } - - // --------------------------------------------------------------------------------------------- - - /** - * Apply the transformation to all expressions reachable through expressions in {@code exprs}. - * Replaces elements of {@code exprs} by their transformation, and return {@code exprs}. - */ - protected ParsingExpression[] apply(ParsingExpression[] exprs) - { - if (unique) { - transformations = new HashMap<>(); - } - - walk(exprs); - - for (int i = 0; i < exprs.length; ++i) - { - exprs[i] = transform(exprs[i]); - } - - transformations = null; - return exprs; - } - - // --------------------------------------------------------------------------------------------- - - /** - * Apply the transformation to all expressions reachable through expressions in {@code exprs}. - * Returns a collection of the transformation of the elements of {@code exprs}, preserving - * the iteration order. - * - */ - protected Collection apply(Iterable exprs) - { - if (unique) { - transformations = new HashMap<>(); - } - - ArrayList array = new ArrayList<>(); - - walk(exprs); - - for (ParsingExpression expr: exprs) - { - array.add(transform(expr)); - } - - transformations = null; - return array; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void afterChild(ParsingExpression pe, ParsingExpression child, int index, State state) - { - pe.setChild(index, - unique - ? transformations.computeIfAbsent(child, this::transform) - : transform(child)); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/ExpressionGraphWalker.java b/src/com/norswap/autumn/parsing/graph/ExpressionGraphWalker.java deleted file mode 100644 index 0fd15ab..0000000 --- a/src/com/norswap/autumn/parsing/graph/ExpressionGraphWalker.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.norswap.autumn.parsing.graph; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; - -import static com.norswap.autumn.parsing.graph.ExpressionGraphWalker.State.*; - -/** - * Captures the pattern of walking over recursive parsing expression graphs. - * - * Upon entering each node, {@link #before} is called. For each of its children, {@link - * #afterChild is called}. The state passed indicate to this method indicate whether we just - * recursively walked the child (ABSENT), if the child was already walked in another branch - * (VISITED) or if this is a recursive visit of the child (VISITING). After all children have - * been walked, {@link #afterAll} is called. - * - * The algorithm never enters a node twice: {@link #before} and {@link #afterAll} are called only - * once per node, hence recursion is cutoff when we encounter nodes we have already visited. - * - * When you extend the methods, you should give it (a) clean entry point(s). These should call - * one of the {@link #walk} methods available. - */ -public abstract class ExpressionGraphWalker -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - // CALLBACKS - - protected void before(ParsingExpression pe) {} - - protected void afterChild(ParsingExpression pe, ParsingExpression child, int index, State state) {} - - protected void afterAll(ParsingExpression pe) {} - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public enum State { ABSENT, VISITED, VISITING } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - private Map states = new HashMap<>(); - - private boolean cutoff = false; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Call this from one of the callbacks to cutoff further recursion. If called from {@link - * #before}, this will block recursion into the children of the node. If called from {@link - * #afterChild}, it will block recursion into further siblings of the child node. Calling this - * from {@link #afterAll} has no effect. - */ - public void cutoff() - { - cutoff = true; - } - - // --------------------------------------------------------------------------------------------- - - public boolean isCutoff() - { - return cutoff; - } - - // --------------------------------------------------------------------------------------------- - - /** - * Walks all the expression in the array, using the same state for all. This means that - * expressions reachable from two entries in the array will still be entered only once. - */ - protected void walk(ParsingExpression[] exprs) - { - for (ParsingExpression pe: exprs) - { - _walk(pe); - } - - states = null; - } - - // --------------------------------------------------------------------------------------------- - - /** - * Walks all the expression in the iterable, using the same state for all. This means that - * expressions reachable from two entries in the iterable will still be entered only once. - */ - protected void walk(Iterable exprs) - { - for (ParsingExpression pe: exprs) - { - _walk(pe); - } - - states = null; - } - - // --------------------------------------------------------------------------------------------- - - protected void walk(ParsingExpression pe) - { - _walk(pe); - states = null; - } - - // --------------------------------------------------------------------------------------------- - - /** - * Returns the state to be passed to pe's parent's {@link #afterChild} invocation for pe. - */ - private final State _walk(ParsingExpression pe) - { - switch (states.getOrDefault(pe, ABSENT)) - { - case ABSENT: - states.put(pe, VISITING); - break; - - // Don't enter the node twice. - - case VISITING: - return VISITING; - - case VISITED: - return VISITED; - } - - /**/ cleanup: do { - - before(pe); - if (cutoff) { break cleanup; } - - ParsingExpression[] children = children(pe); - - for (int i = 0; i < children.length; ++i) - { - afterChild(pe, children[i], i, _walk(children[i])); - if (cutoff) { break cleanup; } - } - - /**/ } while(false); // end cleanup - - cutoff = false; - afterAll(pe); - states.put(pe, VISITED); - return ABSENT; - } - - // --------------------------------------------------------------------------------------------- - - protected ParsingExpression[] children(ParsingExpression pe) - { - return pe.children(); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/FirstCalculator.java b/src/com/norswap/autumn/parsing/graph/FirstCalculator.java deleted file mode 100644 index 3bd6f58..0000000 --- a/src/com/norswap/autumn/parsing/graph/FirstCalculator.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.norswap.autumn.parsing.graph; - -import com.norswap.autumn.parsing.expressions.Sequence; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.nullability.NullabilityCalculator; -import com.norswap.autumn.util.MultiMap; - -import java.util.Set; - -/** - * Computes the FIRST set of parsing expressions. - * - * For PEGs, we take the FIRST set of an expression e1 to be any expression e2 that can be entered - * from e1 without advancing the input. - * - * This is not actually in use; I incorrectly assumed it would be necessary for left-recursion - * detection. Nevertheless it derives pretty easily from {@link ParsingExpression#firsts}, which - * is necessary for left-recursion detection, and so I leave it standing. - * - * We walk our graph and add the result of {@code pe.firsts()} (i.e. the direct children of pe - * that can be invoked at the same input position) to the FIRST(pe). We then include FIRST(x) in - * FIRST(pe) for each x we just added (since (FIRST(pe) contains x) => (FIRST(x) subset of FIRST - * (pe)). But this is not sufficient, due to recursion. - * - * To solve the issue, in addition from storing the mapping (x -> y | FIRST(x) contains y), we - * also store the reverse mapping (x -> y | FIRST(y) contains x). Whenever FIRST(x) is - * updated, we also update the FIRST set of all expressions in reverse(x). - * - * So a FIRST set can change as part of our normal walk, or due to a cascading update via the - * reverse set. Note that we need to ensure that the set actually changed (i.e. grew) before - * propagating changes, otherwise we are faced with infinite propagation. - * - * ---- - * - * NOTE: {@link Sequence#firsts()} relies on {@link #nullCalc} being set to a completed - * nullability calculator. Even if this method is not used in the context of FirstCalculator! - */ -public final class FirstCalculator extends ExpressionGraphWalker -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Nullability calculator required by {@link Sequence#firsts()}. - */ - public static NullabilityCalculator nullCalc; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * The x -> FIRST(x) mapping. Can be freely accessed after the calculator has run. - */ - public MultiMap first = new MultiMap<>(); - - //---------------------------------------------------------------------------------------------- - - private MultiMap reverse = new MultiMap<>(); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Computes and returns the FIRST sets for all parsing expression reachable through the the - * given rules ({@link #first}). - */ - public static MultiMap compute(ParsingExpression[] rules) - { - return new FirstCalculator().run(rules); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Computes and returns the FIRST sets for all parsing expression reachable through the the - * given rules ({@link #first}). - */ - public MultiMap run(ParsingExpression[] rules) - { - walk(rules); - reverse = null; - return first; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void afterAll(ParsingExpression pe) - { - ParsingExpression[] peFirsts = pe.firsts(); - add(pe, peFirsts); - - for (ParsingExpression expr: peFirsts) - { - add(pe, first.get(expr)); - } - - Set peNewFirsts = first.get(pe); - - for (ParsingExpression expr: reverse.get(pe)) - { - addAndPropagate(expr, peNewFirsts); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - private void addAndPropagate(ParsingExpression pe, Iterable set) - { - // The size comparison avoids infinite propagation. - int size = first.get(pe).size(); - - if (add(pe, set).size() > size) - { - for (ParsingExpression expr: reverse.get(pe)) - { - addAndPropagate(pe, set); - } - } - } - - // --------------------------------------------------------------------------------------------- - - private void add(ParsingExpression pe, ParsingExpression[] firsts) - { - first.addAll(pe, firsts); - - for (ParsingExpression expr: firsts) - { - reverse.add(expr, pe); - } - } - - // --------------------------------------------------------------------------------------------- - - private Set add(ParsingExpression pe, Iterable firsts) - { - Set out = first.addAll(pe, firsts); - - for (ParsingExpression expr: firsts) - { - reverse.add(expr, pe); - } - - return out; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/FunctionalTransformer.java b/src/com/norswap/autumn/parsing/graph/FunctionalTransformer.java deleted file mode 100644 index b9fcd3c..0000000 --- a/src/com/norswap/autumn/parsing/graph/FunctionalTransformer.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.norswap.autumn.parsing.graph; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import java.util.Collection; - -/** - * An expression graph transformer whose transformation function is passed as a lambda. - */ -public final class FunctionalTransformer extends ExpressionGraphTransformer -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - @FunctionalInterface - public interface ExpressionTransformer - { - ParsingExpression transform(ParsingExpression pe); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public final ExpressionTransformer transformer; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public FunctionalTransformer(ExpressionTransformer transformer, boolean unique) - { - super(unique); - this.transformer = transformer; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public ParsingExpression transform(ParsingExpression pe) - { - return transformer.transform(pe); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static Collection apply( - Iterable exprs, ExpressionTransformer transformer, boolean unique) - { - return new FunctionalTransformer(transformer, unique).apply(exprs); - } - - // --------------------------------------------------------------------------------------------- - - public static ParsingExpression[] apply( - ParsingExpression[] exprs, ExpressionTransformer transformer, boolean unique) - { - return new FunctionalTransformer(transformer, unique).apply(exprs); - } - - // --------------------------------------------------------------------------------------------- - - public static ParsingExpression apply( - ParsingExpression pe, ExpressionTransformer transformer, boolean unique) - { - return new FunctionalTransformer(transformer, unique).apply(pe); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Collection apply(Iterable exprs) - { - return super.apply(exprs); - } - - // --------------------------------------------------------------------------------------------- - - @Override - public ParsingExpression[] apply(ParsingExpression[] exprs) - { - return super.apply(exprs); - } - - // --------------------------------------------------------------------------------------------- - - @Override - public ParsingExpression apply(ParsingExpression pe) - { - return super.apply(pe); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/LeftRecursionBreaker.java b/src/com/norswap/autumn/parsing/graph/LeftRecursionBreaker.java deleted file mode 100644 index 6a9eb6b..0000000 --- a/src/com/norswap/autumn/parsing/graph/LeftRecursionBreaker.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.norswap.autumn.parsing.graph; - -import com.norswap.autumn.parsing.expressions.LeftRecursive; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; - -import java.util.HashMap; -import java.util.Set; - -import static com.norswap.autumn.parsing.ParsingExpressionFactory.leftRecursive; - -/** - * This break left-recursive cycles detected by a {@link LeftRecursionDetector} by wrapping every - * occurrence of expressions that the detector has recorded in a {@link LeftRecursive} expression. - * - * To do so, the breaker starts by creating the LeftRecursive replacement for each node recorded - * by the detector. It then walks the graph and records the location (a {@link Slot}) where each - * recorded node occur. We can't replace nodes during the walk as that would break the walking - * algorithm. Finally, it replaces each recorded location by its proper replacement. - */ -public final class LeftRecursionBreaker extends ExpressionGraphWalker -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - private static final class Mod - { - Slot slot; - LeftRecursive replacement; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - private HashMap replacements; - private Array mods; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Breaks left-recursive cycles, in the manner specified by {@link LeftRecursionDetector}. - * Modifies the {@code rules} array in place and returns it. - */ - public static ParsingExpression[] breakCycles(ParsingExpression[] rules) - { - return new LeftRecursionBreaker().run(rules); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Breaks left-recursive cycles, in the manner specified by {@link LeftRecursionDetector}. - * Modifies the {@code rules} array in place and returns it. - */ - public ParsingExpression[] run(ParsingExpression[] rules) - { - Set leftRecursives = LeftRecursionDetector.detect(rules); - - replacements = new HashMap<>(); - - for (ParsingExpression pe : leftRecursives) - { - replacements.put(pe, leftRecursive(pe)); - } - - mods = new Array<>(); - walk(rules); - - for (Mod mod: mods) - { - mod.slot.set(mod.replacement); - } - - for (int i = 0; i < rules.length; ++i) - { - LeftRecursive replacement = replacements.get(rules[i]); - - if (replacement != null) - { - rules[i] = replacement; - } - } - - return rules; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void afterChild(ParsingExpression pe, ParsingExpression child, int index, State state) - { - LeftRecursive replacement = replacements.get(child); - - if (replacement != null) - { - Mod mod = new Mod(); - mod.slot = new Slot(pe, index); - mod.replacement = replacement; - mods.add(mod); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/LeftRecursionDetector.java b/src/com/norswap/autumn/parsing/graph/LeftRecursionDetector.java index 1391d64..8a1605d 100644 --- a/src/com/norswap/autumn/parsing/graph/LeftRecursionDetector.java +++ b/src/com/norswap/autumn/parsing/graph/LeftRecursionDetector.java @@ -1,127 +1,108 @@ package com.norswap.autumn.parsing.graph; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.ParsingExpressionFactory; import com.norswap.autumn.parsing.expressions.LeftRecursive; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; +import com.norswap.util.graph_visit.GraphVisitor; +import com.norswap.util.graph_visit.NodeState; +import com.norswap.util.slot.Slot; import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.List; /** - * This detects left-recursive cycles in a parsing expression graphs. For each cycle, it selects - * a parsing expression that must be marked as left recursive to break the cycle and puts into - * {@link #leftRecursives}. - * - * The detector is aware of pre-resolved left-recursion (via {@link LeftRecursive} nodes and does - * not record nodes in {@link #leftRecursives} for that cycle, unless they belong to another cycle. - * - * The basic idea of the algorithm is to mark an expression as left-recursive whenever {@link - * #afterChild} reports {@link State#VISITING}. Effectively, this means that the expression - * selected to break a cycle is the one encountered first when walking the rules in a top-down, - * left-to-right (w.r.t. the order of {@link ParsingExpression#firsts}) manner. Cycles reachable - * from multiple rules will be detected in the first rule that reaches it. - * - * However, this doesn't account for pre-existent {@link LeftRecursive} nodes. To account for - * them, we map each expression to the recursion depth at which it occurs. We also record the - * recursion depth of each encountered LeftRecursive node. When detecting recursion; if the - * recursive node occurs at a lower stack depth than the last encountered LeftRecursive node, it - * means that the cycle goes through the LeftRecursive node and is thus already broken; so we do - * not record it. - * - * This class only detects cycles and record the expressions at which theses cycles should be - * broken. To actually break them, see {@link LeftRecursionBreaker}. + * This detects left-recursive cycles in a parsing expression graphs. For each cycle, it selects a + * node that must be marked as left recursive (by wrapping it inside a {@link LeftRecursive} node) + * to break the cycle. The selected node will be mapped to a new {@link LeftRecursive} inside {@link + * #leftRecursives}. + *

+ * The node selected to break a cycle is the first node pertaining to the cycle encountered in a + * top-down left-to-right walk of the graph. + *

+ * The visitor is aware of pre-existent {@link LeftRecursive} nodes and does not detect already + * cycles anew. + *

+ * To handle these nodes, we map each expression to the recursion depth at which it occurs. We also + * record the recursion depth of each encountered LeftRecursive node. When detecting recursion; if + * the recursive node occurs at a lower stack depth than the last encountered LeftRecursive node, it + * means that the cycle goes through the LeftRecursive node and is thus already broken; so we do not + * record it. */ -public final class LeftRecursionDetector extends ExpressionGraphWalker +public class LeftRecursionDetector extends GraphVisitor { //////////////////////////////////////////////////////////////////////////////////////////////// - public Set leftRecursives; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - private int stackDepth = 0; - private HashMap stackPositions = new HashMap<>(); - private Array leftRecursiveStackPositions = new Array<>(); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Runs the detector then returns {@link #leftRecursives}. - */ - public static Set detect(ParsingExpression[] rules) + public LeftRecursionDetector(Grammar grammar) { - return new LeftRecursionDetector().run(rules); + super(Walks.inPlaceFirsts(grammar)); } //////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Runs the detector then returns {@link #leftRecursives}. - */ - public Set run(ParsingExpression[] rules) - { - leftRecursives = new HashSet<>(); - stackDepth = 0; - stackPositions = new HashMap<>(); - leftRecursiveStackPositions = new Array<>(); + private int stackDepth = 0; - walk(rules); + private HashMap stackPositions = new HashMap<>(); - stackPositions = null; - leftRecursiveStackPositions = null; - return leftRecursives; - } + private Array leftRecursiveStackPositions = new Array<>(); + + public HashMap leftRecursives = new HashMap<>(); //////////////////////////////////////////////////////////////////////////////////////////////// @Override - protected void before(ParsingExpression pe) + public void before(ParsingExpression pe) { if (pe instanceof LeftRecursive) { leftRecursiveStackPositions.push(stackDepth); } - stackPositions.put(pe, stackDepth++); + stackPositions.put(pe, stackDepth); + ++stackDepth; } // --------------------------------------------------------------------------------------------- @Override - protected void afterChild(ParsingExpression pe, ParsingExpression child, int index, State state) + public void after(ParsingExpression pe, List> children, NodeState state) { - Integer leftPos = leftRecursiveStackPositions.peekOrNull(); - - if (state == State.VISITING - && stackPositions.get(child) > (leftPos != null ? leftPos : -1)) + if (pe instanceof LeftRecursive) { - leftRecursives.add(child); + leftRecursiveStackPositions.pop(); } + + stackPositions.remove(pe); + --stackDepth; } // --------------------------------------------------------------------------------------------- @Override - protected void afterAll(ParsingExpression pe) + public void afterChild(ParsingExpression pe, Slot slot, NodeState state) { - if (pe instanceof LeftRecursive) + if (state == NodeState.CUTOFF) { - leftRecursiveStackPositions.pop(); + ParsingExpression child; + Integer leftPos = leftRecursiveStackPositions.peekOr(-1); + + if (stackPositions.get(child = slot.get()) > leftPos) + { + LeftRecursive lr = ParsingExpressionFactory.leftRecursive(child); + leftRecursives.put(child, ParsingExpressionFactory.leftRecursive(child)); + } } - - stackPositions.remove(pe); - --stackDepth; } - - //////////////////////////////////////////////////////////////////////////////////////////////// + // --------------------------------------------------------------------------------------------- @Override - protected ParsingExpression[] children(ParsingExpression pe) + public void conclude() { - return pe.firsts(); + stackPositions = null; + leftRecursiveStackPositions = null; } //////////////////////////////////////////////////////////////////////////////////////////////// -} +} \ No newline at end of file diff --git a/src/com/norswap/autumn/parsing/graph/nullability/Nullability.java b/src/com/norswap/autumn/parsing/graph/Nullability.java similarity index 55% rename from src/com/norswap/autumn/parsing/graph/nullability/Nullability.java rename to src/com/norswap/autumn/parsing/graph/Nullability.java index fef9eff..e4ac493 100644 --- a/src/com/norswap/autumn/parsing/graph/nullability/Nullability.java +++ b/src/com/norswap/autumn/parsing/graph/Nullability.java @@ -1,7 +1,9 @@ -package com.norswap.autumn.parsing.graph.nullability; +package com.norswap.autumn.parsing.graph; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import java.util.Arrays; + /** * A nullability indicates whether a parsing expression is nullable; or, if it can't be determined * yet, on what this determination depends on. @@ -47,7 +49,7 @@ public class Nullability //////////////////////////////////////////////////////////////////////////////////////////////// - Nullability(ParsingExpression pe, boolean resolved, boolean nullable, ParsingExpression[] tr) + protected Nullability(ParsingExpression pe, boolean resolved, boolean nullable, ParsingExpression[] tr) { this.pe = pe; this.resolved = resolved; @@ -88,45 +90,154 @@ public final boolean no() /** * {@code bool ? yes(pe) : no(pe)} */ - public static final Nullability bool(ParsingExpression pe, boolean bool) + public static Nullability bool(ParsingExpression pe, boolean bool) { return new Nullability(pe, true, bool, null); } // --------------------------------------------------------------------------------------------- - public static final Nullability yes(ParsingExpression pe) + public static Nullability yes(ParsingExpression pe) { return new Nullability(pe, true, true, null); } // --------------------------------------------------------------------------------------------- - public static final Nullability no(ParsingExpression pe) + public static Nullability no(ParsingExpression pe) { return new Nullability(pe, true, false, null); } // --------------------------------------------------------------------------------------------- - public static final AllNullable all(ParsingExpression pe, ParsingExpression[] toReduce) + public static Nullability all(ParsingExpression pe, ParsingExpression[] toReduce) { - return new AllNullable(pe, toReduce); + return new Nullability(pe, false, false, toReduce) + { + @Override + public Nullability reduce(Nullability[] nullabilities) + { + boolean allYes = true; + + for (Nullability n : nullabilities) + { + if (n.resolved) + { + if (!n.nullable) + { + return no(pe); + } + } + else if (allYes) + { + allYes = false; + } + } + + if (allYes) + { + return yes(pe); + } + + return all(pe, Arrays.stream(nullabilities) + .filter(n -> !n.resolved) + .map(n -> n.pe) + .toArray(ParsingExpression[]::new)); + } + + @Override + public Nullability update(Nullability n) + { + return n.no() + ? no(pe) + : null; + } + }; } // --------------------------------------------------------------------------------------------- - public static final AnyNullable any(ParsingExpression pe, ParsingExpression[] toReduce) + public static final Nullability any(ParsingExpression pe, ParsingExpression[] toReduce) { - return new AnyNullable(pe, toReduce); + return new Nullability(pe, false, false, toReduce) + { + @Override + public Nullability reduce(Nullability[] nullabilities) + { + boolean allNo = true; + + for (Nullability n : nullabilities) + { + if (n.resolved) + { + if (n.nullable) + { + return yes(pe); + } + } + else if (allNo) + { + allNo = false; + } + } + + if (allNo) + { + return no(pe); + } + + return any(pe, Arrays.stream(nullabilities) + .filter(n -> !n.resolved) + .map(n -> n.pe) + .toArray(ParsingExpression[]::new)); + } + + @Override + public Nullability update(Nullability n) + { + return n.yes() + ? yes(pe) + : null; + } + }; } // --------------------------------------------------------------------------------------------- - public static final SingleNullable single(ParsingExpression pe, ParsingExpression operand) + public static Nullability single(ParsingExpression pe, ParsingExpression operand) { - return new SingleNullable(pe, operand); + return new Nullability(pe, false, false, new ParsingExpression[]{operand}) + { + @Override + public Nullability reduce(Nullability[] nullabilities) + { + Nullability n = nullabilities[0]; + + if (n.resolved) + { + return n.nullable + ? yes(pe) + : no(pe); + } + + return this; + } + + @Override + public Nullability update(Nullability n) + { + if (n.resolved) + { + return n.nullable + ? yes(pe) + : no(pe); + } + + return null; + } + }; } //////////////////////////////////////////////////////////////////////////////////////////////// -} +} \ No newline at end of file diff --git a/src/com/norswap/autumn/parsing/graph/nullability/NullabilityCalculator.java b/src/com/norswap/autumn/parsing/graph/NullabilityCalculator.java similarity index 65% rename from src/com/norswap/autumn/parsing/graph/nullability/NullabilityCalculator.java rename to src/com/norswap/autumn/parsing/graph/NullabilityCalculator.java index d1defcb..a2cdfd2 100644 --- a/src/com/norswap/autumn/parsing/graph/nullability/NullabilityCalculator.java +++ b/src/com/norswap/autumn/parsing/graph/NullabilityCalculator.java @@ -1,12 +1,15 @@ -package com.norswap.autumn.parsing.graph.nullability; +package com.norswap.autumn.parsing.graph; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.ExpressionGraphWalker; -import com.norswap.autumn.util.MultiMap; +import com.norswap.util.MultiMap; +import com.norswap.util.graph_visit.GraphVisitor; +import com.norswap.util.graph_visit.NodeState; +import com.norswap.util.slot.Slot; import java.util.Arrays; import java.util.HashMap; -import java.util.stream.Stream; +import java.util.List; /** * Determines which rules in a parsing expression graph are nullable. @@ -23,14 +26,14 @@ * * To resolve this issue, whenever a nullability cannot be resolved right away, we register the * expression as a "dependant" of its children. Whenever a child becomes resolved, we re-reduce - * all its dependants. Note a child can be become resolved through our walk, or because it was + * all its dependants. Note a child can be become resolved by visiting it, or because it was * itself re-reduced because one of its own child became resolved. * * After running the calculator, the remaining unresolved nullabilities come from infinite * recursion (e.g., "X = X"). Since our handling of left-recursion will ensure that these rules * always fail, we don't need to consider them nullable. */ -public class NullabilityCalculator extends ExpressionGraphWalker +public class NullabilityCalculator extends GraphVisitor { //////////////////////////////////////////////////////////////////////////////////////////////// @@ -38,21 +41,17 @@ public class NullabilityCalculator extends ExpressionGraphWalker private MultiMap dependants = new MultiMap<>(); + private Grammar grammar; + //////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Returns a stream of nullable parsing expression. Call only after the calculator has run. - */ - public Stream nullables() + public NullabilityCalculator(Grammar grammar) { - return nullabilities - .entrySet() - .stream() - .filter(e -> e.getValue().yes()) - .map(e -> e.getKey()); + super(Walks.readOnly); + this.grammar = grammar; } - // ----------------------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////////////////////// /** * Indicate whether the supplied parsing expression is nullable. @@ -65,40 +64,16 @@ public boolean isNullable(ParsingExpression pe) //////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Computes and returns a stream of nullable expressions ({@link #nullables})reachable through - * the given rules. - */ - public static Stream compute(ParsingExpression[] rules) - { - return new NullabilityCalculator().run(rules); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Computes and returns a stream of nullable expressions ({@link #nullables})reachable through - * the given rules. - */ - public Stream run(ParsingExpression[] rules) - { - walk(rules); - dependants = null; - return nullables(); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - @Override - protected void before(ParsingExpression pe) + public void before(ParsingExpression pe) { - nullabilities.put(pe, pe.nullability()); + nullabilities.put(pe, pe.nullability(grammar)); } // ----------------------------------------------------------------------------------------- @Override - protected void afterAll(ParsingExpression pe) + public void after(ParsingExpression pe, List> children, NodeState state) { Nullability n = nullabilities.get(pe); @@ -106,21 +81,40 @@ protected void afterAll(ParsingExpression pe) return; } - n = reduce(n); - nullabilities.put(pe, n); + reduce(n); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// - if (n.resolved) { - propagateResolution(n); + private Nullability update(Nullability n) + { + Nullability updated = n.update(n); + + if (updated == null) + { + return reduce(n); + } + else + { + nullabilities.put(updated.pe, updated); + propagateResolution(updated); + return updated; } } - //////////////////////////////////////////////////////////////////////////////////////////////// + // --------------------------------------------------------------------------------------------- private Nullability reduce(Nullability n) { n = n.reduce(nullabilities(n.toReduce)); - if (!n.resolved) + nullabilities.put(n.pe, n); + + if (n.resolved) + { + propagateResolution(n); + } + else { for (ParsingExpression pe: n.toReduce) { @@ -143,17 +137,7 @@ private void propagateResolution(Nullability n) continue; } - Nullability tmp; - - n = (tmp = n.update(n)) != null - ? tmp - : reduce(n); - - nullabilities.put(expr, n); - - if (n.resolved) { - propagateResolution(n); - } + update(n); } } diff --git a/src/com/norswap/autumn/parsing/graph/Printer.java b/src/com/norswap/autumn/parsing/graph/Printer.java new file mode 100644 index 0000000..ee2f4d0 --- /dev/null +++ b/src/com/norswap/autumn/parsing/graph/Printer.java @@ -0,0 +1,100 @@ +package com.norswap.autumn.parsing.graph; + +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.util.Strings; +import com.norswap.util.graph_visit.GraphVisitor; +import com.norswap.util.graph_visit.NodeState; +import com.norswap.util.slot.Slot; + +import java.util.List; +import java.util.function.Consumer; + +/** + * Prints a parsing expression as a tree. Useful for debugging. + */ +public class Printer extends GraphVisitor +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + private Consumer sink; + + private int depth = 0; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public Printer(Consumer sink) + { + super(Walks.inPlace); + this.sink = sink; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void before(ParsingExpression pe) + { + String name = pe.name(); + String data = pe.ownPrintableData(); + + sink.accept(Strings.times(depth, "-|")); + sink.accept(pe.getClass().getSimpleName()); + sink.accept(" ("); + + if (name != null) + { + sink.accept(name); + sink.accept(" - defined"); + } + else + { + sink.accept(String.format("%X", pe.hashCode())); + } + + sink.accept(")"); + + if (!data.isEmpty()) + sink.accept(" [" + data + "]"); + + sink.accept("\n"); + + ++ depth; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void afterChild(ParsingExpression parent, Slot slot, NodeState state) + { + switch (state) + { + case CUTOFF: + sink.accept(Strings.times(depth, "-|")); + sink.accept("recursive (" + slot.get().name()); + sink.accept(")\n"); + break; + + case VISITED: + String name = slot.get().name(); + sink.accept(Strings.times(depth, "-|")); + sink.accept("visited ("); + sink.accept(name != null + ? name + : String.format("%X", slot.get().hashCode())); + sink.accept(")\n"); + break; + + default: + break; + } + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void after(ParsingExpression parsingExpression, List> children, NodeState state) + { + -- depth; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/graph/ReferenceResolver.java b/src/com/norswap/autumn/parsing/graph/ReferenceResolver.java index a1be1c8..5672e42 100644 --- a/src/com/norswap/autumn/parsing/graph/ReferenceResolver.java +++ b/src/com/norswap/autumn/parsing/graph/ReferenceResolver.java @@ -1,39 +1,40 @@ package com.norswap.autumn.parsing.graph; -import com.norswap.autumn.parsing.IncrementalReferenceResolver; import com.norswap.autumn.parsing.ParsingExpressionFactory; import com.norswap.autumn.parsing.expressions.Reference; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.MultiMap; +import com.norswap.util.graph_visit.GraphVisitor; +import com.norswap.util.graph_visit.NodeState; +import com.norswap.util.slot.Slot; import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** - * Resolves all resolvable references within a number of (possibly mutually referencing) parsing - * expressions. Resolvable references are those for which a target with the specified name exist - * within the expression graph. - * + * Resolves all resolvable references underneath the visited expression graph. Resolvable references + * are those for which a target with the specified name exist within the expression graph. + *

* As a result of the resolution process, all {@link Reference} nodes that have been resolved are * pruned from the expression tree and replaced with edge towards the expression they referenced, * hence making the tree a graph. - * - * This is the preferred way to resolve references in a expression that was constructed - * automatically. If you use factory methods, the method {@link ParsingExpressionFactory#recursive$} - * which uses a {@link IncrementalReferenceResolver} is an alternative. - * - * Implementation-wise, this is an expression graph transformer. The walk records named - * expressions as they are encountered. The transformation replaces a reference with its target, if - * it has already been encountered. Otherwise the reference stays, but the its - * location (a {@link Slot}) is recorded as needing to be assigned whenever the target is - * encountered. - * - * A reference's target might be another reference. We handle these cases by recursively - * resolving until we encounter a non-reference target, or a missing target. + *

+ * If there are unresolved references, an exception is thrown (but if caught, the above still + * applies). + *

+ * This is the preferred way to resolve references. If performance is critical, look into {@link + * ParsingExpressionFactory#recursive$}. */ -public final class ReferenceResolver extends ExpressionGraphTransformer +public class ReferenceResolver extends GraphVisitor { //////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Max allowed number of chained references. Used to detect reference loops (not be confused + * with loops in the grammar -- reference loops involve only references and no actual + * parsing expressions). + */ public static int REFERENCE_CHAIN_LIMIT = 10000; //////////////////////////////////////////////////////////////////////////////////////////////// @@ -41,184 +42,109 @@ public final class ReferenceResolver extends ExpressionGraphTransformer /** * Maps names (e.g. rule names) to the expression they designate. */ - private HashMap named; + public Map named = new HashMap<>(); - /** - * Map target names that can't be resolved to a slot. - */ - private MultiMap unresolved; + // --------------------------------------------------------------------------------------------- /** - * If {@link #transform} encounters a missing target, it will record its name here for the - * benefit of calling functions, who can associate a location to it. + * All the regular TODO */ - private String unresolvedTarget; + public Set> references = new HashSet<>(); //////////////////////////////////////////////////////////////////////////////////////////////// public ReferenceResolver() { - super(false); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static ParsingExpression resolve(ParsingExpression expr) - { - return new ReferenceResolver().run(expr); - } - - // --------------------------------------------------------------------------------------------- - - /** - * Resolves all references within the expressions reachable through {@code exrprs}. If {@code - * exprs} contains references, it is modified in place. It is also returned. - * - * Throws an exception if there are unresolvable expressions. - */ - public static ParsingExpression[] resolve(ParsingExpression[] exprs) - { - return new ReferenceResolver().run(exprs); + super(Walks.inPlace); } //////////////////////////////////////////////////////////////////////////////////////////////// - public ParsingExpression run(ParsingExpression expr) + @Override + public void before(ParsingExpression pe) { - named = new HashMap<>(); - unresolved = new MultiMap<>(); - - walk(expr); + String name = pe.name(); - if (!unresolved.isEmpty()) + if (name != null) { - throw new RuntimeException( - "There were unresolved references in the grammar: " + unresolved.keySet()); + named.put(name, pe); } - - named = null; - unresolved = null; - return expr; } // --------------------------------------------------------------------------------------------- - /** - * Resolves all references within the expressions reachable through {@code exrprs}. If {@code - * exprs} contains references, it is modified in place. It is also returned. - * - * Throws an exception if there are unresolvable expressions. - */ - public ParsingExpression[] run(ParsingExpression[] exprs) + @Override + public void afterChild(ParsingExpression pe, Slot slot, NodeState state) { - named = new HashMap<>(); - unresolved = new MultiMap<>(); - - walk(exprs); - - // Replace the references inside the array by their targets. - - for (int i = 0; i < exprs.length; ++i) + if (slot.get() instanceof Reference) { - exprs[i] = transform(exprs[i]); - - if (unresolvedTarget != null) - { - // Trigger the exception below. - unresolved.add(unresolvedTarget, null); - unresolvedTarget = null; - } + references.add(slot); } - - if (!unresolved.isEmpty()) - { - throw new RuntimeException( - "There were unresolved references in the grammar: " + unresolved.keySet()); - } - - named = null; - unresolved = null; - return exprs; } - //////////////////////////////////////////////////////////////////////////////////////////////// + // --------------------------------------------------------------------------------------------- @Override - public ParsingExpression transform(ParsingExpression pe) + public void afterRoot(Slot slot, NodeState state) { - String targetName; - - int i = 0; - while (pe instanceof Reference) + if (slot.get() instanceof Reference) { - targetName = ((Reference) pe).target; - ParsingExpression target = named.get(targetName); - - if (i > REFERENCE_CHAIN_LIMIT) - { - throw new RuntimeException( - "It is likely that you have a rule which is a reference to itself. " - + "If it is not the case and you use more than " + REFERENCE_CHAIN_LIMIT - + " chained references, increase the value of " - + "ReferenceResolver.REFERENCE_CHAIN_LIMIT."); - } - - if (target == null) - { - unresolvedTarget = targetName; - break; - } - - pe = target; + references.add(slot); } - - return pe; } // --------------------------------------------------------------------------------------------- @Override - protected void before(ParsingExpression pe) + public void conclude() { - String name = pe.name(); + HashSet unresolved = new HashSet<>(); - if (name == null) { - return; - } + for (Slot slot: references) + { + ParsingExpression target = slot.get(); + String name; + int i = 0; - named.put(name, pe); - updateSlotsResolution(name); - } + // References can be chained! - // --------------------------------------------------------------------------------------------- + do { + name = ((Reference)target).target; + target = named.get(name); - @Override - protected void afterChild(ParsingExpression pe, ParsingExpression child, int index, State state) - { - super.afterChild(pe, child, index, state); - updateSlotResolution(new Slot(pe, index)); - } + if (++i > REFERENCE_CHAIN_LIMIT) + { + panic(); + } + } + while (target != null && target instanceof Reference); - //////////////////////////////////////////////////////////////////////////////////////////////// + if (target == null) + { + unresolved.add(name); + } + else + { + slot.set(target); + } + } - private void updateSlotsResolution(String name) - { - for (Slot slot: unresolved.remove(name)) + if (!unresolved.isEmpty()) { - slot.set(transform(slot.get())); - updateSlotResolution(slot); + throw new RuntimeException( + "There were unresolved references in the grammar: " + unresolved); } } // --------------------------------------------------------------------------------------------- - private void updateSlotResolution(Slot slot) + private void panic() { - if (unresolvedTarget != null) - { - unresolved.add(unresolvedTarget, slot); - unresolvedTarget = null; - } + throw new RuntimeException( + "It is likely that you have a rule which is a reference to itself. " + + "If it is not the case and you use more than " + REFERENCE_CHAIN_LIMIT + + " chained references, increase the value of " + + "ReferenceResolver.REFERENCE_CHAIN_LIMIT."); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/parsing/graph/Replacer.java b/src/com/norswap/autumn/parsing/graph/Replacer.java new file mode 100644 index 0000000..cea9db5 --- /dev/null +++ b/src/com/norswap/autumn/parsing/graph/Replacer.java @@ -0,0 +1,45 @@ +package com.norswap.autumn.parsing.graph; + +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.util.graph_visit.GraphTransformer; + +import java.util.Map; + +/** + * Given a partial or total mapping between parsing expressions, this visitor replaces parsing + * expressions in the graph according to the mapping. + */ +public class Replacer extends GraphTransformer +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + private Map replacements; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public Replacer(Map replacements) + { + super(Walks.inPlace); + this.replacements = replacements; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public ParsingExpression transform(ParsingExpression pe) + { + ParsingExpression replacement = replacements.get(pe); + return replacement != null ? replacement : pe; + } + + // --------------------------------------------------------------------------------------------- + + @Override + public void conclude() + { + super.conclude(); + replacements = null; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/graph/Walks.java b/src/com/norswap/autumn/parsing/graph/Walks.java new file mode 100644 index 0000000..a295392 --- /dev/null +++ b/src/com/norswap/autumn/parsing/graph/Walks.java @@ -0,0 +1,80 @@ +package com.norswap.autumn.parsing.graph; + +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.util.Array; +import com.norswap.util.graph_visit.GraphWalker; +import com.norswap.util.Counter; +import com.norswap.util.slot.Slot; + +import java.util.Arrays; + +/** + * This class is a repository of walks over graphs along with modification modes (in-place, copy, + * read-only). + */ +public class Walks +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Walks the whole graph, modification are done in-place. + */ + public static GraphWalker inPlace = (pe, visitor) -> + { + Counter c = new Counter(); + Object[] slots = Arrays.stream(pe.children()).map(x -> new ChildSlot(pe, c.i++)).toArray(); + + return Array.>fromUnsafe(slots); + }; + + // --------------------------------------------------------------------------------------------- + + /** + * Walks the whole graph, modifications are applied to a clone of the original parsing + * expression. Beware this means that the original graph and the new graph will share + * sub-expressions that are not modified! + */ + public static GraphWalker copy = (pe, visitor) -> + { + Counter c = new Counter(); + ParsingExpression pec = pe.clone(); + Object[] slots = Arrays.stream(pe.children()).map(x -> new ChildSlot(pec, c.i++)).toArray(); + + return Array.>fromUnsafe(slots); + }; + + // --------------------------------------------------------------------------------------------- + + /** + * Walks the whole graph. Attempts to set the value of a slot result in an exception. + */ + public static GraphWalker readOnly = (pe, visitor) -> + { + Counter c = new Counter(); + Object[] slots = Arrays.stream(pe.children()).map(x -> new ChildSlot.ReadOnly(pe, c.i++)).toArray(); + + return Array.>fromUnsafe(slots); + }; + + // --------------------------------------------------------------------------------------------- + + /** + * Walks a graph through the children that are part of the FIRST set of the parent parsing + * expression. A parsing expression's FIRST set contains all descendant parsing expression that + * can be invoked at the same input position as the parent, because no input has been consumed + * yet. + */ + public static GraphWalker inPlaceFirsts(Grammar grammar) + { + return (pe, visitor) -> + { + Counter c = new Counter(); + Object[] slots = Arrays.stream(pe.firsts(grammar)).map(x -> new ChildSlot(pe, c.i++)).toArray(); + + return Array.>fromUnsafe(slots); + }; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/parsing/graph/nullability/AllNullable.java b/src/com/norswap/autumn/parsing/graph/nullability/AllNullable.java deleted file mode 100644 index 0931c18..0000000 --- a/src/com/norswap/autumn/parsing/graph/nullability/AllNullable.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.norswap.autumn.parsing.graph.nullability; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import java.util.Arrays; - -/** - * A nullable with a reduction strategy indicating that an expression is nullable if all its - * children are nullable. - */ -public final class AllNullable extends Nullability -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - public AllNullable(ParsingExpression pe, ParsingExpression[] toReduce) - { - super(pe, false, false, toReduce); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Nullability reduce(Nullability[] nullabilities) - { - boolean allYes = true; - - for (Nullability n : nullabilities) - { - if (n.resolved) - { - if (!n.nullable) - { - return no(pe); - } - } - else if (allYes) - { - allYes = false; - } - } - - if (allYes) - { - return yes(pe); - } - - return new AllNullable(pe, Arrays.stream(nullabilities) - .filter(n -> !n.resolved) - .map(n -> n.pe) - .toArray(ParsingExpression[]::new)); - } - - // ----------------------------------------------------------------------------------------- - - @Override - public Nullability update(Nullability n) - { - return n.no() - ? no(pe) - : null; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/nullability/AnyNullable.java b/src/com/norswap/autumn/parsing/graph/nullability/AnyNullable.java deleted file mode 100644 index a17b6c3..0000000 --- a/src/com/norswap/autumn/parsing/graph/nullability/AnyNullable.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.norswap.autumn.parsing.graph.nullability; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import java.util.Arrays; - -/** - * A nullable with a reduction strategy indicating that an expression is nullable of any of its - * children is nullable. - */ -public final class AnyNullable extends Nullability -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - public AnyNullable(ParsingExpression pe, ParsingExpression[] toReduce) - { - super(pe, false, false, toReduce); - } - - // ----------------------------------------------------------------------------------------- - - @Override - public Nullability reduce(Nullability[] nullabilities) - { - boolean allNo = true; - - for (Nullability n : nullabilities) - { - if (n.resolved) - { - if (n.nullable) - { - return yes(pe); - } - } - else if (allNo) - { - allNo = false; - } - } - - if (allNo) - { - return no(pe); - } - - return new AnyNullable(pe, Arrays.stream(nullabilities) - .filter(n -> !n.resolved) - .map(n -> n.pe) - .toArray(ParsingExpression[]::new)); - } - - // ----------------------------------------------------------------------------------------- - - @Override - public Nullability update(Nullability n) - { - return n.yes() - ? yes(pe) - : null; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/graph/nullability/SingleNullable.java b/src/com/norswap/autumn/parsing/graph/nullability/SingleNullable.java deleted file mode 100644 index 68af7d0..0000000 --- a/src/com/norswap/autumn/parsing/graph/nullability/SingleNullable.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.norswap.autumn.parsing.graph.nullability; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -/** - * A nullable with a reduction strategy indicating that an expression is nullable if its only - * child is nullable. - */ -public final class SingleNullable extends Nullability -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - SingleNullable(ParsingExpression pe, ParsingExpression op) - { - super(pe, false, false, new ParsingExpression[]{op}); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Nullability reduce(Nullability[] nullabilities) - { - Nullability n = nullabilities[0]; - - if (n.resolved) - { - return n.nullable - ? yes(pe) - : no(pe); - } - - return this; - } - - // --------------------------------------------------------------------------------------------- - - @Override - public Nullability update(Nullability n) - { - if (n.resolved) - { - return n.nullable - ? yes(pe) - : no(pe); - } - - return null; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/support/GrammarCompiler.java b/src/com/norswap/autumn/parsing/support/GrammarCompiler.java index 8cc4460..74431fe 100644 --- a/src/com/norswap/autumn/parsing/support/GrammarCompiler.java +++ b/src/com/norswap/autumn/parsing/support/GrammarCompiler.java @@ -1,19 +1,22 @@ package com.norswap.autumn.parsing.support; +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.ParseTree; -import com.norswap.autumn.parsing.expressions.DropPrecedence; +import com.norswap.autumn.parsing.Whitespace; +import com.norswap.autumn.parsing.expressions.ExpressionCluster.Group; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; import com.norswap.autumn.parsing.ParsingExpressionFactory; -import com.norswap.autumn.parsing.expressions.ExpressionCluster.Operand; import com.norswap.autumn.parsing.expressions.Reference; -import com.norswap.autumn.util.Array; -import com.norswap.autumn.util.Streams; +import com.norswap.util.Array; +import com.norswap.util.Counter; +import com.norswap.util.Streams; +import java.util.List; import java.util.function.Function; -import java.util.stream.Stream; import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; -import static com.norswap.autumn.util.StringEscape.unescape; +import static com.norswap.util.StringEscape.unescape; public final class GrammarCompiler { @@ -33,9 +36,18 @@ private interface Grouper extends Function exprs = new GrammarCompiler().run(tree); + + ParsingExpression whitespace = exprs.stream() + .filter(rule -> "Spacing".equals(rule.name())) + .findFirst().orElse(Whitespace.DEFAULT()); + + // TODO enable setting whitespace & root from grammar file + + return Autumn.grammarFromExpression( + exprs.get(0), exprs, whitespace, true, true); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -46,14 +58,14 @@ public static ParsingExpression[] compile(ParseTree tree) * * Note that the references inside these expressions are not resolved. */ - public ParsingExpression[] run(ParseTree tree) + public Array run(ParseTree tree) { - ParseTree rules = tree.group("rules"); + Array out = new Array<>( + Streams.from(tree.group("rules")) + .map(this::compileRule).toArray(ParsingExpression[]::new)); - return Stream.concat( - Streams.from(rules).map(this::compileRule), - Streams.from(namedClusterAlternates)) - .toArray(ParsingExpression[]::new); + out.addAll(namedClusterAlternates); + return out; } // --------------------------------------------------------------------------------------------- @@ -61,7 +73,10 @@ public ParsingExpression[] run(ParseTree tree) private ParsingExpression compileRule(ParseTree rule) { String ruleName = rule.value("ruleName"); - ParsingExpression topChoice = compileTopChoice(rule.group("alts")); + + ParsingExpression topChoice = rule.has("cluster") + ? compileCluster(rule.get("cluster")) + : compilePE(rule.get("expr").child()); if (rule.has("dumb")) { @@ -73,17 +88,9 @@ private ParsingExpression compileRule(ParseTree rule) topChoice = token(topChoice); } - return named$(ruleName, topChoice); - } - - - // --------------------------------------------------------------------------------------------- + topChoice = compileCapture(topChoice, rule.group("captureSuffixes")); - private ParsingExpression compileChoiceAlt(ParseTree alt) - { - return alt.name.equals("sequence") - ? compileSequence(alt) - : compileExpression(alt); + return named$(ruleName, topChoice); } // --------------------------------------------------------------------------------------------- @@ -105,261 +112,277 @@ private ParsingExpression compileOneOrGroup( // --------------------------------------------------------------------------------------------- - private ParsingExpression compileTopChoice(ParseTree alts) + private ParsingExpression compileCluster(ParseTree expression) { - return compileOneOrGroup( - t -> compileChoiceAlt(t.child(0)), - exprs -> choice(exprs), - alts); - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileChoice(ParseTree choice) - { - return compileOneOrGroup( - t -> compileChoiceAlt(t), - exprs -> choice(exprs), - choice); - } + final int UNSET = -1; - // --------------------------------------------------------------------------------------------- + Counter currentPrecedence = new Counter(0); + Array namedAlternates = new Array<>(); + Array groups = new Array<>(); + Array> alts = new Array<>(); - private ParsingExpression compileExpression(ParseTree expression) - { - final int UNSET = -1, MULTISET = -2, SET = 1; + for (ParseTree alt: expression.group("alts")) + { + ParsingExpression pe = compilePE(alt.get("expr").child()); - class $ { - int precedence = 0; - boolean leftRecur = false; - boolean leftAssoc = false; - } - $ last = new $(); + int precedence = UNSET; + int psets = 0; + boolean leftRecursive = false; + boolean leftAssociative = false; - Array namedAlternates = new Array<>(); - - ParsingExpression cluster = cluster(Streams.from(expression.group("alts")) - .map(alt -> + for (ParseTree annotation : alt.group("annotations")) { - ParsingExpression pe = compileSequence(alt.get("sequence")); - Operand operand = new Operand(); - int precedence = UNSET; + annotation = annotation.child(); - for (ParseTree annotation : alt.group("annotations")) + switch (annotation.accessor) { - annotation = annotation.child(0); - - switch (annotation.name) - { - case "precedence": - precedence = precedence == -1 - ? Integer.parseInt(annotation.value) - : MULTISET; - break; - - case "increment": - precedence = precedence == -1 - ? last.precedence + 1 - : MULTISET; - break; - - case "same": - precedence = precedence == -1 - ? last.precedence - : MULTISET; - break; - - case "left_assoc": - operand.leftRecursive = true; - operand.leftAssociative = true; - break; - - case "left_recur": - operand.leftRecursive = true; - break; - - case "name": - pe.setName(annotation.value); - namedAlternates.push(pe); - break; - } + case "precedence": + precedence = Integer.parseInt(annotation.value); + ++psets; + break; + + case "increment": + precedence = currentPrecedence.i + 1; + ++psets; + break; + + case "same": + precedence = currentPrecedence.i; + ++psets; + break; + + case "left_assoc": + leftRecursive = true; + leftAssociative = true; + break; + + case "left_recur": + leftRecursive = true; + break; + + case "name": + pe.setName(annotation.value); + namedAlternates.push(pe); + break; } + } - if (precedence == 0) - { - throw new RuntimeException( - "Precedence can't be 0. Don't use @0; or use @= in first position."); - } + if (psets > 1) + { + throw new RuntimeException( + "Expression specifies precedence more than once."); + } - if (precedence == UNSET) - { - throw new RuntimeException( - "Expression alternate does not specify precedence."); - } + if (precedence == 0) + { + throw new RuntimeException( + "Precedence can't be 0. Don't use @0; or use @= in first position."); + } - if (precedence == MULTISET) + if (precedence == UNSET) + { + throw new RuntimeException( + "Expression alternate does not specify precedence."); + } + + if (precedence < currentPrecedence.i) + { + throw new RuntimeException( + "Alternates must be grouped by precedence in expression cluster."); + } + else if (precedence == currentPrecedence.i) + { + if (leftRecursive) { throw new RuntimeException( - "Expression specifies precedence more than once."); + "Can't specify left-recursion or left-associativity on non-first " + + "alternate of a precedence group in an expression cluster."); } - operand.operand = pe; - operand.precedence = precedence; + alts.get(precedence).push(pe); + } + else + { + groups.put(precedence, group(precedence, leftRecursive, leftAssociative, (Group[]) null)); + alts.put(precedence, new Array<>(pe)); + ++currentPrecedence.i; + } + } - if (precedence != last.precedence) - { - last.leftAssoc = operand.leftAssociative; - last.leftRecur = operand.leftRecursive; - last.precedence = precedence; - } - else - { - if (operand.leftAssociative) - { - throw new RuntimeException( - "@left_assoc annotation not on the item with its precedence."); - } - - if (operand.leftRecursive) - { - throw new RuntimeException( - "@left_recur annotation not on the item with its precedence."); - } - - operand.leftAssociative = last.leftAssoc; - operand.leftRecursive = last.leftRecur; - } + namedAlternates.forEach(namedClusterAlternates::push); - return operand; + // Build the groups - }).toArray(Operand[]::new)); + Array groupsArray = new Array<>(); - for (int i = 0; i < namedAlternates.size(); ++i) + for (int i = 0; i < groups.size(); ++i) { - namedClusterAlternates.push(namedAlternates.get(i)); + Group group = groups.get(i); + + if (group == null) { + continue; + } + + group.operands = alts.get(i).toArray(ParsingExpression[]::new); + groupsArray.push(group); } - return cluster; + return cluster(groupsArray.toArray(Group[]::new)); } - // --------------------------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////////////////////// - private ParsingExpression compileSequence(ParseTree sequence) + private ParsingExpression compileRef(ParseTree tree) { - return compileOneOrGroup( - tree -> compilePrefixed(tree), - exprs -> sequence(exprs), - sequence); + Reference ref = reference(tree.value("name")); + + ParseTree allowed = tree.getOrNull("allowed"); + ParseTree forbidden = tree.getOrNull("forbidden"); + + if (allowed != null || forbidden != null) + { + return filter( + allowed == null + ? new ParsingExpression[0] + : Streams.from(allowed) + .map(pe -> reference(pe.value)) + .toArray(ParsingExpression[]::new), + + forbidden == null + ? new ParsingExpression[0] + : Streams.from(forbidden) + .map(pe -> reference(pe.value)) + .toArray(ParsingExpression[]::new), + + ref + ); + } + else { + return ref; + } } // --------------------------------------------------------------------------------------------- - private ParsingExpression compilePrefixed(ParseTree prefixed) + private ParsingExpression compileCapture(ParsingExpression child, List suffixes) { - switch (prefixed.name) + ParsingExpression out = child; + + for (ParseTree suffix: suffixes) { - case "and": - return lookahead(compileSuffixed(prefixed.child())); + suffix = suffix.child(); - case "not": - return not(compileSuffixed((prefixed.child()))); + switch (suffix.accessor) + { + case "capture": + out = capture(suffix.has("captureText"), out); + break; - default: - return compileSuffixed(prefixed); + case "accessor": + out = accessor$(suffix.value("name"), out); + break; + + case "group": + out = group$(suffix.value("name"), out); + break; + + case "tag": + out = tag$(suffix.value("name"), out); + break; + + default: + throw new RuntimeException("Unknown capture type: " + suffix.accessor); + } } + + return out; + } // --------------------------------------------------------------------------------------------- - private ParsingExpression compileSuffixed(ParseTree suffixed) + private ParsingExpression[] compileChildren(ParseTree tree) { - switch (suffixed.name) + return tree.children.stream() + .map(this::compilePE) + .toArray(ParsingExpression[]::new); + } + + // --------------------------------------------------------------------------------------------- + + private ParsingExpression compilePE(ParseTree tree) + { + switch (tree.accessor) { + case "choice": + return choice(compileChildren(tree)); + + case "sequence": + return sequence(compileChildren(tree)); + + case "and": + return lookahead(compilePE(tree.child())); + + case "not": + return not(compilePE(tree.child())); + case "until": return until( - compilePrimary(suffixed.child(0)), - compilePrimary(suffixed.child(1))); + compilePE(tree.child(0)), + compilePE(tree.child(1))); case "aloUntil": return aloUntil( - compilePrimary(suffixed.child(0)), - compilePrimary(suffixed.child(1))); + compilePE(tree.child(0)), + compilePE(tree.child(1))); + + case "separated": + return separated( + compilePE(tree.child(0)), + compilePE(tree.child(1))); + + case "aloSeparated": + return aloSeparated( + compilePE(tree.child(0)), + compilePE(tree.child(1))); case "optional": - return optional(compilePrimary(suffixed.child())); + return optional(compilePE(tree.child())); case "zeroMore": - return zeroMore(compilePrimary(suffixed.child())); + return zeroMore(compilePE(tree.child())); case "oneMore": - return oneMore(compilePrimary(suffixed.child())); - - default: - return compilePrimary(suffixed); - } - } + return oneMore(compilePE(tree.child())); - // --------------------------------------------------------------------------------------------- + case "capture": + return compileCapture(compilePE(tree.child(0)), tree.group("captureSuffixes")); - private ParsingExpression compilePrimary(ParseTree primary) - { - switch (primary.name) - { - case "choice": - return compileChoice(primary); + case "drop": + return exprDropPrecedence(compilePE(tree.child())); case "ref": - Reference ref = reference(primary.value("name")); - - ParseTree allowed = primary.getOrNull("allowed"); - ParseTree forbidden = primary.getOrNull("forbidden"); - - if (allowed != null || forbidden != null) - { - return filter( - allowed == null - ? new ParsingExpression[0] - : Streams.from(allowed) - .map(pe -> reference(pe.value)) - .toArray(ParsingExpression[]::new), - - forbidden == null - ? new ParsingExpression[0] - : Streams.from(forbidden) - .map(pe -> reference(pe.value)) - .toArray(ParsingExpression[]::new), - - ref - ); - } - else { - return ref; - } + return compileRef(tree); case "any": return any(); case "charRange": return charRange( - unescape(primary.value("first")).charAt(0), - unescape(primary.value("last")).charAt(0)); + unescape(tree.value("first")).charAt(0), + unescape(tree.value("last")).charAt(0)); case "charSet": - return charSet(unescape(primary.value("charSet"))); + return charSet(unescape(tree.value("charSet"))); case "notCharSet": - return notCharSet(unescape(primary.value("notCharSet"))); + return notCharSet(unescape(tree.value("notCharSet"))); case "stringLit": - return literal(unescape(primary.value("literal"))); - - case "drop": - DropPrecedence out = new DropPrecedence(); - out.operand = compilePrimary(primary.child(0)); - return out; + return literal(unescape(tree.value("literal"))); default: - throw new RuntimeException("Primary expression with no name."); + throw new RuntimeException("Parsing expression with unknown name: " + tree.accessor); } } diff --git a/src/com/norswap/autumn/parsing/support/GrammarDriver.java b/src/com/norswap/autumn/parsing/support/GrammarDriver.java deleted file mode 100644 index 87bed66..0000000 --- a/src/com/norswap/autumn/parsing/support/GrammarDriver.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.norswap.autumn.parsing.support; - -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.ParserConfiguration; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.graph.ReferenceResolver; -import com.norswap.autumn.parsing.Source; -import com.norswap.autumn.util.Array; - -import java.io.IOException; - -public final class GrammarDriver -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - private final static ParserConfiguration config = new ParserConfiguration(); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Parse the grammar file whose path is supplied and return an array of parsing expressions - * corresponding to the grammar rules defined in the grammar. The resolvable references in these - * rules have been resolved. - * - * It is conventional to have the root of the grammar be the first expression. - */ - public static ParsingExpression[] compile(String grammarFile) throws IOException - { - Source source = Source.fromFile(grammarFile); - Parser parser = new Parser(source, config); - parser.parse(GrammarGrammar.grammar); - - if (!parser.succeeded()) - { - parser.report(); - throw new RuntimeException("Failed to parse the grammar file."); - } - else - { - return ReferenceResolver.resolve(GrammarCompiler.compile(parser.tree())); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/parsing/support/GrammarGrammar.java b/src/com/norswap/autumn/parsing/support/GrammarGrammar.java index f09ed8a..261b41f 100644 --- a/src/com/norswap/autumn/parsing/support/GrammarGrammar.java +++ b/src/com/norswap/autumn/parsing/support/GrammarGrammar.java @@ -1,5 +1,7 @@ package com.norswap.autumn.parsing.support; +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; @@ -8,64 +10,7 @@ public final class GrammarGrammar { //////////////////////////////////////////////////////////////////////////////////////////////// - /* - The original Mouse grammar this is based on. - - Grammar = Space (Rule/Skip)*+ EOF ; - Rule = Name EQUAL RuleRhs DiagName? SEMI ; - Skip = SEMI / _++ (SEMI/EOF) ; - RuleRhs = Sequence Actions (SLASH Sequence Actions)* ; - Choice = Sequence (SLASH Sequence)* ; - Sequence = Prefixed+ ; - Prefixed = PREFIX? Suffixed ; - Suffixed = Primary (UNTIL Primary / SUFFIX)? ; - Primary = Name - / LPAREN Choice RPAREN - / ANY - / StringLit - / Range - / CharClass ; - Actions = OnSucc OnFail ; - OnSucc = (LWING AND? Name? RWING)? ; - OnFail = (TILDA LWING Name? RWING)? ; - Name = Letter (Letter / Digit)* Space ; - DiagName = "<" Char++ ">" Space ; - StringLit = ["] Char++ ["] Space ; - CharClass = ("[" / "^[") Char++ "]" Space ; - Range = "[" Char "-" Char "]" Space ; - Char = Escape / ^[\r\n\\] ; - Escape = "\\u" HexDigit HexDigit HexDigit HexDigit - / "\\t" - / "\\n" - / "\\r" - / !"\\u""\\"_ ; - Letter = [a-z] / [A-Z] ; - Digit = [0-9] ; - HexDigit = [0-9] / [a-f] / [A-F] ; - PREFIX = [&!] Space ; - SUFFIX = [?*+] Space ; - UNTIL = ("*+" / "++") Space ; - EQUAL = "=" Space ; - SEMI = ";" Space ; - SLASH = "/" Space ; - AND = "&" Space ; - LPAREN = "(" Space ; - RPAREN = ")" Space ; - LWING = "{" Space ; - RWING = "}" Space ; - TILDA = "~" Space ; - ANY = "_" Space ; - Space = ([ \r\n\t] / Comment)* ; - Comment = "//" _*+ EOL ; - EOL = [\r]? [\n] / !_ ; - EOF = !_ ; - */ - - //////////////////////////////////////////////////////////////////////////////////////////////// - - // TODO(norswap): - // This should eventually use expression clusters, the grammar just precedes - // that, and I haven't gotten around changing it. + private static int i = 0; public static ParsingExpression @@ -74,22 +19,25 @@ public final class GrammarGrammar equal = token(literal("=")), plus = token(literal("+")), qMark = token(literal("?")), + colon = token(literal(":")), semi = token(literal(";")), slash = token(literal("/")), star = token(literal("*")), - tilda = token(literal("_")), + tilda = token(literal("~")), lBrace = token(literal("{")), rBrace = token(literal("}")), lParen = token(literal("(")), rParen = token(literal(")")), underscore = token(literal("_")), - until = token(literal("*+")), - aloUntil = token(literal("++")), - colEqual = token(literal(":=")), + starPlus = token(literal("*+")), + plusPlus = token(literal("++")), arrow = token(literal("->")), lAnBra = token(literal("<")), rAnBra = token(literal(">")), comma = token(literal(",")), + commaPlus = token(literal(",+")), + minus = token(literal("-")), + hash = token(literal("#")), digit = charRange('0', '9'), hexDigit = choice(digit, charRange('a', 'f'), charRange('A', 'F')), @@ -103,6 +51,8 @@ public final class GrammarGrammar left_assoc = token(literal("left_assoc"), not(nameChar)), left_recur = token(literal("left_recur"), not(nameChar)), + reserved = choice(exprLit, dropLit, left_assoc, left_recur), + escape = named$("escape", choice( sequence(literal("\\u"), hexDigit, hexDigit, hexDigit, hexDigit), sequence(literal("\\"), charSet("tn")), @@ -132,42 +82,71 @@ public final class GrammarGrammar captureText("literal", zeroMore(not(literal("\"")), character)), literal("\""))), - diagName = named$("diagName", token(literal("<"), until(character, literal(">")))), - name = named$("name", token(choice( - sequence(letter, zeroMore(nameChar)), - sequence(literal("'"), aloUntil(any(), literal("'")))))), - - primary = recursive$("primary", choice( - sequence(lParen, reference("choice"), rParen), - capture("drop", sequence(dropLit, reference("primary"))), - sequence(capture("ref", sequence( - captureText("name", name), - optional(token(literal("allow")), - lBrace, aloSeparated(captureTextGrouped("allowed", name), comma), rBrace), - optional(token(literal("forbid")), - lBrace, aloSeparated(captureTextGrouped("forbidden", name), comma), rBrace)))), - capture("any", underscore), - capture("charRange", range), - captureText("stringLit", stringLit), - captureText("charSet", charSet), - captureText("notCharSet", notCharSet))), - - suffixed = named$("suffixed", choice( - capture("until", sequence(primary, until, primary)), - capture("aloUntil", sequence(primary, aloUntil, primary)), - capture("optional", sequence(primary, qMark)), - capture("zeroMore", sequence(primary, star)), - capture("oneMore", sequence(primary, plus)), - primary)), - - prefixed = named$("prefixed", choice( - capture("and", sequence(and, suffixed)), - capture("not", sequence(bang, suffixed)), - suffixed)), - - sequence = named$("sequence", capture("sequence", oneMore(prefixed))), - - exprAnnotation = sequence(literal("@"), + name = named$("name", token(choice( + sequence(not(reserved), letter, zeroMore(nameChar)), + sequence(literal("'"), aloUntil(any(), literal("'")))))), + + nameOrDollar = choice(captureText("name", name), capture("dollar", literal("$"))), + + reference = sequence( + captureText("name", name), + optional(token(literal("allow")), + lBrace, aloSeparated(captureTextGrouped("allowed", name), comma), rBrace), + optional(token(literal("forbid")), + lBrace, aloSeparated(captureTextGrouped("forbidden", name), comma), rBrace)), + + captureSuffix = group$("captureSuffixes", capture(choice( + capture("capture", + sequence(token(literal(":"), optional(capture("captureText", literal("+")))))), + capture("accessor", + sequence(minus, nameOrDollar)), + capture("group", + sequence(hash, nameOrDollar)), + capture("tag", + sequence(tilda, nameOrDollar))))), + + expr = reference("expr"), + + parsingExpression = recursive$("expr", cluster( + + // NOTE(norswap) + // Using left associativity for choice and sequence ensures that sub-expressions + // have higher precedence. So we don't get pesky choice of choices or sequence of sequences. + + groupLeftAssoc(++i, + named$("choice", capture("choice", aloSeparated(expr, slash)))), + + groupLeftAssoc(++i, + capture("sequence", sequence(expr, oneMore(expr)))), + + group(++i, + capture("and", sequence(and, expr)), + capture("not", sequence(bang, expr))), + + group(++i, + capture("until", sequence(expr, starPlus, expr)), + capture("aloUntil", sequence(expr, plusPlus, expr)), + capture("separated", sequence(expr, comma, expr)), + capture("aloSeparated", sequence(expr, commaPlus, expr)), + capture("optional", sequence(expr, qMark)), + capture("zeroMore", sequence(expr, star)), + capture("oneMore", sequence(expr, plus))), + + groupLeftRec(++i, + capture("capture", sequence(expr, oneMore(captureSuffix)))), + + group(++i, + sequence(lParen, exprDropPrecedence(expr), rParen), + capture("drop", sequence(dropLit, expr)), + capture("ref", reference), + capture("any", underscore), + capture("charRange", range), + captureText("stringLit", stringLit), + captureText("charSet", charSet), + captureText("notCharSet", notCharSet)))), + + exprAnnotation = sequence( + literal("@"), choice( captureText("precedence", num), capture("increment", plus), @@ -176,26 +155,27 @@ lBrace, aloSeparated(captureTextGrouped("forbidden", name), comma), rBrace)))), capture("left_recur", left_recur), captureText("name", name))), - expr = named$("expr", capture("expr", sequence( + exprCluster = named$("cluster", capture("cluster", sequence( exprLit, oneMore(captureGrouped("alts", sequence( - arrow, sequence, + arrow, + capture("expr", filter(null, $(reference("choice")), parsingExpression)), oneMore(captureGrouped("annotations", exprAnnotation)))))))), - choice = recursive$("choice", capture("choice", aloSeparated( - choice(expr, sequence), - slash))), - - ruleRhs = named$("ruleRhs", aloSeparated( - captureGrouped("alts", choice(expr, sequence)), - slash)), - rule = named$("rule", sequence( captureText("ruleName", name), + zeroMore(captureSuffix), optional(capture("dumb", literal("!"))), - choice(equal, capture("token", colEqual)), - ruleRhs, - optional(diagName), semi)), + optional(capture("token", literal("%"))), + equal, + choice(exprCluster, capture("expr", parsingExpression)), + semi)), - grammar = named$("grammar", oneMore(captureGrouped("rules", rule))); + root = named$("grammar", oneMore(captureGrouped("rules", rule))); + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static final Grammar grammar = Autumn.grammarFromExpression(root); + + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/test/Ensure.java b/src/com/norswap/autumn/test/Ensure.java index 2741146..248ffba 100644 --- a/src/com/norswap/autumn/test/Ensure.java +++ b/src/com/norswap/autumn/test/Ensure.java @@ -1,9 +1,5 @@ package com.norswap.autumn.test; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.Source; - /** * A bunch of static assertion method to express expectations on test outcomes. * @@ -11,6 +7,8 @@ */ public final class Ensure { + //////////////////////////////////////////////////////////////////////////////////////////////// + public static void ensure(boolean test) { if (!test) @@ -19,6 +17,8 @@ public static void ensure(boolean test) } } + // --------------------------------------------------------------------------------------------- + public static void equals(T x, T y) { if (!x.equals(y)) @@ -27,6 +27,8 @@ public static void equals(T x, T y) } } + // --------------------------------------------------------------------------------------------- + public static void different(T x, T y) { if (x.equals(y)) @@ -35,6 +37,8 @@ public static void different(T x, T y) } } + // --------------------------------------------------------------------------------------------- + public static > void greaterThan(T x, T y) { if (x.compareTo(y) <= 0) @@ -43,6 +47,8 @@ public static > void greaterThan(T x, T y) } } + // --------------------------------------------------------------------------------------------- + public static > void lessThan(T x, T y) { if (x.compareTo(y) >= 0) @@ -51,56 +57,5 @@ public static > void lessThan(T x, T y) } } - public static void match(Source src, ParsingExpression pe) - { - Parser parser = TestConfiguration.parser(src); - parser.parse(pe); - equals(parser.endPosition(), src.length()); - } - - public static void match(String src, ParsingExpression pe) - { - match(Source.fromString(src), pe); - } - - public static void succeeds(Source src, ParsingExpression pe) - { - Parser parser = TestConfiguration.parser(src); - parser.parse(pe); - ensure(parser.succeeded()); - } - - public static void succeeds(String src, ParsingExpression pe) - { - succeeds(Source.fromString(src), pe); - } - - public static void noFail(Source src, ParsingExpression pe) - { - Parser parser = TestConfiguration.parser(src); - parser.parse(pe); - ensure(parser.endPosition() != -1); - } - - public static void noFail(String src, ParsingExpression pe) - { - noFail(Source.fromString(src), pe); - } - - public static void fails(Source src, ParsingExpression pe) - { - Parser parser = TestConfiguration.parser(src); - parser.parse(pe); - int pos = parser.endPosition(); - - if (pos != -1) - { - throw new TestFailed("expecting failure, succeeded with pos: " + pos); - } - } - - public static void fails(String src, ParsingExpression pe) - { - fails(Source.fromString(src), pe); - } + //////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/src/com/norswap/autumn/test/Scratchpad.java b/src/com/norswap/autumn/test/Scratchpad.java index 7be573e..c584319 100644 --- a/src/com/norswap/autumn/test/Scratchpad.java +++ b/src/com/norswap/autumn/test/Scratchpad.java @@ -1,11 +1,14 @@ package com.norswap.autumn.test; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; + /** * A space to try stuff. */ public final class Scratchpad { - public static void _main(String[] args) - { - } -} + @Target({ANNOTATION_TYPE , CONSTRUCTOR , FIELD , LOCAL_VARIABLE , METHOD , PACKAGE , PARAMETER , TYPE , TYPE_PARAMETER, TYPE_USE}) + @interface A {} +} \ No newline at end of file diff --git a/src/com/norswap/autumn/test/TestConfiguration.java b/src/com/norswap/autumn/test/TestConfiguration.java deleted file mode 100644 index 9b3d790..0000000 --- a/src/com/norswap/autumn/test/TestConfiguration.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.norswap.autumn.test; - -import com.norswap.autumn.parsing.Source; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.ParserConfiguration; - -public final class TestConfiguration -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static ParserConfiguration parserConfig = new ParserConfiguration(); - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static Parser parser(String src) - { - return new Parser(Source.fromString(src), parserConfig); - } - - public static Parser parser(Source src) - { - return new Parser(src, parserConfig); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/test/benchmark/AntlrBenchmark.java b/src/com/norswap/autumn/test/benchmark/AntlrBench.java similarity index 78% rename from src/com/norswap/autumn/test/benchmark/AntlrBenchmark.java rename to src/com/norswap/autumn/test/benchmark/AntlrBench.java index 63046b9..5fb4d07 100644 --- a/src/com/norswap/autumn/test/benchmark/AntlrBenchmark.java +++ b/src/com/norswap/autumn/test/benchmark/AntlrBench.java @@ -4,7 +4,8 @@ import com.norswap.autumn.test.antlr.Java7Parser; import com.norswap.autumn.test.antlr.Java8Lexer; import com.norswap.autumn.test.antlr.Java8Parser; -import com.norswap.autumn.util.Glob; +import com.norswap.util.Array; +import com.norswap.util.Glob; import org.antlr.v4.runtime.ANTLRFileStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; @@ -16,20 +17,30 @@ import java.time.Duration; import java.time.Instant; -public final class AntlrBenchmark +public final class AntlrBench { //////////////////////////////////////////////////////////////////////////////////////////////// public static void main(String[] args) throws IOException { + Array durations = new Array<>(); Instant start = Instant.now(); - int iters = 1; + Instant mid = start; + int iters = 20; + for (int i = 0; i < iters; ++i) { - parseDirectory("../guava"); + parseDirectory( + //"../guava"); + "/Users/nilaurent/Documents/spring-framework"); + + Instant tmp = Instant.now(); + durations.add(Duration.between(mid, tmp)); + mid = tmp; } Instant end = Instant.now(); - System.out.println("Guava parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println("Code parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println(durations); } // --------------------------------------------------------------------------------------------- diff --git a/src/com/norswap/autumn/test/benchmark/AutumnBench.java b/src/com/norswap/autumn/test/benchmark/AutumnBench.java index 1c1d17a..b827835 100644 --- a/src/com/norswap/autumn/test/benchmark/AutumnBench.java +++ b/src/com/norswap/autumn/test/benchmark/AutumnBench.java @@ -1,23 +1,18 @@ package com.norswap.autumn.test.benchmark; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.ParserConfiguration; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.Source; -import com.norswap.autumn.parsing.graph.FirstCalculator; -import com.norswap.autumn.parsing.graph.LeftRecursionBreaker; -import com.norswap.autumn.parsing.graph.nullability.NullabilityCalculator; -import com.norswap.autumn.parsing.support.GrammarDriver; -import com.norswap.autumn.util.Glob; +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.ParseResult; +import com.norswap.util.Array; +import com.norswap.util.Glob; -import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Duration; import java.time.Instant; -import java.util.Arrays; -public class AutumnBench +public final class AutumnBench { //////////////////////////////////////////////////////////////////////////////////////////////// @@ -27,103 +22,45 @@ public class AutumnBench public static void main(String[] args) throws IOException { - //System.in.read(); + Instant startParse = Instant.now(); + Grammar grammar = Autumn.grammarFromFile(grammarFile); - Instant start = Instant.now(); - - ParsingExpression[] rules = GrammarDriver.compile(grammarFile); - - Instant end = Instant.now(); - System.out.println("Grammar compiled in: " + Duration.between(start, end)); - - ParsingExpression whitespace = Arrays.stream(rules) - .filter(rule -> "Spacing".equals(rule.name())) - .findFirst().get(); - - NullabilityCalculator nullCalc = new NullabilityCalculator(); - nullCalc.run(rules); - - // Test NullabilityCalculator - //nullCalc.nullables().forEach(x -> System.err.println(x)); - - FirstCalculator.nullCalc = nullCalc; - /* - FirstCalculator firstCalc = new FirstCalculator(); - firstCalc.run(rules); - */ - - // Test FirstCalculator - //firstCalc.first.entrySet().stream().forEach(e -> System.err.println(e)); + // inspect grammar + //new Printer(System.err::print).visit(grammar.root()); - LeftRecursionBreaker leftBreaker = new LeftRecursionBreaker(); - rules = leftBreaker.run(rules); + Instant endParse = Instant.now(); + System.out.println("Grammar compiled in: " + Duration.between(startParse, endParse)); - /* - // Left Recursion Breaker Test - { - Source source = Source.fromString("xxxxx"); - Parser parser = new Parser(source, new ParserConfiguration()); - parser.parse(rules[rules.length - 1]); - System.err.println("breaker test: " + parser.succeeded()); - } - - //*/ - - ParsingExpression root = rules[0]; - - start = Instant.now(); + Array durations = new Array<>(); + Instant start = Instant.now(); + Instant mid = start; int iters = 1; - for (int i = 0; i < iters; ++i) - { - parseDirectory("../guava", root, whitespace); - } - end = Instant.now(); - System.out.println("Guava parsed in: " + Duration.between(start, end).dividedBy(iters)); - } - - // --------------------------------------------------------------------------------------------- - private static void parseDirectory( - String directory, ParsingExpression root, ParsingExpression whitespace) - throws IOException - { - for (Path path: Glob.glob("**/*.java", new File(directory).toPath())) + for (int i = 0; i < iters; ++i) { - ParserConfiguration config = new ParserConfiguration(); - config.whitespace = () -> whitespace; + for (Path path: Glob.glob("**/*.java", Paths.get( + //"/Users/nilaurent/Documents/spring-framework"))) + "../guava"))) + { + ParseResult result = Autumn.parseFile(grammar, path.toString()); - parseFile(path.toString(), root, config); - } - } + if (!result.matched) + { + System.err.println(path); + System.err.println(result.error.message()); - // --------------------------------------------------------------------------------------------- + return; + } - private static void parseFile( - String file, ParsingExpression root, ParserConfiguration config) - { - try - { - Source source = Source.fromFile(file); - Parser parser = new Parser(source, config); - parser.parse(root); - - if (parser.succeeded()) - { - //System.err.println(file); - //System.out.println(parser.tree()); - } - else - { - System.err.println(file); - parser.report(); - System.err.println(); - System.exit(-1); } + + Instant tmp = Instant.now(); + durations.add(Duration.between(mid, tmp)); + mid = tmp; } - catch (IOException e) - { - System.out.println("Could not read file: " + file); - } + Instant end = Instant.now(); + System.out.println("Code parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println(durations); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/test/benchmark/MouseBench.java b/src/com/norswap/autumn/test/benchmark/MouseBench.java index 40f01a8..bddf346 100644 --- a/src/com/norswap/autumn/test/benchmark/MouseBench.java +++ b/src/com/norswap/autumn/test/benchmark/MouseBench.java @@ -1,7 +1,8 @@ package com.norswap.autumn.test.benchmark; import com.norswap.autumn.test.mouse.MouseJava8Parser; -import com.norswap.autumn.util.Glob; +import com.norswap.util.Array; +import com.norswap.util.Glob; import mouse.runtime.Source; import mouse.runtime.SourceFile; @@ -19,14 +20,25 @@ public static void main(String[] args) throws IOException { MouseJava8Parser parser = new MouseJava8Parser(); + Array durations = new Array<>(); Instant start = Instant.now(); + Instant mid = start; int iters = 1; + for (int i = 0; i < iters; ++i) { - parseDirectory("../guava", parser); + parseDirectory( + //"../guava", parser); + "/Users/nilaurent/Documents/spring-framework", parser); + + Instant tmp = Instant.now(); + durations.add(Duration.between(mid, tmp)); + mid = tmp; } + Instant end = Instant.now(); - System.out.println("Guava parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println("Code parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println(durations); } // --------------------------------------------------------------------------------------------- @@ -46,13 +58,20 @@ private static void parseFile(String file, MouseJava8Parser parser) { Source source = new SourceFile(file); - if (parser.parse(source)) - { + try { + if (parser.parse(source)) + { + } + else + { + System.err.println(file); + } } - else + catch (Exception e) { System.err.println(file); } + } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/test/benchmark/ParboiledBench.java b/src/com/norswap/autumn/test/benchmark/ParboiledBench.java index c58967f..980f7c2 100644 --- a/src/com/norswap/autumn/test/benchmark/ParboiledBench.java +++ b/src/com/norswap/autumn/test/benchmark/ParboiledBench.java @@ -1,7 +1,8 @@ package com.norswap.autumn.test.benchmark; import com.norswap.autumn.test.parboiled.ParboiledJava6Parser; -import com.norswap.autumn.util.Glob; +import com.norswap.util.Array; +import com.norswap.util.Glob; import org.parboiled.Parboiled; import org.parboiled.Rule; import org.parboiled.parserunners.ReportingParseRunner; @@ -24,16 +25,28 @@ public class ParboiledBench public static void main(String[] args) throws IOException { ParboiledJava6Parser parser = Parboiled.createParser(ParboiledJava6Parser.class); - Rule root = parser.CompilationUnit().suppressNode(); // don't build parse tree + Rule root = parser.CompilationUnit(); + // Rule root = parser.CompilationUnit().suppressNode(); // don't build parse tree + Array durations = new Array<>(); Instant start = Instant.now(); - int iters = 1; + Instant mid = start; + int iters = 20; + for (int i = 0; i < iters; ++i) { - parseDirectory("../guava", root); + parseDirectory( + //"../guava", root); + "/Users/nilaurent/Documents/spring-framework", root); + + Instant tmp = Instant.now(); + durations.add(Duration.between(mid, tmp)); + mid = tmp; } + Instant end = Instant.now(); - System.out.println("Guava parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println("Code parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println(durations); } // --------------------------------------------------------------------------------------------- diff --git a/src/com/norswap/autumn/test/benchmark/README.md b/src/com/norswap/autumn/test/benchmark/README.md index 4f85d32..6999672 100644 --- a/src/com/norswap/autumn/test/benchmark/README.md +++ b/src/com/norswap/autumn/test/benchmark/README.md @@ -34,6 +34,9 @@ Assuming the jar file and the grammar are in the working directory. Grammar file: http://www.romanredz.se/papers/Java.1.8.peg +Note that a newer (1.7) version of Mouse was released shortly after the paper was accepted. +I did test it, and it performs worse than the 1.6.1 version. + ## Parboiled By extracting the Java 6 parser example from the parboiled repo: diff --git a/src/com/norswap/autumn/test/benchmark/RatsBench.java b/src/com/norswap/autumn/test/benchmark/RatsBench.java index 5c7f8ee..9b40777 100644 --- a/src/com/norswap/autumn/test/benchmark/RatsBench.java +++ b/src/com/norswap/autumn/test/benchmark/RatsBench.java @@ -1,7 +1,8 @@ package com.norswap.autumn.test.benchmark; import com.norswap.autumn.test.rats.RatsJava7Parser; -import com.norswap.autumn.util.Glob; +import com.norswap.util.Array; +import com.norswap.util.Glob; import xtc.parser.ParseError; import xtc.parser.Result; import xtc.parser.SemanticValue; @@ -25,14 +26,25 @@ public class RatsBench public static void main(String[] args) throws IOException { + Array durations = new Array<>(); Instant start = Instant.now(); - int iters = 1; + Instant mid = start; + int iters = 20; + for (int i = 0; i < iters; ++i) { - parseDirectory("../guava"); + parseDirectory( + //"../guava"); + "/Users/nilaurent/Documents/spring-framework"); + + Instant tmp = Instant.now(); + durations.add(Duration.between(mid, tmp)); + mid = tmp; } + Instant end = Instant.now(); - System.out.println("Guava parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println("Code parsed in: " + Duration.between(start, end).dividedBy(iters)); + System.out.println(durations); } // --------------------------------------------------------------------------------------------- @@ -71,7 +83,9 @@ private static void parseFile(String file) { System.out.println(v.value.toString()); } - */ + + return; + //*/ } else { diff --git a/src/com/norswap/autumn/test/grammars/Java8.autumn b/src/com/norswap/autumn/test/grammars/Java8.autumn index 92f5cea..1f91145 100644 --- a/src/com/norswap/autumn/test/grammars/Java8.autumn +++ b/src/com/norswap/autumn/test/grammars/Java8.autumn @@ -1,14 +1,11 @@ -// - Originally from Mouse's Java 7 grammar. -// - Escaped stray backslashes in a few locations ([+\-]); as well as unescaped -// quotes (in char classes in StringLiteral and Escape). -// - Marked a bunch of places as tokens (:=) and removed leading spacing. +// Originally from the Mouse parser //========================================================================= -// Compilation +// Root //========================================================================= -Compilation - = CompilationUnit SUB? EOT; +Root = CompilationUnit "\u001a"? !_; +// the escape is "Ctrl + Z" (JLS 3.5) //========================================================================= // JLS 3 Lexical Structure @@ -25,28 +22,23 @@ Compilation // literals does not apply here. //------------------------------------------------------------------------- -//------------------------------------------------------------------------- -// JLS 3.5 Input Elements and Tokens -//------------------------------------------------------------------------- - -SUB = "\u001a" ; // Ctrl + Z -EOT = !_ ; - //------------------------------------------------------------------------- // JLS 3.6-7 Spacing //------------------------------------------------------------------------- Spacing - = ( [ \t\r\n\f]+ // WhiteSpace - / "/*" _*+ "*/" // TraditionalComment - / "//" _*+ [\r\n] // EndOfLineComment + = ( [ \t\r\n\f]+ // WhiteSpace + / "/*" _ *+ "*/" // TraditionalComment + / "//" _ *+ [\r\n] // EndOfLineComment )* ; //------------------------------------------------------------------------- // JLS 3.8 Identifiers //------------------------------------------------------------------------- -Identifier !:= !Keyword Letter LetterOrDigit* ; +Identifier !%= !Keyword Letter LetterOrDigit* ; + +QualIdent = Identifier ,+ '.'; Letter = [a-z] / [A-Z] / [_$] ; @@ -122,87 +114,92 @@ Keyword ) !LetterOrDigit ; -ABSTRACT !:= "abstract" !LetterOrDigit ; -ASSERT !:= "assert" !LetterOrDigit ; -BOOLEAN !:= "boolean" !LetterOrDigit ; -BREAK !:= "break" !LetterOrDigit ; -BYTE !:= "byte" !LetterOrDigit ; -CASE !:= "case" !LetterOrDigit ; -CATCH !:= "catch" !LetterOrDigit ; -CHAR !:= "char" !LetterOrDigit ; -CLASS !:= "class" !LetterOrDigit ; -CONTINUE !:= "continue" !LetterOrDigit ; -DEFAULT !:= "default" !LetterOrDigit ; -DOUBLE !:= "double" !LetterOrDigit ; -DO !:= "do" !LetterOrDigit ; -ELSE !:= "else" !LetterOrDigit ; -ENUM !:= "enum" !LetterOrDigit ; -EXTENDS !:= "extends" !LetterOrDigit ; -FALSE !:= "false" !LetterOrDigit ; -FINALLY !:= "finally" !LetterOrDigit ; -FINAL !:= "final" !LetterOrDigit ; -FLOAT !:= "float" !LetterOrDigit ; -FOR !:= "for" !LetterOrDigit ; -IF !:= "if" !LetterOrDigit ; -IMPLEMENTS !:= "implements" !LetterOrDigit ; -IMPORT !:= "import" !LetterOrDigit ; -INTERFACE !:= "interface" !LetterOrDigit ; -INT !:= "int" !LetterOrDigit ; -INSTANCEOF !:= "instanceof" !LetterOrDigit ; -LONG !:= "long" !LetterOrDigit ; -NATIVE !:= "native" !LetterOrDigit ; -NEW !:= "new" !LetterOrDigit ; -NULL !:= "null" !LetterOrDigit ; -PACKAGE !:= "package" !LetterOrDigit ; -PRIVATE !:= "private" !LetterOrDigit ; -PROTECTED !:= "protected" !LetterOrDigit ; -PUBLIC !:= "public" !LetterOrDigit ; -RETURN !:= "return" !LetterOrDigit ; -SHORT !:= "short" !LetterOrDigit ; -STATIC !:= "static" !LetterOrDigit ; -STRICTFP !:= "strictfp" !LetterOrDigit ; -SUPER !:= "super" !LetterOrDigit ; -SWITCH !:= "switch" !LetterOrDigit ; -SYNCHRONIZED !:= "synchronized" !LetterOrDigit ; -THIS !:= "this" !LetterOrDigit ; -THROWS !:= "throws" !LetterOrDigit ; -THROW !:= "throw" !LetterOrDigit ; -TRANSIENT !:= "transient" !LetterOrDigit ; -TRUE !:= "true" !LetterOrDigit ; -TRY !:= "try" !LetterOrDigit ; -VOID !:= "void" !LetterOrDigit ; -VOLATILE !:= "volatile" !LetterOrDigit ; -WHILE !:= "while" !LetterOrDigit ; +ABSTRACT !%= "abstract" !LetterOrDigit ; +ASSERT !%= "assert" !LetterOrDigit ; +BOOLEAN !%= "boolean" !LetterOrDigit ; +BREAK !%= "break" !LetterOrDigit ; +BYTE !%= "byte" !LetterOrDigit ; +CASE !%= "case" !LetterOrDigit ; +CATCH !%= "catch" !LetterOrDigit ; +CHAR !%= "char" !LetterOrDigit ; +CLASS !%= "class" !LetterOrDigit ; +CONTINUE !%= "continue" !LetterOrDigit ; +DEFAULT !%= "default" !LetterOrDigit ; +DOUBLE !%= "double" !LetterOrDigit ; +DO !%= "do" !LetterOrDigit ; +ELSE !%= "else" !LetterOrDigit ; +ENUM !%= "enum" !LetterOrDigit ; +EXTENDS !%= "extends" !LetterOrDigit ; +FALSE !%= "false" !LetterOrDigit ; +FINALLY !%= "finally" !LetterOrDigit ; +FINAL !%= "final" !LetterOrDigit ; +FLOAT !%= "float" !LetterOrDigit ; +FOR !%= "for" !LetterOrDigit ; +IF !%= "if" !LetterOrDigit ; +IMPLEMENTS !%= "implements" !LetterOrDigit ; +IMPORT !%= "import" !LetterOrDigit ; +INTERFACE !%= "interface" !LetterOrDigit ; +INT !%= "int" !LetterOrDigit ; +INSTANCEOF !%= "instanceof" !LetterOrDigit ; +LONG !%= "long" !LetterOrDigit ; +NATIVE !%= "native" !LetterOrDigit ; +NEW !%= "new" !LetterOrDigit ; +NULL !%= "null" !LetterOrDigit ; +PACKAGE !%= "package" !LetterOrDigit ; +PRIVATE !%= "private" !LetterOrDigit ; +PROTECTED !%= "protected" !LetterOrDigit ; +PUBLIC !%= "public" !LetterOrDigit ; +RETURN !%= "return" !LetterOrDigit ; +SHORT !%= "short" !LetterOrDigit ; +STATIC !%= "static" !LetterOrDigit ; +STRICTFP !%= "strictfp" !LetterOrDigit ; +SUPER !%= "super" !LetterOrDigit ; +SWITCH !%= "switch" !LetterOrDigit ; +SYNCHRONIZED !%= "synchronized" !LetterOrDigit ; +THIS !%= "this" !LetterOrDigit ; +THROWS !%= "throws" !LetterOrDigit ; +THROW !%= "throw" !LetterOrDigit ; +TRANSIENT !%= "transient" !LetterOrDigit ; +TRUE !%= "true" !LetterOrDigit ; +TRY !%= "try" !LetterOrDigit ; +VOID !%= "void" !LetterOrDigit ; +VOLATILE !%= "volatile" !LetterOrDigit ; +WHILE !%= "while" !LetterOrDigit ; -//------------------------------------------------------------------------- -// JLS 3.10 Literals -//------------------------------------------------------------------------- +//========================================================================= +// Literals (JLS 3.10) +//========================================================================= -Literal - = FloatLiteral - / IntegerLiteral // May be a prefix of FloatLiteral - / BooleanLiteral - / CharLiteral - / StringLiteral - / NullLiteral - ; +/* -//------------------------------------------------------------------------- -// JLS 3.10.1 Integer Literals -//------------------------------------------------------------------------- + + ~literal + OR + :+~floatLiteral + :+~integerLiteral + :+~booleanLiteral + :+~charLiteral + :+~nullLiteral + +*/ + +Literal ~literal + = FloatLiteral :+~floatLiteral + / IntegerLiteral :+~integerLiteral // May be a prefix of FloatLiteral + / BooleanLiteral :+~booleanLiteral + / CharLiteral :+~charLiteral + / StringLiteral :+~stringLiteral + / NullLiteral :+~nullLiteral ; IntegerLiteral - !:= ( HexNumeral + !%= ( HexNumeral / BinaryNumeral / OctalNumeral // May be a prefix of HexNumeral or BinaryNumeral / DecimalNumeral // May be a prefix of OctalNumeral - ) [lL]? - ; + ) [lL]? ; DecimalNumeral - = "0" - / [1-9]([_]*[0-9])* - ; + = "0" / [1-9]([_]*[0-9])* ; HexNumeral = ("0x" / "0X") HexDigits ; @@ -213,22 +210,15 @@ OctalNumeral BinaryNumeral = ("0b" / "0B") [01]([_]*[01])* ; -//------------------------------------------------------------------------- -// JLS 3.10.2 Floatng-point Literals -//------------------------------------------------------------------------- - FloatLiteral - !:= ( HexadecimalFloatingPointLiteral - / DecimalFloatingPointLiteral // May be a prefix of above - ) - ; + !%= HexadecimalFloatingPointLiteral + / DecimalFloatingPointLiteral ; // May be a prefix of above DecimalFloatingPointLiteral = Digits "." Digits? Exponent? [fFdD]? / "." Digits Exponent? [fFdD]? / Digits Exponent [fFdD]? - / Digits Exponent? [fFdD] - ; + / Digits Exponent? [fFdD] ; Exponent = [eE] [+\\-]? Digits ; @@ -238,8 +228,7 @@ HexadecimalFloatingPointLiteral HexSignificand = ("0x" / "0X") HexDigits? "." HexDigits - / HexNumeral "."? // May be a prefix of above - ; + / HexNumeral "."? ; // May be a prefix of above HexDigits = HexDigit ([_]*HexDigit)* ; @@ -253,66 +242,45 @@ BinaryExponent Digits = [0-9]([_]*[0-9])* ; -//------------------------------------------------------------------------- -// JLS 3.10.3 Boolean Literals -//------------------------------------------------------------------------- - BooleanLiteral - = TRUE - / FALSE - ; - -//------------------------------------------------------------------------- -// JLS 3.10.4 Character Literals -//------------------------------------------------------------------------- + = TRUE / FALSE ; CharLiteral - !:= "'" (Escape / !['\\\n\r] _) "'" - ; - -//------------------------------------------------------------------------- -// JLS 3.10.5 String Literals -//------------------------------------------------------------------------- + !%= "'" (Escape / !['\\\n\r] _) "'" ; StringLiteral - !:= "\"" (Escape / ![\"\\\n\r] _)* "\"" - ; + !%= "\"" (Escape / ![\"\\\n\r] _)* "\"" ; Escape - = "\\" ([btnfr\"'\\] / OctalEscape / UnicodeEscape) - ; + = "\\" ([btnfr\"'\\] / OctalEscape / UnicodeEscape) ; OctalEscape = [0-3][0-7][0-7] / [0-7][0-7] - / [0-7] - ; + / [0-7] ; UnicodeEscape = "u"+ HexDigit HexDigit HexDigit HexDigit ; -//------------------------------------------------------------------------- -// JLS 3.10.6 The Null literal -//------------------------------------------------------------------------- - -NullLiteral = NULL ; +NullLiteral + = NULL ; //------------------------------------------------------------------------- // JLS 3.11 Separators //------------------------------------------------------------------------- -'@' := "@" ; -'::' := "::" ; -',' := "," ; -'.' := "." ; -'...' := "..." ; -'(' := "(" ; -'[' := "[" ; -']' := "]" ; -')' := ")" ; -'{' := "{" ; -'}' := "}" ; -';' := ";" ; +'@' %= "@" ; +'::' %= "::" ; +',' %= "," ; +'.' %= "." ; +'...' %= "..." ; +'(' %= "(" ; +'[' %= "[" ; +']' %= "]" ; +')' %= ")" ; +'{' %= "{" ; +'}' %= "}" ; +';' %= ";" ; //------------------------------------------------------------------------- // JLS 3.12 Operators @@ -322,56 +290,114 @@ NullLiteral = NULL ; // rule given in JLS 3.2. //------------------------------------------------------------------------- -AND := "&" ![=&] ; -ANDAND := "&&" ; -ANDEQU := "&=" ; -ARROW := "->" ; -BANG := "!" ![=] ; -BSR := ">>>" ![=] ; -BSREQU := ">>>=" ; -COLON := ":" ![:] ; -DEC := "--" ; -DIV := "/" ![=] ; -DIVEQU := "/=" ; -EQU := "=" ![=] ; -EQUAL := "==" ; -GE := ">=" ; -GT := ">" ![=>] ; -HAT := "^" ![=] ; -HATEQU := "^=" ; -INC := "++" ; -LE := "<=" ; -LPOINT := "<" ; -LT := "<" ![=<] ; -MINUS := "-" ![=\->] ; -MINUSEQU := "-=" ; -MOD := "%" ![=] ; -MODEQU := "%=" ; -NOTEQUAL := "!=" ; -OR := "|" ![=|] ; -OREQU := "|=" ; -OROR := "||" ; -PLUS := "+" ![=+] ; -PLUSEQU := "+=" ; -QUERY := "?" ; -RPOINT := ">" ; -SL := "<<" ![=] ; -SLEQU := "<<=" ; -SR := ">>" ![=>] ; -SREQU := ">>=" ; -STAR := "*" ![=] ; -STAREQU := "*=" ; -TILDE := "~" ; - +AND %= "&" ![=&] ; +ANDAND %= "&&" ; +ANDEQU %= "&=" ; +ARROW %= "->" ; +BANG %= "!" ![=] ; +BSR %= ">>>" ![=] ; +BSREQU %= ">>>=" ; +COLON %= ":" ![:] ; +DEC %= "--" ; +DIV %= "/" ![=] ; +DIVEQU %= "/=" ; +EQU %= "=" ![=] ; +EQUAL %= "==" ; +GE %= ">=" ; +GT %= ">" ![=>] ; +HAT %= "^" ![=] ; +HATEQU %= "^=" ; +INC %= "++" ; +LE %= "<=" ; +LPOINT %= "<" ; +LT %= "<" ![=<] ; +MINUS %= "-" ![=\->] ; +MINUSEQU %= "-=" ; +MOD %= "%" ![=] ; +MODEQU %= "%=" ; +NOTEQUAL %= "!=" ; +OR %= "|" ![=|] ; +OREQU %= "|=" ; +OROR %= "||" ; +PLUS %= "+" ![=+] ; +PLUSEQU %= "+=" ; +QUERY %= "?" ; +RPOINT %= ">" ; +SL %= "<<" ![=] ; +SLEQU %= "<<=" ; +SR %= ">>" ![=>] ; +SREQU %= ">>=" ; +STAR %= "*" ![=] ; +STAREQU %= "*=" ; +TILDE %= "~" ; //========================================================================= -// JLS 4 Types, Values and Variables +// Types (JLS 4) //========================================================================= -//------------------------------------------------------------------------- -// JLS 4.2 Primitive Types and Values -//------------------------------------------------------------------------- -BasicType +/* + +constraints: + - type arguments and bounds must be reference types (classes or arrays, not primitive types) + + + :+~basicType + + + :~primitiveType + + + + + :~classType + :#components + + :+-id + + + + :~type + OR + + + + + + ~stemType + OR + + + + + :#dims + + + + :#typeParameters + + :-+id + #boundTypes + + + + + # typeArgs + OR + + + + + :~ wildcard + + OR? + -extends + + -super + + +*/ + +BasicType :+~ basicType = BYTE / SHORT / INT @@ -379,647 +405,706 @@ BasicType / CHAR / FLOAT / DOUBLE - / BOOLEAN - ; + / BOOLEAN ; -PrimitiveType - = Annotation* BasicType ; +PrimitiveType :~ primitiveType + = Annotations BasicType ; -//------------------------------------------------------------------------- -// JLS 4.3 Reference Types and Values -//------------------------------------------------------------------------- +ClassType :~ classType + = (Annotations Identifier:+-id TypeArguments?) :# components ,+ '.' ; -ReferenceType - = PrimitiveType Dim+ - / ClassType Dim* - ; +Type :~ type + = StemType Dims ; -ClassType - = Annotation* Identifier TypeArguments? - ('.' Annotation* Identifier TypeArguments?)* ; +StemType ~ stemType + = PrimitiveType / ClassType ; -Type - = PrimitiveType - / ClassType - ; +Dim + = Annotations '[' ']' ; -ArrayType - = PrimitiveType Dim+ - / ClassType Dim+ - ; +Dims + = Dim :# dims * ; -TypeVariable - = Annotation* Identifier ; +DimsAlo + = Dim :# dims + ; -Dim - = Annotation* '[' ']' ; - -//------------------------------------------------------------------------- -// JLS 4.4 Type Variables -//------------------------------------------------------------------------- +TypeParameters + = LPOINT TypeParameter :# typeParameters ,+ ',' RPOINT ; TypeParameter - = TypeParameterModifier* Identifier TypeBound? ; - -TypeParameterModifier - = Annotation ; + = Annotations Identifier:+-id TypeBound? ; TypeBound - = EXTENDS (ClassType AdditionalBound* / TypeVariable) ; - -AdditionalBound - = AND ClassType ; - -//------------------------------------------------------------------------- -// JLS 4.5 Parametrized Types -//------------------------------------------------------------------------- + = EXTENDS (ClassType # boundTypes) ,+ AND ; TypeArguments - = LPOINT TypeArgumentList RPOINT ; - -TypeArgumentList - = TypeArgument (',' TypeArgument)* ; + = LPOINT TypeArgument # typeArgs ,+ ',' RPOINT ; TypeArgument - = ReferenceType - / Wildcard - ; + = Type / Wildcard ; -Wildcard - = Annotation* QUERY WildcardBounds? ; +Wildcard :~ wildcard + = Annotations QUERY WildcardBounds? ; WildcardBounds - = EXTENDS ReferenceType - / SUPER ReferenceType - ; - + = EXTENDS Type - extends + / SUPER Type - super ; //========================================================================= -// JLS 6 Names +// Compilation Unit (JLS 7.3) //========================================================================= -QualIdent - = Identifier ('.' Identifier)* ; +/* + + :- package + + :+-id + :#imports + ?:-static + :+-id + ?:-star + :#types + -//========================================================================= -// JLS 7 Packages -//========================================================================= -//------------------------------------------------------------------------- -// JLS 7.3 Compilation Units -//------------------------------------------------------------------------- +*/ CompilationUnit - = PackageDeclaration? ImportDeclaration* TypeDeclaration* ; - -//------------------------------------------------------------------------- -// JLS 7.4 Package Declarations -//------------------------------------------------------------------------- - -PackageDeclaration - = PackageModifier* PACKAGE Identifier ('.' Identifier)* ';' ; + = PackageDeclaration? + ((ImportDeclaration :# imports) / ';')* + (TypeDeclaration :# types)* ; -PackageModifier - = Annotation ; - -//------------------------------------------------------------------------- -// JLS 7.5 Import Declarations -//------------------------------------------------------------------------- +PackageDeclaration :- package + = Annotations PACKAGE QualIdent:+-id ';' ; ImportDeclaration - = IMPORT STATIC? QualIdent ('.' STAR)? ';' - / ';' - ; - -//------------------------------------------------------------------------- -// JLS 7.6 Top Level Type Declarations -//------------------------------------------------------------------------- - -TypeDeclaration - = ClassDeclaration - / InterfaceDeclaration - / ';' - ; - + = IMPORT STATIC:-static? QualIdent:+-id ('.' STAR:-star)? ';' ; //========================================================================= -// JLS 8 Classes +// Type Declarations (JLS 8.1 & 8.9 & 9.6) //========================================================================= -//------------------------------------------------------------------------- -// JLS 8.1 Class Declarations -//------------------------------------------------------------------------- -ClassDeclaration - = NormalClassDeclaration - / EnumDeclaration - ; - -NormalClassDeclaration - = ClassModifier* CLASS Identifier TypeParameters? - Superclass? Superinterfaces? ClassBody - ; - -ClassModifier +/* + +constraints: + - interfaces can't be final + - enums and annotation types can't have superclasses or type parameters + - only enums can have enum constants + - interfaces must "extends" other interfaces and cannot use "implements" + - interfaces cannot have init blocks and constructors + - in interfaces, method must have no body or be declared default + - only annotations can have annotation elements declarations + - (more) + + + #modifiers + OR + + :~public + :~protected + :~private + :~abstract + :~static + :~final + :~strictfp + + + :~typeDeclaration + + ?:-annotationDeclaration + OR + :-class + :-enum + :-interface + :+-id + ? + ?#extended + + ?#implemented + + ?:#enumConstants + + :+-id + ? + + + + #declarations + OR + + + + + ~block + + ~static + + + :~semi + +*/ + +TypeModifier = Annotation - / PUBLIC - / PROTECTED - / PRIVATE - / ABSTRACT - / STATIC - / FINAL - / STRICTFP - ; - -TypeParameters - = LPOINT TypeParameterList RPOINT ; - -TypeParameterList - = TypeParameter (',' TypeParameter)* ; + / PUBLIC :~public + / PROTECTED :~protected + / PRIVATE :~private + / ABSTRACT :~abstract + / STATIC :~static + / FINAL :~final + / STRICTFP :~strictfp ; -Superclass - = EXTENDS ClassType ; +TypeDeclaration :~ typeDeclaration + = TypeModifier # modifiers * (EnumDeclaration / OtherTypeDeclaration) ; -Superinterfaces - = IMPLEMENTS InterfaceTypeList ; - -InterfaceTypeList - = ClassType (',' ClassType)* ; +EnumDeclaration + = ENUM:-enum + Identifier:+-id + Extends? + Implements? + '{' (EnumConstant :# enumConstants) , ',' ','? (';' ClassBodyDeclarations)? '}' ; + +OtherTypeDeclaration + = (CLASS:-class / '@':-annotationDeclaration? INTERFACE:-interface) + Identifier:+-id + TypeParameters? + Extends? + Implements? + ClassBody ; + +Extends # extended + = EXTENDS (ClassType ,+ ',') ; + +Implements # implemented + = IMPLEMENTS (ClassType ,+ ',') ; ClassBody - = '{' ClassBodyDeclaration* '}' ; + = '{' ClassBodyDeclarations '}' ; + +ClassBodyDeclarations # declarations + = ClassBodyDeclaration* ; ClassBodyDeclaration - = ClassMemberDeclaration - / InstanceInitializer - / StaticInitializer - / ConstructorDeclaration - ; -ClassMemberDeclaration + // Members + = FieldDeclaration / MethodDeclaration - / ClassDeclaration - / InterfaceDeclaration - / ';' - ; + / TypeDeclaration + / AnnotationTypeElementDeclaration -//------------------------------------------------------------------------- -// JLS 8.3 Field Declarations -//------------------------------------------------------------------------- - -FieldDeclaration - = FieldModifier* UnannType VariableDeclaratorList ';' ; - -VariableDeclaratorList - = VariableDeclarator (',' VariableDeclarator)* ; - -VariableDeclarator - = VariableDeclaratorId (EQU VariableInitializer)? ; - -VariableDeclaratorId - = Identifier Dim* ; - -VariableInitializer - = Expression - / ArrayInitializer - ; + // Other Declarations -UnannClassType - = Identifier TypeArguments? - ('.' Annotation* Identifier TypeArguments?)* ; + / Block ~ block + / (STATIC Block) ~ static + / ConstructorDeclaration + / ';' :~ semi ; -UnannType - = BasicType Dim* - / UnannClassType Dim* - ; +EnumConstant + = Annotations Identifier:+-id Arguments? ClassBody? ; -FieldModifier - = Annotation - / PUBLIC - / PROTECTED - / PRIVATE - / STATIC - / FINAL - / TRANSIENT - / VOLATILE - ; +//========================================================================= +// Member Declarations (JLS 8.3 & 8.4 & 8.8) +//========================================================================= +/* + +constraints: + - for annotation elements, only the public and abstract modifiers are valid + - the type of annotation elements is limited: http://stackoverflow.com/questions/1458535 + - only interface methods can have the default modifier (iif they have a body) + - a variadic (...) parameter is only allowed as last parameter + - a receiver (this) parameter is only allowed as first parameter + - the type of the receiver must be that of the class + - a constructor can't have a receiver parameter + - (more) + + + :~fieldDeclaration + #modifiers + OR + + :~public + :~protected + :~private + :~static + :~final + :~transient + :~volatile + + + + + :#declarators + + ? + + + :~declaratorID + :+-id + + + + :~variableInitializer + OR + + + + + #initializerElements + + + + #modifiers + OR + + :~public + :~protected + :~private + :~abstract + :~static + :~final + :~synchronized + :~native + :~strictfp + + + :~methodDeclaration + + -returnType + OR + + :~void + :+-id + + + ? + + + + :#parameters + + + ? + ?:-ellipsis + OR + + :-this + + + #modifiers + OR + + :~final + + + #exceptions + + + + :~constructorDeclaration + #modifiers + OR + + :~public + :~protected + :~private + ? + :+-id + + ? + ?:-constrInvoc + ?-enclosingInstance + + ? + OR + :-this + :-super + + + + + :~annotationElemDecl + + + :+-id + + ? + +*/ + +//------------------------------------------------------------------------- +// Fields //------------------------------------------------------------------------- -// JLS 8.4 Method Declarations -//------------------------------------------------------------------------- - -MethodDeclaration - = MethodModifier* MethodHeader MethodBody ; - -MethodHeader - = Result MethodDeclarator Throws? - / TypeParameters Annotation* Result MethodDeclarator Throws? - ; - -MethodDeclarator - = Identifier '(' FormalParameterList? ')' Dim* ; - -FormalParameterList - = (ReceiverParameter / FormalParameter)(',' FormalParameter)* ; - -FormalParameter - = VariableModifier* UnannType VariableDeclaratorId - / VariableModifier* UnannType Annotation* '...' VariableDeclaratorId !',' - ; -VariableModifier +FieldModifier = Annotation - / FINAL - ; + / PUBLIC :~public + / PROTECTED :~protected + / PRIVATE :~private + / STATIC :~static + / FINAL :~final + / TRANSIENT :~transient + / VOLATILE :~volatile ; -ReceiverParameter - = VariableModifier* UnannType (Identifier '.')? THIS ; +FieldDeclaration :~ fieldDeclaration + = FieldModifier # modifiers * Type VariableDeclaratorList ';' ; -Result - = UnannType - / VOID - ; - -MethodModifier - = Annotation - / PUBLIC - / PROTECTED - / PRIVATE - / ABSTRACT - / STATIC - / FINAL - / SYNCHRONIZED - / NATIVE - / STRICTFP - ; +VariableDeclaratorList :# declarators + = VariableDeclarator ,+ ',' ; -Throws - = THROWS ExceptionTypeList ; +VariableDeclarator + = VariableDeclaratorId (EQU VariableInitializer)? ; -ExceptionTypeList - = ExceptionType (',' ExceptionType)* ; +VariableDeclaratorId :~ declaratorID + = Identifier:+-id Dims; -ExceptionType - = ClassType - / TypeVariable - ; +VariableInitializer :~ variableInitializer + = Expression / ArrayInitializer ; -MethodBody - = Block - / ';' - ; +ArrayInitializer + = '{' (VariableInitializer # initializerElements) , ',' ','? '}' ; //------------------------------------------------------------------------- -// JLS 8.6 Instance Initializers +// Methods //------------------------------------------------------------------------- -InstanceInitializer - = Block ; +MethodModifier # modifiers + = Annotation + / PUBLIC :~public + / PROTECTED :~protected + / PRIVATE :~private + / ABSTRACT :~abstract + / STATIC :~static + / FINAL :~final + / SYNCHRONIZED :~synchronized + / NATIVE :~native + / STRICTFP :~strictfp + / DEFAULT :~default ; + +MethodDeclaration :~ methodDeclaration + = MethodModifier* + TypeParameters? + (Type / VOID :~ void) - returnType + Identifier :+- id + FormalParameters + Dims + Throws? + (Block / ';') ; + +FormalParameters + = '(' (FormalParameter :# parameters) , ',' ')' ; -//------------------------------------------------------------------------- -// JLS 8.7 Static Initializers -//------------------------------------------------------------------------- +FormalParameter + = VariableModifiers Type + ( THIS :- this + / VariableDeclaratorId + / Annotations '...' :- ellipsis VariableDeclaratorId !',' ) ; -StaticInitializer - = STATIC Block ; +VariableModifiers # modifiers + = ( Annotation / FINAL :~ final )* ; + +Throws + = THROWS ClassType # exceptions ,+ ',' ; //------------------------------------------------------------------------- -// JLS 8.8 Constructor Declarations +// Constructors //------------------------------------------------------------------------- -ConstructorDeclaration - = ConstructorModifier* ConstructorDeclarator Throws? ConstructorBody ; - -ConstructorDeclarator - = TypeParameters? Identifier '(' FormalParameterList? ')' ; - ConstructorModifier = Annotation - / PUBLIC - / PROTECTED - / PRIVATE - ; - -ConstructorBody - = '{' ExplicitConstructorInvocation? BlockStatements? '}' ; - -ExplicitConstructorInvocation - = TypeArguments? THIS Arguments ';' - / TypeArguments? SUPER Arguments ';' + / PUBLIC :~public + / PROTECTED :~protected + / PRIVATE :~private ; + +ConstructorDeclaration :~ constructorDeclaration + = ConstructorModifier # modifiers * + TypeParameters? + Identifier:+-id + FormalParameters + Throws? + '{' ExplicitConstructorInvocation? BlockStatements '}' ; + +ExplicitConstructorInvocation :- constrInvoc + = TypeArguments? THIS:-this Arguments ';' + / TypeArguments? SUPER:-super Arguments ';' // http://stackoverflow.com/questions/2831484 + // TODO: only primary expression allowed here? - / Expression '.' TypeArguments? SUPER Arguments ';' - ; + / Expression - enclosingInstance '.' TypeArguments? SUPER:-super Arguments ';' ; //------------------------------------------------------------------------- -// JLS 8.9 Enum Types +// Annotation Elements //------------------------------------------------------------------------- -EnumDeclaration - = ClassModifier* ENUM Identifier Superinterfaces? EnumBody ; - -EnumBody - = '{' EnumConstantList? ','? EnumBodyDeclarations? '}' ; - -EnumConstantList - = EnumConstant (',' EnumConstant)* ; - -EnumConstant - = EnumConstantModifier* Identifier Arguments? ClassBody? ; - -EnumConstantModifier - = Annotation ; - -EnumBodyDeclarations - = ';' ClassBodyDeclaration* ; - +AnnotationTypeElementDeclaration :~ annotationElemDecl + = MethodModifier* + Type Identifier:+-id '(' ')' Dims + (DEFAULT ElementValue)? ';' ; //========================================================================= -// JLS 9 Interfaces +// Annotations (JLS 9.7) //========================================================================= -//------------------------------------------------------------------------- -// JLS 9.1 Interface Declarations -//------------------------------------------------------------------------- - -InterfaceDeclaration - = NormalInterfaceDeclaration - / AnnotationTypeDeclaration - ; - -NormalInterfaceDeclaration - = InterfaceModifier* INTERFACE Identifier TypeParameters? - ExtendsInterfaces? InterfaceBody ; - -InterfaceModifier - = Annotation - / PUBLIC - / PROTECTED - / PRIVATE - / ABSTRACT - / STATIC - / STRICTFP - ; -ExtendsInterfaces - = EXTENDS InterfaceTypeList ; +/* -InterfaceBody - = '{' InterfaceMemberDeclaration* '}' ; + + #annotations + -InterfaceMemberDeclaration - = ConstantDeclaration - / InterfaceMethodDeclaration - / ClassDeclaration - / InterfaceDeclaration - / ';' - ; + + :~annotation + :+-id + ?OR + + :-pairs (*) + :+-id + -//------------------------------------------------------------------------- -// JLS 9.3 Field (Constant) Declarations -//------------------------------------------------------------------------- + + :~value + OR + + #values + + -ConstantDeclaration - = ConstantModifier* UnannType VariableDeclaratorList ';' ; +*/ -ConstantModifier - = Annotation - / PUBLIC - / STATIC - / FINAL - ; - -//------------------------------------------------------------------------- -// JLS 9.4 Method Declarations -//------------------------------------------------------------------------- - -InterfaceMethodDeclaration - = InterfaceMethodModifier* MethodHeader MethodBody ; - -InterfaceMethodModifier - = Annotation - / PUBLIC - / ABSTRACT - / DEFAULT - / STATIC - / STRICTFP - ; - -//------------------------------------------------------------------------- -// JLS 9.6 Annotation types -//------------------------------------------------------------------------- +Annotations # annotations + = Annotation* ; -AnnotationTypeDeclaration - = InterfaceModifier* '@' INTERFACE Identifier AnnotationTypeBody ; - -AnnotationTypeBody - = '{' AnnotationTypeMemberDeclaration* '}' ; - -AnnotationTypeMemberDeclaration - = AnnotationTypeElementDeclaration - / ConstantDeclaration - / ClassDeclaration - / InterfaceDeclaration - / ';' - ; - -AnnotationTypeElementDeclaration - = AnnotationTypeElementModifier* UnannType Identifier '(' ')' Dim* - DefaultValue? ';' ; - -AnnotationTypeElementModifier - = Annotation - / PUBLIC - / ABSTRACT - ; - -DefaultValue - = DEFAULT ElementValue ; - -//------------------------------------------------------------------------- -// JLS 9.7 Annotations -//------------------------------------------------------------------------- - -Annotation - = '@' - ( NormalAnnotation - / SingleElementAnnotation - / MarkerAnnotation - ) - ; - -NormalAnnotation - = QualIdent '(' ElementValuePairList* ')' ; - -ElementValuePairList - = ElementValuePair (',' ElementValuePair)* ; +Annotation :~ annotation + = '@' QualIdent:+-id ('('( (ElementValuePair :# pairs) ,+ ',' / ElementValue )? ')')? ; ElementValuePair - = Identifier EQU ElementValue ; + = Identifier:+-id EQU ElementValue ; -ElementValue +ElementValue :~ value = Expression forbid { assign } / ElementValueArrayInitializer / Annotation ; -ElementValueArrayInitializer - = '{' ElementValueList? ','? '}' ; - -ElementValueList - = ElementValue (',' ElementValue)* ; - -MarkerAnnotation - = QualIdent ; - -SingleElementAnnotation - = QualIdent '(' ElementValue ')' ; - +ElementValueArrayInitializer # values + = '{' ElementValue , ',' ','? '}' ; //========================================================================= -// JLS 10 Arrays +// Statements (JLS 14) //========================================================================= -//------------------------------------------------------------------------- -// JLS 10.6 Array Initializers -//------------------------------------------------------------------------- -ArrayInitializer - = '{' VariableInitializerList? ','? '}' ; - -VariableInitializerList - = VariableInitializer (',' VariableInitializer)* ; - -//========================================================================= -// JLS 14 Blocks and Statements -//========================================================================= -//------------------------------------------------------------------------- -// JLS 14.2 Blocks -//------------------------------------------------------------------------- +/* + +constraints: + - interfaces and annotations can't be local + + + :~statements + OR + + + + + + :~ localVarDecl + + + + + + ~statement + OR + + + :~ifElse + + -if + + -else + + + + + + + :~while + + + + :~doWhile + + + + + + :~switch + + :#switchBlocks + #labels + OR + ~label + + :~default + + + :~synchronized + + + + :~return + ? + + ~throw + + + :~break + ?:+-id + + :~continue + ?:+-id + + :~assert + + ?-message + + + :~semi + + ~stmtExpr + + + :~labelled + :+-label + + + + :~basicFor + ?:-init + OR + + + ?-cond + + ?:-iter + + -body + + + + #stmtExprs + + + + :~ enhancedFor + + + + -iterable + + -body + + + + :~try + :#resources + + + + -value + + -body + + :#catchClauses + + #types + + + + -finally + + +*/ Block - = '{' BlockStatements? '}' ; + = '{' BlockStatements '}' ; -BlockStatements - = BlockStatement BlockStatement* ; +BlockStatements :~ statements + = BlockStatement* ; BlockStatement - = LocalVariableDeclarationStatement - / ClassDeclaration - / Statement - ; - -//------------------------------------------------------------------------- -// JLS 14.4 Local Variable Declaration Statements -//------------------------------------------------------------------------- - -LocalVariableDeclarationStatement - = LocalVariableDeclaration ';' ; + = LocalVariableDeclaration ';' + / TypeDeclaration + / Statement ; -LocalVariableDeclaration - = VariableModifier* UnannType VariableDeclaratorList ; +LocalVariableDeclaration :~ localVarDecl + = VariableModifiers Type VariableDeclaratorList ; -//------------------------------------------------------------------------- -// JLS 14.5 Statements -//------------------------------------------------------------------------- - -Statement +Statement ~ statement = Block - / IF ParExpression Statement (ELSE Statement)? + / IfElse / BasicForStatement / EnhancedForStatement - / WHILE ParExpression Statement - / DO Statement WHILE ParExpression ';' + / (WHILE ParExpression Statement) :~while + / (DO Statement WHILE ParExpression ';') :~doWhile / TryStatement - / SWITCH ParExpression SwitchBlock - / SYNCHRONIZED ParExpression Block - / RETURN Expression? ';' - / THROW Expression ';' - / BREAK Identifier? ';' - / CONTINUE Identifier? ';' - / ASSERT Expression (COLON Expression)? ';' - / ';' - / StatementExpression ';' - / Identifier COLON Statement - ; + / (SWITCH ParExpression SwitchBlock) :~switch + / (SYNCHRONIZED ParExpression Block) :~synchronized + / (RETURN Expression? ';') :~return + / (THROW Expression ';') ~throw + / (BREAK Identifier:+-id? ';') :~break + / (CONTINUE Identifier:+-id? ';') :~continue + / (ASSERT Expression (COLON Expression-message)? ';') :~assert + / ';' :~semi + / (StatementExpression ';') ~stmtExpression + / (Identifier:+-label COLON Statement) :~labelled ; + +IfElse :~ ifElse + = IF ParExpression Statement-if (ELSE Statement-else)? ; ParExpression = '(' Expression ')' ; -//------------------------------------------------------------------------- -// JLS 14.11 The SWITCH Statement -//------------------------------------------------------------------------- - SwitchBlock - = '{' SwitchBlockStatementGroup* SwitchLabel* '}' ; - -SwitchBlockStatementGroup - = SwitchLabels BlockStatements ; - -SwitchLabels - = SwitchLabel SwitchLabel* ; + = '{' (SwitchLabel # labels + BlockStatements) :# switchBlocks * '}' ; SwitchLabel - = CASE (Expression / EnumConstantName) COLON - / DEFAULT COLON - ; + = CASE Expression~label COLON / DEFAULT:~default COLON ; -EnumConstantName - = Identifier ; - -//------------------------------------------------------------------------- -// JLS 14.14 The FOR Statement -//------------------------------------------------------------------------- +StatementExpression + = Expression allow { assign, binc, bdec, ainc, adec, mcall, tmcall, ccall } ; -BasicForStatement - = FOR '(' ForInit? ';' Expression? ';' ForUpdate? ')' Statement ; +BasicForStatement :~ basicFor + = FOR '(' ForInit:-init? ';' Expression-cond? ';' StatementExpressionList:-iter? ')' + Statement-body ; ForInit = LocalVariableDeclaration - / StatementExpressionList - ; - -ForUpdate - = StatementExpressionList ; + / StatementExpressionList ; -StatementExpressionList - = StatementExpression (',' StatementExpression)* ; +StatementExpressionList # stmtExprs + = StatementExpression ,+ ',' ; -EnhancedForStatement - = FOR '(' VariableModifier* UnannType VariableDeclaratorId COLON - Expression ')' Statement ; +EnhancedForStatement :~ enhancedFor + = FOR '(' VariableModifiers Type VariableDeclaratorId COLON Expression-iterable ')' + Statement-body ; -//------------------------------------------------------------------------- -// JLS 14.20 The TRY Statement -//------------------------------------------------------------------------- - -TryStatement +TryStatement :~ try = TRY - ( Block (CatchClause* Finally / CatchClause+) - / ResourceSpecification Block CatchClause* Finally? - ) - ; + ( Block - body (CatchClause* Finally / CatchClause+) + / '(' (Resource :# resources) ,+ ';' ';'? ')' Block CatchClause* Finally? ) ; -CatchClause +CatchClause :# catchClauses = CATCH '(' CatchFormalParameter ')' Block ; CatchFormalParameter - = VariableModifier* CatchType VariableDeclaratorId ; - -CatchType - = UnannClassType (OR ClassType)* ; + = VariableModifiers (ClassType # types) ,+ OR VariableDeclaratorId ; Finally - = FINALLY Block ; - -ResourceSpecification - = '(' ResourceList ';'? ')' ; - -ResourceList - = Resource (';' Resource)* ; + = FINALLY Block - finally ; Resource - = VariableModifier* UnannType VariableDeclaratorId EQU Expression ; - + = VariableModifiers Type VariableDeclaratorId EQU Expression-value ; //========================================================================= // JLS 15 Expressions @@ -1029,65 +1114,103 @@ Resource // JLS 15.9 Class Instance Creation Expressions //------------------------------------------------------------------------- +/* + + + (?) + + + :#components + + :+-id + ?OR + + :-diamond + ? + +*/ + ClassCreator - = TypeArguments? Annotation* ClassTypeWithDiamond - Arguments ClassBody? ; + = TypeArguments? Annotations ClassTypeWithDiamond Arguments ClassBody? ; -ClassTypeWithDiamond - = Annotation* Identifier TypeArgumentsOrDiamond? - ('.' Annotation* Identifier TypeArgumentsOrDiamond?)* ; +ClassTypeWithDiamond :# components + = (Annotations Identifier:+-id TypeArgumentsOrDiamond?) ,+ '.' ; TypeArgumentsOrDiamond = TypeArguments - / LPOINT RPOINT !'.' // Must be last - ; + / (LPOINT RPOINT !'.'):-diamond ; // Must be last //------------------------------------------------------------------------- // JLS 15.10 Array Creation and Access Expressions //------------------------------------------------------------------------- +/* + + + + ?:#dimExprs + + + + ? + +*/ + +// NOTE:-arrays with an initializer cannot have dimension expressions + ArrayCreator - = Type DimExpr+ Dim* - / Type Dim+ ArrayInitializer - ; + = StemType DimExpr+ Dims + / StemType DimsAlo ArrayInitializer ; -DimExpr - = Annotation* '[' Expression ']' ; +DimExpr :# dimExprs + = Annotations '[' Expression ']' ; //------------------------------------------------------------------------- // JLS 15.12 Method Invocation Expressions //------------------------------------------------------------------------- -Arguments - = '(' ArgumentList? ')' ; +/* + + + #arguments + -ArgumentList - = Expression (',' Expression)* ; +*/ + +Arguments # arguments + = '(' Expression , ',' ')' ; //------------------------------------------------------------------------- // JLS 15.27 Lambda Expressions //------------------------------------------------------------------------- -LambdaExpression - = LambdaParameters ARROW LambdaBody ; +/* -LambdaParameters - = Identifier - / '(' FormalParameterList? ')' - / '(' InferredFormalParameterList ')' - ; + + :~lambda + OR + :+-id + + :+#inferredParameters + :-lambdaBody + OR + + -InferredFormalParameterList - = Identifier (',' Identifier)* ; +*/ -LambdaBody - = Expression - / Block - ; +LambdaExpression :~ lambda + = LambdaParameters ARROW (Expression / Block) :- lambdaBody ; + +LambdaParameters + = Identifier:+-id + / FormalParameters + / '(' (Identifier :+# inferredParameters) ,+ ',' ')' ; // =============================================================================== -Expression = expr +Expression ~ expression + = expr -> Assignment @+ @left_recur @assign -> LambdaExpression @= @@ -1095,88 +1218,111 @@ Expression = expr // BINARY OPERATORS - -> Expression OROR Expression @+ @left_assoc - -> Expression ANDAND Expression @+ @left_assoc - -> Expression OR Expression @+ @left_assoc - -> Expression HAT Expression @+ @left_assoc - -> Expression AND Expression @+ @left_assoc + -> OrOr @+ @left_assoc + -> AndAnd @+ @left_assoc + -> Or @+ @left_assoc + -> Hat @+ @left_assoc + -> And @+ @left_assoc - -> Expression EQUAL Expression @+ @left_assoc - -> Expression NOTEQUAL Expression @= + -> Equal @+ @left_assoc + -> NotEqual @= - -> Expression LE Expression @+ @left_assoc - -> Expression GE Expression @= - -> Expression LT Expression @= - -> Expression GT Expression @= - -> Expression INSTANCEOF Expression @= + -> Le @+ @left_assoc + -> Ge @= + -> Lt @= + -> Gt @= + -> InstanceOf @= - -> Expression SL Expression @+ @left_assoc - -> Expression SR Expression @= - -> Expression BSR Expression @= + -> Sl @+ @left_assoc + -> Sr @= + -> Bsr @= - -> Expression PLUS Expression @+ @left_assoc - -> Expression MINUS Expression @= + -> Plus @+ @left_assoc + -> Minus @= - -> Expression STAR Expression @+ @left_assoc - -> Expression DIV Expression @= - -> Expression MOD Expression @= + -> Star @+ @left_assoc + -> Div @= + -> Mod @= // PREFIX OPERATORS - -> INC Expression @+ @binc - -> DEC Expression @= @bdec - -> PLUS Expression @= - -> MINUS Expression @= - -> TILDE Expression @= - -> BANG Expression @= - -> CastExpression @= // does not conflict with (expr)(arguments) because lower precedence + -> BInc @+ @binc + -> BDec @= @bdec + -> UPlus @= + -> UMinus @= + -> Tilde @= + -> Bang @= + -> CastExpression @= // does not conflict with (expr)(arguments) because lower precedence // POSTFIX EXPRESSIONS - -> Expression INC @+ @left_assoc @ainc - -> Expression DEC @= @adec - -> Expression '.' TypeArguments Identifier drop Arguments @= @tmcall - -> Expression drop Arguments @= @mcall - -> Expression '.' Identifier @= @dot_iden - -> Expression '.' NEW drop ClassCreator @= - -> Expression '.' THIS @= - -> Expression '.' SUPER @= - -> Expression '.' CLASS @= - -> Expression '[' drop Expression ']' @= @array_access - -> Expression '::' TypeArguments? Identifier @= - -> Expression '::' TypeArguments? NEW @= + -> AInc @+ @left_assoc @ainc + -> ADec @= @adec + -> DotTypeArgs @= @tmcall + -> Call @= @mcall + -> DotNew @= + -> DotThis @= + -> DotSuper @= + -> DotClass @= + -> DotIden @= @dot_iden + -> ArrayAccess @= @array_access + -> MethodRef @= + -> NewRef @= // POSTFIX TYPES - -> Expression TypeArguments @= - -> Expression '[' ']' @= + -> TypeWithArgs @= + -> ArrayType @= // PRIMARY EXPRESSIONS - -> '(' drop Expression ')' @+ - -> THIS Arguments @= - -> THIS @= - -> SUPER Arguments @= - -> SUPER @= - -> NEW drop ClassCreator @= @ccall - -> NEW drop ArrayCreator @= - -> Identifier @= @iden - -> Literal @= + -> '(' drop Expression ')' @+ + -> ThisCall @= + -> THIS:~this @= + -> SuperCall @= + -> SUPER:~super @= + -> CtorCall @= @ccall + -> ArrayCtorCall @= + -> Identifier:+~identifier @= @iden + -> Literal @= // PRIMARY TYPES -> BasicType @= - -> VOID @= + -> VOID:~void @= ; -ConditionalExpression - = Expression QUERY drop Expression COLON (LambdaExpression / Expression) ; - -CastExpression - = '(' (ReferenceType AdditionalBound* / PrimitiveType) ')' (LambdaExpression / Expression) ; +// =============================================================================== -Assignment - = LValue AssignmentOperator Expression ; +/* + + + :~assignment + -l + + :+-op + -r + + + + ~conditionalExpr + -cond + + -if + + -else + + + :~cast + #types + + -op + + +*/ + +Assignment :~ assignment + = LValue-l AssignmentOperator:+-op Expression-r ; LValue = Expression allow { iden, dot_iden, array_access } ; @@ -1193,8 +1339,139 @@ AssignmentOperator / BSREQU / ANDEQU / HATEQU - / OREQU - ; + / OREQU ; -StatementExpression - = Expression allow { assign, binc, bdec, ainc, adec, mcall, tmcall, ccall } ; \ No newline at end of file +ConditionalExpression :~ conditionalExpr + = Expression-cond QUERY drop Expression-if COLON Expression-else ; + +// NOTE:-first must be reference type or primitive type +// further allowed only w/ reference type and must be class types + +CastExpression :~ cast + = '(' (Type # types) ,+ AND ')' Expression-op; + + +/* + +INFIX + -l + + -r + + +PREFIX + -op + + +:~dotTypeArgs + -op + + + :+-id + + +:~call + -op + + + +:~dotIden + -op + + :+-id + +:~arrayAccess + -op + + -subscript + + +:~methodRef + -op + + + :+-id + +:~newRef + -op + + + +:~typeWithArgs + -op + + + +OTHER SUFFIX + -op + + +:~thisCall + + +:~superCall + + +:~ctorCall + + +:~arrayCtorCall + + +*/ + +OrOr = (Expression-l OROR Expression-r) :~oror ; +AndAnd = (Expression-l ANDAND Expression-r) :~andand ; +Or = (Expression-l OR Expression-r) :~or ; +Hat = (Expression-l HAT Expression-r) :~hat ; +And = (Expression-l AND Expression-r) :~and ; + +Equal = (Expression-l EQUAL Expression-r) :~equal ; +NotEqual = (Expression-l NOTEQUAL Expression-r) :~notEqual ; + +Le = (Expression-l LE Expression-r) :~le ; +Ge = (Expression-l GE Expression-r) :~ge ; +Lt = (Expression-l LT Expression-r) :~lt ; +Gt = (Expression-l GT Expression-r) :~gt ; +InstanceOf = (Expression-l INSTANCEOF Expression-r) :~instanceof ; + +Sl = (Expression-l SL Expression-r) :~sl ; +Sr = (Expression-l SR Expression-r) :~sr ; +Bsr = (Expression-l BSR Expression-r) :~bsr ; + +Plus = (Expression-l PLUS Expression-r) :~plus ; +Minus = (Expression-l MINUS Expression-r) :~minus ; + +Star = (Expression-l STAR Expression-r) :~star ; +Div = (Expression-l DIV Expression-r) :~div ; +Mod = (Expression-l MOD Expression-r) :~mod ; + +BInc = (INC Expression-op) :~bInc ; +BDec = (DEC Expression-op) :~bDec ; +UPlus = (PLUS Expression-op) :~uPlus ; +UMinus = (MINUS Expression-op) :~uMinus ; +Tilde = (TILDE Expression-op) :~tilde ; +Bang = (BANG Expression-op) :~bang ; + +AInc = (Expression-op INC ) :~aInc ; +ADec = (Expression-op DEC ) :~aDec ; +DotTypeArgs = (Expression-op '.' TypeArguments Identifier:+-id drop Arguments ) :~dotTypeArgs ; +Call = (Expression-op drop Arguments ) :~call ; +DotIden = (Expression-op '.' Identifier:+-id ) :~dotIden ; +DotNew = (Expression-op '.' NEW drop ClassCreator ) :~dotNew ; +DotThis = (Expression-op '.' THIS ) :~dotThis ; +DotSuper = (Expression-op '.' SUPER ) :~dotSuper ; +DotClass = (Expression-op '.' CLASS ) :~dotClass ; +ArrayAccess = (Expression-op '[' drop Expression-subscript ']' ) :~arrayAccess ; +MethodRef = (Expression-op '::' TypeArguments? Identifier:+-id ) :~methodRef ; +NewRef = (Expression-op '::' TypeArguments? NEW ) :~newRef ; + +TypeWithArgs = (Expression-op TypeArguments ) :~typeWithArgs ; +ArrayType = (Expression-op '[' ']' ) :~arrayTYpe ; + +ThisCall = (THIS Arguments ) :~thisCall ; +SuperCall = (SUPER Arguments ) :~superCall ; +CtorCall = (NEW drop ClassCreator ) :~ctorCall ; +ArrayCtorCall = (NEW drop ArrayCreator ) :~arrayCtorCall ; + +// =============================================================================== \ No newline at end of file diff --git a/src/com/norswap/autumn/test/grammars/Syntax.test b/src/com/norswap/autumn/test/grammars/Syntax.test new file mode 100644 index 0000000..3ba0e6c --- /dev/null +++ b/src/com/norswap/autumn/test/grammars/Syntax.test @@ -0,0 +1,136 @@ +@A package my.pkg; + +import a.pkg.Class; +import a.pkg.*; +import static a.pkg.Class.MEMBER; +import static a.pkg.Class.*; + +@Annotation1 +@Annotation2(1) +@Annotation3({1, 2, 3}) +@Annotation4(@AnnotationParam) +@Annotation5(x = 1, y = {1, 2, 3}, z = @AnnotationParam) + +public final class Test1 extends Something implements X, Y +{ + static { + functionCall(); + } + + { + functionCall(); + } + + private Class() throws E1, E2 + { + super(); + functionCall(); + } + + public volatile @A int x = 1; + + my.pkg.@A Class1.@A Class2.Class3 y; + + @A int @A [] z = new @A int @A []{ 1, 2 }; + + Object[] u = new Object[]{ o1, o2 }; + + Type v; + + int[][] w = new int[3][]; + + int a, b = 1, c; + + abstract void abstractMethod(); + + void test(final @A int x) throws E1, E2; + + @A public final + Object[] method(Test1 this, int x, Object[] y, Class z, List v, Object... w) + { + { + final @A int x = 1; + functionCall(); + } + + if (true) {} else {} + + while (true) ; + do ; while (true); + for (int i = 0; i < 42; ++i) ; + for (Object x: collection) ; + + label: switch(expr) + { + case A: + case B: + functionCall(); + break; + + case C: + break label; + + default: + functionCall(); + break; + } + + synchronized (expr) {} + + throw new Exception(); + + assert true : "true"; + + ; + + try {} + catch (E1 | E2 e) {} + catch (E3 e) {} + finally {} + + try {} finally {} + try {} catch (E1 e) {} + try (Res e = new Res()) {} + try (Res e = new Res()) {} catch (E1 e) {} finally {} + + x = () -> {}; + x = () -> x; + x = y -> {}; + x = (x, y) -> {}; + + x = i++ * ++i + 1 << 2 & 3 >> 4 ^ 5 >>> 6 | 7 == 8 && 9 != 10 || 11 < 12 || x instanceof Object + ? (Object) thing.method(X.this, X.super, X.class, X.sthingElse, "lit", thing.call(), X::new) + : (x = y[1 + 2]) ; + + return null; + } +} + +enum Test2 +{ + A(1, 2){ void method(){} }, + B(), + C { void method(){} }, + D,; + + Test() {} + + void method() {} +} + +abstract interface Test3 implements X, Y +{ + public void method(); + + default int method2() + { + return 42; + } +} + +@interface Test4 +{ + public int x(); + int y()[] default {1, 2, 3}; + Annotation z() default {x=1, y=2}; +} \ No newline at end of file diff --git a/src/com/norswap/autumn/test/grammars/TestGrammar.java b/src/com/norswap/autumn/test/grammars/TestGrammar.java new file mode 100644 index 0000000..f58a1b2 --- /dev/null +++ b/src/com/norswap/autumn/test/grammars/TestGrammar.java @@ -0,0 +1,33 @@ +package com.norswap.autumn.test.grammars; + +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.ParseResult; + +import java.io.IOException; + +public final class TestGrammar +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + private static String grammarFile = "src/com/norswap/autumn/test/grammars/Java8.autumn"; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static void main(String[] args) throws IOException + { + Grammar grammar = Autumn.grammarFromFile(grammarFile); + + ParseResult result = Autumn.parseFile(grammar, "src/com/norswap/autumn/test/grammars/Syntax.test"); + + if (!result.matched) + { + System.err.println(result.error.message()); + } + + System.err.println(result.tree.toTreeString()); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} + diff --git a/src/com/norswap/autumn/test/mouse/MouseCompiler.java b/src/com/norswap/autumn/test/mouse/MouseCompiler.java deleted file mode 100644 index d7b7845..0000000 --- a/src/com/norswap/autumn/test/mouse/MouseCompiler.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.norswap.autumn.test.mouse; - -import com.norswap.autumn.parsing.ParseTree; -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.util.Streams; - -import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; -import static com.norswap.autumn.util.StringEscape.unescape; - -/** - * Compiles Mouse grammars into parsing expressions. - * Not used for anything, but keeping it around just in case. - * - * Currently, vast overlap with {@link com.norswap.autumn.parsing.support.GrammarCompiler}. - */ -public final class MouseCompiler -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Takes the parse tree obtained from a grammar file, and return an array of parsing - * expressions, corresponding to the grammar rules defined in the grammar. - * - * Note that the references inside these expressions are not resolved. - */ - public ParsingExpression[] compile(ParseTree tree) - { - ParseTree rules = tree.group("rules"); - - return Streams.from(rules) - .map(this::compileRule) - .toArray(ParsingExpression[]::new); - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileRule(ParseTree rule) - { - String ruleName = rule.value("ruleName"); - ParsingExpression topChoice = compileTopChoice(rule.group("alts")); - - return named$(ruleName, topChoice); - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileTopChoice(ParseTree alts) - { - if (alts.childrenCount() == 1) - { - return compileSequence(alts.child().get("sequence")); - } - else - { - return choice(Streams.from(alts) - .map(alt -> compileSequence(alt.get("sequence"))) - .toArray(ParsingExpression[]::new)); - } - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileChoice(ParseTree choice) - { - if (choice.childrenCount() == 1) - { - return compileSequence(choice.child()); - } - else - { - return choice(Streams.from(choice) - .map(alt -> compileSequence(alt)) - .toArray(ParsingExpression[]::new)); - } - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileSequence(ParseTree sequence) - { - if (sequence.childrenCount() == 1) - { - return compilePrefixed(sequence.child()); - } - else - { - return sequence(Streams.from(sequence) - .map(item -> compilePrefixed(item)) - .toArray(ParsingExpression[]::new)); - } - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compilePrefixed(ParseTree prefixed) - { - switch (prefixed.name) - { - case "and": - return lookahead(compileSuffixed(prefixed.child())); - - case "not": - return not(compileSuffixed((prefixed.child()))); - - default: - return compileSuffixed(prefixed); - } - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compileSuffixed(ParseTree suffixed) - { - switch (suffixed.name) - { - case "until": - return until( - compilePrimary(suffixed.child(0)), - compilePrimary(suffixed.child(1))); - - case "aloUntil": - return aloUntil( - compilePrimary(suffixed.child(0)), - compilePrimary(suffixed.child(1))); - - case "optional": - return optional(compilePrimary(suffixed.child())); - - case "zeroMore": - return zeroMore(compilePrimary(suffixed.child())); - - case "oneMore": - return oneMore(compilePrimary(suffixed.child())); - - default: - return compilePrimary(suffixed); - } - } - - // --------------------------------------------------------------------------------------------- - - private ParsingExpression compilePrimary(ParseTree primary) - { - switch (primary.name) - { - case "choice": - return compileChoice(primary); - - case "ref": - return reference(primary.value); - - case "any": - return any(); - - case "charRange": - return charRange( - unescape(primary.value("first")).charAt(0), - unescape(primary.value("last")).charAt(0)); - - case "charSet": - return charSet(unescape(primary.value("charSet"))); - - case "notCharSet": - return notCharSet(unescape(primary.value("notCharSet"))); - - case "stringLit": - return literal(unescape(primary.value("literal"))); - - default: - throw new RuntimeException("Primary expression with no name."); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} - diff --git a/src/com/norswap/autumn/test/mouse/MouseGrammar.java b/src/com/norswap/autumn/test/mouse/MouseGrammar.java deleted file mode 100644 index c4ef4f3..0000000 --- a/src/com/norswap/autumn/test/mouse/MouseGrammar.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.norswap.autumn.test.mouse; - -import com.norswap.autumn.parsing.expressions.common.ParsingExpression; - -import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; - -/** - * A grammar for Mouse grammars. - * Not used for anything, but keeping it around just in case. - * - * Currently, vast overlap with {@link com.norswap.autumn.parsing.support.GrammarGrammar}. - */ -public final class MouseGrammar -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - /* - The original Mouse grammar this is based on. - - Grammar = Space (Rule/Skip)*+ EOF ; - Rule = Name EQUAL RuleRhs DiagName? SEMI ; - Skip = SEMI / _++ (SEMI/EOF) ; - RuleRhs = Sequence Actions (SLASH Sequence Actions)* ; - Choice = Sequence (SLASH Sequence)* ; - Sequence = Prefixed+ ; - Prefixed = PREFIX? Suffixed ; - Suffixed = Primary (UNTIL Primary / SUFFIX)? ; - Primary = Name - / LPAREN Choice RPAREN - / ANY - / StringLit - / Range - / CharClass ; - Actions = OnSucc OnFail ; - OnSucc = (LWING AND? Name? RWING)? ; - OnFail = (TILDA LWING Name? RWING)? ; - Name = Letter (Letter / Digit)* Space ; - DiagName = "<" Char++ ">" Space ; - StringLit = ["] Char++ ["] Space ; - CharClass = ("[" / "^[") Char++ "]" Space ; - Range = "[" Char "-" Char "]" Space ; - Char = Escape / ^[\r\n\\] ; - Escape = "\\u" HexDigit HexDigit HexDigit HexDigit - / "\\t" - / "\\n" - / "\\r" - / !"\\u""\\"_ ; - Letter = [a-z] / [A-Z] ; - Digit = [0-9] ; - HexDigit = [0-9] / [a-f] / [A-F] ; - PREFIX = [&!] Space ; - SUFFIX = [?*+] Space ; - UNTIL = ("*+" / "++") Space ; - EQUAL = "=" Space ; - SEMI = ";" Space ; - SLASH = "/" Space ; - AND = "&" Space ; - LPAREN = "(" Space ; - RPAREN = ")" Space ; - LWING = "{" Space ; - RWING = "}" Space ; - TILDA = "~" Space ; - ANY = "_" Space ; - Space = ([ \r\n\t] / Comment)* ; - Comment = "//" _*+ EOL ; - EOL = [\r]? [\n] / !_ ; - EOF = !_ ; - */ - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static ParsingExpression - - and = token(literal("&")), - bang = token(literal("!")), - equal = token(literal("=")), - plus = token(literal("+")), - qMark = token(literal("?")), - semi = token(literal(";")), - slash = token(literal("/")), - star = token(literal("*")), - tilda = token(literal("_")), - lBrace = token(literal("{")), - rBrace = token(literal("}")), - lParen = token(literal("(")), - rParen = token(literal(")")), - underscore = token(literal("_")), - until = token(literal("*+")), - aloUntil = token(literal("++")), - - EOT = named$("EOT", not(any())), - EOL = named$("EOL", choice(literal("\n"), EOT)), - - comment = named$("comment", sequence(literal("//"), zeroMore(not(EOL), any()), EOL)), - whitespace = named$("whitespace", zeroMore(choice(charSet(" \n\t"), comment))), - - digit = charRange('0', '9'), - hexDigit = choice(digit, charRange('a', 'f'), charRange('A', 'F')), - letter = choice(charRange('a', 'z'), charRange('A', 'Z')), - - escape = named$("escape", choice( - sequence(literal("\\u"), hexDigit, hexDigit, hexDigit, hexDigit), - sequence(literal("\\"), charSet("tnr")), - sequence(not(literal("\\u")), literal("\\"), any()))), - - character = named$("character", choice(escape, notCharSet("\n\\"))), - - range = named$("range", token( - literal("["), - captureText("first", character), - literal("-"), - captureText("last", character), - literal("]"))), - - charSet = named$("charSet", token( - literal("["), - captureText("charSet", oneMore(not(literal("]")), character)), - literal("]"))), - - notCharSet = named$("notCharSet", token( - literal("^["), - captureText("notCharSet", oneMore(not(literal("]"), character))), - literal("]"))), - - stringLit = named$("stringLit", token( - literal("\""), - captureText("literal", oneMore(not(literal("\"")), character)), - literal("\""))), - - diagName = named$("diagName", token(literal("<"), until(character, literal(">")))), - name = named$("name", token(letter, zeroMore(choice(letter, digit)))), - - onFail = named$("onFail", capture("onFail", sequence( - tilda, - lBrace, - optional(capture("name", name)), - rBrace))), - - onSucc = named$("onSucc", capture("onSucc", sequence( - lBrace, - optional(capture("boolean", and)), - optional(capture("name", name)), - rBrace))), - - primary = named$("primary", choice( - sequence(lParen, reference("choice"), rParen), - captureText("ref", name), - capture("any", underscore), - capture("charRange", range), - captureText("stringLit", stringLit), - captureText("charSet", charSet), - captureText("notCharSet", notCharSet))), - - suffixed = named$("suffixed", choice( - capture("until", sequence(primary, until, primary)), - capture("aloUntil", sequence(primary, aloUntil, primary)), - capture("optional", sequence(primary, qMark)), - capture("zeroMore", sequence(primary, star)), - capture("oneMore", sequence(primary, plus)), - primary)), - - prefixed = named$("prefixed", choice( - capture("and", sequence(and, suffixed)), - capture("not", sequence(bang, suffixed)), - suffixed)), - - sequence = named$("sequence", capture("sequence", oneMore(prefixed))), - choice = recursive$("choice", capture("choice", aloSeparated(sequence, slash))), - - ruleRhs = named$("ruleRhs", aloSeparated( - captureGrouped("alts", sequence(sequence, optional(onSucc), optional(onFail))), - slash)), - - rule = named$("rule", - sequence(captureText("ruleName", name), equal, ruleRhs, optional(diagName), semi)), - - grammar = named$("grammar", - sequence(whitespace(), aloUntil(captureGrouped("rules", rule), EOT))) - - ; - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/test/mouse/MouseJava8Parser.java b/src/com/norswap/autumn/test/mouse/MouseJava8Parser.java index 8433b4c..bfe783f 100644 --- a/src/com/norswap/autumn/test/mouse/MouseJava8Parser.java +++ b/src/com/norswap/autumn/test/mouse/MouseJava8Parser.java @@ -5130,3 +5130,5140 @@ private boolean ConstantExpression() } +////========================================================================= +//// +//// This file was generated by Mouse 1.7 at 2015-08-22 14:17:32 GMT +//// from grammar +//// 'C:\Users\norswap\Desktop\Mouse-1.7\grammars\Java.1.8.peg'. +//// +////========================================================================= +// +//package com.norswap.autumn.test.mouse; +// +// import mouse.runtime.Source; +// +//public class MouseJava8Parser extends mouse.runtime.ParserBase +//{ +// final mouse.runtime.SemanticsBase sem; +// +// //======================================================================= +// // +// // Initialization +// // +// //======================================================================= +// //------------------------------------------------------------------- +// // Constructor +// //------------------------------------------------------------------- +// public MouseJava8Parser() +// { +// sem = new mouse.runtime.SemanticsBase(); +// sem.rule = this; +// super.sem = sem; +// } +// +// //------------------------------------------------------------------- +// // Run the parser +// //------------------------------------------------------------------- +// public boolean parse(Source src) +// { +// super.init(src); +// sem.init(); +// boolean result = Compilation(); +// closeParser(result); +// return result; +// } +// +// //------------------------------------------------------------------- +// // Get semantics +// //------------------------------------------------------------------- +// public mouse.runtime.SemanticsBase semantics() +// { return sem; } +// +// //======================================================================= +// // +// // Parsing procedures +// // +// //======================================================================= +// //===================================================================== +// // Compilation = Spacing CompilationUnit SUB? EOT ; +// //===================================================================== +// private boolean Compilation() +// { +// begin("Compilation"); +// Spacing(); +// CompilationUnit(); +// SUB(); +// if (!EOT()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // SUB = "\u001a" ; +// //===================================================================== +// private boolean SUB() +// { +// begin("SUB"); +// if (!next('\u001a')) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // EOT = !_ ; +// //===================================================================== +// private boolean EOT() +// { +// begin("EOT"); +// if (!aheadNot()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Spacing = ([ \t\r\n\f]+ / "/*" _*+ "*/" / "//" _*+ [\r\n])* ; +// //===================================================================== +// private boolean Spacing() +// { +// begin("Spacing"); +// while (Spacing_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // Spacing_0 = [ \t\r\n\f]+ / "/*" _*+ "*/" / "//" _*+ [\r\n] +// //------------------------------------------------------------------- +// private boolean Spacing_0() +// { +// begin(""); +// if (Spacing_1()) return acceptInner(); +// if (Spacing_2()) return acceptInner(); +// if (Spacing_3()) return acceptInner(); +// return rejectInner(); +// } +// +// //------------------------------------------------------------------- +// // Spacing_1 = [ \t\r\n\f]+ +// //------------------------------------------------------------------- +// private boolean Spacing_1() +// { +// begin(""); +// if (!nextIn(" \t\r\n\f")) return rejectInner(); +// while (nextIn(" \t\r\n\f")); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Spacing_2 = "/*" _*+ "*/" +// //------------------------------------------------------------------- +// private boolean Spacing_2() +// { +// begin(""); +// if (!next("/*")) return rejectInner(); +// while (!next("*/")) +// if (!next()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Spacing_3 = "//" _*+ [\r\n] +// //------------------------------------------------------------------- +// private boolean Spacing_3() +// { +// begin(""); +// if (!next("//")) return rejectInner(); +// while (!nextIn("\r\n")) +// if (!next()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Identifier = !Keyword Letter LetterOrDigit* Spacing ; +// //===================================================================== +// private boolean Identifier() +// { +// begin("Identifier"); +// if (!Identifier_0()) return reject(); +// if (!Letter()) return reject(); +// while (LetterOrDigit()); +// Spacing(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // Identifier_0 = !Keyword +// //------------------------------------------------------------------- +// private boolean Identifier_0() +// { +// begin("","not Keyword"); +// if (Keyword()) return rejectPred(); +// return acceptPred(); +// } +// +// //===================================================================== +// // Letter = [a-z] / [A-Z] / [_$] ; +// //===================================================================== +// private boolean Letter() +// { +// begin("Letter"); +// if (nextIn('a','z')) return accept(); +// if (nextIn('A','Z')) return accept(); +// if (nextIn("_$")) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // LetterOrDigit = [a-z] / [A-Z] / [0-9] / [_$] ; +// //===================================================================== +// private boolean LetterOrDigit() +// { +// begin("LetterOrDigit"); +// if (nextIn('a','z')) return accept(); +// if (nextIn('A','Z')) return accept(); +// if (nextIn('0','9')) return accept(); +// if (nextIn("_$")) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // Keyword = ("abstract" / "assert" / "boolean" / "break" / "byte" / +// // "case" / "catch" / "char" / "class" / "const" / "continue" / +// // "default" / "double" / "do" / "else" / "enum" / "extends" / +// // "false" / "finally" / "final" / "float" / "for" / "goto" / "if" / +// // "implements" / "import" / "interface" / "int" / "instanceof" / +// // "long" / "native" / "new" / "null" / "package" / "private" / +// // "protected" / "public" / "return" / "short" / "static" / +// // "strictfp" / "super" / "switch" / "synchronized" / "this" / +// // "throws" / "throw" / "transient" / "true" / "try" / "void" / +// // "volatile" / "while") !LetterOrDigit ; +// //===================================================================== +// private boolean Keyword() +// { +// begin("Keyword"); +// if (!next("abstract") +// && !next("assert") +// && !next("boolean") +// && !next("break") +// && !next("byte") +// && !next("case") +// && !next("catch") +// && !next("char") +// && !next("class") +// && !next("const") +// && !next("continue") +// && !next("default") +// && !next("double") +// && !next("do") +// && !next("else") +// && !next("enum") +// && !next("extends") +// && !next("false") +// && !next("finally") +// && !next("final") +// && !next("float") +// && !next("for") +// && !next("goto") +// && !next("if") +// && !next("implements") +// && !next("import") +// && !next("interface") +// && !next("int") +// && !next("instanceof") +// && !next("long") +// && !next("native") +// && !next("new") +// && !next("null") +// && !next("package") +// && !next("private") +// && !next("protected") +// && !next("public") +// && !next("return") +// && !next("short") +// && !next("static") +// && !next("strictfp") +// && !next("super") +// && !next("switch") +// && !next("synchronized") +// && !next("this") +// && !next("throws") +// && !next("throw") +// && !next("transient") +// && !next("true") +// && !next("try") +// && !next("void") +// && !next("volatile") +// && !next("while") +// ) return reject(); +// if (!Keyword_0()) return reject(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // Keyword_0 = !LetterOrDigit +// //------------------------------------------------------------------- +// private boolean Keyword_0() +// { +// begin("","not LetterOrDigit"); +// if (LetterOrDigit()) return rejectPred(); +// return acceptPred(); +// } +// +// //===================================================================== +// // ABSTRACT = "abstract" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean ABSTRACT() +// { +// begin("ABSTRACT"); +// if (!next("abstract")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ASSERT = "assert" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean ASSERT() +// { +// begin("ASSERT"); +// if (!next("assert")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BOOLEAN = "boolean" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean BOOLEAN() +// { +// begin("BOOLEAN"); +// if (!next("boolean")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BREAK = "break" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean BREAK() +// { +// begin("BREAK"); +// if (!next("break")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BYTE = "byte" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean BYTE() +// { +// begin("BYTE"); +// if (!next("byte")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // CASE = "case" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean CASE() +// { +// begin("CASE"); +// if (!next("case")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // CATCH = "catch" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean CATCH() +// { +// begin("CATCH"); +// if (!next("catch")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // CHAR = "char" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean CHAR() +// { +// begin("CHAR"); +// if (!next("char")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // CLASS = "class" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean CLASS() +// { +// begin("CLASS"); +// if (!next("class")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // CONTINUE = "continue" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean CONTINUE() +// { +// begin("CONTINUE"); +// if (!next("continue")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DEFAULT = "default" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean DEFAULT() +// { +// begin("DEFAULT"); +// if (!next("default")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DOUBLE = "double" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean DOUBLE() +// { +// begin("DOUBLE"); +// if (!next("double")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DO = "do" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean DO() +// { +// begin("DO"); +// if (!next("do")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ELSE = "else" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean ELSE() +// { +// begin("ELSE"); +// if (!next("else")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ENUM = "enum" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean ENUM() +// { +// begin("ENUM"); +// if (!next("enum")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // EXTENDS = "extends" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean EXTENDS() +// { +// begin("EXTENDS"); +// if (!next("extends")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // FALSE = "false" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean FALSE() +// { +// begin("FALSE"); +// if (!next("false")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // FINALLY = "finally" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean FINALLY() +// { +// begin("FINALLY"); +// if (!next("finally")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // FINAL = "final" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean FINAL() +// { +// begin("FINAL"); +// if (!next("final")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // FLOAT = "float" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean FLOAT() +// { +// begin("FLOAT"); +// if (!next("float")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // FOR = "for" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean FOR() +// { +// begin("FOR"); +// if (!next("for")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // IF = "if" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean IF() +// { +// begin("IF"); +// if (!next("if")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // IMPLEMENTS = "implements" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean IMPLEMENTS() +// { +// begin("IMPLEMENTS"); +// if (!next("implements")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // IMPORT = "import" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean IMPORT() +// { +// begin("IMPORT"); +// if (!next("import")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // INTERFACE = "interface" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean INTERFACE() +// { +// begin("INTERFACE"); +// if (!next("interface")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // INT = "int" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean INT() +// { +// begin("INT"); +// if (!next("int")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // INSTANCEOF = "instanceof" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean INSTANCEOF() +// { +// begin("INSTANCEOF"); +// if (!next("instanceof")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LONG = "long" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean LONG() +// { +// begin("LONG"); +// if (!next("long")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // NATIVE = "native" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean NATIVE() +// { +// begin("NATIVE"); +// if (!next("native")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // NEW = "new" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean NEW() +// { +// begin("NEW"); +// if (!next("new")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // NULL = "null" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean NULL() +// { +// begin("NULL"); +// if (!next("null")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PACKAGE = "package" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean PACKAGE() +// { +// begin("PACKAGE"); +// if (!next("package")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PRIVATE = "private" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean PRIVATE() +// { +// begin("PRIVATE"); +// if (!next("private")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PROTECTED = "protected" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean PROTECTED() +// { +// begin("PROTECTED"); +// if (!next("protected")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PUBLIC = "public" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean PUBLIC() +// { +// begin("PUBLIC"); +// if (!next("public")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // RETURN = "return" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean RETURN() +// { +// begin("RETURN"); +// if (!next("return")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SHORT = "short" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean SHORT() +// { +// begin("SHORT"); +// if (!next("short")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // STATIC = "static" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean STATIC() +// { +// begin("STATIC"); +// if (!next("static")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // STRICTFP = "strictfp" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean STRICTFP() +// { +// begin("STRICTFP"); +// if (!next("strictfp")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SUPER = "super" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean SUPER() +// { +// begin("SUPER"); +// if (!next("super")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SWITCH = "switch" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean SWITCH() +// { +// begin("SWITCH"); +// if (!next("switch")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SYNCHRONIZED = "synchronized" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean SYNCHRONIZED() +// { +// begin("SYNCHRONIZED"); +// if (!next("synchronized")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // THIS = "this" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean THIS() +// { +// begin("THIS"); +// if (!next("this")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // THROWS = "throws" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean THROWS() +// { +// begin("THROWS"); +// if (!next("throws")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // THROW = "throw" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean THROW() +// { +// begin("THROW"); +// if (!next("throw")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // TRANSIENT = "transient" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean TRANSIENT() +// { +// begin("TRANSIENT"); +// if (!next("transient")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // TRUE = "true" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean TRUE() +// { +// begin("TRUE"); +// if (!next("true")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // TRY = "try" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean TRY() +// { +// begin("TRY"); +// if (!next("try")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // VOID = "void" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean VOID() +// { +// begin("VOID"); +// if (!next("void")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // VOLATILE = "volatile" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean VOLATILE() +// { +// begin("VOLATILE"); +// if (!next("volatile")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // WHILE = "while" !LetterOrDigit Spacing ; +// //===================================================================== +// private boolean WHILE() +// { +// begin("WHILE"); +// if (!next("while")) return reject(); +// if (!Keyword_0()) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // Literal = FloatLiteral / IntegerLiteral / BooleanLiteral / +// // CharLiteral / StringLiteral / NullLiteral ; +// //===================================================================== +// private boolean Literal() +// { +// begin("Literal"); +// if (FloatLiteral()) return accept(); +// if (IntegerLiteral()) return accept(); +// if (BooleanLiteral()) return accept(); +// if (CharLiteral()) return accept(); +// if (StringLiteral()) return accept(); +// if (NullLiteral()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // IntegerLiteral = (HexNumeral / BinaryNumeral / OctalNumeral / +// // DecimalNumeral) [lL]? Spacing ; +// //===================================================================== +// private boolean IntegerLiteral() +// { +// begin("IntegerLiteral"); +// if (!HexNumeral() +// && !BinaryNumeral() +// && !OctalNumeral() +// && !DecimalNumeral() +// ) return reject(); +// nextIn("lL"); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DecimalNumeral = "0" / [1-9] ([_]* [0-9])* ; +// //===================================================================== +// private boolean DecimalNumeral() +// { +// begin("DecimalNumeral"); +// if (next('0')) return accept(); +// if (DecimalNumeral_0()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // DecimalNumeral_0 = [1-9] ([_]* [0-9])* +// //------------------------------------------------------------------- +// private boolean DecimalNumeral_0() +// { +// begin(""); +// if (!nextIn('1','9')) return rejectInner(); +// while (DecimalNumeral_1()); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // DecimalNumeral_1 = [_]* [0-9] +// //------------------------------------------------------------------- +// private boolean DecimalNumeral_1() +// { +// begin(""); +// while (next('_')); +// if (!nextIn('0','9')) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // HexNumeral = ("0x" / "0X") HexDigits ; +// //===================================================================== +// private boolean HexNumeral() +// { +// begin("HexNumeral"); +// if (!next("0x") +// && !next("0X") +// ) return reject(); +// if (!HexDigits()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // OctalNumeral = "0" ([_]* [0-7])+ ; +// //===================================================================== +// private boolean OctalNumeral() +// { +// begin("OctalNumeral"); +// if (!next('0')) return reject(); +// if (!OctalNumeral_0()) return reject(); +// while (OctalNumeral_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // OctalNumeral_0 = [_]* [0-7] +// //------------------------------------------------------------------- +// private boolean OctalNumeral_0() +// { +// begin(""); +// while (next('_')); +// if (!nextIn('0','7')) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // BinaryNumeral = ("0b" / "0B") [01] ([_]* [01])* ; +// //===================================================================== +// private boolean BinaryNumeral() +// { +// begin("BinaryNumeral"); +// if (!next("0b") +// && !next("0B") +// ) return reject(); +// if (!nextIn("01")) return reject(); +// while (BinaryNumeral_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // BinaryNumeral_0 = [_]* [01] +// //------------------------------------------------------------------- +// private boolean BinaryNumeral_0() +// { +// begin(""); +// while (next('_')); +// if (!nextIn("01")) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // FloatLiteral = (HexadecimalFloatingPointLiteral / +// // DecimalFloatingPointLiteral) Spacing ; +// //===================================================================== +// private boolean FloatLiteral() +// { +// begin("FloatLiteral"); +// if (!HexadecimalFloatingPointLiteral() +// && !DecimalFloatingPointLiteral() +// ) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DecimalFloatingPointLiteral = Digits "." Digits? Exponent? [fFdD]? +// // / "." Digits Exponent? [fFdD]? / Digits Exponent [fFdD]? / Digits +// // Exponent? [fFdD] ; +// //===================================================================== +// private boolean DecimalFloatingPointLiteral() +// { +// begin("DecimalFloatingPointLiteral"); +// if (DecimalFloatingPointLiteral_0()) return accept(); +// if (DecimalFloatingPointLiteral_1()) return accept(); +// if (DecimalFloatingPointLiteral_2()) return accept(); +// if (DecimalFloatingPointLiteral_3()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // DecimalFloatingPointLiteral_0 = Digits "." Digits? Exponent? +// // [fFdD]? +// //------------------------------------------------------------------- +// private boolean DecimalFloatingPointLiteral_0() +// { +// begin(""); +// if (!Digits()) return rejectInner(); +// if (!next('.')) return rejectInner(); +// Digits(); +// Exponent(); +// nextIn("fFdD"); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // DecimalFloatingPointLiteral_1 = "." Digits Exponent? [fFdD]? +// //------------------------------------------------------------------- +// private boolean DecimalFloatingPointLiteral_1() +// { +// begin(""); +// if (!next('.')) return rejectInner(); +// if (!Digits()) return rejectInner(); +// Exponent(); +// nextIn("fFdD"); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // DecimalFloatingPointLiteral_2 = Digits Exponent [fFdD]? +// //------------------------------------------------------------------- +// private boolean DecimalFloatingPointLiteral_2() +// { +// begin(""); +// if (!Digits()) return rejectInner(); +// if (!Exponent()) return rejectInner(); +// nextIn("fFdD"); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // DecimalFloatingPointLiteral_3 = Digits Exponent? [fFdD] +// //------------------------------------------------------------------- +// private boolean DecimalFloatingPointLiteral_3() +// { +// begin(""); +// if (!Digits()) return rejectInner(); +// Exponent(); +// if (!nextIn("fFdD")) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Exponent = [eE] [+-]? Digits ; +// //===================================================================== +// private boolean Exponent() +// { +// begin("Exponent"); +// if (!nextIn("eE")) return reject(); +// nextIn("+-"); +// if (!Digits()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // HexadecimalFloatingPointLiteral = HexSignificand BinaryExponent +// // [fFdD]? ; +// //===================================================================== +// private boolean HexadecimalFloatingPointLiteral() +// { +// begin("HexadecimalFloatingPointLiteral"); +// if (!HexSignificand()) return reject(); +// if (!BinaryExponent()) return reject(); +// nextIn("fFdD"); +// return accept(); +// } +// +// //===================================================================== +// // HexSignificand = ("0x" / "0X") HexDigits? "." HexDigits / +// // HexNumeral "."? ; +// //===================================================================== +// private boolean HexSignificand() +// { +// begin("HexSignificand"); +// if (HexSignificand_0()) return accept(); +// if (HexSignificand_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // HexSignificand_0 = ("0x" / "0X") HexDigits? "." HexDigits +// //------------------------------------------------------------------- +// private boolean HexSignificand_0() +// { +// begin(""); +// if (!next("0x") +// && !next("0X") +// ) return rejectInner(); +// HexDigits(); +// if (!next('.')) return rejectInner(); +// if (!HexDigits()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // HexSignificand_1 = HexNumeral "."? +// //------------------------------------------------------------------- +// private boolean HexSignificand_1() +// { +// begin(""); +// if (!HexNumeral()) return rejectInner(); +// next('.'); +// return acceptInner(); +// } +// +// //===================================================================== +// // HexDigits = HexDigit ([_]* HexDigit)* ; +// //===================================================================== +// private boolean HexDigits() +// { +// begin("HexDigits"); +// if (!HexDigit()) return reject(); +// while (HexDigits_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // HexDigits_0 = [_]* HexDigit +// //------------------------------------------------------------------- +// private boolean HexDigits_0() +// { +// begin(""); +// while (next('_')); +// if (!HexDigit()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // HexDigit = [a-f] / [A-F] / [0-9] ; +// //===================================================================== +// private boolean HexDigit() +// { +// begin("HexDigit"); +// if (nextIn('a','f')) return accept(); +// if (nextIn('A','F')) return accept(); +// if (nextIn('0','9')) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // BinaryExponent = [pP] [+-]? Digits ; +// //===================================================================== +// private boolean BinaryExponent() +// { +// begin("BinaryExponent"); +// if (!nextIn("pP")) return reject(); +// nextIn("+-"); +// if (!Digits()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Digits = [0-9] ([_]* [0-9])* ; +// //===================================================================== +// private boolean Digits() +// { +// begin("Digits"); +// if (!nextIn('0','9')) return reject(); +// while (DecimalNumeral_1()); +// return accept(); +// } +// +// //===================================================================== +// // BooleanLiteral = TRUE / FALSE ; +// //===================================================================== +// private boolean BooleanLiteral() +// { +// begin("BooleanLiteral"); +// if (TRUE()) return accept(); +// if (FALSE()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // CharLiteral = "'" (Escape / !['\\n\r] _) "'" Spacing ; +// //===================================================================== +// private boolean CharLiteral() +// { +// begin("CharLiteral"); +// if (!next('\'')) return reject(); +// if (!Escape() +// && !CharLiteral_0() +// ) return reject(); +// if (!next('\'')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // CharLiteral_0 = !['\\n\r] _ +// //------------------------------------------------------------------- +// private boolean CharLiteral_0() +// { +// begin(""); +// if (!aheadNotIn("'\\\n\r")) return rejectInner(); +// if (!next()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // StringLiteral = """ (Escape / !["\\n\r] _)* """ Spacing ; +// //===================================================================== +// private boolean StringLiteral() +// { +// begin("StringLiteral"); +// if (!next('"')) return reject(); +// while (StringLiteral_0()); +// if (!next('"')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // StringLiteral_0 = Escape / !["\\n\r] _ +// //------------------------------------------------------------------- +// private boolean StringLiteral_0() +// { +// begin(""); +// if (Escape()) return acceptInner(); +// if (StringLiteral_1()) return acceptInner(); +// return rejectInner(); +// } +// +// //------------------------------------------------------------------- +// // StringLiteral_1 = !["\\n\r] _ +// //------------------------------------------------------------------- +// private boolean StringLiteral_1() +// { +// begin(""); +// if (!aheadNotIn("\"\\\n\r")) return rejectInner(); +// if (!next()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Escape = "\" ([btnfr"'\] / OctalEscape / UnicodeEscape) ; +// //===================================================================== +// private boolean Escape() +// { +// begin("Escape"); +// if (!next('\\')) return reject(); +// if (!nextIn("btnfr\"'\\") +// && !OctalEscape() +// && !UnicodeEscape() +// ) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // OctalEscape = [0-3] [0-7] [0-7] / [0-7] [0-7] / [0-7] ; +// //===================================================================== +// private boolean OctalEscape() +// { +// begin("OctalEscape"); +// if (OctalEscape_0()) return accept(); +// if (OctalEscape_1()) return accept(); +// if (nextIn('0','7')) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // OctalEscape_0 = [0-3] [0-7] [0-7] +// //------------------------------------------------------------------- +// private boolean OctalEscape_0() +// { +// begin(""); +// if (!nextIn('0','3')) return rejectInner(); +// if (!nextIn('0','7')) return rejectInner(); +// if (!nextIn('0','7')) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // OctalEscape_1 = [0-7] [0-7] +// //------------------------------------------------------------------- +// private boolean OctalEscape_1() +// { +// begin(""); +// if (!nextIn('0','7')) return rejectInner(); +// if (!nextIn('0','7')) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // UnicodeEscape = "u"+ HexDigit HexDigit HexDigit HexDigit ; +// //===================================================================== +// private boolean UnicodeEscape() +// { +// begin("UnicodeEscape"); +// if (!next('u')) return reject(); +// while (next('u')); +// if (!HexDigit()) return reject(); +// if (!HexDigit()) return reject(); +// if (!HexDigit()) return reject(); +// if (!HexDigit()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // NullLiteral = NULL ; +// //===================================================================== +// private boolean NullLiteral() +// { +// begin("NullLiteral"); +// if (!NULL()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // AT = "@" Spacing ; +// //===================================================================== +// private boolean AT() +// { +// begin("AT"); +// if (!next('@')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // COLONCOLON = "::" Spacing ; +// //===================================================================== +// private boolean COLONCOLON() +// { +// begin("COLONCOLON"); +// if (!next("::")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // COMMA = "," Spacing ; +// //===================================================================== +// private boolean COMMA() +// { +// begin("COMMA"); +// if (!next(',')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DOT = "." Spacing ; +// //===================================================================== +// private boolean DOT() +// { +// begin("DOT"); +// if (!next('.')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ELLIPSIS = "..." Spacing ; +// //===================================================================== +// private boolean ELLIPSIS() +// { +// begin("ELLIPSIS"); +// if (!next("...")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LPAR = "(" Spacing ; +// //===================================================================== +// private boolean LPAR() +// { +// begin("LPAR"); +// if (!next('(')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LBRK = "[" Spacing ; +// //===================================================================== +// private boolean LBRK() +// { +// begin("LBRK"); +// if (!next('[')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // RBRK = "]" Spacing ; +// //===================================================================== +// private boolean RBRK() +// { +// begin("RBRK"); +// if (!next(']')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // RPAR = ")" Spacing ; +// //===================================================================== +// private boolean RPAR() +// { +// begin("RPAR"); +// if (!next(')')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LWING = "{" Spacing ; +// //===================================================================== +// private boolean LWING() +// { +// begin("LWING"); +// if (!next('{')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // RWING = "}" Spacing ; +// //===================================================================== +// private boolean RWING() +// { +// begin("RWING"); +// if (!next('}')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SEMI = ";" Spacing ; +// //===================================================================== +// private boolean SEMI() +// { +// begin("SEMI"); +// if (!next(';')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // AND = "&" ![=&] Spacing ; +// //===================================================================== +// private boolean AND() +// { +// begin("AND"); +// if (!next('&')) return reject(); +// if (!aheadNotIn("=&")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ANDAND = "&&" Spacing ; +// //===================================================================== +// private boolean ANDAND() +// { +// begin("ANDAND"); +// if (!next("&&")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ANDEQU = "&=" Spacing ; +// //===================================================================== +// private boolean ANDEQU() +// { +// begin("ANDEQU"); +// if (!next("&=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // ARROW = "->" Spacing ; +// //===================================================================== +// private boolean ARROW() +// { +// begin("ARROW"); +// if (!next("->")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BANG = "!" ![=] Spacing ; +// //===================================================================== +// private boolean BANG() +// { +// begin("BANG"); +// if (!next('!')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BSR = ">>>" ![=] Spacing ; +// //===================================================================== +// private boolean BSR() +// { +// begin("BSR"); +// if (!next(">>>")) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BSREQU = ">>>=" Spacing ; +// //===================================================================== +// private boolean BSREQU() +// { +// begin("BSREQU"); +// if (!next(">>>=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // COLON = ":" ![:] Spacing ; +// //===================================================================== +// private boolean COLON() +// { +// begin("COLON"); +// if (!next(':')) return reject(); +// if (!aheadNot(':')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DEC = "--" Spacing ; +// //===================================================================== +// private boolean DEC() +// { +// begin("DEC"); +// if (!next("--")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DIV = "/" ![=] Spacing ; +// //===================================================================== +// private boolean DIV() +// { +// begin("DIV"); +// if (!next('/')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // DIVEQU = "/=" Spacing ; +// //===================================================================== +// private boolean DIVEQU() +// { +// begin("DIVEQU"); +// if (!next("/=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // EQU = "=" ![=] Spacing ; +// //===================================================================== +// private boolean EQU() +// { +// begin("EQU"); +// if (!next('=')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // EQUAL = "==" Spacing ; +// //===================================================================== +// private boolean EQUAL() +// { +// begin("EQUAL"); +// if (!next("==")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // GE = ">=" Spacing ; +// //===================================================================== +// private boolean GE() +// { +// begin("GE"); +// if (!next(">=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // GT = ">" ![=>] Spacing ; +// //===================================================================== +// private boolean GT() +// { +// begin("GT"); +// if (!next('>')) return reject(); +// if (!aheadNotIn("=>")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // HAT = "^" ![=] Spacing ; +// //===================================================================== +// private boolean HAT() +// { +// begin("HAT"); +// if (!next('^')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // HATEQU = "^=" Spacing ; +// //===================================================================== +// private boolean HATEQU() +// { +// begin("HATEQU"); +// if (!next("^=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // INC = "++" Spacing ; +// //===================================================================== +// private boolean INC() +// { +// begin("INC"); +// if (!next("++")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LE = "<=" Spacing ; +// //===================================================================== +// private boolean LE() +// { +// begin("LE"); +// if (!next("<=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LPOINT = "<" Spacing ; +// //===================================================================== +// private boolean LPOINT() +// { +// begin("LPOINT"); +// if (!next('<')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // LT = "<" ![=<] Spacing ; +// //===================================================================== +// private boolean LT() +// { +// begin("LT"); +// if (!next('<')) return reject(); +// if (!aheadNotIn("=<")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // MINUS = "-" ![=->] Spacing ; +// //===================================================================== +// private boolean MINUS() +// { +// begin("MINUS"); +// if (!next('-')) return reject(); +// if (!aheadNotIn("=->")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // MINUSEQU = "-=" Spacing ; +// //===================================================================== +// private boolean MINUSEQU() +// { +// begin("MINUSEQU"); +// if (!next("-=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // MOD = "%" ![=] Spacing ; +// //===================================================================== +// private boolean MOD() +// { +// begin("MOD"); +// if (!next('%')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // MODEQU = "%=" Spacing ; +// //===================================================================== +// private boolean MODEQU() +// { +// begin("MODEQU"); +// if (!next("%=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // NOTEQUAL = "!=" Spacing ; +// //===================================================================== +// private boolean NOTEQUAL() +// { +// begin("NOTEQUAL"); +// if (!next("!=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // OR = "|" ![=|] Spacing ; +// //===================================================================== +// private boolean OR() +// { +// begin("OR"); +// if (!next('|')) return reject(); +// if (!aheadNotIn("=|")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // OREQU = "|=" Spacing ; +// //===================================================================== +// private boolean OREQU() +// { +// begin("OREQU"); +// if (!next("|=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // OROR = "||" Spacing ; +// //===================================================================== +// private boolean OROR() +// { +// begin("OROR"); +// if (!next("||")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PLUS = "+" ![=+] Spacing ; +// //===================================================================== +// private boolean PLUS() +// { +// begin("PLUS"); +// if (!next('+')) return reject(); +// if (!aheadNotIn("=+")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // PLUSEQU = "+=" Spacing ; +// //===================================================================== +// private boolean PLUSEQU() +// { +// begin("PLUSEQU"); +// if (!next("+=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // QUERY = "?" Spacing ; +// //===================================================================== +// private boolean QUERY() +// { +// begin("QUERY"); +// if (!next('?')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // RPOINT = ">" Spacing ; +// //===================================================================== +// private boolean RPOINT() +// { +// begin("RPOINT"); +// if (!next('>')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SL = "<<" ![=] Spacing ; +// //===================================================================== +// private boolean SL() +// { +// begin("SL"); +// if (!next("<<")) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SLEQU = "<<=" Spacing ; +// //===================================================================== +// private boolean SLEQU() +// { +// begin("SLEQU"); +// if (!next("<<=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SR = ">>" ![=>] Spacing ; +// //===================================================================== +// private boolean SR() +// { +// begin("SR"); +// if (!next(">>")) return reject(); +// if (!aheadNotIn("=>")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // SREQU = ">>=" Spacing ; +// //===================================================================== +// private boolean SREQU() +// { +// begin("SREQU"); +// if (!next(">>=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // STAR = "*" ![=] Spacing ; +// //===================================================================== +// private boolean STAR() +// { +// begin("STAR"); +// if (!next('*')) return reject(); +// if (!aheadNot('=')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // STAREQU = "*=" Spacing ; +// //===================================================================== +// private boolean STAREQU() +// { +// begin("STAREQU"); +// if (!next("*=")) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // TILDE = "~" Spacing ; +// //===================================================================== +// private boolean TILDE() +// { +// begin("TILDE"); +// if (!next('~')) return reject(); +// Spacing(); +// return accept(); +// } +// +// //===================================================================== +// // BasicType = BYTE / SHORT / INT / LONG / CHAR / FLOAT / DOUBLE / +// // BOOLEAN ; +// //===================================================================== +// private boolean BasicType() +// { +// begin("BasicType"); +// if (BYTE()) return accept(); +// if (SHORT()) return accept(); +// if (INT()) return accept(); +// if (LONG()) return accept(); +// if (CHAR()) return accept(); +// if (FLOAT()) return accept(); +// if (DOUBLE()) return accept(); +// if (BOOLEAN()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // PrimitiveType = Annotation* BasicType ; +// //===================================================================== +// private boolean PrimitiveType() +// { +// begin("PrimitiveType"); +// while (Annotation()); +// if (!BasicType()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ReferenceType = PrimitiveType Dim+ / ClassType Dim* ; +// //===================================================================== +// private boolean ReferenceType() +// { +// begin("ReferenceType"); +// if (ReferenceType_0()) return accept(); +// if (ReferenceType_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // ReferenceType_0 = PrimitiveType Dim+ +// //------------------------------------------------------------------- +// private boolean ReferenceType_0() +// { +// begin(""); +// if (!PrimitiveType()) return rejectInner(); +// if (!Dim()) return rejectInner(); +// while (Dim()); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ReferenceType_1 = ClassType Dim* +// //------------------------------------------------------------------- +// private boolean ReferenceType_1() +// { +// begin(""); +// if (!ClassType()) return rejectInner(); +// while (Dim()); +// return acceptInner(); +// } +// +// //===================================================================== +// // ClassType = Annotation* Identifier TypeArguments? (DOT Annotation* +// // Identifier TypeArguments?)* ; +// //===================================================================== +// private boolean ClassType() +// { +// begin("ClassType"); +// while (Annotation()); +// if (!Identifier()) return reject(); +// TypeArguments(); +// while (ClassType_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ClassType_0 = DOT Annotation* Identifier TypeArguments? +// //------------------------------------------------------------------- +// private boolean ClassType_0() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// while (Annotation()); +// if (!Identifier()) return rejectInner(); +// TypeArguments(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Type = PrimitiveType / ClassType ; +// //===================================================================== +// private boolean Type() +// { +// begin("Type"); +// if (PrimitiveType()) return accept(); +// if (ClassType()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ArrayType = PrimitiveType Dim+ / ClassType Dim+ ; +// //===================================================================== +// private boolean ArrayType() +// { +// begin("ArrayType"); +// if (ReferenceType_0()) return accept(); +// if (ArrayType_0()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // ArrayType_0 = ClassType Dim+ +// //------------------------------------------------------------------- +// private boolean ArrayType_0() +// { +// begin(""); +// if (!ClassType()) return rejectInner(); +// if (!Dim()) return rejectInner(); +// while (Dim()); +// return acceptInner(); +// } +// +// //===================================================================== +// // TypeVariable = Annotation* Identifier ; +// //===================================================================== +// private boolean TypeVariable() +// { +// begin("TypeVariable"); +// while (Annotation()); +// if (!Identifier()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Dim = Annotation* LBRK RBRK ; +// //===================================================================== +// private boolean Dim() +// { +// begin("Dim"); +// while (Annotation()); +// if (!LBRK()) return reject(); +// if (!RBRK()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TypeParameter = TypeParameterModifier* Identifier TypeBound? ; +// //===================================================================== +// private boolean TypeParameter() +// { +// begin("TypeParameter"); +// while (TypeParameterModifier()); +// if (!Identifier()) return reject(); +// TypeBound(); +// return accept(); +// } +// +// //===================================================================== +// // TypeParameterModifier = Annotation ; +// //===================================================================== +// private boolean TypeParameterModifier() +// { +// begin("TypeParameterModifier"); +// if (!Annotation()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TypeBound = EXTENDS (ClassType AdditionalBound* / TypeVariable) ; +// //===================================================================== +// private boolean TypeBound() +// { +// begin("TypeBound"); +// if (!EXTENDS()) return reject(); +// if (!TypeBound_0() +// && !TypeVariable() +// ) return reject(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // TypeBound_0 = ClassType AdditionalBound* +// //------------------------------------------------------------------- +// private boolean TypeBound_0() +// { +// begin(""); +// if (!ClassType()) return rejectInner(); +// while (AdditionalBound()); +// return acceptInner(); +// } +// +// //===================================================================== +// // AdditionalBound = AND ClassType ; +// //===================================================================== +// private boolean AdditionalBound() +// { +// begin("AdditionalBound"); +// if (!AND()) return reject(); +// if (!ClassType()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TypeArguments = LPOINT TypeArgumentList RPOINT ; +// //===================================================================== +// private boolean TypeArguments() +// { +// begin("TypeArguments"); +// if (!LPOINT()) return reject(); +// if (!TypeArgumentList()) return reject(); +// if (!RPOINT()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TypeArgumentList = TypeArgument (COMMA TypeArgument)* ; +// //===================================================================== +// private boolean TypeArgumentList() +// { +// begin("TypeArgumentList"); +// if (!TypeArgument()) return reject(); +// while (TypeArgumentList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // TypeArgumentList_0 = COMMA TypeArgument +// //------------------------------------------------------------------- +// private boolean TypeArgumentList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!TypeArgument()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // TypeArgument = ReferenceType / Wildcard ; +// //===================================================================== +// private boolean TypeArgument() +// { +// begin("TypeArgument"); +// if (ReferenceType()) return accept(); +// if (Wildcard()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // Wildcard = Annotation* QUERY WildcardBounds? ; +// //===================================================================== +// private boolean Wildcard() +// { +// begin("Wildcard"); +// while (Annotation()); +// if (!QUERY()) return reject(); +// WildcardBounds(); +// return accept(); +// } +// +// //===================================================================== +// // WildcardBounds = EXTENDS ReferenceType / SUPER ReferenceType ; +// //===================================================================== +// private boolean WildcardBounds() +// { +// begin("WildcardBounds"); +// if (WildcardBounds_0()) return accept(); +// if (WildcardBounds_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // WildcardBounds_0 = EXTENDS ReferenceType +// //------------------------------------------------------------------- +// private boolean WildcardBounds_0() +// { +// begin(""); +// if (!EXTENDS()) return rejectInner(); +// if (!ReferenceType()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // WildcardBounds_1 = SUPER ReferenceType +// //------------------------------------------------------------------- +// private boolean WildcardBounds_1() +// { +// begin(""); +// if (!SUPER()) return rejectInner(); +// if (!ReferenceType()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // QualIdent = Identifier (DOT Identifier)* ; +// //===================================================================== +// private boolean QualIdent() +// { +// begin("QualIdent"); +// if (!Identifier()) return reject(); +// while (QualIdent_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // QualIdent_0 = DOT Identifier +// //------------------------------------------------------------------- +// private boolean QualIdent_0() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // CompilationUnit = PackageDeclaration? ImportDeclaration* +// // TypeDeclaration* ; +// //===================================================================== +// private boolean CompilationUnit() +// { +// begin("CompilationUnit"); +// PackageDeclaration(); +// while (ImportDeclaration()); +// while (TypeDeclaration()); +// return accept(); +// } +// +// //===================================================================== +// // PackageDeclaration = PackageModifier* PACKAGE Identifier (DOT +// // Identifier)* SEMI ; +// //===================================================================== +// private boolean PackageDeclaration() +// { +// begin("PackageDeclaration"); +// while (PackageModifier()); +// if (!PACKAGE()) return reject(); +// if (!Identifier()) return reject(); +// while (QualIdent_0()); +// if (!SEMI()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // PackageModifier = Annotation ; +// //===================================================================== +// private boolean PackageModifier() +// { +// begin("PackageModifier"); +// if (!Annotation()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ImportDeclaration = IMPORT STATIC? QualIdent (DOT STAR)? SEMI / +// // SEMI ; +// //===================================================================== +// private boolean ImportDeclaration() +// { +// begin("ImportDeclaration"); +// if (ImportDeclaration_0()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // ImportDeclaration_0 = IMPORT STATIC? QualIdent (DOT STAR)? SEMI +// //------------------------------------------------------------------- +// private boolean ImportDeclaration_0() +// { +// begin(""); +// if (!IMPORT()) return rejectInner(); +// STATIC(); +// if (!QualIdent()) return rejectInner(); +// ImportDeclaration_1(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ImportDeclaration_1 = DOT STAR +// //------------------------------------------------------------------- +// private boolean ImportDeclaration_1() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// if (!STAR()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // TypeDeclaration = ClassDeclaration / InterfaceDeclaration / SEMI ; +// //===================================================================== +// private boolean TypeDeclaration() +// { +// begin("TypeDeclaration"); +// if (ClassDeclaration()) return accept(); +// if (InterfaceDeclaration()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ClassDeclaration = NormalClassDeclaration / EnumDeclaration ; +// //===================================================================== +// private boolean ClassDeclaration() +// { +// begin("ClassDeclaration"); +// if (NormalClassDeclaration()) return accept(); +// if (EnumDeclaration()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // NormalClassDeclaration = ClassModifier* CLASS Identifier +// // TypeParameters? Superclass? Superinterfaces? ClassBody ; +// //===================================================================== +// private boolean NormalClassDeclaration() +// { +// begin("NormalClassDeclaration"); +// while (ClassModifier()); +// if (!CLASS()) return reject(); +// if (!Identifier()) return reject(); +// TypeParameters(); +// Superclass(); +// Superinterfaces(); +// if (!ClassBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ClassModifier = Annotation / PUBLIC / PROTECTED / PRIVATE / +// // ABSTRACT / STATIC / FINAL / STRICTFP ; +// //===================================================================== +// private boolean ClassModifier() +// { +// begin("ClassModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (PROTECTED()) return accept(); +// if (PRIVATE()) return accept(); +// if (ABSTRACT()) return accept(); +// if (STATIC()) return accept(); +// if (FINAL()) return accept(); +// if (STRICTFP()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // TypeParameters = LPOINT TypeParameterList RPOINT ; +// //===================================================================== +// private boolean TypeParameters() +// { +// begin("TypeParameters"); +// if (!LPOINT()) return reject(); +// if (!TypeParameterList()) return reject(); +// if (!RPOINT()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TypeParameterList = TypeParameter (COMMA TypeParameter)* ; +// //===================================================================== +// private boolean TypeParameterList() +// { +// begin("TypeParameterList"); +// if (!TypeParameter()) return reject(); +// while (TypeParameterList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // TypeParameterList_0 = COMMA TypeParameter +// //------------------------------------------------------------------- +// private boolean TypeParameterList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!TypeParameter()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Superclass = EXTENDS ClassType ; +// //===================================================================== +// private boolean Superclass() +// { +// begin("Superclass"); +// if (!EXTENDS()) return reject(); +// if (!ClassType()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Superinterfaces = IMPLEMENTS InterfaceTypeList ; +// //===================================================================== +// private boolean Superinterfaces() +// { +// begin("Superinterfaces"); +// if (!IMPLEMENTS()) return reject(); +// if (!InterfaceTypeList()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceTypeList = ClassType (COMMA ClassType)* ; +// //===================================================================== +// private boolean InterfaceTypeList() +// { +// begin("InterfaceTypeList"); +// if (!ClassType()) return reject(); +// while (InterfaceTypeList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // InterfaceTypeList_0 = COMMA ClassType +// //------------------------------------------------------------------- +// private boolean InterfaceTypeList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!ClassType()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // ClassBody = LWING ClassBodyDeclaration* RWING ; +// //===================================================================== +// private boolean ClassBody() +// { +// begin("ClassBody"); +// if (!LWING()) return reject(); +// while (ClassBodyDeclaration()); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ClassBodyDeclaration = ClassMemberDeclaration / InstanceInitializer +// // / StaticInitializer / ConstructorDeclaration ; +// //===================================================================== +// private boolean ClassBodyDeclaration() +// { +// begin("ClassBodyDeclaration"); +// if (ClassMemberDeclaration()) return accept(); +// if (InstanceInitializer()) return accept(); +// if (StaticInitializer()) return accept(); +// if (ConstructorDeclaration()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ClassMemberDeclaration = FieldDeclaration / MethodDeclaration / +// // ClassDeclaration / InterfaceDeclaration / SEMI ; +// //===================================================================== +// private boolean ClassMemberDeclaration() +// { +// begin("ClassMemberDeclaration"); +// if (FieldDeclaration()) return accept(); +// if (MethodDeclaration()) return accept(); +// if (ClassDeclaration()) return accept(); +// if (InterfaceDeclaration()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // FieldDeclaration = FieldModifier* UnannType VariableDeclaratorList +// // SEMI ; +// //===================================================================== +// private boolean FieldDeclaration() +// { +// begin("FieldDeclaration"); +// while (FieldModifier()); +// if (!UnannType()) return reject(); +// if (!VariableDeclaratorList()) return reject(); +// if (!SEMI()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // VariableDeclaratorList = VariableDeclarator (COMMA +// // VariableDeclarator)* ; +// //===================================================================== +// private boolean VariableDeclaratorList() +// { +// begin("VariableDeclaratorList"); +// if (!VariableDeclarator()) return reject(); +// while (VariableDeclaratorList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // VariableDeclaratorList_0 = COMMA VariableDeclarator +// //------------------------------------------------------------------- +// private boolean VariableDeclaratorList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!VariableDeclarator()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // VariableDeclarator = VariableDeclaratorId (EQU +// // VariableInitializer)? ; +// //===================================================================== +// private boolean VariableDeclarator() +// { +// begin("VariableDeclarator"); +// if (!VariableDeclaratorId()) return reject(); +// VariableDeclarator_0(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // VariableDeclarator_0 = EQU VariableInitializer +// //------------------------------------------------------------------- +// private boolean VariableDeclarator_0() +// { +// begin(""); +// if (!EQU()) return rejectInner(); +// if (!VariableInitializer()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // VariableDeclaratorId = Identifier Dim* ; +// //===================================================================== +// private boolean VariableDeclaratorId() +// { +// begin("VariableDeclaratorId"); +// if (!Identifier()) return reject(); +// while (Dim()); +// return accept(); +// } +// +// //===================================================================== +// // VariableInitializer = Expression / ArrayInitializer ; +// //===================================================================== +// private boolean VariableInitializer() +// { +// begin("VariableInitializer"); +// if (Expression()) return accept(); +// if (ArrayInitializer()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // UnannClassType = Identifier TypeArguments? (DOT Annotation* +// // Identifier TypeArguments?)* ; +// //===================================================================== +// private boolean UnannClassType() +// { +// begin("UnannClassType"); +// if (!Identifier()) return reject(); +// TypeArguments(); +// while (ClassType_0()); +// return accept(); +// } +// +// //===================================================================== +// // UnannType = BasicType Dim* / UnannClassType Dim* ; +// //===================================================================== +// private boolean UnannType() +// { +// begin("UnannType"); +// if (UnannType_0()) return accept(); +// if (UnannType_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // UnannType_0 = BasicType Dim* +// //------------------------------------------------------------------- +// private boolean UnannType_0() +// { +// begin(""); +// if (!BasicType()) return rejectInner(); +// while (Dim()); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // UnannType_1 = UnannClassType Dim* +// //------------------------------------------------------------------- +// private boolean UnannType_1() +// { +// begin(""); +// if (!UnannClassType()) return rejectInner(); +// while (Dim()); +// return acceptInner(); +// } +// +// //===================================================================== +// // FieldModifier = Annotation / PUBLIC / PROTECTED / PRIVATE / STATIC +// // / FINAL / TRANSIENT / VOLATILE ; +// //===================================================================== +// private boolean FieldModifier() +// { +// begin("FieldModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (PROTECTED()) return accept(); +// if (PRIVATE()) return accept(); +// if (STATIC()) return accept(); +// if (FINAL()) return accept(); +// if (TRANSIENT()) return accept(); +// if (VOLATILE()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // MethodDeclaration = MethodModifier* MethodHeader MethodBody ; +// //===================================================================== +// private boolean MethodDeclaration() +// { +// begin("MethodDeclaration"); +// while (MethodModifier()); +// if (!MethodHeader()) return reject(); +// if (!MethodBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // MethodHeader = Result MethodDeclarator Throws? / TypeParameters +// // Annotation* Result MethodDeclarator Throws? ; +// //===================================================================== +// private boolean MethodHeader() +// { +// begin("MethodHeader"); +// if (MethodHeader_0()) return accept(); +// if (MethodHeader_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // MethodHeader_0 = Result MethodDeclarator Throws? +// //------------------------------------------------------------------- +// private boolean MethodHeader_0() +// { +// begin(""); +// if (!Result()) return rejectInner(); +// if (!MethodDeclarator()) return rejectInner(); +// Throws(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // MethodHeader_1 = TypeParameters Annotation* Result +// // MethodDeclarator Throws? +// //------------------------------------------------------------------- +// private boolean MethodHeader_1() +// { +// begin(""); +// if (!TypeParameters()) return rejectInner(); +// while (Annotation()); +// if (!Result()) return rejectInner(); +// if (!MethodDeclarator()) return rejectInner(); +// Throws(); +// return acceptInner(); +// } +// +// //===================================================================== +// // MethodDeclarator = Identifier LPAR FormalParameterList? RPAR Dim* +// // ; +// //===================================================================== +// private boolean MethodDeclarator() +// { +// begin("MethodDeclarator"); +// if (!Identifier()) return reject(); +// if (!LPAR()) return reject(); +// FormalParameterList(); +// if (!RPAR()) return reject(); +// while (Dim()); +// return accept(); +// } +// +// //===================================================================== +// // FormalParameterList = (ReceiverParameter / FormalParameter) (COMMA +// // FormalParameter)* ; +// //===================================================================== +// private boolean FormalParameterList() +// { +// begin("FormalParameterList"); +// if (!ReceiverParameter() +// && !FormalParameter() +// ) return reject(); +// while (FormalParameterList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // FormalParameterList_0 = COMMA FormalParameter +// //------------------------------------------------------------------- +// private boolean FormalParameterList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!FormalParameter()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // FormalParameter = VariableModifier* UnannType VariableDeclaratorId +// // / VariableModifier* UnannType Annotation* ELLIPSIS +// // VariableDeclaratorId !COMMA ; +// //===================================================================== +// private boolean FormalParameter() +// { +// begin("FormalParameter"); +// if (FormalParameter_0()) return accept(); +// if (FormalParameter_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // FormalParameter_0 = VariableModifier* UnannType +// // VariableDeclaratorId +// //------------------------------------------------------------------- +// private boolean FormalParameter_0() +// { +// begin(""); +// while (VariableModifier()); +// if (!UnannType()) return rejectInner(); +// if (!VariableDeclaratorId()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // FormalParameter_1 = VariableModifier* UnannType Annotation* +// // ELLIPSIS VariableDeclaratorId !COMMA +// //------------------------------------------------------------------- +// private boolean FormalParameter_1() +// { +// begin(""); +// while (VariableModifier()); +// if (!UnannType()) return rejectInner(); +// while (Annotation()); +// if (!ELLIPSIS()) return rejectInner(); +// if (!VariableDeclaratorId()) return rejectInner(); +// if (!FormalParameter_2()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // FormalParameter_2 = !COMMA +// //------------------------------------------------------------------- +// private boolean FormalParameter_2() +// { +// begin("","not COMMA"); +// if (COMMA()) return rejectPred(); +// return acceptPred(); +// } +// +// //===================================================================== +// // VariableModifier = Annotation / FINAL ; +// //===================================================================== +// private boolean VariableModifier() +// { +// begin("VariableModifier"); +// if (Annotation()) return accept(); +// if (FINAL()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ReceiverParameter = VariableModifier* UnannType (Identifier DOT)? +// // THIS ; +// //===================================================================== +// private boolean ReceiverParameter() +// { +// begin("ReceiverParameter"); +// while (VariableModifier()); +// if (!UnannType()) return reject(); +// ReceiverParameter_0(); +// if (!THIS()) return reject(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ReceiverParameter_0 = Identifier DOT +// //------------------------------------------------------------------- +// private boolean ReceiverParameter_0() +// { +// begin(""); +// if (!Identifier()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Result = UnannType / VOID ; +// //===================================================================== +// private boolean Result() +// { +// begin("Result"); +// if (UnannType()) return accept(); +// if (VOID()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // MethodModifier = Annotation / PUBLIC / PROTECTED / PRIVATE / +// // ABSTRACT / STATIC / FINAL / SYNCHRONIZED / NATIVE / STRICTFP ; +// //===================================================================== +// private boolean MethodModifier() +// { +// begin("MethodModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (PROTECTED()) return accept(); +// if (PRIVATE()) return accept(); +// if (ABSTRACT()) return accept(); +// if (STATIC()) return accept(); +// if (FINAL()) return accept(); +// if (SYNCHRONIZED()) return accept(); +// if (NATIVE()) return accept(); +// if (STRICTFP()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // Throws = THROWS ExceptionTypeList ; +// //===================================================================== +// private boolean Throws() +// { +// begin("Throws"); +// if (!THROWS()) return reject(); +// if (!ExceptionTypeList()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ExceptionTypeList = ExceptionType (COMMA ExceptionType)* ; +// //===================================================================== +// private boolean ExceptionTypeList() +// { +// begin("ExceptionTypeList"); +// if (!ExceptionType()) return reject(); +// while (ExceptionTypeList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ExceptionTypeList_0 = COMMA ExceptionType +// //------------------------------------------------------------------- +// private boolean ExceptionTypeList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!ExceptionType()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // ExceptionType = ClassType / TypeVariable ; +// //===================================================================== +// private boolean ExceptionType() +// { +// begin("ExceptionType"); +// if (ClassType()) return accept(); +// if (TypeVariable()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // MethodBody = Block / SEMI ; +// //===================================================================== +// private boolean MethodBody() +// { +// begin("MethodBody"); +// if (Block()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // InstanceInitializer = Block ; +// //===================================================================== +// private boolean InstanceInitializer() +// { +// begin("InstanceInitializer"); +// if (!Block()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // StaticInitializer = STATIC Block ; +// //===================================================================== +// private boolean StaticInitializer() +// { +// begin("StaticInitializer"); +// if (!STATIC()) return reject(); +// if (!Block()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ConstructorDeclaration = ConstructorModifier* ConstructorDeclarator +// // Throws? ConstructorBody ; +// //===================================================================== +// private boolean ConstructorDeclaration() +// { +// begin("ConstructorDeclaration"); +// while (ConstructorModifier()); +// if (!ConstructorDeclarator()) return reject(); +// Throws(); +// if (!ConstructorBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ConstructorDeclarator = TypeParameters? Identifier LPAR +// // FormalParameterList? RPAR ; +// //===================================================================== +// private boolean ConstructorDeclarator() +// { +// begin("ConstructorDeclarator"); +// TypeParameters(); +// if (!Identifier()) return reject(); +// if (!LPAR()) return reject(); +// FormalParameterList(); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ConstructorModifier = Annotation / PUBLIC / PROTECTED / PRIVATE ; +// //===================================================================== +// private boolean ConstructorModifier() +// { +// begin("ConstructorModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (PROTECTED()) return accept(); +// if (PRIVATE()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ConstructorBody = LWING ExplicitConstructorInvocation? +// // BlockStatements? RWING ; +// //===================================================================== +// private boolean ConstructorBody() +// { +// begin("ConstructorBody"); +// if (!LWING()) return reject(); +// ExplicitConstructorInvocation(); +// BlockStatements(); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ExplicitConstructorInvocation = TypeArguments? THIS Arguments SEMI +// // / TypeArguments? SUPER Arguments SEMI / Primary DOT +// // TypeArguments? SUPER Arguments SEMI / QualIdent DOT +// // TypeArguments? SUPER Arguments SEMI ; +// //===================================================================== +// private boolean ExplicitConstructorInvocation() +// { +// begin("ExplicitConstructorInvocation"); +// if (ExplicitConstructorInvocation_0()) return accept(); +// if (ExplicitConstructorInvocation_1()) return accept(); +// if (ExplicitConstructorInvocation_2()) return accept(); +// if (ExplicitConstructorInvocation_3()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // ExplicitConstructorInvocation_0 = TypeArguments? THIS Arguments +// // SEMI +// //------------------------------------------------------------------- +// private boolean ExplicitConstructorInvocation_0() +// { +// begin(""); +// TypeArguments(); +// if (!THIS()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ExplicitConstructorInvocation_1 = TypeArguments? SUPER Arguments +// // SEMI +// //------------------------------------------------------------------- +// private boolean ExplicitConstructorInvocation_1() +// { +// begin(""); +// TypeArguments(); +// if (!SUPER()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ExplicitConstructorInvocation_2 = Primary DOT TypeArguments? +// // SUPER Arguments SEMI +// //------------------------------------------------------------------- +// private boolean ExplicitConstructorInvocation_2() +// { +// begin(""); +// if (!Primary()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// TypeArguments(); +// if (!SUPER()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ExplicitConstructorInvocation_3 = QualIdent DOT TypeArguments? +// // SUPER Arguments SEMI +// //------------------------------------------------------------------- +// private boolean ExplicitConstructorInvocation_3() +// { +// begin(""); +// if (!QualIdent()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// TypeArguments(); +// if (!SUPER()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // EnumDeclaration = ClassModifier* ENUM Identifier Superinterfaces? +// // EnumBody ; +// //===================================================================== +// private boolean EnumDeclaration() +// { +// begin("EnumDeclaration"); +// while (ClassModifier()); +// if (!ENUM()) return reject(); +// if (!Identifier()) return reject(); +// Superinterfaces(); +// if (!EnumBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // EnumBody = LWING EnumConstantList? COMMA? EnumBodyDeclarations? +// // RWING ; +// //===================================================================== +// private boolean EnumBody() +// { +// begin("EnumBody"); +// if (!LWING()) return reject(); +// EnumConstantList(); +// COMMA(); +// EnumBodyDeclarations(); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // EnumConstantList = EnumConstant (COMMA EnumConstant)* ; +// //===================================================================== +// private boolean EnumConstantList() +// { +// begin("EnumConstantList"); +// if (!EnumConstant()) return reject(); +// while (EnumConstantList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // EnumConstantList_0 = COMMA EnumConstant +// //------------------------------------------------------------------- +// private boolean EnumConstantList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!EnumConstant()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // EnumConstant = EnumConstantModifier* Identifier Arguments? +// // ClassBody? ; +// //===================================================================== +// private boolean EnumConstant() +// { +// begin("EnumConstant"); +// while (EnumConstantModifier()); +// if (!Identifier()) return reject(); +// Arguments(); +// ClassBody(); +// return accept(); +// } +// +// //===================================================================== +// // EnumConstantModifier = Annotation ; +// //===================================================================== +// private boolean EnumConstantModifier() +// { +// begin("EnumConstantModifier"); +// if (!Annotation()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // EnumBodyDeclarations = SEMI ClassBodyDeclaration* ; +// //===================================================================== +// private boolean EnumBodyDeclarations() +// { +// begin("EnumBodyDeclarations"); +// if (!SEMI()) return reject(); +// while (ClassBodyDeclaration()); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceDeclaration = NormalInterfaceDeclaration / +// // AnnotationTypeDeclaration ; +// //===================================================================== +// private boolean InterfaceDeclaration() +// { +// begin("InterfaceDeclaration"); +// if (NormalInterfaceDeclaration()) return accept(); +// if (AnnotationTypeDeclaration()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // NormalInterfaceDeclaration = InterfaceModifier* INTERFACE +// // Identifier TypeParameters? ExtendsInterfaces? InterfaceBody ; +// //===================================================================== +// private boolean NormalInterfaceDeclaration() +// { +// begin("NormalInterfaceDeclaration"); +// while (InterfaceModifier()); +// if (!INTERFACE()) return reject(); +// if (!Identifier()) return reject(); +// TypeParameters(); +// ExtendsInterfaces(); +// if (!InterfaceBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceModifier = Annotation / PUBLIC / PROTECTED / PRIVATE / +// // ABSTRACT / STATIC / STRICTFP ; +// //===================================================================== +// private boolean InterfaceModifier() +// { +// begin("InterfaceModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (PROTECTED()) return accept(); +// if (PRIVATE()) return accept(); +// if (ABSTRACT()) return accept(); +// if (STATIC()) return accept(); +// if (STRICTFP()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ExtendsInterfaces = EXTENDS InterfaceTypeList ; +// //===================================================================== +// private boolean ExtendsInterfaces() +// { +// begin("ExtendsInterfaces"); +// if (!EXTENDS()) return reject(); +// if (!InterfaceTypeList()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceBody = LWING InterfaceMemberDeclaration* RWING ; +// //===================================================================== +// private boolean InterfaceBody() +// { +// begin("InterfaceBody"); +// if (!LWING()) return reject(); +// while (InterfaceMemberDeclaration()); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceMemberDeclaration = ConstantDeclaration / +// // InterfaceMethodDeclaration / ClassDeclaration / +// // InterfaceDeclaration / SEMI ; +// //===================================================================== +// private boolean InterfaceMemberDeclaration() +// { +// begin("InterfaceMemberDeclaration"); +// if (ConstantDeclaration()) return accept(); +// if (InterfaceMethodDeclaration()) return accept(); +// if (ClassDeclaration()) return accept(); +// if (InterfaceDeclaration()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ConstantDeclaration = ConstantModifier* UnannType +// // VariableDeclaratorList SEMI ; +// //===================================================================== +// private boolean ConstantDeclaration() +// { +// begin("ConstantDeclaration"); +// while (ConstantModifier()); +// if (!UnannType()) return reject(); +// if (!VariableDeclaratorList()) return reject(); +// if (!SEMI()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ConstantModifier = Annotation / PUBLIC / STATIC / FINAL ; +// //===================================================================== +// private boolean ConstantModifier() +// { +// begin("ConstantModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (STATIC()) return accept(); +// if (FINAL()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // InterfaceMethodDeclaration = InterfaceMethodModifier* MethodHeader +// // MethodBody ; +// //===================================================================== +// private boolean InterfaceMethodDeclaration() +// { +// begin("InterfaceMethodDeclaration"); +// while (InterfaceMethodModifier()); +// if (!MethodHeader()) return reject(); +// if (!MethodBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // InterfaceMethodModifier = Annotation / PUBLIC / ABSTRACT / DEFAULT +// // / STATIC / STRICTFP ; +// //===================================================================== +// private boolean InterfaceMethodModifier() +// { +// begin("InterfaceMethodModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (ABSTRACT()) return accept(); +// if (DEFAULT()) return accept(); +// if (STATIC()) return accept(); +// if (STRICTFP()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // AnnotationTypeDeclaration = InterfaceModifier* AT INTERFACE +// // Identifier AnnotationTypeBody ; +// //===================================================================== +// private boolean AnnotationTypeDeclaration() +// { +// begin("AnnotationTypeDeclaration"); +// while (InterfaceModifier()); +// if (!AT()) return reject(); +// if (!INTERFACE()) return reject(); +// if (!Identifier()) return reject(); +// if (!AnnotationTypeBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // AnnotationTypeBody = LWING AnnotationTypeMemberDeclaration* RWING +// // ; +// //===================================================================== +// private boolean AnnotationTypeBody() +// { +// begin("AnnotationTypeBody"); +// if (!LWING()) return reject(); +// while (AnnotationTypeMemberDeclaration()); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // AnnotationTypeMemberDeclaration = AnnotationTypeElementDeclaration +// // / ConstantDeclaration / ClassDeclaration / InterfaceDeclaration / +// // SEMI ; +// //===================================================================== +// private boolean AnnotationTypeMemberDeclaration() +// { +// begin("AnnotationTypeMemberDeclaration"); +// if (AnnotationTypeElementDeclaration()) return accept(); +// if (ConstantDeclaration()) return accept(); +// if (ClassDeclaration()) return accept(); +// if (InterfaceDeclaration()) return accept(); +// if (SEMI()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // AnnotationTypeElementDeclaration = AnnotationTypeElementModifier* +// // UnannType Identifier LPAR RPAR Dim* DefaultValue? SEMI ; +// //===================================================================== +// private boolean AnnotationTypeElementDeclaration() +// { +// begin("AnnotationTypeElementDeclaration"); +// while (AnnotationTypeElementModifier()); +// if (!UnannType()) return reject(); +// if (!Identifier()) return reject(); +// if (!LPAR()) return reject(); +// if (!RPAR()) return reject(); +// while (Dim()); +// DefaultValue(); +// if (!SEMI()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // AnnotationTypeElementModifier = Annotation / PUBLIC / ABSTRACT ; +// //===================================================================== +// private boolean AnnotationTypeElementModifier() +// { +// begin("AnnotationTypeElementModifier"); +// if (Annotation()) return accept(); +// if (PUBLIC()) return accept(); +// if (ABSTRACT()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // DefaultValue = DEFAULT ElementValue ; +// //===================================================================== +// private boolean DefaultValue() +// { +// begin("DefaultValue"); +// if (!DEFAULT()) return reject(); +// if (!ElementValue()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Annotation = AT (NormalAnnotation / SingleElementAnnotation / +// // MarkerAnnotation) ; +// //===================================================================== +// private boolean Annotation() +// { +// begin("Annotation"); +// if (!AT()) return reject(); +// if (!NormalAnnotation() +// && !SingleElementAnnotation() +// && !MarkerAnnotation() +// ) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // NormalAnnotation = QualIdent LPAR ElementValuePairList* RPAR ; +// //===================================================================== +// private boolean NormalAnnotation() +// { +// begin("NormalAnnotation"); +// if (!QualIdent()) return reject(); +// if (!LPAR()) return reject(); +// while (ElementValuePairList()); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ElementValuePairList = ElementValuePair (COMMA ElementValuePair)* +// // ; +// //===================================================================== +// private boolean ElementValuePairList() +// { +// begin("ElementValuePairList"); +// if (!ElementValuePair()) return reject(); +// while (ElementValuePairList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ElementValuePairList_0 = COMMA ElementValuePair +// //------------------------------------------------------------------- +// private boolean ElementValuePairList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!ElementValuePair()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // ElementValuePair = Identifier EQU ElementValue ; +// //===================================================================== +// private boolean ElementValuePair() +// { +// begin("ElementValuePair"); +// if (!Identifier()) return reject(); +// if (!EQU()) return reject(); +// if (!ElementValue()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ElementValue = ConditionalExpression / ElementValueArrayInitializer +// // / Annotation ; +// //===================================================================== +// private boolean ElementValue() +// { +// begin("ElementValue"); +// if (ConditionalExpression()) return accept(); +// if (ElementValueArrayInitializer()) return accept(); +// if (Annotation()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ElementValueArrayInitializer = LWING ElementValueList? COMMA? RWING +// // ; +// //===================================================================== +// private boolean ElementValueArrayInitializer() +// { +// begin("ElementValueArrayInitializer"); +// if (!LWING()) return reject(); +// ElementValueList(); +// COMMA(); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ElementValueList = ElementValue (COMMA ElementValue)* ; +// //===================================================================== +// private boolean ElementValueList() +// { +// begin("ElementValueList"); +// if (!ElementValue()) return reject(); +// while (ElementValueList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ElementValueList_0 = COMMA ElementValue +// //------------------------------------------------------------------- +// private boolean ElementValueList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!ElementValue()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // MarkerAnnotation = QualIdent ; +// //===================================================================== +// private boolean MarkerAnnotation() +// { +// begin("MarkerAnnotation"); +// if (!QualIdent()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // SingleElementAnnotation = QualIdent LPAR ElementValue RPAR ; +// //===================================================================== +// private boolean SingleElementAnnotation() +// { +// begin("SingleElementAnnotation"); +// if (!QualIdent()) return reject(); +// if (!LPAR()) return reject(); +// if (!ElementValue()) return reject(); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ArrayInitializer = LWING VariableInitializerList? COMMA? RWING ; +// //===================================================================== +// private boolean ArrayInitializer() +// { +// begin("ArrayInitializer"); +// if (!LWING()) return reject(); +// VariableInitializerList(); +// COMMA(); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // VariableInitializerList = VariableInitializer (COMMA +// // VariableInitializer)* ; +// //===================================================================== +// private boolean VariableInitializerList() +// { +// begin("VariableInitializerList"); +// if (!VariableInitializer()) return reject(); +// while (VariableInitializerList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // VariableInitializerList_0 = COMMA VariableInitializer +// //------------------------------------------------------------------- +// private boolean VariableInitializerList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!VariableInitializer()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Block = LWING BlockStatements? RWING ; +// //===================================================================== +// private boolean Block() +// { +// begin("Block"); +// if (!LWING()) return reject(); +// BlockStatements(); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // BlockStatements = BlockStatement BlockStatement* ; +// //===================================================================== +// private boolean BlockStatements() +// { +// begin("BlockStatements"); +// if (!BlockStatement()) return reject(); +// while (BlockStatement()); +// return accept(); +// } +// +// //===================================================================== +// // BlockStatement = LocalVariableDeclarationStatement / +// // ClassDeclaration / Statement ; +// //===================================================================== +// private boolean BlockStatement() +// { +// begin("BlockStatement"); +// if (LocalVariableDeclarationStatement()) return accept(); +// if (ClassDeclaration()) return accept(); +// if (Statement()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // LocalVariableDeclarationStatement = LocalVariableDeclaration SEMI +// // ; +// //===================================================================== +// private boolean LocalVariableDeclarationStatement() +// { +// begin("LocalVariableDeclarationStatement"); +// if (!LocalVariableDeclaration()) return reject(); +// if (!SEMI()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // LocalVariableDeclaration = VariableModifier* UnannType +// // VariableDeclaratorList ; +// //===================================================================== +// private boolean LocalVariableDeclaration() +// { +// begin("LocalVariableDeclaration"); +// while (VariableModifier()); +// if (!UnannType()) return reject(); +// if (!VariableDeclaratorList()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Statement = Block / IF ParExpression Statement (ELSE Statement)? / +// // BasicForStatement / EnhancedForStatement / WHILE ParExpression +// // Statement / DO Statement WHILE ParExpression SEMI / TryStatement +// // / SWITCH ParExpression SwitchBlock / SYNCHRONIZED ParExpression +// // Block / RETURN Expression? SEMI / THROW Expression SEMI / BREAK +// // Identifier? SEMI / CONTINUE Identifier? SEMI / ASSERT Expression +// // (COLON Expression)? SEMI / SEMI / StatementExpression SEMI / +// // Identifier COLON Statement ; +// //===================================================================== +// private boolean Statement() +// { +// begin("Statement"); +// if (Block()) return accept(); +// if (Statement_0()) return accept(); +// if (BasicForStatement()) return accept(); +// if (EnhancedForStatement()) return accept(); +// if (Statement_1()) return accept(); +// if (Statement_2()) return accept(); +// if (TryStatement()) return accept(); +// if (Statement_3()) return accept(); +// if (Statement_4()) return accept(); +// if (Statement_5()) return accept(); +// if (Statement_6()) return accept(); +// if (Statement_7()) return accept(); +// if (Statement_8()) return accept(); +// if (Statement_9()) return accept(); +// if (SEMI()) return accept(); +// if (Statement_10()) return accept(); +// if (Statement_11()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // Statement_0 = IF ParExpression Statement (ELSE Statement)? +// //------------------------------------------------------------------- +// private boolean Statement_0() +// { +// begin(""); +// if (!IF()) return rejectInner(); +// if (!ParExpression()) return rejectInner(); +// if (!Statement()) return rejectInner(); +// Statement_12(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_1 = WHILE ParExpression Statement +// //------------------------------------------------------------------- +// private boolean Statement_1() +// { +// begin(""); +// if (!WHILE()) return rejectInner(); +// if (!ParExpression()) return rejectInner(); +// if (!Statement()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_2 = DO Statement WHILE ParExpression SEMI +// //------------------------------------------------------------------- +// private boolean Statement_2() +// { +// begin(""); +// if (!DO()) return rejectInner(); +// if (!Statement()) return rejectInner(); +// if (!WHILE()) return rejectInner(); +// if (!ParExpression()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_3 = SWITCH ParExpression SwitchBlock +// //------------------------------------------------------------------- +// private boolean Statement_3() +// { +// begin(""); +// if (!SWITCH()) return rejectInner(); +// if (!ParExpression()) return rejectInner(); +// if (!SwitchBlock()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_4 = SYNCHRONIZED ParExpression Block +// //------------------------------------------------------------------- +// private boolean Statement_4() +// { +// begin(""); +// if (!SYNCHRONIZED()) return rejectInner(); +// if (!ParExpression()) return rejectInner(); +// if (!Block()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_5 = RETURN Expression? SEMI +// //------------------------------------------------------------------- +// private boolean Statement_5() +// { +// begin(""); +// if (!RETURN()) return rejectInner(); +// Expression(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_6 = THROW Expression SEMI +// //------------------------------------------------------------------- +// private boolean Statement_6() +// { +// begin(""); +// if (!THROW()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_7 = BREAK Identifier? SEMI +// //------------------------------------------------------------------- +// private boolean Statement_7() +// { +// begin(""); +// if (!BREAK()) return rejectInner(); +// Identifier(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_8 = CONTINUE Identifier? SEMI +// //------------------------------------------------------------------- +// private boolean Statement_8() +// { +// begin(""); +// if (!CONTINUE()) return rejectInner(); +// Identifier(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_9 = ASSERT Expression (COLON Expression)? SEMI +// //------------------------------------------------------------------- +// private boolean Statement_9() +// { +// begin(""); +// if (!ASSERT()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// Statement_13(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_10 = StatementExpression SEMI +// //------------------------------------------------------------------- +// private boolean Statement_10() +// { +// begin(""); +// if (!StatementExpression()) return rejectInner(); +// if (!SEMI()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_11 = Identifier COLON Statement +// //------------------------------------------------------------------- +// private boolean Statement_11() +// { +// begin(""); +// if (!Identifier()) return rejectInner(); +// if (!COLON()) return rejectInner(); +// if (!Statement()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_12 = ELSE Statement +// //------------------------------------------------------------------- +// private boolean Statement_12() +// { +// begin(""); +// if (!ELSE()) return rejectInner(); +// if (!Statement()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // Statement_13 = COLON Expression +// //------------------------------------------------------------------- +// private boolean Statement_13() +// { +// begin(""); +// if (!COLON()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // StatementExpression = Assignment / (INC / DEC) (Primary / +// // QualIdent) / (Primary / QualIdent) (INC / DEC) / Primary ; +// //===================================================================== +// private boolean StatementExpression() +// { +// begin("StatementExpression"); +// if (Assignment()) return accept(); +// if (StatementExpression_0()) return accept(); +// if (StatementExpression_1()) return accept(); +// if (Primary()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // StatementExpression_0 = (INC / DEC) (Primary / QualIdent) +// //------------------------------------------------------------------- +// private boolean StatementExpression_0() +// { +// begin(""); +// if (!INC() +// && !DEC() +// ) return rejectInner(); +// if (!Primary() +// && !QualIdent() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // StatementExpression_1 = (Primary / QualIdent) (INC / DEC) +// //------------------------------------------------------------------- +// private boolean StatementExpression_1() +// { +// begin(""); +// if (!Primary() +// && !QualIdent() +// ) return rejectInner(); +// if (!INC() +// && !DEC() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // SwitchBlock = LWING SwitchBlockStatementGroup* SwitchLabel* RWING +// // ; +// //===================================================================== +// private boolean SwitchBlock() +// { +// begin("SwitchBlock"); +// if (!LWING()) return reject(); +// while (SwitchBlockStatementGroup()); +// while (SwitchLabel()); +// if (!RWING()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // SwitchBlockStatementGroup = SwitchLabels BlockStatements ; +// //===================================================================== +// private boolean SwitchBlockStatementGroup() +// { +// begin("SwitchBlockStatementGroup"); +// if (!SwitchLabels()) return reject(); +// if (!BlockStatements()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // SwitchLabels = SwitchLabel SwitchLabel* ; +// //===================================================================== +// private boolean SwitchLabels() +// { +// begin("SwitchLabels"); +// if (!SwitchLabel()) return reject(); +// while (SwitchLabel()); +// return accept(); +// } +// +// //===================================================================== +// // SwitchLabel = CASE (ConstantExpression / EnumConstantName) COLON / +// // DEFAULT COLON ; +// //===================================================================== +// private boolean SwitchLabel() +// { +// begin("SwitchLabel"); +// if (SwitchLabel_0()) return accept(); +// if (SwitchLabel_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // SwitchLabel_0 = CASE (ConstantExpression / EnumConstantName) +// // COLON +// //------------------------------------------------------------------- +// private boolean SwitchLabel_0() +// { +// begin(""); +// if (!CASE()) return rejectInner(); +// if (!ConstantExpression() +// && !EnumConstantName() +// ) return rejectInner(); +// if (!COLON()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // SwitchLabel_1 = DEFAULT COLON +// //------------------------------------------------------------------- +// private boolean SwitchLabel_1() +// { +// begin(""); +// if (!DEFAULT()) return rejectInner(); +// if (!COLON()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // EnumConstantName = Identifier ; +// //===================================================================== +// private boolean EnumConstantName() +// { +// begin("EnumConstantName"); +// if (!Identifier()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // BasicForStatement = FOR LPAR ForInit? SEMI Expression? SEMI +// // ForUpdate? RPAR Statement ; +// //===================================================================== +// private boolean BasicForStatement() +// { +// begin("BasicForStatement"); +// if (!FOR()) return reject(); +// if (!LPAR()) return reject(); +// ForInit(); +// if (!SEMI()) return reject(); +// Expression(); +// if (!SEMI()) return reject(); +// ForUpdate(); +// if (!RPAR()) return reject(); +// if (!Statement()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ForInit = LocalVariableDeclaration / StatementExpressionList ; +// //===================================================================== +// private boolean ForInit() +// { +// begin("ForInit"); +// if (LocalVariableDeclaration()) return accept(); +// if (StatementExpressionList()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ForUpdate = StatementExpressionList ; +// //===================================================================== +// private boolean ForUpdate() +// { +// begin("ForUpdate"); +// if (!StatementExpressionList()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // StatementExpressionList = StatementExpression (COMMA +// // StatementExpression)* ; +// //===================================================================== +// private boolean StatementExpressionList() +// { +// begin("StatementExpressionList"); +// if (!StatementExpression()) return reject(); +// while (StatementExpressionList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // StatementExpressionList_0 = COMMA StatementExpression +// //------------------------------------------------------------------- +// private boolean StatementExpressionList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!StatementExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // EnhancedForStatement = FOR LPAR VariableModifier* UnannType +// // VariableDeclaratorId COLON Expression RPAR Statement ; +// //===================================================================== +// private boolean EnhancedForStatement() +// { +// begin("EnhancedForStatement"); +// if (!FOR()) return reject(); +// if (!LPAR()) return reject(); +// while (VariableModifier()); +// if (!UnannType()) return reject(); +// if (!VariableDeclaratorId()) return reject(); +// if (!COLON()) return reject(); +// if (!Expression()) return reject(); +// if (!RPAR()) return reject(); +// if (!Statement()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // TryStatement = TRY (Block (CatchClause* Finally / CatchClause+) / +// // ResourceSpecification Block CatchClause* Finally?) ; +// //===================================================================== +// private boolean TryStatement() +// { +// begin("TryStatement"); +// if (!TRY()) return reject(); +// if (!TryStatement_0() +// && !TryStatement_1() +// ) return reject(); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // TryStatement_0 = Block (CatchClause* Finally / CatchClause+) +// //------------------------------------------------------------------- +// private boolean TryStatement_0() +// { +// begin(""); +// if (!Block()) return rejectInner(); +// if (!TryStatement_2() +// && !TryStatement_3() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // TryStatement_1 = ResourceSpecification Block CatchClause* +// // Finally? +// //------------------------------------------------------------------- +// private boolean TryStatement_1() +// { +// begin(""); +// if (!ResourceSpecification()) return rejectInner(); +// if (!Block()) return rejectInner(); +// while (CatchClause()); +// Finally(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // TryStatement_2 = CatchClause* Finally +// //------------------------------------------------------------------- +// private boolean TryStatement_2() +// { +// begin(""); +// while (CatchClause()); +// if (!Finally()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // TryStatement_3 = CatchClause+ +// //------------------------------------------------------------------- +// private boolean TryStatement_3() +// { +// begin(""); +// if (!CatchClause()) return rejectInner(); +// while (CatchClause()); +// return acceptInner(); +// } +// +// //===================================================================== +// // CatchClause = CATCH LPAR CatchFormalParameter RPAR Block ; +// //===================================================================== +// private boolean CatchClause() +// { +// begin("CatchClause"); +// if (!CATCH()) return reject(); +// if (!LPAR()) return reject(); +// if (!CatchFormalParameter()) return reject(); +// if (!RPAR()) return reject(); +// if (!Block()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // CatchFormalParameter = VariableModifier* CatchType +// // VariableDeclaratorId ; +// //===================================================================== +// private boolean CatchFormalParameter() +// { +// begin("CatchFormalParameter"); +// while (VariableModifier()); +// if (!CatchType()) return reject(); +// if (!VariableDeclaratorId()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // CatchType = UnannClassType (OR ClassType)* ; +// //===================================================================== +// private boolean CatchType() +// { +// begin("CatchType"); +// if (!UnannClassType()) return reject(); +// while (CatchType_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // CatchType_0 = OR ClassType +// //------------------------------------------------------------------- +// private boolean CatchType_0() +// { +// begin(""); +// if (!OR()) return rejectInner(); +// if (!ClassType()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Finally = FINALLY Block ; +// //===================================================================== +// private boolean Finally() +// { +// begin("Finally"); +// if (!FINALLY()) return reject(); +// if (!Block()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ResourceSpecification = LPAR ResourceList SEMI? RPAR ; +// //===================================================================== +// private boolean ResourceSpecification() +// { +// begin("ResourceSpecification"); +// if (!LPAR()) return reject(); +// if (!ResourceList()) return reject(); +// SEMI(); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ResourceList = Resource (SEMI Resource)* ; +// //===================================================================== +// private boolean ResourceList() +// { +// begin("ResourceList"); +// if (!Resource()) return reject(); +// while (ResourceList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ResourceList_0 = SEMI Resource +// //------------------------------------------------------------------- +// private boolean ResourceList_0() +// { +// begin(""); +// if (!SEMI()) return rejectInner(); +// if (!Resource()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // Resource = VariableModifier* UnannType VariableDeclaratorId EQU +// // Expression ; +// //===================================================================== +// private boolean Resource() +// { +// begin("Resource"); +// while (VariableModifier()); +// if (!UnannType()) return reject(); +// if (!VariableDeclaratorId()) return reject(); +// if (!EQU()) return reject(); +// if (!Expression()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Expression = LambdaExpression / AssignmentExpression ; +// //===================================================================== +// private boolean Expression() +// { +// begin("Expression"); +// if (LambdaExpression()) return accept(); +// if (AssignmentExpression()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // Primary = PrimaryBase PrimaryRest* ; +// //===================================================================== +// private boolean Primary() +// { +// begin("Primary"); +// if (!PrimaryBase()) return reject(); +// while (PrimaryRest()); +// return accept(); +// } +// +// //===================================================================== +// // PrimaryBase = THIS / Literal / ParExpression / SUPER (DOT +// // TypeArguments? Identifier Arguments / DOT Identifier / COLONCOLON +// // TypeArguments? Identifier) / NEW (ClassCreator / ArrayCreator) / +// // QualIdent (LBRK Expression RBRK / Arguments / DOT (THIS / NEW +// // ClassCreator / TypeArguments Identifier Arguments / SUPER DOT +// // TypeArguments? Identifier Arguments / SUPER DOT Identifier / +// // SUPER COLONCOLON TypeArguments? Identifier) / (LBRK RBRK)* DOT +// // CLASS / COLONCOLON TypeArguments? Identifier) / VOID DOT CLASS / +// // BasicType (LBRK RBRK)* DOT CLASS / ReferenceType COLONCOLON +// // TypeArguments? Identifier / ClassType COLONCOLON TypeArguments? +// // NEW / ArrayType COLONCOLON NEW ; +// //===================================================================== +// private boolean PrimaryBase() +// { +// begin("PrimaryBase"); +// if (THIS()) return accept(); +// if (Literal()) return accept(); +// if (ParExpression()) return accept(); +// if (PrimaryBase_0()) return accept(); +// if (PrimaryBase_1()) return accept(); +// if (PrimaryBase_2()) return accept(); +// if (PrimaryBase_3()) return accept(); +// if (PrimaryBase_4()) return accept(); +// if (PrimaryBase_5()) return accept(); +// if (PrimaryBase_6()) return accept(); +// if (PrimaryBase_7()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_0 = SUPER (DOT TypeArguments? Identifier Arguments / +// // DOT Identifier / COLONCOLON TypeArguments? Identifier) +// //------------------------------------------------------------------- +// private boolean PrimaryBase_0() +// { +// begin(""); +// if (!SUPER()) return rejectInner(); +// if (!PrimaryBase_8() +// && !QualIdent_0() +// && !PrimaryBase_9() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_1 = NEW (ClassCreator / ArrayCreator) +// //------------------------------------------------------------------- +// private boolean PrimaryBase_1() +// { +// begin(""); +// if (!NEW()) return rejectInner(); +// if (!ClassCreator() +// && !ArrayCreator() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_2 = QualIdent (LBRK Expression RBRK / Arguments / DOT +// // (THIS / NEW ClassCreator / TypeArguments Identifier Arguments / +// // SUPER DOT TypeArguments? Identifier Arguments / SUPER DOT +// // Identifier / SUPER COLONCOLON TypeArguments? Identifier) / +// // (LBRK RBRK)* DOT CLASS / COLONCOLON TypeArguments? Identifier) +// //------------------------------------------------------------------- +// private boolean PrimaryBase_2() +// { +// begin(""); +// if (!QualIdent()) return rejectInner(); +// if (!PrimaryBase_10() +// && !Arguments() +// && !PrimaryBase_11() +// && !PrimaryBase_12() +// && !PrimaryBase_9() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_3 = VOID DOT CLASS +// //------------------------------------------------------------------- +// private boolean PrimaryBase_3() +// { +// begin(""); +// if (!VOID()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// if (!CLASS()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_4 = BasicType (LBRK RBRK)* DOT CLASS +// //------------------------------------------------------------------- +// private boolean PrimaryBase_4() +// { +// begin(""); +// if (!BasicType()) return rejectInner(); +// while (PrimaryBase_13()); +// if (!DOT()) return rejectInner(); +// if (!CLASS()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_5 = ReferenceType COLONCOLON TypeArguments? +// // Identifier +// //------------------------------------------------------------------- +// private boolean PrimaryBase_5() +// { +// begin(""); +// if (!ReferenceType()) return rejectInner(); +// if (!COLONCOLON()) return rejectInner(); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_6 = ClassType COLONCOLON TypeArguments? NEW +// //------------------------------------------------------------------- +// private boolean PrimaryBase_6() +// { +// begin(""); +// if (!ClassType()) return rejectInner(); +// if (!COLONCOLON()) return rejectInner(); +// TypeArguments(); +// if (!NEW()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_7 = ArrayType COLONCOLON NEW +// //------------------------------------------------------------------- +// private boolean PrimaryBase_7() +// { +// begin(""); +// if (!ArrayType()) return rejectInner(); +// if (!COLONCOLON()) return rejectInner(); +// if (!NEW()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_8 = DOT TypeArguments? Identifier Arguments +// //------------------------------------------------------------------- +// private boolean PrimaryBase_8() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_9 = COLONCOLON TypeArguments? Identifier +// //------------------------------------------------------------------- +// private boolean PrimaryBase_9() +// { +// begin(""); +// if (!COLONCOLON()) return rejectInner(); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_10 = LBRK Expression RBRK +// //------------------------------------------------------------------- +// private boolean PrimaryBase_10() +// { +// begin(""); +// if (!LBRK()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// if (!RBRK()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_11 = DOT (THIS / NEW ClassCreator / TypeArguments +// // Identifier Arguments / SUPER DOT TypeArguments? Identifier +// // Arguments / SUPER DOT Identifier / SUPER COLONCOLON +// // TypeArguments? Identifier) +// //------------------------------------------------------------------- +// private boolean PrimaryBase_11() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// if (!THIS() +// && !PrimaryBase_14() +// && !PrimaryBase_15() +// && !PrimaryBase_16() +// && !PrimaryBase_17() +// && !PrimaryBase_18() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_12 = (LBRK RBRK)* DOT CLASS +// //------------------------------------------------------------------- +// private boolean PrimaryBase_12() +// { +// begin(""); +// while (PrimaryBase_13()); +// if (!DOT()) return rejectInner(); +// if (!CLASS()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_13 = LBRK RBRK +// //------------------------------------------------------------------- +// private boolean PrimaryBase_13() +// { +// begin(""); +// if (!LBRK()) return rejectInner(); +// if (!RBRK()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_14 = NEW ClassCreator +// //------------------------------------------------------------------- +// private boolean PrimaryBase_14() +// { +// begin(""); +// if (!NEW()) return rejectInner(); +// if (!ClassCreator()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_15 = TypeArguments Identifier Arguments +// //------------------------------------------------------------------- +// private boolean PrimaryBase_15() +// { +// begin(""); +// if (!TypeArguments()) return rejectInner(); +// if (!Identifier()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_16 = SUPER DOT TypeArguments? Identifier Arguments +// //------------------------------------------------------------------- +// private boolean PrimaryBase_16() +// { +// begin(""); +// if (!SUPER()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_17 = SUPER DOT Identifier +// //------------------------------------------------------------------- +// private boolean PrimaryBase_17() +// { +// begin(""); +// if (!SUPER()) return rejectInner(); +// if (!DOT()) return rejectInner(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryBase_18 = SUPER COLONCOLON TypeArguments? Identifier +// //------------------------------------------------------------------- +// private boolean PrimaryBase_18() +// { +// begin(""); +// if (!SUPER()) return rejectInner(); +// if (!COLONCOLON()) return rejectInner(); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // PrimaryRest = DOT (TypeArguments? Identifier Arguments / Identifier +// // / NEW ClassCreator) / LBRK Expression RBRK / COLONCOLON +// // TypeArguments? Identifier ; +// //===================================================================== +// private boolean PrimaryRest() +// { +// begin("PrimaryRest"); +// if (PrimaryRest_0()) return accept(); +// if (PrimaryBase_10()) return accept(); +// if (PrimaryBase_9()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryRest_0 = DOT (TypeArguments? Identifier Arguments / +// // Identifier / NEW ClassCreator) +// //------------------------------------------------------------------- +// private boolean PrimaryRest_0() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// if (!PrimaryRest_1() +// && !Identifier() +// && !PrimaryBase_14() +// ) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // PrimaryRest_1 = TypeArguments? Identifier Arguments +// //------------------------------------------------------------------- +// private boolean PrimaryRest_1() +// { +// begin(""); +// TypeArguments(); +// if (!Identifier()) return rejectInner(); +// if (!Arguments()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // ParExpression = LPAR Expression RPAR ; +// //===================================================================== +// private boolean ParExpression() +// { +// begin("ParExpression"); +// if (!LPAR()) return reject(); +// if (!Expression()) return reject(); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ClassCreator = TypeArguments? Annotation* ClassTypeWithDiamond +// // Arguments ClassBody? ; +// //===================================================================== +// private boolean ClassCreator() +// { +// begin("ClassCreator"); +// TypeArguments(); +// while (Annotation()); +// if (!ClassTypeWithDiamond()) return reject(); +// if (!Arguments()) return reject(); +// ClassBody(); +// return accept(); +// } +// +// //===================================================================== +// // ClassTypeWithDiamond = Annotation* Identifier +// // TypeArgumentsOrDiamond? (DOT Annotation* Identifier +// // TypeArgumentsOrDiamond?)* ; +// //===================================================================== +// private boolean ClassTypeWithDiamond() +// { +// begin("ClassTypeWithDiamond"); +// while (Annotation()); +// if (!Identifier()) return reject(); +// TypeArgumentsOrDiamond(); +// while (ClassTypeWithDiamond_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ClassTypeWithDiamond_0 = DOT Annotation* Identifier +// // TypeArgumentsOrDiamond? +// //------------------------------------------------------------------- +// private boolean ClassTypeWithDiamond_0() +// { +// begin(""); +// if (!DOT()) return rejectInner(); +// while (Annotation()); +// if (!Identifier()) return rejectInner(); +// TypeArgumentsOrDiamond(); +// return acceptInner(); +// } +// +// //===================================================================== +// // TypeArgumentsOrDiamond = TypeArguments / LPOINT RPOINT !DOT ; +// //===================================================================== +// private boolean TypeArgumentsOrDiamond() +// { +// begin("TypeArgumentsOrDiamond"); +// if (TypeArguments()) return accept(); +// if (TypeArgumentsOrDiamond_0()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // TypeArgumentsOrDiamond_0 = LPOINT RPOINT !DOT +// //------------------------------------------------------------------- +// private boolean TypeArgumentsOrDiamond_0() +// { +// begin(""); +// if (!LPOINT()) return rejectInner(); +// if (!RPOINT()) return rejectInner(); +// if (!TypeArgumentsOrDiamond_1()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // TypeArgumentsOrDiamond_1 = !DOT +// //------------------------------------------------------------------- +// private boolean TypeArgumentsOrDiamond_1() +// { +// begin("","not DOT"); +// if (DOT()) return rejectPred(); +// return acceptPred(); +// } +// +// //===================================================================== +// // ArrayCreator = Type DimExpr+ Dim* / Type Dim+ ArrayInitializer ; +// //===================================================================== +// private boolean ArrayCreator() +// { +// begin("ArrayCreator"); +// if (ArrayCreator_0()) return accept(); +// if (ArrayCreator_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // ArrayCreator_0 = Type DimExpr+ Dim* +// //------------------------------------------------------------------- +// private boolean ArrayCreator_0() +// { +// begin(""); +// if (!Type()) return rejectInner(); +// if (!DimExpr()) return rejectInner(); +// while (DimExpr()); +// while (Dim()); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // ArrayCreator_1 = Type Dim+ ArrayInitializer +// //------------------------------------------------------------------- +// private boolean ArrayCreator_1() +// { +// begin(""); +// if (!Type()) return rejectInner(); +// if (!Dim()) return rejectInner(); +// while (Dim()); +// if (!ArrayInitializer()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // DimExpr = Annotation* LBRK Expression RBRK ; +// //===================================================================== +// private boolean DimExpr() +// { +// begin("DimExpr"); +// while (Annotation()); +// if (!LBRK()) return reject(); +// if (!Expression()) return reject(); +// if (!RBRK()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // Arguments = LPAR ArgumentList? RPAR ; +// //===================================================================== +// private boolean Arguments() +// { +// begin("Arguments"); +// if (!LPAR()) return reject(); +// ArgumentList(); +// if (!RPAR()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // ArgumentList = Expression (COMMA Expression)* ; +// //===================================================================== +// private boolean ArgumentList() +// { +// begin("ArgumentList"); +// if (!Expression()) return reject(); +// while (ArgumentList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ArgumentList_0 = COMMA Expression +// //------------------------------------------------------------------- +// private boolean ArgumentList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // UnaryExpression = (INC / DEC) (Primary / QualIdent) / PLUS +// // UnaryExpression / MINUS UnaryExpression / +// // UnaryExpressionNotPlusMinus ; +// //===================================================================== +// private boolean UnaryExpression() +// { +// begin("UnaryExpression"); +// if (StatementExpression_0()) return accept(); +// if (UnaryExpression_0()) return accept(); +// if (UnaryExpression_1()) return accept(); +// if (UnaryExpressionNotPlusMinus()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpression_0 = PLUS UnaryExpression +// //------------------------------------------------------------------- +// private boolean UnaryExpression_0() +// { +// begin(""); +// if (!PLUS()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpression_1 = MINUS UnaryExpression +// //------------------------------------------------------------------- +// private boolean UnaryExpression_1() +// { +// begin(""); +// if (!MINUS()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // UnaryExpressionNotPlusMinus = TILDE UnaryExpression / BANG +// // UnaryExpression / CastExpression / (Primary / QualIdent) (INC / +// // DEC)? ; +// //===================================================================== +// private boolean UnaryExpressionNotPlusMinus() +// { +// begin("UnaryExpressionNotPlusMinus"); +// if (UnaryExpressionNotPlusMinus_0()) return accept(); +// if (UnaryExpressionNotPlusMinus_1()) return accept(); +// if (CastExpression()) return accept(); +// if (UnaryExpressionNotPlusMinus_2()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpressionNotPlusMinus_0 = TILDE UnaryExpression +// //------------------------------------------------------------------- +// private boolean UnaryExpressionNotPlusMinus_0() +// { +// begin(""); +// if (!TILDE()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpressionNotPlusMinus_1 = BANG UnaryExpression +// //------------------------------------------------------------------- +// private boolean UnaryExpressionNotPlusMinus_1() +// { +// begin(""); +// if (!BANG()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpressionNotPlusMinus_2 = (Primary / QualIdent) (INC / +// // DEC)? +// //------------------------------------------------------------------- +// private boolean UnaryExpressionNotPlusMinus_2() +// { +// begin(""); +// if (!Primary() +// && !QualIdent() +// ) return rejectInner(); +// UnaryExpressionNotPlusMinus_3(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // UnaryExpressionNotPlusMinus_3 = INC / DEC +// //------------------------------------------------------------------- +// private boolean UnaryExpressionNotPlusMinus_3() +// { +// begin(""); +// if (INC()) return acceptInner(); +// if (DEC()) return acceptInner(); +// return rejectInner(); +// } +// +// //===================================================================== +// // CastExpression = LPAR PrimitiveType RPAR UnaryExpression / LPAR +// // ReferenceType AdditionalBound* RPAR LambdaExpression / LPAR +// // ReferenceType AdditionalBound* RPAR UnaryExpressionNotPlusMinus +// // ; +// //===================================================================== +// private boolean CastExpression() +// { +// begin("CastExpression"); +// if (CastExpression_0()) return accept(); +// if (CastExpression_1()) return accept(); +// if (CastExpression_2()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // CastExpression_0 = LPAR PrimitiveType RPAR UnaryExpression +// //------------------------------------------------------------------- +// private boolean CastExpression_0() +// { +// begin(""); +// if (!LPAR()) return rejectInner(); +// if (!PrimitiveType()) return rejectInner(); +// if (!RPAR()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // CastExpression_1 = LPAR ReferenceType AdditionalBound* RPAR +// // LambdaExpression +// //------------------------------------------------------------------- +// private boolean CastExpression_1() +// { +// begin(""); +// if (!LPAR()) return rejectInner(); +// if (!ReferenceType()) return rejectInner(); +// while (AdditionalBound()); +// if (!RPAR()) return rejectInner(); +// if (!LambdaExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // CastExpression_2 = LPAR ReferenceType AdditionalBound* RPAR +// // UnaryExpressionNotPlusMinus +// //------------------------------------------------------------------- +// private boolean CastExpression_2() +// { +// begin(""); +// if (!LPAR()) return rejectInner(); +// if (!ReferenceType()) return rejectInner(); +// while (AdditionalBound()); +// if (!RPAR()) return rejectInner(); +// if (!UnaryExpressionNotPlusMinus()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // InfixExpression = UnaryExpression (InfixOperator UnaryExpression / +// // INSTANCEOF ReferenceType)* ; +// //===================================================================== +// private boolean InfixExpression() +// { +// begin("InfixExpression"); +// if (!UnaryExpression()) return reject(); +// while (InfixExpression_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // InfixExpression_0 = InfixOperator UnaryExpression / INSTANCEOF +// // ReferenceType +// //------------------------------------------------------------------- +// private boolean InfixExpression_0() +// { +// begin(""); +// if (InfixExpression_1()) return acceptInner(); +// if (InfixExpression_2()) return acceptInner(); +// return rejectInner(); +// } +// +// //------------------------------------------------------------------- +// // InfixExpression_1 = InfixOperator UnaryExpression +// //------------------------------------------------------------------- +// private boolean InfixExpression_1() +// { +// begin(""); +// if (!InfixOperator()) return rejectInner(); +// if (!UnaryExpression()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // InfixExpression_2 = INSTANCEOF ReferenceType +// //------------------------------------------------------------------- +// private boolean InfixExpression_2() +// { +// begin(""); +// if (!INSTANCEOF()) return rejectInner(); +// if (!ReferenceType()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // InfixOperator = OROR / ANDAND / OR / HAT / AND / EQUAL / NOTEQUAL / +// // LT / GT / LE / GE / SL / SR / BSR / PLUS / MINUS / STAR / DIV / +// // MOD ; +// //===================================================================== +// private boolean InfixOperator() +// { +// begin("InfixOperator"); +// if (OROR()) return accept(); +// if (ANDAND()) return accept(); +// if (OR()) return accept(); +// if (HAT()) return accept(); +// if (AND()) return accept(); +// if (EQUAL()) return accept(); +// if (NOTEQUAL()) return accept(); +// if (LT()) return accept(); +// if (GT()) return accept(); +// if (LE()) return accept(); +// if (GE()) return accept(); +// if (SL()) return accept(); +// if (SR()) return accept(); +// if (BSR()) return accept(); +// if (PLUS()) return accept(); +// if (MINUS()) return accept(); +// if (STAR()) return accept(); +// if (DIV()) return accept(); +// if (MOD()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ConditionalExpression = InfixExpression (QUERY Expression COLON +// // Expression)* ; +// //===================================================================== +// private boolean ConditionalExpression() +// { +// begin("ConditionalExpression"); +// if (!InfixExpression()) return reject(); +// while (ConditionalExpression_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // ConditionalExpression_0 = QUERY Expression COLON Expression +// //------------------------------------------------------------------- +// private boolean ConditionalExpression_0() +// { +// begin(""); +// if (!QUERY()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// if (!COLON()) return rejectInner(); +// if (!Expression()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // AssignmentExpression = Assignment / ConditionalExpression ; +// //===================================================================== +// private boolean AssignmentExpression() +// { +// begin("AssignmentExpression"); +// if (Assignment()) return accept(); +// if (ConditionalExpression()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // Assignment = LeftHandSide AssignmentOperator Expression ; +// //===================================================================== +// private boolean Assignment() +// { +// begin("Assignment"); +// if (!LeftHandSide()) return reject(); +// if (!AssignmentOperator()) return reject(); +// if (!Expression()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // LeftHandSide = Primary / QualIdent ; +// //===================================================================== +// private boolean LeftHandSide() +// { +// begin("LeftHandSide"); +// if (Primary()) return accept(); +// if (QualIdent()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // AssignmentOperator = EQU / STAREQU / DIVEQU / MODEQU / PLUSEQU / +// // MINUSEQU / SLEQU / SREQU / BSREQU / ANDEQU / HATEQU / OREQU ; +// //===================================================================== +// private boolean AssignmentOperator() +// { +// begin("AssignmentOperator"); +// if (EQU()) return accept(); +// if (STAREQU()) return accept(); +// if (DIVEQU()) return accept(); +// if (MODEQU()) return accept(); +// if (PLUSEQU()) return accept(); +// if (MINUSEQU()) return accept(); +// if (SLEQU()) return accept(); +// if (SREQU()) return accept(); +// if (BSREQU()) return accept(); +// if (ANDEQU()) return accept(); +// if (HATEQU()) return accept(); +// if (OREQU()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // LambdaExpression = LambdaParameters ARROW LambdaBody ; +// //===================================================================== +// private boolean LambdaExpression() +// { +// begin("LambdaExpression"); +// if (!LambdaParameters()) return reject(); +// if (!ARROW()) return reject(); +// if (!LambdaBody()) return reject(); +// return accept(); +// } +// +// //===================================================================== +// // LambdaParameters = Identifier / LPAR FormalParameterList? RPAR / +// // LPAR InferredFormalParameterList RPAR ; +// //===================================================================== +// private boolean LambdaParameters() +// { +// begin("LambdaParameters"); +// if (Identifier()) return accept(); +// if (LambdaParameters_0()) return accept(); +// if (LambdaParameters_1()) return accept(); +// return reject(); +// } +// +// //------------------------------------------------------------------- +// // LambdaParameters_0 = LPAR FormalParameterList? RPAR +// //------------------------------------------------------------------- +// private boolean LambdaParameters_0() +// { +// begin(""); +// if (!LPAR()) return rejectInner(); +// FormalParameterList(); +// if (!RPAR()) return rejectInner(); +// return acceptInner(); +// } +// +// //------------------------------------------------------------------- +// // LambdaParameters_1 = LPAR InferredFormalParameterList RPAR +// //------------------------------------------------------------------- +// private boolean LambdaParameters_1() +// { +// begin(""); +// if (!LPAR()) return rejectInner(); +// if (!InferredFormalParameterList()) return rejectInner(); +// if (!RPAR()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // InferredFormalParameterList = Identifier (COMMA Identifier)* ; +// //===================================================================== +// private boolean InferredFormalParameterList() +// { +// begin("InferredFormalParameterList"); +// if (!Identifier()) return reject(); +// while (InferredFormalParameterList_0()); +// return accept(); +// } +// +// //------------------------------------------------------------------- +// // InferredFormalParameterList_0 = COMMA Identifier +// //------------------------------------------------------------------- +// private boolean InferredFormalParameterList_0() +// { +// begin(""); +// if (!COMMA()) return rejectInner(); +// if (!Identifier()) return rejectInner(); +// return acceptInner(); +// } +// +// //===================================================================== +// // LambdaBody = Expression / Block ; +// //===================================================================== +// private boolean LambdaBody() +// { +// begin("LambdaBody"); +// if (Expression()) return accept(); +// if (Block()) return accept(); +// return reject(); +// } +// +// //===================================================================== +// // ConstantExpression = Expression ; +// //===================================================================== +// private boolean ConstantExpression() +// { +// begin("ConstantExpression"); +// if (!Expression()) return reject(); +// return accept(); +// } +// +//} \ No newline at end of file diff --git a/src/com/norswap/autumn/test/parsing/Common.java b/src/com/norswap/autumn/test/parsing/Common.java new file mode 100644 index 0000000..a1d74d5 --- /dev/null +++ b/src/com/norswap/autumn/test/parsing/Common.java @@ -0,0 +1,92 @@ +package com.norswap.autumn.test.parsing; + +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.ParseResult; +import com.norswap.autumn.parsing.ParseTree; +import com.norswap.autumn.parsing.expressions.common.ParsingExpression; +import com.norswap.autumn.test.TestFailed; + +public final class Common +{ + //////////////////////////////////////////////////////////////////////////////////////////////// + + public static ParseResult parse(ParsingExpression pe, String string) + { + return Autumn.parseString(Autumn.grammarFromExpression(pe), string); + } + + // --------------------------------------------------------------------------------------------- + + public static void ensureMatch(ParsingExpression pe, String string) + { + ensureMatch(parse(pe, string)); + } + + // --------------------------------------------------------------------------------------------- + + public static void ensureMatch(ParseResult result) + { + if (!result.succeeded) + { + throw new TestFailed("expecting match, got failure"); + } + + if (!result.matched) + { + throw new TestFailed( + "expecting match, got success with end position: " + result.endPosition); + } + } + + + // --------------------------------------------------------------------------------------------- + + public static void ensureSuccess(ParsingExpression pe, String string) + { + ensureSuccess(parse(pe, string)); + } + + // --------------------------------------------------------------------------------------------- + + public static void ensureSuccess(ParseResult result) + { + if (!result.succeeded) + { + throw new TestFailed("expecting success, got failure"); + } + } + + // --------------------------------------------------------------------------------------------- + + public static void ensureFail(ParsingExpression pe, String string) + { + ensureFail(parse(pe, string)); + } + + // --------------------------------------------------------------------------------------------- + + public static void ensureFail(ParseResult result) + { + if (result.matched) + { + throw new TestFailed("expecting failure, got match"); + } + + if (result.succeeded) + { + throw new TestFailed( + "expecting failure, got success with end position: " + result.endPosition); + } + } + + // --------------------------------------------------------------------------------------------- + + public static ParseTree tree(ParsingExpression pe, String string) + { + ParseResult result = parse(pe, string); + ensureMatch(result); + return result.tree; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// +} diff --git a/src/com/norswap/autumn/test/parsing/FeatureTests.java b/src/com/norswap/autumn/test/parsing/FeatureTests.java index c5f3c00..83f4a01 100644 --- a/src/com/norswap/autumn/test/parsing/FeatureTests.java +++ b/src/com/norswap/autumn/test/parsing/FeatureTests.java @@ -1,20 +1,25 @@ package com.norswap.autumn.test.parsing; import com.norswap.autumn.parsing.ParseTree; -import com.norswap.autumn.parsing.Parser; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; import com.norswap.autumn.test.Ensure; import com.norswap.autumn.test.TestRunner; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; + +import java.util.List; import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; -import static com.norswap.autumn.test.TestConfiguration.parser; +import static com.norswap.autumn.test.parsing.Common.*; import static com.norswap.autumn.test.parsing.ParseTreeBuilder.$; public final class FeatureTests { //////////////////////////////////////////////////////////////////////////////////////////////// + ParsingExpression pe; + + ParseTree tree, expected; + Runnable[] tests = { this::testToken, this::testLeftRecursive, @@ -90,45 +95,45 @@ void doRun() public void testToken() { - ParsingExpression expr = oneMore(token(literal("*"))); - - Ensure.match("*", expr); - Ensure.match("* \n\t", expr); - Ensure.match("* \n\t*** * * \n\t", expr); - Ensure.match("* // hello lol", expr); - Ensure.match("* /* is diz real life? */", expr); - Ensure.match("* /* nested /* amazing innit? */ lol */", expr); - Ensure.fails(" ", expr); - Ensure.match(" *", expr); + pe = oneMore(token(literal("*"))); + + ensureMatch(pe, "*"); + ensureMatch(pe, "* \n\t"); + ensureMatch(pe, "* \n\t*** * * \n\t"); + ensureMatch(pe, "* // hello lol"); + ensureMatch(pe, "* /* is diz real life? */"); + ensureMatch(pe, "* /* nested /* amazing innit? */ lol */"); + ensureFail(pe, " "); + ensureMatch(pe, " *"); } // --------------------------------------------------------------------------------------------- public void testLeftRecursive() { - ParsingExpression expr = recursive$("expr", choice( + pe = recursive$("expr", choice( leftRecursive(reference("expr"), literal("*")), num.deepCopy())); - Ensure.match("1", expr); - Ensure.match("1*", expr); - Ensure.match("1***", expr); + ensureMatch(pe, "1"); + ensureMatch(pe, "1*"); + ensureMatch(pe, "1***"); } // --------------------------------------------------------------------------------------------- public void testLeftAssociative() { - ParsingExpression expr = recursive$("expr", choice( + pe = recursive$("expr", choice( leftAssociative(reference("expr"), literal("+"), reference("expr")), leftAssociative(reference("expr"), literal("*"), reference("expr")), num.deepCopy())); - Ensure.match("1", expr); - Ensure.match("1+1", expr); - Ensure.match("1*1", expr); - Ensure.match("1+1+1+1", expr); - Ensure.match("1*1+1*1", expr); + ensureMatch(pe, "1"); + ensureMatch(pe, "1+1"); + ensureMatch(pe, "1*1"); + ensureMatch(pe, "1+1+1+1"); + ensureMatch(pe, "1*1+1*1"); } @@ -136,29 +141,16 @@ public void testLeftAssociative() public void testCapture() { - ParsingExpression expr = captureText("a", oneMore(literal("a"))); - - Parser parser = parser("aaa"); - parser.parse(expr); - - ParseTree tree = parser.tree(); - ParseTree aTree = tree.get("a"); - - Ensure.equals(aTree.value, "aaa"); + tree = tree(captureText("a", oneMore(literal("a"))), "aaa"); + Ensure.equals(tree.get("a").value, "aaa"); } // --------------------------------------------------------------------------------------------- public void testMultipleCapture() { - ParsingExpression expr = sequence( - oneMore(captureTextGrouped("a", literal("a")))); - - Parser parser = parser("aaa"); - parser.parse(expr); - - ParseTree tree = parser.tree(); - Array aResults = tree.get("a").children; + tree = tree(sequence(oneMore(captureTextGrouped("a", literal("a")))), "aaa"); + List aResults = tree.group("a"); Ensure.equals(aResults.size(), 3); @@ -182,17 +174,26 @@ public void testRightAssociativity() for (ParsingExpression expr: new ParsingExpression[]{expr1, expr2}) { - Parser parser = parser("1+2+3"); - parser.parse(expr); - Ensure.equals(parser.endPosition(), 5); - ParseTree tree = parser.tree(); + tree = tree(expr, "1+2+3"); - ParseTree expected = $($("+", + expected = $($("+", $("left", $("num", "1")), $("right", $("+", $("left", $("num", "2")), $("right", $("num", "3")))))); + // [[+: [ + // left: [num: "1"], + // right: [[+: [ + // left: [num: "2"], + // right: [num: "3"]]]]]]], + // + // expected: [+: [ + // left: [num: "1"], + // right: [+: [ + // left: [num: "2"], + // right: [num: "3"]]]]] + Ensure.equals(tree, expected); } } @@ -203,16 +204,13 @@ public void testLeftAssociativity() { // NOTE(norswap): it also works if leftAssociative is nested inside the capture - ParsingExpression expr = recursive$("expr", choice( + pe = recursive$("expr", choice( leftAssociative(plus.deepCopy()), num.deepCopy())); - Parser parser = parser("1+2+3"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - ParseTree tree = parser.tree(); + tree = tree(pe, "1+2+3"); - ParseTree expected = $($("+", + expected = $($("+", $("left", $("+", $("left", $("num", "1")), $("right", $("num", "2")))), @@ -227,18 +225,15 @@ public void testPrecedence() { // NOTE(norswap): it also works if leftAssociative is nested inside the capture - ParsingExpression expr = recursive$("expr", choice( + pe = recursive$("expr", choice( precedence(1, leftAssociative(plus.deepCopy())), precedence(2, leftAssociative(mult.deepCopy())), precedence(3, leftAssociative(exp.deepCopy())), num.deepCopy())); - Parser parser = parser("1+2*3"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - ParseTree tree = parser.tree(); + tree = tree(pe, "1+2*3"); - ParseTree expected = $($("+", + expected = $($("+", $("left", $("num", "1")), $("right", $("*", $("left", $("num", "2")), @@ -246,10 +241,7 @@ public void testPrecedence() Ensure.equals(tree, expected); - parser = parser("1*2+3"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - tree = parser.tree(); + tree = tree(pe, "1*2+3"); expected = $($("+", $("left", $("*", @@ -264,19 +256,19 @@ public void testPrecedence() public void testExpression() { - ParsingExpression expr = recursive$("expr", cluster( - exprLeftAssoc(1, plus.deepCopy()), - exprLeftAssoc(1, minus.deepCopy()), - exprLeftAssoc(2, mult.deepCopy()), - exprLeftAssoc(2, div.deepCopy()), - exprAlt(3, num.deepCopy()))); - - Parser parser = parser("1+2-3+4*5/6*7+8"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - ParseTree tree = parser.tree(); - - ParseTree expected = $($("+", + pe = recursive$("expr", cluster( + groupLeftAssoc(1, + plus.deepCopy(), + minus.deepCopy()), + groupLeftAssoc(2, + mult.deepCopy(), + div.deepCopy()), + group(3, + num.deepCopy()))); + + tree = tree(pe, "1+2-3+4*5/6*7+8"); + + expected = $($("+", $("left", $("+", $("left", $("-", $("left", $("+", @@ -299,19 +291,19 @@ public void testExpression2() { // NOTE(norswap): Same as testExpression() but + and - are now right-associative. - ParsingExpression expr = recursive$("expr", cluster( - exprLeftRecur(1, plus.deepCopy()), - exprLeftRecur(1, minus.deepCopy()), - exprLeftAssoc(2, mult.deepCopy()), - exprLeftAssoc(2, div.deepCopy()), - exprAlt(3, num.deepCopy()))); + pe = recursive$("expr", cluster( + groupLeftRec(1, + plus.deepCopy(), + minus.deepCopy()), + groupLeftAssoc(2, + mult.deepCopy(), + div.deepCopy()), + group(3, + num.deepCopy()))); - Parser parser = parser("1+2-3+4*5/6*7+8"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - ParseTree tree = parser.tree(); + tree = tree(pe, "1+2-3+4*5/6*7+8"); - ParseTree expected = $($("+", + expected = $($("+", $("left", $("num", "1")), $("right", $("-", $("left", $("num", "2")), @@ -334,19 +326,19 @@ public void testExpression3() { // NOTE(norswap): Same as testExpression() but * and / are now right-associative. - ParsingExpression expr = recursive$("expr", cluster( - exprLeftAssoc(1, plus.deepCopy()), - exprLeftAssoc(1, minus.deepCopy()), - exprLeftRecur(2, mult.deepCopy()), - exprLeftRecur(2, div.deepCopy()), - exprAlt(3, num.deepCopy()))); + pe = recursive$("expr", cluster( + groupLeftAssoc(1, + plus.deepCopy(), + minus.deepCopy()), + groupLeftRec(2, + mult.deepCopy(), + div.deepCopy()), + group(3, + num.deepCopy()))); - Parser parser = parser("1+2-3+4*5/6*7+8"); - parser.parse(expr); - Ensure.ensure(parser.succeeded()); - ParseTree tree = parser.tree(); + tree = tree(pe, "1+2-3+4*5/6*7+8"); - ParseTree expected = $($("+", + expected = $($("+", $("left", $("+", $("left", $("-", $("left", $("+", diff --git a/src/com/norswap/autumn/test/parsing/JavaGrammarTest.java b/src/com/norswap/autumn/test/parsing/JavaGrammarTest.java index b4a949b..ab96a4b 100644 --- a/src/com/norswap/autumn/test/parsing/JavaGrammarTest.java +++ b/src/com/norswap/autumn/test/parsing/JavaGrammarTest.java @@ -1,21 +1,17 @@ package com.norswap.autumn.test.parsing; -import com.norswap.autumn.parsing.Parser; -import com.norswap.autumn.parsing.ParserConfiguration; +import com.norswap.autumn.Autumn; +import com.norswap.autumn.parsing.Grammar; +import com.norswap.autumn.parsing.ParseResult; import com.norswap.autumn.parsing.expressions.instrument.StackTrace; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.Source; -import com.norswap.autumn.parsing.graph.FirstCalculator; -import com.norswap.autumn.parsing.graph.FunctionalTransformer; -import com.norswap.autumn.parsing.graph.LeftRecursionBreaker; -import com.norswap.autumn.parsing.graph.nullability.NullabilityCalculator; -import com.norswap.autumn.parsing.support.GrammarDriver; -import com.norswap.autumn.util.Glob; +import com.norswap.autumn.parsing.graph.Walks; +import com.norswap.util.Glob; +import com.norswap.util.graph_visit.GraphTransformer; -import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.Arrays; +import java.nio.file.Paths; public final class JavaGrammarTest { @@ -23,71 +19,22 @@ public final class JavaGrammarTest private static String grammarFile = "src/com/norswap/autumn/test/grammars/Java8.autumn"; + private static boolean trace = false; + //////////////////////////////////////////////////////////////////////////////////////////////// public static void main(String[] args) throws IOException { - ParsingExpression[] rules = GrammarDriver.compile(grammarFile); - - NullabilityCalculator nullCalc = new NullabilityCalculator(); - nullCalc.run(rules); - FirstCalculator.nullCalc = nullCalc; - - LeftRecursionBreaker.breakCycles(rules); - - ParsingExpression root = rules[0]; - - root = FunctionalTransformer.apply(root, JavaGrammarTest::transform, true); - - ParsingExpression whitespace = Arrays.stream(rules) - .filter(rule -> "Spacing".equals(rule.name())) - .findFirst().get(); - - parseDirectory("../guava", root, whitespace); - } - - // --------------------------------------------------------------------------------------------- + Grammar grammar = Autumn.grammarFromFile(grammarFile); - private static void parseDirectory( - String directory, ParsingExpression root, ParsingExpression whitespace) - throws IOException - { - for (Path path: Glob.glob("**/*.java", new File(directory).toPath())) + if (trace) { - ParserConfiguration config = new ParserConfiguration(); - config.whitespace = () -> whitespace; - - parseFile(path.toString(), root, config); + grammar.walk(GraphTransformer.from(JavaGrammarTest::transform, Walks.inPlace)); } - } - - // --------------------------------------------------------------------------------------------- - public static void parseFile( - String file, ParsingExpression root, ParserConfiguration config) - { - try - { - Source source = Source.fromFile(file); - Parser parser = new Parser(source, config); - parser.parse(root); - - if (parser.succeeded()) - { - //System.err.println(filename); - //System.out.println(parser.tree()); - } - else - { - System.err.println(file); - parser.report(); - System.err.println(); - System.exit(-1); - } - } - catch (IOException e) + for (Path path: Glob.glob("**/*.java", Paths.get("../guava"))) { - System.out.println("Could not read file: " + file); + ParseResult result = Autumn.parseFile(grammar, path.toString()); } } diff --git a/src/com/norswap/autumn/test/parsing/OperatorTests.java b/src/com/norswap/autumn/test/parsing/OperatorTests.java index dac6876..9158770 100644 --- a/src/com/norswap/autumn/test/parsing/OperatorTests.java +++ b/src/com/norswap/autumn/test/parsing/OperatorTests.java @@ -1,11 +1,10 @@ package com.norswap.autumn.test.parsing; import com.norswap.autumn.parsing.expressions.common.ParsingExpression; -import com.norswap.autumn.parsing.Source; -import com.norswap.autumn.test.Ensure; import com.norswap.autumn.test.TestRunner; import static com.norswap.autumn.parsing.ParsingExpressionFactory.*; +import static com.norswap.autumn.test.parsing.Common.*; public final class OperatorTests { @@ -13,8 +12,6 @@ public final class OperatorTests boolean testDumb = false; - Source src; - ParsingExpression pe; Runnable[] tests = { @@ -71,18 +68,14 @@ public ParsingExpression pe(ParsingExpression pe) public void testLiteral() { - pe = pe(literal("test")); - src = Source.fromString("test"); - Ensure.match(src, pe); + ensureMatch(pe(literal("test")), "test"); } // --------------------------------------------------------------------------------------------- public void testAny() { - pe = pe(any()); - src = Source.fromString("x"); - Ensure.match(src, pe); + ensureMatch(pe(any()), "x"); } // --------------------------------------------------------------------------------------------- @@ -90,12 +83,8 @@ public void testAny() public void testCharRange() { pe = pe(charRange('a', 'c')); - - src = Source.fromString("a"); - Ensure.match(src, pe); - - src = Source.fromString("c"); - Ensure.match(src, pe); + ensureMatch(pe, "a"); + ensureMatch(pe, "c"); } // --------------------------------------------------------------------------------------------- @@ -103,21 +92,15 @@ public void testCharRange() public void testCharSet() { pe = pe(charSet("abc")); - - src = Source.fromString("a"); - Ensure.match(src, pe); - - src = Source.fromString("c"); - Ensure.match(src, pe); + ensureMatch(pe, "a"); + ensureMatch(pe, "c"); } // --------------------------------------------------------------------------------------------- public void testSequence() { - pe = pe(sequence(literal("a"), literal("b"), literal("c"))); - src = Source.fromString("abc"); - Ensure.match(src, pe); + ensureMatch(pe(sequence(literal("a"), literal("b"), literal("c"))), "abc"); } // --------------------------------------------------------------------------------------------- @@ -125,12 +108,8 @@ public void testSequence() public void testChoice() { pe = pe(choice(literal("a"), literal("b"), literal("c"))); - - src = Source.fromString("a"); - Ensure.match(src, pe); - - src = Source.fromString("c"); - Ensure.match(src, pe); + ensureMatch(pe, "a"); + ensureMatch(pe, "c"); } // --------------------------------------------------------------------------------------------- @@ -138,12 +117,8 @@ public void testChoice() public void testOptional() { pe = pe(optional(literal("a"))); - - src = Source.fromString("a"); - Ensure.match(src, pe); - - src = Source.fromString(""); - Ensure.match(src, pe); + ensureMatch(pe, "a"); + ensureMatch(pe, ""); } // --------------------------------------------------------------------------------------------- @@ -151,12 +126,8 @@ public void testOptional() public void testZeroMore() { pe = pe(zeroMore(literal("a"))); - - src = Source.fromString("aaaa"); - Ensure.match(src, pe); - - src = Source.fromString(""); - Ensure.match(src, pe); + ensureMatch(pe, "aaaa"); + ensureMatch(pe, ""); } // --------------------------------------------------------------------------------------------- @@ -164,21 +135,15 @@ public void testZeroMore() public void testOneMore() { pe = pe(oneMore(literal("a"))); - - src = Source.fromString("aaaa"); - Ensure.match(src, pe); - - src = Source.fromString(""); - Ensure.fails(src, pe); + ensureMatch(pe, "aaaa"); + ensureFail(pe, ""); } // --------------------------------------------------------------------------------------------- public void testLookahead() { - pe = pe(lookahead(literal("test"))); - src = Source.fromString("test"); - Ensure.noFail(src, pe); + ensureSuccess(pe(lookahead(literal("test"))), "test"); } // --------------------------------------------------------------------------------------------- @@ -186,12 +151,8 @@ public void testLookahead() public void testNot() { pe = pe(not(literal("test"))); - - src = Source.fromString("bird"); - Ensure.noFail(src, pe); - - src = Source.fromString("test"); - Ensure.fails(src, pe); + ensureSuccess(pe, "bird"); + ensureFail(pe, "test"); } // --------------------------------------------------------------------------------------------- @@ -199,8 +160,7 @@ public void testNot() public void testLongestMatch() { pe = pe(longestMatch(literal("a"), literal("ab"), literal("z"), literal("abc"))); - src = Source.fromString("abc"); - Ensure.match(src, pe); + ensureMatch(pe, "abc"); } // --------------------------------------------------------------------------------------------- @@ -212,11 +172,8 @@ public void testCut() pe = pe(cuttable("test", sequence(cut("test"), literal("a")), literal("b"))); testDumb = oldTestDumb; - src = Source.fromString("a"); - Ensure.match(src, pe); - - src = Source.fromString("b"); - Ensure.fails(src, pe); + ensureMatch(pe, "a"); + ensureFail(pe, "b"); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/com/norswap/autumn/test/parsing/ParseTreeBuilder.java b/src/com/norswap/autumn/test/parsing/ParseTreeBuilder.java index 958ff66..c933d6b 100644 --- a/src/com/norswap/autumn/test/parsing/ParseTreeBuilder.java +++ b/src/com/norswap/autumn/test/parsing/ParseTreeBuilder.java @@ -1,7 +1,7 @@ package com.norswap.autumn.test.parsing; import com.norswap.autumn.parsing.ParseTree; -import com.norswap.autumn.util.Array; +import com.norswap.util.Array; public class ParseTreeBuilder { @@ -16,19 +16,19 @@ public class ParseTreeBuilder // --------------------------------------------------------------------------------------------- - public static ParseTree $(String name, ParseTree... children) + public static ParseTree $(String accessor, ParseTree... children) { ParseTree tree = new ParseTree(); - tree.name = name; + tree.accessor = accessor; tree.children = new Array<>(children); return tree; } // --------------------------------------------------------------------------------------------- - public static ParseTree $(String name, String value, ParseTree... children) + public static ParseTree $(String accessor, String value, ParseTree... children) { - ParseTree tree = $(name, children); + ParseTree tree = $(accessor, children); tree.value = value; return tree; } diff --git a/src/com/norswap/autumn/util/Array.java b/src/com/norswap/autumn/util/Array.java deleted file mode 100644 index da77a04..0000000 --- a/src/com/norswap/autumn/util/Array.java +++ /dev/null @@ -1,378 +0,0 @@ -package com.norswap.autumn.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.function.Function; - -/** - * A dynamic array to serve as minimal substitute to ArrayList. - * - * The idea to to be able to implement functions not implemented by ArrayList, such as {@link - * #truncate}. - */ -public final class Array implements Iterable, Cloneable -{ - //////////////////////////////////////////////////////////////////////////////////////////////// - - public static int DEFAULT_SIZE = 4; - public static double GROWTH_FACTOR = 2.0f; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - private Object[] array; - private int next; - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public Array(T[] array, int next) - { - this.array = array; - this.next = next; - } - - public Array(T[] array) - { - this.array = array; - this.next = array.length; - } - - public Array(int size) - { - array = new Object[size]; - } - - public Array() - { - array = new Object[DEFAULT_SIZE]; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public boolean isEmpty() - { - return next == 0; - } - - // --------------------------------------------------------------------------------------------- - - public int size() - { - return next; - } - - // --------------------------------------------------------------------------------------------- - - public void add(T t) - { - if (next == array.length) - { - grow(array.length + 1); - } - - array[next++] = t; - } - - // --------------------------------------------------------------------------------------------- - - public T get(int index) - { - return Caster.cast(array[index]); - } - - // --------------------------------------------------------------------------------------------- - - public void set(int index, T t) - { - array[index] = t; - } - - // --------------------------------------------------------------------------------------------- - - public void grow(int capacity) - { - int size = array.length; - - while (size < capacity) - { - size = (int) (size * GROWTH_FACTOR); - } - - array = Arrays.copyOf(array, size); - } - - // --------------------------------------------------------------------------------------------- - - public void truncate(int size) - { - for (int i = size; i < next; ++i) - { - array[i] = null; - } - - if (size < next) - { - next = size; - } - } - - // --------------------------------------------------------------------------------------------- - - public void clear() - { - truncate(0); - } - - // --------------------------------------------------------------------------------------------- - - public void addAll(Collection collection) - { - collection.forEach(this::add); - } - - // --------------------------------------------------------------------------------------------- - - public void addAll(Array array) - { - array.forEach(this::add); - } - - // --------------------------------------------------------------------------------------------- - - public void push(T t) - { - add(t); - } - - // --------------------------------------------------------------------------------------------- - - public T pop() - { - return Caster.cast(array[--next]); - } - - // --------------------------------------------------------------------------------------------- - - public T popOrNull() - { - return next == 0 ? null : pop(); - } - - // --------------------------------------------------------------------------------------------- - - public T peek() - { - return Caster.cast(array[next - 1]); - } - - // --------------------------------------------------------------------------------------------- - - public T peekOrNull() - { - return next == 0 ? null : peek(); - } - - // --------------------------------------------------------------------------------------------- - - public void remove(int index) - { - System.arraycopy(array, index + 1, array, index, next - index - 1); - --next; - } - - // --------------------------------------------------------------------------------------------- - - public boolean remove(T t) - { - for (int i = 0; i < next; ++i) - { - if (array[i].equals(t)) - { - remove(i); - return true; - } - } - - return false; - } - - // --------------------------------------------------------------------------------------------- - - public boolean removeFromEnd(T t) - { - for (int i = next - 1; i >= 0; --i) - { - if (array[i].equals(t)) - { - remove(i); - return true; - } - } - - return false; - } - - // --------------------------------------------------------------------------------------------- - - public int indexOf(T t) - { - for (int i = 0; i < next; ++i) - { - if (t == null ? array[i] == null : t.equals(array[i])) - { - return i; - } - } - - return -1; - } - - // --------------------------------------------------------------------------------------------- - - public boolean contains(T t) - { - return indexOf(t) >= 0; - } - - // --------------------------------------------------------------------------------------------- - - @Override - public Iterator iterator() - { - return new Iterator() - { - private int index; - - @Override - public boolean hasNext() - { - return index < next; - } - - @Override - public T next() - { - return Caster.cast(array[index++]); - } - }; - } - - // --------------------------------------------------------------------------------------------- - - public Iterable reverseIterable() - { - return this::reverseIterator; - } - - // --------------------------------------------------------------------------------------------- - - public Iterator reverseIterator() - { - return new Iterator() - { - private int index = next - 1; - - @Override - public boolean hasNext() - { - return index >= 0; - } - - @Override - public T next() - { - return Caster.cast(array[index--]); - } - }; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - public T[] toArray(Function supplier) - { - T[] out = supplier.apply(next); - System.arraycopy(array, 0, out, 0, next); - return out; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public String toString() - { - StringBuilder b = new StringBuilder(); - b.append("["); - - for (int i = 0; i < next; ++i) - { - b.append(array[i]); - b.append(", "); - } - - if (next > 0) - { - b.setLength(b.length() - 2); - } - - b.append("]"); - return b.toString(); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - @SuppressWarnings({"unchecked", "CloneDoesntCallSuperClone"}) - public Array clone() - { - return new Array(array.clone(), next); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public boolean equals(Object o) - { - // part auto-generated, part lifted from Arrays.equals - - if (this == o) - return true; - - if (o == null || getClass() != o.getClass()) - return false; - - Array array1 = (Array) o; - - if (next != array1.next) - return false; - - for (int i = 0; i < next; ++i) - { - Object o1 = array[i]; - Object o2 = array1.array[i]; - - if (!(o1==null ? o2==null : o1.equals(o2))) - return false; - } - - return true; - } - - // --------------------------------------------------------------------------------------------- - - @Override - public int hashCode() - { - // lifted from Arrays.hashCode - - int result = 1; - - for (T t: this) - { - result = 31 * result + (t == null ? 0 : t.hashCode()); - } - - return result; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/com/norswap/autumn/util/FlagFactory.java b/src/com/norswap/autumn/util/FlagFactory.java deleted file mode 100644 index e094f4d..0000000 --- a/src/com/norswap/autumn/util/FlagFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.norswap.autumn.util; - -public class FlagFactory -{ - private int next; - - public int next() - { - if (next >= 32) - { - throw new RuntimeException("Flag space (32 flags) exhausted."); - } - - return 1 << next++; - } -} diff --git a/src/com/norswap/autumn/util/HandleFactory.java b/src/com/norswap/autumn/util/HandleFactory.java deleted file mode 100644 index 2e4f8e1..0000000 --- a/src/com/norswap/autumn/util/HandleFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.norswap.autumn.util; - -public final class HandleFactory -{ - public final int start; - public final int end; - public final int stride; - - private int next; - - public HandleFactory(int start, int end, int stride) - { - this.start = start; - this.end = end; - this.stride = stride; - this.next = start; - } - - public HandleFactory(int stride) - { - this(0, 0, stride); - } - - public HandleFactory() - { - this(0, 0, 1); - } - - public int next() - { - if (end > 0 && next >= end) - { - throw new RuntimeException("Handle space (2^32 handles / stride) exhausted."); - } - - int result = next; - next += stride; - return result; - } -} diff --git a/src/com/norswap/autumn/util/IO.java b/src/com/norswap/autumn/util/IO.java deleted file mode 100644 index e88d3c7..0000000 --- a/src/com/norswap/autumn/util/IO.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.norswap.autumn.util; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -public class IO -{ - public static String readFile(String file) - { - try { - return new String(Files.readAllBytes(Paths.get(file))); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } -}