Package org.jnode.shell.bjorne

Source Code of org.jnode.shell.bjorne.BjorneInterpreter

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell.bjorne;

import static org.jnode.shell.bjorne.BjorneToken.TOK_CLOBBER;
import static org.jnode.shell.bjorne.BjorneToken.TOK_DGREAT;
import static org.jnode.shell.bjorne.BjorneToken.TOK_DLESS;
import static org.jnode.shell.bjorne.BjorneToken.TOK_DLESSDASH;
import static org.jnode.shell.bjorne.BjorneToken.TOK_GREAT;
import static org.jnode.shell.bjorne.BjorneToken.TOK_GREATAND;
import static org.jnode.shell.bjorne.BjorneToken.TOK_LESS;
import static org.jnode.shell.bjorne.BjorneToken.TOK_LESSAND;
import static org.jnode.shell.bjorne.BjorneToken.TOK_LESSGREAT;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.jnode.shell.CommandInterpreter;
import org.jnode.shell.CommandLine;
import org.jnode.shell.CommandShell;
import org.jnode.shell.Completable;
import org.jnode.shell.ShellException;
import org.jnode.shell.ShellFailureException;
import org.jnode.shell.ShellSyntaxException;
import org.jnode.shell.io.CommandIO;
import org.jnode.shell.io.CommandOutput;
import org.jnode.vm.VmExit;

/**
* This is the JNode implementation of the Bourne Shell language.  The long term
* goal is to faithfully implement the POSIX Shell specification.
*
* @author crawley@jnode.org
*/
public class BjorneInterpreter implements CommandInterpreter {

    public static final int CMD_EMPTY = 0;

    public static final int CMD_COMMAND = 1;

    public static final int CMD_LIST = 2;

    public static final int CMD_FOR = 3;

    public static final int CMD_WHILE = 4;

    public static final int CMD_UNTIL = 5;

    public static final int CMD_IF = 6;

    public static final int CMD_ELIF = 7;

    public static final int CMD_ELSE = 8;

    public static final int CMD_CASE = 9;

    public static final int CMD_SUBSHELL = 10;

    public static final int CMD_BRACE_GROUP = 11;

    public static final int CMD_FUNCTION_DEF = 12;

    public static final int BRANCH_BREAK = 1;

    public static final int BRANCH_CONTINUE = 2;

    public static final int BRANCH_EXIT = 3;

    public static final int BRANCH_RETURN = 4;

    public static final int REDIR_LESS = TOK_LESS;

    public static final int REDIR_GREAT = TOK_GREAT;

    public static final int REDIR_DLESS = TOK_DLESS;

    public static final int REDIR_DLESSDASH = TOK_DLESSDASH;

    public static final int REDIR_DGREAT = TOK_DGREAT;

    public static final int REDIR_LESSAND = TOK_LESSAND;

    public static final int REDIR_GREATAND = TOK_GREATAND;

    public static final int REDIR_LESSGREAT = TOK_LESSGREAT;

    public static final int REDIR_CLOBBER = TOK_CLOBBER;

    public static final int FLAG_ASYNC = 0x0001;

    public static final int FLAG_AND_IF = 0x0002;

    public static final int FLAG_OR_IF = 0x0004;

    public static final int FLAG_BANG = 0x0008;

    public static final int FLAG_PIPE = 0x0010;

    public static final CommandNode EMPTY =
        new SimpleCommandNode(CMD_EMPTY, new BjorneToken[0]);

    static HashMap<String, BjorneBuiltin.Factory> BUILTINS =
        new HashMap<String, BjorneBuiltin.Factory>();
   
    private static boolean DEBUG = false;
   
    private static long subshellCount;

    static {
        BUILTINS.put("alias", AliasBuiltin.FACTORY);
        BUILTINS.put("break", BreakBuiltin.FACTORY);
        BUILTINS.put("continue", ContinueBuiltin.FACTORY);
        BUILTINS.put("exit", ExitBuiltin.FACTORY);
        BUILTINS.put("export", ExportBuiltin.FACTORY);
        BUILTINS.put("read", ReadBuiltin.FACTORY);
        BUILTINS.put("readonly", ReadonlyBuiltin.FACTORY);
        BUILTINS.put("return", ReturnBuiltin.FACTORY);
        BUILTINS.put("set", SetBuiltin.FACTORY);
        BUILTINS.put("shift", ShiftBuiltin.FACTORY);
        BUILTINS.put("source", SourceBuiltin.FACTORY);
        BUILTINS.put("unalias", UnaliasBuiltin.FACTORY);
        BUILTINS.put("unset", UnsetBuiltin.FACTORY);
        BUILTINS.put(".", SourceBuiltin.FACTORY);
        BUILTINS.put(":", ColonBuiltin.FACTORY);
    }

    private CommandShell shell;

    private BjorneContext context;
   
    private BjorneParser parser;
   
    private Reader reader;

    public BjorneInterpreter() {
        this.context = new BjorneContext(this);
    }

    @Override
    public String getName() {
        return "bjorne";
    }

