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 Symbol[] parameters;
|
||||||
protected final SExp body;
|
protected final SExp body;
|
||||||
|
|
||||||
public SExp call(SymbolTable symbolTable, Seq seq) {
|
public FunctionEntry(Symbol[] parameters, SExp body) {
|
||||||
// TODO
|
this.parameters = parameters;
|
||||||
return null;
|
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 class Lisp {
|
||||||
|
|
||||||
|
public SymbolTable globalSymbolTable;
|
||||||
|
|
||||||
private Parser parser;
|
private Parser parser;
|
||||||
private SymbolTable globalSymbolTable;
|
|
||||||
private boolean interactive = true;
|
private boolean interactive = true;
|
||||||
|
|
||||||
public Lisp() {
|
public Lisp() {
|
||||||
|
@ -17,29 +17,16 @@ public class List implements SExp {
|
|||||||
// then that symbol is the name of an operator
|
// then that symbol is the name of an operator
|
||||||
// Depending on the funciton binding of the operator in the
|
// Depending on the funciton binding of the operator in the
|
||||||
// current lexical environment the form is either:
|
// current lexical environment the form is either:
|
||||||
|
|
||||||
// a special form
|
// a special form
|
||||||
// a macro form or
|
// a macro form or
|
||||||
// a function form
|
// a function form
|
||||||
|
|
||||||
// look up in the symbol table
|
// look up in the symbol table
|
||||||
TableEntry functionEntry = table.findFunction((Symbol) seq.car);
|
FunctionEntry functionEntry = table.lookupFunction((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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call function
|
// call function
|
||||||
return functionEntry.body.eval(newTable);
|
return functionEntry.call(table);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,101 @@
|
|||||||
package edu.utexas.cs345.jdblisp;
|
package edu.utexas.cs345.jdblisp;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SpecialForms
|
* SpecialFormEntry
|
||||||
* @author Jonathan Bernard (jdbernard@gmail.com)
|
* @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;
|
this.locked = locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Symbol defineFunction(Symbol s, FunctionEntry f) {
|
public Symbol bind(Symbol s, FunctionEntry f) {
|
||||||
if (functions.get(s) != null) {
|
if (functions.get(s) != null) {
|
||||||
// TODO: warning: function redefinition
|
// TODO: warning: function redefinition
|
||||||
// Also, check access permissions
|
// Also, check access permissions
|
||||||
@ -29,7 +29,7 @@ public class SymbolTable {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Symbol defineVariable(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
|
||||||
// Also, check access permissions
|
// Also, check access permissions
|
||||||
|
@ -8,6 +8,8 @@ public class VariableEntry {
|
|||||||
|
|
||||||
protected final SExp expression;
|
protected final SExp expression;
|
||||||
|
|
||||||
|
public VariableEntry(SExp expression) { this.expression = expression; }
|
||||||
|
|
||||||
public SExp eval(SymbolTable symbolTable) {
|
public SExp eval(SymbolTable symbolTable) {
|
||||||
return expression.eval(symbolTable);
|
return expression.eval(symbolTable);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user