Reworked closure calculation. Added several special forms. Bug fixes. TypeUtil
Not completely happy with closure calculation, but satisfied. Added debug toString to SymbolTable Many additional changes, see diff.
This commit is contained in:
parent
7f288c0878
commit
2b45af2d9c
@ -1,13 +1,13 @@
|
|||||||
#Wed Nov 25 16:01:45 CST 2009
|
#Mon Nov 30 20:37:52 CST 2009
|
||||||
build.dir=build
|
build.dir=build
|
||||||
src.dir=src
|
src.dir=src
|
||||||
grammar.output.dir=${src.dir}/edu/utexas/cs345/jdblisp/parser
|
grammar.output.dir=${src.dir}/edu/utexas/cs345/jdblisp/parser
|
||||||
build.jar=${build.dir}/JCLisp-${application.version}.${build.number}.jar
|
build.jar=${build.dir}/JCLisp-${application.version}.${build.number}.jar
|
||||||
build.number=27
|
build.number=46
|
||||||
dist.dir=dist
|
dist.dir=dist
|
||||||
javacc.home=${lib.dir}/javacc
|
javacc.home=${lib.dir}/javacc
|
||||||
lib.dir=lib
|
|
||||||
dist.jar=${dist.dir}/JCLisp-${application.version}.jar
|
dist.jar=${dist.dir}/JCLisp-${application.version}.jar
|
||||||
build.classes.dir=${build.dir}/classes
|
lib.dir=lib
|
||||||
grammar.file=${src.dir}/edu/utexas/cs345/jdblisp/Parser.jj
|
grammar.file=${src.dir}/edu/utexas/cs345/jdblisp/Parser.jj
|
||||||
|
build.classes.dir=${build.dir}/classes
|
||||||
application.version=0.1.0
|
application.version=0.1.0
|
||||||
|
58
src/edu/utexas/cs345/jdblisp/ClosureSymbolTable.java
Normal file
58
src/edu/utexas/cs345/jdblisp/ClosureSymbolTable.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package edu.utexas.cs345.jdblisp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClosureSymbolTable
|
||||||
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
*/
|
||||||
|
public class ClosureSymbolTable extends SymbolTable {
|
||||||
|
|
||||||
|
private SymbolTable lexicalScope;
|
||||||
|
|
||||||
|
public ClosureSymbolTable(SymbolTable lexicalScope,
|
||||||
|
SymbolTable closedScope) {
|
||||||
|
super(closedScope);
|
||||||
|
this.lexicalScope = lexicalScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FormEntry lookupFunction(Symbol s) throws LispException {
|
||||||
|
|
||||||
|
// lookup function in the closed binding first
|
||||||
|
FormEntry fe = super.lookupFunction(s);
|
||||||
|
|
||||||
|
// lookup in the lexical scope if it is not found in the closure
|
||||||
|
if (fe == null && lexicalScope != null)
|
||||||
|
fe = lexicalScope.lookupFunction(s);
|
||||||
|
|
||||||
|
// return the result (may be null if not found anywhere)
|
||||||
|
return fe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a variable bound to the given
|
||||||
|
* {@link edu.utexas.cs345.jdblisp.Symbol}. The lookup is performed first
|
||||||
|
* in the closed scope and then the lexical scope if the variable is not
|
||||||
|
* found in the closed scope.
|
||||||
|
* @param s The symbol to lookup.
|
||||||
|
* @return The variable bound to the symbol, or <b>null</b> if the symbol
|
||||||
|
* is unbound.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public VariableEntry lookupVariable(Symbol s) throws LispException {
|
||||||
|
|
||||||
|
// lookup variable in the closed binding first
|
||||||
|
VariableEntry ve = super.lookupVariable(s);
|
||||||
|
|
||||||
|
// lookup in the lexical scope if it is not found in the closure
|
||||||
|
if (ve == null && lexicalScope != null)
|
||||||
|
ve = lexicalScope.lookupVariable(s);
|
||||||
|
|
||||||
|
// return the result (may be null if not found anywhere)
|
||||||
|
return ve;
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,13 @@ package edu.utexas.cs345.jdblisp;
|
|||||||
* FormEntry
|
* FormEntry
|
||||||
* @author Jonathan Bernard(jdbernard@gmail.com)
|
* @author Jonathan Bernard(jdbernard@gmail.com)
|
||||||
*/
|
*/
|
||||||
public abstract class FormEntry implements SExp {
|
public abstract class FormEntry implements SExp, SymbolTableEntry {
|
||||||
|
|
||||||
public final Symbol name;
|
public final Symbol symbol;
|
||||||
public HelpTopic helpinfo;
|
public HelpTopic helpinfo;
|
||||||
|
|
||||||
public FormEntry(Symbol name, HelpTopic helpinfo) {
|
public FormEntry(Symbol symbol, HelpTopic helpinfo) {
|
||||||
this.name = name;
|
this.symbol = symbol;
|
||||||
this.helpinfo = helpinfo;
|
this.helpinfo = helpinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,4 +19,5 @@ public abstract class FormEntry implements SExp {
|
|||||||
|
|
||||||
public SExp eval(SymbolTable symbolTable) { return this; }
|
public SExp eval(SymbolTable symbolTable) { return this; }
|
||||||
|
|
||||||
|
public Symbol symbol() { return symbol; }
|
||||||
}
|
}
|
||||||
|
@ -13,26 +13,26 @@ public class FunctionEntry extends FormEntry {
|
|||||||
|
|
||||||
//private Logger traceLog = Logger.getLogger(getClass());
|
//private Logger traceLog = Logger.getLogger(getClass());
|
||||||
|
|
||||||
public FunctionEntry(Symbol name, Symbol[] parameters, SExp body) {
|
public FunctionEntry(Symbol symbol, Symbol[] parameters, SExp body) {
|
||||||
super(name, null);
|
super(symbol, null);
|
||||||
|
|
||||||
// build invocation help string
|
// build invocation help string
|
||||||
String invokation = "(" + name.name;
|
String invokation = "(" + symbol.name;
|
||||||
for (Symbol param : parameters) invokation += " <" + param.name + ">";
|
for (Symbol param : parameters) invokation += " <" + param.name + ">";
|
||||||
invokation += ")";
|
invokation += ")";
|
||||||
String bodyInfo = "Function body: " + body.toString();
|
String bodyInfo = "Function body: " + body.toString();
|
||||||
|
|
||||||
// build help topic
|
// build help topic
|
||||||
FormHelpTopic helpinfo = new FormHelpTopic(name.name, null, invokation, bodyInfo);
|
FormHelpTopic helpinfo = new FormHelpTopic(symbol.name, null, invokation, bodyInfo);
|
||||||
|
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.helpinfo = helpinfo;
|
this.helpinfo = helpinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionEntry(Symbol name, Symbol[] parameters, SExp body,
|
public FunctionEntry(Symbol symbol, Symbol[] parameters, SExp body,
|
||||||
HelpTopic helpinfo) {
|
HelpTopic helpinfo) {
|
||||||
super(name, helpinfo);
|
super(symbol, helpinfo);
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
@ -42,10 +42,10 @@ public class FunctionEntry extends FormEntry {
|
|||||||
public void enableTrace(boolean enable) { this.traceEnabled = enable; }
|
public void enableTrace(boolean enable) { this.traceEnabled = enable; }
|
||||||
|
|
||||||
public String display(String offset) {
|
public String display(String offset) {
|
||||||
return offset + "Function: " + name.toString();
|
return offset + "Function: " + symbol.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() { return "<FUNCTION " + name.toString() + ">"; }
|
public String toString() { return "<FUNCTION " + symbol.toString() + ">"; }
|
||||||
|
|
||||||
public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException {
|
public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException {
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ public class FunctionEntry extends FormEntry {
|
|||||||
SExp evaluatedArg, retVal;
|
SExp evaluatedArg, retVal;
|
||||||
|
|
||||||
if (traceEnabled)
|
if (traceEnabled)
|
||||||
traceString = "(" + name.name;
|
traceString = "(" + symbol.name;
|
||||||
|
|
||||||
// bind arguments to parameters
|
// bind arguments to parameters
|
||||||
SymbolTable localScope = new SymbolTable(symbolTable);
|
SymbolTable localScope = new SymbolTable(symbolTable);
|
||||||
@ -63,11 +63,12 @@ public class FunctionEntry extends FormEntry {
|
|||||||
// too few arguments
|
// too few arguments
|
||||||
if (arguments == null)
|
if (arguments == null)
|
||||||
throw new InvalidArgumentQuantityException(
|
throw new InvalidArgumentQuantityException(
|
||||||
parameters.length, i);
|
toString(), parameters.length, i);
|
||||||
|
|
||||||
// bind one arg to param
|
// bind one arg to param
|
||||||
evaluatedArg = arguments.car.eval(symbolTable);
|
evaluatedArg = arguments.car.eval(symbolTable);
|
||||||
localScope.bind(parameters[i], new VariableEntry(evaluatedArg));
|
localScope.bind(parameters[i], new VariableEntry(parameters[i],
|
||||||
|
evaluatedArg));
|
||||||
|
|
||||||
if (traceEnabled) traceString += " " + evaluatedArg.toString();
|
if (traceEnabled) traceString += " " + evaluatedArg.toString();
|
||||||
|
|
||||||
@ -77,8 +78,8 @@ public class FunctionEntry extends FormEntry {
|
|||||||
|
|
||||||
// too many arguments
|
// too many arguments
|
||||||
if (arguments != null)
|
if (arguments != null)
|
||||||
throw new InvalidArgumentQuantityException(parameters.length,
|
throw new InvalidArgumentQuantityException(
|
||||||
(i + arguments.length()));
|
toString(),parameters.length, (i + arguments.length()));
|
||||||
|
|
||||||
if (traceEnabled) traceString += ")";
|
if (traceEnabled) traceString += ")";
|
||||||
if (traceEnabled) System.out.println(traceString);
|
if (traceEnabled) System.out.println(traceString);
|
||||||
@ -87,7 +88,7 @@ public class FunctionEntry extends FormEntry {
|
|||||||
retVal = body.eval(localScope);
|
retVal = body.eval(localScope);
|
||||||
|
|
||||||
if (traceEnabled)
|
if (traceEnabled)
|
||||||
traceString = name.name + " returned " + retVal.toString();
|
traceString = symbol.name + " returned " + retVal.toString();
|
||||||
if (traceEnabled) System.out.println(traceString);
|
if (traceEnabled) System.out.println(traceString);
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -7,16 +7,16 @@ package edu.utexas.cs345.jdblisp;
|
|||||||
*/
|
*/
|
||||||
public class InvalidArgumentQuantityException extends LispException {
|
public class InvalidArgumentQuantityException extends LispException {
|
||||||
|
|
||||||
public InvalidArgumentQuantityException(int expected, int actual) {
|
public InvalidArgumentQuantityException(String invokeName, int expected, int actual) {
|
||||||
super ("Invalid number of arguments: " + actual
|
super ("Invalid number of arguments to " + invokeName + ": " + actual
|
||||||
+ " (expected " + expected + ").");
|
+ " (expected " + expected + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvalidArgumentQuantityException(int actual) {
|
public InvalidArgumentQuantityException(String invokeName, int expected) {
|
||||||
super ("Invalid number of arguments: " + actual);
|
super ("Invalid number of arguments to " + invokeName + ": expected " + expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvalidArgumentQuantityException(String message) {
|
public InvalidArgumentQuantityException(String invokeName, String message) {
|
||||||
super ("Invalid number of arguments: " + message);
|
super ("Invalid number of arguments to " + invokeName + ": " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,9 +122,11 @@ public class LISPRuntime {
|
|||||||
void signalStop() { stop = true; }
|
void signalStop() { stop = true; }
|
||||||
|
|
||||||
private static SymbolTable defineGlobalConstants() {
|
private static SymbolTable defineGlobalConstants() {
|
||||||
|
Symbol T = new Symbol("T");
|
||||||
|
Symbol NIL = new Symbol("NIL");
|
||||||
SymbolTable constantsTable = new SymbolTable();
|
SymbolTable constantsTable = new SymbolTable();
|
||||||
constantsTable.bind(new Symbol("T"), new VariableEntry(SExp.T, true));
|
constantsTable.bind(T, new VariableEntry(T, SExp.T, true));
|
||||||
constantsTable.bind(new Symbol("NIL"), new VariableEntry(SExp.NIL, true));
|
constantsTable.bind(NIL, new VariableEntry(NIL, SExp.NIL, true));
|
||||||
|
|
||||||
return constantsTable;
|
return constantsTable;
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,14 @@ public class Lambda extends FunctionEntry {
|
|||||||
private SymbolTable closure;
|
private SymbolTable closure;
|
||||||
|
|
||||||
public Lambda(Symbol[] parameters, SExp body, SymbolTable closure) {
|
public Lambda(Symbol[] parameters, SExp body, SymbolTable closure) {
|
||||||
super(new Symbol(""), parameters, body);
|
super(new Symbol("L()"), parameters, body);
|
||||||
|
|
||||||
this.closure = closure;
|
this.closure = closure;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Lambda(Symbol[] parameters, SExp body, SymbolTable closure,
|
public Lambda(Symbol[] parameters, SExp body, SymbolTable closure,
|
||||||
HelpTopic helpinfo) {
|
HelpTopic helpinfo) {
|
||||||
super(new Symbol(""), parameters, body, helpinfo);
|
super(new Symbol("L()"), parameters, body, helpinfo);
|
||||||
|
|
||||||
this.closure = closure;
|
this.closure = closure;
|
||||||
}
|
}
|
||||||
@ -31,6 +31,7 @@ public class Lambda extends FunctionEntry {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("<LAMBDA (");
|
sb.append("<LAMBDA (");
|
||||||
@ -44,6 +45,8 @@ public class Lambda extends FunctionEntry {
|
|||||||
@Override
|
@Override
|
||||||
public SExp call(SymbolTable symbolTable, Seq arguments)
|
public SExp call(SymbolTable symbolTable, Seq arguments)
|
||||||
throws LispException {
|
throws LispException {
|
||||||
return super.call(closure, arguments);
|
return super.call(new ClosureSymbolTable(symbolTable, closure),
|
||||||
|
arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,10 @@ public class Num implements SExp, Comparable<Num> {
|
|||||||
return new Num(n.abs());
|
return new Num(n.abs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Num remainder(Num divisor) {
|
||||||
|
return new Num(n.remainder(divisor.n));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Num that) {
|
public int compareTo(Num that) {
|
||||||
return this.n.compareTo(that.n);
|
return this.n.compareTo(that.n);
|
||||||
|
@ -41,7 +41,7 @@ TOKEN : /* LITERALS & SYMBOLS */
|
|||||||
| < STRG: "\"" (~["\""])* "\"" >
|
| < STRG: "\"" (~["\""])* "\"" >
|
||||||
| < SYMB: (["A"-"Z", "a"-"z", "_", "+", "-", "*", "/", "=", ">", "<"])+
|
| < SYMB: (["A"-"Z", "a"-"z", "_", "+", "-", "*", "/", "=", ">", "<"])+
|
||||||
(["A"-"Z", "a"-"z", "0"-"9",
|
(["A"-"Z", "a"-"z", "0"-"9",
|
||||||
"_", "+", "-", "*", "/", "=", ">", "<"])? >
|
"_", "+", "-", "*", "/", "=", ">", "<"])* >
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,4 +26,5 @@ public interface SExp {
|
|||||||
public String display(String offset) { return offset + "NIL\n"; }
|
public String display(String offset) { return offset + "NIL\n"; }
|
||||||
public String toString() { return "NIL"; }
|
public String toString() { return "NIL"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,23 +6,47 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* SymbolTable
|
* SymbolTable
|
||||||
* @author Jonathan Bernard (jdbernard@gmail.com)
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
* A SymbolTable holds the bindings of function definitions and variables for
|
||||||
|
* a lexical scope. Functions and variables are maintained seperately, so you
|
||||||
|
* can have a variable and function with the same symbol.
|
||||||
*/
|
*/
|
||||||
public class SymbolTable {
|
public class SymbolTable {
|
||||||
|
|
||||||
private Map<Symbol, FormEntry> functions = new HashMap<Symbol, FormEntry>();
|
private Map<Symbol, FormEntry> functions = new HashMap<Symbol, FormEntry>();
|
||||||
private Map<Symbol, VariableEntry> variables = new HashMap<Symbol, VariableEntry>();
|
private Map<Symbol, VariableEntry> variables =
|
||||||
|
new HashMap<Symbol, VariableEntry>();
|
||||||
|
|
||||||
private SymbolTable enclosingTable;
|
private SymbolTable enclosingTable;
|
||||||
private boolean locked = false;
|
private boolean locked = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new, unlocked, and empty symbol table.
|
||||||
|
*/
|
||||||
public SymbolTable() { this(null, false); }
|
public SymbolTable() { this(null, false); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new unlocked SymbolTable enclosed by the given table.
|
||||||
|
* @param table The outer, enclosing table.
|
||||||
|
*/
|
||||||
public SymbolTable(SymbolTable table) { this(table, false); }
|
public SymbolTable(SymbolTable table) { this(table, false); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SymbolTable enclosed by the given table.
|
||||||
|
* @param table The outer, enclosing table.
|
||||||
|
* @param locked If this table is locked.
|
||||||
|
*/
|
||||||
public SymbolTable(SymbolTable table, boolean locked) {
|
public SymbolTable(SymbolTable table, boolean locked) {
|
||||||
this.enclosingTable = table;
|
this.enclosingTable = table;
|
||||||
this.locked = locked;
|
this.locked = locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a value to a (potentially new) function definition named by the
|
||||||
|
* {@link edu.utexas.cs345.jdblisp.Symbol} s.
|
||||||
|
* @param s The {@link edu.utexas.cs345.jdblisp.Symbol} to bind to.
|
||||||
|
* @param f The {@link edu.utexas.cs345.jdblisp.FormEntry} representing
|
||||||
|
* the function definition.
|
||||||
|
*/
|
||||||
public Symbol bind(Symbol s, FormEntry f) {
|
public Symbol bind(Symbol s, FormEntry f) {
|
||||||
if (functions.get(s) != null) {
|
if (functions.get(s) != null) {
|
||||||
// TODO: warning: function redefinition
|
// TODO: warning: function redefinition
|
||||||
@ -32,6 +56,13 @@ public class SymbolTable {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a value to a (potentially new) variable named by the
|
||||||
|
* {@link edu.utexas.cs345.jdblisp.Symbol} s.
|
||||||
|
* @param s The {@link edu.utexas.cs345.jdblisp.Symbol} to bind.
|
||||||
|
* @param c The {@link edu.utexas.cs345.jdblisp.VariableEntry} representing
|
||||||
|
* the value to bind.
|
||||||
|
*/
|
||||||
public Symbol bind(Symbol s, VariableEntry v) {
|
public Symbol bind(Symbol s, VariableEntry v) {
|
||||||
if (variables.get(s) != null) {
|
if (variables.get(s) != null) {
|
||||||
// TODO: warning: variable redefinition
|
// TODO: warning: variable redefinition
|
||||||
@ -42,6 +73,15 @@ public class SymbolTable {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a new value to an existing variable named by the
|
||||||
|
* {@link edu.utexas.cs345.jdblisp.Symbol} s.
|
||||||
|
* @param s The {@link edu.utexas.cs345.jdblisp.Symbol} to bind.
|
||||||
|
* @param v The {@link edu.utexas.cs345.jdblisp.VariableEntry} representing
|
||||||
|
* the new value to bind.
|
||||||
|
* @throws edu.utexas.cs345.jdblisp.LispException if the variable is not
|
||||||
|
* defined or if the variable was defined as a constant.
|
||||||
|
*/
|
||||||
public Symbol rebind(Symbol s, VariableEntry v) throws LispException {
|
public Symbol rebind(Symbol s, VariableEntry v) throws LispException {
|
||||||
|
|
||||||
// look up the variable in the current table
|
// look up the variable in the current table
|
||||||
@ -74,6 +114,12 @@ public class SymbolTable {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a function definition in this symbol table.
|
||||||
|
* @param s The symbol representing the function in question.
|
||||||
|
* @return The function definiton of the function bound to the Symbol s
|
||||||
|
* or <b>null</b> if there is no function bound to the symbol.
|
||||||
|
*/
|
||||||
public FormEntry lookupFunction(Symbol s) throws LispException {
|
public FormEntry lookupFunction(Symbol s) throws LispException {
|
||||||
FormEntry fe = functions.get(s);
|
FormEntry fe = functions.get(s);
|
||||||
|
|
||||||
@ -87,6 +133,12 @@ public class SymbolTable {
|
|||||||
return enclosingTable.lookupFunction(s);
|
return enclosingTable.lookupFunction(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a variable definition in this symbol table.
|
||||||
|
* @param s The symbol representing the variable.
|
||||||
|
* @return The variable entry for the given symbol or <b>null</b> if there
|
||||||
|
* is no variable bound to the symbol.
|
||||||
|
*/
|
||||||
public VariableEntry lookupVariable(Symbol s) throws LispException {
|
public VariableEntry lookupVariable(Symbol s) throws LispException {
|
||||||
VariableEntry ve = variables.get(s);
|
VariableEntry ve = variables.get(s);
|
||||||
|
|
||||||
@ -100,4 +152,31 @@ public class SymbolTable {
|
|||||||
return enclosingTable.lookupVariable(s);
|
return enclosingTable.lookupVariable(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEBUG ONLY: traverses the entire scope history.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return toString("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toString(String enclosedTable) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{").append(enclosedTable).append("} V: ");
|
||||||
|
|
||||||
|
for (VariableEntry ve : variables.values())
|
||||||
|
sb.append(ve.symbol.toString()).append("=")
|
||||||
|
.append(ve.value.toString()).append(" ");
|
||||||
|
|
||||||
|
sb.append("F: ");
|
||||||
|
|
||||||
|
for (FormEntry fe : functions.values())
|
||||||
|
sb.append(fe.symbol.toString()).append("=")
|
||||||
|
.append(fe.toString()).append(" ");
|
||||||
|
|
||||||
|
sb.append("}");
|
||||||
|
|
||||||
|
if (enclosingTable == null) return sb.toString();
|
||||||
|
|
||||||
|
return enclosingTable.toString(sb.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
5
src/edu/utexas/cs345/jdblisp/SymbolTableEntry.java
Normal file
5
src/edu/utexas/cs345/jdblisp/SymbolTableEntry.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package edu.utexas.cs345.jdblisp;
|
||||||
|
|
||||||
|
public interface SymbolTableEntry {
|
||||||
|
Symbol symbol();
|
||||||
|
}
|
24
src/edu/utexas/cs345/jdblisp/TypeUtil.java
Normal file
24
src/edu/utexas/cs345/jdblisp/TypeUtil.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package edu.utexas.cs345.jdblisp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TypeUtil
|
||||||
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
|
*/
|
||||||
|
public class TypeUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to perform a LISP type conversion and create an appropriate
|
||||||
|
* error if the type conversion fails.
|
||||||
|
* @param desiredClass The class to cast to.
|
||||||
|
* @param value The value to cast.
|
||||||
|
* @return The value cast to the desired class.
|
||||||
|
* @throws {@link edu.utexas.cs345.jdblisp.TypeException} if the cast fails.
|
||||||
|
*/
|
||||||
|
static <T extends SExp> T attemptCast(Class<T> desiredClass, SExp value)
|
||||||
|
throws TypeException {
|
||||||
|
try { return desiredClass.cast(value); }
|
||||||
|
catch (ClassCastException cce) {
|
||||||
|
throw new TypeException(value, desiredClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,22 +4,29 @@ package edu.utexas.cs345.jdblisp;
|
|||||||
* VariableEntry
|
* VariableEntry
|
||||||
* @author Jonathan Bernard (jdbernard@gmail.com)
|
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||||
*/
|
*/
|
||||||
public class VariableEntry {
|
public class VariableEntry implements SymbolTableEntry {
|
||||||
|
|
||||||
|
public final Symbol symbol;
|
||||||
public final SExp value;
|
public final SExp value;
|
||||||
public final boolean isConstant;
|
public final boolean isConstant;
|
||||||
public final HelpTopic helpinfo;
|
public final HelpTopic helpinfo;
|
||||||
|
|
||||||
public VariableEntry(SExp value) { this(value, false); }
|
public VariableEntry(Symbol symbol, SExp value) {
|
||||||
|
this(symbol, value, false);
|
||||||
public VariableEntry(SExp value, boolean constant) {
|
|
||||||
this(value, constant, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableEntry(SExp value, boolean constant, HelpTopic helpinfo) {
|
public VariableEntry(Symbol symbol, SExp value, boolean constant) {
|
||||||
|
this(symbol, value, constant, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableEntry(Symbol symbol, SExp value, boolean constant,
|
||||||
|
HelpTopic helpinfo) {
|
||||||
|
this.symbol = symbol;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.isConstant = constant;
|
this.isConstant = constant;
|
||||||
this.helpinfo = helpinfo;
|
this.helpinfo = helpinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Symbol symbol() { return symbol; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
|
;;; - TEST NUMERIC COMPARISONS
|
||||||
|
|
||||||
|
(defvar one 1)
|
||||||
|
|
||||||
|
(defvar two 2)
|
||||||
|
|
||||||
(<= 1 1 2 3 5 8 13) ; => T
|
(<= 1 1 2 3 5 8 13) ; => T
|
||||||
|
|
||||||
(<= 1 2 3 4) ; => T
|
(<= 1 2 3 4) ; => T
|
||||||
|
|
||||||
|
(<= one one two) ; => T
|
||||||
|
|
||||||
|
(<= one two ((lambda (x) (+ x 2)) one)) ; => T
|
||||||
|
|
||||||
(<= 1 2 3 2) ; => NIL
|
(<= 1 2 3 2) ; => NIL
|
||||||
|
|
||||||
(<= 1 "Hi") ; => TYPE-ERROR
|
(<= 1 "Hi") ; => TYPE-ERROR
|
||||||
@ -16,6 +26,10 @@
|
|||||||
|
|
||||||
(< 1 3) ; => T
|
(< 1 3) ; => T
|
||||||
|
|
||||||
|
(< one two) ; => T
|
||||||
|
|
||||||
|
(< one two ((lambda (x) (+ x 2)) one)) ; => T
|
||||||
|
|
||||||
(< 2 1) ; => NIL
|
(< 2 1) ; => NIL
|
||||||
|
|
||||||
(< 1 "hi") ; type error
|
(< 1 "hi") ; type error
|
||||||
@ -24,6 +38,10 @@
|
|||||||
|
|
||||||
(= 1 1) ; => T
|
(= 1 1) ; => T
|
||||||
|
|
||||||
|
(= one one) ; => T
|
||||||
|
|
||||||
|
(= two ((lambda (x) (+ x 2)) 0)) ; => T
|
||||||
|
|
||||||
(= 1.0 -1.0) ; => NIL
|
(= 1.0 -1.0) ; => NIL
|
||||||
|
|
||||||
(= 0.0 -0.0) ; => T
|
(= 0.0 -0.0) ; => T
|
||||||
@ -31,3 +49,173 @@
|
|||||||
(= 1 2) ; => NIL
|
(= 1 2) ; => NIL
|
||||||
|
|
||||||
(= 7 7 7) ; => T
|
(= 7 7 7) ; => T
|
||||||
|
|
||||||
|
(> 3 2 1) ; => T
|
||||||
|
|
||||||
|
(> 14 10) ; => T
|
||||||
|
|
||||||
|
(> two one) ; => T
|
||||||
|
|
||||||
|
(> two one ((lambda (x) (- x 2)) one)) ; => T
|
||||||
|
|
||||||
|
(> 10 14) ; => NIL
|
||||||
|
|
||||||
|
(> 1 2 3) ; => NIL
|
||||||
|
|
||||||
|
(> 8 7 6 4 5 3 2) ; => NIL
|
||||||
|
|
||||||
|
(> 5 "hi") ; type error
|
||||||
|
|
||||||
|
(>) ; not enough args
|
||||||
|
|
||||||
|
(>= 7 7 7) ; => T
|
||||||
|
|
||||||
|
(>= 8 6 4 2 2 1) ; => T
|
||||||
|
|
||||||
|
(>= 2 1) ; => T
|
||||||
|
|
||||||
|
(>= two two one one) ; => T
|
||||||
|
|
||||||
|
(>= two ((lambda (x) (+ x 1)) one) one) ; => T
|
||||||
|
|
||||||
|
(>= 8 6 4 2 3 1) ; => NIL
|
||||||
|
|
||||||
|
(>= 3 5) ; => NIL
|
||||||
|
|
||||||
|
(>= 3 "hi") ; type error
|
||||||
|
|
||||||
|
(>=) ; not enough args
|
||||||
|
|
||||||
|
;;; - TEST NUMERIC OPERATIONS
|
||||||
|
|
||||||
|
(+) ; => 0
|
||||||
|
|
||||||
|
(+ 5) ; => 5
|
||||||
|
|
||||||
|
(+ 1 5) ; => 6
|
||||||
|
|
||||||
|
(+ 30.05 0.7 1.25) ; => 32
|
||||||
|
|
||||||
|
(+ one two) ; => 3
|
||||||
|
|
||||||
|
(+ 5 "hi") ; => error: type
|
||||||
|
|
||||||
|
(-) ; => error: arg #
|
||||||
|
|
||||||
|
(- 5) ; => -5
|
||||||
|
|
||||||
|
(- 7 2) ; => 5
|
||||||
|
|
||||||
|
(- 2 7) ; => -5
|
||||||
|
|
||||||
|
(- 25 3 4 5 6 7) ; => 0
|
||||||
|
|
||||||
|
(- 100 75.4 24.6) ; => 0
|
||||||
|
|
||||||
|
(- two one one one) ; => -1
|
||||||
|
|
||||||
|
(*) ; => 1
|
||||||
|
|
||||||
|
(* 5) ; => 5
|
||||||
|
|
||||||
|
(* 1 5) ; => 5
|
||||||
|
|
||||||
|
(* 5 5) ; => 25
|
||||||
|
|
||||||
|
(* two two) ; => 4
|
||||||
|
|
||||||
|
(* 2 3 4) ; => 24
|
||||||
|
|
||||||
|
(* -23 43) ; => -989
|
||||||
|
|
||||||
|
(* 5 "hi") ; => error: type
|
||||||
|
|
||||||
|
(/) ; => error: arg #
|
||||||
|
|
||||||
|
(/ 5) ; => 0.2
|
||||||
|
|
||||||
|
(/ 10 2) ; => 5
|
||||||
|
|
||||||
|
(/ two one) ; => 2
|
||||||
|
|
||||||
|
(/ 100 5 2) ; => 10
|
||||||
|
|
||||||
|
;; (/ 33 3) ; => 11
|
||||||
|
|
||||||
|
;;; - TEST LAMBDAs
|
||||||
|
|
||||||
|
(defvar sq (lambda (x) (* x x))) ; => SQ
|
||||||
|
|
||||||
|
sq ; => <LAMBDA (X) >
|
||||||
|
|
||||||
|
(funcall sq 5) ; => 25
|
||||||
|
|
||||||
|
#'sq ; => undefined function SQ
|
||||||
|
|
||||||
|
(sq 5) ; => undefined function SQ
|
||||||
|
|
||||||
|
((lambda (x) (funcall sq x)) 6) ; => 36
|
||||||
|
|
||||||
|
;; - test persistent values of lexical closure
|
||||||
|
(let* ((x 2) (sqx (lambda () (setq x (* x x)))))
|
||||||
|
(funcall sqx) ; local x = 4 after this call
|
||||||
|
(defparameter *sqx* sqx))
|
||||||
|
|
||||||
|
(funcall *sqx*) ; => 16
|
||||||
|
|
||||||
|
;; - check binding (the lexical closure overrides the calling context)
|
||||||
|
(let ((x 1)) (funcall *sqx*)) ; warning, x defined but unsed => 256
|
||||||
|
|
||||||
|
;; - check binding (the lexical closure includes non-local variables)
|
||||||
|
(let ((x 1))
|
||||||
|
(let ((y 2)) (defparameter *sqy* (lambda () (setq x (* x x))))))
|
||||||
|
|
||||||
|
(funcall *sqy*) ; => 1
|
||||||
|
|
||||||
|
(let ((x 2)) (funcall *sqy*)) ; => 1
|
||||||
|
|
||||||
|
;; - check binding (the lexical closue does NOT include unreferenced variables)
|
||||||
|
(let ((a 50) (b 60) (c 7))
|
||||||
|
(defparameter *sqz* (lambda (fun2arg) (+ c (funcall fun2arg))))) ; => *SQZ*
|
||||||
|
|
||||||
|
(let ((a 0) (b 0) (c 0))
|
||||||
|
(funcall *sqz* (lambda () (+ a b)))) ; => 7
|
||||||
|
|
||||||
|
;; - check binding (the lexical closure includes function definitions)
|
||||||
|
(defparameter funlam
|
||||||
|
(let ((x 5))
|
||||||
|
(defun f1 (i) (+ i 1))
|
||||||
|
(lambda () (f1 x)))) ; => FUNLAM
|
||||||
|
|
||||||
|
|
||||||
|
(funcall funlam) ; => 6
|
||||||
|
|
||||||
|
;;; SAMPLE ALGORITHMS
|
||||||
|
|
||||||
|
(defun factorial (n) (if (<= n 1)
|
||||||
|
1
|
||||||
|
(+
|
||||||
|
(factorial (- n 1))
|
||||||
|
(factorial (- n 2)))))
|
||||||
|
|
||||||
|
(factorial 0) ; => 1
|
||||||
|
|
||||||
|
(factorial 1) ; => 1
|
||||||
|
|
||||||
|
(factorial 2) ; => 2
|
||||||
|
|
||||||
|
(factorial 3) ; => 3
|
||||||
|
|
||||||
|
(factorial 4) ; => 5
|
||||||
|
|
||||||
|
(factorial 5) ; => 8
|
||||||
|
|
||||||
|
(factorial 6) ; => 13
|
||||||
|
|
||||||
|
(factorial 20) ; => 10946
|
||||||
|
|
||||||
|
(defun collatz (n) (if (= n 1)
|
||||||
|
1
|
||||||
|
(if (= 0 (mod n 2))
|
||||||
|
(+ 1 (collatz (/ n 2)))
|
||||||
|
(+ 1 (collatz (+ (* n 3) 1))))))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user