[e-cvs] cvs commit: e/src/jsrc/org/quasiliteral/term Functor.java Term.java Term.updoc

markm@eros.cs.jhu.edu markm@eros.cs.jhu.edu
Sat, 3 Nov 2001 08:32:52 -0500


markm       01/11/03 08:32:52

  Modified:    src/jsrc Makefile
               src/jsrc/org/capml/quasi QuasiContent.java
               src/jsrc/org/erights/e/elang/syntax EBuilder.java
                        ELexer.java EParser.java URI.java
  Added:       src/jsrc/org/quasiliteral/astro Astro.java
                        AstroLexerSharedInputState.java AstroToken.java
               src/jsrc/org/quasiliteral/term Functor.java Term.java
                        Term.updoc
  Removed:     src/jsrc/org/quasiliteral/astro Functor.java MilkAST.java
                        MilkToken.java TermTree.java TermTree.updoc
  Log:
  some term & astro refactoring

Revision  Changes    Path
1.56      +8 -8      e/src/jsrc/Makefile

Index: Makefile
===================================================================
RCS file: /cvs/e/src/jsrc/Makefile,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -r1.55 -r1.56
--- Makefile	2001/10/27 17:27:42	1.55
+++ Makefile	2001/11/03 13:32:50	1.56
@@ -1,7 +1,7 @@
 # This Makefile is hereby placed in the public domain.
 #
 # Makefile for $(TOP)/src/jsrc
-# Note that we now depend on Java JDK >= 1.2
+# Note that we now depend on Java JDK >= 1.3
 
 default: all
 
@@ -39,11 +39,12 @@
 	find $(ER)/meta/$(ER)/elib -name '*.java' >> files.tmp
 	$(JCOMPILE) @files.tmp
 
-# Capability Markup Language
-# dom variant for quasi-literal xml
+# AST manipulations
 # depends on stl_elib
-_capml:
-	find org/capml -name '*.java' > files.tmp
+_astro:
+	find antlr -name '*.java' > files.tmp
+	find org/quasiliteral -name '*.java' >> files.tmp
+	find org/capml -name '*.java' >> files.tmp
 	$(JCOMPILE) @files.tmp
 
 # tools needed to build elang
@@ -59,8 +60,7 @@
 	(cd $(ER)/elang/syntax; $(MAKE) all)
 
 # space-time-local elang
-# depends on stl_elib, elang_builder
-# expected to depend on _capml
+# depends on stl_elib, elang_builder, _astro
 stl_elang:
 	find $(ER)/elang            -name '*.java' > files.tmp
 	$(JCOMPILE) @files.tmp
@@ -96,7 +96,7 @@
 	$(JCOMPILE) @files.tmp
 
 
-pre_parser: setup _develop stl_elib _capml elang_builder
+pre_parser: setup _develop stl_elib _astro elang_builder
 
 post_parser: stl_elang _elmer _extern _vattp _captp _ertp
 



1.7       +1 -1      e/src/jsrc/org/capml/quasi/QuasiContent.java

