diff -r 17ba167b8ee1 -r 553a5456963b compiler/PetitBenchmarkSources.st
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/compiler/PetitBenchmarkSources.st Sun Oct 26 01:03:31 2014 +0000
@@ -0,0 +1,5170 @@
+"{ Package: 'stx:goodies/petitparser/compiler' }"
+
+Object subclass:#PetitBenchmarkSources
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'PetitCompiler-Benchmarks'
+!
+
+PetitBenchmarkSources comment:''
+!
+
+!PetitBenchmarkSources methodsFor:'as yet unclassified'!
+
+javaLangClass
+!
+
+javaLangMath
+ ^ '/*
+ * @(#)Math.java 1.69 04/06/14
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package java.lang;
+import java.util.Random;
+
+
+/**
+ * The class Math contains methods for performing basic
+ * numeric operations such as the elementary exponential, logarithm,
+ * square root, and trigonometric functions.
+ *
+ *
Unlike some of the numeric methods of class
+ * StrictMath, all implementations of the equivalent
+ * functions of class Math are not defined to return the
+ * bit-for-bit same results. This relaxation permits
+ * better-performing implementations where strict reproducibility is
+ * not required.
+ *
+ *
By default many of the Math methods simply call
+ * the equivalent method in StrictMath for their
+ * implementation. Code generators are encouraged to use
+ * platform-specific native libraries or microprocessor instructions,
+ * where available, to provide higher-performance implementations of
+ * Math methods. Such higher-performance
+ * implementations still must conform to the specification for
+ * Math.
+ *
+ *
The quality of implementation specifications concern two
+ * properties, accuracy of the returned result and monotonicity of the
+ * method. Accuracy of the floating-point Math methods
+ * is measured in terms of ulps, units in the last place. For
+ * a given floating-point format, an ulp of a specific real number
+ * value is the distance between the two floating-point values
+ * bracketing that numerical value. When discussing the accuracy of a
+ * method as a whole rather than at a specific argument, the number of
+ * ulps cited is for the worst-case error at any argument. If a
+ * method always has an error less than 0.5 ulps, the method always
+ * returns the floating-point number nearest the exact result; such a
+ * method is correctly rounded. A correctly rounded method is
+ * generally the best a floating-point approximation can be; however,
+ * it is impractical for many floating-point methods to be correctly
+ * rounded. Instead, for the Math class, a larger error
+ * bound of 1 or 2 ulps is allowed for certain methods. Informally,
+ * with a 1 ulp error bound, when the exact result is a representable
+ * number, the exact result should be returned as the computed result;
+ * otherwise, either of the two floating-point values which bracket
+ * the exact result may be returned. For exact results large in
+ * magnitude, one of the endpoints of the bracket may be infinite.
+ * Besides accuracy at individual arguments, maintaining proper
+ * relations between the method at different arguments is also
+ * important. Therefore, most methods with more than 0.5 ulp errors
+ * are required to be semi-monotonic: whenever the mathematical
+ * function is non-decreasing, so is the floating-point approximation,
+ * likewise, whenever the mathematical function is non-increasing, so
+ * is the floating-point approximation. Not all approximations that
+ * have 1 ulp accuracy will automatically meet the monotonicity
+ * requirements.
+ *
+ * @author unascribed
+ * @author Joseph D. Darcy
+ * @version 1.69, 06/14/04
+ * @since JDK1.0
+ */
+
+public final class Math {
+
+ /**
+ * Don''t let anyone instantiate this class.
+ */
+ private Math() {}
+
+ /**
+ * The double value that is closer than any other to
+ * e, the base of the natural logarithms.
+ */
+ public static final double E = 2.7182818284590452354;
+
+ /**
+ * The double value that is closer than any other to
+ * pi, the ratio of the circumference of a circle to its
+ * diameter.
+ */
+ public static final double PI = 3.14159265358979323846;
+
+ /**
+ * Returns the trigonometric sine of an angle. Special cases:
+ *
If the argument is NaN or an infinity, then the
+ * result is NaN.
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a an angle, in radians.
+ * @return the sine of the argument.
+ */
+ public static double sin(double a) {
+ return StrictMath.sin(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the trigonometric cosine of an angle. Special cases:
+ *
If the argument is NaN or an infinity, then the
+ * result is NaN.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a an angle, in radians.
+ * @return the cosine of the argument.
+ */
+ public static double cos(double a) {
+ return StrictMath.cos(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the trigonometric tangent of an angle. Special cases:
+ *
If the argument is NaN or an infinity, then the result
+ * is NaN.
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a an angle, in radians.
+ * @return the tangent of the argument.
+ */
+ public static double tan(double a) {
+ return StrictMath.tan(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the arc sine of an angle, in the range of -pi/2 through
+ * pi/2. Special cases:
+ *
If the argument is NaN or its absolute value is greater
+ * than 1, then the result is NaN.
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a the value whose arc sine is to be returned.
+ * @return the arc sine of the argument.
+ */
+ public static double asin(double a) {
+ return StrictMath.asin(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the arc cosine of an angle, in the range of 0.0 through
+ * pi. Special case:
+ *
If the argument is NaN or its absolute value is greater
+ * than 1, then the result is NaN.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a the value whose arc cosine is to be returned.
+ * @return the arc cosine of the argument.
+ */
+ public static double acos(double a) {
+ return StrictMath.acos(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the arc tangent of an angle, in the range of -pi/2
+ * through pi/2. Special cases:
+ *
If the argument is NaN, then the result is NaN.
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a the value whose arc tangent is to be returned.
+ * @return the arc tangent of the argument.
+ */
+ public static double atan(double a) {
+ return StrictMath.atan(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Converts an angle measured in degrees to an approximately
+ * equivalent angle measured in radians. The conversion from
+ * degrees to radians is generally inexact.
+ *
+ * @param angdeg an angle, in degrees
+ * @return the measurement of the angle angdeg
+ * in radians.
+ * @since 1.2
+ */
+ public static double toRadians(double angdeg) {
+ return angdeg / 180.0 * PI;
+ }
+
+ /**
+ * Converts an angle measured in radians to an approximately
+ * equivalent angle measured in degrees. The conversion from
+ * radians to degrees is generally inexact; users should
+ * not expect cos(toRadians(90.0)) to exactly
+ * equal 0.0.
+ *
+ * @param angrad an angle, in radians
+ * @return the measurement of the angle angrad
+ * in degrees.
+ * @since 1.2
+ */
+ public static double toDegrees(double angrad) {
+ return angrad * 180.0 / PI;
+ }
+
+ /**
+ * Returns Euler''s number e raised to the power of a
+ * double value. Special cases:
+ *
If the argument is NaN, the result is NaN.
+ *
If the argument is positive infinity, then the result is
+ * positive infinity.
+ *
If the argument is negative infinity, then the result is
+ * positive zero.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a the exponent to raise e to.
+ * @return the value ea,
+ * where e is the base of the natural logarithms.
+ */
+ public static double exp(double a) {
+ return StrictMath.exp(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the natural logarithm (base e) of a double
+ * value. Special cases:
+ *
If the argument is NaN or less than zero, then the result
+ * is NaN.
+ *
If the argument is positive infinity, then the result is
+ * positive infinity.
+ *
If the argument is positive zero or negative zero, then the
+ * result is negative infinity.
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a a value
+ * @return the value ln a, the natural logarithm of
+ * a.
+ */
+ public static double log(double a) {
+ return StrictMath.log(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the base 10 logarithm of a double value.
+ * Special cases:
+ *
+ *
If the argument is NaN or less than zero, then the result
+ * is NaN.
+ *
If the argument is positive infinity, then the result is
+ * positive infinity.
+ *
If the argument is positive zero or negative zero, then the
+ * result is negative infinity.
+ *
If the argument is equal to 10n for
+ * integer n, then the result is n.
+ *
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a a value
+ * @return the base 10 logarithm of a.
+ * @since 1.5
+ */
+ public static double log10(double a) {
+ return StrictMath.log10(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the correctly rounded positive square root of a
+ * double value.
+ * Special cases:
+ *
If the argument is NaN or less than zero, then the result
+ * is NaN.
+ *
If the argument is positive infinity, then the result is positive
+ * infinity.
+ *
If the argument is positive zero or negative zero, then the
+ * result is the same as the argument.
+ * Otherwise, the result is the double value closest to
+ * the true mathematical square root of the argument value.
+ *
+ * @param a a value.
+ * @return the positive square root of a.
+ * If the argument is NaN or less than zero, the result is NaN.
+ */
+ public static double sqrt(double a) {
+ return StrictMath.sqrt(a); // default impl. delegates to StrictMath
+ // Note that hardware sqrt instructions
+ // frequently can be directly used by JITs
+ // and should be much faster than doing
+ // Math.sqrt in software.
+ }
+
+
+ /**
+ * Returns the cube root of a double value. For
+ * positive finite x, cbrt(-x) ==
+ * -cbrt(x); that is, the cube root of a negative value is
+ * the negative of the cube root of that value''s magnitude.
+ *
+ * Special cases:
+ *
+ *
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
+ *
If the argument is infinite, then the result is an infinity
+ * with the same sign as the argument.
+ *
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ *
+ * @param a a value.
+ * @return the cube root of a.
+ * @since 1.5
+ */
+ public static double cbrt(double a) {
+ return StrictMath.cbrt(a);
+ }
+
+ /**
+ * Computes the remainder operation on two arguments as prescribed
+ * by the IEEE 754 standard.
+ * The remainder value is mathematically equal to
+ * f1 - f2 × n,
+ * where n is the mathematical integer closest to the exact
+ * mathematical value of the quotient f1/f2, and if two
+ * mathematical integers are equally close to f1/f2,
+ * then n is the integer that is even. If the remainder is
+ * zero, its sign is the same as the sign of the first argument.
+ * Special cases:
+ *
If either argument is NaN, or the first argument is infinite,
+ * or the second argument is positive zero or negative zero, then the
+ * result is NaN.
+ *
If the first argument is finite and the second argument is
+ * infinite, then the result is the same as the first argument.
+ *
+ * @param f1 the dividend.
+ * @param f2 the divisor.
+ * @return the remainder when f1 is divided by
+ * f2.
+ */
+ public static double IEEEremainder(double f1, double f2) {
+ return StrictMath.IEEEremainder(f1, f2); // delegate to StrictMath
+ }
+
+ /**
+ * Returns the smallest (closest to negative infinity)
+ * double value that is greater than or equal to the
+ * argument and is equal to a mathematical integer. Special cases:
+ *
If the argument value is already equal to a
+ * mathematical integer, then the result is the same as the
+ * argument.
If the argument is NaN or an infinity or
+ * positive zero or negative zero, then the result is the same as
+ * the argument.
If the argument value is less than zero but
+ * greater than -1.0, then the result is negative zero.
Note
+ * that the value of Math.ceil(x) is exactly the
+ * value of -Math.floor(-x).
+ *
+ *
+ * @param a a value.
+ * @return the smallest (closest to negative infinity)
+ * floating-point value that is greater than or equal to
+ * the argument and is equal to a mathematical integer.
+ */
+ public static double ceil(double a) {
+ return StrictMath.ceil(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the largest (closest to positive infinity)
+ * double value that is less than or equal to the
+ * argument and is equal to a mathematical integer. Special cases:
+ *
If the argument value is already equal to a
+ * mathematical integer, then the result is the same as the
+ * argument.
If the argument is NaN or an infinity or
+ * positive zero or negative zero, then the result is the same as
+ * the argument.
+ *
+ * @param a a value.
+ * @return the largest (closest to positive infinity)
+ * floating-point value that less than or equal to the argument
+ * and is equal to a mathematical integer.
+ */
+ public static double floor(double a) {
+ return StrictMath.floor(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the double value that is closest in value
+ * to the argument and is equal to a mathematical integer. If two
+ * double values that are mathematical integers are
+ * equally close, the result is the integer value that is
+ * even. Special cases:
+ *
If the argument value is already equal to a mathematical
+ * integer, then the result is the same as the argument.
+ *
If the argument is NaN or an infinity or positive zero or negative
+ * zero, then the result is the same as the argument.
+ *
+ * @param a a double value.
+ * @return the closest floating-point value to a that is
+ * equal to a mathematical integer.
+ */
+ public static double rint(double a) {
+ return StrictMath.rint(a); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Converts rectangular coordinates (x, y)
+ * to polar (r, theta).
+ * This method computes the phase theta by computing an arc tangent
+ * of y/x in the range of -pi to pi. Special
+ * cases:
+ *
If either argument is NaN, then the result is NaN.
+ *
If the first argument is positive zero and the second argument
+ * is positive, or the first argument is positive and finite and the
+ * second argument is positive infinity, then the result is positive
+ * zero.
+ *
If the first argument is negative zero and the second argument
+ * is positive, or the first argument is negative and finite and the
+ * second argument is positive infinity, then the result is negative zero.
+ *
If the first argument is positive zero and the second argument
+ * is negative, or the first argument is positive and finite and the
+ * second argument is negative infinity, then the result is the
+ * double value closest to pi.
+ *
If the first argument is negative zero and the second argument
+ * is negative, or the first argument is negative and finite and the
+ * second argument is negative infinity, then the result is the
+ * double value closest to -pi.
+ *
If the first argument is positive and the second argument is
+ * positive zero or negative zero, or the first argument is positive
+ * infinity and the second argument is finite, then the result is the
+ * double value closest to pi/2.
+ *
If the first argument is negative and the second argument is
+ * positive zero or negative zero, or the first argument is negative
+ * infinity and the second argument is finite, then the result is the
+ * double value closest to -pi/2.
+ *
If both arguments are positive infinity, then the result is the
+ * double value closest to pi/4.
+ *
If the first argument is positive infinity and the second argument
+ * is negative infinity, then the result is the double
+ * value closest to 3*pi/4.
+ *
If the first argument is negative infinity and the second argument
+ * is positive infinity, then the result is the double value
+ * closest to -pi/4.
+ *
If both arguments are negative infinity, then the result is the
+ * double value closest to -3*pi/4.
+ *
+ *
The computed result must be within 2 ulps of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param y the ordinate coordinate
+ * @param x the abscissa coordinate
+ * @return the theta component of the point
+ * (r, theta)
+ * in polar coordinates that corresponds to the point
+ * (x, y) in Cartesian coordinates.
+ */
+ public static double atan2(double y, double x) {
+ return StrictMath.atan2(y, x); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the value of the first argument raised to the power of the
+ * second argument. Special cases:
+ *
+ *
If the second argument is positive or negative zero, then the
+ * result is 1.0.
+ *
If the second argument is 1.0, then the result is the same as the
+ * first argument.
+ *
If the second argument is NaN, then the result is NaN.
+ *
If the first argument is NaN and the second argument is nonzero,
+ * then the result is NaN.
+ *
+ *
If
+ *
+ *
the absolute value of the first argument is greater than 1
+ * and the second argument is positive infinity, or
+ *
the absolute value of the first argument is less than 1 and
+ * the second argument is negative infinity,
+ *
+ * then the result is positive infinity.
+ *
+ *
If
+ *
+ *
the absolute value of the first argument is greater than 1 and
+ * the second argument is negative infinity, or
+ *
the absolute value of the
+ * first argument is less than 1 and the second argument is positive
+ * infinity,
+ *
+ * then the result is positive zero.
+ *
+ *
If the absolute value of the first argument equals 1 and the
+ * second argument is infinite, then the result is NaN.
+ *
+ *
If
+ *
+ *
the first argument is positive zero and the second argument
+ * is greater than zero, or
+ *
the first argument is positive infinity and the second
+ * argument is less than zero,
+ *
+ * then the result is positive zero.
+ *
+ *
If
+ *
+ *
the first argument is positive zero and the second argument
+ * is less than zero, or
+ *
the first argument is positive infinity and the second
+ * argument is greater than zero,
+ *
+ * then the result is positive infinity.
+ *
+ *
If
+ *
+ *
the first argument is negative zero and the second argument
+ * is greater than zero but not a finite odd integer, or
+ *
the first argument is negative infinity and the second
+ * argument is less than zero but not a finite odd integer,
+ *
+ * then the result is positive zero.
+ *
+ *
If
+ *
+ *
the first argument is negative zero and the second argument
+ * is a positive finite odd integer, or
+ *
the first argument is negative infinity and the second
+ * argument is a negative finite odd integer,
+ *
+ * then the result is negative zero.
+ *
+ *
If
+ *
+ *
the first argument is negative zero and the second argument
+ * is less than zero but not a finite odd integer, or
+ *
the first argument is negative infinity and the second
+ * argument is greater than zero but not a finite odd integer,
+ *
+ * then the result is positive infinity.
+ *
+ *
If
+ *
+ *
the first argument is negative zero and the second argument
+ * is a negative finite odd integer, or
+ *
the first argument is negative infinity and the second
+ * argument is a positive finite odd integer,
+ *
+ * then the result is negative infinity.
+ *
+ *
If the first argument is finite and less than zero
+ *
+ *
if the second argument is a finite even integer, the
+ * result is equal to the result of raising the absolute value of
+ * the first argument to the power of the second argument
+ *
+ *
if the second argument is a finite odd integer, the result
+ * is equal to the negative of the result of raising the absolute
+ * value of the first argument to the power of the second
+ * argument
+ *
+ *
if the second argument is finite and not an integer, then
+ * the result is NaN.
+ *
+ *
+ *
If both arguments are integers, then the result is exactly equal
+ * to the mathematical result of raising the first argument to the power
+ * of the second argument if that result can in fact be represented
+ * exactly as a double value.
+ *
+ *
(In the foregoing descriptions, a floating-point value is
+ * considered to be an integer if and only if it is finite and a
+ * fixed point of the method {@link #ceil ceil} or,
+ * equivalently, a fixed point of the method {@link #floor
+ * floor}. A value is a fixed point of a one-argument
+ * method if and only if the result of applying the method to the
+ * value is equal to the value.)
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param a the base.
+ * @param b the exponent.
+ * @return the value ab.
+ */
+ public static double pow(double a, double b) {
+ return StrictMath.pow(a, b); // default impl. delegates to StrictMath
+ }
+
+ /**
+ * Returns the closest int to the argument. The
+ * result is rounded to an integer by adding 1/2, taking the
+ * floor of the result, and casting the result to type int.
+ * In other words, the result is equal to the value of the expression:
+ *
(int)Math.floor(a + 0.5f)
+ *
+ * Special cases:
+ *
If the argument is NaN, the result is 0.
+ *
If the argument is negative infinity or any value less than or
+ * equal to the value of Integer.MIN_VALUE, the result is
+ * equal to the value of Integer.MIN_VALUE.
+ *
If the argument is positive infinity or any value greater than or
+ * equal to the value of Integer.MAX_VALUE, the result is
+ * equal to the value of Integer.MAX_VALUE.
+ *
+ * @param a a floating-point value to be rounded to an integer.
+ * @return the value of the argument rounded to the nearest
+ * int value.
+ * @see java.lang.Integer#MAX_VALUE
+ * @see java.lang.Integer#MIN_VALUE
+ */
+ public static int round(float a) {
+ return (int)floor(a + 0.5f);
+ }
+
+ /**
+ * Returns the closest long to the argument. The result
+ * is rounded to an integer by adding 1/2, taking the floor of the
+ * result, and casting the result to type long. In other
+ * words, the result is equal to the value of the expression:
+ *
(long)Math.floor(a + 0.5d)
+ *
+ * Special cases:
+ *
If the argument is NaN, the result is 0.
+ *
If the argument is negative infinity or any value less than or
+ * equal to the value of Long.MIN_VALUE, the result is
+ * equal to the value of Long.MIN_VALUE.
+ *
If the argument is positive infinity or any value greater than or
+ * equal to the value of Long.MAX_VALUE, the result is
+ * equal to the value of Long.MAX_VALUE.
+ *
+ * @param a a floating-point value to be rounded to a
+ * long.
+ * @return the value of the argument rounded to the nearest
+ * long value.
+ * @see java.lang.Long#MAX_VALUE
+ * @see java.lang.Long#MIN_VALUE
+ */
+ public static long round(double a) {
+ return (long)floor(a + 0.5d);
+ }
+
+ private static Random randomNumberGenerator;
+
+ private static synchronized void initRNG() {
+ if (randomNumberGenerator == null)
+ randomNumberGenerator = new Random();
+ }
+
+ /**
+ * Returns a double value with a positive sign, greater
+ * than or equal to 0.0 and less than 1.0.
+ * Returned values are chosen pseudorandomly with (approximately)
+ * uniform distribution from that range.
+ *
+ *
When this method is first called, it creates a single new
+ * pseudorandom-number generator, exactly as if by the expression
+ *
new java.util.Random
This
+ * new pseudorandom-number generator is used thereafter for all
+ * calls to this method and is used nowhere else.
+ *
+ *
This method is properly synchronized to allow correct use by
+ * more than one thread. However, if many threads need to generate
+ * pseudorandom numbers at a great rate, it may reduce contention
+ * for each thread to have its own pseudorandom-number generator.
+ *
+ * @return a pseudorandom double greater than or equal
+ * to 0.0 and less than 1.0.
+ * @see java.util.Random#nextDouble()
+ */
+ public static double random() {
+ if (randomNumberGenerator == null) initRNG();
+ return randomNumberGenerator.nextDouble();
+ }
+
+ /**
+ * Returns the absolute value of an int value.
+ * If the argument is not negative, the argument is returned.
+ * If the argument is negative, the negation of the argument is returned.
+ *
+ *
Note that if the argument is equal to the value of
+ * Integer.MIN_VALUE, the most negative representable
+ * int value, the result is that same value, which is
+ * negative.
+ *
+ * @param a the argument whose absolute value is to be determined
+ * @return the absolute value of the argument.
+ * @see java.lang.Integer#MIN_VALUE
+ */
+ public static int abs(int a) {
+ return (a < 0) ? -a : a;
+ }
+
+ /**
+ * Returns the absolute value of a long value.
+ * If the argument is not negative, the argument is returned.
+ * If the argument is negative, the negation of the argument is returned.
+ *
+ *
Note that if the argument is equal to the value of
+ * Long.MIN_VALUE, the most negative representable
+ * long value, the result is that same value, which
+ * is negative.
+ *
+ * @param a the argument whose absolute value is to be determined
+ * @return the absolute value of the argument.
+ * @see java.lang.Long#MIN_VALUE
+ */
+ public static long abs(long a) {
+ return (a < 0) ? -a : a;
+ }
+
+ /**
+ * Returns the absolute value of a float value.
+ * If the argument is not negative, the argument is returned.
+ * If the argument is negative, the negation of the argument is returned.
+ * Special cases:
+ *
If the argument is positive zero or negative zero, the
+ * result is positive zero.
+ *
If the argument is infinite, the result is positive infinity.
+ *
If the argument is NaN, the result is NaN.
+ * In other words, the result is the same as the value of the expression:
+ *
+ *
+ * @param a the argument whose absolute value is to be determined
+ * @return the absolute value of the argument.
+ */
+ public static float abs(float a) {
+ return (a <= 0.0F) ? 0.0F - a : a;
+ }
+
+ /**
+ * Returns the absolute value of a double value.
+ * If the argument is not negative, the argument is returned.
+ * If the argument is negative, the negation of the argument is returned.
+ * Special cases:
+ *
If the argument is positive zero or negative zero, the result
+ * is positive zero.
+ *
If the argument is infinite, the result is positive infinity.
+ *
If the argument is NaN, the result is NaN.
+ * In other words, the result is the same as the value of the expression:
+ *
Double.longBitsToDouble((Double.doubleToLongBits(a)<<1)>>>1)
+ *
+ * @param a the argument whose absolute value is to be determined
+ * @return the absolute value of the argument.
+ */
+ public static double abs(double a) {
+ return (a <= 0.0D) ? 0.0D - a : a;
+ }
+
+ /**
+ * Returns the greater of two int values. That is, the
+ * result is the argument closer to the value of
+ * Integer.MAX_VALUE. If the arguments have the same value,
+ * the result is that same value.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the larger of a and b.
+ * @see java.lang.Long#MAX_VALUE
+ */
+ public static int max(int a, int b) {
+ return (a >= b) ? a : b;
+ }
+
+ /**
+ * Returns the greater of two long values. That is, the
+ * result is the argument closer to the value of
+ * Long.MAX_VALUE. If the arguments have the same value,
+ * the result is that same value.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the larger of a and b.
+ * @see java.lang.Long#MAX_VALUE
+ */
+ public static long max(long a, long b) {
+ return (a >= b) ? a : b;
+ }
+
+ private static long negativeZeroFloatBits = Float.floatToIntBits(-0.0f);
+ private static long negativeZeroDoubleBits = Double.doubleToLongBits(-0.0d);
+
+ /**
+ * Returns the greater of two float values. That is,
+ * the result is the argument closer to positive infinity. If the
+ * arguments have the same value, the result is that same
+ * value. If either value is NaN, then the result is NaN. Unlike
+ * the numerical comparison operators, this method considers
+ * negative zero to be strictly smaller than positive zero. If one
+ * argument is positive zero and the other negative zero, the
+ * result is positive zero.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the larger of a and b.
+ */
+ public static float max(float a, float b) {
+ if (a !!= a) return a; // a is NaN
+ if ((a == 0.0f) && (b == 0.0f)
+ && (Float.floatToIntBits(a) == negativeZeroFloatBits)) {
+ return b;
+ }
+ return (a >= b) ? a : b;
+ }
+
+ /**
+ * Returns the greater of two double values. That
+ * is, the result is the argument closer to positive infinity. If
+ * the arguments have the same value, the result is that same
+ * value. If either value is NaN, then the result is NaN. Unlike
+ * the numerical comparison operators, this method considers
+ * negative zero to be strictly smaller than positive zero. If one
+ * argument is positive zero and the other negative zero, the
+ * result is positive zero.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the larger of a and b.
+ */
+ public static double max(double a, double b) {
+ if (a !!= a) return a; // a is NaN
+ if ((a == 0.0d) && (b == 0.0d)
+ && (Double.doubleToLongBits(a) == negativeZeroDoubleBits)) {
+ return b;
+ }
+ return (a >= b) ? a : b;
+ }
+
+ /**
+ * Returns the smaller of two int values. That is,
+ * the result the argument closer to the value of
+ * Integer.MIN_VALUE. If the arguments have the same
+ * value, the result is that same value.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the smaller of a and b.
+ * @see java.lang.Long#MIN_VALUE
+ */
+ public static int min(int a, int b) {
+ return (a <= b) ? a : b;
+ }
+
+ /**
+ * Returns the smaller of two long values. That is,
+ * the result is the argument closer to the value of
+ * Long.MIN_VALUE. If the arguments have the same
+ * value, the result is that same value.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the smaller of a and b.
+ * @see java.lang.Long#MIN_VALUE
+ */
+ public static long min(long a, long b) {
+ return (a <= b) ? a : b;
+ }
+
+ /**
+ * Returns the smaller of two float values. That is,
+ * the result is the value closer to negative infinity. If the
+ * arguments have the same value, the result is that same
+ * value. If either value is NaN, then the result is NaN. Unlike
+ * the numerical comparison operators, this method considers
+ * negative zero to be strictly smaller than positive zero. If
+ * one argument is positive zero and the other is negative zero,
+ * the result is negative zero.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the smaller of a and b.
+ */
+ public static float min(float a, float b) {
+ if (a !!= a) return a; // a is NaN
+ if ((a == 0.0f) && (b == 0.0f)
+ && (Float.floatToIntBits(b) == negativeZeroFloatBits)) {
+ return b;
+ }
+ return (a <= b) ? a : b;
+ }
+
+ /**
+ * Returns the smaller of two double values. That
+ * is, the result is the value closer to negative infinity. If the
+ * arguments have the same value, the result is that same
+ * value. If either value is NaN, then the result is NaN. Unlike
+ * the numerical comparison operators, this method considers
+ * negative zero to be strictly smaller than positive zero. If one
+ * argument is positive zero and the other is negative zero, the
+ * result is negative zero.
+ *
+ * @param a an argument.
+ * @param b another argument.
+ * @return the smaller of a and b.
+ */
+ public static double min(double a, double b) {
+ if (a !!= a) return a; // a is NaN
+ if ((a == 0.0d) && (b == 0.0d)
+ && (Double.doubleToLongBits(b) == negativeZeroDoubleBits)) {
+ return b;
+ }
+ return (a <= b) ? a : b;
+ }
+
+ /**
+ * Returns the size of an ulp of the argument. An ulp of a
+ * double value is the positive distance between this
+ * floating-point value and the double value next
+ * larger in magnitude. Note that for non-NaN x,
+ * ulp(-x) == ulp(x).
+ *
+ *
Special Cases:
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
If the argument is positive or negative infinity, then the
+ * result is positive infinity.
+ *
If the argument is positive or negative zero, then the result is
+ * Double.MIN_VALUE.
+ *
If the argument is ±Double.MAX_VALUE, then
+ * the result is equal to 2971.
+ *
+ *
+ * @param d the floating-point value whose ulp is to be returned
+ * @return the size of an ulp of the argument
+ * @author Joseph D. Darcy
+ * @since 1.5
+ */
+ public static double ulp(double d) {
+ return sun.misc.FpUtils.ulp(d);
+ }
+
+ /**
+ * Returns the size of an ulp of the argument. An ulp of a
+ * float value is the positive distance between this
+ * floating-point value and the float value next
+ * larger in magnitude. Note that for non-NaN x,
+ * ulp(-x) == ulp(x).
+ *
+ *
Special Cases:
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
If the argument is positive or negative infinity, then the
+ * result is positive infinity.
+ *
If the argument is positive or negative zero, then the result is
+ * Float.MIN_VALUE.
+ *
If the argument is ±Float.MAX_VALUE, then
+ * the result is equal to 2104.
+ *
+ *
+ * @param f the floating-point value whose ulp is to be returned
+ * @return the size of an ulp of the argument
+ * @author Joseph D. Darcy
+ * @since 1.5
+ */
+ public static float ulp(float f) {
+ return sun.misc.FpUtils.ulp(f);
+ }
+
+ /**
+ * Returns the signum function of the argument; zero if the argument
+ * is zero, 1.0 if the argument is greater than zero, -1.0 if the
+ * argument is less than zero.
+ *
+ *
Special Cases:
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
If the argument is positive zero or negative zero, then the
+ * result is the same as the argument.
+ *
+ *
+ * @param d the floating-point value whose signum is to be returned
+ * @return the signum function of the argument
+ * @author Joseph D. Darcy
+ * @since 1.5
+ */
+ public static double signum(double d) {
+ return sun.misc.FpUtils.signum(d);
+ }
+
+ /**
+ * Returns the signum function of the argument; zero if the argument
+ * is zero, 1.0f if the argument is greater than zero, -1.0f if the
+ * argument is less than zero.
+ *
+ *
Special Cases:
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
If the argument is positive zero or negative zero, then the
+ * result is the same as the argument.
+ *
+ *
+ * @param f the floating-point value whose signum is to be returned
+ * @return the signum function of the argument
+ * @author Joseph D. Darcy
+ * @since 1.5
+ */
+ public static float signum(float f) {
+ return sun.misc.FpUtils.signum(f);
+ }
+
+ /**
+ * Returns the hyperbolic sine of a double value.
+ * The hyperbolic sine of x is defined to be
+ * (ex - e-x)/2
+ * where e is {@linkplain Math#E Euler''s number}.
+ *
+ *
Special cases:
+ *
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
+ *
If the argument is infinite, then the result is an infinity
+ * with the same sign as the argument.
+ *
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
+ *
+ *
The computed result must be within 2.5 ulps of the exact result.
+ *
+ * @param x The number whose hyperbolic sine is to be returned.
+ * @return The hyperbolic sine of x.
+ * @since 1.5
+ */
+ public static double sinh(double x) {
+ return StrictMath.sinh(x);
+ }
+
+ /**
+ * Returns the hyperbolic cosine of a double value.
+ * The hyperbolic cosine of x is defined to be
+ * (ex + e-x)/2
+ * where e is {@linkplain Math#E Euler''s number}.
+ *
+ *
Special cases:
+ *
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
+ *
If the argument is infinite, then the result is positive
+ * infinity.
+ *
+ *
If the argument is zero, then the result is 1.0.
+ *
+ *
+ *
+ *
The computed result must be within 2.5 ulps of the exact result.
+ *
+ * @param x The number whose hyperbolic cosine is to be returned.
+ * @return The hyperbolic cosine of x.
+ * @since 1.5
+ */
+ public static double cosh(double x) {
+ return StrictMath.cosh(x);
+ }
+
+ /**
+ * Returns the hyperbolic tangent of a double value.
+ * The hyperbolic tangent of x is defined to be
+ * (ex - e-x)/(ex + e-x),
+ * in other words, {@linkplain Math#sinh
+ * sinh(x)}/{@linkplain Math#cosh cosh(x)}. Note
+ * that the absolute value of the exact tanh is always less than
+ * 1.
+ *
+ *
Special cases:
+ *
+ *
+ *
If the argument is NaN, then the result is NaN.
+ *
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
If the argument is positive infinity, then the result is
+ * +1.0.
+ *
+ *
If the argument is negative infinity, then the result is
+ * -1.0.
+ *
+ *
+ *
+ *
The computed result must be within 2.5 ulps of the exact result.
+ * The result of tanh for any finite input must have
+ * an absolute value less than or equal to 1. Note that once the
+ * exact result of tanh is within 1/2 of an ulp of the limit value
+ * of ±1, correctly signed ±1.0 should
+ * be returned.
+ *
+ * @param x The number whose hyperbolic tangent is to be returned.
+ * @return The hyperbolic tangent of x.
+ * @since 1.5
+ */
+ public static double tanh(double x) {
+ return StrictMath.tanh(x);
+ }
+
+ /**
+ * Returns sqrt(x2 +y2)
+ * without intermediate overflow or underflow.
+ *
+ *
Special cases:
+ *
+ *
+ *
If either argument is infinite, then the result
+ * is positive infinity.
+ *
+ *
If either argument is NaN and neither argument is infinite,
+ * then the result is NaN.
+ *
+ *
+ *
+ *
The computed result must be within 1 ulp of the exact
+ * result. If one parameter is held constant, the results must be
+ * semi-monotonic in the other parameter.
+ *
+ * @param x a value
+ * @param y a value
+ * @return sqrt(x2 +y2)
+ * without intermediate overflow or underflow
+ * @since 1.5
+ */
+ public static double hypot(double x, double y) {
+ return StrictMath.hypot(x, y);
+ }
+
+ /**
+ * Returns ex -1. Note that for values of
+ * x near 0, the exact sum of
+ * expm1(x) + 1 is much closer to the true
+ * result of ex than exp(x).
+ *
+ *
Special cases:
+ *
+ *
If the argument is NaN, the result is NaN.
+ *
+ *
If the argument is positive infinity, then the result is
+ * positive infinity.
+ *
+ *
If the argument is negative infinity, then the result is
+ * -1.0.
+ *
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic. The result of
+ * expm1 for any finite input must be greater than or
+ * equal to -1.0. Note that once the exact result of
+ * ex - 1 is within 1/2
+ * ulp of the limit value -1, -1.0 should be
+ * returned.
+ *
+ * @param x the exponent to raise e to in the computation of
+ * ex -1.
+ * @return the value ex - 1.
+ */
+ public static double expm1(double x) {
+ return StrictMath.expm1(x);
+ }
+
+ /**
+ * Returns the natural logarithm of the sum of the argument and 1.
+ * Note that for small values x, the result of
+ * log1p(x) is much closer to the true result of ln(1
+ * + x) than the floating-point evaluation of
+ * log(1.0+x).
+ *
+ *
Special cases:
+ *
+ *
+ *
+ *
If the argument is NaN or less than -1, then the result is
+ * NaN.
+ *
+ *
If the argument is positive infinity, then the result is
+ * positive infinity.
+ *
+ *
If the argument is negative one, then the result is
+ * negative infinity.
+ *
+ *
If the argument is zero, then the result is a zero with the
+ * same sign as the argument.
+ *
+ *
+ *
+ *
The computed result must be within 1 ulp of the exact result.
+ * Results must be semi-monotonic.
+ *
+ * @param x a value
+ * @return the value ln(x + 1), the natural
+ * log of x + 1
+ */
+ public static double log1p(double x) {
+ return StrictMath.log1p(x);
+ }
+}
+'
+!
+
+petitParserPackage
+^ '
+Object subclass: #PPCharSetPredicate
+ instanceVariableNames: ''block classification''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Tools''!!
+!!PPCharSetPredicate commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPCharSetPredicate methodsFor: ''initialization'' stamp: ''lr 8/30/2010 12:19''!!
+initializeOn: aBlock
+ block := aBlock.
+ classification := Array new: 255.
+ 1 to: classification size do: [ :index |
+ classification at: index put: (block
+ value: (Character value: index)) ]!! !!
+
+
+!!PPCharSetPredicate methodsFor: ''evaluating'' stamp: ''lr 8/30/2010 12:19''!!
+value: aCharacter
+ | index |
+ index := aCharacter asInteger.
+ index == 0
+ ifTrue: [ ^ block value: aCharacter ].
+ index > 255
+ ifTrue: [ ^ block value: aCharacter ].
+ ^ classification at: index!! !!
+
+"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!!
+
+PPCharSetPredicate class
+ instanceVariableNames: ''''!!
+!!PPCharSetPredicate class commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPCharSetPredicate class methodsFor: ''instance creation'' stamp: ''lr 8/25/2010 11:05''!!
+on: aBlock
+ ^ self basicNew initializeOn: aBlock!! !!
+
+
+PPDelegateParser subclass: #PPExpressionParser
+ instanceVariableNames: ''operators''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Tools''!!
+!!PPExpressionParser commentStamp: '''' prior: 0!!
+A PPExpressionParser is a parser to conveniently define an expression grammar with prefix, postfix, and left- and right-associative infix operators.
+
+The following code initializes a parser for arithmetic expressions. First we instantiate an expression parser, a simple parser for expressions in parenthesis and a simple parser for integer numbers.
+
+ expression := PPExpressionParser new.
+ parens := $( asParser token trim , expression , $) asParser token trim
+ ==> [ :nodes | nodes second ].
+ integer := #digit asParser plus token trim
+ ==> [ :token | token value asInteger ].
+
+Then we define on what term the expression grammar is built on:
+
+ expression term: parens / integer.
+
+Finally we define the operator-groups in descending precedence. Note, that the action blocks receive both, the terms and the parsed operator in the order they appear in the parsed input.
+
+ expression
+ group: [ :g |
+ g prefix: $- asParser token trim do: [ :op :a | a negated ] ];
+ group: [ :g |
+ g postfix: ''++'' asParser token trim do: [ :a :op | a + 1 ].
+ g postfix: ''--'' asParser token trim do: [ :a :op | a - 1 ] ];
+ group: [ :g |
+ g right: $^ asParser token trim do: [ :a :op :b | a raisedTo: b ] ];
+ group: [ :g |
+ g left: $* asParser token trim do: [ :a :op :b | a * b ].
+ g left: $/ asParser token trim do: [ :a :op :b | a / b ] ];
+ group: [ :g |
+ g left: $+ asParser token trim do: [ :a :op :b | a + b ].
+ g left: $- asParser token trim do: [ :a :op :b | a - b ] ].
+
+After evaluating the above code the ''expression'' is an efficient parser that evaluates examples like:
+
+ expression parse: ''-8++''.
+ expression parse: ''1+2*3''.
+ expression parse: ''1*2+3''.
+ expression parse: ''(1+2)*3''.
+ expression parse: ''8/4/2''.
+ expression parse: ''8/(4/2)''.
+ expression parse: ''2^2^3''.
+ expression parse: ''(2^2)^3''.
+
+Instance Variables:
+ operators The operators defined in the current group.!!
+
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''FirstnameLastname 11/26/2009 20:48''!!
+build: aParser right: aChoiceParser
+ ^ (aParser separatedBy: aChoiceParser) foldRight: [ :a :op :b | op first value: a value: op second value: b ]!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''FirstnameLastname 11/26/2009 20:48''!!
+build: aParser left: aChoiceParser
+ ^ (aParser separatedBy: aChoiceParser) foldLeft: [ :a :op :b | op first value: a value: op second value: b ]!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''lr 12/4/2009 17:38''!!
+build: aParser postfix: aChoiceParser
+ ^ aParser , aChoiceParser star map: [ :term :ops | ops inject: term into: [ :result :operator | operator first value: result value: operator second ] ]!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''FirstnameLastname 11/26/2009 21:15''!!
+buildOn: aParser
+ ^ self buildSelectors inject: aParser into: [ :term :selector |
+ | list |
+ list := operators at: selector ifAbsent: [ #() ].
+ list isEmpty
+ ifTrue: [ term ]
+ ifFalse: [
+ self
+ perform: selector with: term
+ with: (list size = 1
+ ifTrue: [ list first first ==> [ :operator | Array with: list first second with: operator ] ]
+ ifFalse: [
+ list
+ inject: PPChoiceParser new
+ into: [ :choice :each | choice / (each first ==> [ :operator | Array with: each second with: operator ]) ] ]) ] ]!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''lr 12/4/2009 17:39''!!
+build: aParser prefix: aChoiceParser
+ ^ aChoiceParser star , aParser map: [ :ops :term | ops reversed inject: term into: [ :result :operator | operator first value: operator second value: result ] ]!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''FirstnameLastname 11/26/2009 20:48''!!
+buildSelectors
+ ^ #(build:prefix: build:postfix: build:right: build:left:)!! !!
+
+!!PPExpressionParser methodsFor: ''private'' stamp: ''lr 2/7/2010 23:23''!!
+operator: aSymbol parser: aParser do: aBlock
+ parser isNil
+ ifTrue: [ ^ self error: ''You did not specify a term when creating the receiver.'' ].
+ operators isNil
+ ifTrue: [ ^ self error: ''Use #group: to define precedence groups in descending order.'' ].
+ (operators at: aSymbol ifAbsentPut: [ OrderedCollection new ])
+ addLast: (Array with: aParser asParser with: aBlock)!! !!
+
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''FirstnameLastname 11/26/2009 21:26''!!
+term: aParser
+ "Defines the initial term aParser of the receiver."
+
+ parser isNil
+ ifTrue: [ parser := aParser ]
+ ifFalse: [ self error: ''Unable to redefine the term.'' ]!! !!
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''FirstnameLastname 11/26/2009 20:49''!!
+postfix: aParser do: aTwoArgumentBlock
+ "Define a postfix operator aParser. Evaluate aTwoArgumentBlock with the term and the operator."
+
+ self operator: #build:postfix: parser: aParser do: aTwoArgumentBlock!! !!
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''FirstnameLastname 11/26/2009 20:49''!!
+left: aParser do: aThreeArgumentBlock
+ "Define an operator aParser that is left-associative. Evaluate aThreeArgumentBlock with the first term, the operator, and the second term."
+
+ self operator: #build:left: parser: aParser do: aThreeArgumentBlock!! !!
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''FirstnameLastname 11/26/2009 20:49''!!
+prefix: aParser do: aTwoArgumentBlock
+ "Define a prefix operator aParser. Evaluate aTwoArgumentBlock with the operator and the term."
+
+ self operator: #build:prefix: parser: aParser do: aTwoArgumentBlock!! !!
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''FirstnameLastname 11/26/2009 20:49''!!
+right: aParser do: aThreeArgumentBlock
+ "Define an operator aParser that is right-associative. Evaluate aThreeArgumentBlock with the first term, the operator, and the second term."
+
+ self operator: #build:right: parser: aParser do: aThreeArgumentBlock!! !!
+
+!!PPExpressionParser methodsFor: ''specifying'' stamp: ''lr 2/7/2010 23:20''!!
+group: aOneArgumentBlock
+ "Defines a priority group by evaluating aOneArgumentBlock."
+
+ operators := Dictionary new.
+ parser := [
+ aOneArgumentBlock value: self.
+ self buildOn: parser ]
+ ensure: [ operators := nil ]!! !!
+
+
+PPDelegateParser subclass: #PPCompositeParser
+ instanceVariableNames: ''dependencies''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Tools''!!
+!!PPCompositeParser commentStamp: ''lr 12/4/2009 18:38'' prior: 0!!
+A PPCompositeParser is composed parser built from various primitive parsers.
+
+Every production in the receiver is specified as a method that returns its parser. Note that every production requires an instance variable of the same name, otherwise the production is not cached and cannot be used in recursive grammars. Productions should refer to each other by reading the respective inst-var. Note: these inst-vars are typically not written, as the assignment happens in the initialize method using reflection.
+
+The start production is defined in the method start. It is aliased to the inst-var parser defined in the superclass of PPCompositeParser.!!
+
+
+!!PPCompositeParser methodsFor: ''querying'' stamp: ''lr 6/4/2010 13:37''!!
+productionAt: aSymbol ifAbsent: aBlock
+ "Answer the production named aSymbol, if there is no such production answer the result of evaluating aBlock."
+
+ (self class ignoredNames includes: aSymbol asString)
+ ifTrue: [ ^ aBlock value ].
+ (self class startSymbol = aSymbol)
+ ifTrue: [ ^ parser ].
+ ^ self instVarAt: (self class allInstVarNames
+ indexOf: aSymbol asString
+ ifAbsent: [ ^ aBlock value ])!! !!
+
+!!PPCompositeParser methodsFor: ''querying'' stamp: ''lr 5/8/2011 15:45''!!
+productionNames
+ "Answer a dictionary of slot indexes and production names."
+
+ | productionNames ignoredNames |
+ productionNames := Dictionary new.
+ ignoredNames := self class ignoredNames
+ collect: [ :each | each asSymbol ].
+ self class allInstVarNames keysAndValuesDo: [ :key :value |
+ (ignoredNames includes: value asSymbol)
+ ifFalse: [ productionNames at: key put: value asSymbol ] ].
+ ^ productionNames!! !!
+
+!!PPCompositeParser methodsFor: ''querying'' stamp: ''lr 3/16/2013 21:41''!!
+dependencyAt: aClass
+ "Answer the dependent parser aClass. Throws an error if this parser class is not declared in the method #dependencies on the class-side of the receiver."
+
+ ^ dependencies at: aClass ifAbsent: [ self error: ''Undeclared dependency in '' , self class name , '' to '' , aClass name ]!! !!
+
+!!PPCompositeParser methodsFor: ''querying'' stamp: ''lr 12/4/2009 18:39''!!
+productionAt: aSymbol
+ "Answer the production named aSymbol."
+
+ ^ self productionAt: aSymbol ifAbsent: [ nil ]!! !!
+
+
+!!PPCompositeParser methodsFor: ''initialization'' stamp: ''lr 3/16/2013 17:15''!!
+initializeStartingAt: aSymbol dependencies: aDictionary
+ self initialize.
+ parser := PPDelegateParser named: aSymbol.
+ self productionNames keysAndValuesDo: [ :key :value |
+ self instVarAt: key put: (PPDelegateParser named: value) ].
+ dependencies := aDictionary!! !!
+
+
+!!PPCompositeParser methodsFor: ''accessing'' stamp: ''lr 5/16/2008 17:32''!!
+start
+ "Answer the production to start this parser with."
+
+ self subclassResponsibility!! !!
+
+"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!!
+
+PPCompositeParser class
+ instanceVariableNames: ''''!!
+!!PPCompositeParser class commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPCompositeParser class methodsFor: ''accessing'' stamp: ''lr 1/29/2010 11:35''!!
+ignoredNames
+ "Answer a collection of instance-variables that should not be automatically initialized with productions, but that are used internal to the composite parser."
+
+ ^ PPCompositeParser allInstVarNames!! !!
+
+!!PPCompositeParser class methodsFor: ''accessing'' stamp: ''lr 12/7/2009 08:20''!!
+startSymbol
+ "Answer the method that represents the default start symbol."
+
+ ^ #start!! !!
+
+!!PPCompositeParser class methodsFor: ''accessing'' stamp: ''lr 3/16/2013 21:42''!!
+dependencies
+ "Answer a collection of PPCompositeParser classes that this parser directly dependends on. Override this method in subclasses to declare dependent parsers. The default implementation does not depend on other PPCompositeParser."
+
+ ^ #()!! !!
+
+
+!!PPCompositeParser class methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 12/19/2013 15:40''!!
+debug: anObject startingAt: aSymbol onError: aBlock
+ ^ (self newStartingAt: aSymbol) debug: anObject onError: aBlock!! !!
+
+!!PPCompositeParser class methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 12/19/2013 15:39''!!
+debug: anObject startingAt: aSymbol
+ ^ (self newStartingAt: aSymbol) debug: anObject!! !!
+
+!!PPCompositeParser class methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 12/19/2013 15:40''!!
+debug: anObject onError: aBlock
+ ^ self debug: anObject startingAt: self startSymbol onError: aBlock!! !!
+
+!!PPCompositeParser class methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 12/19/2013 15:39''!!
+debug: anObject
+ ^ self debug: anObject startingAt: self startSymbol!! !!
+
+
+!!PPCompositeParser class methodsFor: ''instance creation'' stamp: ''lr 3/16/2013 21:21''!!
+newStartingAt: aSymbol
+ "Answer a new parser starting at aSymbol. The code makes sure to resolve all dependent parsers correctly."
+
+ | parsers remaining |
+ parsers := IdentityDictionary new.
+ remaining := OrderedCollection with: self.
+ [ remaining isEmpty ] whileFalse: [
+ | dependency |
+ dependency := remaining removeLast.
+ (parsers includesKey: dependency) ifFalse: [
+ parsers at: dependency put: dependency basicNew.
+ remaining addAll: dependency dependencies ] ].
+ parsers keysAndValuesDo: [ :class :parser |
+ | dependencies |
+ dependencies := IdentityDictionary new.
+ class dependencies
+ do: [ :dependency | dependencies at: dependency put: (parsers at: dependency) ].
+ parser
+ initializeStartingAt: (class == self
+ ifTrue: [ aSymbol ]
+ ifFalse: [ class startSymbol ])
+ dependencies: dependencies ].
+ parsers keysAndValuesDo: [ :class :parser |
+ parser setParser: (parser perform: parser children first name).
+ parser productionNames keysAndValuesDo: [ :key :value |
+ (parser instVarAt: key) setParser: (parser perform: value) ] ].
+ ^ parsers at: self!! !!
+
+!!PPCompositeParser class methodsFor: ''instance creation'' stamp: ''lr 12/7/2009 08:24''!!
+new
+ "Answer a new parser starting at the default start symbol."
+
+ ^ self newStartingAt: self startSymbol!! !!
+
+
+!!PPCompositeParser class methodsFor: ''parsing'' stamp: ''lr 2/7/2010 21:02''!!
+parse: anObject onError: aBlock
+ ^ self parse: anObject startingAt: self startSymbol onError: aBlock!! !!
+
+!!PPCompositeParser class methodsFor: ''parsing'' stamp: ''lr 2/7/2010 21:02''!!
+parse: anObject startingAt: aSymbol onError: aBlock
+ ^ (self newStartingAt: aSymbol) parse: anObject onError: aBlock!! !!
+
+!!PPCompositeParser class methodsFor: ''parsing'' stamp: ''lr 2/7/2010 20:57''!!
+parse: anObject startingAt: aSymbol
+ ^ (self newStartingAt: aSymbol) parse: anObject!! !!
+
+!!PPCompositeParser class methodsFor: ''parsing'' stamp: ''lr 2/7/2010 20:57''!!
+parse: anObject
+ ^ self parse: anObject startingAt: self startSymbol!! !!
+
+
+PPParser subclass: #PPUnresolvedParser
+ instanceVariableNames: ''''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Tools''!!
+!!PPUnresolvedParser commentStamp: ''lr 11/28/2009 18:50'' prior: 0!!
+This is a temporary placeholder or forward reference to a parser that has not been defined yet. If everything goes well it will eventually be replaced with the real parser instance.!!
+
+
+!!PPUnresolvedParser methodsFor: ''parsing'' stamp: ''lr 2/7/2010 20:51''!!
+parseOn: aStream
+ self error: self printString , '' need to be resolved before execution.''!! !!
+
+
+!!PPUnresolvedParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/13/2009 14:15''!!
+displayColor
+ ^ Color red!! !!
+
+
+!!PPUnresolvedParser methodsFor: ''testing'' stamp: ''lr 10/27/2008 11:29''!!
+isUnresolved
+ ^ true!! !!
+Object subclass: #PPParser
+ instanceVariableNames: ''properties''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Parsers''!!
+!!PPParser commentStamp: '''' prior: 0!!
+An abstract parser for all parsers in PetitParser. Subclasses implement #parseOn: to perform the actual recursive-descent parsing. All parsers support a variety of methods to perform an actual parse, see the methods in the #parsing protocol. Parsers are combined with a series of operators that can be found in the #operations protocol.
+
+Instance Variables:
+ properties Stores additional state in the parser object.!!
+
+
+!!PPParser methodsFor: ''*petitjava-operations'' stamp: ''sback 9/2/2010 23:01''!!
+javaToken
+ ^ PPJavaTokenParser on: self!! !!
+
+
+!!PPParser methodsFor: ''*petitgui'' stamp: ''TudorGirba 12/18/2013 06:41''!!
+gtInspectorParserInspectorIn: composite
+
+ composite custom: (
+ PPVerticalParserInspector new
+ title: ''Sampler'';
+ startOn: self)!! !!
+
+!!PPParser methodsFor: ''*petitgui'' stamp: ''AlexandreBergel 12/18/2013 16:40''!!
+gtGraphViewIn: composite
+
+
+ composite roassal
+ title: ''Graph'';
+ painting: [ :view |
+ self visualizeStructureInGraphOn: view.
+ ].!! !!
+
+!!PPParser methodsFor: ''*petitgui'' stamp: ''TudorGirba 6/24/2013 23:44''!!
+gtNamedTreeViewIn: composite
+
+
+ composite tree
+ title: ''Named Tree'';
+ children: [:n | n namedChildren ];
+ format: [:n| n name ifNil: [ n asString ] ];
+ shouldExpandToLevel: 3!! !!
+
+!!PPParser methodsFor: ''*petitgui'' stamp: ''TudorGirba 6/24/2013 23:44''!!
+gtTreeViewIn: composite
+
+
+ composite tree
+ title: ''Tree'';
+ children: [:n | n children ];
+ format: [:n| n name ifNil: [ n asString ] ifNotNil: [n name] ];
+ shouldExpandToLevel: 6!! !!
+
+
+!!PPParser methodsFor: ''*petitgui-morphic'' stamp: ''lr 1/30/2013 19:35''!!
+morphicShapeDefault
+ ^ self newRowMorph
+ addMorphBack: (self newColumnMorph
+ addMorphBack: (self newSpacerMorph);
+ addMorphBack: (LineMorph from: 0 @ 0 to: 20 @ 0 color: Color black width: 1)
+ makeForwardArrow;
+ yourself);
+ addMorphBack: (self newRowMorph
+ borderWidth: 1;
+ layoutInset: 3;
+ color: Color white;
+ addMorphBack: (StringMorph new
+ contents: self displayName;
+ color: self displayColor;
+ yourself);
+ yourself);
+ yourself!! !!
+
+!!PPParser methodsFor: ''*petitgui-morphic'' stamp: ''lr 11/18/2009 10:56''!!
+morphicProduction
+ ^ self newRowMorph
+ layoutInset: 4;
+ addMorphBack: (self newRowMorph
+ layoutInset: 4;
+ addMorphBack: (StringMorph new
+ contents: self displayName;
+ emphasis: TextEmphasis bold emphasisCode;
+ yourself);
+ yourself);
+ addMorphBack: (self morphicShapeSeen: IdentitySet new depth: 0);
+ addMorphBack: (self newColumnMorph
+ addMorphBack: (self newSpacerMorph);
+ addMorphBack: (LineMorph from: 0 @ 0 to: 20 @ 0 color: Color black width: 1)
+ makeForwardArrow;
+ yourself);
+ yourself!! !!
+
+!!PPParser methodsFor: ''*petitgui-morphic'' stamp: ''lr 11/13/2009 13:24''!!
+morphicShapeSeen: aSet depth: anInteger
+ ^ self morphicShapeDefault!! !!
+
+!!PPParser methodsFor: ''*petitgui-morphic'' stamp: ''lr 11/13/2009 13:43''!!
+morphicShapeSeen: aSet depth: anInteger do: aBlock
+ " avoid recursion "
+ (aSet includes: self)
+ ifTrue: [ ^ self morphicShapeDefault ].
+ " display nice name when possible "
+ (anInteger > 0 and: [ self name notNil ])
+ ifTrue: [ ^ self morphicShapeDefault ].
+ " don''t do it too deep "
+ (anInteger > 10)
+ ifTrue: [ ^ self morphicShapeDefault ].
+ aSet add: self.
+ ^ aBlock value: [ :parser |
+ parser
+ morphicShapeSeen: aSet
+ depth: anInteger + 1 ]!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-transforming'' stamp: ''lr 10/30/2010 11:54''!!
+transform: aBlock
+ "Answer a copy of all parsers reachable from the receiver transformed using aBlock."
+
+ | mapping root |
+ mapping := IdentityDictionary new.
+ self allParsersDo: [ :each |
+ mapping
+ at: each
+ put: (aBlock value: each copy) ].
+ root := mapping at: self.
+ [ | changed |
+ changed := false.
+ root allParsersDo: [ :each |
+ each children do: [ :old |
+ mapping at: old ifPresent: [ :new |
+ each replace: old with: new.
+ changed := true ] ] ].
+ changed ] whileTrue.
+ ^ root!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-transforming'' stamp: ''lr 4/13/2010 09:38''!!
+replace: aParser with: anotherParser
+ "Replace the references of the receiver pointing to aParser with anotherParser."!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 11/23/2010 10:55''!!
+namedChildrenDo: aBlock
+ "Iterate over the named children of the receiver."
+
+ self namedChildrenDo: aBlock seen: IdentitySet new!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 11/23/2010 10:01''!!
+allNamedParsers
+ "Answer all the named parse nodes of the receiver."
+
+ | result |
+ result := OrderedCollection new.
+ self allNamedParsersDo: [ :parser | result addLast: parser ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 11/23/2010 10:55''!!
+namedChildrenDo: aBlock seen: aSet
+ "Iterate over the named children of the receiver."
+
+ self children do: [ :each |
+ (aSet includes: each)
+ ifTrue: [ ^ self ].
+ aSet add: each.
+ each name isNil
+ ifTrue: [ each namedChildrenDo: aBlock seen: aSet ]
+ ifFalse: [ aBlock value: each ] ]!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 12/3/2010 16:45''!!
+innerChildren
+ "Answer the inner children of the receiver."
+
+ | result |
+ result := OrderedCollection new.
+ self innerChildrenDo: [ :parser | result addLast: parser ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 12/3/2010 16:51''!!
+innerChildrenDo: aBlock seen: aSet
+ "Iterate over the inner children of the receiver."
+
+ self children do: [ :each |
+ (aSet includes: each)
+ ifTrue: [ ^ self ].
+ aSet add: each.
+ each name isNil ifTrue: [
+ aBlock value: each.
+ each innerChildrenDo: aBlock seen: aSet ] ]!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 12/3/2010 16:48''!!
+innerChildrenDo: aBlock
+ "Iterate over the inner children of the receiver."
+
+ self innerChildrenDo: aBlock seen: IdentitySet new!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 11/23/2010 10:12''!!
+allNamedParsersDo: aBlock
+ "Iterate over all the named parse nodes of the receiver."
+
+ self allParsersDo: [ :each |
+ each name notNil
+ ifTrue: [ aBlock value: each ] ]!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-named'' stamp: ''lr 11/23/2010 10:55''!!
+namedChildren
+ "Answer the named children of the receiver."
+
+ | result |
+ result := OrderedCollection new.
+ self namedChildrenDo: [ :parser | result addLast: parser ].
+ ^ result!! !!
+
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 7/11/2011 11:03''!!
+trimBlanks
+ "Answer a new parser that consumes blanks before and after the receiving parser."
+
+ ^ self trim: #blank asParser!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 2/19/2010 07:42''!!
+answer: anObject
+ "Answer a new parser that always returns anObject from a successful parse."
+
+ ^ self ==> [ :nodes | anObject ]!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 7/11/2011 11:03''!!
+trim: aParser
+ "Answer a new parser that consumes and ignores aParser repeatedly before and after the receiving parser."
+
+ ^ PPTrimmingParser on: self trimmer: aParser!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 5/6/2011 20:28''!!
+map: aBlock
+ "Answer a new parser that works on the receiving sequence an passes in each element as a block argument."
+
+ ^ aBlock numArgs = 1
+ ifTrue: [ self ==> aBlock ]
+ ifFalse: [ self error: aBlock numArgs asString , '' arguments expected.'' ]
+!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 6/29/2010 14:25''!!
+token
+ "Answer a new parser that transforms the input to a token."
+
+ ^ PPTokenParser on: self!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 4/3/2011 14:59''!!
+foldRight: aBlock
+ "Answer a new parser that that folds the result of the receiver from right-to-left into aBlock. The argument aBlock must take two or more arguments."
+
+ | size args |
+ size := aBlock numArgs.
+ args := Array new: size.
+ ^ self ==> [ :nodes |
+ args at: size put: nodes last.
+ nodes size - size + 1 to: 1 by: 1 - size do: [ :index |
+ args
+ replaceFrom: 1 to: size - 1 with: nodes startingAt: index;
+ at: size put: (aBlock valueWithArguments: args) ].
+ args at: size ]!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 7/11/2011 11:03''!!
+trimSpaces
+ "Answer a new parser that consumes spaces before and after the receiving parser."
+
+ ^ self trim: #space asParser!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 5/15/2008 16:08''!!
+flatten
+ "Answer a new parser that flattens the underlying collection."
+
+ ^ PPFlattenParser on: self!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 7/31/2010 12:06''!!
+trim
+ "Answer a new parser that consumes spaces before and after the receiving parser."
+
+ ^ self trimSpaces!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 6/12/2010 10:20''!!
+>=> aBlock
+ "Answer a new parser that wraps the receiving parser with a two argument block. The first argument is the parsed stream, the second argument a continuation block on the delegate parser."
+
+ ^ PPWrappingParser on: self block: aBlock!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 5/12/2010 20:32''!!
+==> aBlock
+ "Answer a new parser that performs aBlock as action handler on success."
+
+ ^ PPActionParser on: self block: aBlock!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 4/3/2011 15:00''!!
+foldLeft: aBlock
+ "Answer a new parser that that folds the result of the receiver from left-to-right into aBlock. The argument aBlock must take two or more arguments."
+
+ | size args |
+ size := aBlock numArgs.
+ args := Array new: size.
+ ^ self ==> [ :nodes |
+ args at: 1 put: nodes first.
+ 2 to: nodes size by: size - 1 do: [ :index |
+ args
+ replaceFrom: 2 to: size with: nodes startingAt: index;
+ at: 1 put: (aBlock valueWithArguments: args) ].
+ args first ]!! !!
+
+!!PPParser methodsFor: ''operators-mapping'' stamp: ''lr 4/6/2010 19:26''!!
+token: aTokenClass
+ "Answer a new parser that transforms the input to a token of class aTokenClass."
+
+ ^ self token tokenClass: aTokenClass!! !!
+
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:57''!!
+max: anInteger lazy: aParser
+ "Answer a new parser that parses the receiver at most anInteger times until it reaches aParser. This is a lazy non-blind implementation. aParser is not consumed."
+
+ ^ (self starLazy: aParser) setMax: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/2/2011 10:01''!!
+starLazy: aParser
+ "Answer a new parser that parses the receiver zero or more times until it reaches aParser. This is a lazy non-blind implementation of the star operator. aParser is not consumed."
+
+ ^ PPLazyRepeatingParser on: self limit: aParser!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 9/15/2010 09:34''!!
+times: anInteger
+ "Answer a new parser that parses the receiver exactly anInteger times."
+
+ ^ self min: anInteger max: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:56''!!
+min: aMinInteger max: aMaxInteger greedy: aParser
+ "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed."
+
+ ^ (self starGreedy: aParser) setMin: aMinInteger; setMax: aMaxInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/2/2011 10:02''!!
+star
+ "Answer a new parser that parses the receiver zero or more times. This is a greedy and blind implementation that tries to consume as much input as possible and it does not consider what comes afterwards."
+
+ ^ PPPossessiveRepeatingParser on: self!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:02''!!
+min: anInteger
+ "Answer a new parser that parses the receiver at least anInteger times."
+
+ ^ self star setMin: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:03''!!
+min: aMinInteger max: aMaxInteger
+ "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times."
+
+ ^ self star setMin: aMinInteger; setMax: aMaxInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/2/2011 10:01''!!
+starGreedy: aParser
+ "Answer a new parser that parses the receiver zero or more times until it reaches aParser. This is a greedy non-blind implementation of the star operator. aParser is not consumed."
+
+ ^ PPGreedyRepeatingParser on: self limit: aParser!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:57''!!
+min: aMinInteger max: aMaxInteger lazy: aParser
+ "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed."
+
+ ^ (self starLazy: aParser) setMin: aMinInteger; setMax: aMaxInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:57''!!
+min: anInteger lazy: aParser
+ "Answer a new parser that parses the receiver at least anInteger times until it reaches aParser. This is a lazy non-blind implementation. aParser is not consumed."
+
+ ^ (self starLazy: aParser) setMin: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:56''!!
+max: anInteger greedy: aParser
+ "Answer a new parser that parses the receiver at most anInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed."
+
+ ^ (self starGreedy: aParser) setMax: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:03''!!
+plus
+ "Answer a new parser that parses the receiver one or more times."
+
+ ^ self star setMin: 1!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/3/2011 14:56''!!
+min: anInteger greedy: aParser
+ "Answer a new parser that parses the receiver at least anInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed."
+
+ ^ (self starGreedy: aParser) setMin: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:03''!!
+max: anInteger
+ "Answer a new parser that parses the receiver at most anInteger times."
+
+ ^ self star setMax: anInteger!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:04''!!
+plusGreedy: aParser
+ "Answer a new parser that parses the receiver one or more times until it reaches aParser. This is a greedy non-blind implementation of the star operator. aParser is not consumed."
+
+ ^ (self starGreedy: aParser) setMin: 1!! !!
+
+!!PPParser methodsFor: ''operators-repeating'' stamp: ''lr 4/1/2011 21:04''!!
+plusLazy: aParser
+ "Answer a new parser that parses the receiver one or more times until it reaches aParser. This is a lazy non-blind implementation of the star operator. aParser is not consumed."
+
+ ^ (self starLazy: aParser) setMin: 1!! !!
+
+
+!!PPParser methodsFor: ''*petitsmalltalk-operations'' stamp: ''lr 6/29/2010 14:27''!!
+smalltalkToken
+ ^ PPSmalltalkTokenParser on: self!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-testing'' stamp: ''lr 5/22/2010 10:45''!!
+isTerminal
+ "Answer true if the receiver is a terminal or leaf parser, that means it does not delegate to any other parser."
+
+ ^ self children isEmpty!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-testing'' stamp: ''JanKurs 5/31/2013 11:49''!!
+isFirstSetTerminal
+ "Answer true if the receiver is a terminal or leaf parser, that means it does not delegate to any other parser."
+
+ ^ self children isEmpty!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-testing'' stamp: ''lr 11/12/2009 17:25''!!
+isNullable
+ "Answer true if the receiver is a nullable parser, e.g. it can successfully parse nothing."
+
+ ^ false!! !!
+
+
+!!PPParser methodsFor: ''converting'' stamp: ''lr 11/29/2011 20:48''!!
+asParser
+ "Answer the receiving parser."
+
+ ^ self!! !!
+
+
+!!PPParser methodsFor: ''printing'' stamp: ''lr 4/16/2010 16:36''!!
+printNameOn: aStream
+ self name isNil
+ ifTrue: [ aStream print: self hash ]
+ ifFalse: [ aStream nextPutAll: self name ]!! !!
+
+!!PPParser methodsFor: ''printing'' stamp: ''lr 4/16/2010 16:36''!!
+printOn: aStream
+ super printOn: aStream.
+ aStream nextPut: $(.
+ self printNameOn: aStream.
+ aStream nextPut: $)!! !!
+
+
+!!PPParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/9/2009 14:37''!!
+example
+ ^ String streamContents: [ :stream | self exampleOn: stream ] limitedTo: 1024!! !!
+
+!!PPParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/9/2009 14:20''!!
+exampleOn: aStream!! !!
+
+!!PPParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 9/12/2011 18:34''!!
+displayColor
+ ^ self isTerminal
+ ifTrue: [ Color r: 0.5 g: 0.0 b: 0.5 ]
+ ifFalse: [ Color blue ]!! !!
+
+!!PPParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/6/2009 18:31''!!
+displayName
+ ^ self name isNil
+ ifFalse: [ self name asString ]
+ ifTrue: [ self class name asString ]!! !!
+
+!!PPParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/13/2009 14:11''!!
+backgroundForDepth: anInteger
+ ^ Color gray: 1.0 - (anInteger / 20.0)!! !!
+
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 10/29/2010 17:05''!!
+parse: anObject onError: aBlock
+ "Parse anObject with the receiving parser and answer the parse-result or answer the result of evaluating aBlock. Depending on the number of arguments of the block it is simply evaluated, evaluated with the failure object, or evaluated with the error message and position."
+
+ | result |
+ result := self parse: anObject.
+ result isPetitFailure
+ ifFalse: [ ^ result ].
+ aBlock numArgs = 0
+ ifTrue: [ ^ aBlock value ].
+ aBlock numArgs = 1
+ ifTrue: [ ^ aBlock value: result ].
+ ^ aBlock value: result message value: result position!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 6/4/2011 18:12''!!
+matchesIn: anObject
+ "Search anObject repeatedly for the matches of the receiver. Answered an OrderedCollection of the matched parse-trees."
+
+ | result |
+ result := OrderedCollection new.
+ self
+ matchesIn: anObject
+ do: [ :each | result addLast: each ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 8/16/2011 07:26''!!
+matchesSkipIn: anObject
+ "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of the matched parse-trees. Skip over matches."
+
+ | result |
+ result := OrderedCollection new.
+ self
+ matchesSkipIn: anObject
+ do: [ :each | result addLast: each ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 2/25/2013 23:42''!!
+matchingSkipRangesIn: anObject do: aBlock
+ "Search anObject repeatedly for the matches of the receiver. Skip over matches. Evaluate aBlock with the range of each match (index of first character to: index of last character)."
+
+ self token
+ matchesSkipIn: anObject
+ do: [ :token | aBlock value: (token start to: token stop) ]!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''DamienCassou 10/29/2011 19:18''!!
+matchingSkipRangesIn: anObject
+ "Search anObject repeatedly for the matches of the receiver. Skip over matches. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)."
+
+ | result |
+ result := OrderedCollection new.
+ self
+ matchingSkipRangesIn: anObject
+ do: [ :value | result addLast: value ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 6/4/2011 18:12''!!
+matchingRangesIn: anObject
+ "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)."
+
+ | result |
+ result := OrderedCollection new.
+ self
+ matchingRangesIn: anObject
+ do: [ :value | result addLast: value ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 8/16/2011 07:26''!!
+matchesSkipIn: anObject do: aBlock
+ "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock for each match with the matched parse-tree as the argument. Skip over matches."
+
+ (self ==> aBlock / #any asParser) star parse: anObject!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 2/25/2013 23:41''!!
+matchingRangesIn: anObject do: aBlock
+ "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock with the range of each match (index of first character to: index of last character)."
+
+ self token
+ matchesIn: anObject
+ do: [ :token | aBlock value: (token start to: token stop) ]!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 2/8/2010 00:30''!!
+matches: anObject
+ "Answer if anObject can be parsed by the receiver."
+
+ ^ (self parse: anObject) isPetitFailure not!! !!
+
+!!PPParser methodsFor: ''parsing'' stamp: ''lr 3/1/2010 21:51''!!
+matchesIn: anObject do: aBlock
+ "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock for each match with the matched parse-tree as the argument. Make sure to always consume exactly one character with each step, to not miss any match."
+
+ ((self and ==> aBlock , #any asParser) / #any asParser) star parse: anObject!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 5/31/2010 18:37''!!
+matchList: matchList index: matchIndex against: parserList index: parserIndex inContext: aDictionary seen: aSet
+ | parser currentIndex currentDictionary currentSeen parsers |
+ matchList size < matchIndex
+ ifTrue: [ ^ parserList size < parserIndex ].
+ parser := matchList at: matchIndex.
+ parser class = PPListPattern ifTrue: [
+ currentIndex := parserIndex - 1.
+ [ currentDictionary := aDictionary copy.
+ currentSeen := aSet copy.
+ parserList size < currentIndex or: [
+ parsers := parserList copyFrom: parserIndex to: currentIndex.
+ (currentDictionary at: parser ifAbsentPut: [ parsers ]) = parsers and: [
+ (self
+ matchList: matchList
+ index: matchIndex + 1
+ against: parserList
+ index: currentIndex + 1
+ inContext: currentDictionary
+ seen: currentSeen)
+ ifTrue: [
+ currentDictionary keysAndValuesDo: [ :key :value | aDictionary at: key put: value ].
+ ^ true ].
+ false ] ] ] whileFalse: [ currentIndex := currentIndex + 1 ].
+ ^ false ].
+ parserList size < parserIndex
+ ifTrue: [ ^ false ].
+ (parser match: (parserList at: parserIndex) inContext: aDictionary seen: aSet)
+ ifFalse: [ ^ false ].
+ ^ self
+ matchList: matchList
+ index: matchIndex + 1
+ against: parserList
+ index: parserIndex + 1
+ inContext: aDictionary
+ seen: aSet!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 7/17/2011 11:53''!!
+copyInContext: aDictionary seen: aSeenDictionary
+ | copy |
+ aSeenDictionary
+ at: self
+ ifPresent: [ :value | ^ value ].
+ copy := aSeenDictionary
+ at: self
+ put: self copy.
+ copy children do: [ :each |
+ copy
+ replace: each
+ with: (each copyInContext: aDictionary seen: aSeenDictionary) ].
+ ^ copy!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 4/30/2010 07:49''!!
+copyInContext: aDictionary
+ ^ self copyInContext: aDictionary seen: IdentityDictionary new!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 4/29/2010 23:07''!!
+matchList: matchList against: parserList inContext: aDictionary seen: aSet
+ ^ self matchList: matchList index: 1 against: parserList index: 1 inContext: aDictionary seen: aSet!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 6/18/2010 14:09''!!
+match: aParser inContext: aDictionary seen: anIdentitySet
+ "This is the default implementation to match two parsers. This code can properly handle recursion. This is code is supposed to be overridden in subclasses that add new state."
+
+ (self == aParser or: [ anIdentitySet includes: self ])
+ ifTrue: [ ^ true ].
+ anIdentitySet add: self.
+ ^ self class = aParser class and: [ self matchList: self children against: aParser children inContext: aDictionary seen: anIdentitySet ]!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 4/29/2010 23:14''!!
+match: aParser inContext: aDictionary
+ ^ self match: aParser inContext: aDictionary seen: IdentitySet new!! !!
+
+
+!!PPParser methodsFor: ''testing'' stamp: ''lr 10/27/2008 11:28''!!
+isUnresolved
+ ^ false!! !!
+
+!!PPParser methodsFor: ''testing'' stamp: ''lr 8/6/2010 16:44''!!
+isPetitParser
+ ^ true!! !!
+
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:32''!!
+propertyAt: aKey ifAbsentPut: aBlock
+ "Answer the property associated with aKey or, if aKey isn''t found store the result of evaluating aBlock as new value."
+
+ ^ self propertyAt: aKey ifAbsent: [ self propertyAt: aKey put: aBlock value ]!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:33''!!
+removeProperty: aKey ifAbsent: aBlock
+ "Remove the property with aKey. Answer the value or, if aKey isn''t found, answer the result of evaluating aBlock."
+
+ | answer |
+ properties isNil ifTrue: [ ^ aBlock value ].
+ answer := properties removeKey: aKey ifAbsent: aBlock.
+ properties isEmpty ifTrue: [ properties := nil ].
+ ^ answer!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:32''!!
+propertyAt: aKey
+ "Answer the property value associated with aKey."
+
+ ^ self propertyAt: aKey ifAbsent: [ self error: ''Property not found'' ]!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:32''!!
+propertyAt: aKey ifAbsent: aBlock
+ "Answer the property value associated with aKey or, if aKey isn''t found, answer the result of evaluating aBlock."
+
+ ^ properties isNil
+ ifTrue: [ aBlock value ]
+ ifFalse: [ properties at: aKey ifAbsent: aBlock ]!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:33''!!
+propertyAt: aKey put: anObject
+ "Set the property at aKey to be anObject. If aKey is not found, create a new entry for aKey and set is value to anObject. Answer anObject."
+
+ ^ (properties ifNil: [ properties := Dictionary new: 1 ])
+ at: aKey put: anObject!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:32''!!
+hasProperty: aKey
+ "Test if the property aKey is present."
+
+ ^ properties notNil and: [ properties includesKey: aKey ]!! !!
+
+!!PPParser methodsFor: ''accessing-properties'' stamp: ''lr 4/19/2010 10:33''!!
+removeProperty: aKey
+ "Remove the property with aKey. Answer the property or raise an error if aKey isn''t found."
+
+ ^ self removeProperty: aKey ifAbsent: [ self error: ''Property not found'' ]!! !!
+
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''AlexandreBergel 12/18/2013 16:41''!!
+visualizationGraphType
+ ^ nil!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''AlexandreBergel 12/18/2013 17:26''!!
+visualizeStructureInGraphOn: view
+ view shape rectangle
+ borderWidth: 1;
+ if: [ :p | p name isNil ] fillColor: Color lightGray.
+
+ view interaction
+ item: ''Explore'' action: #explore;
+ highlightWhenOver: [ :p |
+ self allParsers select: [ :ch | ch children includes: p ]
+ ] color: Color orange muchLighter;
+ highlightWhenOver: [ :p | |children|
+ children := p namedChildren.
+ ] color: Color orange muchDarker;
+ highlightWhenOver: [ :p | Array with: p ] color: Color orange;
+ popupText: [:p | p class name asString ].
+
+ view
+ nodes: self allParsers
+ forEach: [ :aParser | |labels|
+ labels := OrderedCollection new.
+ aParser name notNil ifTrue: [ labels add: aParser name ].
+ aParser visualizationGraphType notNil ifTrue: [ labels add: aParser visualizationGraphType ].
+ labels isEmpty ifFalse: [
+ view shape label.
+ view interaction forwarder.
+ view nodes: labels asArray ].
+ ].
+
+ view shape: (ROLine new add: (ROArrow new size: 4) offset: 0.1).
+ view edgesToAll: #children.
+ view treeLayout
+ layered;
+ on: ROLayoutEnd do: [ :evt | ROFocusView on: (view raw elementFromModel: self) ].
+
+ view zoomInButton.
+ view zoomOutButton.!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''tg 8/25/2010 00:32''!!
+namedParsersDo: aBlock
+ self namedParsersDo: aBlock seen: IdentitySet new!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''VincentBlondeau 2/14/2014 17:06''!!
+viewAllNamedParsersWithSelection: aCollectionOfNames previewing: aBlock on: view
+ view shape label
+ color: [ :each |
+ (aCollectionOfNames includes: each name)
+ ifFalse: [ Color black ]
+ ifTrue: [ Color red ] ];
+ text: [ :each | each displayName ].
+ view interaction popupText: aBlock.
+ view interaction item: ''Explore'' action: #explore.
+ view nodes: (self allParsers reject: [ :each | each name isEmptyOrNil ]).
+ view edges: (self allParsers reject: [ :each | each name isEmptyOrNil ]) from: #yourself toAll: #namedParsers.
+ view horizontalDominanceTreeLayout
+ verticalGap: 10;
+ layered!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''AlexandreBergel 12/18/2013 17:21''!!
+visualizeStructureInGraph
+
+ "
+ PPSmalltalkParser new visualize
+
+
+ "
+ | view |
+
+ view := ROMondrianViewBuilder new.
+ self visualizeStructureInGraphOn: view.
+ view open.
+ ^ view!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''VincentBlondeau 2/14/2014 17:06''!!
+viewAllNamedParsersOn: view
+ view shape
+ rectangleWithoutBorder;
+ withText: #displayName.
+ view nodes: (self allParsers reject: [ :each | each name isEmptyOrNil ]).
+ view edgesToAll: #namedParsers.
+ view horizontalDominanceTreeLayout layered!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''TudorGirba 12/6/2011 07:43''!!
+viewAllNamedParsersWithSelection: aCollectionOfNames on: view
+ self viewAllNamedParsersWithSelection: aCollectionOfNames previewing: [ :each | each name ] on: view!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''TudorGirba 12/14/2011 12:40''!!
+namedParsersDo: aBlock seen: aSet
+ self children do: [ :each |
+ (aSet includes: each)
+ ifFalse: [
+ aSet add: each.
+ each name isEmptyOrNil
+ ifFalse: [ aBlock value: each ]
+ ifTrue: [ each namedParsersDo: aBlock seen: aSet ] ] ]!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''TudorGirba 6/5/2013 23:01''!!
+viewAllNamedParsers
+ | view |
+ view := ROMondrianViewBuilder new.
+ self viewAllNamedParsersOn: view.
+ ^ view open setLabel: ''All named parsers''!! !!
+
+!!PPParser methodsFor: ''*petitgui-mondrian'' stamp: ''tg 8/25/2010 00:31''!!
+namedParsers
+ | result |
+ result := OrderedCollection new.
+ self namedParsersDo: [ :parser | result addLast: parser ].
+ ^ result!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-enumerating'' stamp: ''lr 4/13/2010 08:36''!!
+allParsers
+ "Answer all the parse nodes of the receiver."
+
+ | result |
+ result := OrderedCollection new.
+ self allParsersDo: [ :parser | result addLast: parser ].
+ ^ result!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-enumerating'' stamp: ''lr 4/13/2010 08:36''!!
+allParsersDo: aBlock
+ "Iterate over all the parse nodes of the receiver."
+
+ self allParsersDo: aBlock seen: IdentitySet new!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-enumerating'' stamp: ''lr 4/13/2010 08:35''!!
+allParsersDo: aBlock seen: aSet
+ "Iterate over all the parse nodes of the receiver, do not visit and follow the ones contained in aSet."
+
+ (aSet includes: self)
+ ifTrue: [ ^ self ].
+ aSet add: self.
+ aBlock value: self.
+ self children
+ do: [ :each | each allParsersDo: aBlock seen: aSet ]!! !!
+
+
+!!PPParser methodsFor: ''operators-convenience'' stamp: ''lr 2/19/2010 07:56''!!
+separatedBy: aParser
+ "Answer a new parser that parses the receiver one or more times, separated by aParser."
+
+ ^ (PPSequenceParser with: self with: (PPSequenceParser with: aParser with: self) star) ==> [ :nodes |
+ | result |
+ result := Array new: 2 * nodes second size + 1.
+ result at: 1 put: nodes first.
+ nodes second
+ keysAndValuesDo: [ :index :pair | result replaceFrom: 2 * index to: 2 * index + 1 with: pair startingAt: 1 ].
+ result ]!! !!
+
+!!PPParser methodsFor: ''operators-convenience'' stamp: ''lr 2/19/2010 07:42''!!
+delimitedBy: aParser
+ "Answer a new parser that parses the receiver one or more times, separated and possibly ended by aParser."
+
+ ^ (self separatedBy: aParser) , (aParser optional) ==> [ :node |
+ node second isNil
+ ifTrue: [ node first ]
+ ifFalse: [ node first copyWith: node second ] ]!! !!
+
+!!PPParser methodsFor: ''operators-convenience'' stamp: ''lr 2/25/2012 16:54''!!
+withoutSeparators
+ "Filters out the separators from a parse result produced by one of the productions #delimitedBy: or #separatedBy:."
+
+ ^ self ==> [ :items |
+ | result |
+ result := Array new: items size + 1 // 2.
+ 1 to: result size do: [ :index | result at: index put: (items at: 2 * index - 1) ].
+ result ]!! !!
+
+
+!!PPParser methodsFor: ''copying'' stamp: ''lr 4/19/2010 10:33''!!
+postCopy
+ super postCopy.
+ properties := properties copy!! !!
+
+
+!!PPParser methodsFor: ''initialization'' stamp: ''lr 4/24/2008 10:33''!!
+initialize!! !!
+
+
+!!PPParser methodsFor: ''*petitgui-morphic-creational'' stamp: ''lr 11/17/2009 21:58''!!
+newColumnMorph
+ ^ AlignmentMorph newColumn
+ cellPositioning: #topLeft;
+ color: Color transparent;
+ listCentering: #topLeft;
+ vResizing: #shrinkWrap;
+ hResizing: #shrinkWrap;
+ layoutInset: 0;
+ yourself!! !!
+
+!!PPParser methodsFor: ''*petitgui-morphic-creational'' stamp: ''lr 11/17/2009 21:57''!!
+newRowMorph
+ ^ AlignmentMorph newRow
+ cellPositioning: #topLeft;
+ color: Color transparent;
+ listCentering: #topLeft;
+ vResizing: #shrinkWrap;
+ hResizing: #shrinkWrap;
+ layoutInset: 0;
+ yourself!! !!
+
+!!PPParser methodsFor: ''*petitgui-morphic-creational'' stamp: ''lr 11/17/2009 22:03''!!
+newSpacerMorph
+ ^ Morph new
+ color: Color transparent;
+ borderWidth: 0;
+ extent: 7 @ 7;
+ yourself!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-querying'' stamp: ''lr 9/16/2010 17:55''!!
+followSets
+ "Answer a dictionary with all the parsers reachable from the receiver as key and their follow-set as value. The follow-set of a parser is the list of terminal parsers that can appear immediately to the right of that parser."
+
+ | current previous continue firstSets followSets |
+ current := previous := 0.
+ firstSets := self firstSets.
+ followSets := IdentityDictionary new.
+ self allParsersDo: [ :each | followSets at: each put: IdentitySet new ].
+ (followSets at: self) add: PPSentinel instance.
+ [ followSets keysAndValuesDo: [ :parser :follow |
+ parser
+ followSets: followSets
+ firstSets: firstSets
+ into: follow ].
+ current := followSets
+ inject: 0
+ into: [ :result :each | result + each size ].
+ continue := previous < current.
+ previous := current.
+ continue ] whileTrue.
+ ^ followSets!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-querying'' stamp: ''lr 10/22/2009 19:59''!!
+firstSet
+ "Answer the first-set of the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #firstSets to calculate the first-sets at once."
+
+ ^ self firstSets at: self!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-querying'' stamp: ''lr 11/19/2009 23:49''!!
+cycleSet
+ "Answer a set of all nodes that are within one or more cycles of left-recursion. This is generally not a problem if at least one of the nodes is memoized, but it might make the grammar very inefficient and should be avoided if possible."
+
+ | cycles |
+ cycles := IdentitySet new.
+ self cycleSet: OrderedCollection new firstSets: self firstSets into: cycles.
+ ^ cycles!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-querying'' stamp: ''JanKurs 5/31/2013 11:49''!!
+firstSets
+ "Answer a dictionary with all the parsers reachable from the receiver as key and their first-set as value. The first-set of a parser is the list of terminal parsers that begin the parser derivable from that parser."
+
+ | firstSets |
+ firstSets := IdentityDictionary new.
+ self allParsersDo: [ :each |
+ firstSets at: each put: (each isFirstSetTerminal
+ ifTrue: [ IdentitySet with: each ]
+ ifFalse: [ IdentitySet new ]).
+ each isNullable
+ ifTrue: [ (firstSets at: each) add: PPSentinel instance ] ].
+ [ | changed tally |
+ changed := false.
+ firstSets keysAndValuesDo: [ :parser :first |
+ tally := first size.
+ parser firstSets: firstSets into: first.
+ changed := changed or: [ tally ~= first size ] ].
+ changed ] whileTrue.
+ ^ firstSets!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-querying'' stamp: ''lr 11/12/2009 21:13''!!
+followSet
+ "Answer the follow-set of the receiver starting at the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #followSets to calculate the follow-sets at once."
+
+ ^ self followSets at: self!! !!
+
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 11/11/2013 09:30''!!
+parseOn: aPPContext
+ "Parse aStream with the receiving parser and answer the parse-result or an instance of PPFailure. Override this method in subclasses to specify custom parse behavior. Do not call this method from outside, instead use #parse:."
+
+ self subclassResponsibility!! !!
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 3/17/2014 13:15''!!
+debugWithContext: aPPContext
+
+ ^ self enableDebug parseWithContext: aPPContext !! !!
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 3/11/2014 13:33''!!
+updateContext: aPPContext
+ "nothing to do"!! !!
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 8/19/2014 13:26''!!
+parse: anObject withContext: aPPContext
+ "Parse anObject with the receiving parser and answer the parse-result or an instance of PPFailure."
+
+ aPPContext stream: anObject asPetitStream.
+ ^ self parseWithContext: aPPContext.
+!! !!
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 8/19/2014 13:25''!!
+parse: anObject
+ "Parse anObject with the receiving parser and answer the parse-result or an instance of PPFailure."
+
+ ^ self parse: anObject withContext: PPContext new!! !!
+
+!!PPParser methodsFor: ''pp-context'' stamp: ''JanKurs 3/19/2014 16:34''!!
+parseWithContext: context
+ context root: self.
+ self updateContext: context.
+ ^ self parseOn: context!! !!
+
+
+!!PPParser methodsFor: ''accessing'' stamp: ''lr 10/21/2009 16:38''!!
+children
+ "Answer a set of child parsers that could follow the receiver."
+
+ ^ #()!! !!
+
+!!PPParser methodsFor: ''accessing'' stamp: ''lr 4/19/2010 10:38''!!
+name: aString
+ self propertyAt: #name put: aString!! !!
+
+!!PPParser methodsFor: ''accessing'' stamp: ''lr 4/19/2010 10:35''!!
+name
+ "Answer the production name of the receiver."
+
+ ^ self propertyAt: #name ifAbsent: [ nil ]!! !!
+
+
+!!PPParser methodsFor: ''*petitanalyzer-private'' stamp: ''lr 11/19/2009 23:47''!!
+cycleSet: aDictionary
+ "PRIVATE: Answer the children that could be part of a cycle-set with the receiver, subclasses might restrict the number of children returned. aDictionary is pre-calcualted first-sets."
+
+ ^ self children!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-private'' stamp: ''lr 5/22/2010 10:45''!!
+cycleSet: aStack firstSets: aDictionary into: aSet
+ "PRIVATE: Try to find a cycle, where aStack contains the previously visited parsers. The method returns quickly when the receiver is a terminal, terminals cannot be part of a cycle. If aStack already contains the receiver, then we are in a cycle. In this case we don''t process the children further and add the nodes to aSet."
+
+ | index |
+ self isTerminal
+ ifTrue: [ ^ self ].
+ (index := aStack indexOf: self) > 0
+ ifTrue: [ ^ aSet addAll: (aStack copyFrom: index to: aStack size) ].
+ aStack addLast: self.
+ (self cycleSet: aDictionary)
+ do: [ :each | each cycleSet: aStack firstSets: aDictionary into: aSet ].
+ aStack removeLast!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-private'' stamp: ''lr 11/12/2009 21:25''!!
+firstSets: aFirstDictionary into: aSet
+ "PRIVATE: Try to add additional elements to the first-set aSet of the receiver, use the incomplete aFirstDictionary."
+
+ self children do: [ :parser | aSet addAll: (aFirstDictionary at: parser) ]!! !!
+
+!!PPParser methodsFor: ''*petitanalyzer-private'' stamp: ''lr 11/12/2009 21:25''!!
+followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet
+ "PRIVATE: Try to add additional elements to the follow-set aSet of the receiver, use the incomplete aFollowDictionary and the complete aFirstDictionary."
+
+ self children do: [ :parser | (aFollowDictionary at: parser) addAll: aSet ]!! !!
+
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 1/16/2014 15:41''!!
+debug: anObject
+ "Parse anObject with the receiving parser and answer the parse-result or an instance of PPFailure."
+
+ ^ self enableDebug parse: anObject asPetitStream!! !!
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 3/18/2014 12:21''!!
+enableDebuggerOutput
+ self debuggerOutput: true.!! !!
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 4/22/2013 18:04''!!
+debuggerOutput: aBoolean
+ self propertyAt: #debuggerOutput put: aBoolean!! !!
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 3/18/2014 12:21''!!
+disableDebuggerOutput
+ self debuggerOutput: false. !! !!
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 3/18/2014 17:01''!!
+enableDebug
+ | root newParser |
+ root := PPParserDebuggerResult new.
+
+ newParser := self transform: [:each |
+ each >=> [:stream :continuation |
+ | result child |
+ child := PPParserDebuggerResult new
+ parser: each;
+ parent: root.
+ root := root children add: child.
+ child start: stream position + 1.
+ child showChildren: each debuggerOutput.
+ result := continuation value.
+ child end: stream position.
+ root result: result.
+ root := root parent.
+ result
+ ]
+ ].
+
+ ^ PPDebugParser on: newParser root: root.
+!! !!
+
+!!PPParser methodsFor: ''*petitgui-debug'' stamp: ''JanKurs 4/22/2013 18:04''!!
+debuggerOutput
+ ^ self propertyAt: #debuggerOutput ifAbsentPut: true.!! !!
+
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 2/19/2010 07:36''!!
+negate
+ "Answer a new parser consumes any input token but the receiver."
+
+ ^ self not , #any asParser ==> #second!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 9/1/2010 22:03''!!
+optional
+ "Answer a new parser that parses the receiver, if possible."
+
+ ^ PPOptionalParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 12/3/2010 11:34''!!
+def: aParser
+ "Redefine the receiver as the argument aParser. This method is useful when defining recursive parsers: instantiate a PPUnresolvedParser and later redefine it with another one."
+
+ ^ self becomeForward: (aParser name: self name)!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 10/23/2008 14:05''!!
+wrapped
+ "Answer a new parser that is simply wrapped."
+
+ ^ PPDelegateParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 5/31/2010 16:34''!!
+memoized
+ "Answer a new memoized parser, for refraining redundant computations. This ensures polynomial time O(n^4) for left-recursive grammars and O(n^3) for non left-recursive grammars in the worst case. Not necessary for most grammars that are carefully written and in O(n) anyway."
+
+ ^ PPMemoizedParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 5/31/2010 15:12''!!
+and
+ "Answer a new parser (logical and-predicate) that succeeds whenever the receiver does, but never consumes input."
+
+ ^ PPAndParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 4/14/2010 11:46''!!
+/ aParser
+ "Answer a new parser that parses the receiver, if the receiver fails try with aParser (ordered-choice)."
+
+ ^ PPChoiceParser with: self with: aParser!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 4/30/2010 12:13''!!
+end
+ "Answer a new parser that succeeds at the end of the input and return the result of the receiver."
+
+ ^ PPEndOfInputParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 5/31/2010 15:12''!!
+not
+ "Answer a new parser (logical not-predicate) that succeeds whenever the receiver fails, but never consumes input."
+
+ ^ PPNotParser on: self!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 4/14/2010 11:53''!!
+| aParser
+ "Answer a new parser that either parses the receiver or aParser. Fail if both pass or fail (exclusive choice, unordered choice)."
+
+ ^ (self not , aParser) / (aParser not , self) ==> #second!! !!
+
+!!PPParser methodsFor: ''operators'' stamp: ''lr 9/23/2008 18:32''!!
+, aParser
+ "Answer a new parser that parses the receiver followed by aParser."
+
+ ^ PPSequenceParser with: self with: aParser!! !!
+
+"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!!
+
+PPParser class
+ instanceVariableNames: ''''!!
+!!PPParser class commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPParser class methodsFor: ''instance creation'' stamp: ''lr 10/27/2008 11:17''!!
+named: aString
+ ^ self new name: aString!! !!
+
+!!PPParser class methodsFor: ''instance creation'' stamp: ''lr 4/18/2008 14:00''!!
+new
+ ^ self basicNew initialize!! !!
+
+
+PPParser subclass: #PPPluggableParser
+ instanceVariableNames: ''block''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Parsers''!!
+!!PPPluggableParser commentStamp: '''' prior: 0!!
+A pluggable parser that passes the parser stream into a block. This enables users to perform manual parsing or to embed other parser frameworks into PetitParser.
+
+Instance Variables:
+ block The pluggable one-argument block.
+!!
+
+
+!!PPPluggableParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 6/18/2010 14:09''!!
+match: aParser inContext: aDictionary seen: anIdentitySet
+ ^ (super match: aParser inContext: aDictionary seen: anIdentitySet) and: [ self block = aParser block ]!! !!
+
+
+!!PPPluggableParser methodsFor: ''initialization'' stamp: ''lr 5/2/2010 16:52''!!
+initializeOn: aBlock
+ block := aBlock!! !!
+
+
+!!PPPluggableParser methodsFor: ''pp-context'' stamp: ''JanKurs 11/11/2013 09:42''!!
+parseOn: aPPContext
+ | position result |
+ position := aPPContext remember.
+ result := block value: aPPContext.
+ result isPetitFailure
+ ifTrue: [ aPPContext restore: position ].
+ ^ result!! !!
+
+
+!!PPPluggableParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/13/2009 14:41''!!
+displayName
+ ^ String streamContents: [ :stream | block decompile shortPrintOn: stream ]!! !!
+
+
+!!PPPluggableParser methodsFor: ''accessing'' stamp: ''lr 4/30/2010 11:10''!!
+block
+ "Answer the pluggable block."
+
+ ^ block!! !!
+
+"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!!
+
+PPPluggableParser class
+ instanceVariableNames: ''''!!
+!!PPPluggableParser class commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPPluggableParser class methodsFor: ''instance creation'' stamp: ''lr 5/2/2010 16:52''!!
+on: aBlock
+ ^ self new initializeOn: aBlock!! !!
+
+
+PPParser subclass: #PPFailingParser
+ instanceVariableNames: ''message''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Parsers''!!
+!!PPFailingParser commentStamp: '''' prior: 0!!
+A parser that consumes nothing and always fails.
+
+Instance Variables:
+ message The failure message.!!
+
+
+!!PPFailingParser methodsFor: ''initialization'' stamp: ''lr 5/2/2010 19:16''!!
+setMessage: aString
+ message := aString!! !!
+
+
+!!PPFailingParser methodsFor: ''pp-context'' stamp: ''JanKurs 8/19/2014 16:59''!!
+parseOn: aPPContext
+ ^ PPFailure message: message context: aPPContext!! !!
+
+
+!!PPFailingParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/6/2009 18:43''!!
+displayName
+ ^ message!! !!
+
+!!PPFailingParser methodsFor: ''*petitgui-accessing'' stamp: ''lr 11/13/2009 14:16''!!
+displayColor
+ ^ Color red!! !!
+
+
+!!PPFailingParser methodsFor: ''printing'' stamp: ''lr 4/16/2010 21:27''!!
+printNameOn: aStream
+ super printNameOn: aStream.
+ aStream nextPutAll: '', ''; print: message!! !!
+
+
+!!PPFailingParser methodsFor: ''*petitanalyzer-matching'' stamp: ''lr 4/30/2010 12:01''!!
+match: aParser inContext: aDictionary seen: anIdentitySet
+ ^ (super match: aParser inContext: aDictionary seen: anIdentitySet) and: [ self message = aParser message ]!! !!
+
+
+!!PPFailingParser methodsFor: ''accessing'' stamp: ''lr 4/30/2010 11:10''!!
+message
+ "Answer the error message of the receiving parser."
+
+ ^ message!! !!
+
+"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!!
+
+PPFailingParser class
+ instanceVariableNames: ''''!!
+!!PPFailingParser class commentStamp: '''' prior: 0!!
+!!
+
+
+!!PPFailingParser class methodsFor: ''instance creation'' stamp: ''lr 5/2/2010 19:16''!!
+message: aString
+ ^ self new setMessage: aString!! !!
+
+
+PPParser subclass: #PPLiteralParser
+ instanceVariableNames: ''literal message''
+ classVariableNames: ''''
+ poolDictionaries: ''''
+ category: ''PetitParser-Parsers''!!
+!!PPLiteralParser commentStamp: '''' prior: 0!!
+Abstract literal parser that parses some kind of literal type (to be specified by subclasses).
+
+Instance Variables:
+ literal