Continued work on List.eval, general function/macro/special form invocation.
This commit is contained in:
parent
1595ae1921
commit
adc5b2d250
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 + ").");
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user