Index: QuasiContent.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/capml/quasi/QuasiContent.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- QuasiContent.java	2001/09/07 05:49:20	1.6
+++ QuasiContent.java	2001/11/03 13:32:50	1.7
@@ -111,7 +111,7 @@
 
     /**
      * A convenience for placing @-hole matches into bindings.  XXX Note that
-     * it will not detect multiple store of null to the same index.
+     * it will not detect multiple stores of null to the same index.
      */
     static /*package*/ void bind(FlexList bindings, int index, Object value) {
         bindings.ensureSize(index+1);



1.80      +16 -16    e/src/jsrc/org/erights/e/elang/syntax/EBuilder.java

Index: EBuilder.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elang/syntax/EBuilder.java,v
retrieving revision 1.79
retrieving revision 1.80
diff -u -r1.79 -r1.80
--- EBuilder.java	2001/11/01 17:42:29	1.79
+++ EBuilder.java	2001/11/03 13:32:50	1.80
@@ -60,7 +60,7 @@
 import org.erights.e.elib.tables.EList;
 import org.erights.e.elib.tables.FlexList;
 import org.erights.e.elib.tables.FlexMap;
-import org.quasiliteral.astro.MilkToken;
+import org.quasiliteral.astro.AstroToken;
 
 /**
  * Build E parse-trees.  As a notational hack, EParser inherits from
@@ -233,8 +233,8 @@
     /*package*/ EExpr update(Object lValue, Object verb, Object rnValue) {
 
         String verbName;
-        if (verb instanceof MilkToken) {
-            verbName = ((MilkToken)verb).getText();
+        if (verb instanceof AstroToken) {
+            verbName = ((AstroToken)verb).getText();
         } else {
             verbName = (String)verb;
         }
@@ -325,7 +325,7 @@
      *
      */
     /*package*/ EExpr doMeta(Object keyword, Object verb, Object args) {
-        String kword = ((MilkToken)keyword).getText().intern();
+        String kword = ((AstroToken)keyword).getText().intern();
         String vrb = ((String)verb).intern();
         EExpr[] exprs = exprs(args);
         if ("meta" == kword) {
@@ -394,7 +394,7 @@
      *
      */
     /*package*/ EExpr doMetaSend(Object keyword, Object verb, Object args) {
-        String kword = ((MilkToken)keyword).getText().intern();
+        String kword = ((AstroToken)keyword).getText().intern();
         String vrb = ((String)verb).intern();
         EExpr[] exprs = exprs(args);
         if ("meta" == kword) {
@@ -601,7 +601,7 @@
      * When an at-hole is '@<ident>' or '@_'
      */
     /*package*/ Pattern atNoun(Object token) {
-        String str = ((MilkToken)token).getText();
+        String str = ((AstroToken)token).getText();
         if (str.charAt(0) != '@') {
             throw new RuntimeException("internal: \"" + str +
                                        "\" needs initial @");
@@ -658,7 +658,7 @@
      * When a dollar-hole is '$<ident>'
      */
     /*package*/ EExpr dollarNoun(Object token) {
-        String str = ((MilkToken)token).getText();
+        String str = ((AstroToken)token).getText();
         if (str.charAt(0) != '$') {
             throw new RuntimeException("internal: \"" + str +
                                        "\" needs initial $");
@@ -960,7 +960,7 @@
      *
      */
     /*package*/ LiteralExpr literal(Object token) {
-        MilkToken tokn = (MilkToken)token;
+        AstroToken tokn = (AstroToken)token;
         return new LiteralExpr(tokn.getOptValue());
     }
 
@@ -1135,7 +1135,7 @@
                                   eScript);
         } else if (isLiteralToken(optOName)) {
             return object(docComment,
-                          ((MilkToken)optOName).getOptValue(),
+                          ((AstroToken)optOName).getOptValue(),
                           auditors,
                           eScript);
 
@@ -1197,7 +1197,7 @@
 
         for (int i = 0; i < qList.length; i++) {
             if (isQuasiPart(qList[i])) {
-                buf.append(((MilkToken)qList[i]).getOptValue());
+                buf.append(((AstroToken)qList[i]).getOptValue());
 
             } else {
                 EExpr eExpr = (EExpr)qList[i];
@@ -1222,7 +1222,7 @@
      *
      */
     /*package*/ QuasiLiteralExpr quasiLiteralExpr(Object litIndex) {
-        MilkToken lit = (MilkToken)litIndex;
+        AstroToken lit = (AstroToken)litIndex;
         int index = ((Number)lit.getOptValue()).intValue();
         return new QuasiLiteralExpr(index);
     }
@@ -1231,7 +1231,7 @@
      *
      */
     /*package*/ QuasiLiteralPatt quasiLiteralPatt(Object litIndex) {
-        MilkToken lit = (MilkToken)litIndex;
+        AstroToken lit = (AstroToken)litIndex;
         int index = ((Number)lit.getOptValue()).intValue();
         return new QuasiLiteralPatt(index);
     }
@@ -1252,7 +1252,7 @@
 
         for (int i = 0; i < qList.length; i++) {
             if (isQuasiPart(qList[i])) {
-                buf.append(((MilkToken)qList[i]).getOptValue());
+                buf.append(((AstroToken)qList[i]).getOptValue());
 
             } else if (qList[i] instanceof EExpr) {
                 EExpr eExpr = (EExpr)qList[i];
@@ -1280,7 +1280,7 @@
      *
      */
     /*package*/ QuasiPatternExpr quasiPatternExpr(Object litIndex) {
-        MilkToken lit = (MilkToken)litIndex;
+        AstroToken lit = (AstroToken)litIndex;
         int index = ((Number)lit.getOptValue()).intValue();
         return new QuasiPatternExpr(index);
     }
@@ -1289,7 +1289,7 @@
      *
      */
     /*package*/ QuasiPatternPatt quasiPatternPatt(Object litIndex) {
-        MilkToken lit = (MilkToken)litIndex;
+        AstroToken lit = (AstroToken)litIndex;
         int index = ((Number)lit.getOptValue()).intValue();
         return new QuasiPatternPatt(index);
     }
@@ -1753,7 +1753,7 @@
 
         } else if (isLiteralToken(optOName)) {
             return oType(docComment,
-                         ((MilkToken)optOName).getOptValue(),
+                         ((AstroToken)optOName).getOptValue(),
                          auditors,
                          mTypes);
 



1.59      +95 -88    e/src/jsrc/org/erights/e/elang/syntax/ELexer.java

Index: ELexer.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elang/syntax/ELexer.java,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -r1.58 -r1.59
--- ELexer.java	2001/11/01 17:42:29	1.58
+++ ELexer.java	2001/11/03 13:32:50	1.59
@@ -22,7 +22,7 @@
 import org.erights.e.develop.exception.PrintStreamWriter;
 import org.erights.e.elib.eio.TextWriter;
 import org.erights.e.elib.tables.Twine;
-import org.quasiliteral.astro.MilkToken;
+import org.quasiliteral.astro.AstroToken;
 
 import java.io.BufferedReader;
 import java.io.FileReader;
@@ -248,8 +248,8 @@
     /**
      *
      */
-    public MilkToken nextToken() throws IOException, SyntaxException {
-        MilkToken result;
+    public AstroToken nextToken() throws IOException, SyntaxException {
+        AstroToken result;
         try {
             result = getNextToken();
         } finally {
@@ -266,7 +266,7 @@
     /**
      * Separated out for use by '>'
      */
-    private MilkToken continuer(MilkToken result) throws IOException {
+    private AstroToken continuer(AstroToken result) throws IOException {
         if (isWhite(myPos, myLData.length)) {
             myContinueFlag = true;
             skipLine();
@@ -386,7 +386,7 @@
     /**
      *
      */
-    private MilkToken getNextToken() throws IOException, SyntaxException {
+    private AstroToken getNextToken() throws IOException, SyntaxException {
         if (myDelayedNextChar) {
             nextChar();
             myDelayedNextChar = false;
@@ -407,12 +407,12 @@
             case '?': {
                 char c = (char)myChar;
                 nextChar();
-                return new MilkToken(c, endToken());
+                return new AstroToken(c, endToken());
             } case EOFCHAR: {
-                return new MilkToken(EParser.EOFTOK, Twine.fromString(""));
+                return new AstroToken(EParser.EOFTOK, Twine.fromString(""));
             } case '\n': {
                 myDelayedNextChar = true;
-                return new MilkToken(EParser.EOL, endToken());
+                return new AstroToken(EParser.EOL, endToken());
             } case '(': {
                 return openBracket(')');
             } case ')': {
@@ -447,9 +447,9 @@
                         syntaxError(key + " is a keyword");
                     }
                     myIndenter.pop('$', name);
-                    return new MilkToken(EParser.DollarIdent, name);
+                    return new AstroToken(EParser.DollarIdent, name);
                 }
-                return new MilkToken('$', endToken());
+                return new AstroToken('$', endToken());
             } case '@': {
                 nextChar();
                 if (myChar == '{') {
@@ -464,7 +464,7 @@
                     nextChar();
                     Twine name = endToken();
                     myIndenter.pop('@', name);
-                    return new MilkToken(EParser.AtIdent, name);
+                    return new AstroToken(EParser.AtIdent, name);
                 } else if (myChar != EOFCHAR &&
                            isIdentifierStart((char)myChar)) {
                     //A '@<ident>' closes a '@'
@@ -479,62 +479,62 @@
                         syntaxError(key + " is a keyword");
                     }
                     myIndenter.pop('@', name);
-                    return new MilkToken(EParser.AtIdent, name);
+                    return new AstroToken(EParser.AtIdent, name);
                 }
-                return new MilkToken('@', endToken());
+                return new AstroToken('@', endToken());
             } case '.': {
                 nextChar();
                 if (myChar == '.') {
                     nextChar();
                     if (myChar == '!') {
                         nextChar();
-                        return new MilkToken(EParser.OpTill, endToken());
+                        return new AstroToken(EParser.OpTill, endToken());
                     }
-                    return new MilkToken(EParser.OpThru, endToken());
+                    return new AstroToken(EParser.OpThru, endToken());
                 }
-                return new MilkToken('.', endToken());
+                return new AstroToken('.', endToken());
             } case '^': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssXor, endToken());
+                    return new AstroToken(EParser.OpAssXor, endToken());
                 }
-                return new MilkToken('^', endToken());
+                return new AstroToken('^', endToken());
             } case '+': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssAdd, endToken());
+                    return new AstroToken(EParser.OpAssAdd, endToken());
                 } else if (myChar == '+') {
                     nextChar();
                     syntaxError("token \"++\" is reserved");
                     return null; //keep compiler happy
                 }
-                return new MilkToken('+', endToken());
+                return new AstroToken('+', endToken());
             } case '-': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssSub, endToken());
+                    return new AstroToken(EParser.OpAssSub, endToken());
                 } else if (myChar == '>') {
                     nextChar();
-                    return new MilkToken(EParser.OpWhen, endToken());
+                    return new AstroToken(EParser.OpWhen, endToken());
                 } else if (myChar == '-') {
                     nextChar();
                     syntaxError("token \"--\" is reserved");
                     return null; //keep compiler happy
                 }
-                return new MilkToken('-', endToken());
+                return new AstroToken('-', endToken());
             } case ':': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAss, endToken());
+                    return new AstroToken(EParser.OpAss, endToken());
                 } else if (myChar == ':') {
                     nextChar();
-                    return new MilkToken(EParser.Audit, endToken());
+                    return new AstroToken(EParser.Audit, endToken());
                 }
-                return new MilkToken(':', endToken());
+                return new AstroToken(':', endToken());
             } case '<': {
                 nextChar();
                 if (myChar == '-') {
@@ -544,43 +544,43 @@
                         syntaxError("token \"<-*\" is reserved");
                         return null; //keep compiler happy
                     }
-                    return new MilkToken(EParser.Send, endToken());
+                    return new AstroToken(EParser.Send, endToken());
                 } else if (myChar == '=') {
                     nextChar();
                     if (myChar == '>') {
                         nextChar();
-                        return new MilkToken(EParser.OpABA, endToken());
+                        return new AstroToken(EParser.OpABA, endToken());
                     }
-                    return new MilkToken(EParser.OpLeq, endToken());
+                    return new AstroToken(EParser.OpLeq, endToken());
                 } else if (myChar == '<') {
                     nextChar();
                     if (myChar == '=') {
                         nextChar();
-                        return new MilkToken(EParser.OpAssAsl, endToken());
+                        return new AstroToken(EParser.OpAssAsl, endToken());
                     }
-                    return new MilkToken(EParser.OpAsl, endToken());
+                    return new AstroToken(EParser.OpAsl, endToken());
                 } else if (isIdentifierStart((char)myChar)) {
-                    MilkToken optResult = optUri();
+                    AstroToken optResult = optUri();
                     if (null != optResult) {
                         return optResult;
                     }
                 }
-                return new MilkToken('<', endToken());
+                return new AstroToken('<', endToken());
             } case '>': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpGeq, endToken());
+                    return new AstroToken(EParser.OpGeq, endToken());
                 } else if (myChar == '>') {
                     nextChar();
                     if (myChar == '=') {
                         nextChar();
-                        return new MilkToken(EParser.OpAssAsr, endToken());
+                        return new AstroToken(EParser.OpAssAsr, endToken());
                     }
-                    return new MilkToken(EParser.OpAsr, endToken());
+                    return new AstroToken(EParser.OpAsr, endToken());
                 }
                 Twine closer = endToken();
-                MilkToken result = new MilkToken('>', closer);
+                AstroToken result = new AstroToken('>', closer);
                 if (myIndenter.getCloser() == '>') {
                     myIndenter.pop('>', closer);
                     return result;
@@ -593,12 +593,12 @@
                     nextChar();
                     if (myChar == '=') {
                         nextChar();
-                        return new MilkToken(EParser.OpAssPow, endToken());
+                        return new AstroToken(EParser.OpAssPow, endToken());
                     }
-                    return new MilkToken(EParser.OpPow, endToken());
+                    return new AstroToken(EParser.OpPow, endToken());
                 } else if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssMul, endToken());
+                    return new AstroToken(EParser.OpAssMul, endToken());
                 } else if (myChar == '-' && peekChar('>')) {
                     nextChar();
                     nextChar();
@@ -609,26 +609,26 @@
                     syntaxError("'/*..*/' comments are reserved. " +
                                 "Use '#' or '//' on each line instead");
                 }
-                return new MilkToken('*', endToken());
+                return new AstroToken('*', endToken());
             } case '/': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssAprxDiv, endToken());
+                    return new AstroToken(EParser.OpAssAprxDiv, endToken());
                 } else if (myChar == '/') {
                     // Skip comment to end of line
                     skipLine();
-                    return new MilkToken(EParser.EOL, endToken());
+                    return new AstroToken(EParser.EOL, endToken());
                 } else if (myChar == '*') {
                     nextChar();
                     syntaxError("'/*..*/' comments are reserved. " +
                                 "Use '#' or '//' on each line instead");
                 }
