From adc5b2d2509b537d9f7fde3ea47f066a5e37b35d Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 20 Nov 2009 06:19:03 -0600 Subject: [PATCH] Continued work on List.eval, general function/macro/special form invocation. --- .../utexas/cs345/jdblisp/FunctionEntry.java | 33 ++++++- .../InvalidArgumentQuantityException.java | 13 +++ src/edu/utexas/cs345/jdblisp/Lisp.java | 3 +- src/edu/utexas/cs345/jdblisp/List.java | 19 +--- .../utexas/cs345/jdblisp/SpecialForms.java | 97 ++++++++++++++++++- src/edu/utexas/cs345/jdblisp/SymbolTable.java | 4 +- .../utexas/cs345/jdblisp/VariableEntry.java | 2 + 7 files changed, 144 insertions(+), 27 deletions(-) create mode 100644 src/edu/utexas/cs345/jdblisp/InvalidArgumentQuantityException.java diff --git a/src/edu/utexas/cs345/jdblisp/FunctionEntry.java b/src/edu/utexas/cs345/jdblisp/FunctionEntry.java index e1ccbbf..65b4d40 100644 --- a/src/edu/utexas/cs345/jdblisp/FunctionEntry.java +++ b/src/edu/utexas/cs345/jdblisp/FunctionEntry.java @@ -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); } } diff --git a/src/edu/utexas/cs345/jdblisp/InvalidArgumentQuantityException.java b/src/edu/utexas/cs345/jdblisp/InvalidArgumentQuantityException.java new file mode 100644 index 0000000..9bc903e --- /dev/null +++ b/src/edu/utexas/cs345/jdblisp/InvalidArgumentQuantityException.java @@ -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 + ")."); + } +} diff --git a/src/edu/utexas/cs345/jdblisp/Lisp.java b/src/edu/utexas/cs345/jdblisp/Lisp.java index eff9680..bc1ab13 100644 --- a/src/edu/utexas/cs345/jdblisp/Lisp.java +++ b/src/edu/utexas/cs345/jdblisp/Lisp.java @@ -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() { diff --git a/src/edu/utexas/cs345/jdblisp/List.java b/src/edu/utexas/cs345/jdblisp/List.java index 41e7743..2edac91 100644 --- a/src/edu/utexas/cs345/jdblisp/List.java +++ b/src/edu/utexas/cs345/jdblisp/List.java @@ -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); } diff --git a/src/edu/utexas/cs345/jdblisp/SpecialForms.java b/src/edu/utexas/cs345/jdblisp/SpecialForms.java index 92dbf62..121b6b6 100644 --- a/src/edu/utexas/cs345/jdblisp/SpecialForms.java +++ b/src/edu/utexas/cs345/jdblisp/SpecialForms.java @@ -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 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(); + 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 } diff --git a/src/edu/utexas/cs345/jdblisp/SymbolTable.java b/src/edu/utexas/cs345/jdblisp/SymbolTable.java index 66c4da1..627ef83 100644 --- a/src/edu/utexas/cs345/jdblisp/SymbolTable.java +++ b/src/edu/utexas/cs345/jdblisp/SymbolTable.java @@ -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 diff --git a/src/edu/utexas/cs345/jdblisp/VariableEntry.java b/src/edu/utexas/cs345/jdblisp/VariableEntry.java index 6f6d9d7..053f311 100644 --- a/src/edu/utexas/cs345/jdblisp/VariableEntry.java +++ b/src/edu/utexas/cs345/jdblisp/VariableEntry.java @@ -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); }