Improve procedural, add loop break command
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1736047 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
index d1bf87e..054b2f1 100644
--- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
+++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
@@ -18,102 +18,303 @@
*/
package org.apache.felix.gogo.jline;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Function;
+import org.jline.builtins.Options;
public class Procedural {
- static final String[] functions = {"each", "if", "not", "throw", "try", "until", "while"};
+ static final String[] functions = {"each", "if", "not", "throw", "try", "until", "while", "break"};
- public List<Object> each(CommandSession session, Collection<Object> list,
- Function closure) throws Exception {
+ public void _main(CommandSession session, Object[] argv) throws Throwable {
+ if (argv == null || argv.length < 1) {
+ throw new IllegalArgumentException();
+ }
+ try {
+ run(session, argv);
+ } catch (IllegalArgumentException e) {
+ System.err.println(e.getMessage());
+ session.error(2);
+ } catch (HelpException e) {
+ System.err.println(e.getMessage());
+ session.error(0);
+ } catch (ThrownException e) {
+ session.error(1);
+ throw e.getCause();
+ } catch (Exception e) {
+ System.err.println(argv[0] + ": " + e.getMessage());
+ session.error(1);
+ }
+ }
+
+ protected static class HelpException extends Exception {
+ public HelpException(String message) {
+ super(message);
+ }
+ }
+
+ protected static class ThrownException extends Exception {
+ public ThrownException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ protected static class BreakException extends Exception {
+ }
+
+ protected Options parseOptions(CommandSession session, String[] usage, Object[] argv) throws HelpException {
+ Options opt = Options.compile(usage, s -> get(session, s)).parse(argv, true);
+ if (opt.isSet("help")) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ opt.usage(new PrintStream(baos));
+ throw new HelpException(baos.toString());
+ }
+ return opt;
+ }
+
+ protected String get(CommandSession session, String name) {
+ Object o = session.get(name);
+ return o != null ? o.toString() : null;
+ }
+
+ protected Object run(CommandSession session, Object[] argv) throws Throwable {
+ switch (argv[0].toString()) {
+ case "each":
+ return doEach(session, argv);
+ case "if":
+ return doIf(session, argv);
+ case "not":
+ return doNot(session, argv);
+ case "throw":
+ return doThrow(session, argv);
+ case "try":
+ return doTry(session, argv);
+ case "until":
+ return doUntil(session, argv);
+ case "while":
+ return doWhile(session, argv);
+ case "break":
+ return doBreak(session, argv);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ protected List<Object> doEach(CommandSession session,
+ Object[] argv) throws Exception {
+ String[] usage = {
+ "each - loop over the elements",
+ "Usage: each [-r] elements { closure }",
+ " elements an array to iterate on",
+ " closure a closure to call",
+ " -? --help Show help",
+ " -r --result Return a list containing each iteration result",
+ };
+ Options opt = parseOptions(session, usage, argv);
+
+ Collection<Object> elements = getElements(opt);
+ List<Function> functions = getFunctions(opt);
+
+ if (elements == null || functions == null || functions.size() != 1) {
+ System.err.println("usage: each elements { closure }");
+ System.err.println(" elements: an array to iterate on");
+ System.err.println(" closure: a function or closure to call");
+ session.error(2);
+ return null;
+ }
+
List<Object> args = new ArrayList<>();
List<Object> results = new ArrayList<>();
args.add(null);
- for (Object x : list) {
+ for (Object x : elements) {
checkInterrupt();
args.set(0, x);
- results.add(closure.execute(session, args));
- }
-
- return results;
- }
-
- public Object _if(CommandSession session, Function[] fns) throws Exception {
- int length = fns.length;
- if (length < 2) {
- throw new IllegalArgumentException(
- "Usage: if {condition} {if-action} ... {else-action}");
- }
-
- for (int i = 0; i < length; ++i) {
- if (i == length - 1 || isTrue(fns[i++].execute(session, null))) {
- return fns[i].execute(session, null);
+ try {
+ results.add(functions.get(0).execute(session, args));
+ } catch (BreakException b) {
+ break;
}
}
+ return opt.isSet("result") ? results : null;
+ }
+
+ protected Object doIf(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "if - if / then / else construct",
+ "Usage: if {condition} {if-action} ... {else-action}",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ List<Function> functions = getFunctions(opt);
+ if (functions == null || functions.size() < 2) {
+ System.err.println("usage: if {condition} {if-action} ... {else-action}");
+ session.error(2);
+ return null;
+ }
+ for (int i = 0, length = functions.size(); i < length; ++i) {
+ if (i == length - 1 || isTrue(session, ((Function) opt.argObjects().get(i++)))) {
+ return ((Function) opt.argObjects().get(i)).execute(session, null);
+ }
+ }
return null;
}
- public boolean not(CommandSession session, Function condition) throws Exception {
- return condition == null || !isTrue(condition.execute(session, null));
-
- }
-
- // Reflective.coerce() prefers to construct a new Throwable(String)
- // than to call this method directly.
- public void _throw(String message) {
- throw new IllegalArgumentException(message);
- }
-
- public void _throw(Exception e) throws Exception {
- throw e;
- }
-
- public void _throw(CommandSession session) throws Throwable {
- Object exception = session.get("exception");
- if (exception instanceof Throwable)
- throw (Throwable) exception;
- else
- throw new IllegalArgumentException("exception not set or not Throwable.");
- }
-
- public Object _try(CommandSession session, Function func) throws Exception {
- try {
- return func.execute(session, null);
- } catch (Exception e) {
- session.put("exception", e);
+ protected Boolean doNot(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "not - return the opposite condition",
+ "Usage: not { condition }",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ List<Function> functions = getFunctions(opt);
+ if (functions == null || functions.size() != 1) {
+ System.err.println("usage: not { condition }");
+ session.error(2);
return null;
}
+ return !isTrue(session, functions.get(0));
+
}
- public Object _try(CommandSession session, Function func, Function error)
- throws Exception {
+ protected Object doThrow(CommandSession session, Object[] argv) throws ThrownException, HelpException {
+ String[] usage = {
+ "throw - throw an exception",
+ "Usage: throw [ message [ cause ] ]",
+ " throw exception",
+ " throw",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ if (opt.argObjects().size() == 0) {
+ Object exception = session.get("exception");
+ if (exception instanceof Throwable)
+ throw new ThrownException((Throwable) exception);
+ else
+ throw new ThrownException(new Exception());
+ }
+ else if (opt.argObjects().size() == 1 && opt.argObjects().get(0) instanceof Throwable) {
+ throw new ThrownException((Throwable) opt.argObjects().get(0));
+ }
+ else {
+ String message = opt.argObjects().get(0).toString();
+ Throwable cause = null;
+ if (opt.argObjects().size() > 1) {
+ if (opt.argObjects().get(1) instanceof Throwable) {
+ cause = (Throwable) opt.argObjects().get(1);
+ }
+ }
+ throw new ThrownException(new Exception(message).initCause(cause));
+ }
+ }
+
+ protected Object doTry(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "try - try / catch / finally construct",
+ "Usage: try { try-action } [ { catch-action } [ { finally-action } ] ]",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ List<Function> functions = getFunctions(opt);
+ if (functions == null || functions.size() < 1 || functions.size() > 3) {
+ System.err.println("usage: try { try-action } [ { catch-action } [ { finally-action } ] ]");
+ session.error(2);
+ return null;
+ }
try {
- return func.execute(session, null);
+ return functions.get(0).execute(session, null);
+ } catch (BreakException b) {
+ throw b;
} catch (Exception e) {
session.put("exception", e);
- return error.execute(session, null);
+ if (functions.size() > 1) {
+ functions.get(1).execute(session, null);
+ }
+ return null;
+ } finally {
+ if (functions.size() > 2) {
+ functions.get(2).execute(session, null);
+ }
}
}
- public void _while(CommandSession session, Function condition, Function ifTrue)
- throws Exception {
- while (isTrue(condition.execute(session, null))) {
- ifTrue.execute(session, null);
+ protected Object doWhile(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "while - while loop",
+ "Usage: while { condition } { action }",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ List<Function> functions = getFunctions(opt);
+ if (functions == null || functions.size() != 2) {
+ System.err.println("usage: while { condition } { action }");
+ session.error(2);
+ return null;
}
+ while (isTrue(session, functions.get(0))) {
+ try {
+ functions.get(1).execute(session, null);
+ } catch (BreakException b) {
+ break;
+ }
+ }
+ return null;
}
- public void until(CommandSession session, Function condition, Function ifTrue)
- throws Exception {
- while (!isTrue(condition.execute(session, null))) {
- ifTrue.execute(session, null);
+ protected Object doUntil(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "until - until loop",
+ "Usage: until { condition } { action }",
+ " -? --help Show help",
+ };
+ Options opt = parseOptions(session, usage, argv);
+ List<Function> functions = new ArrayList<>();
+ for (Object o : opt.argObjects()) {
+ if (o instanceof Function) {
+ functions.add((Function) o);
+ }
+ else {
+ functions = null;
+ break;
+ }
}
+ int length = opt.argObjects().size();
+ if (length != 2 || functions == null) {
+ System.err.println("usage: until { condition } { action }");
+ session.error(2);
+ return null;
+ }
+ while (!isTrue(session, functions.get(0))) {
+ try {
+ functions.get(1).execute(session, null);
+ } catch (BreakException b) {
+ break;
+ }
+ }
+ return null;
+ }
+
+ protected Object doBreak(CommandSession session, Object[] argv) throws Exception {
+ String[] usage = {
+ "break - break from loop",
+ "Usage: break",
+ " -? --help Show help",
+ };
+ parseOptions(session, usage, argv);
+ throw new BreakException();
+ }
+
+ private boolean isTrue(CommandSession session, Function function) throws Exception {
+ checkInterrupt();
+ return isTrue(function.execute(session, null));
}
private boolean isTrue(Object result) throws InterruptedException {
@@ -141,6 +342,35 @@
private void checkInterrupt() throws InterruptedException {
if (Thread.currentThread().isInterrupted())
- throw new InterruptedException("loop interrupted");
+ throw new InterruptedException("interrupted");
}
+
+ @SuppressWarnings("unchecked")
+ private Collection<Object> getElements(Options opt) {
+ Collection<Object> elements = null;
+ if (opt.argObjects().size() > 0) {
+ Object o = opt.argObjects().remove(0);
+ if (o instanceof Collection) {
+ elements = (Collection<Object>) o;
+ } else if (o != null && o.getClass().isArray()) {
+ elements = Arrays.asList((Object[]) o);
+ }
+ }
+ return elements;
+ }
+
+ private List<Function> getFunctions(Options opt) {
+ List<Function> functions = new ArrayList<>();
+ for (Object o : opt.argObjects()) {
+ if (o instanceof Function) {
+ functions.add((Function) o);
+ }
+ else {
+ functions = null;
+ break;
+ }
+ }
+ return functions;
+ }
+
}
diff --git a/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java
index 8d6e27c..74a3127 100644
--- a/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java
+++ b/gogo/jline/src/test/java/org/apache/felix/gogo/jline/ShellTest.java
@@ -35,6 +35,13 @@
}
@Test
+ public void testLoopBreak() throws Exception {
+ Context context = new Context();
+ Object result = context.execute("$(each {1..10} { i = $it; if { %(i >= 5) } { break } ; echo $i })");
+ Assert.assertEquals("1\n2\n3\n4", result);
+ }
+
+ @Test
public void testJobIds() throws Exception {
Context context = new Context();
// TODO: not than in zsh, the same thing is achieved using
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java
index f64d6ea..28e3aa9 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java
@@ -63,6 +63,7 @@
Method[] methods = target.getClass().getMethods();
name = name.toLowerCase();
+ String org = name;
String get = "get" + name;
String is = "is" + name;
String set = "set" + name;
@@ -105,7 +106,7 @@
// multiple commands
if (mname.equals(MAIN))
{
- xargs.add(0, name);
+ xargs.add(0, org);
}
Object[] parms = new Object[types.length];