Initial commit of OSGi Shell contribution. (FELIX-946)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@783826 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/src/aQute/shell/runtime/Closure.java b/gogo/src/aQute/shell/runtime/Closure.java
new file mode 100644
index 0000000..00a297b
--- /dev/null
+++ b/gogo/src/aQute/shell/runtime/Closure.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package aQute.shell.runtime;
+
+import java.util.*;
+
+import org.osgi.service.command.*;
+
+public class Closure extends Reflective implements Function {
+ private static final long serialVersionUID = 1L;
+ final CharSequence source;
+ final Closure parent;
+ CommandSessionImpl session;
+ List<Object> parms;
+
+ Closure(CommandSessionImpl session, Closure parent, CharSequence source) {
+ this.session = session;
+ this.parent = parent;
+ this.source = source;
+ }
+
+ public Object execute(CommandSession x, List<Object> values)
+ throws Exception {
+ parms = values;
+ Parser parser = new Parser(source);
+ ArrayList<Pipe> pipes = new ArrayList<Pipe>();
+ List<List<List<CharSequence>>> program = parser.program();
+
+ for (List<List<CharSequence>> statements : program) {
+ Pipe current = new Pipe(this, statements);
+
+ if (pipes.isEmpty()) {
+ current.setIn(session.in);
+ current.setOut(session.out);
+ } else {
+ Pipe previous = pipes.get(pipes.size() - 1);
+ previous.connect(current);
+ }
+ pipes.add(current);
+ }
+ if (pipes.size() == 0)
+ return null;
+
+ if (pipes.size() == 1) {
+ pipes.get(0).run();
+ } else {
+ for (Pipe pipe : pipes) {
+ pipe.start();
+ }
+ for (Pipe pipe : pipes) {
+ pipe.join();
+ }
+ }
+
+ Pipe last = pipes.get(pipes.size() - 1);
+ if (last.exception != null)
+ throw last.exception;
+
+ if (last.result instanceof Object[]) {
+ return Arrays.asList((Object[]) last.result);
+ }
+ return last.result;
+ }
+
+ Object executeStatement(List<CharSequence> statement) throws Exception {
+ Object result;
+ List<Object> values = new ArrayList<Object>();
+ Object cmd = eval(statement.remove(0));
+ for (CharSequence token : statement)
+ values.add(eval(token));
+
+ result = execute(cmd, values);
+ return result;
+ }
+
+ private Object execute(Object cmd, List<Object> values) throws Exception {
+ if (cmd == null) {
+ if (values.isEmpty())
+ return null;
+ else
+ throw new IllegalArgumentException(
+ "Command name evaluates to null");
+ }
+
+ // Now there are the following cases
+ // <string> '=' statement // complex assignment
+ // <string> statement // cmd call
+ // <object> // value of <object>
+ // <object> statement // method call
+
+ if (cmd instanceof CharSequence) {
+ String scmd = cmd.toString();
+
+ if (values.size() > 0 && "=".equals(values.get(0))) {
+ if (values.size() == 0)
+ return session.variables.remove(scmd);
+ else {
+ Object value = execute(values.get(1), values.subList(2,
+ values.size()));
+ return assignment(scmd, value);
+ }
+ } else {
+ String scopedFunction = scmd;
+ Object x = get(scmd);
+ if ( !(x instanceof Function) ) {
+ if (scmd.indexOf(':') < 0) {
+ scopedFunction = "*:" + scmd;
+ }
+ x = get(scopedFunction);
+ if (x == null || !(x instanceof Function)) {
+ if (values.isEmpty())
+ return scmd;
+ throw new IllegalArgumentException("Command not found: "
+ + scopedFunction);
+ }
+ }
+ return ((Function) x).execute(session, values);
+ }
+ } else {
+ if (values.isEmpty())
+ return cmd;
+ else
+ return method(session, cmd, values.remove(0).toString(), values);
+ }
+ }
+
+ private Object assignment(Object name, Object value) {
+ session.variables.put(name, value);
+ return value;
+ }
+
+ private Object eval(CharSequence seq) throws Exception {
+ int end = seq.length();
+ switch (seq.charAt(0)) {
+ case '$':
+ return var(seq);
+ case '<':
+ Closure c = new Closure(session, this, seq.subSequence(1, end - 1));
+ return c.execute(session, parms);
+ case '[':
+ return array(seq.subSequence(1, end - 1));
+
+ case '{':
+ return new Closure(session, this, seq.subSequence(1, end - 1));
+
+ default:
+ String result = new Parser(seq).unescape();
+ if ("null".equals(result))
+ return null;
+ if ("true".equalsIgnoreCase(result))
+ return true;
+ if ("false".equalsIgnoreCase(result))
+ return false;
+ return seq;
+ }
+ }
+
+ private Object array(CharSequence array) throws Exception {
+ List<Object> list = new ArrayList<Object>();
+ Map<Object, Object> map = new LinkedHashMap<Object, Object>();
+ Parser p = new Parser(array);
+
+ while (!p.eof()) {
+ CharSequence token = p.value();
+
+ p.ws();
+ if (p.peek() == '=') {
+ p.next();
+ p.ws();
+ if (!p.eof()) {
+ CharSequence value = p.messy();
+ map.put(eval(token), eval(value));
+ }
+ } else
+ list.add(eval(token));
+
+ if (p.peek() == ',')
+ p.next();
+ p.ws();
+ }
+ p.ws();
+ if (!p.eof())
+ throw new IllegalArgumentException("Invalid array syntax: " + array);
+
+ if (map.size() != 0 && list.size() != 0)
+ throw new IllegalArgumentException(
+ "You can not mix maps and arrays: " + array);
+
+ if (map.size() > 0)
+ return map;
+ else
+ return list;
+ }
+
+ private Object var(CharSequence var) throws Exception {
+ String name = eval(var.subSequence(1, var.length())).toString();
+ return get(name);
+ }
+
+ /**
+ *
+ * @param name
+ * @return
+ */
+ private Object get(String name) {
+ if (parms != null) {
+ if ("it".equals(name))
+ return parms.get(0);
+ if ("args".equals(name))
+ return parms;
+
+ if (name.length() == 1 && Character.isDigit(name.charAt(0)))
+ return parms.get(name.charAt(0) - '0');
+ }
+ return session.get(name);
+ }
+}