diff --git a/build-common-versioning.xml b/build-common-versioning.xml
index 2f39d52..cda1f29 100755
--- a/build-common-versioning.xml
+++ b/build-common-versioning.xml
@@ -1,28 +1,29 @@
-
+
+
-
+
-
+
-
+
-
+
-
+
diff --git a/build.xml b/build.xml
index ffff82c..728878c 100755
--- a/build.xml
+++ b/build.xml
@@ -12,7 +12,7 @@
-
+
@@ -35,20 +35,38 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project.properties b/project.properties
index f8fa2f6..1b2dac9 100755
--- a/project.properties
+++ b/project.properties
@@ -1,7 +1,12 @@
-src.dir=src
+#Tue Nov 24 11:54:14 CST 2009
build.dir=build
+src.dir=src
+grammar.output.dir=${src.dir}/edu/utexas/cs345/jdblisp/parser
+build.jar=${build.dir}/JCLisp-${application.version}.${build.number}.jar
+build.number=6
dist.dir=dist
+dist.jar=${dist.dir}/JCLisp-${application.version}.jar
lib.dir=lib
grammar.file=${src.dir}/edu/utexas/cs345/jdblisp/Parser.jj
-grammar.output.dir=${src.dir}/edu/utexas/cs345/jdblisp/parser
-project.version=0.1.0
+build.classes.dir=${build.dir}/classes
+application.version=0.1.0
diff --git a/src/edu/utexas/cs345/jdblisp/Cons.java b/src/edu/utexas/cs345/jdblisp/Cons.java
new file mode 100644
index 0000000..f950903
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/Cons.java
@@ -0,0 +1,46 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * Cons
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class Cons extends Seq {
+
+ public final SExp cdr;
+
+ public Cons(SExp car, SExp cdr) {
+ super(car, (cdr == null ||
+ cdr == SExp.NIL ||
+ !(cdr instanceof Seq) ?
+ null : (Seq) cdr));
+ this.cdr = (cdr == SExp.NIL ? null : cdr);
+ }
+
+ public Cons(SExp car, List list) {
+ super(car, list.seq);
+ this.cdr = list.seq;
+ }
+
+ @Override
+ public String display(String offset) {
+ if (this.cdr == super.cdr)
+ return super.display(offset);
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(offset);
+ sb.append("Cons: \n");
+
+ sb.append(car.display(offset + " "));
+
+ if (cdr != null) sb.append(cdr.display(offset));
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ if (this.cdr == super.cdr) return super.toString();
+
+ else return car.toString() + " . " + cdr.toString();
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/HelpTopic.java b/src/edu/utexas/cs345/jdblisp/HelpTopic.java
index 58d4adf..fb06566 100644
--- a/src/edu/utexas/cs345/jdblisp/HelpTopic.java
+++ b/src/edu/utexas/cs345/jdblisp/HelpTopic.java
@@ -94,7 +94,7 @@ public class HelpTopic {
}
// any left over, it will fit on one line
- if (i - lineStartIdx > 1) {
+ if (i - lineStartIdx > 0) {
String lastLine = message.substring(lineStartIdx);
printer.print(lastLine);
curLineLength += lastLine.length();
diff --git a/src/edu/utexas/cs345/jdblisp/List.java b/src/edu/utexas/cs345/jdblisp/List.java
index 8363826..09015c0 100755
--- a/src/edu/utexas/cs345/jdblisp/List.java
+++ b/src/edu/utexas/cs345/jdblisp/List.java
@@ -30,7 +30,12 @@ public class List implements SExp {
// look up in the symbol table
FormEntry functionEntry = table.lookupFunction((Symbol) seq.car);
- // call function
+ // throw an eror if it is not defined
+ if (functionEntry == null)
+ throw new LispException("Undefined function "
+ + ((Symbol) seq.car).name);
+
+ // call function if it is
return functionEntry.call(table, seq.cdr);
}
diff --git a/src/edu/utexas/cs345/jdblisp/Seq.java b/src/edu/utexas/cs345/jdblisp/Seq.java
index 5f7fdd9..2239416 100755
--- a/src/edu/utexas/cs345/jdblisp/Seq.java
+++ b/src/edu/utexas/cs345/jdblisp/Seq.java
@@ -35,6 +35,7 @@ public class Seq implements SExp {
return 1 + cdr.length();
}
+ @Override
public String display(String offset) {
StringBuilder sb = new StringBuilder();
sb.append(offset);
diff --git a/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java b/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java
index 8a47710..69a6502 100755
--- a/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java
+++ b/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java
@@ -222,6 +222,41 @@ public abstract class SpecialFormEntry implements FormEntry {
}
};
+ // ----
+ // CONS
+ // ----
+
+ SpecialFormEntry CONS = new SpecialFormEntry(
+ environment,
+ new FormHelpTopic("CONS", "create a cons",
+ "(cons ) => ",
+ "Creates a fresh cons, the car of which is object-1 and the "
+ + "cdr of which is object-2.",
+ "object-1", "an object",
+ "object-2", "an object",
+ "cons", "a cons"))
+ {
+ public SExp call(SymbolTable symbolTable, Seq arguments)
+ throws LispException {
+
+ SExp object1, object2;
+ Cons cons;
+
+ if (arguments.length() != 2)
+ throw new InvalidArgumentQuantityException(2,
+ arguments.length());
+
+ // get the two objects
+ object1 = arguments.car.eval(symbolTable);
+ object2 = arguments.cdr.car.eval(symbolTable);
+
+ if (object2 instanceof List) cons = new Cons(object1, (List) object2);
+ else cons = new Cons(object1, object2);
+
+ return new List(cons);
+ }
+ };
+
// -----
// DEFUN
// -----
@@ -326,17 +361,18 @@ public abstract class SpecialFormEntry implements FormEntry {
// second argument: initial value
arguments = arguments.cdr;
- if (arguments != null)
+ if (arguments != null) {
initValue = arguments.car.eval(symbolTable);
- // thrid argument: documentation
- arguments = arguments.cdr;
- if (arguments != null) {
- if (!(arguments.car instanceof Str))
- throw new TypeException(arguments.car, Str.class);
+ // third argument: documentation
+ arguments = arguments.cdr;
+ if (arguments != null) {
+ if (!(arguments.car instanceof Str))
+ throw new TypeException(arguments.car, Str.class);
- helpinfo = new HelpTopic(name.name, "variable",
- ((Str) arguments.car).value);
+ helpinfo = new HelpTopic(name.toString(), "variable",
+ ((Str) arguments.car).value);
+ }
}
symbolTable.bind(name,
@@ -421,6 +457,69 @@ public abstract class SpecialFormEntry implements FormEntry {
}
};
+ // ----
+ // GETF
+ // ----
+
+ SpecialFormEntry GETF = new SpecialFormEntry(
+ environment,
+ new FormHelpTopic("GETF", "",
+ "(getf []) => ",
+ "getf finds a property on the plist whose property indicator "
+ + "is identical to indicator, and returns its "
+ + "corresponding property value. If there are multiple "
+ + "properties with that property indicator, getf uses the "
+ + "first such property. If there is no property with that "
+ + "property indicator, default is returned.",
+ "plist", "a property list.",
+ "indicator", "an object",
+ "default", "an object. The default is NIL",
+ "value", "an object"))
+ {
+ public SExp call(SymbolTable symbolTable, Seq arguments)
+ throws LispException {
+
+ SExp plistEval;
+ Seq plistSeq;
+ SExp indicator;
+ SExp retVal = SExp.NIL;
+
+ // check number of arguments
+ if (arguments.length() < 2)
+ throw new InvalidArgumentQuantityException(
+ "form requires at least 2 arguments.");
+
+ // first argument: property list
+ plistEval = arguments.car.eval(symbolTable);
+ if (!(plistEval instanceof List))
+ throw new TypeException(arguments.car, List.class);
+
+ plistSeq = ((List) plistEval).seq;
+
+ // second argument: indicator
+ arguments = arguments.cdr;
+ indicator = arguments.car.eval(symbolTable);
+
+ // third argument: default value
+ arguments = arguments.cdr;
+ if (arguments != null)
+ retVal = arguments.car.eval(symbolTable);
+
+ while(plistSeq != null) {
+
+ // check this value for equality
+ if (plistSeq.car.equals(indicator))
+ if (plistSeq.cdr != null)
+ return plistSeq.cdr.car;
+
+ // advance to the next pair (or terminate)
+ plistSeq = (plistSeq.cdr == null ? null : plistSeq.cdr.cdr);
+ }
+
+ return retVal;
+ }
+ };
+
// ----
// HELP
// ----
@@ -429,48 +528,45 @@ public abstract class SpecialFormEntry implements FormEntry {
environment,
new FormHelpTopic("HELP",
"Display online help information for a topic.",
- "(help )",
+ "(help [*])",
null,
"topic",
- "either a string representing the topic to lookup or a symbol"))
+ "either a string representing the topic to lookup or a symbol"))
{
public SExp call(SymbolTable symbolTable, Seq arguments)
throws LispException {
- HelpTopic topic = null;
+ ArrayList topics = new ArrayList();
// no arguments: print help for HELP
if (arguments == null)
return this.call(symbolTable,
new Seq(new Symbol("HELP"), null));
- // too many arguments
- if (arguments.length() > 1)
- throw new InvalidArgumentQuantityException(1,
- arguments.length());
+ while (arguments != null) {
+ // try to find the topic or function help
+ if (arguments.car instanceof Str) {
+ topics.add(HelpTopic.helpTopics.get(
+ ((Str) arguments.car).value));
+ } else if (arguments.car instanceof Symbol) {
- // try to find the topic or function help
- if (arguments.car instanceof Str) {
- topic = HelpTopic.helpTopics.get(
- ((Str) arguments.car).value);
- } else if (arguments.car instanceof Symbol) {
- try {
+ // lookup help for funtion
FormEntry fe = symbolTable.lookupFunction(
(Symbol) arguments.car);
- topic = fe.helpinfo();
- } catch (LispException le) { topic = null; }
+ if (fe != null) topics.add(fe.helpinfo());
+
+ // lookup help for variable
+ VariableEntry ve = symbolTable.lookupVariable(
+ (Symbol) arguments.car);
+ if (ve != null) topics.add(ve.helpinfo);
+ }
+
+ arguments = arguments.cdr;
}
- // no topic found
- if (topic == null) {
- new PrintWriter(environment.getOutputStream(), true)
- .println(
- "No help information found for topic '"
- + arguments.car.toString() + "'.");
- return SExp.NIL;
- }
+ for (HelpTopic topic : topics)
+ topic.print(environment.getOutputStream());
- topic.print(environment.getOutputStream());
return SExp.NIL;
}
};
@@ -866,7 +962,13 @@ public abstract class SpecialFormEntry implements FormEntry {
FormEntry fe = symbolTable.lookupFunction((Symbol) arguments.car);
- if (fe instanceof FunctionEntry) ((FunctionEntry) fe).enableTrace(true);
+ if (fe == null)
+ throw new UndefinedFunctionException(
+ ((Symbol) arguments.car));
+
+ if (fe instanceof FunctionEntry)
+ ((FunctionEntry) fe).enableTrace(true);
+
// TODO: else throw error
return SExp.NIL;
@@ -877,9 +979,12 @@ public abstract class SpecialFormEntry implements FormEntry {
environment.globalSymbolTable.bind(new Symbol("/"), DIV);
environment.globalSymbolTable.bind(new Symbol("*"), MUL);
environment.globalSymbolTable.bind(new Symbol("+"), SUM);
+ environment.globalSymbolTable.bind(new Symbol("CONS"), CONS);
environment.globalSymbolTable.bind(new Symbol("DEFUN"), DEFUN);
+ environment.globalSymbolTable.bind(new Symbol("DEFPARAMETER"), DEFPARAMETER);
environment.globalSymbolTable.bind(new Symbol("DEFVAR"), DEFVAR);
environment.globalSymbolTable.bind(new Symbol("ENABLE-DEBUG-AST"), ENABLEDEBUGAST);
+ environment.globalSymbolTable.bind(new Symbol("GETF"), GETF);
environment.globalSymbolTable.bind(new Symbol("HELP"), HELP);
environment.globalSymbolTable.bind(new Symbol("IF"), IF);
environment.globalSymbolTable.bind(new Symbol("LET"), LET);
diff --git a/src/edu/utexas/cs345/jdblisp/Symbol.java b/src/edu/utexas/cs345/jdblisp/Symbol.java
index 6049eaf..f5be9b5 100755
--- a/src/edu/utexas/cs345/jdblisp/Symbol.java
+++ b/src/edu/utexas/cs345/jdblisp/Symbol.java
@@ -10,7 +10,12 @@ public class Symbol implements SExp {
/** {@inheritdoc}*/
public SExp eval(SymbolTable table) throws LispException {
+ // lookup value in the symbol table
VariableEntry ve = table.lookupVariable(this);
+
+ // err if not defined
+ if (ve == null) throw new UndefinedVariableException(this);
+
return ve.value;
}
diff --git a/src/edu/utexas/cs345/jdblisp/SymbolTable.java b/src/edu/utexas/cs345/jdblisp/SymbolTable.java
index d5f3972..353b0ee 100755
--- a/src/edu/utexas/cs345/jdblisp/SymbolTable.java
+++ b/src/edu/utexas/cs345/jdblisp/SymbolTable.java
@@ -81,8 +81,7 @@ public class SymbolTable {
if (fe != null) return fe;
// did not find function, and there is no outer scope
- if (enclosingTable == null)
- throw new LispException("Undefined function " + s.toString());
+ if (enclosingTable == null) return null;
// search outer scope
return enclosingTable.lookupFunction(s);
@@ -95,8 +94,7 @@ public class SymbolTable {
if (ve != null) return ve;
// did not find variable entry and there is no outer scope
- if (enclosingTable == null)
- throw new LispException("Undefined variable " + s.toString());
+ if (enclosingTable == null) return null;
// search outer scope
return enclosingTable.lookupVariable(s);
diff --git a/src/edu/utexas/cs345/jdblisp/UndefinedFunctionException.java b/src/edu/utexas/cs345/jdblisp/UndefinedFunctionException.java
new file mode 100644
index 0000000..43fb5e4
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/UndefinedFunctionException.java
@@ -0,0 +1,15 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * UndefinedFunctionException
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class UndefinedFunctionException extends LispException {
+
+ Symbol symbol;
+
+ public UndefinedFunctionException(Symbol symbol) {
+ super("Undefined function: " + symbol.toString());
+ this.symbol = symbol;
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/UndefinedVariableException.java b/src/edu/utexas/cs345/jdblisp/UndefinedVariableException.java
new file mode 100644
index 0000000..f565de2
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/UndefinedVariableException.java
@@ -0,0 +1,15 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * UndefinedVariableException
+ * @author Jonathan Bernard
+ */
+public class UndefinedVariableException extends LispException {
+
+ public final Symbol symbol;
+
+ public UndefinedVariableException(Symbol symbol) {
+ super("Undefined variable: " + symbol.toString());
+ this.symbol = symbol;
+ }
+}
diff --git a/src/lisp-samples/cd-database.lisp b/src/lisp-samples/cd-database.lisp
index 7be3aa2..558bb3c 100644
--- a/src/lisp-samples/cd-database.lisp
+++ b/src/lisp-samples/cd-database.lisp
@@ -1,7 +1,10 @@
(defun make-cd (title artist rating ripped)
- (list title artist rating ripped))
-
-(make-cd "Roses" "Kathy Mattea" 7 t)
+ (list :title title :artist artist :rating rating :ripped ripped))
(defvar *db* nil)
+(defun add-record (cd) (setq *db* (cons cd *db*)))
+
+(add-record (make-cd "Roses" "Kathy Mattea" 7 t))
+(add-record (make-cd "Fly" "Dixie Chicks" 8 t))
+(add-record (make-cd "Home" "Dixie Chicks" 9 t))
diff --git a/todo.txt b/todo.txt
index 175e5b1..9bb204b 100644
--- a/todo.txt
+++ b/todo.txt
@@ -2,12 +2,20 @@ Outstanding
-----------
- Implement FORMAT
+ - Implement GETF
- Implement lambdas
- Implement LIST*
- Implement macros
- Implement packages
- Implement READ and PRINT
+ - Implement SETF
- Redefine DEFUN as a macro
+ - Help for property list
+ - Help for keyword
+ - Help for symbol
+ - Help for sexp
+ - Help for number
+ - Help for string
Partially Done
--------------