diff --git a/src/main/java/serene/simple/AScope.java b/src/main/java/serene/simple/AScope.java new file mode 100644 index 0000000..a9392eb --- /dev/null +++ b/src/main/java/serene/simple/AScope.java @@ -0,0 +1,73 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AScope implements IScope { + private Map symbolsMap = new HashMap(); + + protected IScope parentScope; + + public AScope() { + this(null); + } + + public AScope(IScope parent) { + this.parentScope = parent; + } + + public IScope parent() { + return this.parentScope; + } + + public Map symbols() { + return this.symbolsMap; + } + + public Object lookupSymbol(String symbolName) { + Object value = this.getLocalSymbol(symbolName); + + if (value != null) { + return value; + } + else if (this.parent() != null) { + return this.parent().lookupSymbol(symbolName); + } + else { + throw new RuntimeException( + String.format("Symbol '%s' is not defined in this scope.", symbolName)); + } + } + + public void insertSymbol(String symbolName, Object symbolValue) { + this.symbols().put(symbolName, symbolValue); + } + + protected Object getLocalSymbol(String symbolName) { + if (this.symbols().containsKey(symbolName)) { + return this.symbols().get(symbolName); + } + + return null; + } +} diff --git a/src/main/java/serene/simple/IScope.java b/src/main/java/serene/simple/IScope.java new file mode 100644 index 0000000..112fdf0 --- /dev/null +++ b/src/main/java/serene/simple/IScope.java @@ -0,0 +1,31 @@ +/** + * 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; + +import java.util.Map; + + +public interface IScope { + public IScope parent(); + public Map symbols(); + public Object lookupSymbol(String symbolName); + public void insertSymbol(String symbolName, Object symbolValue); +} diff --git a/src/main/java/serene/simple/RootScope.java b/src/main/java/serene/simple/RootScope.java index b5a0332..22102db 100644 --- a/src/main/java/serene/simple/RootScope.java +++ b/src/main/java/serene/simple/RootScope.java @@ -26,6 +26,7 @@ import serene.simple.builtin.PrintlnFn; import serene.simple.builtin.QuitFn; import serene.simple.builtin.PlusFn; import serene.simple.builtin.MinusFn; +import serene.simple.builtin.TimesFn; import serene.simple.builtin.NewFn; public class RootScope extends AScope { @@ -35,13 +36,14 @@ public class RootScope extends AScope { put("quit", new QuitFn()); put("+", new PlusFn()); put("-", new MinusFn()); + put("*", new TimesFn()); put("System", System.class); put("Boolean", Boolean.class); put("String", String.class); put("new", new NewFn()); }}; - // "*", TimesFn, + // "/", ObelusFn, // "mod", ModFn, // "now", NowFn,; diff --git a/src/main/java/serene/simple/SNumber.java b/src/main/java/serene/simple/SNumber.java index e97b4c3..a1b2e71 100644 --- a/src/main/java/serene/simple/SNumber.java +++ b/src/main/java/serene/simple/SNumber.java @@ -30,6 +30,9 @@ public class SNumber { public IOps subtract(Object x); public IOps subtract(Double x); public IOps subtract(Long x); + public IOps multiply(Object x); + public IOps multiply(Double x); + public IOps multiply(Long x); public Object value(); } @@ -37,10 +40,6 @@ public class SNumber { public static class LongNumber implements IOps { private long v; - public LongNumber() { - this.v = 0; - } - public LongNumber(long v) { this.v = v; } @@ -83,6 +82,25 @@ public class SNumber { return y.subtract(this.v); } + public IOps multiply(Object x) throws SereneException { + if (x instanceof Long) { + return this.multiply((long) x); + } + else if (x instanceof Double) { + return this.multiply((Double) x); + } + throw new SereneException("Can't cast anything beside Long and Double"); + } + + public IOps multiply(Long x) { + return new LongNumber(this.v * x); + } + + public IOps multiply(Double x) { + DoubleNumber y = new DoubleNumber(x); + return y.multiply(this.v); + } + public Object value() { return this.v; } @@ -131,6 +149,24 @@ public class SNumber { return new DoubleNumber(this.v - x.doubleValue()); } + public IOps multiply(Object x) throws SereneException { + if (x instanceof Long) { + return this.multiply((long) x); + } + else if (x instanceof Double) { + return this.multiply((Double) x); + } + throw new SereneException("Can't cast anything beside Long and Double"); + } + + public IOps multiply(Double x) { + return new DoubleNumber(this.v * x); + } + + public IOps multiply(Long x) { + return new DoubleNumber(this.v * x.doubleValue()); + } + public Object value() { return this.v; } diff --git a/src/main/java/serene/simple/builtin/MinusFn.java b/src/main/java/serene/simple/builtin/MinusFn.java new file mode 100644 index 0000000..393932b --- /dev/null +++ b/src/main/java/serene/simple/builtin/MinusFn.java @@ -0,0 +1,52 @@ +/** + * 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 MinusFn 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."); + } + + SNumber.IOps result = SNumber.createNumber(args.get(0)); + + try { + for(Object x: args.subList(1, args.size())) { + result = (SNumber.IOps) result.subtract(x); + } + } + catch (IndexOutOfBoundsException e) {} + return result.value(); + } +} diff --git a/src/main/java/serene/simple/builtin/PlusFn.java b/src/main/java/serene/simple/builtin/PlusFn.java index d0b6e0f..1354a9b 100644 --- a/src/main/java/serene/simple/builtin/PlusFn.java +++ b/src/main/java/serene/simple/builtin/PlusFn.java @@ -30,7 +30,7 @@ public class PlusFn extends AFn { }; public Object eval(IScope scope) throws SereneException{ - SNumber.IOps result = (SNumber.IOps) new SNumber.LongNumber(); + SNumber.IOps result = (SNumber.IOps) new SNumber.LongNumber(0); for(Object x: this.arguments()) { result = (SNumber.IOps) result.add(x); diff --git a/src/main/java/serene/simple/builtin/TimesFn.java b/src/main/java/serene/simple/builtin/TimesFn.java new file mode 100644 index 0000000..ac6473e --- /dev/null +++ b/src/main/java/serene/simple/builtin/TimesFn.java @@ -0,0 +1,41 @@ +/** + * 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 serene.simple.IScope; +import serene.simple.SNumber; +import serene.simple.SereneException; + + +public class TimesFn extends AFn { + public String fnName() { + return "*"; + }; + + public Object eval(IScope scope) throws SereneException{ + SNumber.IOps result = (SNumber.IOps) new SNumber.LongNumber(1); + + for(Object x: this.arguments()) { + result = (SNumber.IOps) result.multiply(x); + } + + return result.value(); + } +}