Refactored the symbol table code

This commit is contained in:
Mike Cifelli 2017-01-30 16:12:38 -05:00
parent d3fc8f9812
commit db2817f7be
6 changed files with 83 additions and 48 deletions

View File

@ -3,15 +3,15 @@ package function;
import java.util.ArrayList; import java.util.ArrayList;
import function.builtin.EVAL; import function.builtin.EVAL;
import function.builtin.special.SETF;
import sexpression.*; import sexpression.*;
import table.SymbolTable; import table.*;
public class UserDefinedFunction extends LispFunction { public class UserDefinedFunction extends LispFunction {
private String name; private String name;
private Cons body; private Cons body;
private Cons lambdaExpression; private Cons lambdaExpression;
private ExecutionContext executionContext;
private SymbolTable scope; private SymbolTable scope;
private ArrayList<String> formalParameters; private ArrayList<String> formalParameters;
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
@ -20,7 +20,8 @@ public class UserDefinedFunction extends LispFunction {
this.name = name; this.name = name;
this.body = body; this.body = body;
this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body)); this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body));
this.scope = SETF.getSymbolTable(); this.executionContext = ExecutionContext.getInstance();
this.scope = executionContext.getScope();
for (this.formalParameters = new ArrayList<>(); lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr()) for (this.formalParameters = new ArrayList<>(); lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr())
this.formalParameters.add(lambdaList.getCar().toString()); this.formalParameters.add(lambdaList.getCar().toString());
@ -37,11 +38,11 @@ public class UserDefinedFunction extends LispFunction {
// store the environment of the S-expression that called this function // store the environment of the S-expression that called this function
// (the current environment) // (the current environment)
SymbolTable callingScope = SETF.getSymbolTable(); SymbolTable callingScope = executionContext.getScope();
// replace the current environment with the environment of this // replace the current environment with the environment of this
// function // function
SETF.setSymbolTable(scope); executionContext.setScope(scope);
Cons currentSExpression = body; Cons currentSExpression = body;
SExpression lastValue = null; SExpression lastValue = null;
@ -54,7 +55,7 @@ public class UserDefinedFunction extends LispFunction {
// replace the environment of the S-expression that called this // replace the environment of the S-expression that called this
// function // function
SETF.setSymbolTable(callingScope); executionContext.setScope(callingScope);
// remove the bindings of the arguments to the formal parameter names // remove the bindings of the arguments to the formal parameter names
// in the environment of this function // in the environment of this function

View File

@ -5,9 +5,9 @@ import java.text.MessageFormat;
import error.LispException; import error.LispException;
import function.*; import function.*;
import function.builtin.cons.LIST; import function.builtin.cons.LIST;
import function.builtin.special.*; import function.builtin.special.LAMBDA;
import sexpression.*; import sexpression.*;
import table.FunctionTable; import table.*;
public class EVAL extends LispFunction { public class EVAL extends LispFunction {
@ -37,7 +37,7 @@ public class EVAL extends LispFunction {
else if (symbolName.startsWith(":")) else if (symbolName.startsWith(":"))
return new Symbol(symbolName); return new Symbol(symbolName);
return SETF.lookupSymbolValue(symbolName); return ExecutionContext.getInstance().lookupSymbolValue(symbolName);
} }
public static SExpression eval(SExpression sExpression) { public static SExpression eval(SExpression sExpression) {

View File

@ -3,9 +3,15 @@ package function.builtin.special;
import function.*; import function.*;
import function.builtin.EVAL; import function.builtin.EVAL;
import sexpression.*; import sexpression.*;
import table.SymbolTable; import table.*;
public class LET extends LispFunction { public class LET extends LispFunction {
private ExecutionContext executionContext;
public LET() {
this.executionContext = ExecutionContext.getInstance();
}
public SExpression call(Cons argList) { public SExpression call(Cons argList) {
// make sure we have received at least one argument // make sure we have received at least one argument
@ -15,13 +21,13 @@ public class LET extends LispFunction {
// create a new symbol table on top of the current environment to add // create a new symbol table on top of the current environment to add
// all the local variables to // all the local variables to
SymbolTable environment = new SymbolTable(SETF.getSymbolTable()); SymbolTable environment = new SymbolTable(executionContext.getScope());
SExpression car = argList.getCar(); SExpression car = argList.getCar();
Cons cdr = (Cons) argList.getCdr(); Cons cdr = (Cons) argList.getCdr();
addVariablesToTable(environment, car); addVariablesToTable(environment, car);
SETF.setSymbolTable(environment); executionContext.setScope(environment);
SExpression retval = Nil.getInstance(); SExpression retval = Nil.getInstance();
@ -32,7 +38,7 @@ public class LET extends LispFunction {
} }
// restore the environment to its original value // restore the environment to its original value
SETF.setSymbolTable(environment.getParent()); executionContext.setScope(environment.getParent());
return retval; return retval;
} }

View File

@ -3,34 +3,18 @@ package function.builtin.special;
import function.*; import function.*;
import function.builtin.EVAL; import function.builtin.EVAL;
import sexpression.*; import sexpression.*;
import table.SymbolTable; import table.*;
public class SETF extends LispFunction { public class SETF extends LispFunction {
private static SymbolTable symbolTable = new SymbolTable();
public static SExpression lookupSymbolValue(String symbolName) {
for (SymbolTable t = symbolTable; t != null; t = t.getParent())
if (t.contains(symbolName))
return t.get(symbolName);
return null;
}
public static void setSymbolTable(SymbolTable newSymbolTable) {
symbolTable = newSymbolTable;
}
public static SymbolTable getSymbolTable() {
return symbolTable;
}
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private ExecutionContext executionContext;
public SETF() { public SETF() {
this.argumentValidator = new ArgumentValidator("SETF"); this.argumentValidator = new ArgumentValidator("SETF");
this.argumentValidator.setExactNumberOfArguments(2); this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setFirstArgumentExpectedType(Symbol.class); this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
this.executionContext = ExecutionContext.getInstance();
} }
public SExpression call(Cons argumentList) { public SExpression call(Cons argumentList) {
@ -40,14 +24,14 @@ public class SETF extends LispFunction {
SExpression symbol = argumentList.getCar(); SExpression symbol = argumentList.getCar();
SExpression value = EVAL.eval(cdr.getCar()); SExpression value = EVAL.eval(cdr.getCar());
SymbolTable table = findTableForSymbol(symbol); SymbolTable table = findScopeOfSymbol(symbol);
table.put(symbol.toString(), value); table.put(symbol.toString(), value);
return value; return value;
} }
private SymbolTable findTableForSymbol(SExpression symbol) { private SymbolTable findScopeOfSymbol(SExpression symbol) {
SymbolTable table = symbolTable; SymbolTable table = executionContext.getScope();
while (!isSymbolInTable(symbol, table) && !isGlobalTable(table)) while (!isSymbolInTable(symbol, table) && !isGlobalTable(table))
table = table.getParent(); table = table.getParent();

View File

@ -0,0 +1,38 @@
package table;
import sexpression.SExpression;
public class ExecutionContext {
private static ExecutionContext uniqueInstance = new ExecutionContext();
public static ExecutionContext getInstance() {
return uniqueInstance;
}
private SymbolTable scope;
private ExecutionContext() {
this.scope = new SymbolTable();
}
public SymbolTable getScope() {
return scope;
}
public void setScope(SymbolTable scope) {
this.scope = scope;
}
public void clearContext() {
this.scope = new SymbolTable();
}
public SExpression lookupSymbolValue(String symbolName) {
for (SymbolTable t = scope; t != null; t = t.getParent())
if (t.contains(symbolName))
return t.get(symbolName);
return null;
}
}

View File

@ -8,13 +8,19 @@ import org.junit.*;
import function.ArgumentValidator.*; import function.ArgumentValidator.*;
import function.builtin.EVAL.UndefinedSymbolException; import function.builtin.EVAL.UndefinedSymbolException;
import sexpression.LispNumber; import sexpression.LispNumber;
import table.SymbolTable; import table.*;
public class SETFTester { public class SETFTester {
private ExecutionContext executionContext;
public SETFTester() {
this.executionContext = ExecutionContext.getInstance();
}
@Before @Before
public void setUp() { public void setUp() {
SETF.setSymbolTable(new SymbolTable()); executionContext.clearContext();
} }
@Test @Test
@ -26,45 +32,45 @@ public class SETFTester {
@Test @Test
public void lookupDefinedSymbol() { public void lookupDefinedSymbol() {
evaluateString("(setf a 23)"); evaluateString("(setf a 23)");
assertSExpressionsMatch(new LispNumber("23"), SETF.lookupSymbolValue("A")); assertSExpressionsMatch(new LispNumber("23"), executionContext.lookupSymbolValue("A"));
} }
@Test @Test
public void lookupUndefinedSymbol() { public void lookupUndefinedSymbol() {
assertNull(SETF.lookupSymbolValue("A")); assertNull(executionContext.lookupSymbolValue("A"));
} }
@Test @Test
public void setfGlobalVariable() { public void setfGlobalVariable() {
evaluateString("(setf a 23)"); evaluateString("(setf a 23)");
SymbolTable global = SETF.getSymbolTable(); SymbolTable global = executionContext.getScope();
SETF.setSymbolTable(new SymbolTable(global)); executionContext.setScope(new SymbolTable(global));
evaluateString("(setf a 94)"); evaluateString("(setf a 94)");
SETF.setSymbolTable(global); executionContext.setScope(global);
assertSExpressionsMatch(new LispNumber("94"), evaluateString("a")); assertSExpressionsMatch(new LispNumber("94"), evaluateString("a"));
} }
@Test(expected = UndefinedSymbolException.class) @Test(expected = UndefinedSymbolException.class)
public void setfLocalVariableDefined_DoesNotSetGlobal() { public void setfLocalVariableDefined_DoesNotSetGlobal() {
SymbolTable global = SETF.getSymbolTable(); SymbolTable global = executionContext.getScope();
SymbolTable local = new SymbolTable(global); SymbolTable local = new SymbolTable(global);
local.put("A", new LispNumber("99")); local.put("A", new LispNumber("99"));
SETF.setSymbolTable(local); executionContext.setScope(local);
evaluateString("(setf a 94)"); evaluateString("(setf a 94)");
SETF.setSymbolTable(global); executionContext.setScope(global);
evaluateString("a"); evaluateString("a");
} }
@Test @Test
public void setfLocalVariableUndefined_SetsGlobal() { public void setfLocalVariableUndefined_SetsGlobal() {
SymbolTable global = SETF.getSymbolTable(); SymbolTable global = executionContext.getScope();
SymbolTable local = new SymbolTable(global); SymbolTable local = new SymbolTable(global);
SETF.setSymbolTable(local); executionContext.setScope(local);
evaluateString("(setf a 94)"); evaluateString("(setf a 94)");
SETF.setSymbolTable(global); executionContext.setScope(global);
assertSExpressionsMatch(new LispNumber("94"), evaluateString("a")); assertSExpressionsMatch(new LispNumber("94"), evaluateString("a"));
} }