Skip to content
Snippets Groups Projects
Commit f6c5903d authored by dgelessus's avatar dgelessus
Browse files

Add support for cell (multiline) commands and an ::echo test command

parent fe1d1d52
No related branches found
No related tags found
No related merge requests found
...@@ -16,10 +16,12 @@ import de.prob.animator.domainobjects.FormulaExpand; ...@@ -16,10 +16,12 @@ import de.prob.animator.domainobjects.FormulaExpand;
import de.prob.scripting.ClassicalBFactory; import de.prob.scripting.ClassicalBFactory;
import de.prob.statespace.Trace; import de.prob.statespace.Trace;
import de.prob2.jupyter.commands.CellCommand;
import de.prob2.jupyter.commands.CommandExecutionException; import de.prob2.jupyter.commands.CommandExecutionException;
import de.prob2.jupyter.commands.EchoCellCommand;
import de.prob2.jupyter.commands.HelpCommand; import de.prob2.jupyter.commands.HelpCommand;
import de.prob2.jupyter.commands.LineCommand;
import de.prob2.jupyter.commands.NoSuchCommandException; import de.prob2.jupyter.commands.NoSuchCommandException;
import de.prob2.jupyter.commands.ReplCommand;
import io.github.spencerpark.jupyter.kernel.BaseKernel; import io.github.spencerpark.jupyter.kernel.BaseKernel;
import io.github.spencerpark.jupyter.kernel.LanguageInfo; import io.github.spencerpark.jupyter.kernel.LanguageInfo;
...@@ -28,24 +30,34 @@ import io.github.spencerpark.jupyter.messages.DisplayData; ...@@ -28,24 +30,34 @@ import io.github.spencerpark.jupyter.messages.DisplayData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public final class ProBKernel extends BaseKernel { public final class ProBKernel extends BaseKernel {
private static final Pattern COMMAND_PATTERN = Pattern.compile("\\s*(\\:.*)"); private static final Pattern CELL_COMMAND_PATTERN = Pattern.compile("\\s*(\\:\\:[^\n]*)(?:\n(.*))?", Pattern.DOTALL);
private static final Pattern LINE_COMMAND_PATTERN = Pattern.compile("\\s*(\\:.*)");
private final @NotNull Map<@NotNull String, @NotNull ReplCommand> commands; private final @NotNull Map<@NotNull String, @NotNull LineCommand> lineCommands;
private final @NotNull Map<@NotNull String, @NotNull CellCommand> cellCommands;
private @NotNull Trace trace; private @NotNull Trace trace;
@Inject @Inject
private ProBKernel(final @NotNull ClassicalBFactory classicalBFactory) { private ProBKernel(final @NotNull ClassicalBFactory classicalBFactory) {
super(); super();
this.commands = new HashMap<>(); this.lineCommands = new HashMap<>();
final ReplCommand help = new HelpCommand(); final LineCommand help = new HelpCommand();
this.commands.put(":?", help); this.lineCommands.put(":?", help);
this.commands.put(":help", help); this.lineCommands.put(":help", help);
this.cellCommands = new HashMap<>();
this.cellCommands.put("::echo", new EchoCellCommand());
this.trace = new Trace(classicalBFactory.create("MACHINE repl END").load()); this.trace = new Trace(classicalBFactory.create("MACHINE repl END").load());
} }
public @NotNull Map<@NotNull String, @NotNull ReplCommand> getCommands() { public @NotNull Map<@NotNull String, @NotNull CellCommand> getCellCommands() {
return Collections.unmodifiableMap(this.commands); return Collections.unmodifiableMap(this.cellCommands);
}
public @NotNull Map<@NotNull String, @NotNull LineCommand> getLineCommands() {
return Collections.unmodifiableMap(this.lineCommands);
} }
@Override @Override
...@@ -58,8 +70,16 @@ public final class ProBKernel extends BaseKernel { ...@@ -58,8 +70,16 @@ public final class ProBKernel extends BaseKernel {
return Collections.singletonList(new LanguageInfo.Help("ProB User Manual", "https://www3.hhu.de/stups/prob/index.php/User_Manual")); return Collections.singletonList(new LanguageInfo.Help("ProB User Manual", "https://www3.hhu.de/stups/prob/index.php/User_Manual"));
} }
private @NotNull DisplayData executeCommand(final @NotNull String name, final @NotNull List<@NotNull String> args) { private @NotNull DisplayData executeCellCommand(final @NotNull String name, final @NotNull List<@NotNull String> args, final @NotNull String body) {
final ReplCommand command = this.getCommands().get(name); final CellCommand command = this.getCellCommands().get(name);
if (command == null) {
throw new NoSuchCommandException(name);
}
return command.run(this, name, args, body);
}
private @NotNull DisplayData executeLineCommand(final @NotNull String name, final @NotNull List<@NotNull String> args) {
final LineCommand command = this.getLineCommands().get(name);
if (command == null) { if (command == null) {
throw new NoSuchCommandException(name); throw new NoSuchCommandException(name);
} }
...@@ -70,18 +90,28 @@ public final class ProBKernel extends BaseKernel { ...@@ -70,18 +90,28 @@ public final class ProBKernel extends BaseKernel {
public @NotNull DisplayData eval(final String expr) { public @NotNull DisplayData eval(final String expr) {
assert expr != null; assert expr != null;
final Matcher matcher = COMMAND_PATTERN.matcher(expr); final Matcher cellMatcher = CELL_COMMAND_PATTERN.matcher(expr);
if (matcher.matches()) { if (cellMatcher.matches()) {
final List<String> args = new ArrayList<>(Arrays.asList(matcher.group(1).split("\\s+"))); final List<String> args = new ArrayList<>(Arrays.asList(cellMatcher.group(1).split("\\s+")));
// args always contains at least one element, even for an empty string (in that case the only element is an empty string). // args always contains at least one element, even for an empty string (in that case the only element is an empty string).
assert args.size() >= 1; assert args.size() >= 1;
final String name = args.remove(0); final String name = args.remove(0);
return this.executeCommand(name, args); final String body = cellMatcher.group(2) == null ? "" : cellMatcher.group(2);
} else { return this.executeCellCommand(name, args, body);
}
final Matcher lineMatcher = LINE_COMMAND_PATTERN.matcher(expr);
if (lineMatcher.matches()) {
final List<String> args = new ArrayList<>(Arrays.asList(lineMatcher.group(1).split("\\s+")));
// args always contains at least one element, even for an empty string (in that case the only element is an empty string).
assert args.size() >= 1;
final String name = args.remove(0);
return this.executeLineCommand(name, args);
}
final AbstractEvalResult result = this.trace.evalCurrent(expr, FormulaExpand.EXPAND); final AbstractEvalResult result = this.trace.evalCurrent(expr, FormulaExpand.EXPAND);
return new DisplayData(result.toString()); return new DisplayData(result.toString());
} }
}
@Override @Override
public @NotNull LanguageInfo getLanguageInfo() { public @NotNull LanguageInfo getLanguageInfo() {
......
package de.prob2.jupyter.commands;
import org.jetbrains.annotations.NotNull;
public interface BaseCommand {
public abstract @NotNull String getSyntax();
public abstract @NotNull String getShortHelp();
public default @NotNull String getLongHelp() {
return this.getSyntax() + "\n\n" + this.getShortHelp();
}
}
package de.prob2.jupyter.commands;
import java.util.List;
import de.prob2.jupyter.ProBKernel;
import io.github.spencerpark.jupyter.messages.DisplayData;
import org.jetbrains.annotations.NotNull;
public interface CellCommand extends BaseCommand {
public abstract @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args, final @NotNull String body);
}
package de.prob2.jupyter.commands;
import java.util.List;
import de.prob2.jupyter.ProBKernel;
import io.github.spencerpark.jupyter.messages.DisplayData;
import org.jetbrains.annotations.NotNull;
public final class EchoCellCommand implements CellCommand {
@Override
public @NotNull String getSyntax() {
return "::echo [ARGS [...]]\nBODY";
}
@Override
public @NotNull String getShortHelp() {
return "Echoes the arguments and body back.";
}
@Override
public @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args, final @NotNull String body) {
return new DisplayData(String.format("Name: %s\nArguments: %s\nBody:\n%s", name, args, body));
}
}
package de.prob2.jupyter.commands; package de.prob2.jupyter.commands;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import de.prob2.jupyter.ProBKernel; import de.prob2.jupyter.ProBKernel;
...@@ -10,7 +10,7 @@ import io.github.spencerpark.jupyter.messages.DisplayData; ...@@ -10,7 +10,7 @@ import io.github.spencerpark.jupyter.messages.DisplayData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public final class HelpCommand implements ReplCommand { public final class HelpCommand implements LineCommand {
@Override @Override
public @NotNull String getSyntax() { public @NotNull String getSyntax() {
return ":? [COMMAND]\n:help [COMMAND]"; return ":? [COMMAND]\n:help [COMMAND]";
...@@ -25,23 +25,35 @@ public final class HelpCommand implements ReplCommand { ...@@ -25,23 +25,35 @@ public final class HelpCommand implements ReplCommand {
public @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args) { public @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args) {
if (args.isEmpty()) { if (args.isEmpty()) {
final StringBuilder sb = new StringBuilder("Type a valid B expression, or one of the following commands:\n"); final StringBuilder sb = new StringBuilder("Type a valid B expression, or one of the following commands:\n");
final List<String> names = new ArrayList<>(kernel.getCommands().keySet()); final SortedMap<String, BaseCommand> commands = new TreeMap<>();
Collections.sort(names); commands.putAll(kernel.getCellCommands());
for (final String commandName : names) { commands.putAll(kernel.getLineCommands());
final ReplCommand command = kernel.getCommands().get(commandName); commands.forEach((commandName, command) -> {
assert command != null;
sb.append(commandName); sb.append(commandName);
sb.append(' '); sb.append(' ');
sb.append(command.getShortHelp()); sb.append(command.getShortHelp());
sb.append('\n'); sb.append('\n');
} });
return new DisplayData(sb.toString()); return new DisplayData(sb.toString());
} else if (args.size() == 1) { } else if (args.size() == 1) {
String commandName = args.get(0); String commandName = args.get(0);
// If the user entered a command name without colons, add one or two colons as appropriate.
// (If the command cannot be found, no colons are added, because we'll error out later anyway.)
if (!commandName.startsWith(":")) { if (!commandName.startsWith(":")) {
if (kernel.getLineCommands().containsKey(':' + commandName)) {
commandName = ':' + commandName; commandName = ':' + commandName;
} else if (kernel.getCellCommands().containsKey("::" + commandName)) {
commandName = "::" + commandName;
}
}
final BaseCommand command;
if (commandName.startsWith("::")) {
command = kernel.getCellCommands().get(commandName);
} else {
command = kernel.getLineCommands().get(commandName);
} }
final ReplCommand command = kernel.getCommands().get(commandName);
if (command == null) { if (command == null) {
throw new CommandExecutionException(name, String.format("Cannot display help for unknown command \"%s\"", commandName)); throw new CommandExecutionException(name, String.format("Cannot display help for unknown command \"%s\"", commandName));
} }
......
...@@ -8,14 +8,6 @@ import io.github.spencerpark.jupyter.messages.DisplayData; ...@@ -8,14 +8,6 @@ import io.github.spencerpark.jupyter.messages.DisplayData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface ReplCommand { public interface LineCommand extends BaseCommand {
public abstract @NotNull String getSyntax();
public abstract @NotNull String getShortHelp();
public default @NotNull String getLongHelp() {
return this.getSyntax() + "\n\n" + this.getShortHelp();
}
public abstract @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args); public abstract @NotNull DisplayData run(final @NotNull ProBKernel kernel, final @NotNull String name, final @NotNull List<@NotNull String> args);
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment