[e-cvs] cvs commit: e/src/jsrc/org/quasiliteral/term QuasiBuilder.java QuasiBuilderAdaptor.java Term.java Term.updoc TermParser.java term.y
markm@eros.cs.jhu.edu
markm@eros.cs.jhu.edu
Fri, 21 Dec 2001 00:30:35 -0500
markm 01/12/21 00:30:35
Modified: src Makefile
src/jsrc/org/erights/e/develop/assertion T.java
src/jsrc/org/quasiliteral/quasiterm QAstroArg.java
QBuilder.java QTerm.java
src/jsrc/org/quasiliteral/term QuasiBuilder.java
QuasiBuilderAdaptor.java Term.java Term.updoc
TermParser.java term.y
Added: src/jsrc/org/quasiliteral/quasiterm QAstro.java QAtHole.java
QDollarHole.java QFunctor.java QHole.java
QSome.java
Log:
quasiliteral terms work with quantifiers. Ready for the 0.8.10epsilon1 release
Revision Changes Path
1.131 +2 -2 e/src/Makefile
Index: Makefile
===================================================================
RCS file: /cvs/e/src/Makefile,v
retrieving revision 1.130
retrieving revision 1.131
diff -u -r1.130 -r1.131
--- Makefile 2001/12/18 05:24:40 1.130
+++ Makefile 2001/12/21 05:30:35 1.131
@@ -7,8 +7,8 @@
# Prefix tagging this release's attributes
PREFIX=E
-DOTVER=0.8.10delta5
-TAGVER=0_8_10delta5
+DOTVER=0.8.10epsilon1
+TAGVER=0_8_10epsilon1
RELEASE=working
TOP=..
1.2 +90 -88 e/src/jsrc/org/erights/e/develop/assertion/T.java
Index: T.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/develop/assertion/T.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- T.java 2001/12/18 05:24:41 1.1
+++ T.java 2001/12/21 05:30:35 1.2
@@ -49,16 +49,18 @@
*/
public class T {
- static private final String prefix = "Internal: ";
+ static private final String internal = "Internal: ";
+ static private final String failed = "Failed: ";
+
/**
* If this method is executed, it throws an AssertionError with the
- * message "Internal: 'Unreachable' code was reached." Plant
+ * message "Internal: 'Unreachable' code was reached." Plant
* such assertions in places the program should never reach (such as
* the default case in a switch).
*/
static public void fail() throws AssertionError {
- throw new AssertionError(prefix + "'Unreachable' code was reached.");
+ throw new AssertionError(internal + "'Unreachable' code was reached.");
}
/**
@@ -66,7 +68,7 @@
* given explanation, prefixed by "Internal: ".
*/
static public void fail(String explanation) throws AssertionError {
- throw new AssertionError(prefix + explanation);
+ throw new AssertionError(internal + explanation);
}
/**
@@ -75,7 +77,7 @@
*/
static public void test(boolean mustBeTrue) throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix + "Assertion failed.");
+ throw new AssertionError(internal + "Assertion failed.");
}
}
@@ -87,7 +89,7 @@
String explanation)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation);
}
}
@@ -106,7 +108,7 @@
int explanation1)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1);
}
@@ -126,7 +128,7 @@
Object explanation1)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1);
}
@@ -146,7 +148,7 @@
Object explanation2)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2);
@@ -168,7 +170,7 @@
Object explanation3)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2 +
@@ -192,7 +194,7 @@
Object explanation4)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2 +
@@ -218,7 +220,7 @@
Object explanation5)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2 +
@@ -246,7 +248,7 @@
Object explanation6)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2 +
@@ -276,7 +278,7 @@
Object explanation7)
throws AssertionError {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
+ throw new AssertionError(internal +
explanation0 +
explanation1 +
explanation2 +
@@ -289,22 +291,22 @@
}
/**
- * If the argument is false, throws an AssertionError with the
- * given explanation, prefixed by "Internal: ".
+ * If the argument is false, throws a RuntimeException with the
+ * given explanation, prefixed by "Failed: ".
*/
static public void require(boolean mustBeTrue,
String explanation)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation);
+ throw new RuntimeException(failed +
+ explanation);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p>
* Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
@@ -313,18 +315,18 @@
static public void requireSI(boolean mustBeTrue,
Object explanation0,
int explanation1)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p>
* Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
@@ -333,18 +335,18 @@
static public void require(boolean mustBeTrue,
Object explanation0,
Object explanation1)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -353,19 +355,19 @@
Object explanation0,
Object explanation1,
Object explanation2)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -375,20 +377,20 @@
Object explanation1,
Object explanation2,
Object explanation3)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2 +
- explanation3);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2 +
+ explanation3);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -399,21 +401,21 @@
Object explanation2,
Object explanation3,
Object explanation4)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2 +
- explanation3 +
- explanation4);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2 +
+ explanation3 +
+ explanation4);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -425,22 +427,22 @@
Object explanation3,
Object explanation4,
Object explanation5)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2 +
- explanation3 +
- explanation4 +
- explanation5);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2 +
+ explanation3 +
+ explanation4 +
+ explanation5);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -453,23 +455,23 @@
Object explanation4,
Object explanation5,
Object explanation6)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2 +
- explanation3 +
- explanation4 +
- explanation5 +
- explanation6);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2 +
+ explanation3 +
+ explanation4 +
+ explanation5 +
+ explanation6);
}
}
/**
- * If the argument is false, throws an AssertionError with the
+ * If the argument is false, throws a RuntimeException with the
* given explanation arguments, concatenated as strings and prefixed
- * by "Internal: ".
+ * by "Failed: ".
* <p> Use this routine when you need to avoid paying the overhead of
* string concatenation ("+") on every test. It does the concatenation
* only if the test fails.
@@ -483,17 +485,17 @@
Object explanation5,
Object explanation6,
Object explanation7)
- throws AssertionError {
+ throws RuntimeException {
if (mustBeTrue == false) {
- throw new AssertionError(prefix +
- explanation0 +
- explanation1 +
- explanation2 +
- explanation3 +
- explanation4 +
- explanation5 +
- explanation6 +
- explanation7);
+ throw new RuntimeException(failed +
+ explanation0 +
+ explanation1 +
+ explanation2 +
+ explanation3 +
+ explanation4 +
+ explanation5 +
+ explanation6 +
+ explanation7);
}
}
}
1.3 +62 -8 e/src/jsrc/org/quasiliteral/quasiterm/QAstroArg.java
Index: QAstroArg.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/quasiterm/QAstroArg.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- QAstroArg.java 2001/12/19 10:18:08 1.2
+++ QAstroArg.java 2001/12/21 05:30:35 1.3
@@ -9,6 +9,11 @@
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Selfless;
import org.erights.e.elib.tables.Twine;
+import org.erights.e.elib.tables.EList;
+import org.erights.e.elib.base.Ejector;
+import org.erights.e.elib.base.ClassDesc;
+import org.erights.e.elib.slot.ValueGuard;
+import org.erights.e.elib.prim.E;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.base.MatchMaker;
@@ -29,6 +34,16 @@
AstroArg, ValueMaker, MatchMaker {
/**
+ *
+ */
+ static /*package*/ final int[] EMPTY_INDEX = {};
+
+ /**
+ *
+ */
+ static /*package*/ ValueGuard EListGuard = ClassDesc.make(EList.class);
+
+ /**
* @serial Builds Terms using the Schema derived from myTag.
*/
/*package*/
@@ -56,7 +71,7 @@
* @return :Astro
*/
public Object substitute(Object[] args) {
- ConstList list = substSlice(args, "");
+ ConstList list = substSlice(args, EMPTY_INDEX);
T.require(list.size() == 1,
"Must be singleton: ", list);
return list.get(0);
@@ -69,18 +84,36 @@
* lists of terms, for which the outer list may only be zero
* or one long, the middle lists may be any length, and the
* inner lists must all have at least one element.
- * @param rank :String(('?'|'+'|'*')*)
+ * @param index Further indexes after a hole's hole-num. For example,
+ * If a dollar-hole's hole-num is 3 and index is [4,5], then
+ * the dollar-hole would evaluate to args[3][4][5].
* @return :(ConstList of(Astro))
*/
- public abstract ConstList substSlice(Object[] args, String rank);
+ public abstract ConstList substSlice(Object[] args, int[] index);
/**
+ * Transitive snapshot through all substructure that's instanceof EList.
+ */
+ static private Object transSnapshot(Object thing) {
+ if (! (thing instanceof EList)) {
+ return thing;
+ }
+ EList list = (EList)thing;
+ int len = list.size();
+ Object[] result = new Object[len];
+ for (int i = 0; i < len; i++) {
+ result[i] = transSnapshot(list.get(i));
+ }
+ return ConstList.fromArray(result);
+ }
+
+ /**
*
*/
public ConstList matchBind(Object[] args, Object specimen) {
FlexList bindings = FlexList.make();
if (matchBind(args, specimen, bindings)) {
- return bindings.snapshot();
+ return (ConstList)transSnapshot(bindings);
} else {
return null;
}
@@ -100,7 +133,7 @@
return 1 == matchBindSlice(args,
ConstList.EmptyList.with(specimen),
bindings,
- "");
+ EMPTY_INDEX);
}
/**
@@ -109,7 +142,11 @@
* String)}
* @param specimenList :(ConstList of(Astro))
* @param bindings Like 'args', but by extraction from specimen
- * @param rank :String(('?'|'+'|'*')*)
+ * @param index Further indexes after a hole's hole-num. For example,
+ * If a dollar-hole's hole-num is 3 and index is [4,5], then
+ * the dollar-hole would access args[3][4][5]. Similarly,
+ * an at-hole with hole-num 3 would store into
+ * bindings[3][4][5].
* @return How many elements of specimen are matched? Zero indicates a
* successful match of no elements, so -1 is used to instead
* indicate a failed match.
@@ -117,7 +154,24 @@
public abstract int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
- String rank);
+ int[] index);
+
+ /**
+ * For this substree and this index-prefix, how many index elements should
+ * be enumerated?
+ * <p>
+ * If this subtree has no dollar-holes, it should just return shapeSoFar.
+ * The initial shapeSoFar is -1 (meaning "indeterminate"), so a tree with
+ * no dollar-holes will just return -1. An non-ranking inner node (eg, a
+ * QTerm) just asks all its children, passing to each the shapeSoFar from
+ * the previous.
+ * <p>
+ * All the rest of the semantics is specific to dollar-hole or to raking
+ * nodes, so see the documentation there.
+ */
+ /*package*/ abstract int getShape(Object args[],
+ int[] prefix,
+ int shapeSoFar);
/**
* What source text was originally lexed or parsed to produce this node,
@@ -152,7 +206,7 @@
/**
*
*/
- public String asText() {
+ public String toString() {
StringWriter strWriter = new StringWriter();
try {
prettyPrintOn(new TextWriter(strWriter));
1.4 +50 -9 e/src/jsrc/org/quasiliteral/quasiterm/QBuilder.java
Index: QBuilder.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/quasiterm/QBuilder.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- QBuilder.java 2001/12/19 22:36:13 1.3
+++ QBuilder.java 2001/12/21 05:30:35 1.4
@@ -3,6 +3,8 @@
import org.erights.e.elib.tables.EList;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Twine;
+import org.erights.e.elib.tables.EmptyTwine;
+import org.erights.e.develop.assertion.T;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.AstroBuilder;
@@ -16,6 +18,8 @@
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.TermParser;
+import java.math.BigInteger;
+
//This file is hereby placed in the public domain
/**
@@ -94,14 +98,28 @@
}
/**
- *
+ * Returns the QTerm '<functor>(<args>...)'.
+ * <p>
+ * Note that the QTerm constructor will first convert 'functor' using
+ * {@link QAstro#asFunctor()}, so if 'functor' is originally a term-hole,
+ * the functor of the resulting QTerm will be a corresponding
+ * functor-hole.
*/
public Astro term(Astro functor, Object args) {
- return new QTerm(myBuilder, (QAstro)functor, ((EList)args).snapshot());
+ return new QTerm(myBuilder,
+ (QAstro)functor,
+ ((EList)args).snapshot());
}
+ /**
+ * Just returns 'functor' itself.
+ * <p>
+ * Note that, if 'functor' is a term-hole (one that doesn't constrain
+ * the literal term to be zero-arity), then so will the result, since it's
+ * the same.
+ */
public Astro term(Astro functor) {
- throw new RuntimeException("XXX not yet implemented");
+ return functor;
}
/**
@@ -128,7 +146,7 @@
}
public Astro taggedHole(Astro ident, Astro functorHole) {
- throw new RuntimeException("XXX not yet implemented");
+ return ((QHole)functorHole).asTagged(ident);
}
/**
@@ -148,8 +166,18 @@
/**
*
*/
- public AstroArg seq(Astro optTerm, String quant) {
- throw new RuntimeException("XXX not yet implemented");
+ public AstroArg some(Astro optTerm, String quant) {
+ T.require(quant.length() == 1, "Must be single char: ", quant);
+ Twine source;
+ if (null == optTerm) {
+ source = EmptyTwine.THE_ONE;
+ } else {
+ source = optTerm.getSource();
+ }
+ return new QSome(myBuilder,
+ (QAstroArg)optTerm,
+ quant.charAt(0),
+ source);
}
/**
@@ -160,16 +188,29 @@
}
/**
- *
+ * The dollar-hole that's returned is initially a term-hole, but may get
+ * converted to a functor-hole by {@link QAstro#asFunctor()}.
*/
public Astro dollarHole(Astro litInt) {
- throw new RuntimeException("XXX not yet implemented");
+ int holeNum = ((BigInteger)litInt.getOptData()).intValue();
+ return new QDollarHole(myBuilder,
+ null,
+ holeNum,
+ false,
+ litInt.getSource());
}
/**
*
+ * The at-hole that's returned is initially a term-hole, but may get
+ * converted to a functor-hole by {@link QAstro#asFunctor()}.
*/
public Astro atHole(Astro litInt) {
- throw new RuntimeException("XXX not yet implemented");
+ int holeNum = ((BigInteger)litInt.getOptData()).intValue();
+ return new QAtHole(myBuilder,
+ null,
+ holeNum,
+ false,
+ litInt.getSource());
}
}
1.4 +39 -10 e/src/jsrc/org/quasiliteral/quasiterm/QTerm.java
Index: QTerm.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/quasiterm/QTerm.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- QTerm.java 2001/12/19 22:36:13 1.3
+++ QTerm.java 2001/12/21 05:30:35 1.4
@@ -63,7 +63,7 @@
ConstList qArgs) {
super(builder, qFunctor.getSource());
- myQFunctor = qFunctor;
+ myQFunctor = qFunctor.asFunctor();
myQArgs = qArgs;
}
@@ -152,12 +152,12 @@
* literal functor info of this qterm, and whose args are the
* concatentation of the substSlice of the qargs of this qterm.
*/
- public ConstList substSlice(Object[] args, String rank) {
- Astro tFunctor = (Astro)myQFunctor.substSlice(args, rank).get(0);
+ public ConstList substSlice(Object[] args, int[] index) {
+ Astro tFunctor = (Astro)myQFunctor.substSlice(args, index).get(0);
Object tArgs = myBuilder.list();
for (int i = 0, ilen = myQArgs.size(); i < ilen; i++) {
QAstroArg qArg = (QAstroArg)myQArgs.get(i);
- ConstList tSlice = qArg.substSlice(args, rank);
+ ConstList tSlice = qArg.substSlice(args, index);
for (int j = 0, jlen = tSlice.size(); j < jlen; j++) {
AstroArg tArg = (AstroArg)tSlice.get(j);
tArgs = myBuilder.with(tArgs, tArg);
@@ -178,23 +178,26 @@
public int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
- String rank) {
+ int[] index) {
+ Astro specimen = (Astro)specimenList.get(0);
+ ConstList singletonFunctorList =
+ ConstList.EmptyList.with(specimen.withoutArgs());
int matches = myQFunctor.matchBindSlice(args,
- specimenList,
+ singletonFunctorList,
bindings,
- rank);
+ index);
if (matches <= 0) {
return -1;
}
T.requireSI(1 == matches,
"Functor may only match 0 or 1 specimen: ", matches);
- ConstList tArgs = ((Astro)specimenList.get(0)).getArgs();
+ ConstList tArgs = specimen.getArgs();
for (int i = 0, len = myQArgs.size(); i < len; i++) {
QAstroArg qArg = (QAstroArg)myQArgs.get(i);
int num = qArg.matchBindSlice(args,
tArgs,
bindings,
- rank);
+ index);
if (num <= -1) {
return -1;
}
@@ -226,7 +229,7 @@
*/
public void prettyPrintOn(TextWriter out)
throws IOException {
- String label = myQFunctor.asText();
+ String label = myQFunctor.toString();
out.print(label);
int h = getHeight();
if (h <= 1) {
@@ -259,5 +262,31 @@
((QAstroArg)myQArgs.get(i)).prettyPrintOn(sub);
}
sub.print(")");
+ }
+
+ /**
+ *
+ */
+ /*package*/
+ QAstro asFunctor() {
+ T.require(myQArgs.size() == 0,
+ "Terms with args can't be used as functors: ", this);
+ //could 'return this;', but may as well shed unnecessary structure
+ return myQFunctor;
+ }
+
+ /**
+ * A QTerm has whatever shape its children agree on
+ */
+ /*package*/
+ int getShape(Object args[],
+ int[] prefix,
+ int shapeSoFar) {
+ shapeSoFar = myQFunctor.getShape(args, prefix, shapeSoFar);
+ for (int i = 0, len = myQArgs.size(); i < len; i++) {
+ QAstroArg qArg = (QAstroArg)myQArgs.get(i);
+ shapeSoFar = qArg.getShape(args, prefix, shapeSoFar);
+ }
+ return shapeSoFar;
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QAstro.java
Index: QAstro.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.develop.assertion.T;
import org.erights.e.elib.tables.Twine;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.astro.AstroTag;
//This file is hereby placed in the public domain
/**
*
* @author <a href="mailto:markm@caplet.com">Mark Miller</a>
*/
public abstract class QAstro extends QAstroArg implements Astro {
public QAstro(AstroBuilder builder, Twine source) {
super(builder, source);
}
/**
*
*/
public Astro build(AstroBuilder builder) {
throw new RuntimeException("Can't build. Try qbuild instead");
}
/**
*
*/
public short getOptTagCode() {
return getTag().getOptTagCode();
}
/**
*
*/
public String getOptString() {
return ((Twine)getOptData()).bare();
}
/**
*
*/
public Object getOptArgData() {
if (getArgs().size() != 1) {
return null;
}
QAstroArg qaa = (QAstroArg)getArgs().get(0);
if (!(qaa instanceof QAstro)) {
return null;
}
return ((QAstro)qaa).getOptData();
}
/**
*
*/
public Object getOptArgData(short tagCode) {
//This is too much reporting work when the error doesn't happen.
//Should consider putting into a thunk instead.
AstroTag optTag = getTag().getSchema().getOptTagForCode(tagCode);
T.require(tagCode == getTag().getOptTagCode(),
"Tag mismatch: ", getTag(), " vs ",
(null == optTag ?
(Object)new Integer(tagCode) :
(Object)optTag));
return getOptArgData();
}
/**
*
*/
public String getOptArgString(short tagCode) {
return ((Twine)getOptArgData(tagCode)).bare();
}
/**
* Returns a variant of this Astro that may serve as a functor of a
* QTerm.
* <p>
* If this Astro (or derivatives) should not be used as a functor, then
* this operation should throw.
*/
/*package*/ abstract QAstro asFunctor();
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QAtHole.java
Index: QAtHole.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.develop.assertion.T;
import org.erights.e.develop.exception.ExceptionMgr;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.EList;
import org.erights.e.elib.base.Ejector;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.astro.AstroTag;
import org.quasiliteral.term.QuasiBuilder;
import java.io.IOException;
import java.math.BigInteger;
//This file is hereby placed in the public domain
/**
* An at-hole of a quasi-literal term expression extracts the specimen into
* a binding.
* <p>
* An at-hole is not a valid ValueMaker, and so neither is any quasi tree that
* contains an at-hole. If encountered during substitution, an at-hole
* throws. It would be good to make this error occur earlier.
* <p>
* As a MatchMaker, this requires the specimen to meet its constraints
* (optional tag, optional requirement of zero arity), and then extracts it
* into the binding at [hole-number]+index.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QAtHole extends QHole {
/**
*
*/
static public final StaticMaker QAtHoleMaker =
StaticMaker.make(QAtHole.class);
/**
* Makes a hole that extracts a specimen into a binding.
* <p>
* The invariants of a QAtHole are not checked here, but rather are
* enforced by the callers in this class and in QTermBuilder.
* <p>
* For the meanings of the parameters, see the {@link QHole} constructor,
* which has the same parameters.
*/
/*package*/
QAtHole(AstroBuilder builder,
AstroTag optTag,
int holeNum,
boolean isFunctorHole,
Twine source) {
super(builder, optTag, holeNum, isFunctorHole, source);
}
/**
* Uses 'QAtHoleMaker new(myBuilder, myOptTag, myHoleNum,
* myIsFunctorHole, mySource)'
*/
public Object[] getCanonicalState() {
Object[] result = {
QAtHoleMaker,
"new",
myBuilder,
myOptTag,
BigInteger.valueOf(myHoleNum),
myIsFunctorHole ? Boolean.TRUE : Boolean.FALSE,
mySource
};
return result;
}
/**
*
*/
public AstroArg qbuild(QuasiBuilder qbuilder) {
Astro holeNum = qbuilder.leafLong(myHoleNum, mySource);
Astro result = qbuilder.atHole(holeNum);
if (null != myOptTag) {
result = qbuilder.taggedHole(this, result);
}
if (myIsFunctorHole) {
result = qbuilder.term(result, qbuilder.list());
}
return result;
}
/**
* An at-hole doesn't contribute to the shape, so just returns
* shapeSoFar.
*/
/*package*/
int getShape(Object[] args, int[] prefix, int shapeSoFar) {
return shapeSoFar;
}
/**
* This throws, complaining that a quasi-tree with an @-hole may not be
* used as a ValueMaker.
*/
public ConstList substSlice(Object[] args, int[] index) {
throw new RuntimeException
("A quasi-tree with an @-hole may not be used as a ValueMaker: " +
this);
}
/**
* Given a multi-dimensional list and an index path, put newValue at that
* position in the list.
* <p>
* For example, if 'bindings' is [['a','b'],['c','d','e']] diverge(),
* 'holeNum' is 1, 'index' is [2], and 'newValue' is 'x', then the 'e'
* should be replaced with 'x', since it's at list[1][2]. If any index
* step is out of bounds, the corresponding list is grown to include it
* (see {@link FlexList#ensureSize(int)} and null is returned.
* Alternatively, if an old value is being overwritten, then that old
* value is also returned.
*/
static public Object multiPut(FlexList bindings,
int holeNum,
int[] index,
Object newValue) {
FlexList list = bindings;
int dest = holeNum;
for (int i = 0, len = index.length; i < len; i++) {
list.ensureSize(dest +1);
Object optNext = list.get(dest);
if (optNext == null) {
optNext = FlexList.make(index[i] +1);
list.put(dest, optNext);
} else if (optNext instanceof FlexList) {
//we're cool
} else {
optNext = EListGuard.coerce(optNext, null);
optNext = ((EList)optNext).diverge();
}
list = (FlexList)optNext;
dest = index[i];
}
Object result = null;
if (list.size() > dest) {
result = list.get(dest);
}
list.ensureSize(dest +1);
list.put(dest, newValue);
return result;
}
/**
* This extracts the specimen into the binding at [myHoleNum]+index.
* <p>
* This first ensures the specimen meets our own constraints.
*
* @return -1 or 1, depending on whether they match.
*/
public int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
int[] index) {
if (specimenList.size() <= 0) {
return -1;
}
Object specimen = specimenList.get(0);
if (! matches(specimen)) {
return -1;
}
//XXX when matches/1 coerces term to an Astro, this should be updated
//to return a singleton list of the coerced term rather than the
//pre-coerced term.
Object optOldValue = multiPut(bindings, myHoleNum, index, specimen);
if (null == optOldValue ||
0.0 == E.asFloat64(E.call(optOldValue, "compareTo", specimen))) {
return 1;
} else {
//XXX Should this throw?
return -1;
}
}
/**
*
*/
/*package*/
QHole asTagged(Astro ident) {
T.require(null == myOptTag,
"Already tagged: ", this);
return new QAtHole(myBuilder,
ident.getTag(),
myHoleNum,
myIsFunctorHole,
mySource);
}
/**
*
*/
/*package*/
QAstro asFunctor() {
if (myIsFunctorHole) {
return this;
} else {
return new QAtHole(myBuilder,
myOptTag,
myHoleNum,
true,
mySource);
}
}
/**
*
*/
public void prettyPrintOn(TextWriter out)
throws IOException {
if (null != myOptTag) {
out.print(myOptTag.getTagName());
}
out.print("@{", new Integer(myHoleNum), "}");
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QDollarHole.java
Index: QDollarHole.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.develop.assertion.T;
import org.erights.e.develop.exception.ExceptionMgr;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.EList;
import org.erights.e.elib.base.Ejector;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.astro.AstroTag;
import org.quasiliteral.term.QuasiBuilder;
import java.io.IOException;
import java.math.BigInteger;
//This file is hereby placed in the public domain
/**
* A dollar hole of a quasi-literal term expression is filled in with a
* substitution arg.
* <p>
* As a ValueMaker, this evaluates to the corresponding substitution arg,
* given that it meets all encoded conditions (see {@link QHole}).
* <p>
* As a MatchMaker, this compares ("<=>") a specimen term against
* the substitution argument. The substitution argument must again meet all
* encoded conditions.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QDollarHole extends QHole {
/**
*
*/
static public final StaticMaker QDollarHoleMaker =
StaticMaker.make(QDollarHole.class);
/**
* Makes a hole that is filled in by a substitution arg.
* <p>
* The invariants of a QDollarHole are not checked here, but rather are
* enforced by the callers in this class and in QTermBuilder.
* <p>
* For the meanings of the parameters, see the {@link QHole} constructor,
* which has the same parameters.
*/
/*package*/
QDollarHole(AstroBuilder builder,
AstroTag optTag,
int holeNum,
boolean isFunctorHole,
Twine source) {
super(builder, optTag, holeNum, isFunctorHole, source);
}
/**
* Uses 'QDollarHoleMaker new(myBuilder, myOptTag, myHoleNum,
* myIsFunctorHole, mySource)'
*/
public Object[] getCanonicalState() {
Object[] result = {
QDollarHoleMaker,
"new",
myBuilder,
myOptTag,
BigInteger.valueOf(myHoleNum),
myIsFunctorHole ? Boolean.TRUE : Boolean.FALSE,
mySource
};
return result;
}
/**
*
*/
public AstroArg qbuild(QuasiBuilder qbuilder) {
Astro holeNum = qbuilder.leafLong(myHoleNum, mySource);
Astro result = qbuilder.dollarHole(holeNum);
if (null != myOptTag) {
result = qbuilder.taggedHole(this, result);
}
if (myIsFunctorHole) {
result = qbuilder.term(result, qbuilder.list());
}
return result;
}
/**
* Given a multi-dimensional list and an index path, retrieve the
* corresponding element of the list.
* <p>
* For example, if 'args' is [['a','b'],['c','d','e']], 'holeNum' is 1,
* 'index' is [2,3], and 'repeat' is true, then the answer should be
* 'e', since it's at args[1][2], and the repeat flag allows us to ignore
* the 3 when we find that 'e' isn't a list. If 'repeat' had been false,
* the presence of an additional step on the index path would have caused
* an exception to be thrown. In either case, if an index step is out of
* bounds, an exception is thrown regardless of the value of 'repeat'.
*/
static public Object multiGet(Object args[],
int holeNum,
int[] index,
boolean repeat) {
Object result = args[holeNum];
for (int i = 0, len = index.length; i < len; i++) {
Ejector optEj = null;
if (repeat) {
optEj = new Ejector();
}
EList list;
try {
list = (EList)EListGuard.coerce(result, optEj);
} catch (Throwable th) {
if (null == optEj) {
throw ExceptionMgr.asSafe(th);
} else {
optEj.result(th);
//It doesn't matter why the coercion failed. If we're
//here, the coercion failed rather than throwing. This
//means we should simply repeat the last non-list result
//we got.
return result;
}
}
result = list.get(index[i]);
}
return result;
}
/**
* If the substitution arg at [myHoleHum]+prefix is actually a list
* for further indexing, what's the size of that list?
* <p>
* If it's not a list, it could still act as a list by repetition,
* but then it's of indeterminate size, so just return shapeSoFar.
* If it is a list, then if shapeSoFar has already been determined (ie,
* not -1), then require these to agree.
*/
/*package*/
int getShape(Object[] args, int[] prefix, int shapeSoFar) {
Object term = multiGet(args, myHoleNum, prefix, true);
Ejector ej = new Ejector();
EList list;
try {
list = (EList)EListGuard.coerce(term, ej);
} catch (Throwable th) {
ej.result(th);
//It doesn't matter why the coercion failed. If we're
//here, the coercion failed rather than throwing.
return shapeSoFar;
}
int result = list.size();
T.require(-1 == shapeSoFar || shapeSoFar == result,
"Inconsistent shape: " + shapeSoFar,
" vs " + result);
return result;
}
/**
* This extracts the substitution arg at [myHoleNum]+index, requires that
* it matches, and returns a singleton list containing that arg (which
* should be a literal term).
*/
public ConstList substSlice(Object[] args, int[] index) {
Object term = multiGet(args, myHoleNum, index, true);
T.require(matches(term),
"Term ", term, " doesn't match ", this);
//XXX when matches/1 coerces term to an Astro, this should be updated
//to return a singleton list of the coerced term rather than the
//pre-coerced term.
return ConstList.EmptyList.with(term);
}
/**
* This compares ("<=>") the substitution arg at [myHoleNum]+index against
* the specimenList[0].
* <p>
* This first ensures that the substitution arg meets our own constraints.
*
* @return -1 or 1, depending on whether they match.
*/
public int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
int[] index) {
if (specimenList.size() <= 0) {
return -1;
}
Object specimen = specimenList.get(0);
Object term = multiGet(args, myHoleNum, index, true);
T.require(matches(term),
"Term ", term, " doesn't match ", this);
//XXX when matches/1 coerces term to an Astro, this should be updated
//to return a singleton list of the coerced term rather than the
//pre-coerced term.
if (0.0 == E.asFloat64(E.call(term, "compareTo", specimen))) {
return 1;
} else {
return -1;
}
}
/**
*
*/
/*package*/
QHole asTagged(Astro ident) {
T.require(null == myOptTag,
"Already tagged: ", this);
return new QDollarHole(myBuilder,
ident.getTag(),
myHoleNum,
myIsFunctorHole,
mySource);
}
/**
*
*/
/*package*/
QAstro asFunctor() {
if (myIsFunctorHole) {
return this;
} else {
return new QDollarHole(myBuilder,
myOptTag,
myHoleNum,
true,
mySource);
}
}
/**
*
*/
public void prettyPrintOn(TextWriter out)
throws IOException {
if (null != myOptTag) {
out.print(myOptTag.getTagName());
}
out.print("${", new Integer(myHoleNum), "}");
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QFunctor.java
Index: QFunctor.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Twine;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.astro.AstroTag;
import org.quasiliteral.term.QuasiBuilder;
import java.io.IOException;
//This file is hereby placed in the public domain
/**
* A quasi-literal functor of a {@link Term}.
* <p>
* As a ValueMaker, this acts like a 0-arity Term. As a MatchMaker, this
* matches only the functor info of a specimen term, and ignores the
* specimen's arguments.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QFunctor extends QAstro {
/**
*
*/
static public final StaticMaker QFunctorMaker =
StaticMaker.make(QFunctor.class);
/**
* @serial Represents the token-type of the functor of this QTerm.
*/
private final AstroTag myTag;
/**
* @serial If the functor represents a literal-data token, then this is
* the data, and myTag must represent the cononical corresponding
* token-type for this kind of data in this schema.
*/
private final Object myOptData;
/**
* Makes a QTerm that matches or generates a Astro.
* <p>
* The invariants of a QTerm are not checked here, but rather are
* enforced by the callers in this class and in QTermBuilder.
*
* @param builder Used to build the result of a substitute
* @param tag Identifies a token type in a particular grammar or set
* of related grammars, used as the functor (or "label") of
* this QTerm
* @param optData Either {@link Character},
* {@link BigInteger}, {@link Double},
* or {@link Twine} or null. If not null, then the tag
* must represent the canonical literal type for this
* kind of data in this schema.
* @param source The source text this node was extracted from. To
* provide no info, use "" rather than null.
*/
/*package*/
QFunctor(AstroBuilder builder,
AstroTag tag,
Object optData,
Twine source) {
super(builder, source);
myTag = tag;
myOptData = optData;
}
/**
* Uses 'QFunctorMaker new(myBuilder, myTag, myOptData, mySource)'
*/
public Object[] getCanonicalState() {
Object[] result = {
QFunctorMaker, "new", myBuilder, myTag, myOptData, mySource
};
return result;
}
/**
*
*/
public AstroArg qbuild(QuasiBuilder qbuilder) {
if (null == myOptData) {
return qbuilder.leafTag(myTag, mySource);
} else {
//Assumes tag adds no more info.
return qbuilder.leafData(myOptData, mySource);
}
}
/**
* Represents the token-type of the functor of this term.
*/
public AstroTag getTag() {
return myTag;
}
/**
* Either literal data or null. If not null, then the tag
* must represent the canonical literal type for this
* kind of data in this schema.
*/
public Object getOptData() {
return myOptData;
}
/**
* @return An empty list of QAstroArg
*/
public ConstList getArgs() {
return ConstList.EmptyList;
}
/**
*
*/
public Astro withoutArgs() {
return this;
}
/**
*
*/
public Astro withArgs(ConstList qArgs) {
return new QTerm(myBuilder, this, qArgs);
}
/**
* @return A single list of a single Astro, whose functor is based on
* literal functor info of this qfunctor
*/
public ConstList substSlice(Object[] args, int[] index) {
Astro tFunctor;
if (null == myOptData) {
tFunctor = myBuilder.leafTag(myTag, mySource);
} else {
tFunctor = myBuilder.leafData(myOptData, mySource);
}
return ConstList.EmptyList.with(tFunctor);
}
/**
* Attempts to match against the Astro specimenList[0].
* <p>
* @return -1 or 1, depending on whether the functor information of
* specimenList[0] matches that of this qfunctor, while ignoring
* the args.
*/
public int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
int[] index) {
if (specimenList.size() <= 0) {
return -1;
}
Astro term = (Astro)specimenList.get(0);
if (0.0 != myTag.compareTo(term.getTag())) {
return -1;
}
if (null != myOptData) {
//if myOptData is null, then it's a wildcard.
Object optOtherData = term.getOptData();
if (null == optOtherData) {
//If the pattern has data, then the specimen must as well
return -1;
}
if (!myOptData.equals(optOtherData)) {
//'equals/1' is valid for all valid literal data types except
//Twine
if (myOptData instanceof Twine &&
optOtherData instanceof Twine) {
String mine = ((Twine)myOptData).bare();
String other = ((Twine)optOtherData).bare();
if (!mine.equals(other)) {
return -1;
}
}
}
}
//functor info matches, so we match one (the first) element of
//specimenList
return 1;
}
/**
* A functor as a Term is a leaf, and so has height 1
*/
public int getHeight() {
return 1;
}
/**
*
*/
public void prettyPrintOn(TextWriter out)
throws IOException {
String label = myTag.getTagName();
if (null != myOptData) {
label = E.toQuote(myOptData).bare();
label = StringHelper.replaceAll(label, "$", "$$");
label = StringHelper.replaceAll(label, "@", "@@");
label = StringHelper.replaceAll(label, "`", "``");
}
out.print(label);
}
/*package*/
QAstro asFunctor() {
return this;
}
/**
* Just returns shapeSoFar, since this has no shape and no children
*/
/*package*/
int getShape(Object args[],
int[] prefix,
int shapeSoFar) {
return shapeSoFar;
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QHole.java
Index: QHole.java
===================================================================
package org.quasiliteral.quasiterm;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.astro.AstroTag;
import org.quasiliteral.astro.Astro;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.develop.assertion.T;
//This file is hereby placed in the public domain
/**
* Represents a dollar-hole ("${<hole-num>}") or an at-hole ("@{<hole-num>}")
* that may be a functor-hole or a term-hole, and that may or may not insist
* on a tag.
*
* @author <a href="mailto:markm@caplet.com">Mark Miller</a>
*/
public abstract class QHole extends QAstro {
/**
* @serial If present, represents the token tag that the corresponding
* literal term must have, and this is a tagged-hole. If this is
* a dollar-hole, the corresponding literal term must be the
* substitution are at myHoleNum. If this is an at-hole, the
* corresponding literal term is the specimen.
*/
/*package*/ final AstroTag myOptTag;
/**
* @serial Which hole am I? If this is a dollar-hole, then this
* says which substitution-arg. If this is an at-hole, then this
* says which binding.
*/
/*package*/ final int myHoleNum;
/**
* @serial If true, then the corresponding literal term must be
* 0-arity. If false, then the corresponding literal term may
* itself have any argument list, and this is a termHole
*/
/*package*/ final boolean myIsFunctorHole;
/**
* Makes a hole that matches a term (either a substitution-arg or a
* specimen), and either evaluates to it (if this is a dollar-hole) or
* extracts it (if this is an at-hole).
*
* @param builder Used to build the result of a substitute.
* @param optTag If present, represents the token tag that the
* corresponding literal term must have, and this is a
* tagged-hole. If this is a dollar-hole, the corresponding
* literal term must be the substitution are at myHoleNum.
* If this is an at-hole, the corresponding literal term is
* the specimen.
* @param holeNum Which hole am I? If this is a dollar-hole, then this
* says which substitution-arg. If this is an at-hole,
* then this says which binding.
* @param isFunctorHole If true, then the corresponding literal term must
* be 0-arity. If false, then the corresponding
* literal term may itself have any argument list,
* and this is a termHole.
* @param source The source text this node was extracted from. To
* provide no info, use "" rather than null.
*/
/*package*/
QHole(AstroBuilder builder,
AstroTag optTag,
int holeNum,
boolean isFunctorHole,
Twine source) {
super(builder, source);
myOptTag = optTag;
myHoleNum = holeNum;
myIsFunctorHole = isFunctorHole;
}
/**
* Does the literal 'term' match the pattern represented by this hole?
* <p>
* When this hole is a dollar-hole, term will be a substitution-arg.
* When this hole is an at-hole, term will be the specimen. In either
* case, the same criteria are applied: <ul>
* <li>If term isn't an Astro (or, XXX eventually, coerces to an Astro),
* then false -- we have no match</li>
* <li>If we have a tag, and it doesn't match term's tag, then false.</li>
* <li>If we are a functor-hole (rather than a term-hole) and term has
* one or more arguments, then false.</li>
* <li>Otherwise, we match, so true.</li>
* </ul>
*/
/*package*/
boolean matches(Object term) {
if (! (term instanceof Astro)) {
return false;
}
Astro astro = (Astro)term;
if (null != myOptTag && 0.0 != myOptTag.compareTo(astro.getTag())) {
return false;
}
if (myIsFunctorHole && astro.getArgs().size() != 0) {
return false;
}
return true;
}
/**
* Tagged holes return their tag, otherwise throws.
*/
public AstroTag getTag() {
T.require(null != myOptTag,
"There ain't no tag on an untagged hole");
return myOptTag;
}
/**
* Holes have no data, so getOptData/0 always returns null.
*/
public Object getOptData() {
return null;
}
/**
* A hole itself has no args, even though a term-hole will match a
* corresponding literal term that does.
*
* @return An empty list of QAstroAr
*/
public ConstList getArgs() {
return ConstList.EmptyList;
}
/**
* A hole itself has no args, so this just returns itself.
*/
public Astro withoutArgs() {
return this;
}
/**
* Can only do this to a functor-hole, in which case it makes a
* {@link QTerm}.
*/
public Astro withArgs(ConstList qArgs) {
T.require(myIsFunctorHole,
"Can only add args to a functor-hole, not a term-hole: ",
this);
return new QTerm(myBuilder, this, qArgs);
}
/**
* A hole is a leaf, and so has height 1
*/
public int getHeight() {
return 1;
}
/**
*
*/
/*package*/ abstract QHole asTagged(Astro ident);
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QSome.java
Index: QSome.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.EList;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.develop.assertion.T;
import org.quasiliteral.astro.AstroTag;
import org.quasiliteral.astro.AstroArg;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.astro.AstroBuilder;
import org.quasiliteral.term.QuasiBuilder;
import java.io.IOException;
//This file is hereby placed in the public domain
/**
*
* @author <a href="mailto:markm@caplet.com">Mark Miller</a>
*/
public class QSome extends QAstroArg {
/**
*
*/
static public StaticMaker QSomeMaker =
StaticMaker.make(QSome.class);
/**
*
*/
private final QAstroArg myOptSubPattern;
/**
*
*/
private final char myQuant;
/**
*
* @param quant One of '?', '+', or '*'.
*/
public QSome(AstroBuilder builder,
QAstroArg optSubPattern,
char quant,
Twine source) {
super(builder, source);
myOptSubPattern = optSubPattern;
myQuant = quant;
}
/**
* Uses 'QSomeMaker new(myBuilder, myOptSubPattern, myQuant, mySource)'
*/
public Object[] getCanonicalState() {
Object[] result = {
QSomeMaker,
"new",
myBuilder,
myOptSubPattern,
new Character(myQuant),
mySource
};
return result;
}
/**
*
*/
static private boolean inBounds(int num, char quant) {
switch (quant) {
case '?': return num == 0 || num == 1;
case '+': return num >= 1;
case '*': return num >= 0;
default: throw new RuntimeException
("Must be '?', '+', or '*': " + quant);
}
}
/**
*
*/
public ConstList substSlice(Object[] args, int[] index) {
T.require(null != myOptSubPattern,
"A ValueMaker must have a sub-pattern: ", this);
int shape = myOptSubPattern.getShape(args, index, -1);
T.require(shape >= 0,
"Indeterminate repetition: ", this);
FlexList result = FlexList.fromType(Astro.class, shape);
int lastDim = index.length;
int[] subIndex = (int[])EList.resize(index, lastDim +1);
for (int i = 0; i < shape; i++) {
subIndex[lastDim] = i;
ConstList slice = myOptSubPattern.substSlice(args, subIndex);
result.append(slice);
}
T.require(inBounds(result.size(), myQuant),
"Improper quantity: " + shape, " vs " + myQuant);
return result.snapshot();
}
/**
*
*/
public int matchBindSlice(Object[] args,
ConstList specimenList,
FlexList bindings,
int[] index) {
if (null == myOptSubPattern) {
int result = specimenList.size();
switch (myQuant) {
case '?': return Math.min(result, 1);
case '+': return result <= 0 ? -1 : result;
case '*': return result;
default: T.fail("Unrecognized: " + myQuant);
}
return -666; //just so the compiler will know
}
int shape = myOptSubPattern.getShape(args, index, -1);
int result = 0;
int lastDim = index.length;
int[] subIndex = (int[])EList.resize(index, lastDim +1);
for (int i = 0; shape == -1 || i < shape; i++) {
if (specimenList.size() == 0) {
break;
}
if (myQuant == '?' && result >= 1) {
break;
}
subIndex[lastDim] = i;
int more = myOptSubPattern.matchBindSlice(args,
specimenList,
bindings,
subIndex);
if (-1 == more) {
break;
}
T.require(more >= 1 || shape != -1,
"Patterns of indeterminate rank must make progress: ",
this, " vs ", specimenList);
result += more;
specimenList = specimenList.run(more, specimenList.size());
}
T.require(inBounds(result, myQuant),
"Improper quantity: " + result, " vs " + myQuant);
return result;
}
/**
*
*/
/*package*/
int getShape(Object args[],
int[] prefix,
int shapeSoFar) {
throw new RuntimeException("XXX not yet implemented");
}
/**
*
*/
public AstroArg qbuild(QuasiBuilder qbuilder) {
//XXX what if myOptSubPattern is only an AstroArg, not an Astro?
return qbuilder.some((Astro)myOptSubPattern, "" + myQuant);
}
/**
* If I have a sub-pattern, my height is the same as its.
* <p>
* Otherwise, my height is 1, which is the height of a leaf.
*/
public int getHeight() {
if (null == myOptSubPattern) {
return 1;
} else {
return myOptSubPattern.getHeight();
}
}
/**
*
*/
public void prettyPrintOn(TextWriter out)
throws IOException {
if (null != myOptSubPattern) {
myOptSubPattern.prettyPrintOn(out);
}
out.print("" + myQuant);
}
}
1.4 +3 -2 e/src/jsrc/org/quasiliteral/term/QuasiBuilder.java
Index: QuasiBuilder.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/QuasiBuilder.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- QuasiBuilder.java 2001/12/19 22:36:13 1.3
+++ QuasiBuilder.java 2001/12/21 05:30:35 1.4
@@ -70,11 +70,12 @@
AstroArg bag(AstroArg leftArg, AstroArg rightArg);
/**
- * Matches a consecutive sequence of Terms matched by optTerm.
+ * Matches a consecutive sequence of Terms matched by optTerm, where the
+ * number matched is constrained by quant.
* <p>
* Adds quant to the rank of optTerm.
*/
- AstroArg seq(Astro optTerm, String quant);
+ AstroArg some(Astro optTerm, String quant);
/**
* Treat the 'args' list as a repeating sequence.
1.4 +1 -1 e/src/jsrc/org/quasiliteral/term/QuasiBuilderAdaptor.java
Index: QuasiBuilderAdaptor.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/QuasiBuilderAdaptor.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- QuasiBuilderAdaptor.java 2001/12/19 22:36:13 1.3
+++ QuasiBuilderAdaptor.java 2001/12/21 05:30:35 1.4
@@ -145,7 +145,7 @@
throw new RuntimeException("not quasi-ing");
}
- public AstroArg seq(Astro optTerm, String quant) {
+ public AstroArg some(Astro optTerm, String quant) {
throw new RuntimeException("not quasi-ing");
}
1.20 +1 -1 e/src/jsrc/org/quasiliteral/term/Term.java
Index: Term.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/Term.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- Term.java 2001/12/19 10:18:08 1.19
+++ Term.java 2001/12/21 05:30:35 1.20
@@ -300,7 +300,7 @@
/**
*
*/
- public String asText() {
+ public String toString() {
StringWriter strWriter = new StringWriter();
try {
prettyPrintOn(new TextWriter(strWriter), false);
1.17 +87 -11 e/src/jsrc/org/quasiliteral/term/Term.updoc
Index: Term.updoc
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/Term.updoc,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- Term.updoc 2001/12/19 10:18:08 1.16
+++ Term.updoc 2001/12/21 05:30:35 1.17
@@ -232,35 +232,111 @@
# x(3, 'x'),
# zip)`
- ?
- ?
+
+
+
? def t1 := term`"foo"`
# value: term`"foo"`
- ? def t2 := term`bar(3, "x", zip(zap, 'x', 2.3))`
+ ? def tx := term`bar(3, "x", zip(zap, 'x', 2.3))`
# value: term`bar(3,
# "x",
# zip(zap, 'x', 2.3))`
? def t2 := term`$t1(4)`
- # problem: XXX not yet implemented
- #
- # org.quasiliteral.quasiterm.QBuilder@12033fc valueMaker("${0}(4)")
- # <interactive interp> evalPrint(e`def t2 :any := term__quasiParser valueMaker("${0}(4)") substitute(ListMaker run(t1))`)
+ # value: term`"foo"(4)`
? def t3 := term`$t1(bar, $t2)`
# value: term`"foo"(bar,
# "foo"(4))`
- ? def term`LiteralString(@x*)` := t3
- # problem: XXX not yet implemented
+ ? def term`LiteralString@x` := t3
+ # value: term`"foo"(bar,
+ # "foo"(4))`
+
+ ? x
+ # value: term`"foo"(bar,
+ # "foo"(4))`
+
+ ? def term`LiteralInteger@f(@a1, @a2)` := t3
+ # problem: such-that expression was false
#
- # ....(org.erights.e.develop.exception.NestedException: ...)
- # <interactive interp> evalPrint(e`def q_1 :any ? (term__quasiParser matchMaker("LiteralString(@{0}*)") matchBind(ListMaker run(), q_1) =~ [x :any]) := t3`)
+ # <interactive interp> evalPrint(e`def q_3 :any ? (term__quasiParser matchMaker("LiteralInteger@{0}(@{1},...") matchBind(ListMaker run(), q_3) =~ [f :any, a1 :any, a2 :any]) := t3`)
+
+ ? f
+ # value: <ref broken by problem: <NullPointerException: must be a EList rather than null>>
+
+ ? def term`LiteralString@f(@a1, @a2)` := t3
+ # value: term`"foo"(bar,
+ # "foo"(4))`
+
+ ? f
+ # value: term`"foo"`
+
+ ? a1
+ # value: term`bar`
+
+ ? a2
+ # value: term`"foo"(4)`
?
+
+
+
+ ? def args := [term`foo`, term`bar(3)`]
+ # value: [term`foo`, term`bar(3)`]
+
+ ? def t4 := term`zip($args*)`
+ # value: term`zip(foo,
+ # bar(3))`
+
+ ? term`zip($args?)`
+ # problem: <AssertionError: Internal: Improper quantity: 2 vs ?>
+ #
+ # term`zip(${0}?)` substitute([[term`foo`, term`bar(3)`]])
+ # <interactive interp> evalPrint(e`term__quasiParser valueMaker("zip(${0}?)") substitute(ListMaker run(args))`)
+
+ ? term`zip($args+)`
+ # value: term`zip(foo,
+ # bar(3))`
+
+ ? term`zip(${[]}+)`
+ # problem: <AssertionError: Internal: Improper quantity: 0 vs +>
+ #
+ # term`zip(${0}+)` substitute([[]])
+ # <interactive interp> evalPrint(e`term__quasiParser valueMaker("zip(${0}+)") substitute(ListMaker run(ListMaker run()))`)
+
+ ? term`zip(${[]}*)`
+ # value: term`zip`
+
+ ?
+
+
+ ?
+ ? def term`LiteralString(@args*)` := t3
+ # problem: XXX not yet implemented
+ #
+ # org.quasiliteral.quasiterm.QBuilder@ff1fcedf matchMaker("LiteralString(@{0}*)")
+ # <interactive interp> evalPrint(e`def q_5 :any ? (term__quasiParser matchMaker("LiteralString(@{0}*)") matchBind(ListMaker run(), q_5) =~ [args :any]) := t3`)
+
?
?
+ ? def ta := term`foo(bar, bar(3), zip(zap))`
+ # value: term`foo(bar,
+ # bar(3),
+ # zip(zap))`
+
+ ? def term`foo(bar@bars*, zip@z)` := ta
+ # value: term`foo(bar,
+ # bar(3),
+ # zip(zap))`
+
+ ? bars
+ # value: [term`bar`, term`bar(3)`]
+
+ ? z
+ # value: term`zip(zap)`
+
?
?
?
1.19 +33 -25 e/src/jsrc/org/quasiliteral/term/TermParser.java
Index: TermParser.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/TermParser.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- TermParser.java 2001/12/19 22:36:13 1.18
+++ TermParser.java 2001/12/21 05:30:35 1.19
@@ -314,7 +314,7 @@
"functorHole : '@' '{' LiteralInteger '}'",
};
-//#line 153 "term.y"
+//#line 152 "term.y"
/**
@@ -398,6 +398,13 @@
/**
*
*/
+private void reserved(String s) throws SyntaxException {
+ yyerror("reserved: " + s);
+}
+
+/**
+ *
+ */
private void yyerror(String s) throws SyntaxException {
short tagCode = ((Astro)yylval).getOptTagCode();
if (TermParser.EOFTOK == tagCode && "syntax error".equals(s)) {
@@ -469,6 +476,8 @@
TheTokens['?'] = "Question";
TheTokens['.'] = "Dot";
+ TheTokens['['] = "OpenBracket";
+ TheTokens[']'] = "CloseBracket";
TheTokens['('] = "OpenParen";
TheTokens[')'] = "CloseParen";
TheTokens['{'] = "OpenBrace";
@@ -481,7 +490,7 @@
static public final AstroSchema DEFAULT_SCHEMA =
new BaseSchema("Term-Tree-Language", ConstList.fromArray(TheTokens));
-//#line 433 "TermParser.java"
+//#line 442 "TermParser.java"
//###############################################################
// method: yylexdebug : check lexer state
//###############################################################
@@ -645,74 +654,73 @@
break;
case 7:
//#line 89 "term.y"
-{ yyval = b.taggedHole((Astro)val_peek(1),
- (Astro)val_peek(0)); }
+{ yyval = b.taggedHole((Astro)val_peek(1), (Astro)val_peek(0)); }
break;
case 8:
-//#line 94 "term.y"
+//#line 93 "term.y"
{ yyval = b.list(); }
break;
case 10:
-//#line 99 "term.y"
+//#line 98 "term.y"
{ yyval = b.list((AstroArg)val_peek(0)); }
break;
case 11:
-//#line 100 "term.y"
+//#line 99 "term.y"
{ yyval = b.with(val_peek(2), (AstroArg)val_peek(0)); }
break;
case 13:
-//#line 105 "term.y"
+//#line 104 "term.y"
{ yyval = b.alt((AstroArg)val_peek(2), (AstroArg)val_peek(0));}
break;
case 15:
-//#line 110 "term.y"
+//#line 109 "term.y"
{ yyval = b.bag((AstroArg)val_peek(2), (AstroArg)val_peek(0));}
break;
case 17:
-//#line 118 "term.y"
-{ yyval = b.seq((Astro)val_peek(1), (String)val_peek(0)); }
+//#line 117 "term.y"
+{ yyval = b.some((Astro)val_peek(1), (String)val_peek(0)); }
break;
case 18:
-//#line 119 "term.y"
-{ yyval = b.seq(null, (String)val_peek(0)); }
+//#line 118 "term.y"
+{ yyval = b.some(null, (String)val_peek(0)); }
break;
case 19:
-//#line 120 "term.y"
-{ yyval = b.seq(null, "."); }
+//#line 119 "term.y"
+{ reserved("Use '@{_}' for now"); }
break;
case 20:
-//#line 121 "term.y"
-{ yyval = b.group(val_peek(2), (String)val_peek(0)); }
+//#line 120 "term.y"
+{ yyval = b.group(val_peek(2), (String)val_peek(0)); }
break;
case 21:
-//#line 122 "term.y"
+//#line 121 "term.y"
{ yyval = b.unpack((Astro)val_peek(0)); }
break;
case 22:
-//#line 126 "term.y"
+//#line 125 "term.y"
{ yyval = "?"; }
break;
case 23:
-//#line 127 "term.y"
+//#line 126 "term.y"
{ yyval = "+"; }
break;
case 24:
-//#line 128 "term.y"
+//#line 127 "term.y"
{ yyval = "*"; }
break;
case 30:
-//#line 140 "term.y"
+//#line 139 "term.y"
{ yyval = untag((Astro)val_peek(0)); }
break;
case 31:
-//#line 147 "term.y"
+//#line 146 "term.y"
{ yyval = b.dollarHole((Astro)val_peek(1)); }
break;
case 32:
-//#line 148 "term.y"
+//#line 147 "term.y"
{ yyval = b.atHole( (Astro)val_peek(1)); }
break;
-//#line 661 "TermParser.java"
+//#line 669 "TermParser.java"
//########## END OF USER-SUPPLIED ACTIONS ##########
}//switch
//#### Now let's reduce... ####
1.18 +31 -23 e/src/jsrc/org/quasiliteral/term/term.y
Index: term.y
===================================================================
RCS file: /cvs/e/src/jsrc/org/quasiliteral/term/term.y,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- term.y 2001/12/19 22:36:13 1.17
+++ term.y 2001/12/21 05:30:35 1.18
@@ -74,58 +74,57 @@
* </pre>
*/
start:
- term { myOptResult = b.start((Astro)$1); }
+ term { myOptResult = b.start((Astro)$1); }
;
term:
- functor { $$ = b.term((Astro)$1); }
- | functor '(' argList ')' { $$ = b.term((Astro)$1, $3); }
- | '[' argList ']' { $$ = b.tuple($2); }
+ functor { $$ = b.term((Astro)$1); }
+ | functor '(' argList ')' { $$ = b.term((Astro)$1, $3); }
+ | '[' argList ']' { $$ = b.tuple($2); }
;
functor:
leaf
| functorHole
- | id functorHole { $$ = b.taggedHole((Astro)$1,
- (Astro)$2); }
+ | id functorHole { $$ = b.taggedHole((Astro)$1, (Astro)$2); }
;
argList:
- /* empty */ { $$ = b.list(); }
+ /* empty */ { $$ = b.list(); }
| args
;
args:
- arg { $$ = b.list((AstroArg)$1); }
- | args ',' arg { $$ = b.with($1, (AstroArg)$3); }
+ arg { $$ = b.list((AstroArg)$1); }
+ | args ',' arg { $$ = b.with($1, (AstroArg)$3); }
;
arg:
bag
- | arg '|' bag { $$ = b.alt((AstroArg)$1, (AstroArg)$3);}
+ | arg '|' bag { $$ = b.alt((AstroArg)$1, (AstroArg)$3);}
;
bag:
seq
- | bag '&' seq { $$ = b.bag((AstroArg)$1, (AstroArg)$3);}
+ | bag '&' seq { $$ = b.bag((AstroArg)$1, (AstroArg)$3);}
;
/**
* Each seq represents some number of Terms
*/
seq:
- term // An Astro is already a fine AstroArg
- | term quant { $$ = b.seq((Astro)$1, (String)$2); }
- | quant { $$ = b.seq(null, (String)$1); }
- | '.' { $$ = b.seq(null, "."); }
- | '(' args ')' quant { $$ = b.group($2, (String)$4); }
- | '^' LiteralString { $$ = b.unpack((Astro)$2); }
+ term // An Astro is already a fine AstroArg
+ | term quant { $$ = b.some((Astro)$1, (String)$2); }
+ | quant { $$ = b.some(null, (String)$1); }
+ | '.' { reserved("Use '@{_}' for now"); }
+ | '(' args ')' quant { $$ = b.group($2, (String)$4); }
+ | '^' LiteralString { $$ = b.unpack((Astro)$2); }
;
quant:
- '?' { $$ = "?"; }
- | '+' { $$ = "+"; }
- | '*' { $$ = "*"; }
+ '?' { $$ = "?"; }
+ | '+' { $$ = "+"; }
+ | '*' { $$ = "*"; }
;
leaf:
@@ -137,15 +136,15 @@
;
id:
- ID { $$ = untag((Astro)$1); }
+ ID { $$ = untag((Astro)$1); }
;
/**
* Starts off as a hole for a Functor, but may get promoted.
*/
functorHole:
- '$' '{' LiteralInteger '}' { $$ = b.dollarHole((Astro)$3); }
- | '@' '{' LiteralInteger '}' { $$ = b.atHole( (Astro)$3); }
+ '$' '{' LiteralInteger '}' { $$ = b.dollarHole((Astro)$3); }
+ | '@' '{' LiteralInteger '}' { $$ = b.atHole( (Astro)$3); }
;
@@ -233,6 +232,13 @@
/**
*
*/
+private void reserved(String s) throws SyntaxException {
+ yyerror("reserved: " + s);
+}
+
+/**
+ *
+ */
private void yyerror(String s) throws SyntaxException {
short tagCode = ((Astro)yylval).getOptTagCode();
if (TermParser.EOFTOK == tagCode && "syntax error".equals(s)) {
@@ -304,6 +310,8 @@
TheTokens['?'] = "Question";
TheTokens['.'] = "Dot";
+ TheTokens['['] = "OpenBracket";
+ TheTokens[']'] = "CloseBracket";
TheTokens['('] = "OpenParen";
TheTokens[')'] = "CloseParen";
TheTokens['{'] = "OpenBrace";