Convert ExecutionContext to kotlin

This commit is contained in:
Mike Cifelli 2018-03-21 19:49:51 -04:00
parent 04a4164c1b
commit 91c4070b53
14 changed files with 126 additions and 150 deletions

View File

@ -34,7 +34,7 @@ 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.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
this.functionScope = executionContext.getScope(); this.functionScope = executionContext.getScope();
this.keywordRestParameter = null; this.keywordRestParameter = null;
this.isKeywordRestPresent = false; this.isKeywordRestPresent = false;

View File

@ -14,6 +14,7 @@ import sexpression.Symbol;
import table.ExecutionContext; import table.ExecutionContext;
import static function.builtin.cons.LIST.makeList; import static function.builtin.cons.LIST.makeList;
import static function.builtin.special.LAMBDA.Lambda;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
import static sexpression.Nil.NIL; import static sexpression.Nil.NIL;
import static sexpression.Symbol.T; import static sexpression.Symbol.T;
@ -22,7 +23,7 @@ import static table.FunctionTable.lookupFunction;
@FunctionNames({ "EVAL" }) @FunctionNames({ "EVAL" })
public class EVAL extends LispFunction { public class EVAL extends LispFunction {
private static ExecutionContext executionContext = ExecutionContext.getInstance(); private static ExecutionContext executionContext = ExecutionContext.INSTANCE;
public static SExpression eval(SExpression sExpression) { public static SExpression eval(SExpression sExpression) {
Cons argumentList = makeList(sExpression); Cons argumentList = makeList(sExpression);
@ -59,8 +60,8 @@ public class EVAL extends LispFunction {
private static LispFunction createLambdaFunction(SExpression lambdaExpression) { private static LispFunction createLambdaFunction(SExpression lambdaExpression) {
if (lambdaExpression.isFunction()) if (lambdaExpression.isFunction())
return ((LambdaExpression) lambdaExpression).getFunction(); return ((LambdaExpression) lambdaExpression).getFunction();
else if (LAMBDA.Companion.isLambdaExpression(lambdaExpression)) else if (Lambda.isLambdaExpression(lambdaExpression))
return LAMBDA.Companion.createFunction((Cons) lambdaExpression); return Lambda.createFunction((Cons) lambdaExpression);
else else
throw new UndefinedFunctionException(lambdaExpression); throw new UndefinedFunctionException(lambdaExpression);
} }
@ -73,7 +74,7 @@ public class EVAL extends LispFunction {
else if (symbolName.startsWith(":")) else if (symbolName.startsWith(":"))
return new Symbol(symbolName); return new Symbol(symbolName);
return ExecutionContext.getInstance().lookupSymbolValue(symbolName); return ExecutionContext.INSTANCE.lookupSymbolValue(symbolName);
} }
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;

View File

@ -25,7 +25,7 @@ public class SET extends LispFunction {
this.argumentValidator = new ArgumentValidator(name); this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2); this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setFirstArgumentExpectedType(Symbol.class); this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
this.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
} }
@Override @Override

View File

@ -16,7 +16,7 @@ public class SYMBOLS extends LispFunction {
public SYMBOLS(String name) { public SYMBOLS(String name) {
this.argumentValidator = new ArgumentValidator(name); this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(0); this.argumentValidator.setExactNumberOfArguments(0);
this.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
} }
@Override @Override

View File

@ -40,7 +40,7 @@ class LAMBDA(name: String) : LispSpecialFunction() {
return Cons(Symbol("LAMBDA"), argumentList) return Cons(Symbol("LAMBDA"), argumentList)
} }
companion object { companion object Lambda {
fun isLambdaExpression(sexpr: SExpression): Boolean { fun isLambdaExpression(sexpr: SExpression): Boolean {
if (sexpr.isCons) { if (sexpr.isCons) {

View File

@ -33,7 +33,7 @@ public class LET extends LispSpecialFunction {
this.pairValidator.setMaximumNumberOfArguments(2); this.pairValidator.setMaximumNumberOfArguments(2);
this.pairValidator.setFirstArgumentExpectedType(Symbol.class); this.pairValidator.setFirstArgumentExpectedType(Symbol.class);
this.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
} }
@Override @Override

View File

@ -18,7 +18,7 @@ public class RECUR extends LispSpecialFunction {
public RECUR(String name) { public RECUR(String name) {
this.argumentValidator = new ArgumentValidator(name); this.argumentValidator = new ArgumentValidator(name);
this.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
} }
@Override @Override

View File

@ -1,129 +0,0 @@
package table;
import function.LispFunction;
import sexpression.Cons;
import sexpression.SExpression;
import java.util.Stack;
import static sexpression.Nil.NIL;
public class ExecutionContext {
private static ExecutionContext uniqueInstance = new ExecutionContext();
public static ExecutionContext getInstance() {
return uniqueInstance;
}
private SymbolTable scope;
private Stack<LispFunctionRecurInfo> functionCalls;
private boolean recur;
private ExecutionContext() {
clearContext();
}
public void clearContext() {
this.scope = new SymbolTable();
this.functionCalls = new Stack<>();
this.clearRecur();
}
public SymbolTable getScope() {
return scope;
}
public void setScope(SymbolTable scope) {
this.scope = scope;
}
public void restoreGlobalScope() {
while (!scope.isGlobal())
scope = scope.getParent();
}
public SExpression lookupSymbolValue(String symbolName) {
for (SymbolTable t = scope; t != null; t = t.getParent())
if (t.contains(symbolName))
return t.get(symbolName);
return null;
}
public Cons toList() {
Cons symbols = NIL;
for (SymbolTable t = scope; t != null; t = t.getParent())
symbols = new Cons(t.toList(), symbols);
return symbols;
}
public void pushFunctionCall(LispFunction function) {
functionCalls.push(new LispFunctionRecurInfo(function));
}
public void popFunctionCall() {
functionCalls.pop();
}
public boolean isInFunctionCall() {
return !functionCalls.empty();
}
public LispFunction getCurrentFunction() {
return functionCalls.peek().getLispFunction();
}
public boolean isRecur() {
return recur;
}
public void setRecur() {
recur = true;
}
public void clearRecur() {
recur = false;
}
public boolean isRecurInitializing() {
return functionCalls.peek().isRecurInitializing();
}
public void setRecurInitializing() {
functionCalls.peek().setRecurInitializing();
}
public void clearRecurInitializing() {
functionCalls.peek().clearRecurInitializing();
}
public static class LispFunctionRecurInfo {
private LispFunction lispFunction;
private boolean recurInitializing;
public LispFunctionRecurInfo(LispFunction lispFunction) {
this.lispFunction = lispFunction;
this.clearRecurInitializing();
}
public boolean isRecurInitializing() {
return recurInitializing;
}
public void setRecurInitializing() {
this.recurInitializing = true;
}
public void clearRecurInitializing() {
this.recurInitializing = false;
}
public LispFunction getLispFunction() {
return lispFunction;
}
}
}

View File

@ -0,0 +1,101 @@
package table
import function.LispFunction
import sexpression.Cons
import sexpression.SExpression
import java.util.Stack
import sexpression.Nil.NIL
object ExecutionContext {
private val functionCalls: Stack<LispFunctionRecurInfo> = Stack()
var scope: SymbolTable = SymbolTable(NullSymbolTable)
var isRecur: Boolean = false
private set
val isInFunctionCall: Boolean
get() = !functionCalls.empty()
val currentFunction: LispFunction
get() = functionCalls.peek().lispFunction
val isRecurInitializing: Boolean
get() = functionCalls.peek().isRecurInitializing
fun clearContext() {
scope = SymbolTable(NullSymbolTable)
functionCalls.clear()
clearRecur()
}
fun restoreGlobalScope() {
while (!scope.isGlobal)
scope = scope.parent
}
fun lookupSymbolValue(symbolName: String): SExpression? {
var t = scope
while (t !== NullSymbolTable) {
if (t.contains(symbolName))
return t.get(symbolName)
t = t.parent
}
return null
}
fun toList(): Cons {
var symbols: Cons = NIL
var t = scope
while (t !== NullSymbolTable) {
symbols = Cons(t.toList(), symbols)
t = t.parent
}
return symbols
}
fun pushFunctionCall(function: LispFunction) {
functionCalls.push(LispFunctionRecurInfo(function))
}
fun popFunctionCall() {
functionCalls.pop()
}
fun setRecur() {
isRecur = true
}
fun clearRecur() {
isRecur = false
}
fun setRecurInitializing() {
functionCalls.peek().setRecurInitializing()
}
fun clearRecurInitializing() {
functionCalls.peek().clearRecurInitializing()
}
class LispFunctionRecurInfo(val lispFunction: LispFunction) {
var isRecurInitializing: Boolean = false
private set
fun setRecurInitializing() {
isRecurInitializing = true
}
fun clearRecurInitializing() {
isRecurInitializing = false
}
}
object NullSymbolTable : SymbolTable()
}

View File

@ -3,6 +3,7 @@ package table;
import sexpression.Cons; import sexpression.Cons;
import sexpression.SExpression; import sexpression.SExpression;
import sexpression.Symbol; import sexpression.Symbol;
import table.ExecutionContext.NullSymbolTable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -19,7 +20,7 @@ public class SymbolTable {
private SymbolTable parent; private SymbolTable parent;
public SymbolTable() { public SymbolTable() {
this(null); this(NullSymbolTable.INSTANCE);
} }
public SymbolTable(SymbolTable parent) { public SymbolTable(SymbolTable parent) {
@ -44,7 +45,7 @@ public class SymbolTable {
} }
public boolean isGlobal() { public boolean isGlobal() {
return parent == null; return parent == NullSymbolTable.INSTANCE;
} }
public Cons toList() { public Cons toList() {

View File

@ -19,7 +19,7 @@ import static util.Path.getPathPrefix;
public class LispInterpreterFixture { public class LispInterpreterFixture {
private static ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private static ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private static ExecutionContext executionContext = ExecutionContext.getInstance(); private static ExecutionContext executionContext = ExecutionContext.INSTANCE;
private static RuntimeEnvironment environment = RuntimeEnvironment.getInstance(); private static RuntimeEnvironment environment = RuntimeEnvironment.getInstance();
private static LispInterpreter interpreter = null; private static LispInterpreter interpreter = null;

View File

@ -11,6 +11,7 @@ import sexpression.LispNumber;
import sexpression.Symbol; import sexpression.Symbol;
import testutil.SymbolAndFunctionCleaner; import testutil.SymbolAndFunctionCleaner;
import static function.builtin.special.LAMBDA.Lambda;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static sexpression.LispNumber.ONE; import static sexpression.LispNumber.ONE;
@ -47,12 +48,12 @@ public class LAMBDATest extends SymbolAndFunctionCleaner {
public void lambdaExpressionIsLambdaExpression() { public void lambdaExpressionIsLambdaExpression() {
Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, new Cons(NIL, NIL))); Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, new Cons(NIL, NIL)));
assertTrue(LAMBDA.Companion.isLambdaExpression(lambdaExpression)); assertTrue(Lambda.isLambdaExpression(lambdaExpression));
} }
@Test @Test
public void somethingElseIsNotLambdaExpression() { public void somethingElseIsNotLambdaExpression() {
assertFalse(LAMBDA.Companion.isLambdaExpression(T)); assertFalse(Lambda.isLambdaExpression(T));
} }
@Test @Test
@ -60,7 +61,7 @@ public class LAMBDATest extends SymbolAndFunctionCleaner {
Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, new Cons(NIL, NIL))); Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, new Cons(NIL, NIL)));
assertSExpressionsMatch(parseString("(:LAMBDA () ())"), assertSExpressionsMatch(parseString("(:LAMBDA () ())"),
LAMBDA.Companion.createFunction(lambdaExpression).getLambdaExpression()); Lambda.createFunction(lambdaExpression).getLambdaExpression());
} }
@Test(expected = DottedArgumentListException.class) @Test(expected = DottedArgumentListException.class)
@ -81,14 +82,14 @@ public class LAMBDATest extends SymbolAndFunctionCleaner {
public void createFunctionWithDottedArgumentList() { public void createFunctionWithDottedArgumentList() {
Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, ONE)); Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), new Cons(NIL, ONE));
LAMBDA.Companion.createFunction(lambdaExpression); Lambda.createFunction(lambdaExpression);
} }
@Test(expected = BadArgumentTypeException.class) @Test(expected = BadArgumentTypeException.class)
public void createFunctionWithNonList() { public void createFunctionWithNonList() {
Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), ONE); Cons lambdaExpression = new Cons(new Symbol("LAMBDA"), ONE);
LAMBDA.Companion.createFunction(lambdaExpression); Lambda.createFunction(lambdaExpression);
} }
@Test(expected = BadArgumentTypeException.class) @Test(expected = BadArgumentTypeException.class)

View File

@ -8,11 +8,12 @@ import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import sexpression.Nil.NIL import sexpression.Nil.NIL
import sexpression.Symbol.T import sexpression.Symbol.T
import table.ExecutionContext.NullSymbolTable
@TestInstance(PER_CLASS) @TestInstance(PER_CLASS)
class ExecutionContextTest { class ExecutionContextTest {
private val executionContext: ExecutionContext = ExecutionContext.getInstance() private val executionContext: ExecutionContext = ExecutionContext
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
@ -40,7 +41,7 @@ class ExecutionContextTest {
assertThat(executionContext.scope).isEqualTo(scope) assertThat(executionContext.scope).isEqualTo(scope)
executionContext.clearContext() executionContext.clearContext()
assertThat(executionContext.scope).isNotEqualTo(scope) assertThat(executionContext.scope).isNotEqualTo(scope)
assertThat(executionContext.scope.parent).isNull() assertThat(executionContext.scope.parent).isEqualTo(NullSymbolTable)
} }
@Test @Test

View File

@ -11,7 +11,7 @@ public abstract class SymbolAndFunctionCleaner {
protected ExecutionContext executionContext; protected ExecutionContext executionContext;
public SymbolAndFunctionCleaner() { public SymbolAndFunctionCleaner() {
this.executionContext = ExecutionContext.getInstance(); this.executionContext = ExecutionContext.INSTANCE;
} }
@Before @Before