-                return new MilkToken('/', endToken());
+                return new AstroToken('/', endToken());
             } case '#': {
                 // Skip comment to end of line (as in "//" case above).
                 skipLine();
-                return new MilkToken(EParser.EOL, endToken());
+                return new AstroToken(EParser.EOL, endToken());
             } case '\\': {
                 nextChar();
                 if (myChar == 'u' || myChar == 'U') {
@@ -642,7 +642,7 @@
                     myContinueFlag = true;
                     skipLine();
                     stopToken();
-                    MilkToken result = getNextToken();
+                    AstroToken result = getNextToken();
                     if (result.getType() == EParser.EOFTOK) {
                         needMore("continued line");
                         return null; //make compiler happy
@@ -658,35 +658,35 @@
                     nextChar();
                     if (myChar == '=') { // check for "%%="
                         nextChar();
-                        return new MilkToken(EParser.OpAssMod, endToken());
+                        return new AstroToken(EParser.OpAssMod, endToken());
                     }
-                    return new MilkToken(EParser.OpMod, endToken());
+                    return new AstroToken(EParser.OpMod, endToken());
                 } else if (myChar == '=') { // check for "%="
                      nextChar();
-                     return new MilkToken(EParser.OpAssRemdr, endToken());
+                     return new AstroToken(EParser.OpAssRemdr, endToken());
                 }
-                return new MilkToken('%', endToken());
+                return new AstroToken('%', endToken());
             } case '!': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpNSame, endToken());
