diff --git a/src/main/java/serene/simple/Main.java b/src/main/java/serene/simple/Main.java index 59ed95b..ec9d388 100644 --- a/src/main/java/serene/simple/Main.java +++ b/src/main/java/serene/simple/Main.java @@ -24,7 +24,22 @@ import java.io.ByteArrayInputStream; import java.io.Console; import java.io.FileInputStream; - +/** + * What is missing: + * * A namespace functionality. Because creating and compiling dynamic classes + * is a rabbit hole and tons of work which doesn't make sense for a toy + * project. + * * Unified function interface. + * * Requiring different namespaces + * * A sophisticated parser. My Reader implementation is really cheap that + * suits a toy project. It might worth investigating on different solutions + * including using a parser generator or a head of time read implementation. + * * Primitive functions in Serene. I implemented lots of primitive functions + * in java rather than Serene itself mostly because of two reasons. Lack of + * macros and namespaces. + * * Quality code. The general quality of this implementation is not great, I + * sacrificed quality for time. + */ public class Main { private static String licenseHeader = "\nSerene(simple), Copyright (C) 2019-2020 " + "Sameer Rahmani \n" + diff --git a/src/main/java/serene/simple/RootScope.java b/src/main/java/serene/simple/RootScope.java index ac64d8b..5bee134 100644 --- a/src/main/java/serene/simple/RootScope.java +++ b/src/main/java/serene/simple/RootScope.java @@ -37,9 +37,12 @@ public class RootScope extends AScope { put("mod", new ModFn()); put("=", new EqFn()); put(">", new GtFn()); - // put("<", new LtFn()); - // put("<=", new LteFn()); - // put(">=", new GteFn()); + put(">=", new GteFn()); + put("<", new LtFn()); + put("<=", new LteFn()); + put("and", new AndFn()); + put("or", new OrFn()); + put("not", new NotFn()); put("System", System.class); put("Boolean", Boolean.class); put("String", String.class); diff --git a/src/main/java/serene/simple/SNumber.java b/src/main/java/serene/simple/SNumber.java index 6272478..806a175 100644 --- a/src/main/java/serene/simple/SNumber.java +++ b/src/main/java/serene/simple/SNumber.java @@ -19,11 +19,7 @@ */ package serene.simple; - -import java.util.Collection; -import java.util.Collections; import java.util.List; - import serene.simple.SereneException; @@ -46,8 +42,17 @@ public class SNumber { public IOps mod(Long x); public boolean gt(boolean acc, List xs); + public boolean gte(boolean acc, List xs); + public boolean lt(boolean acc, List xs); + public boolean lte(boolean acc, List xs); public Object value(); + } + + public abstract static class ANumber { + + + } public static class LongNumber implements IOps { @@ -166,12 +171,46 @@ public class SNumber { return true; } - public boolean gt(Long x) { - return this.v > x; + public boolean gte(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v >= (x instanceof Long ? (long) x : (double) x))) { + return false; + } + } + + return true; } - public boolean gt(Double x) { - return this.v > x; + public boolean lt(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v < (x instanceof Long ? (long) x : (double) x))) { + return false; + } + } + + return true; + } + + public boolean lte(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v <= (x instanceof Long ? (long) x : (double) x))) { + return false; + } + } + + return true; } public Object value() { @@ -280,16 +319,59 @@ public class SNumber { } public boolean gt(boolean acc, List xs) { - if (xs.size() > 1) { - IOps next = SNumber.createNumber(xs.get(0)); - return next.gt(this.v > (double) next.value(), xs.subList(1, xs.size())); + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + if (!(this.v > (x instanceof Long ? (long) x : (double) x))) { + return false; + } } - else if (xs.size() == 1){ - IOps next = SNumber.createNumber(xs.get(0)); - return this.v > (double) next.value(); + + return true; + } + + public boolean gte(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v >= (x instanceof Long ? (long) x : (double) x))) { + return false; + } } - return acc; + + return true; + } + + public boolean lt(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v < (x instanceof Long ? (long) x : (double) x))) { + return false; + } + } + + return true; + } + + public boolean lte(boolean acc, List xs) { + for(Object x: xs) { + if (!(x instanceof Number)) { + throw new SereneException("Only number parameters can be use with '>' function."); + } + + if (!(this.v <= (x instanceof Long ? (long) x : (double) x))) { + return false; + } + } + + return true; } public Object value() { diff --git a/src/main/java/serene/simple/builtin/AndFn.java b/src/main/java/serene/simple/builtin/AndFn.java new file mode 100644 index 0000000..e0f5d2f --- /dev/null +++ b/src/main/java/serene/simple/builtin/AndFn.java @@ -0,0 +1,56 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SereneException; + + +public class AndFn extends AFn { + public String fnName() { + return "and"; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() == 0) { + return true; + } + + if (args.size() == 1) { + return args.get(0); + } + + Object next = true; + + for (Object x : args) { + next = x; + if (x != null && x != Boolean.FALSE) + continue; + break; + } + + return next; + + } +} diff --git a/src/main/java/serene/simple/builtin/GteFn.java b/src/main/java/serene/simple/builtin/GteFn.java new file mode 100644 index 0000000..d921067 --- /dev/null +++ b/src/main/java/serene/simple/builtin/GteFn.java @@ -0,0 +1,49 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SNumber; +import serene.simple.SereneException; + + +public class GteFn extends AFn { + public String fnName() { + return ">="; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() == 0) { + throw new SereneException( + "ArityError: You need 1 or more parameters for this functions."); + } + + if (args.size() == 1) { + return true; + } + + SNumber.IOps result = SNumber.createNumber(args.get(0)); + return result.gte(true, args.subList(1, args.size())); + } +} diff --git a/src/main/java/serene/simple/builtin/LtFn.java b/src/main/java/serene/simple/builtin/LtFn.java new file mode 100644 index 0000000..48b6c0a --- /dev/null +++ b/src/main/java/serene/simple/builtin/LtFn.java @@ -0,0 +1,49 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SNumber; +import serene.simple.SereneException; + + +public class LtFn extends AFn { + public String fnName() { + return "<"; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() == 0) { + throw new SereneException( + "ArityError: You need 1 or more parameters for this functions."); + } + + if (args.size() == 1) { + return true; + } + + SNumber.IOps result = SNumber.createNumber(args.get(0)); + return result.lt(true, args.subList(1, args.size())); + } +} diff --git a/src/main/java/serene/simple/builtin/LteFn.java b/src/main/java/serene/simple/builtin/LteFn.java new file mode 100644 index 0000000..99d4272 --- /dev/null +++ b/src/main/java/serene/simple/builtin/LteFn.java @@ -0,0 +1,49 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SNumber; +import serene.simple.SereneException; + + +public class LteFn extends AFn { + public String fnName() { + return "<="; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() == 0) { + throw new SereneException( + "ArityError: You need 1 or more parameters for this functions."); + } + + if (args.size() == 1) { + return true; + } + + SNumber.IOps result = SNumber.createNumber(args.get(0)); + return result.lte(true, args.subList(1, args.size())); + } +} diff --git a/src/main/java/serene/simple/builtin/NotFn.java b/src/main/java/serene/simple/builtin/NotFn.java new file mode 100644 index 0000000..2bc6109 --- /dev/null +++ b/src/main/java/serene/simple/builtin/NotFn.java @@ -0,0 +1,47 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SereneException; + + +public class NotFn extends AFn { + public String fnName() { + return "not"; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() != 1) { + throw new SereneException( + String.format("Wrong arity for 'not'. Got: %s", args.size())); + } + Object x = args.get(0); + + if (x != null && x != Boolean.FALSE) { + return Boolean.FALSE; + } + return Boolean.TRUE; + } +} diff --git a/src/main/java/serene/simple/builtin/OrFn.java b/src/main/java/serene/simple/builtin/OrFn.java new file mode 100644 index 0000000..b1c6393 --- /dev/null +++ b/src/main/java/serene/simple/builtin/OrFn.java @@ -0,0 +1,55 @@ +/** + * Serene (simple) - A PoC lisp to collect data on Serenes concepts + * Copyright (C) 2019-2020 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package serene.simple.builtin; + +import java.util.List; + +import serene.simple.IScope; +import serene.simple.SereneException; + + +public class OrFn extends AFn { + public String fnName() { + return "or"; + }; + + public Object eval(IScope scope) throws SereneException{ + List args = this.arguments(); + + if (args.size() == 0) { + return null; + } + + if (args.size() == 1) { + return args.get(0); + } + + Object next = false; + + for (Object x : args) { + next = x; + if (x != null || x != Boolean.FALSE) + break; + continue; + } + + return next; + } +}