[e-cvs] cvs commit: e/src/jsrc/org/quasiliteral/quasiterm DollarHole.java QuasiFunctor.java QuasiNode.java QuasiTerm.java QuasiTermBuilder.java
markm@eros.cs.jhu.edu
markm@eros.cs.jhu.edu
Mon, 19 Nov 2001 14:33:02 -0500
markm 01/11/19 14:33:02
Added: src/jsrc/org/erights/e/elang/evm SimpleNounExpr.java
src/jsrc/org/erights/e/elang/scope ContourBoundary.java
ScopeMapBase.java ScopeMapLink.java
src/jsrc/org/erights/e/elib/base EComparable.java
src/jsrc/org/erights/e/elib/tables Iteratable.java
src/jsrc/org/quasiliteral/quasiterm DollarHole.java
QuasiFunctor.java QuasiNode.java QuasiTerm.java
QuasiTermBuilder.java
Log:
Oops, forgot these
Revision Changes Path
1.1 e/src/jsrc/org/erights/e/elang/evm/SimpleNounExpr.java
Index: SimpleNounExpr.java
===================================================================
package org.erights.e.elang.evm;
/**
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class SimpleNounExpr extends NounExpr {
/**
*
*/
public SimpleNounExpr(String name) {
super(name);
}
/**
*
*/
public boolean mayBeAssignable() {
return true;
}
}
1.1 e/src/jsrc/org/erights/e/elang/scope/ContourBoundary.java
Index: ContourBoundary.java
===================================================================
package org.erights.e.elang.scope;
import org.erights.e.elang.evm.NounExpr;
import org.erights.e.elib.tables.FlexSet;
import org.erights.e.elib.tables.ConstSet;
/**
* A ScopeMap consisting of an empty innermost contour on top of some other
* ScopeMap.
*
* @author <a href="mailto:tribble@e-dean.com">E. Dean Tribble</a>
* @author some mods by <a href="mailto:markm@erights.org">Mark S. Miller</a>
*/
/*package*/ class ContourBoundary extends ScopeMap {
private ScopeMap myNext;
/**
*
*/
/*package*/ ContourBoundary(ScopeMap outer) {
myNext = outer;
}
/**
*
*/
public NounExpr getNoun(String name) {
return myNext.getNoun(name);
}
/**
*
*/
public boolean contains(String name) {
return myNext.contains(name);
}
/**
*
*/
public ConstSet namesSet() {
return myNext.namesSet();
}
/**
*
*/
/*package*/ void addNamesTo(FlexSet names) {
myNext.addNamesTo(names);
}
/**
*
*/
public void assertShadowable(String varName) {
// Do nothing; we are at the end of the contour
}
/*
* There is no need for two contiguous boundaries, so just return self.
*/
public ScopeMap nested() {
return this;
}
}
1.1 e/src/jsrc/org/erights/e/elang/scope/ScopeMapBase.java
Index: ScopeMapBase.java
===================================================================
package org.erights.e.elang.scope;
import org.erights.e.elib.tables.ConstMap;
import org.erights.e.elib.tables.ConstSet;
import org.erights.e.elib.tables.FlexSet;
import org.erights.e.elib.util.AlreadyDefinedException;
import org.erights.e.elang.evm.NounExpr;
/**
* A single contour ScopeMap.
*
* @author <a href="mailto:tribble@e-dean.com">E. Dean Tribble</a>
* @author some mods by <a href="mailto:markm@erights.org">Mark S. Miller</a>
*/
/*package*/ class ScopeMapBase extends ScopeMap {
private final ConstMap myBindings;
/**
*
*/
/*package*/ ScopeMapBase(ConstMap bindings) {
myBindings = bindings;
}
/**
*
*/
public NounExpr getNoun(String name) {
NounExpr optRes = (NounExpr)myBindings.get(name, null);
if (optRes == null) {
throw new UndefinedVariableException(name + " not in scope");
}
return optRes;
}
/**
*
*/
public boolean contains(String name) {
return myBindings.maps(name);
}
/**
*
*/
public ConstSet namesSet() {
return (ConstSet)myBindings.domain();
}
/**
*
*/
/*package*/ void addNamesTo(FlexSet names) {
String[] varNames = (String[])myBindings.getKeys(String.class);
for (int i = 0; i < varNames.length; i++) {
names.addElement(varNames[i]);
}
}
/**
*
*/
public void assertShadowable(String name) {
if (contains(name)) {
throw new AlreadyDefinedException(name + " already in scope");
}
}
}
1.1 e/src/jsrc/org/erights/e/elang/scope/ScopeMapLink.java
Index: ScopeMapLink.java
===================================================================
package org.erights.e.elang.scope;
import org.erights.e.elang.evm.NounExpr;
import org.erights.e.elib.tables.ConstSet;
import org.erights.e.elib.tables.FlexSet;
import org.erights.e.elib.util.AlreadyDefinedException;
/**
* A ScopeMap having at least one name -> NounExpr association in the
* innermost contour.
* <p>
* Built from a single association and a previous ScopeMap.
*
* @author <a href="mailto:tribble@e-dean.com">E. Dean Tribble</a>
* @author some mods by <a href="mailto:markm@erights.org">Mark S. Miller</a>
*/
/*package*/ class ScopeMapLink extends ScopeMap {
private ScopeMap myNext;
private final String myName;
private final NounExpr myNoun;
/**
*
*/
/*package*/ ScopeMapLink(String name, NounExpr noun, ScopeMap others) {
myNext = others;
myName = name;
myNoun = noun;
}
/**
*
*/
public NounExpr getNoun(String name) {
// TODO markm are we guaranteed that the names are canonical?
return myName.equals(name) ? myNoun : myNext.getNoun(name);
}
/**
*
*/
public boolean contains(String name) {
// TODO markm are we guaranteed that the names are canonical?
return myName.equals(name) || myNext.contains(name);
}
/**
*
*/
/*package*/ void addNamesTo(FlexSet names) {
myNext.addNamesTo(names);
names.addElement(myName);
}
/**
*
*/
public void assertShadowable(String name) {
// TODO markm are we guaranteed that the names are canonical?
if (myName.equals(name)) {
throw new AlreadyDefinedException(name + " already in scope");
}
myNext.assertShadowable(name);
}
}
1.1 e/src/jsrc/org/erights/e/elib/base/EComparable.java
Index: EComparable.java
===================================================================
package org.erights.e.elib.base;
/**
* Like {@link Comparable}, but applies to irreflexive partial orders as well.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public interface EComparable {
/**
* 'x compareTo(y)' should return <ul>
* <li>0.0 is x is equivalent (in the order) to y: 'x <=> y'.</li>
* <li>A negative number if x is less than y: 'x < y'.</li>
* <li>A positive number if x is greater than y: 'x > y'.</li>
* <li>NaN is x and y are incomparable</li>
* </ul>
* This must follow the usual defintion of partial orders, except that we
* don't require the order to be reflexive. (In a reflexive order, for
* all x, 'x <=> x'.) Rather, we require that for all x, either x is <=>
* itself or it is incomparable to itself. This allows IEEE floating
* point numbers to play, even though NaNs break conventional reflexivity
* rules.
*/
double compareTo(EComparable other);
}
1.1 e/src/jsrc/org/erights/e/elib/tables/Iteratable.java
Index: Iteratable.java
===================================================================
package org.erights.e.elib.tables;
/**
* The operation assumed by E's for-loop.
* <p>
* This should therefore be universal to all E collections.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public interface Iteratable {
/**
*
*/
void iterate(AssocFunc func);
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/DollarHole.java
Index: DollarHole.java
===================================================================
package org.quasiliteral.quasiterm;
import antlr.Token;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.elib.base.SourceSpan;
import org.erights.e.elib.base.EComparable;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.serial.PassByConstruction;
import org.erights.e.elib.serial.Persistent;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.ConstMap;
import org.erights.e.elib.tables.Selfless;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.quasi.ValueMaker;
import org.erights.e.elib.quasi.MatchMaker;
import org.quasiliteral.astro.AstroToken;
import org.quasiliteral.term.TermLexer;
import org.quasiliteral.term.TermParser;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.Functor;
import java.math.BigInteger;
/**
* Corresponds to a "${<expression>}".
* <p>
* Depending on context, it may represent a Functor, a Term, or a list of
* Terms.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class DollarHole extends QuasiNode {
/**
*
*/
public static StaticMaker DollarHoleMaker =
StaticMaker.make(DollarHole.class);
/**
* @serial In normal usage, this should have the source position of the
* expression that was extracted to leave this hole behind.
*/
private final Twine mySource;
/**
* @serial Which dollar-hole is this?
*/
private final BigInteger myIndex;
/**
* @param index Which dollar-hole is this?
*/
public DollarHole(Twine source, BigInteger index) {
mySource = source;
myIndex = index;
}
/**
*
*/
public Object qbuild(TermBuilder builder) {
AstroToken token = new AstroToken(TermParser.LiteralInteger,
mySource,
myIndex);
return builder.dollarHole(token);
}
/**
* 'DollarHole new(mySource, myIndex)'
*/
public Object[] getCanonicalState() {
Object[] result = {
DollarHoleMaker, "new",
mySource, myIndex
};
return result;
}
/**
* "Evaluates" to args[myIndex]
*/
public Object substitute(Object[] args) {
return args[myIndex.intValue()];
}
/**
* Matches iff the specimen is <=> args[index], where this dollar-hole is
* encoded as '${<index>}'.
*/
public boolean matchBind(Object[] args,
Object specimen,
FlexList bindings)
{
if (! (specimen instanceof EComparable)) {
return false;
}
EComparable mine = (EComparable)args[myIndex.intValue()];
EComparable spec = (EComparable)specimen;
//XXX BUG: If mine and spec are types that don't compare, this will
//throw rather than returning false. It's unclear where to fix this.
return 0.0 == mine.compareTo(spec);
}
/**
*
*/
public String toString(boolean quasiFlag) {
return "${" + myIndex + "}";
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QuasiFunctor.java
Index: QuasiFunctor.java
===================================================================
package org.quasiliteral.quasiterm;
import antlr.Token;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.elib.base.SourceSpan;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.serial.PassByConstruction;
import org.erights.e.elib.serial.Persistent;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.ConstMap;
import org.erights.e.elib.tables.Selfless;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.quasi.ValueMaker;
import org.erights.e.elib.quasi.MatchMaker;
import org.quasiliteral.astro.AstroToken;
import org.quasiliteral.term.TermLexer;
import org.quasiliteral.term.TermParser;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.Functor;
import java.math.BigInteger;
/**
* A quasiliteral form of a {@link Functor}, for generating or matching
* actual Functors.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QuasiFunctor extends QuasiNode {
/**
*
*/
public static StaticMaker QuasiFunctorMaker =
StaticMaker.make(QuasiFunctor.class);
/**
* @serial The name of an Antlr token type int in a particular grammar.
*/
private final String myName;
/**
* @serial The source text corresponding to the original source of the
* token.
*/
private final Twine mySource;
/**
* Indicates the type of myValue.
* <pre>
* If myValue is myValueType is
* null -1
* a Character TermParser.LiteralChar
* a BigInteger TermParser.LiteralInteger
* a Double TermParser.LiteralFloat64
* a String TermParser.LiteralString
* a Twine TermParser.LiteralString
* </pre>
*/
private int myValueType;
/**
* @serial null, {@link Character}, {@link BigInteger}, {@link Double},
* {@link String}, or {@link Twine} calculated from lexing
* the token. When matching, a null is treated as a don't
* care.
*/
private Object myValue;
/**
* @param name The name of an Antlr token type int in a particular
* grammar. Must be an identifier. Printed only if not
* implied by value. When matching, must match exactly.
* @param source The source text corresponding to the original source of
* the token, although it isn't necessarily the same as the
* original source text. In any case, its source span
* information says what positions in the original source
* it corresponds to. This is not part of the normal
* printed form. Ignored when matching.
* @param value null, {@link Character},
* {@link BigInteger}, {@link Double},
* {@link String}, or {@link Twine}
* If non-null, is always part of the normal printed
* form. When matching, null means don't-care.
*/
public QuasiFunctor(String name, Twine source, Object value) {
if (!TermLexer.isIdentifier(name)) {
throw new RuntimeException("Must be an identifier: " + name);
}
myName = name;
mySource = source;
if (null == value) {
myValueType = -1;
} else if (value instanceof Character) {
myValueType = TermParser.LiteralChar;
} else if (value instanceof Number) {
if (value instanceof BigInteger) {
myValueType = TermParser.LiteralInteger;
} else if (value instanceof Double) {
myValueType = TermParser.LiteralFloat64;
} else {
throw new RuntimeException
("XXX Functor value coercion not yet implemented");
}
} else if (value instanceof String) {
myValueType = TermParser.LiteralString;
//XXX consider coercing value to Twine
} else if (value instanceof Twine) {
myValueType = TermParser.LiteralString;
} else {
throw new RuntimeException(value.getClass().getName() +
" not a literal type");
}
myValue = value;
}
/**
*
*/
public QuasiFunctor(Functor functor) {
this(functor.getName(), functor.getSource(), functor.getValue());
}
/**
*
*/
public Object qbuild(TermBuilder builder) {
if (null == myValue) {
return builder.functor(new AstroToken(TermParser.ID,
mySource,
myName));
} else if (isJustLiteral()) {
return builder.literal(new AstroToken(myValueType,
mySource,
myValue));
} else {
return builder.functor(new AstroToken(TermParser.ID,
Twine.fromString(""),
myName),
new AstroToken(myValueType,
mySource,
myValue));
}
}
/**
* 'QuasiFunctorMaker new(myTokenType, mySource, myOptValue)'
*/
public Object[] getCanonicalState() {
Object[] result = {
QuasiFunctorMaker, "new", myName, mySource, myValue
};
return result;
}
/**
*
*/
public String getName() {
return myName;
}
/**
*
*/
public Twine getSource() {
return mySource;
}
/**
*
*/
public Object getValue() {
return myValue;
}
/**
* Since a QuasiFunctor cannot yet contain any holes, this just returns
* the equivalent Functor.
*/
public Object substitute(Object[] args) {
return new Functor(myName, mySource, myValue);
}
/**
* If the specimen is a {@link Functor} that matches this QuasiFunctor,
* then add to 'bindings' any aspects of specimen extracted by
* corresponding at-holes, and return true. Otherwise, return false.
* <p>
* Since QuasiFunctors currently contain no holes, this just determines
* if the specimen matches. For purposes of the match, the names must be
* the same, the sources are ignored, and the values, if non-null, must be
* <=> (the same magnitude). This has the peculiar consequence that a
* literal NaN can't be matched, since it isn't <=> to anything. Further,
* 0.0 will match -0.0, since they are <=>.
* <p>
* If this QuasiFunctor's myValue is null, this is treated as a don't
* care. We should eventually be able to use an at-hole for this purpose
* as well.
*/
public boolean matchBind(Object[] args,
Object specimen,
FlexList bindings)
{
if (! (specimen instanceof Functor)) {
return false;
}
Functor spec = (Functor)specimen;
if (! myName.equals(spec.getName())) {
return false;
}
if (null == myValue) {
return true;
}
if (myValueType != spec.getValueType()) {
return false;
}
double comp =
E.asFloat64(E.call(myValue, "compareTo", spec.getValue()));
return 0.0 == comp;
}
/**
* Is myName the name implied by the type of myValue?
*/
private boolean isJustLiteral() {
return TermParser.getTokenNames().get(myValueType).equals(myName);
}
/**
*
*/
public String toString(boolean quasiFlag) {
if (null == myValue) {
return myName;
}
String valueStr = E.toQuote(myValue).bare();
if (quasiFlag) {
valueStr = StringHelper.replaceAll(valueStr, "$", "$$");
valueStr = StringHelper.replaceAll(valueStr, "@", "@@");
valueStr = StringHelper.replaceAll(valueStr, "`", "``");
}
if (isJustLiteral()) {
return valueStr;
}
return myName + ":" + valueStr;
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QuasiNode.java
Index: QuasiNode.java
===================================================================
package org.quasiliteral.quasiterm;
import antlr.Token;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.elib.base.SourceSpan;
import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.serial.PassByConstruction;
import org.erights.e.elib.serial.Persistent;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.ConstMap;
import org.erights.e.elib.tables.Selfless;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.FlexList;
import org.erights.e.elib.quasi.ValueMaker;
import org.erights.e.elib.quasi.MatchMaker;
import org.quasiliteral.astro.AstroToken;
import org.quasiliteral.term.TermLexer;
import org.quasiliteral.term.TermParser;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.Functor;
import java.math.BigInteger;
/**
* A node in a quasiliteral Term/Functor tree.
* <p>
* The superclass of all the particular kinds of node in such a tree.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public abstract class QuasiNode
implements Selfless, PassByConstruction, Persistent,
ValueMaker, MatchMaker {
/**
* When built using the QuasiTermBuilder, the result should be
* semantically equivalent to the original.
*/
public abstract Object qbuild(TermBuilder builder);
/**
* quasiFlag defaults to false
*/
public String toString() {
return toString(false);
}
/**
* If the printed form is read by the term__quasiParser (the
* QuasiTermBuilder), the result should be semantically equivalent to the
* original.
*/
public abstract String toString(boolean quasiFlag);
/**
* matchBind/2 is implemented generically in terms of matchBind/3.
*/
public ConstList matchBind(Object[] args, Object specimen) {
FlexList bindings = FlexList.make();
if (matchBind(args, specimen, bindings)) {
return bindings.snapshot();
} else {
return null;
}
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QuasiTerm.java
Index: QuasiTerm.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.elib.tables.Selfless;
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.ConstMap;
import org.erights.e.elib.serial.PassByConstruction;
import org.erights.e.elib.serial.Persistent;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.quasi.ValueMaker;
import org.erights.e.elib.quasi.MatchMaker;
import org.erights.e.develop.format.StringHelper;
import org.erights.e.develop.exception.ExceptionMgr;
import org.quasiliteral.astro.Astro;
import org.quasiliteral.term.Functor;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.Term;
import antlr.collections.AST;
import antlr.Grammar;
import antlr.Token;
import antlr.CommonToken;
import antlr.CommonAST;
import java.io.IOException;
import java.io.StringWriter;
/**
* A quasiliteral form of a {@link Term}, for generating or matching
* actual Terms.
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QuasiTerm extends QuasiNode {
/**
*
*/
static public final StaticMaker QuasiTermMaker =
StaticMaker.make(QuasiTerm.class);
/** @serial Tags this QuasiTerm to explain its meaning. */
private final QuasiNode myFunctor;
/** @serial A list of QuasiTerms */
private final ConstList myArgs;
/**
* Just used to decide how to pretty print.
* <p>
* Initialized lazily. 0 if uninitialized, so does not need to be
* recalculated on revival.
*/
private transient int myHeight = 0;
/**
* @param functor "explains" what kind of node this QuasiTerm is, and how
* to interpret the args.
* @param args A list of the children QuasiTerms.
*/
public QuasiTerm(QuasiNode functor, ConstList args) {
myFunctor = functor;
myArgs = args;
}
/**
* Like a visitor pattern, where 'builder' is the visitor.
* <p>
* When built using the QuasiTermBuilder, the result should be
* a semantically equivalent copy.
*/
public Object qbuild(TermBuilder builder) {
Object builtFunctor = myFunctor.qbuild(builder);
Object builtArgs = builder.argList();
int len = myArgs.size();
for (int i = 0; i < len; i++) {
QuasiTerm arg = (QuasiTerm)myArgs.get(i);
builtArgs = builder.argList(builtArgs, arg.qbuild(builder));
}
return builder.term(builtFunctor, builtArgs);
}
/**
*
*/
public Object[] getCanonicalState() {
Object[] result = { QuasiTermMaker, "new", myFunctor, myArgs };
return result;
}
/**
*
*/
public QuasiNode getQuasiFunctor() {
return myFunctor;
}
/**
*
*/
public ConstList getQuasiArgs() {
return myArgs;
}
/**
*"Evaluates" to a {@link Term}, by substituting the args for the
* dollar-holes in this QuasiTerm / QuasiFunctor tree.
*/
public Object substitute(Object[] args) {
int len = myArgs.size();
Object fobj = myFunctor.substitute(args);
Functor functor = null;
if (fobj instanceof Functor) {
functor = (Functor)fobj;
} else if (fobj instanceof Term) {
Term fTerm = (Term)fobj;
if (0 == len) {
//XXX Bug: Grammar must distinguish term`$1`
//vs term`$1()`. Since it doesn't, we treat both as the first
//and return $1 as the Term.
return fTerm;
} else if (0 == fTerm.getArgs().size()) {
functor = fTerm.getFunctor();
} else {
throw new RuntimeException
("XXX term where functor expected: " + fTerm);
}
}
ConstList terms = ConstList.EmptyList;
for (int i = 0; i < len; i++) {
QuasiNode node = (QuasiNode)myArgs.get(i);
Object val = node.substitute(args);
if (val instanceof Term) {
terms = terms.with((Term)val);
} else {
throw new RuntimeException("XXX not yet implemented");
}
}
return new Term(functor, terms);
}
/**
*
*/
public boolean matchBind(Object[] args,
Object specimen,
FlexList bindings)
{
if (! (specimen instanceof Term)) {
return false;
}
Term term = (Term)specimen;
if (! myFunctor.matchBind(args, term.getFunctor(), bindings)) {
return false;
}
int len = myArgs.size();
ConstList terms = term.getArgs();
for (int i = 0; i < len; i++) {
Object thing = myArgs.get(i);
if (thing instanceof QuasiTerm) {
Term spec = (Term)terms.get(0);
terms = terms.run(0, terms.size());
if (! ((QuasiTerm)thing).matchBind(args, spec, bindings)) {
return false;
}
} else {
throw new RuntimeException("XXX not yet implemented");
}
}
return true;
}
/**
* What's the longest distance to the bottom?
* <p>
* A leaf node is height 1. All other nodes are one more than the height
* of their highest child. This is used for pretty printing.
*/
public int getHeight() {
if (myHeight <= 0) {
myHeight = 1;
for (int i = 0; i < myArgs.size(); i++) {
int h = ((QuasiTerm)myArgs.get(i)).getHeight();
myHeight = Math.max(myHeight, h + 1);
}
}
return myHeight;
}
/**
*
*/
public String toString(boolean quasiFlag) {
StringWriter strWriter = new StringWriter();
try {
prettyPrintOn(new TextWriter(strWriter), quasiFlag);
} catch (Throwable th) {
throw ExceptionMgr.asSafe(th);
}
return strWriter.getBuffer().toString();
}
/**
*
*/
public void printOn(TextWriter out) throws IOException {
out.print("qterm`");
prettyPrintOn(out.indent(" "), true);
out.print("`");
}
/**
*
*/
public void prettyPrintOn(TextWriter out, boolean quasiFlag)
throws IOException {
String functorStr = myFunctor.toString(quasiFlag);
out.print(functorStr);
int h = getHeight();
if (h <= 1) {
if (myArgs.size() != 0) {
throw new RuntimeException("internal: bad height " + h);
}
//If it's a leaf, don't show parens either
return;
}
if (h == 2) {
//If it only contains leaves, do it on one line
out.print("(");
((QuasiTerm)myArgs.get(0)).prettyPrintOn(out, quasiFlag);
for (int i = 1; i < myArgs.size(); i++) {
out.print(", ");
((QuasiTerm)myArgs.get(i)).prettyPrintOn(out, quasiFlag);
}
out.print(")");
return;
}
//print each child lined up.
out.print("(");
int reps = functorStr.length() + 1;
String spaces = StringHelper.multiply(" ", reps);
TextWriter sub = out.indent(spaces);
((QuasiTerm)myArgs.get(0)).prettyPrintOn(sub, quasiFlag);
for (int i = 1; i < myArgs.size(); i++) {
sub.println(",");
((QuasiTerm)myArgs.get(i)).prettyPrintOn(sub, quasiFlag);
}
sub.print(")");
}
}
1.1 e/src/jsrc/org/quasiliteral/quasiterm/QuasiTermBuilder.java
Index: QuasiTermBuilder.java
===================================================================
package org.quasiliteral.quasiterm;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.quasi.QuasiExprParser;
import org.erights.e.elib.quasi.QuasiPatternParser;
import org.erights.e.elib.quasi.ValueMaker;
import org.erights.e.elib.quasi.MatchMaker;
import org.quasiliteral.astro.AstroToken;
import org.quasiliteral.term.TermBuilder;
import org.quasiliteral.term.Term;
import org.quasiliteral.term.Functor;
import org.quasiliteral.term.TermParser;
import java.math.BigInteger;
/**
* For building a quasiliteral for generating or matching Term/Functor trees.
* <p>
* The parameterization of types from TermBuilder are:<ul>
* <li>PDollarHole -- ??</li>
* <li>PAtHole -- ??</li>
* <li>PHole -- ??</li>
* <li>PDollarRepr -- ??</li>
* <li>PFunctor -- {@link QuasiFunctor}</li>
* <li>PTerm -- {@link QuasiTerm}</li>
* <li>PTerms, PArgs -- a {@link ConstList} of {@link QuasiTerm}</li>
* </ul>
*
* @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
*/
public class QuasiTermBuilder
implements TermBuilder, QuasiExprParser, QuasiPatternParser {
/**
*
*/
static public final QuasiTermBuilder THE_ONE = new QuasiTermBuilder();
/**
*
*/
private QuasiTermBuilder() {}
/**
*
*/
public ValueMaker valueMaker(Twine template, int[] dlrHoles) {
throw new RuntimeException
("XXX new quasi valueMaker API not yet implemented");
}
/**
*
*/
public ValueMaker valueMaker(Twine template) {
return (QuasiTerm)TermParser.run(template, THE_ONE);
}
/**
*
*/
public MatchMaker matchMaker(Twine template,
int[] dlrHoles,
int[] atHoles)
{
throw new RuntimeException
("XXX new quasi matchMaker API not yet implemented");
}
/**
*
*/
public MatchMaker matchMaker(Twine template) {
return (QuasiTerm)TermParser.run(template, THE_ONE);
}
/**
* @return true
*/
public boolean doesQuasis() { return true; }
/**
* @return :ConstList(QuasiTerm)
*/
public Object argList() {
return ConstList.EmptyList;
}
/**
* @param first :QuasiTerm
* @return :ConstList(QuasiTerm)
*/
public Object argList(Object first) {
return ConstList.EmptyList.with(first);
}
/**
* @param list :ConstList(QuasiTerm)
* @param next :QuasiTerm
* @return :ConstList(QuasiTerm)
*/
public Object argList(Object list, Object next) {
return ((ConstList)list).with(next);
}
/**
*
*/
public Object term(Object fnctr) {
//XXX Must promote hole to Term hole
return term(fnctr, ConstList.EmptyList);
}
/**
* @param fnctr :(QuasiNode
* @param args :ConstList(QuasiNode)
* @return :QuasiTerm
*/
public Object term(Object fnctr, Object args) {
return new QuasiTerm((QuasiNode)fnctr, (ConstList)args);
}
/**
* @param ident :AstroToken(ID)
* @return :QuasiFunctor
*/
public Object functor(Object ident) {
AstroToken tok = (AstroToken)ident;
if (TermParser.ID != tok.getType()) {
throw new RuntimeException("Must be ID: " + ident);
}
String name = (String)tok.getValue();
if (null == name) {
throw new RuntimeException("Must have value: " + ident);
}
return new QuasiFunctor(name, tok.getSource(), null);
}
/**
* @param lit :AstroToken(Literal*)
* @return :QuasiFunctor
*/
public Object literal(Object lit) {
AstroToken tok = (AstroToken)lit;
//XXX check that it's a kind of literal
Functor functor = tok.asFunctor(TermParser.getTokenNames());
return new QuasiFunctor(functor);
}
/**
* @param ident :AstroToken(ID)
* @param lit :AstroToken(Literal*)
* @return :QuasiFunctor
*/
public Object functor(Object ident, Object lit) {
AstroToken idTok = (AstroToken)ident;
AstroToken litTok = (AstroToken)lit;
if (TermParser.ID != idTok.getType()) {
throw new RuntimeException("Must be ID: " + ident);
}
String name = (String)idTok.getValue();
if (null == name) {
throw new RuntimeException("Must have value: " + ident);
}
Twine source = (Twine)idTok.getSource()
.add(":")
.add(litTok.getSource());
return new QuasiFunctor(name, source, litTok.getValue());
}
/**
*
*/
public Object dollarHole(Object index) {
AstroToken token = ((AstroToken)index);
return new DollarHole((Twine)token.getSource(),
(BigInteger)token.getValue());
}
/**
*
*/
public Object atHole(Object index) {
throw new RuntimeException("XXX Not yet implemented");
}
/**
*
*/
public Object dollarQuant(Object dHole, Object quant) {
throw new RuntimeException("XXX Not yet implemented");
}
/**
*
*/
public Object atQuant(Object optIdent, Object optQuant, Object atHole) {
throw new RuntimeException("XXX Not yet implemented");
}
/**
*
*/
public String toString() { return "<QuasiTermBuilder>"; }
}