Refactored the symbol table code
This commit is contained in:
		
							parent
							
								
									d3fc8f9812
								
							
						
					
					
						commit
						db2817f7be
					
				@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,10 +3,16 @@ 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
 | 
				
			||||||
        if (argList.nullp()) {
 | 
					        if (argList.nullp()) {
 | 
				
			||||||
@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								src/table/ExecutionContext.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/table/ExecutionContext.java
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user