Convert remaining built in functions to kotlin
This commit is contained in:
		
							parent
							
								
									add24979d5
								
							
						
					
					
						commit
						35406b9f03
					
				| @ -1,7 +1,7 @@ | |||||||
| package function | package function | ||||||
| 
 | 
 | ||||||
| import error.LispException | import error.LispException | ||||||
| import function.builtin.cons.LENGTH.getLength | import function.builtin.cons.Length.Companion.getLength | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.DisplayName | import sexpression.DisplayName | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import error.LispException | |||||||
| import function.ArgumentValidator | import function.ArgumentValidator | ||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.LispFunction | import function.LispFunction | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import function.builtin.special.Lambda.Lambda.createFunction | import function.builtin.special.Lambda.Lambda.createFunction | ||||||
| import function.builtin.special.Lambda.Lambda.isLambdaExpression | import function.builtin.special.Lambda.Lambda.isLambdaExpression | ||||||
| import function.builtin.special.Recur.RecurNotInTailPositionException | import function.builtin.special.Recur.RecurNotInTailPositionException | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import function.ArgumentValidator | |||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.LispFunction | import function.LispFunction | ||||||
| import function.builtin.Apply.Companion.apply | import function.builtin.Apply.Companion.apply | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,74 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.Nil; |  | ||||||
| import table.FunctionTable; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "APPEND" }) |  | ||||||
| public class APPEND extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     public static Cons append(Cons firstList, Cons secondList) { |  | ||||||
|         return lookupAppend().appendLists(firstList, secondList); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static APPEND lookupAppend() { |  | ||||||
|         return (APPEND) FunctionTable.INSTANCE.lookupFunction("APPEND"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private ArgumentValidator firstListValidator; |  | ||||||
| 
 |  | ||||||
|     public APPEND(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(2); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); |  | ||||||
|         this.firstListValidator = new ArgumentValidator(name + "|first-list|"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @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 appendLists(firstList, secondList); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Cons appendLists(Cons firstList, Cons secondList) { |  | ||||||
|         firstListValidator.validate(firstList); |  | ||||||
| 
 |  | ||||||
|         if (firstList.isNull()) |  | ||||||
|             return secondList; |  | ||||||
| 
 |  | ||||||
|         Cons appendedLists = copy(firstList); |  | ||||||
|         getLastItem(appendedLists).setRest(secondList); |  | ||||||
| 
 |  | ||||||
|         return appendedLists; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Cons copy(Cons list) { |  | ||||||
|         Cons newList = new Cons(list.getFirst(), Nil.INSTANCE); |  | ||||||
|         Cons builder = newList; |  | ||||||
| 
 |  | ||||||
|         for (Cons iterator = (Cons) list.getRest(); iterator.isCons(); iterator = (Cons) iterator.getRest()) { |  | ||||||
|             builder.setRest(new Cons(iterator.getFirst(), Nil.INSTANCE)); |  | ||||||
|             builder = (Cons) builder.getRest(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return newList; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Cons getLastItem(Cons list) { |  | ||||||
|         Cons tail = list; |  | ||||||
| 
 |  | ||||||
|         while (tail.getRest().isCons()) |  | ||||||
|             tail = (Cons) tail.getRest(); |  | ||||||
| 
 |  | ||||||
|         return tail; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										63
									
								
								src/main/kotlin/function/builtin/cons/Append.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/main/kotlin/function/builtin/cons/Append.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.Nil | ||||||
|  | import table.FunctionTable | ||||||
|  | 
 | ||||||
|  | @FunctionNames("APPEND") | ||||||
|  | class Append(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(2) | ||||||
|  |         setEveryArgumentExpectedType(Cons::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val firstListValidator = ArgumentValidator("$name|first-list|") | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): Cons { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         val rest = argumentList.rest as Cons | ||||||
|  |         val firstList = argumentList.first as Cons | ||||||
|  |         val secondList = rest.first as Cons | ||||||
|  | 
 | ||||||
|  |         return appendLists(firstList, secondList) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun appendLists(firstList: Cons, secondList: Cons): Cons { | ||||||
|  |         firstListValidator.validate(firstList) | ||||||
|  | 
 | ||||||
|  |         if (firstList.isNull) | ||||||
|  |             return secondList | ||||||
|  | 
 | ||||||
|  |         val appendedLists = copy(firstList) | ||||||
|  |         appendedLists.last().rest = secondList | ||||||
|  | 
 | ||||||
|  |         return appendedLists | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun copy(list: Cons): Cons { | ||||||
|  |         val newList = Cons(list.first, Nil) | ||||||
|  |         var builder = newList | ||||||
|  | 
 | ||||||
|  |         list.asSequence().drop(1).forEach { | ||||||
|  |             builder.rest = Cons(it.first, Nil) | ||||||
|  |             builder = builder.rest as Cons | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return newList | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  | 
 | ||||||
|  |         @JvmStatic | ||||||
|  |         fun append(firstList: Cons, secondList: Cons): Cons { | ||||||
|  |             return lookupAppend().appendLists(firstList, secondList) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private fun lookupAppend() = FunctionTable.lookupFunction("APPEND") as Append | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,29 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "CONS" }) |  | ||||||
| public class CONS extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public CONS(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(2); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public Cons call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         Cons rest = (Cons) argumentList.getRest(); |  | ||||||
|         SExpression firstArgument = argumentList.getFirst(); |  | ||||||
|         SExpression secondArgument = rest.getFirst(); |  | ||||||
| 
 |  | ||||||
|         return new Cons(firstArgument, secondArgument); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										24
									
								
								src/main/kotlin/function/builtin/cons/Construct.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/main/kotlin/function/builtin/cons/Construct.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | 
 | ||||||
|  | @FunctionNames("CONS") | ||||||
|  | class Construct(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(2) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): Cons { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         val rest = argumentList.rest as Cons | ||||||
|  |         val firstArgument = argumentList.first | ||||||
|  |         val secondArgument = rest.first | ||||||
|  | 
 | ||||||
|  |         return Cons(firstArgument, secondArgument) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,27 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "FIRST", "CAR" }) |  | ||||||
| public class FIRST extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public FIRST(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(1); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public SExpression call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
|         Cons argument = (Cons) argumentList.getFirst(); |  | ||||||
| 
 |  | ||||||
|         return argument.getFirst(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										23
									
								
								src/main/kotlin/function/builtin/cons/First.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/main/kotlin/function/builtin/cons/First.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.SExpression | ||||||
|  | 
 | ||||||
|  | @FunctionNames("FIRST", "CAR") | ||||||
|  | class First(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(1) | ||||||
|  |         setEveryArgumentExpectedType(Cons::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): SExpression { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  |         val argument = argumentList.first as Cons | ||||||
|  | 
 | ||||||
|  |         return argument.first | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,65 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import recursion.TailCall; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| import table.FunctionTable; |  | ||||||
| 
 |  | ||||||
| import java.math.BigInteger; |  | ||||||
| 
 |  | ||||||
| import static function.builtin.cons.LIST.makeList; |  | ||||||
| import static recursion.TailCalls.done; |  | ||||||
| import static recursion.TailCalls.tailCall; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "LENGTH" }) |  | ||||||
| public class LENGTH extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     public static BigInteger getLength(Cons list) { |  | ||||||
|         LispNumber length = lookupLength().callWithoutArgumentValidation(makeList(list)); |  | ||||||
| 
 |  | ||||||
|         return length.getValue(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static LENGTH lookupLength() { |  | ||||||
|         return (LENGTH) FunctionTable.INSTANCE.lookupFunction("LENGTH"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private ArgumentValidator properListValidator; |  | ||||||
| 
 |  | ||||||
|     public LENGTH(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(1); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); |  | ||||||
|         this.properListValidator = new ArgumentValidator(name + "|list|"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public LispNumber call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
|         properListValidator.validate((Cons) argumentList.getFirst()); |  | ||||||
| 
 |  | ||||||
|         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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,29 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.Nil; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "LIST" }) |  | ||||||
| public class LIST extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     public static Cons makeList(SExpression sexpr) { |  | ||||||
|         return new Cons(sexpr, Nil.INSTANCE); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public LIST(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public Cons call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         return argumentList; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										39
									
								
								src/main/kotlin/function/builtin/cons/Length.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main/kotlin/function/builtin/cons/Length.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | import table.FunctionTable | ||||||
|  | import table.FunctionTable.lookupFunction | ||||||
|  | import java.math.BigInteger.ZERO | ||||||
|  | 
 | ||||||
|  | @FunctionNames("LENGTH") | ||||||
|  | class Length(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(1) | ||||||
|  |         setEveryArgumentExpectedType(Cons::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val properListValidator = ArgumentValidator("$name|list|") | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): LispNumber { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         val arguments = argumentList.first as Cons | ||||||
|  |         properListValidator.validate(arguments) | ||||||
|  | 
 | ||||||
|  |         return getLength(arguments) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getLength(arguments: Cons) = | ||||||
|  |         LispNumber(arguments.fold(ZERO) { count, _ -> count.inc() }) | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  | 
 | ||||||
|  |         fun getLength(list: Cons) = lookupLength().getLength(list).value | ||||||
|  |         private fun lookupLength() = lookupFunction("LENGTH") as Length | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								src/main/kotlin/function/builtin/cons/List.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/main/kotlin/function/builtin/cons/List.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.Nil | ||||||
|  | import sexpression.SExpression | ||||||
|  | 
 | ||||||
|  | @FunctionNames("LIST") | ||||||
|  | class List(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name) | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): Cons { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         return argumentList | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  | 
 | ||||||
|  |         @JvmStatic | ||||||
|  |         fun makeList(sexpr: SExpression): Cons { | ||||||
|  |             return Cons(sexpr, Nil) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,27 +0,0 @@ | |||||||
| package function.builtin.cons; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "REST", "CDR" }) |  | ||||||
| public class REST extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public REST(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(1); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public SExpression call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
|         Cons argument = (Cons) argumentList.getFirst(); |  | ||||||
| 
 |  | ||||||
|         return argument.getRest(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										23
									
								
								src/main/kotlin/function/builtin/cons/Rest.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/main/kotlin/function/builtin/cons/Rest.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | package function.builtin.cons | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.SExpression | ||||||
|  | 
 | ||||||
|  | @FunctionNames("REST", "CDR") | ||||||
|  | class Rest(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(1) | ||||||
|  |         setEveryArgumentExpectedType(Cons::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): SExpression { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  |         val argument = argumentList.first as Cons | ||||||
|  | 
 | ||||||
|  |         return argument.rest | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,53 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import error.LispException; |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| 
 |  | ||||||
| import java.math.BigInteger; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "/" }) |  | ||||||
| public class DIVIDE extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private MathFunction mathFunction; |  | ||||||
| 
 |  | ||||||
|     public DIVIDE(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setMinimumNumberOfArguments(1); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|         this.mathFunction = new MathFunction(this::getReciprocal, this::divide); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public LispNumber call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             return mathFunction.callTailRecursive(argumentList).invoke(); |  | ||||||
|         } catch (ArithmeticException e) { |  | ||||||
|             throw new DivideByZeroException(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber getReciprocal(LispNumber number) { |  | ||||||
|         return new LispNumber(BigInteger.ONE.divide(number.getValue())); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber divide(LispNumber number1, LispNumber number2) { |  | ||||||
|         return new LispNumber(number1.getValue().divide(number2.getValue())); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class DivideByZeroException extends LispException { |  | ||||||
| 
 |  | ||||||
|         private static final long serialVersionUID = 1L; |  | ||||||
| 
 |  | ||||||
|         @Override |  | ||||||
|         public String getMessage() { |  | ||||||
|             return "divide by zero"; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										41
									
								
								src/main/kotlin/function/builtin/math/Divide.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/main/kotlin/function/builtin/math/Divide.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import error.LispException | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | import java.math.BigInteger.ONE | ||||||
|  | 
 | ||||||
|  | @FunctionNames("/") | ||||||
|  | class Divide(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setMinimumNumberOfArguments(1) | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val mathFunction = MathFunction(this::getReciprocal, this::divide) | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): LispNumber { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             return mathFunction.callTailRecursive(argumentList) | ||||||
|  |         } catch (e: ArithmeticException) { | ||||||
|  |             throw DivideByZeroException() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getReciprocal(number: LispNumber) = | ||||||
|  |         LispNumber(ONE / number.value) | ||||||
|  | 
 | ||||||
|  |     private fun divide(number1: LispNumber, number2: LispNumber) = | ||||||
|  |         LispNumber(number1.value / number2.value) | ||||||
|  | 
 | ||||||
|  |     class DivideByZeroException : LispException() { | ||||||
|  | 
 | ||||||
|  |         override val message = "divide by zero" | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,38 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| 
 |  | ||||||
| import java.math.BigInteger; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "-" }) |  | ||||||
| public class MINUS extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private MathFunction mathFunction; |  | ||||||
| 
 |  | ||||||
|     public MINUS(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setMinimumNumberOfArguments(1); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|         this.mathFunction = new MathFunction(this::additiveInverse, this::subtract); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public LispNumber call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         return mathFunction.callTailRecursive(argumentList).invoke(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber additiveInverse(LispNumber number) { |  | ||||||
|         return new LispNumber(BigInteger.ZERO.subtract(number.getValue())); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber subtract(LispNumber number1, LispNumber number2) { |  | ||||||
|         return new LispNumber(number1.getValue().subtract(number2.getValue())); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import error.LispException; |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "MOD", "MODULO", "%" }) |  | ||||||
| public class MODULO extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public MODULO(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(2); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public SExpression call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
|         LispNumber dividend = (LispNumber) argumentList.getFirst(); |  | ||||||
|         LispNumber divisor = (LispNumber) ((Cons) argumentList.getRest()).getFirst(); |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             return new LispNumber(dividend.getValue().mod(divisor.getValue())); |  | ||||||
|         } catch (ArithmeticException e) { |  | ||||||
|             throw new ModulusNotPositiveException(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class ModulusNotPositiveException extends LispException { |  | ||||||
| 
 |  | ||||||
|         private static final long serialVersionUID = 1L; |  | ||||||
| 
 |  | ||||||
|         @Override |  | ||||||
|         public String getMessage() { |  | ||||||
|             return "modulus not positive"; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "*" }) |  | ||||||
| public class MULTIPLY extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private MathFunction mathFunction; |  | ||||||
| 
 |  | ||||||
|     public MULTIPLY(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|         this.mathFunction = new MathFunction(number -> number, this::multiply); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public LispNumber call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         return mathFunction.callTailRecursive(new Cons(LispNumber.Companion.getONE(), argumentList)).invoke(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber multiply(LispNumber number1, LispNumber number2) { |  | ||||||
|         return new LispNumber(number1.getValue().multiply(number2.getValue())); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,43 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import recursion.TailCall; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| import java.util.function.BiFunction; |  | ||||||
| import java.util.function.Function; |  | ||||||
| 
 |  | ||||||
| import static recursion.TailCalls.done; |  | ||||||
| import static recursion.TailCalls.tailCall; |  | ||||||
| 
 |  | ||||||
| class MathFunction { |  | ||||||
| 
 |  | ||||||
|     Function<LispNumber, LispNumber> singleValueOperation; |  | ||||||
|     BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation; |  | ||||||
| 
 |  | ||||||
|     public MathFunction(Function<LispNumber, LispNumber> singleValueOperation, |  | ||||||
|                         BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation) { |  | ||||||
|         this.singleValueOperation = singleValueOperation; |  | ||||||
|         this.multipleValueOperation = multipleValueOperation; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public TailCall<LispNumber> callTailRecursive(Cons argumentList) { |  | ||||||
|         Cons remainingArguments = (Cons) argumentList.getRest(); |  | ||||||
|         SExpression firstArgument = argumentList.getFirst(); |  | ||||||
|         LispNumber number1 = (LispNumber) firstArgument; |  | ||||||
| 
 |  | ||||||
|         if (remainingArguments.isNull()) |  | ||||||
|             return done(singleValueOperation.apply(number1)); |  | ||||||
| 
 |  | ||||||
|         SExpression secondArgument = remainingArguments.getFirst(); |  | ||||||
|         LispNumber number2 = (LispNumber) secondArgument; |  | ||||||
|         LispNumber operationResult = multipleValueOperation.apply(number1, number2); |  | ||||||
|         SExpression remainingNumbers = remainingArguments.getRest(); |  | ||||||
| 
 |  | ||||||
|         if (remainingNumbers.isNull()) |  | ||||||
|             return done(operationResult); |  | ||||||
| 
 |  | ||||||
|         return tailCall(() -> callTailRecursive(new Cons(operationResult, remainingNumbers))); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										27
									
								
								src/main/kotlin/function/builtin/math/MathFunction.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/main/kotlin/function/builtin/math/MathFunction.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | 
 | ||||||
|  | internal class MathFunction(private val singleValueOperation: (LispNumber) -> LispNumber, | ||||||
|  |                             private val multipleValueOperation: (LispNumber, LispNumber) -> LispNumber) { | ||||||
|  | 
 | ||||||
|  |     tailrec fun callTailRecursive(argumentList: Cons): LispNumber { | ||||||
|  |         val remainingArguments = argumentList.rest as Cons | ||||||
|  |         val firstArgument = argumentList.first | ||||||
|  |         val number1 = firstArgument as LispNumber | ||||||
|  | 
 | ||||||
|  |         if (remainingArguments.isNull) | ||||||
|  |             return singleValueOperation(number1) | ||||||
|  | 
 | ||||||
|  |         val secondArgument = remainingArguments.first | ||||||
|  |         val number2 = secondArgument as LispNumber | ||||||
|  |         val operationResult = multipleValueOperation(number1, number2) | ||||||
|  |         val remainingNumbers = remainingArguments.rest | ||||||
|  | 
 | ||||||
|  |         return if (remainingNumbers.isNull) | ||||||
|  |             operationResult | ||||||
|  |         else | ||||||
|  |             callTailRecursive(Cons(operationResult, remainingNumbers)) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								src/main/kotlin/function/builtin/math/Minus.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/main/kotlin/function/builtin/math/Minus.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | 
 | ||||||
|  | import java.math.BigInteger.ZERO | ||||||
|  | 
 | ||||||
|  | @FunctionNames("-") | ||||||
|  | class Minus(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setMinimumNumberOfArguments(1) | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val mathFunction: MathFunction = MathFunction(this::additiveInverse, this::subtract) | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): LispNumber { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         return mathFunction.callTailRecursive(argumentList) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun additiveInverse(number: LispNumber) = | ||||||
|  |         LispNumber(ZERO - number.value) | ||||||
|  | 
 | ||||||
|  |     private fun subtract(number1: LispNumber, number2: LispNumber) = | ||||||
|  |         LispNumber(number1.value - number2.value) | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								src/main/kotlin/function/builtin/math/Module.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/main/kotlin/function/builtin/math/Module.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import error.LispException | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | import sexpression.SExpression | ||||||
|  | 
 | ||||||
|  | @FunctionNames("MOD", "MODULO", "%") | ||||||
|  | class Module(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(2) | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): SExpression { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         val dividend = argumentList.first as LispNumber | ||||||
|  |         val divisor = (argumentList.rest as Cons).first as LispNumber | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             return LispNumber(dividend.value.mod(divisor.value)) | ||||||
|  |         } catch (e: ArithmeticException) { | ||||||
|  |             throw ModulusNotPositiveException() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class ModulusNotPositiveException : LispException() { | ||||||
|  | 
 | ||||||
|  |         override val message = "modulus not positive" | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/main/kotlin/function/builtin/math/Multiply.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/main/kotlin/function/builtin/math/Multiply.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | import sexpression.LispNumber.Companion.ONE | ||||||
|  | 
 | ||||||
|  | @FunctionNames("*") | ||||||
|  | class Multiply(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val mathFunction: MathFunction = MathFunction({ it }, this::multiply) | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): LispNumber { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         return mathFunction.callTailRecursive(Cons(ONE, argumentList)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun multiply(number1: LispNumber, number2: LispNumber) = | ||||||
|  |         LispNumber(number1.value * number2.value) | ||||||
|  | } | ||||||
| @ -1,31 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "+" }) |  | ||||||
| public class PLUS extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
|     private MathFunction mathFunction; |  | ||||||
| 
 |  | ||||||
|     public PLUS(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|         this.mathFunction = new MathFunction(number -> number, this::add); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public LispNumber call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
| 
 |  | ||||||
|         return mathFunction.callTailRecursive(new Cons(LispNumber.Companion.getZERO(), argumentList)).invoke(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private LispNumber add(LispNumber number1, LispNumber number2) { |  | ||||||
|         return new LispNumber(number1.getValue().add(number2.getValue())); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										26
									
								
								src/main/kotlin/function/builtin/math/Plus.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/main/kotlin/function/builtin/math/Plus.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | 
 | ||||||
|  | @FunctionNames("+") | ||||||
|  | class Plus(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val mathFunction: MathFunction = MathFunction({ it }, this::add) | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): LispNumber { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         return mathFunction.callTailRecursive(Cons(LispNumber.ZERO, argumentList)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun add(number1: LispNumber, number2: LispNumber) = | ||||||
|  |         LispNumber(number1.value + number2.value) | ||||||
|  | } | ||||||
| @ -1,34 +0,0 @@ | |||||||
| package function.builtin.math; |  | ||||||
| 
 |  | ||||||
| import function.ArgumentValidator; |  | ||||||
| import function.FunctionNames; |  | ||||||
| import function.LispFunction; |  | ||||||
| import function.builtin.math.DIVIDE.DivideByZeroException; |  | ||||||
| import sexpression.Cons; |  | ||||||
| import sexpression.LispNumber; |  | ||||||
| import sexpression.SExpression; |  | ||||||
| 
 |  | ||||||
| @FunctionNames({ "REM", "REMAINDER" }) |  | ||||||
| public class REMAINDER extends LispFunction { |  | ||||||
| 
 |  | ||||||
|     private ArgumentValidator argumentValidator; |  | ||||||
| 
 |  | ||||||
|     public REMAINDER(String name) { |  | ||||||
|         this.argumentValidator = new ArgumentValidator(name); |  | ||||||
|         this.argumentValidator.setExactNumberOfArguments(2); |  | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public SExpression call(Cons argumentList) { |  | ||||||
|         argumentValidator.validate(argumentList); |  | ||||||
|         LispNumber dividend = (LispNumber) argumentList.getFirst(); |  | ||||||
|         LispNumber divisor = (LispNumber) ((Cons) argumentList.getRest()).getFirst(); |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             return new LispNumber(dividend.getValue().remainder(divisor.getValue())); |  | ||||||
|         } catch (ArithmeticException e) { |  | ||||||
|             throw new DivideByZeroException(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										31
									
								
								src/main/kotlin/function/builtin/math/Remainder.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/main/kotlin/function/builtin/math/Remainder.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | package function.builtin.math | ||||||
|  | 
 | ||||||
|  | import function.ArgumentValidator | ||||||
|  | import function.FunctionNames | ||||||
|  | import function.LispFunction | ||||||
|  | import function.builtin.math.Divide.DivideByZeroException | ||||||
|  | import sexpression.Cons | ||||||
|  | import sexpression.LispNumber | ||||||
|  | import sexpression.SExpression | ||||||
|  | 
 | ||||||
|  | @FunctionNames("REM", "REMAINDER") | ||||||
|  | class Remainder(name: String) : LispFunction() { | ||||||
|  | 
 | ||||||
|  |     private val argumentValidator = ArgumentValidator(name).apply { | ||||||
|  |         setExactNumberOfArguments(2) | ||||||
|  |         setEveryArgumentExpectedType(LispNumber::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun call(argumentList: Cons): SExpression { | ||||||
|  |         argumentValidator.validate(argumentList) | ||||||
|  | 
 | ||||||
|  |         val dividend = argumentList.first as LispNumber | ||||||
|  |         val divisor = (argumentList.rest as Cons).first as LispNumber | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             return LispNumber(dividend.value % divisor.value) | ||||||
|  |         } catch (e: ArithmeticException) { | ||||||
|  |             throw DivideByZeroException() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,14 +3,10 @@ package function.builtin.predicate | |||||||
| import function.ArgumentValidator | import function.ArgumentValidator | ||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.LispFunction | import function.LispFunction | ||||||
| import recursion.TailCall |  | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.LispNumber | import sexpression.LispNumber | ||||||
| import sexpression.Nil | import sexpression.Nil | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
| 
 |  | ||||||
| import recursion.TailCalls.done |  | ||||||
| import recursion.TailCalls.tailCall |  | ||||||
| import sexpression.Symbol.Companion.T | import sexpression.Symbol.Companion.T | ||||||
| 
 | 
 | ||||||
| @FunctionNames("<") | @FunctionNames("<") | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ import error.LispWarning | |||||||
| import function.ArgumentValidator | import function.ArgumentValidator | ||||||
| import function.LispSpecialFunction | import function.LispSpecialFunction | ||||||
| import function.UserDefinedFunction | import function.UserDefinedFunction | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
| import sexpression.Symbol | import sexpression.Symbol | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| package function.builtin.special | package function.builtin.special | ||||||
| 
 | 
 | ||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.UserDefinedFunction |  | ||||||
| import function.UserDefinedSpecialFunction | import function.UserDefinedSpecialFunction | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| package function.builtin.special | package function.builtin.special | ||||||
| 
 | 
 | ||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.UserDefinedFunction |  | ||||||
| import function.UserDefinedMacro | import function.UserDefinedMacro | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import function.ArgumentValidator | |||||||
| import function.FunctionNames | import function.FunctionNames | ||||||
| import function.LispSpecialFunction | import function.LispSpecialFunction | ||||||
| import function.UserDefinedFunction | import function.UserDefinedFunction | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.LambdaExpression | import sexpression.LambdaExpression | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ import function.FunctionNames | |||||||
| import function.LispSpecialFunction | import function.LispSpecialFunction | ||||||
| import function.builtin.Eval.Companion.eval | import function.builtin.Eval.Companion.eval | ||||||
| import function.builtin.Set.Companion.set | import function.builtin.Set.Companion.set | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
| import sexpression.Symbol | import sexpression.Symbol | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package table | package table | ||||||
| 
 | 
 | ||||||
| import function.builtin.cons.APPEND.append | import function.builtin.cons.Append.Companion.append | ||||||
| import function.builtin.cons.LIST.makeList | import function.builtin.cons.List.Companion.makeList | ||||||
| import sexpression.Cons | import sexpression.Cons | ||||||
| import sexpression.Nil | import sexpression.Nil | ||||||
| import sexpression.SExpression | import sexpression.SExpression | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class APPENDTest extends SymbolAndFunctionCleaner { | public class AppendTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void appendNil() { |     public void appendNil() { | ||||||
| @ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class CONSTest extends SymbolAndFunctionCleaner { | public class ConstructTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void consWithNilValues() { |     public void consWithNilValues() { | ||||||
| @ -10,7 +10,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class FIRSTTest extends SymbolAndFunctionCleaner { | public class FirstTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void firstOfNil() { |     public void firstOfNil() { | ||||||
| @ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class LENGTHTest extends SymbolAndFunctionCleaner { | public class LengthTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void lengthOfNil() { |     public void lengthOfNil() { | ||||||
| @ -3,12 +3,12 @@ package function.builtin.cons; | |||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import testutil.SymbolAndFunctionCleaner; | import testutil.SymbolAndFunctionCleaner; | ||||||
| 
 | 
 | ||||||
| import static function.builtin.cons.LIST.makeList; | import static function.builtin.cons.List.makeList; | ||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class LISTTest extends SymbolAndFunctionCleaner { | public class ListTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void listWithNoArguments() { |     public void listWithNoArguments() { | ||||||
| @ -10,7 +10,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class RESTTest extends SymbolAndFunctionCleaner { | public class RestTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void restOfNil() { |     public void restOfNil() { | ||||||
| @ -2,7 +2,7 @@ package function.builtin.math; | |||||||
| 
 | 
 | ||||||
| import function.ArgumentValidator.BadArgumentTypeException; | import function.ArgumentValidator.BadArgumentTypeException; | ||||||
| import function.ArgumentValidator.TooFewArgumentsException; | import function.ArgumentValidator.TooFewArgumentsException; | ||||||
| import function.builtin.math.DIVIDE.DivideByZeroException; | import function.builtin.math.Divide.DivideByZeroException; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import testutil.SymbolAndFunctionCleaner; | import testutil.SymbolAndFunctionCleaner; | ||||||
| 
 | 
 | ||||||
| @ -11,7 +11,7 @@ import static testutil.TestUtilities.assertSExpressionsMatch; | |||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| import static testutil.TestUtilities.parseString; | import static testutil.TestUtilities.parseString; | ||||||
| 
 | 
 | ||||||
| public class DIVIDETest extends SymbolAndFunctionCleaner { | public class DivideTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void divideWithOne() { |     public void divideWithOne() { | ||||||
| @ -9,7 +9,7 @@ import testutil.SymbolAndFunctionCleaner; | |||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| 
 | 
 | ||||||
| public class MINUSTest extends SymbolAndFunctionCleaner { | public class MinusTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void minusWithOneNumber() { |     public void minusWithOneNumber() { | ||||||
| @ -3,7 +3,7 @@ package function.builtin.math; | |||||||
| import function.ArgumentValidator.BadArgumentTypeException; | import function.ArgumentValidator.BadArgumentTypeException; | ||||||
| import function.ArgumentValidator.TooFewArgumentsException; | import function.ArgumentValidator.TooFewArgumentsException; | ||||||
| import function.ArgumentValidator.TooManyArgumentsException; | import function.ArgumentValidator.TooManyArgumentsException; | ||||||
| import function.builtin.math.MODULO.ModulusNotPositiveException; | import function.builtin.math.Module.ModulusNotPositiveException; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import sexpression.LispNumber; | import sexpression.LispNumber; | ||||||
| import testutil.SymbolAndFunctionCleaner; | import testutil.SymbolAndFunctionCleaner; | ||||||
| @ -12,7 +12,7 @@ import static testutil.TestUtilities.assertIsErrorWithMessage; | |||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| 
 | 
 | ||||||
| public class MODULOTest extends SymbolAndFunctionCleaner { | public class ModuleTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void mod() { |     public void mod() { | ||||||
| @ -8,7 +8,7 @@ import testutil.SymbolAndFunctionCleaner; | |||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| 
 | 
 | ||||||
| public class MULTIPLYTest extends SymbolAndFunctionCleaner { | public class MultiplyTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void multiplyWithNoArguments() { |     public void multiplyWithNoArguments() { | ||||||
| @ -8,7 +8,7 @@ import testutil.SymbolAndFunctionCleaner; | |||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| 
 | 
 | ||||||
| public class PLUSTest extends SymbolAndFunctionCleaner { | public class PlusTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void plusWithNoArguments() { |     public void plusWithNoArguments() { | ||||||
| @ -3,7 +3,7 @@ package function.builtin.math; | |||||||
| import function.ArgumentValidator.BadArgumentTypeException; | import function.ArgumentValidator.BadArgumentTypeException; | ||||||
| import function.ArgumentValidator.TooFewArgumentsException; | import function.ArgumentValidator.TooFewArgumentsException; | ||||||
| import function.ArgumentValidator.TooManyArgumentsException; | import function.ArgumentValidator.TooManyArgumentsException; | ||||||
| import function.builtin.math.DIVIDE.DivideByZeroException; | import function.builtin.math.Divide.DivideByZeroException; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import sexpression.LispNumber; | import sexpression.LispNumber; | ||||||
| import testutil.SymbolAndFunctionCleaner; | import testutil.SymbolAndFunctionCleaner; | ||||||
| @ -11,7 +11,7 @@ import testutil.SymbolAndFunctionCleaner; | |||||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | import static testutil.TestUtilities.assertSExpressionsMatch; | ||||||
| import static testutil.TestUtilities.evaluateString; | import static testutil.TestUtilities.evaluateString; | ||||||
| 
 | 
 | ||||||
| public class REMAINDERTest extends SymbolAndFunctionCleaner { | public class RemainderTest extends SymbolAndFunctionCleaner { | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void rem() { |     public void rem() { | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user