Polished build process. Added CONS special form.
This commit is contained in:
parent
e6a608ee2b
commit
2c0e932f89
@ -1,28 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="Common Build Versioning" >
|
||||
<property name="cbv-basedir" value="nbproject" />
|
||||
<property name="cbv-basedir" value="${basedir}" />
|
||||
<property name="cbv-property-file" value="project.properties"/>
|
||||
|
||||
<target name="-cbv-init">
|
||||
<property file="${cbv-basedir}/project.versioning.properties" />
|
||||
<property file="${cbv-basedir}/${cbv-property-file}" />
|
||||
</target>
|
||||
|
||||
<target name="-pre-set-version" />
|
||||
<target name="-do-set-version">
|
||||
<input message="Current version is ${application.version}. Enter new version: " addproperty="new-version"/>
|
||||
<propertyfile file="${cbv-basedir}/project.versioning.properties">
|
||||
<propertyfile file="${cbv-basedir}/${cbv-property-file}">
|
||||
<entry key="application.version" value="${new-version}" />
|
||||
<entry key="build.number" value="0" />
|
||||
</propertyfile>
|
||||
<property file="${cbv-basedir}/project.versioning.properties" />
|
||||
<property file="${cbv-basedir}/${cbv-property-file}" />
|
||||
</target>
|
||||
<target name="-post-set-version" />
|
||||
<target name="set-version" depends="-cbv-init,-pre-set-version,-do-set-version,-post-set-version"/>
|
||||
|
||||
<target name="increment-build-number">
|
||||
<propertyfile file="${cbv-basedir}/project.versioning.properties">
|
||||
<propertyfile file="${cbv-basedir}/${cbv-property-file}">
|
||||
<entry key="build.number" operation="+" type="int" default="0"/>
|
||||
</propertyfile>
|
||||
<property file="${cbv-basedir}/project.versioning.properties" />
|
||||
<property file="${cbv-basedir}/${cbv-property-file}" />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
28
build.xml
28
build.xml
@ -12,7 +12,7 @@
|
||||
<!-- This path represents all run-time dependancies -->
|
||||
<path id="java.path">
|
||||
<path refid="javac.path"/>
|
||||
<pathelement path="${build.dir}"/>
|
||||
<pathelement path="${build.classes.dir}"/>
|
||||
</path>
|
||||
|
||||
<target name="init">
|
||||
@ -35,20 +35,38 @@
|
||||
|
||||
<target name="compile" depends="compile-parser">
|
||||
<!-- Make build directory if it does not exist -->
|
||||
<mkdir dir="${build.dir}"/>
|
||||
<mkdir dir="${build.classes.dir}"/>
|
||||
|
||||
<!-- Compile all sources to build directory -->
|
||||
<javac
|
||||
srcdir="${src.dir}"
|
||||
destdir="${build.dir}"
|
||||
destdir="${build.classes.dir}"
|
||||
classpathref="javac.path"
|
||||
debug="on"
|
||||
debuglevel="source,vars,lines"/>
|
||||
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="init,compile">
|
||||
<mkdir dir="${dist.dir}"/>
|
||||
<target name="build" depends="compile,increment-build-number">
|
||||
<jar
|
||||
basedir="${build.classes.dir}"
|
||||
destfile="${build.jar}">
|
||||
<manifest>
|
||||
<attribute
|
||||
name="Main-Class"
|
||||
value="edu.utexas.cs345.jdblisp.LISPRuntime"/>
|
||||
<attribute
|
||||
name="Built-By"
|
||||
value="Jonathan Bernard (jdbernard@gmail.com)"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="build">
|
||||
<mkdir dir="${dist.dir}/lib"/>
|
||||
<move file="${build.jar}" tofile="${dist.jar}" />
|
||||
<copy todir="${dist.dir}/lib">
|
||||
<fileset dir="${lib.dir}"/>
|
||||
</copy>
|
||||
</target>
|
||||
</project>
|
||||
|
@ -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
|
||||
|
46
src/edu/utexas/cs345/jdblisp/Cons.java
Normal file
46
src/edu/utexas/cs345/jdblisp/Cons.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -222,6 +222,41 @@ public abstract class SpecialFormEntry implements FormEntry {
|
||||
}
|
||||
};
|
||||
|
||||
// ----
|
||||
// CONS
|
||||
// ----
|
||||
|
||||
SpecialFormEntry CONS = new SpecialFormEntry(
|
||||
environment,
|
||||
new FormHelpTopic("CONS", "create a cons",
|
||||
"(cons <object-1> <object-2>) => <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 <plist> <indicator> [<default>]) => <value>",
|
||||
"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 <topic>)",
|
||||
"(help [<topic>*])",
|
||||
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<HelpTopic> topics = new ArrayList<HelpTopic>();
|
||||
|
||||
// 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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
15
src/edu/utexas/cs345/jdblisp/UndefinedFunctionException.java
Normal file
15
src/edu/utexas/cs345/jdblisp/UndefinedFunctionException.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
15
src/edu/utexas/cs345/jdblisp/UndefinedVariableException.java
Normal file
15
src/edu/utexas/cs345/jdblisp/UndefinedVariableException.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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))
|
||||
|
8
todo.txt
8
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
|
||||
--------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user