Commit c8a7be53db009fc7ea28fcb7c06c841e9e627776
- Diff rendering mode:
- inline
- side by side
|   | |||
| 48 | 48 | ||
| 49 | 49 | /** | |
| 50 | 50 | * Temporary adapter method. Unconverted builtin classes override this. | |
| 51 | * | ||
| 52 | * @param command | ||
| 53 | * @param interpreter | ||
| 54 | * @param context | ||
| 55 | * @return | ||
| 56 | * @throws ShellException | ||
| 57 | 51 | */ | |
| 58 | 52 | int invoke(CommandLine command, BjorneInterpreter interpreter, | |
| 59 | 53 | BjorneContext context) throws ShellException { |
|   | |||
| 90 | 90 | private final BjorneInterpreter interpreter; | |
| 91 | 91 | ||
| 92 | 92 | private Map<String, VariableSlot> variables; | |
| 93 | |||
| 93 | |||
| 94 | 94 | private TreeMap<String, String> aliases; | |
| 95 | |||
| 96 | private TreeMap<String, CommandNode> functions; | ||
| 95 | 97 | ||
| 96 | 98 | private String command = ""; | |
| 97 | 99 | ||
| … | … | ||
| 124 | 124 | this.holders = holders; | |
| 125 | 125 | this.variables = new HashMap<String, VariableSlot>(); | |
| 126 | 126 | this.aliases = new TreeMap<String, String>(); | |
| 127 | this.functions = new TreeMap<String, CommandNode>(); | ||
| 127 | 128 | initVariables(); | |
| 128 | 129 | } | |
| 129 | 130 | ||
| … | … | ||
| 160 | 160 | this.holders = copyStreamHolders(parent.holders); | |
| 161 | 161 | this.variables = copyVariables(parent.variables); | |
| 162 | 162 | this.aliases = new TreeMap<String, String>(parent.aliases); | |
| 163 | this.functions = new TreeMap<String, CommandNode>(parent.functions); | ||
| 163 | 164 | this.globbing = parent.globbing; | |
| 164 | 165 | this.tildeExpansion = parent.tildeExpansion; | |
| 165 | 166 | this.echoExpansions = parent.echoExpansions; | |
| … | … | ||
| 410 | 410 | * @param tokens the tokens to be expanded and split into words | |
| 411 | 411 | * @throws ShellException | |
| 412 | 412 | */ | |
| 413 | public List<BjorneToken> expandAndSplit(BjorneToken ... tokens) | ||
| 414 | throws ShellException { | ||
| 415 | List<BjorneToken> wordTokens = new LinkedList<BjorneToken>(); | ||
| 416 | for (BjorneToken token : tokens) { | ||
| 417 | dollarBacktickSplit(token, wordTokens); | ||
| 418 | } | ||
| 419 | wordTokens = fileExpand(wordTokens); | ||
| 420 | wordTokens = dequote(wordTokens); | ||
| 421 | return wordTokens; | ||
| 413 | public List<BjorneToken> expandAndSplit(BjorneToken ... tokens) throws ShellException { | ||
| 414 | return expandAndSplit(Arrays.asList(tokens)); | ||
| 422 | 415 | } | |
| 423 | 416 | ||
| 424 | 417 | /** | |
| … | … | ||
| 1058 | 1058 | return new BjorneArithmeticEvaluator(this).evaluateExpression(tmp); | |
| 1059 | 1059 | } | |
| 1060 | 1060 | ||
| 1061 | int execute(CommandLine command, CommandIO[] streams, boolean isBuiltin) throws ShellException { | ||
| 1061 | int execute(CommandLine command, CommandIO[] streams) throws ShellException { | ||
| 1062 | 1062 | if (isEchoExpansions()) { | |
| 1063 | 1063 | StringBuilder sb = new StringBuilder(); | |
| 1064 | 1064 | sb.append(" + ").append(command.getCommandName()); | |
| … | … | ||
| 1068 | 1068 | resolvePrintStream(streams[Command.STD_ERR]).println(sb); | |
| 1069 | 1069 | } | |
| 1070 | 1070 | Map<String, String> env = buildEnvFromExports(); | |
| 1071 | lastReturnCode = interpreter.executeCommand(command, this, streams, null, env, isBuiltin); | ||
| 1071 | lastReturnCode = interpreter.executeCommand(command, this, streams, null, env); | ||
| 1072 | 1072 | return lastReturnCode; | |
| 1073 | 1073 | } | |
| 1074 | 1074 | ||
| … | … | ||
| 1385 | 1385 | ||
| 1386 | 1386 | public Collection<String> getVariableNames() { | |
| 1387 | 1387 | return variables.keySet(); | |
| 1388 | } | ||
| 1389 | |||
| 1390 | void defineFunction(BjorneToken name, CommandNode body) { | ||
| 1391 | functions.put(name.getText(), body); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | CommandNode getFunction(String name) { | ||
| 1395 | return functions.get(name); | ||
| 1388 | 1396 | } | |
| 1389 | 1397 | ||
| 1390 | 1398 | } |
|   | |||
| 122 | 122 | public static final int FLAG_PIPE = 0x0010; | |
| 123 | 123 | ||
| 124 | 124 | public static final CommandNode EMPTY = | |
| 125 | new SimpleCommandNode(CMD_EMPTY, new BjorneToken[0], false); | ||
| 125 | new SimpleCommandNode(CMD_EMPTY, new BjorneToken[0]); | ||
| 126 | 126 | ||
| 127 | 127 | static HashMap<String, BjorneBuiltin.Factory> BUILTINS = | |
| 128 | 128 | new HashMap<String, BjorneBuiltin.Factory>(); | |
| … | … | ||
| 313 | 313 | } | |
| 314 | 314 | ||
| 315 | 315 | int executeCommand(CommandLine cmdLine, BjorneContext context, CommandIO[] streams, | |
| 316 | Properties sysProps, Map<String, String> env, boolean isBuiltin) | ||
| 316 | Properties sysProps, Map<String, String> env) | ||
| 317 | 317 | throws ShellException { | |
| 318 | if (isBuiltin) { | ||
| 319 | BjorneBuiltinCommandInfo builtin = | ||
| 320 | BUILTINS.get(cmdLine.getCommandName()).buildCommandInfo(context); | ||
| 318 | String commandName = cmdLine.getCommandName(); | ||
| 319 | if (isBuiltin(commandName)) { | ||
| 320 | BjorneBuiltinCommandInfo builtin = BUILTINS.get(commandName).buildCommandInfo(context); | ||
| 321 | 321 | cmdLine.setCommandInfo(builtin); | |
| 322 | } | ||
| 322 | } else { | ||
| 323 | CommandNode body = context.getFunction(commandName); | ||
| 324 | if (body != null) { | ||
| 325 | // FIXME setup a new context, streams and args. | ||
| 326 | return body.execute(context); | ||
| 327 | } | ||
| 328 | } | ||
| 323 | 329 | cmdLine.setStreams(streams); | |
| 324 | 330 | return shell.invoke(cmdLine, sysProps, env); | |
| 325 | 331 | } |
|   | |||
| 145 | 145 | } else { | |
| 146 | 146 | noLineBreaks(); | |
| 147 | 147 | if (optNext(TOK_END_OF_LINE_BIT) != null) { | |
| 148 | command = new SimpleCommandNode(CMD_COMMAND, new BjorneToken[0], false); | ||
| 148 | command = new SimpleCommandNode(CMD_COMMAND, new BjorneToken[0]); | ||
| 149 | 149 | } | |
| 150 | 150 | } | |
| 151 | 151 | return command; | |
| … | … | ||
| 292 | 292 | List<BjorneToken> assignments = new LinkedList<BjorneToken>(); | |
| 293 | 293 | List<RedirectionNode> redirects = new LinkedList<RedirectionNode>(); | |
| 294 | 294 | List<BjorneToken> words = new LinkedList<BjorneToken>(); | |
| 295 | boolean builtin = false; | ||
| 296 | 295 | ||
| 297 | 296 | // Deal with cmd_prefix'es before the command name; i.e. assignments and | |
| 298 | 297 | // redirections | |
| … | … | ||
| 337 | 337 | redirects.add(parseRedirect()); | |
| 338 | 338 | } | |
| 339 | 339 | } | |
| 340 | String commandWord = words.get(0).getText(); | ||
| 341 | builtin = BjorneInterpreter.isBuiltin(commandWord); | ||
| 342 | // FIXME ... built-in commands should use the Syntax mechanisms so | ||
| 343 | // that completion, help, etc will work as expected. | ||
| 344 | 340 | } | |
| 345 | 341 | } catch (ShellSyntaxException ex) { | |
| 346 | 342 | if (completer != null) { | |
| 347 | 343 | completer.setCommand(words.size() == 0 ? null : | |
| 348 | 344 | new SimpleCommandNode(CMD_COMMAND, | |
| 349 | words.toArray(new BjorneToken[words.size()]), builtin)); | ||
| 345 | words.toArray(new BjorneToken[words.size()]))); | ||
| 350 | 346 | } | |
| 351 | 347 | throw ex; | |
| 352 | 348 | } | |
| 353 | 349 | SimpleCommandNode res = new SimpleCommandNode(CMD_COMMAND, | |
| 354 | words.toArray(new BjorneToken[words.size()]), builtin); | ||
| 350 | words.toArray(new BjorneToken[words.size()])); | ||
| 355 | 351 | if (completer != null) { | |
| 356 | 352 | completer.setCommand(words.size() == 0 ? null : res); | |
| 357 | 353 | } | |
| … | … | ||
| 377 | 377 | } | |
| 378 | 378 | ||
| 379 | 379 | private CommandNode parseFunctionBody() throws ShellSyntaxException { | |
| 380 | // TODO ... need to set the context to 'rule 9' while parsing the | ||
| 381 | // function body | ||
| 382 | 380 | CommandNode body = parseCompoundCommand(); | |
| 383 | 381 | body.setRedirects(parseOptRedirects()); | |
| 384 | 382 | return body; |
|   | |||
| 56 | 56 | ||
| 57 | 57 | @Override | |
| 58 | 58 | public int execute(BjorneContext context) { | |
| 59 | return -1; | ||
| 59 | context.defineFunction(name, body); | ||
| 60 | return 0; | ||
| 60 | 61 | } | |
| 61 | 62 | ||
| 62 | 63 | @Override |
|   | |||
| 38 | 38 | ||
| 39 | 39 | private final BjorneToken[] words; | |
| 40 | 40 | ||
| 41 | private final boolean builtin; | ||
| 42 | 41 | ||
| 43 | public SimpleCommandNode(int nodeType, BjorneToken[] words, boolean builtin) { | ||
| 42 | public SimpleCommandNode(int nodeType, BjorneToken[] words) { | ||
| 44 | 43 | super(nodeType); | |
| 45 | 44 | this.words = words; | |
| 46 | this.builtin = builtin; | ||
| 47 | 45 | } | |
| 48 | 46 | ||
| 49 | 47 | public void setAssignments(BjorneToken[] assignments) { | |
| … | … | ||
| 56 | 56 | return assignments; | |
| 57 | 57 | } | |
| 58 | 58 | ||
| 59 | public boolean isBuiltin() { | ||
| 60 | return builtin; | ||
| 61 | } | ||
| 62 | |||
| 63 | 59 | public String toString() { | |
| 64 | 60 | StringBuilder sb = new StringBuilder(); | |
| 65 | 61 | sb.append("SimpleCommand{").append(super.toString()); | |
| … | … | ||
| 63 | 63 | sb.append(",assignments="); | |
| 64 | 64 | appendArray(sb, assignments); | |
| 65 | 65 | } | |
| 66 | if (builtin) { | ||
| 67 | sb.append(",builtin=true"); | ||
| 68 | } | ||
| 69 | 66 | if (words != null) { | |
| 70 | 67 | sb.append(",words="); | |
| 71 | 68 | appendArray(sb, words); | |
| … | … | ||
| 101 | 101 | throw new ShellFailureException( | |
| 102 | 102 | "asynchronous execution (&) not implemented yet"); | |
| 103 | 103 | } else { | |
| 104 | rc = childContext.execute(command, ios, builtin); | ||
| 104 | rc = childContext.execute(command, ios); | ||
| 105 | 105 | } | |
| 106 | 106 | } | |
| 107 | 107 | } catch (BjorneControlException ex) { | |
| … | … | ||
| 144 | 144 | throws CompletionException { | |
| 145 | 145 | try { | |
| 146 | 146 | CommandLine command = context.buildCommandLine(words); | |
| 147 | if (builtin) { | ||
| 147 | String commandName = command.getCommandName(); | ||
| 148 | if (commandName != null && BjorneInterpreter.isBuiltin(commandName)) { | ||
| 148 | 149 | BjorneBuiltinCommandInfo commandInfo = | |
| 149 | BjorneInterpreter.BUILTINS.get(command.getCommandName()).buildCommandInfo(context); | ||
| 150 | BjorneInterpreter.BUILTINS.get(commandName).buildCommandInfo(context); | ||
| 150 | 151 | command.setCommandInfo(commandInfo); | |
| 151 | 152 | } | |
| 152 | 153 | command.setArgumentAnticipated(argumentAnticipated); |
|   | |||
| 74 | 74 | <output>fred='ls' | |
| 75 | 75 | </output> | |
| 76 | 76 | </testSpec> | |
| 77 | <testSpec title="builtins recognized early" command="test" runMode="AS_SCRIPT" rc="0"> | ||
| 78 | <script>#!bjorne | ||
| 79 | alias fred=ls | ||
| 80 | alias | ||
| 81 | unalias -a | ||
| 82 | echo done | ||
| 83 | UNALIAS=unalias | ||
| 84 | alias fred=dir | ||
| 85 | alias | ||
| 86 | $UNALIAS -a | ||
| 87 | echo done | ||
| 88 | </script> | ||
| 89 | <output>fred='ls' | ||
| 90 | done | ||
| 91 | fred='dir' | ||
| 92 | done | ||
| 93 | </output> | ||
| 94 | <error>Cannot find an alias or load a command class for 'unalias' | ||
| 95 | </error> | ||
| 96 | </testSpec> | ||
| 97 | 77 | <testSpec title="readonly" runMode="AS_SCRIPT" rc="0"> | |
| 98 | 78 | <script>#!bjorne | |
| 99 | 79 | readonly A |
|   | |||
| 969 | 969 | <error>Cannot find an alias or load a command class for 'foo' | |
| 970 | 970 | </error> | |
| 971 | 971 | </testSpec> | |
| 972 | <testSpec title="shell function" command="test" runMode="AS_SCRIPT" rc="0"> | ||
| 973 | <script>#!bjorne | ||
| 974 | foo() { | ||
| 975 | echo hi | ||
| 976 | } | ||
| 977 | foo | ||
| 978 | </script> | ||
| 979 | <output >hi | ||
| 980 | </output> | ||
| 981 | </testSpec> | ||
| 972 | 982 | </testSet> |