+                    return new AstroToken(EParser.OpNSame, endToken());
                 } else if (myChar == '~') {
                     nextChar();
-                    return new MilkToken(EParser.MisMatch, endToken());
+                    return new AstroToken(EParser.MisMatch, endToken());
                 }
-                return new MilkToken('!', endToken());
+                return new AstroToken('!', endToken());
             } case '=': {
                 nextChar();
                 if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpSame, endToken());
+                    return new AstroToken(EParser.OpSame, endToken());
                 } else if (myChar == '>') {
                     nextChar();
-                    return new MilkToken(EParser.MapsTo, endToken());
+                    return new AstroToken(EParser.MapsTo, endToken());
                 } else if (myChar == '~') {
                     nextChar();
-                    return new MilkToken(EParser.MatchBind, endToken());
+                    return new AstroToken(EParser.MatchBind, endToken());
                 }
                 syntaxError("use ':=' for assignment, or '==' for equality");
                 return null; //keep compiler happy
@@ -694,25 +694,25 @@
                 nextChar();
                 if (myChar == '&') {
                     nextChar();
-                    return new MilkToken(EParser.OpLAnd, endToken());
+                    return new AstroToken(EParser.OpLAnd, endToken());
                 } else if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssAnd, endToken());
+                    return new AstroToken(EParser.OpAssAnd, endToken());
                 } else if (myChar == '!') {
                     nextChar();
-                    return new MilkToken(EParser.OpButNot, endToken());
+                    return new AstroToken(EParser.OpButNot, endToken());
                 }
-                return new MilkToken('&', endToken());
+                return new AstroToken('&', endToken());
             } case '|': {
                 nextChar();
                 if (myChar == '|') {
                     nextChar();
-                    return new MilkToken(EParser.OpLOr, endToken());
+                    return new AstroToken(EParser.OpLOr, endToken());
                 } else if (myChar == '=') {
                     nextChar();
-                    return new MilkToken(EParser.OpAssOr, endToken());
+                    return new AstroToken(EParser.OpAssOr, endToken());
                 }
-                return new MilkToken('|', endToken());
+                return new AstroToken('|', endToken());
             } case '\'': {
                 return charLiteral();
             } case '"': {
@@ -747,11 +747,11 @@
                     nextChar();
                     if (myChar == '=') {
                         nextChar();
-                        return new MilkToken(EParser.OpAssFlrDiv, endToken());
+                        return new AstroToken(EParser.OpAssFlrDiv, endToken());
                     }
-                    return new MilkToken(EParser.OpFlrDiv, endToken());
+                    return new AstroToken(EParser.OpFlrDiv, endToken());
                 }