    @Override
    public synchronized Completable parsePartial(CommandShell shell, String partial) throws ShellSyntaxException {
        bindShell(shell);
        BjorneTokenizer tokens = new BjorneTokenizer(partial);
        BjorneCompleter completer = new BjorneCompleter(context);
        try {
            parser = new BjorneParser(tokens);
            parser.parse(completer);
        } catch (ShellSyntaxException ex) {
            if (DEBUG) {
                System.err.println("exception in parsePartial: " + ex);
                ex.printStackTrace();
            }
        } finally {
            parser = null;
        }
        return completer;
    }
   
    @Override
    public synchronized boolean help(CommandShell shell, String partial, PrintWriter pw) throws ShellException {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public String escapeWord(String word) {
        // FIXME ... do this properly
        if (word.indexOf(' ') == -1 && word.indexOf('\t') == -1) {
            return word;
        } else {
            return "'" + word + "'";
        }
    }

    synchronized int interpret(CommandShell shell, Reader reader, boolean script,
            StringWriter capture, boolean source)
        throws ShellException {
        BjorneContext myContext;
        if (capture == null) {
            bindShell(shell);
            myContext = this.context;
        } else {
            myContext = new BjorneContext(this);
            myContext.setIO(1, new CommandOutput(capture), true);
        }
        BjorneTokenizer tokens = new BjorneTokenizer(reader);
        // (Save the current parser and reader objects in the case where we are called
        // recursively ... to interpret a back-tick command.)
        BjorneParser savedParser = this.parser;
        Reader savedReader = this.reader;
        this.reader = reader;
        parser = new BjorneParser(tokens);
        try {
            do {
                CommandNode tree = this.parser.parse();
                if (tree == null) {
                    break;
                }
                if (DEBUG) {
                    System.err.println(tree);
                }
                tree.execute((BjorneContext) myContext);
            } while (script);
            return myContext.getLastReturnCode();
        } finally {
            this.parser = savedParser;
            this.reader = savedReader;
        }
    }

    @Override
    public int interpret(CommandShell shell, Reader reader, boolean script, String alias, String[] args)
        throws ShellException {
        context.setCommand(alias == null ? "" : alias);
        context.setArgs(args == null ? new String[0] : args);
        try {
            return interpret(shell, reader, script, null, false);
        } catch (BjorneControlException ex) {
            switch (ex.getControl()) {
                case BjorneInterpreter.BRANCH_EXIT:
                    // The script will exit immediately
                    return ex.getCount();
                case BjorneInterpreter.BRANCH_BREAK:
                    throw new ShellSyntaxException(
                            "'break' has been executed in an inappropriate context");
                case BjorneInterpreter.BRANCH_CONTINUE:
                    throw new ShellSyntaxException(
                            "'continue' has been executed in an inappropriate context");
                case BjorneInterpreter.BRANCH_RETURN:
                    throw new ShellSyntaxException(
                            "'return' has been executed in an inappropriate context");
                default:
                    throw new ShellFailureException(
                            "unknown 'control' in BjorneControlException");
            }
        } catch (VmExit ex) {
            return ex.getStatus();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ex) {
                    // ignore
                }
            }
        }
    }
   
    @Override
    public String getPrompt(CommandShell shell, boolean continuation) {
        try {
            String res = context.variable(continuation ? "PS2" : "PS1");
            return (res == null) ? "$ " : expandPrompt(res);
        } catch (ShellSyntaxException ex) {
            return "$ ";
        }
    }

    private String expandPrompt(String prompt) {
        // FIXME implement
        return prompt;
    }

    @Override
    public boolean supportsMultiline() {
        return true;
    }
   
    Reader getReader() {
        return this.reader;
    }

    private void bindShell(CommandShell shell) {
        if (this.shell != shell) {
            if (this.shell != null) {
                throw new ShellFailureException("my shell changed");
            }
            this.shell = shell;
        }
    }
   
    static boolean isBuiltin(String commandWord) {
        return BUILTINS.containsKey(commandWord);
    }

    int executeCommand(CommandLine cmdLine, BjorneContext context, CommandIO[] streams,
            Properties sysProps, Map<String, String> env)
        throws ShellException {
        String commandName = cmdLine.getCommandName();
        if (isBuiltin(commandName)) {
            BjorneBuiltinCommandInfo builtin = BUILTINS.get(commandName).buildCommandInfo(context);
            cmdLine.setCommandInfo(builtin);
        } else {
            CommandNode body = context.getFunction(commandName);
            if (body != null) {
                context.evaluateRedirectionsAndPushHolders(body.getRedirects(), streams);
                String[] savedArgs = context.getArgs();
                try {
                    context.setArgs(cmdLine.getArguments());
                    return body.execute(context);
                } finally {
                    context.popHolders();
                    context.setArgs(savedArgs);
                }
            }
        }
        cmdLine.setStreams(streams);
        return shell.invoke(cmdLine, sysProps, env);
    }

    BjorneContext createContext() throws ShellFailureException {
        return new BjorneContext(this);
    }

    CommandShell getShell() {
        return shell;
    }

    PrintStream resolvePrintStream(CommandIO commandIOIF) {
        return shell.resolvePrintStream(commandIOIF);
    }

    InputStream resolveInputStream(CommandIO stream) {
        return shell.resolveInputStream(stream);
    }
   
    private static synchronized long getSubshellNumber() {
        return subshellCount++;
    }

    String getUniqueName() {
        return getName() + "-" + getSubshellNumber();
    }
}
TOP

Related Classes of org.jnode.shell.bjorne.BjorneInterpreter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.