From f3ac693da347e5f00c7f168fcdd4a070303d9ce2 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Tue, 24 Dec 2019 17:31:45 +0000 Subject: [PATCH] Very basic java interop has been added --- src/main/java/serene/simple/ListNode.java | 63 ++++++++++++++++++- src/main/java/serene/simple/RootScope.java | 2 + .../java/serene/simple/builtin/PlusFn.java | 14 +++++ .../java/serene/simple/builtin/QuitFn.java | 2 +- 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/main/java/serene/simple/builtin/PlusFn.java diff --git a/src/main/java/serene/simple/ListNode.java b/src/main/java/serene/simple/ListNode.java index 0ae6165..8f1da6c 100644 --- a/src/main/java/serene/simple/ListNode.java +++ b/src/main/java/serene/simple/ListNode.java @@ -9,6 +9,9 @@ import serene.simple.builtin.AFn; import static java.util.Arrays.asList; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + public class ListNode extends Node implements Iterable { public static final ListNode EMPTY = new ListNode<>(); @@ -47,13 +50,18 @@ public class ListNode extends Node implements Iterable { @Override public Object eval(BaseScope scope) { - Object f = this.first().eval(scope); + SymbolNode firstElement = (SymbolNode) this.first(); List args = new ArrayList(); for (T node : this.rest()) { args.add(node.eval(scope)); } + if (firstElement.name.startsWith(".")) { + return this.evalInterop(scope, firstElement, args.subList(1, args.size())); + } + + Object f = firstElement.eval(scope); if (f instanceof AFn) { return evalBuiltin(scope, (AFn) f, args); } @@ -71,6 +79,59 @@ public class ListNode extends Node implements Iterable { return fn.apply(args.toArray()); } + public Object evalInterop(BaseScope scope, SymbolNode firstElement, List rest) + throws SereneException { + + String mName = firstElement.name.substring(1, firstElement.name.length()); + Object target = this.rest().first().eval(scope); + + if (mName.startsWith("-")) { + return this.evalInteropProperty( + scope, + target, + mName.substring(1, firstElement.name.length())); + } + + try { + System.out.println(target.getClass().getName()); + Method f = target.getClass().getMethod(mName); + return f.invoke(target, rest.toArray()); + } + catch(NoSuchMethodException e) { + throw new SereneException( + String.format( + "Can't find method '%s' on object '%s'.", + mName, + this.rest().first())); + } + catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + throw new SereneException( + String.format( + "Invocation of '%s' failed because of: %s%n", + mName, cause.getMessage())); + } + catch (IllegalAccessException e) { + throw new SereneException( + String.format("Illegal access from '%s'", mName)); + } + } + + public Object evalInteropProperty(BaseScope scope, Object target, String propertyName) + throws SereneException { + try { + Class targetClass = target.getClass(); + return targetClass.getField(propertyName); + } + catch(NoSuchFieldException e) { + throw new SereneException( + String.format( + "Can't find field '%s' on object '%s'.", + propertyName, + target.toString())); + } + } + public T first() { if (this != EMPTY) { return this.first; diff --git a/src/main/java/serene/simple/RootScope.java b/src/main/java/serene/simple/RootScope.java index c26290d..65b0e6f 100644 --- a/src/main/java/serene/simple/RootScope.java +++ b/src/main/java/serene/simple/RootScope.java @@ -3,6 +3,7 @@ package serene.simple; import java.util.HashMap; import serene.simple.builtin.PrintlnFn; import serene.simple.builtin.QuitFn; +import serene.simple.builtin.PlusFn; public class RootScope extends BaseScope { @@ -10,6 +11,7 @@ public class RootScope extends BaseScope { private final HashMap symbolsMapping = new HashMap() {{ put("println", new PrintlnFn()); put("quit", new QuitFn()); + put("+", new PlusFn()); }}; // "+", PlusFn, // "-", MinusFn, diff --git a/src/main/java/serene/simple/builtin/PlusFn.java b/src/main/java/serene/simple/builtin/PlusFn.java new file mode 100644 index 0000000..27821d6 --- /dev/null +++ b/src/main/java/serene/simple/builtin/PlusFn.java @@ -0,0 +1,14 @@ +package serene.simple.builtin; + +import serene.simple.BaseScope; + + +public class PlusFn extends AFn { + public String fnName() { + return "+"; + }; + + public Object eval(BaseScope scope) { + return 0; + } +} diff --git a/src/main/java/serene/simple/builtin/QuitFn.java b/src/main/java/serene/simple/builtin/QuitFn.java index fd14154..ea227a7 100644 --- a/src/main/java/serene/simple/builtin/QuitFn.java +++ b/src/main/java/serene/simple/builtin/QuitFn.java @@ -5,7 +5,7 @@ import serene.simple.BaseScope; public class QuitFn extends AFn { public String fnName() { - return "println"; + return "quit"; }; public Object eval(BaseScope scope) {