Implement append built in function
This commit is contained in:
parent
cd7a8361fc
commit
ac365918b2
|
@ -12,7 +12,7 @@
|
|||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
|
|
|
@ -37,12 +37,12 @@
|
|||
accumulator))
|
||||
accumulator))
|
||||
|
||||
(defun append (list-one list-two)
|
||||
(append-tail (reverse list-one) list-two))
|
||||
; (defun append (list-one list-two)
|
||||
; (append-tail (reverse list-one) list-two))
|
||||
|
||||
(defun append-tail (reversed-list list-two)
|
||||
(if (null reversed-list) list-two
|
||||
(recur (rest reversed-list) (cons (car reversed-list) list-two))))
|
||||
; (defun append-tail (reversed-list list-two)
|
||||
; (if (null reversed-list) list-two
|
||||
; (recur (rest reversed-list) (cons (car reversed-list) list-two))))
|
||||
|
||||
(defun reverse (the-list)
|
||||
(reverse-tail () the-list))
|
||||
|
|
|
@ -13,12 +13,12 @@ import sexpression.SExpression;
|
|||
@FunctionNames({ "APPLY" })
|
||||
public class APPLY extends LispFunction {
|
||||
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public static SExpression apply(Cons argumentList) {
|
||||
return lookupFunction("APPLY").call(argumentList);
|
||||
}
|
||||
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public APPLY(String name) {
|
||||
this.argumentValidator = new ArgumentValidator(name);
|
||||
this.argumentValidator.setExactNumberOfArguments(2);
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package function.builtin.cons;
|
||||
|
||||
import static sexpression.Nil.NIL;
|
||||
|
||||
import function.ArgumentValidator;
|
||||
import function.FunctionNames;
|
||||
import function.LispFunction;
|
||||
import sexpression.Cons;
|
||||
|
||||
@FunctionNames({ "APPEND" })
|
||||
public class APPEND extends LispFunction {
|
||||
|
||||
public static Cons append(Cons firstList, Cons secondList) {
|
||||
Cons appendedLists = copy(firstList);
|
||||
|
||||
if (firstList.isNull())
|
||||
return copy(secondList);
|
||||
|
||||
getLastItem(appendedLists).setRest(copy(secondList));
|
||||
|
||||
return appendedLists;
|
||||
}
|
||||
|
||||
private static Cons copy(Cons list) {
|
||||
if (list.isNull())
|
||||
return NIL;
|
||||
|
||||
Cons newList = new Cons(list.getFirst(), NIL);
|
||||
Cons builder = newList;
|
||||
|
||||
for (Cons iterator = (Cons) list.getRest(); iterator.isCons(); iterator = (Cons) iterator.getRest()) {
|
||||
builder.setRest(new Cons(iterator.getFirst(), NIL));
|
||||
builder = (Cons) builder.getRest();
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
private static Cons getLastItem(Cons list) {
|
||||
Cons tail = list;
|
||||
|
||||
while (tail.getRest().isCons())
|
||||
tail = (Cons) tail.getRest();
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public APPEND(String name) {
|
||||
this.argumentValidator = new ArgumentValidator(name);
|
||||
this.argumentValidator.setExactNumberOfArguments(2);
|
||||
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cons call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
Cons rest = (Cons) argumentList.getRest();
|
||||
Cons firstList = (Cons) argumentList.getFirst();
|
||||
Cons secondList = (Cons) rest.getFirst();
|
||||
|
||||
return append(firstList, secondList);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@ package function.builtin.cons;
|
|||
import static function.builtin.cons.LIST.makeList;
|
||||
import static recursion.TailCalls.done;
|
||||
import static recursion.TailCalls.tailCall;
|
||||
import static table.FunctionTable.lookupFunction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
|
@ -18,13 +17,25 @@ import sexpression.LispNumber;
|
|||
public class LENGTH extends LispFunction {
|
||||
|
||||
public static BigInteger getLength(Cons list) {
|
||||
LispNumber length = lookupLength().callWithoutArgumentValidation(makeList(list));
|
||||
|
||||
return length.getValue();
|
||||
return callWithoutArgumentValidation(makeList(list)).getValue();
|
||||
}
|
||||
|
||||
private static LENGTH lookupLength() {
|
||||
return (LENGTH) lookupFunction("LENGTH");
|
||||
private static LispNumber callWithoutArgumentValidation(Cons argumentList) {
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||
}
|
||||
|
||||
private static TailCall<LispNumber> callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
|
||||
Cons list = (Cons) argumentList.getFirst();
|
||||
Cons restOfList = makeList(list.getRest());
|
||||
|
||||
if (list.isNull())
|
||||
return done(new LispNumber(accumulatedLength));
|
||||
|
||||
return tailCall(() -> callTailRecursive(increment(accumulatedLength), restOfList));
|
||||
}
|
||||
|
||||
private static BigInteger increment(BigInteger number) {
|
||||
return number.add(BigInteger.ONE);
|
||||
}
|
||||
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
@ -42,22 +53,4 @@ public class LENGTH extends LispFunction {
|
|||
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||
}
|
||||
|
||||
private LispNumber callWithoutArgumentValidation(Cons argumentList) {
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||
}
|
||||
|
||||
private TailCall<LispNumber> callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
|
||||
Cons list = (Cons) argumentList.getFirst();
|
||||
Cons restOfList = makeList(list.getRest());
|
||||
|
||||
if (list.isNull())
|
||||
return done(new LispNumber(accumulatedLength));
|
||||
|
||||
return tailCall(() -> callTailRecursive(increment(accumulatedLength), restOfList));
|
||||
}
|
||||
|
||||
private BigInteger increment(BigInteger number) {
|
||||
return number.add(BigInteger.ONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import function.builtin.PRINT;
|
|||
import function.builtin.SET;
|
||||
import function.builtin.SYMBOLS;
|
||||
import function.builtin.SYMBOL_FUNCTION;
|
||||
import function.builtin.cons.APPEND;
|
||||
import function.builtin.cons.CONS;
|
||||
import function.builtin.cons.FIRST;
|
||||
import function.builtin.cons.LENGTH;
|
||||
|
@ -63,6 +64,7 @@ public class FunctionTable {
|
|||
|
||||
static {
|
||||
allBuiltIns.add(AND.class);
|
||||
allBuiltIns.add(APPEND.class);
|
||||
allBuiltIns.add(APPLY.class);
|
||||
allBuiltIns.add(ATOM.class);
|
||||
allBuiltIns.add(CASE.class);
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import function.builtin.cons.APPEND;
|
||||
import sexpression.Cons;
|
||||
import sexpression.SExpression;
|
||||
import sexpression.Symbol;
|
||||
|
@ -50,7 +51,7 @@ public class SymbolTable {
|
|||
Cons context = NIL;
|
||||
|
||||
for (Entry<String, SExpression> binding : getSortedBindings())
|
||||
context = append(context, makeList(makeSymbolValuePair(binding)));
|
||||
context = APPEND.append(context, makeList(makeSymbolValuePair(binding)));
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -63,19 +64,4 @@ public class SymbolTable {
|
|||
return new Cons(new Symbol(binding.getKey()), makeList(binding.getValue()));
|
||||
}
|
||||
|
||||
// TODO - extract into built in append function
|
||||
private Cons append(Cons firstList, Cons secondList) {
|
||||
if (firstList.isNull())
|
||||
return secondList; // FIXME - copy
|
||||
|
||||
Cons appendedList = firstList; // FIXME - copy
|
||||
Cons appender = appendedList;
|
||||
|
||||
for (; !((Cons) appender.getRest()).isNull(); appender = (Cons) appender.getRest()) {}
|
||||
|
||||
appender.setRest(secondList); // FIXME - copy
|
||||
|
||||
return appendedList;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package function.builtin.cons;
|
||||
|
||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
||||
import static testutil.TestUtilities.evaluateString;
|
||||
import static testutil.TestUtilities.parseString;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import function.ArgumentValidator.BadArgumentTypeException;
|
||||
import function.ArgumentValidator.TooFewArgumentsException;
|
||||
import function.ArgumentValidator.TooManyArgumentsException;
|
||||
import testutil.SymbolAndFunctionCleaner;
|
||||
|
||||
public class APPENDTest extends SymbolAndFunctionCleaner {
|
||||
|
||||
@Test
|
||||
public void appendNil() {
|
||||
String input = "(append () ())";
|
||||
|
||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendNilToList() {
|
||||
String input = "(append () '(1 2 3))";
|
||||
|
||||
assertSExpressionsMatch(parseString("(1 2 3)"), evaluateString(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendListToNil() {
|
||||
String input = "(append '(1 2 3) ())";
|
||||
|
||||
assertSExpressionsMatch(parseString("(1 2 3)"), evaluateString(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendTwoLists() {
|
||||
String input = "(append '(1 2 3) '(4 5 6))";
|
||||
|
||||
assertSExpressionsMatch(parseString("(1 2 3 4 5 6)"), evaluateString(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendMakesCopies() {
|
||||
evaluateString("(setq x '(1 2 3))");
|
||||
evaluateString("(setq y '(4 5 6))");
|
||||
evaluateString("(append x y)");
|
||||
|
||||
assertSExpressionsMatch(parseString("(1 2 3)"), evaluateString("x"));
|
||||
assertSExpressionsMatch(parseString("(4 5 6)"), evaluateString("y"));
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void appendWithTooManyArguments() {
|
||||
evaluateString("(append () () ())");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void appendWithTooFewArguments() {
|
||||
evaluateString("(append ())");
|
||||
}
|
||||
|
||||
@Test(expected = BadArgumentTypeException.class)
|
||||
public void appendWithBadArgumentType() {
|
||||
evaluateString("(append 1 '(2))");
|
||||
}
|
||||
}
|
|
@ -51,16 +51,12 @@ public class CONSTest extends SymbolAndFunctionCleaner {
|
|||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void consWithTooManyArguments() {
|
||||
String input = "(cons 1 2 3)";
|
||||
|
||||
evaluateString(input);
|
||||
evaluateString("(cons 1 2 3)");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void consWithTooFewArguments() {
|
||||
String input = "(cons 1)";
|
||||
|
||||
evaluateString(input);
|
||||
evaluateString("(cons 1)");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,13 +24,6 @@
|
|||
(defun extend-apply (function-name param-list)
|
||||
(eval (cons function-name param-list)))
|
||||
|
||||
(defun append (listA listB)
|
||||
(cond
|
||||
((null listA) listB)
|
||||
(t (cons (first listA) (append (rest listA) listB)))
|
||||
)
|
||||
)
|
||||
|
||||
(defun second (listA) (first (rest listA)))
|
||||
(defun third (listA) (first (rest (rest listA))))
|
||||
(defun fourth (listA) (first (rest (rest (rest listA)))))
|
||||
|
|
Loading…
Reference in New Issue