-                return new MilkToken(EParser._, endToken());
+                return new AstroToken(EParser._, endToken());
 
             } default: {
                 if (isIdentifierStart((char)myChar)) {
@@ -768,7 +768,7 @@
     /**
      *
      */
-    private MilkToken openBracket(char closer) throws IOException {
+    private AstroToken openBracket(char closer) throws IOException {
         int tokenType = myChar;
         nextChar();
         Twine openner = endToken();
@@ -778,7 +778,7 @@
     /**
      *
      */
-    private MilkToken openBracket(int tokenType, Twine openner, char closer)
+    private AstroToken openBracket(int tokenType, Twine openner, char closer)
     throws IOException {
         if (isWhite(myPos, myLData.length)) {
             myIndenter.nest(openner, closer);
@@ -786,20 +786,20 @@
             //Indent the next line to right after the open.
             myIndenter.push(openner, closer, myPos);
         }
-        return new MilkToken(tokenType, openner);
+        return new AstroToken(tokenType, openner);
     }
 
     /**
      *
      */
-    private MilkToken closeBracket() throws IOException {
+    private AstroToken closeBracket() throws IOException {
         char closerChar = (char)myChar;
         nextChar();
         Twine closer = endToken();
         //on mismatched close, throws SyntaxError at openner
         //on unmatched close, throws Syntax error at closer
         myIndenter.pop(closerChar, closer);
-        return new MilkToken(closerChar, closer);
+        return new AstroToken(closerChar, closer);
     }
 
     /**
@@ -852,7 +852,7 @@
     /**
      *
      */
-    private MilkToken charLiteral() throws IOException, SyntaxException {
+    private AstroToken charLiteral() throws IOException, SyntaxException {
         nextChar();
         char value = charConstant();
         nextChar();
@@ -860,7 +860,7 @@
             syntaxError("char constant must end in \"'\"");
         }
         nextChar();
-        return new MilkToken(EParser.LiteralChar,
+        return new AstroToken(EParser.LiteralChar,
                              endToken(),
                              new Character(value));
     }
@@ -868,21 +868,26 @@
     /**
      * Called with myChar as the first character of the identifier.
      */
-    private MilkToken identifier() throws IOException, SyntaxException {
+    private AstroToken identifier() throws IOException, SyntaxException {
         do {
             nextChar();
         } while (myChar != EOFCHAR && isIdentifierPart((char)myChar));
 
         if ('=' == myChar) {
-            nextChar();
-            return new MilkToken(EParser.VerbAss, endToken());
+            char c = peekChar();
+            if ("=>~".indexOf(c) == -1) {
+                //'<ident>=' is a VerbAss, given that the '=' isn't
+                //part of a '==', '=>', or '=~'.
+                nextChar();
+                return new AstroToken(EParser.VerbAss, endToken());
+            }
         }
         Twine source = endToken();
         int ttype = EParser.tokenType(source.toLowerCase());
         if (-1 == ttype) {
             ttype = EParser.Identifier;
         }
-        return new MilkToken(ttype, source);
+        return new AstroToken(ttype, source);
     }
 
     /** pretty self explanatory */
@@ -938,7 +943,7 @@
     /**
      *
      */
-    private MilkToken numberLiteral()
+    private AstroToken numberLiteral()
     throws IOException, SyntaxException {
         // Now handles floating point numbers as well as integers
         boolean floating = false;
@@ -976,7 +981,7 @@
         tok = tok.replaceAll("_", "");
         String str = tok.bare();
         if (floating) {
-            return new MilkToken(EParser.LiteralFloat64,
+            return new AstroToken(EParser.LiteralFloat64,
                                  tok,
                                  Double.valueOf(str));
         } else {
@@ -984,7 +989,7 @@
                 //remove the leading "0x" to make BigInteger happy
                 str = str.substring(2);
             }
-            return new MilkToken(EParser.LiteralInteger,
+            return new AstroToken(EParser.LiteralInteger,
                                  tok,
                                  new BigInteger(str, radix));
         }
@@ -1023,9 +1028,11 @@
     }
 
     /**
-     *
+     * XXX In order to enable optValue to be recovered from ttype and
+     * source, we need four ttypes rather than the current two: QuasiOpen
+     * and QuasiClose.
      */
-    private MilkToken quasiPart() throws IOException, SyntaxException {
+    private AstroToken quasiPart() throws IOException, SyntaxException {
         StringBuffer buf = new StringBuffer();
         while (true) {
             while (QUASI_ENDER.indexOf(myChar) == -1) {
@@ -1055,7 +1062,7 @@
                 nextChar();
                 Twine closer = endToken();
                 myIndenter.pop('`', closer);
-                return new MilkToken(EParser.QuasiClose,
+                return new AstroToken(EParser.QuasiClose,
                                      closer,
                                      buf.toString());
 
@@ -1080,7 +1087,7 @@
                 myIndenter.nest(openner, (char)myChar);
                 //interpolated '$' or '@' is neither eaten nor added to the
                 //value of the resulting QuasiOpen token.
-                return new MilkToken(EParser.QuasiOpen,
+                return new AstroToken(EParser.QuasiOpen,
                                      openner,
                                      buf.toString());
             }
@@ -1146,7 +1153,7 @@
     /**
      *
      */
-    private MilkToken stringLiteral() throws IOException, SyntaxException {
+    private AstroToken stringLiteral() throws IOException, SyntaxException {
         nextChar();
         Twine openner = (Twine)myLTwine.run(myOptStartPos, myPos);
         myIndenter.push(openner, '"', 0);
@@ -1161,7 +1168,7 @@
         nextChar();
         Twine closer = endToken();
         myIndenter.pop('"', closer);
-        return new MilkToken(EParser.LiteralString,
+        return new AstroToken(EParser.LiteralString,
                              closer,
                              value.toString());
     }
@@ -1172,7 +1179,7 @@
      * is not immediately followed by a ":", return null and cause no side
      * effects -- in particular, do not effect the current position.
      */
-    private MilkToken optUri() throws IOException, SyntaxException {
+    private AstroToken optUri() throws IOException, SyntaxException {
         int len = myLData.length;
         int pos = myPos + 1;
         while (pos < len && isIdentifierPart(myLData[pos])) {
@@ -1232,7 +1239,7 @@
         ELexer lex = new ELexer(lr, false, false);
         while (true) {
             try {
-                MilkToken t;
+                AstroToken t;
                 do {
                     t = lex.nextToken();
                     stdout.println(t);



1.96      +15 -15    e/src/jsrc/org/erights/e/elang/syntax/EParser.java

Index: EParser.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elang/syntax/EParser.java,v
retrieving revision 1.95
retrieving revision 1.96
diff -u -r1.95 -r1.96
--- EParser.java	2001/11/01 17:42:29	1.95
+++ EParser.java	2001/11/03 13:32:50	1.96
@@ -27,7 +27,7 @@
 import org.erights.e.elib.tables.IdentityCacheTable;
 import org.erights.e.elib.tables.IntTable;
 import org.erights.e.elib.tables.Twine;
- import org.quasiliteral.astro.MilkToken;
+ import org.quasiliteral.astro.AstroToken;
 //#line 29 "EParser.java"
 
 
@@ -1141,7 +1141,7 @@
 static public final StaticMaker EParserMaker =
     StaticMaker.make(EParser.class);
 
-/** 
+/**
  * caches previous simple parses (as is used for quasi-parsing)
  */
 static private IdentityCacheTable OurCache =
@@ -1150,7 +1150,7 @@
 /**
  *
  */
-static private final ConstMap DefaultProps = 
+static private final ConstMap DefaultProps =
   ConstMap.fromProperties(System.getProperties());
 
 
@@ -1158,7 +1158,7 @@
 /** contains all the tokens after yylval */
 private ELexer myLexer;
 
-/** 
+/**
  * Do we escape after parsing only one expression, or do we parse the
  * entire input?
  */
@@ -1260,7 +1260,7 @@
 
 /**
  * If the input is empty, returns the null expression e`null`, rather
- * than null. 
+ * than null.
  */
 public ENode parse() {
     ENode result = optParse();
@@ -1303,7 +1303,7 @@
  *
  */
 private int yylex() {
-    MilkToken token = null;
+    AstroToken token = null;
     try {
         token = myLexer.nextToken();
     } catch (IOException ex) {
@@ -1318,10 +1318,10 @@
  *
  */
 private void yyerror(String s) throws SyntaxException {
-    int ttype = ((MilkToken)yylval).getType();
+    int ttype = ((AstroToken)yylval).getType();
     if (EParser.EOFTOK == ttype && "syntax error".equals(s)) {
         myLexer.needMore("Unexpected EOF");
-        
+
     } else {
         syntaxError(s);
     }
@@ -1353,10 +1353,10 @@
  *
  */
 private boolean isTokenKind(Object tok, int[] members) {
-    if (! (tok instanceof MilkToken)) {
+    if (! (tok instanceof AstroToken)) {
         return false;
     }
-    int ttype = ((MilkToken)tok).getType();
+    int ttype = ((AstroToken)tok).getType();
     for (int i = 0; i < members.length; i++) {
         if (ttype == members[i]) {
             return true;
@@ -1622,7 +1622,7 @@
 /**
  * These are the tokens that may appear at the end of a line, in which
  * case the next line is a (to be indented) continuation of the
- * expression. 
+ * expression.
  * <p>
  * Note that &gt; isn't on the list because of its role in closing a
  * calculated URI expression.
@@ -1720,7 +1720,7 @@
 //###############################################################
 // method: yyparse : parse input and execute indicated items
 //###############################################################
-int yyparse() 
+int yyparse()
 {
 int yyn;       //next next thing to do
 int yym;       //
@@ -1736,7 +1736,7 @@
   while (true) //until parsing is done, either correctly, or w/error
     {
     doaction=true;
-    if (yydebug) debug("loop"); 
+    if (yydebug) debug("loop");
     //#### NEXT ACTION (from reduction table)
     for (yyn=yydefred[yystate];yyn==0;yyn=yydefred[yystate])
       {
@@ -2677,12 +2677,12 @@
 break;
 case 260:
 //#line 972 "e.y"
-{ yyval = ((MilkToken)val_peek(0)).getText(); }
+{ yyval = ((AstroToken)val_peek(0)).getText(); }
 break;
 case 261:
 //#line 973 "e.y"
 { reserved("keyword \"" +
-                                                   ((MilkToken)val_peek(0)).getText() +
+                                                   ((AstroToken)val_peek(0)).getText() +
                                                    "\""); }
 break;
 case 262:



1.16      +5 -5      e/src/jsrc/org/erights/e/elang/syntax/URI.java

Index: URI.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elang/syntax/URI.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- URI.java	2001/11/01 17:42:30	1.15
+++ URI.java	2001/11/03 13:32:51	1.16
@@ -20,7 +20,7 @@
 */
 
 import org.erights.e.elib.tables.Twine;
-import org.quasiliteral.astro.MilkToken;
+import org.quasiliteral.astro.AstroToken;
 
 /**
  * A URI is an E token and an E expression. <p> <pre>
@@ -30,8 +30,8 @@
  *      '<' Identifier ':'
  * </pre>
  * XXX This class should probably not define a separate subclass of
- * MilkToken, but rather just provide some static conveniences for dealing
- * with MilkTokens that are of type URI or URIStart.
+ * AstroToken, but rather just provide some static conveniences for dealing
+ * with AstroTokens that are of type URI or URIStart.
  *
  * @see org.erights.e.elang.syntax.Identifier
  * @see org.erights.e.elang.syntax.URI#isURICStart
@@ -39,7 +39,7 @@
  *
  * @author <a href="mailto:markm@erights.org">Mark S. Miller</a>
  */
-public class URI extends MilkToken {
+public class URI extends AstroToken {
 
     static private boolean URICs[] = new boolean[128];
 
@@ -92,7 +92,7 @@
     /**
      *
      */
-    static public MilkToken make(int tokenType, Twine source) {
+    static public AstroToken make(int tokenType, Twine source) {
         source = source.replaceAll("\\","/").replaceAll("|",":");
         return new URI(tokenType, source);
     }



1.1                  e/src/jsrc/org/quasiliteral/astro/Astro.java

Index: Astro.java
===================================================================
package org.quasiliteral.astro;

import antlr.Token;
import antlr.CommonToken;
import antlr.BaseAST;
import antlr.collections.AST;

/**
 * AST node implementation which stores tokens explicitly. This
 * is handy if you'd rather derive information from tokens on an
 * as-needed basis instead of snarfing data from a token as an AST
 * is being built.
 *
 * @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
 * @author Based on Danfuzz Bornstein's TokenAST
 */
public class Astro extends BaseAST {

    /**
     *
     */
    private Token myToken;

    /**
     * Construct an instance which (at least initially) is not associated
     * with a token.
     */
    public Astro() {
        myToken = null;
    }

    /**
     * Construct an instance which is associated with the given token.
     *
     * @param tok null-ok; the token to associate this instance with
     */
    public Astro(Token tok) {
        initialize(tok);
    }

    /**
     * Get the token text for this instance. If there is no token associated
     * with this instance, then this returns the empty string
     * (<code>""</code>), not <code>null</code>.
     *
     * @return non-null; the token text
     */
    public String getText() {
        if (myToken == null) {
            return "";
        } else {
            return myToken.getText();
        }
    }

    /**
     * Get the token type for this instance. If there is no token associated
     * with this instance, then this returns {@link Token#INVALID_TYPE}.
     *
     * @return the token type
     */
    public int getType() {
        if (myToken == null) {
            return Token.INVALID_TYPE;
        } else {
            return myToken.getType();
        }
    }

    /**
     * Get the token associated with this instance. If there is no token
     * associated with this instance, then this returns <code>null</code>.
     *
     * @return null-ok; the token associated with this instance or
     * <code>mull</code> if there is no associated token
     */
    public Token getToken() {
        return myToken;
    }

    /**
     * Set the token associated with this instance.
     *
     * @param tok null-ok; the new token to associate with this instance
     */
    public void setToken(Token tok) {
        myToken = tok;
    }

    /**
     * Initialize this instance with the given token.
     *
     * @param tok null-ok; the token to associate with this instance
     */
    public void initialize(Token tok) {
        myToken = tok;
    }

    /**
     * Initialize this instance with the given token type and text.
     * This will construct a new {@link CommonToken} with the given
     * parameters and associate this instance with it.
     *
     * @param type the token type
     * @param text null-ok; the token text
     */
    public void initialize(int type, String text) {
        initialize(new CommonToken(type, text));
    }

    /**
     * Initialize this instance based on the given {@link AST}.
     * If the given <code>AST</code> is in fact an instance of
     * <code>Astro</code>, then this instance will be initialized
     * to point at the same token as the given one. If not, then this
     * instance will be initialized with the same token type and text
     * as the given one.
     *
     * @param ast non-null; the <code>AST</code> to base this instance on
     */
    public void initialize(AST ast) {
        if (ast instanceof Astro) {
            initialize(((Astro)ast).getToken());
        } else {
            initialize(ast.getType(), ast.getText());
        }
    }

    /**
     * Set the token text for this node. If this instance is already
     * associated with a token, then that token is destructively modified
     * by this operation. If not, then a new token is constructed with
     * the type {@link Token#INVALID_TYPE} and the given text.
     *
     * @param text the new token text
     */
    public void setText(String text) {
        if (myToken == null) {
            initialize(Token.INVALID_TYPE, text);
        } else {
            myToken.setText(text);
        }
    }

    /**
     * Set the token type for this node. If this instance is already
     * associated with a token, then that token is destructively modified
     * by this operation. If not, then a new token is constructed with
     * the given type and an empty (<code>""</code>, not <code>null</code>)
     * text string.
     *
     * @param type the new token type
     */
    public void setType(int type) {
        if (myToken == null) {
            initialize(type, "");
        } else {
            myToken.setType(type);
        }
    }

}



1.1                  e/src/jsrc/org/quasiliteral/astro/AstroLexerSharedInputState.java

Index: AstroLexerSharedInputState.java
===================================================================
package org.quasiliteral.astro;

import antlr.LexerSharedInputState;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Extension of {@link LexerSharedInputState} that is aware of
 * file names and can annotate {@link ExtentTokens} with them and
 * with end position information.
 *
 * <p>This file is in the public domain.</p>
 *
 * @author Mark Miller
 * @author based on Dan Bornstein's ExtentLexerSharedInputState
 */
public class AstroLexerSharedInputState extends LexerSharedInputState {

    /** the name of the file this instance refers to */
    private String mySourceURL;

    /**
     * Construct an instance.
     *
     * @param s the input stream to use
     * @param url null-ok; the file name to associate with this instance
     */
    public AstroLexerSharedInputState(InputStream s, String url) {
        super(s);
        mySourceURL = url;
    }

    /**
     * Construct an instance. The file name is set to <code>null</code>
     * initially.
     *
     * @param s the input stream to use
     */
    public AstroLexerSharedInputState(InputStream s) {
        this(s, null);
    }

    /**
     * Get the current line of this instance.
     *
     * @return the current line number
     */
    public int getLine() {
        return line;
    }

    /**
     * Get the current column of this instance.
     *
     * @return the current column number
     */
    public int getColumn() {
        return column;
    }

    /**
     * Get the file name of this instance.
     *
     * @return null-ok; the file name
     */
    public String getSourceURL() {
        return mySourceURL;
    }

    /**
     * Annotate an {@link ExtentToken} based on this instance. It sets
     * the end position information as well as the file name.
     *
     * @param token non-null; the token to annotate
     */
    public void annotate(AstroToken token) {
        //XXX does nothing yet.
    }
}



1.1                  e/src/jsrc/org/quasiliteral/astro/AstroToken.java

Index: AstroToken.java
===================================================================
package org.quasiliteral.astro;

import antlr.CommonToken;
import antlr.Token;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.ConstList;
import org.erights.e.elib.base.SourceSpan;
import org.quasiliteral.term.Functor;
import org.quasiliteral.term.Literal;

/**
 * A Kind of Antlr {@link Token} that preserves all the information in a
 * {@link Functor}, except that it uses an int rather that a string for the
 * token-type.
 *
 * @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
 * @author Based on ValueExtentToken by Danfuzz Bornstein
 */
public class AstroToken extends CommonToken {

    /**
     *
     */
    private Twine mySource;

    /**
     * If present, then this should be a literal character, string, twine
     * integer, or float64 whose value can be recovered from mySource
     */
    private Object myOptValue;

    /**
     * Construct an instance. The instance will be of type {@link
     * #INVALID_TYPE}, and have empty (<code>""</code>, not
     * <code>null</code>) twine.
     */
    public AstroToken() {
        this(INVALID_TYPE, Twine.fromString(""), null);
    }

    /**
     * Construct an instance. The instance will be of type {@link
     * #INVALID_TYPE}
     */
    public AstroToken(Twine source) {
        this(INVALID_TYPE, source, null);
    }

    /**
     *
     */
    public AstroToken(int ttype, Twine source) {
        this(ttype, source, null);
    }

    /**
     *
     */
    public AstroToken(int ttype, Twine source, Object optValue) {
        super(ttype, source.bare());
        setSource(source);
        myOptValue = optValue;
    }

    /**
     *
     */
    public Functor asFunctor(ConstList typeNames) {
        String tokenType = (String)typeNames.get(getType());
        if (null == myOptValue) {
            return new Functor(tokenType, mySource);
        } else {
            return new Literal(tokenType, mySource, myOptValue);
        }
    }

    /**
     *
     */
    public Twine getSource() {
        return mySource;
    }

    /**
     *
     */
    public void setSource(Twine source) {
        mySource = source;
        setText(source.bare());
        SourceSpan optSpan = source.optSourceSpan();
        if (null != optSpan) {
            setLine(optSpan.getStartLine());
            setColumn(optSpan.getStartCol());
        }
    }

    /**
     *
     */
    public Object getOptValue() {
        return myOptValue;
    }

    /**
     *
     */
    public void setOptValue(Object optValue) {
        myOptValue = optValue;
    }
}



1.1                  e/src/jsrc/org/quasiliteral/term/Functor.java

Index: Functor.java
===================================================================
package org.quasiliteral.term;

import org.erights.e.elib.tables.Selfless;
import org.erights.e.elib.tables.Twine;
import org.erights.e.elib.tables.ConstList;
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.base.SourceSpan;
import org.erights.e.elib.eio.TextWriter;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.prim.E;
import org.quasiliteral.astro.AstroToken;
import antlr.Token;
import antlr.Grammar;
import antlr.CommonToken;

/**
 * Like an Antlr {@link Token}, but with differences that make it suitable
 * for quasiliteral processing.
 * <p>
 * The differences are
 * <ul>
 * <li>It knows how to convert to and from an Antlr Token, in a way that
 *     preserves the semantics of vanilla Tokens.
 * <li>It's PassByCopy, necessitating it be Immutable.</li>
 * <li>The token-type is identified by a string instead of a number,
 *     enabling it to make some sense without reference to a specific
 *     grammar.</li>
 * <li>The token-text is a {@link Twine} instead of a string, and can
 *     therefore remember its source positions.</li>
 * <li>It has a convenient printed form.</li>
 * </ul>
 *
 * @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
 * @author Many ideas from Danfuzz Bornstein
 * @author Many thanks also to Dean Tribble
 */
public class Functor implements Selfless, PassByConstruction, Persistent {

    /**
     *
     */
    public static StaticMaker FunctorMaker = StaticMaker.make(Functor.class);

    /**
     * @serial The name of an Antlr token type int in a particular grammar.
     */
    private final String myTokenType;

    /**
     * @serial The source text corresponding to the original source of the
     *         token.
     */
    private final Twine mySource;

    /**
     * @param tokenType The name of an Antlr token type int in a particular
     *                  grammar.
     * @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. The source position info is not part
     *               of the normal printed form.
     * @param optValue An optional value calculated from the source text.
     *                 Not part of the normal printed form.
     */
    public Functor(String tokenType, Twine source) {
        myTokenType = tokenType;
        mySource = source;
    }

    /**
     * If token is an AstroToken, this just does token.asFunctor(typeNames)
     */
    static public Functor fromToken(Token token,
                                    String url,
                                    ConstList typeNames)
    {
        if (token instanceof AstroToken) {
            return ((AstroToken)token).asFunctor(typeNames);
        } else {
            String tokenType = (String)typeNames.get(token.getType());
            SourceSpan span = new SourceSpan(url,
                                             false,
                                             token.getLine(),
                                             token.getColumn(),
                                             token.getLine(),
                                             token.getColumn());
            return new Functor(tokenType,
                               Twine.fromString(token.getText(), span));
        }
    }

    /**
     *
     */
    public AstroToken asToken(ConstMap typeNums) {
        int tokenTypeInt = E.asInt(typeNums.get(myTokenType));
        return new AstroToken(tokenTypeInt, mySource);
    }

    /**
     * 'FunctorMaker new(myTokenType, mySource)'
     */
    public Object[] getCanonicalState() {
        Object[] result = {
            FunctorMaker, "new",
            myTokenType, mySource
        };
        return result;
    }

    /**
     *
     */
    public String getTokenType() {
        return myTokenType;
    }

    /**
     *
     */
    public Twine getSource() {
        return mySource;
    }

    /**
     *
     */
    public String toString() {
        return toString(false);
    }

    /**
     *
     */
    public String toString(boolean quasiFlag) {
        String result = myTokenType;
        if (! myTokenType.equals(mySource.bare())) {
            result += ":";
            Twine quoted = mySource.quote();
            if (quasiFlag) {
                quoted = quoted.replaceAll("$", "$$");
                quoted = quoted.replaceAll("@", "@@");
                quoted = quoted.replaceAll("`", "``");
            }
            result += quoted.bare();
        }
        return result;
    }
}



1.1                  e/src/jsrc/org/quasiliteral/term/Term.java

Index: Term.java
===================================================================
package org.quasiliteral.term;

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.develop.format.StringHelper;
import org.quasiliteral.astro.Astro;
import antlr.collections.AST;
import antlr.Grammar;
import antlr.Token;
import antlr.CommonToken;
import antlr.CommonAST;

import java.io.IOException;

/**
 * Like an Antlr {@link AST}, but with differences that make it suitable for
 * quasiliteral processing.
 * <p>
 * The differences are:<ul>
 * <li>It knows how to convert to and from an Antlr AST, in a way that
 *     preserves the semantics of vanilla ASTs.
 * <li>It's PassByCopy, necessitating it be Immutable.</li>
 * <li>Each Term only points downward, not rightward, making them
 *     sharable by different containing contexts.</li>
 * <li>The functor is a {@link Functor}, which is likewise like an Antlr
 *     {@link Token}, rather than just storing a String and an int.</li>
 * <li>It has a more conventional printed form, like a prolog term tree.</li>
 * </ul>
 *
 * @author <a href="mailto:markm@caplet.com">Mark S Miller</a>
 * @author Many ideas from Danfuzz Bornstein
 * @author Many thanks also to Dean Tribble
 */
public class Term implements Selfless, PassByConstruction, Persistent {

    /**
     *
     */
    static public final StaticMaker TermMaker =
      StaticMaker.make(Term.class);

    /** @serial Tags this Term to explain its meaning. */
    private final Functor myFunctor;

    /** @serial A list of Terms */
    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 Term is, and how
     *                to interpret the args.
     * @param args A list of the children Terms.
     */
    public Term(Functor functor, ConstList args) {
        myFunctor = functor;
        myArgs = args;
    }

    /**
     * Converts an Antlr AST to a Term tree, while preserving all the vanilla
     * AST semantics.
     */
    static public Term fromAST(AST ast,
                               String url,
                               ConstList typeNames)
    {
        Token token;
        if (ast instanceof Astro) {
            token = ((Astro)ast).getToken();
        } else {
            token = new CommonToken(ast.getType(), ast.getText());
        }
        FlexList args = FlexList.fromType(Term.class);
        for (AST arg = ast.getFirstChild();
             null != arg;
             arg = arg.getNextSibling())
        {
            args.push(Term.fromAST(arg, url, typeNames));
        }
        return new Term(Functor.fromToken(token, url, typeNames),
                        args.snapshot());
    }

    /**
     * Convert this Term tree to an equivalent Antlr AST representation.
     */
    public Astro asAST(ConstMap typeNums) {
        Token token = myFunctor.asToken(typeNums);
        Astro result = new Astro(token);
        for (int i = 0; i < myArgs.size(); i++) {
            result.addChild(((Term)myArgs.get(i)).asAST(typeNums));
        }
        return result;
    }

    /**
     *
     */
    public Object[] getCanonicalState() {
        Object[] result = { TermMaker, "new", myFunctor, myArgs };
        return result;
    }

    /**
     *
     */
    public Functor getFunctor() {
        return myFunctor;
    }

    /**
     *
     */
    public ConstList getArgs() {
        return myArgs;
    }

    /**
     * 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 = ((Term)myArgs.get(i)).getHeight();
                myHeight = Math.max(myHeight, h + 1);
            }
        }
        return myHeight;
    }

    /**
     *
     */
    public void printOn(TextWriter out) throws IOException {
        out.print("term`");
        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("(");
            ((Term)myArgs.get(0)).prettyPrintOn(out, quasiFlag);
            for (int i = 1; i < myArgs.size(); i++) {
                out.print(", ");
                ((Term)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);

        ((Term)myArgs.get(0)).prettyPrintOn(sub, quasiFlag);
        for (int i = 1; i < myArgs.size(); i++) {
            sub.println(",");
            ((Term)myArgs.get(i)).prettyPrintOn(sub, quasiFlag);
        }
        sub.print(")");
    }
}



1.1                  e/src/jsrc/org/quasiliteral/term/Term.updoc

Index: Term.updoc
===================================================================
    ? def astro__uriGetter := <unsafe:org.quasiliteral.astro.*>
    # value: <unsafe:org.quasiliteral.astro.*>
    
    ? def TermTreeMaker := <astro:TermTree>
    # value: <unsafe:org.quasiliteral.astro.TermTree>
    
    ? def FunctorMaker := <astro:Functor>
    # value: <unsafe:org.quasiliteral.astro.Functor>
    
    ? def foo := FunctorMaker new("id", "foo$@`x", null)
    # value: id:"foo$@`x"
    
    ? def tree1 := TermTreeMaker new(foo, [])
    # value: ast`id:"foo$$@@``x"`
    
    ? def tree2 := TermTreeMaker new(foo, [tree1, tree1])
    # value: ast`id:"foo$$@@``x"(id:"foo$$@@``x", id:"foo$$@@``x")`
    
    ? def tree3 := TermTreeMaker new(foo, [tree2, tree1, tree2])
    # value: ast`id:"foo$$@@``x"(id:"foo$$@@``x"(id:"foo$$@@``x", id:"foo$$@@``x"),
    #                            id:"foo$$@@``x",
    #                            id:"foo$$@@``x"(id:"foo$$@@``x", id:"foo$$@@``x"))`
    
    ? def ast3 := tree3 asAST(["id" => 2])
    # value: foo$@`x
    
    ? def tree4 := TermTreeMaker fromAST(ast3, "file:what-me-worry.txt", ["huh?", "what", "wow", "zippy"])
    # value: ast`wow:"foo$$@@``x"(wow:"foo$$@@``x"(wow:"foo$$@@``x", wow:"foo$$@@``x"),
    #                             wow:"foo$$@@``x",
    #                             wow:"foo$$@@``x"(wow:"foo$$@@``x", wow:"foo$$@@``x"))`
    
    ?