Continued work on List.eval, general function/macro/special form invocation.

This commit is contained in:
Jonathan Bernard 2009-11-20 06:19:03 -06:00
parent 1595ae1921
commit adc5b2d250
7 changed files with 144 additions and 27 deletions

View File

@ -9,8 +9,35 @@ public class FunctionEntry {
protected final Symbol[] parameters;
protected final SExp body;
public SExp call(SymbolTable symbolTable, Seq seq) {
// TODO
return null;
public FunctionEntry(Symbol[] parameters, SExp body) {
this.parameters = parameters;
this.body = body;
}
public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException {
// bind arguments to parameters
SymbolTable localScope = new SymbolTable(symbolTable);
int i = 0
while (i < parameters.length) {
// too few arguments
if (arguments == null)
throw new InvalidArgumentQuantityException(
parameters.length, i);
// bind one arg to param
localScope.bind(parameters[i], new VariableEntry(arguments.car));
arguments = arguments.cdr;
++i;
}
// too many arguments
if (arguments != null)
throw new InvalidArgumentQuantityException(parameters.length,
(i + arguments.length()));
return body.eval(localScope);
}
}

View File

@ -0,0 +1,13 @@
package edu.utexas.cs345.jdb-lisp;
/**
* InvalidArgumentQuantityException
* Indicates a call to a form with an incorrect number of arguments.
*/
public class InvalidArgumentQuantityException extends LispException {
public InvalidArgumentQuantityException(int expected, int actual) {
super ("Invalid number of arguments: " + actual
+ " (expected " + expected + ").");
}
}

View File

@ -14,8 +14,9 @@ import edu.utexas.cs345.jdblisp.parser.ParseException;
*/
public class Lisp {
public SymbolTable globalSymbolTable;
private Parser parser;
private SymbolTable globalSymbolTable;
private boolean interactive = true;
public Lisp() {

View File

@ -17,29 +17,16 @@ public class List implements SExp {
// then that symbol is the name of an operator
// Depending on the funciton binding of the operator in the
// current lexical environment the form is either:
// a special form
// a macro form or
// a function form
// look up in the symbol table
TableEntry functionEntry = table.findFunction((Symbol) seq.car);
// check parameter length
if (functionEntry.parameters.length != seq.cdr.length())
throw new LispException("Invalid number of parameters: "
+ seq.cdr.length());
// create a new SymbolTable and bind arguments to parameters
SymbolTable newTable = table;
Seq nextArg = seq.cdr;
for (Symbol parameter : functionEntry.parameters) {
TableEntry newEntry = new TableEntry(parameter, null, nextArg.car);
newTable = new SymbolTable(newEntry, newTable);
nextArg = nextArg.cdr;
}
FunctionEntry functionEntry = table.lookupFunction((Symbol) seq.car);
// call function
return functionEntry.body.eval(newTable);
return functionEntry.call(table);
}

View File

@ -1,14 +1,101 @@
package edu.utexas.cs345.jdblisp;
import java.util.ArrayList;
/**
* SpecialForms
* SpecialFormEntry
* @author Jonathan Bernard (jdbernard@gmail.com)
*/
public class SpecialForms {
public abstract class SpecialFormEntry extends FunctionEntry {
public static SymbolTable createTable() {
protected Lisp environment;
public SpecialFormEntry(Lisp environment) { this.environment = environment; }
public abstract SExp call(SymbolTable symbolTable, Seq arguments) throws LispException;
public static definSpecialForms(Lisp environment) {
SpecialFormEntry DEFUN = new SpecialFormEntry(environment) {
public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException {
Symbol functionName;
ArrayList<Symbol> parameters;
SExp body;
// TODO: check to see if a function for this symbol exists
// and warn if so
if (arguments.length() != 3)
new InvalidArgumentQuantityException(3, arguments.length());
// first argument: Symbol for function name
if (!(arguments.car instanceof Symbol))
// TODO: error: has to be a symbol
functionName = (Symbol) arguments.car;
// second argument, parameter list
arguments = arguments.cdr;
assert (arguments != null);
if (!(arguments.car instanceof List))
// TODO: error, need parameter list
// read parameters
parameters = new ArrayList<Symbol>();
Seq paramSeq = ((List) arguments.car).seq;
while (seq != null) {
if (!(seq.car instanceof Symbol))
// TODO: error, expected symbol
parameters.add((Symbol) seq.car);
seq = seq.cdr;
}
// third argument: function body
arguments = arguments.cdr;
assert (arguments != null);
// TODO: necessary? if (!(arguments.car instanceof List))
body = arguments.car;
environment.globalSymbolTable.define(functionName,
new FunctionEntry(parameters.toArray(new Symbol[]{}), body));
return functionName;
}
};
SpecialFormEntry SETQ = new SpecialFormEntry(environment) throws LispException {
public SExp call(SymbolTable symbolTable, Seq arguments) {
Symbol variableName;
SExp variableValue;
// TODO: check for redifinition of variable (and warn)
if (arguments.length() != 2)
throw new InvalidArgumentQuantityException(2,
arguments.length());
// first argument: Symbol for variable name
if (!(arguments.car instanceof Symbol))
// TODO: error: expected symbol
variableName = (Symbol) arguments.car;
// second argument: variable value
arguments = arguments.cdr;
assert (arguments != null);
variableValue = arguments.car;
}
};
environment.globalSymbolTable.defin(new Symbol("DEFUN"), DEFUN);
environment.globalSymbolTable.defin(new Symbol("SETQ"), SETQ);
}
public static TableEntry
}

View File

@ -20,7 +20,7 @@ public class SymbolTable {
this.locked = locked;
}
public Symbol defineFunction(Symbol s, FunctionEntry f) {
public Symbol bind(Symbol s, FunctionEntry f) {
if (functions.get(s) != null) {
// TODO: warning: function redefinition
// Also, check access permissions
@ -29,7 +29,7 @@ public class SymbolTable {
return s;
}
public Symbol defineVariable(Symbol s, VariableEntry v) {
public Symbol bind(Symbol s, VariableEntry v) {
if (variables.get(s) != null) {
// TODO: warning: variable redefinition
// Also, check access permissions

View File

@ -8,6 +8,8 @@ public class VariableEntry {
protected final SExp expression;
public VariableEntry(SExp expression) { this.expression = expression; }
public SExp eval(SymbolTable symbolTable) {
return expression.eval(symbolTable);
}