Convert ExecutionContext to kotlin
This commit is contained in:
parent
04a4164c1b
commit
91c4070b53
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue