mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[code] The Python console compiles and executes commands entered.
It stores and displays the result in the console store. An empty line returned at the end of the execution is deleted. Change-Id: Ic90e02e2d91d0a0033413da0588032d9450aefd0
This commit is contained in:
@@ -8,7 +8,6 @@ app_objs += $(addprefix apps/code/,\
|
||||
console_line_cell.o\
|
||||
console_store.o\
|
||||
editor_controller.o\
|
||||
executor_controller.o\
|
||||
menu_controller.o\
|
||||
program.o\
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Console = "Console"
|
||||
ConsoleError = "Error"
|
||||
EditProgram = "Programm bearbeiten"
|
||||
ExecuteProgram = "Programm ausfuhren"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Console = "Console"
|
||||
ConsoleError = "Error"
|
||||
EditProgram = "Edit program"
|
||||
ExecuteProgram = "Execute program"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Console = "Console"
|
||||
ConsoleError = "Error"
|
||||
EditProgram = "Editar el programa"
|
||||
ExecuteProgram = "Ejecutar el programa"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Console = "Console"
|
||||
ConsoleError = "Error"
|
||||
EditProgram = "Editer le programme"
|
||||
ExecuteProgram = "Executer le programme"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Console = "Console"
|
||||
ConsoleError = "Error"
|
||||
EditProgram = "Editar programa"
|
||||
ExecuteProgram = "Executar programa"
|
||||
|
||||
@@ -1,13 +1,61 @@
|
||||
#include "console_controller.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "port.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/stackctrl.h"
|
||||
}
|
||||
|
||||
namespace Code {
|
||||
|
||||
/* mp_hal_stdout_tx_strn_cooked symbol required by micropython at printing
|
||||
* needs to access information about where to print. This 'context' is provided
|
||||
* by the global sCurrentConsoleStore that points to the console store. */
|
||||
|
||||
static ConsoleStore * sCurrentConsoleStore = nullptr;
|
||||
|
||||
extern "C"
|
||||
void mp_hal_stdout_tx_strn_cooked(const char * str, size_t len) {
|
||||
assert(sCurrentConsoleStore != nullptr);
|
||||
sCurrentConsoleStore->pushResult(str, len);
|
||||
}
|
||||
|
||||
mp_obj_t execute_from_str(const char *str) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(0, str, strlen(str), false);
|
||||
mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_SINGLE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(&pt, lex->source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_hal_set_interrupt_char((int)Ion::Keyboard::Key::A6);
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // Disable interrupt
|
||||
nlr_pop();
|
||||
return 0;
|
||||
} else {
|
||||
// Uncaught exception
|
||||
return (mp_obj_t) nlr.ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleController::ConsoleController(Responder * parentResponder) :
|
||||
ViewController(parentResponder),
|
||||
TextFieldDelegate(),
|
||||
m_rowHeight(KDText::charSize(k_fontSize).height()),
|
||||
m_tableView(this, this, 0, 0),
|
||||
m_editCell(this, this)
|
||||
{
|
||||
assert(sCurrentConsoleStore == nullptr);
|
||||
sCurrentConsoleStore = &m_consoleStore;
|
||||
initPython();
|
||||
}
|
||||
|
||||
ConsoleController::~ConsoleController() {
|
||||
stopPython();
|
||||
}
|
||||
|
||||
void ConsoleController::viewWillAppear() {
|
||||
@@ -23,7 +71,7 @@ int ConsoleController::numberOfRows() {
|
||||
}
|
||||
|
||||
KDCoordinate ConsoleController::rowHeight(int j) {
|
||||
return k_rowHeight;
|
||||
return m_rowHeight;
|
||||
}
|
||||
|
||||
KDCoordinate ConsoleController::cumulatedHeightFromIndex(int j) {
|
||||
@@ -82,9 +130,11 @@ bool ConsoleController::textFieldDidReceiveEvent(TextField * textField, Ion::Eve
|
||||
|
||||
bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
m_consoleStore.pushCommand(text, strlen(text));
|
||||
executePython(text);
|
||||
textField->setText("");
|
||||
m_tableView.reloadData();
|
||||
m_tableView.scrollToCell(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -92,4 +142,26 @@ Toolbox * ConsoleController::toolboxForTextField(TextField * textFied) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ConsoleController::initPython() {
|
||||
mp_stack_set_limit(40000);
|
||||
mp_port_init_stack_top();
|
||||
|
||||
m_pythonHeap = (char *)malloc(16384);
|
||||
gc_init(m_pythonHeap, m_pythonHeap + 16384);
|
||||
|
||||
mp_init();
|
||||
}
|
||||
|
||||
void ConsoleController::executePython(const char * str) {
|
||||
if (execute_from_str(str)) {
|
||||
mp_hal_stdout_tx_strn_cooked(I18n::translate(I18n::Message::ConsoleError), 5);
|
||||
}
|
||||
m_consoleStore.deleteLastLineIfEmpty();
|
||||
}
|
||||
|
||||
void ConsoleController::stopPython() {
|
||||
free(m_pythonHeap);
|
||||
sCurrentConsoleStore = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace Code {
|
||||
class ConsoleController : public ViewController, public ListViewDataSource, public ScrollViewDataSource, public TextFieldDelegate {
|
||||
public:
|
||||
ConsoleController(Responder * parentResponder);
|
||||
~ConsoleController();
|
||||
ConsoleController(const ConsoleController& other) = delete;
|
||||
ConsoleController(ConsoleController&& other) = delete;
|
||||
ConsoleController operator=(const ConsoleController& other) = delete;
|
||||
ConsoleController& operator=(ConsoleController&& other) = delete;
|
||||
|
||||
// ViewController
|
||||
View * view() override { return &m_tableView; }
|
||||
@@ -34,15 +39,23 @@ public:
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
Toolbox * toolboxForTextField(TextField * textFied) override;
|
||||
|
||||
// Python
|
||||
void initPython();
|
||||
void executePython(const char * str);
|
||||
void stopPython();
|
||||
|
||||
// Other
|
||||
static constexpr KDText::FontSize k_fontSize = KDText::FontSize::Large;
|
||||
private:
|
||||
static constexpr int LineCellType = 0;
|
||||
static constexpr int EditCellType = 1;
|
||||
static constexpr int k_numberOfLineCells = 15; // May change depending on the height
|
||||
static constexpr int k_rowHeight = 20;
|
||||
int m_rowHeight;
|
||||
ConsoleStore m_consoleStore;
|
||||
TableView m_tableView;
|
||||
ConsoleLineCell m_cells[k_numberOfLineCells];
|
||||
ConsoleEditCell m_editCell;
|
||||
char * m_pythonHeap;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "console_edit_cell.h"
|
||||
#include "console_controller.h"
|
||||
#include <escher/app.h>
|
||||
#include <apps/i18n.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Code {
|
||||
@@ -7,21 +9,28 @@ namespace Code {
|
||||
ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, TextFieldDelegate * delegate) :
|
||||
HighlightCell(),
|
||||
Responder(parentResponder),
|
||||
m_textField(this, m_textBuffer, m_draftTextBuffer, TextField::maxBufferSize(), delegate)
|
||||
m_promptView(ConsoleController::k_fontSize, I18n::Message::ConsolePrompt, 0, 0.5),
|
||||
m_textField(this, m_textBuffer, m_draftTextBuffer, TextField::maxBufferSize(), delegate, true, ConsoleController::k_fontSize)
|
||||
{
|
||||
}
|
||||
|
||||
int ConsoleEditCell::numberOfSubviews() const {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
View * ConsoleEditCell::subviewAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
return &m_textField;
|
||||
assert(index == 0 || index ==1);
|
||||
if (index == 0) {
|
||||
return &m_promptView;
|
||||
} else {
|
||||
return &m_textField;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleEditCell::layoutSubviews() {
|
||||
m_textField.setFrame(bounds());
|
||||
KDSize chevronsSize = KDText::stringSize(I18n::translate(I18n::Message::ConsolePrompt), ConsoleController::k_fontSize);
|
||||
m_promptView.setFrame(KDRect(KDPointZero, chevronsSize.width(), bounds().height()));
|
||||
m_textField.setFrame(KDRect(KDPoint(chevronsSize.width(), KDCoordinate(0)), bounds().width() - chevronsSize.width(), bounds().height()));
|
||||
}
|
||||
|
||||
void ConsoleEditCell::didBecomeFirstResponder() {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <escher/highlight_cell.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
#include <escher/message_text_view.h>
|
||||
#include "console_line.h"
|
||||
|
||||
namespace Code {
|
||||
|
||||
@@ -26,6 +28,7 @@ public:
|
||||
private:
|
||||
char m_textBuffer[TextField::maxBufferSize()];
|
||||
char m_draftTextBuffer[TextField::maxBufferSize()];
|
||||
MessageTextView m_promptView;
|
||||
TextField m_textField;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include "console_line_cell.h"
|
||||
#include "console_controller.h"
|
||||
#include <kandinsky/point.h>
|
||||
#include <kandinsky/coordinate.h>
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Code {
|
||||
|
||||
@@ -9,8 +13,14 @@ ConsoleLineCell::ConsoleLineCell() :
|
||||
}
|
||||
|
||||
void ConsoleLineCell::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(bounds(), KDColorRed);
|
||||
ctx->drawString(m_line.text(), KDPointZero);
|
||||
ctx->fillRect(bounds(), KDColorWhite);
|
||||
if (m_line.type() == ConsoleLine::Type::Command) {
|
||||
ctx->drawString(I18n::translate(I18n::Message::ConsolePrompt), KDPointZero, ConsoleController::k_fontSize);
|
||||
KDCoordinate chevronsWidth = KDText::stringSize(I18n::translate(I18n::Message::ConsolePrompt), ConsoleController::k_fontSize).width();
|
||||
ctx->drawString(m_line.text(), KDPoint(chevronsWidth, KDCoordinate(0)), ConsoleController::k_fontSize);
|
||||
} else {
|
||||
ctx->drawString(m_line.text(), KDPointZero, ConsoleController::k_fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLineCell::setLine(ConsoleLine line) {
|
||||
|
||||
@@ -50,6 +50,15 @@ void ConsoleStore::pushResult(const char * text, size_t length) {
|
||||
push(ResultMarker, text, length);
|
||||
}
|
||||
|
||||
|
||||
void ConsoleStore::deleteLastLineIfEmpty() {
|
||||
ConsoleLine lastLine = lineAtIndex(numberOfLines()-1);
|
||||
char lastLineFirstChar = lastLine.text()[0];
|
||||
if (lastLineFirstChar == 0 || lastLineFirstChar == '\n') {
|
||||
deleteLastLine();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleStore::push(const char marker, const char * text, size_t length) {
|
||||
// TODO: Verify that the text field does not accept texts that are bigger than
|
||||
// k_historySize, or put an alert message if the command is too big.
|
||||
@@ -88,14 +97,37 @@ void ConsoleStore::deleteFirstLine() {
|
||||
if (m_history[0] == 0) {
|
||||
return;
|
||||
}
|
||||
int indexOfSecondLineMarker = 1;
|
||||
while (m_history[indexOfSecondLineMarker] != 0) {
|
||||
indexOfSecondLineMarker++;
|
||||
int secondLineMarkerIndex = 1;
|
||||
while (m_history[secondLineMarkerIndex] != 0) {
|
||||
secondLineMarkerIndex++;
|
||||
}
|
||||
indexOfSecondLineMarker++;
|
||||
for (int i=0; i<k_historySize - indexOfSecondLineMarker; i++) {
|
||||
m_history[i] = m_history[indexOfSecondLineMarker+i];
|
||||
secondLineMarkerIndex++;
|
||||
for (int i=0; i<k_historySize - secondLineMarkerIndex; i++) {
|
||||
m_history[i] = m_history[secondLineMarkerIndex+i];
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleStore::deleteLastLine() {
|
||||
int lineCount = numberOfLines();
|
||||
if (lineCount < 0) {
|
||||
return;
|
||||
}
|
||||
if (lineCount == 1) {
|
||||
deleteFirstLine();
|
||||
return;
|
||||
}
|
||||
int currentLineIndex = 1;
|
||||
int lastLineMarkerIndex = 0;
|
||||
for (int i=0; i<k_historySize; i++) {
|
||||
if (m_history[i] == 0) {
|
||||
currentLineIndex++;
|
||||
if (currentLineIndex == lineCount) {
|
||||
lastLineMarkerIndex = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_history[lastLineMarkerIndex] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
int numberOfLines() const;
|
||||
void pushCommand(const char * text, size_t length);
|
||||
void pushResult(const char * text, size_t length);
|
||||
void deleteLastLineIfEmpty();
|
||||
private:
|
||||
static constexpr char CommandMarker = 0x01;
|
||||
static constexpr char ResultMarker = 0x02;
|
||||
@@ -25,6 +26,7 @@ private:
|
||||
* old ConsoleLines. deleteFirstLine() deletes the first ConsoleLine of
|
||||
* m_history and shifts the rest of the ConsoleLines towards the beginning of
|
||||
* m_history. */
|
||||
void deleteLastLine();
|
||||
char m_history[k_historySize];
|
||||
/* The m_history variable sequentially stores an array of ConsoleLine objects.
|
||||
* Each ConsoleLine is stored as follow:
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
#include "executor_controller.h"
|
||||
|
||||
extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "port.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/stackctrl.h"
|
||||
}
|
||||
|
||||
namespace Code {
|
||||
|
||||
mp_obj_t execute_from_str(const char *str) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(0/*MP_QSTR_*/, str, strlen(str), false);
|
||||
mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(&pt, lex->source_name, MP_EMIT_OPT_NONE, false);
|
||||
mp_hal_set_interrupt_char((int)Ion::Keyboard::Key::A6);
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||
nlr_pop();
|
||||
return 0;
|
||||
} else {
|
||||
// uncaught exception
|
||||
return (mp_obj_t)nlr.ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
/* mp_hal_stdout_tx_strn_cooked symbol required by micropython at printing
|
||||
* needs to access information about where to print (depending on the strings
|
||||
* printed before). This 'context' is provided by the global sCurrentView that
|
||||
* points to the content view only within the drawRect method (as runPython is
|
||||
* called within drawRect). */
|
||||
static const ExecutorController::ContentView * sCurrentView = nullptr;
|
||||
|
||||
extern "C"
|
||||
void mp_hal_stdout_tx_strn_cooked(const char * str, size_t len) {
|
||||
assert(sCurrentView != nullptr);
|
||||
sCurrentView->print(str);
|
||||
}
|
||||
|
||||
ExecutorController::ContentView::ContentView(Program * program) :
|
||||
View(),
|
||||
m_program(program),
|
||||
m_printLocation(KDPointZero)
|
||||
{
|
||||
}
|
||||
|
||||
void ExecutorController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
assert(ctx == KDIonContext::sharedContext());
|
||||
clearScreen(ctx);
|
||||
|
||||
assert(sCurrentView == nullptr);
|
||||
sCurrentView = this;
|
||||
|
||||
// Reinitialize the print location
|
||||
m_printLocation = KDPointZero;
|
||||
runPython();
|
||||
|
||||
sCurrentView = nullptr;
|
||||
}
|
||||
|
||||
void ExecutorController::ContentView::print(const char * str) const {
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
m_printLocation = ctx->drawString(str, m_printLocation);
|
||||
if (bounds().height() < m_printLocation.y()) {
|
||||
clearScreen(ctx);
|
||||
m_printLocation = KDPoint(m_printLocation.x(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ExecutorController::ContentView::runPython() const {
|
||||
// Initialized stack limit
|
||||
mp_stack_set_limit(40000);
|
||||
|
||||
mp_port_init_stack_top();
|
||||
|
||||
char * pythonHeap = (char *)malloc(16384);
|
||||
|
||||
gc_init(pythonHeap, pythonHeap + 16384);
|
||||
|
||||
// Initialize interpreter
|
||||
mp_init();
|
||||
|
||||
if (execute_from_str(m_program->readOnlyContent())) {
|
||||
mp_hal_stdout_tx_strn_cooked("Error", 0);
|
||||
}
|
||||
|
||||
free(pythonHeap);
|
||||
}
|
||||
|
||||
void ExecutorController::ContentView::clearScreen(KDContext * ctx) const {
|
||||
ctx->fillRect(bounds(), KDColorWhite);
|
||||
}
|
||||
|
||||
ExecutorController::ExecutorController(Program * program) :
|
||||
ViewController(nullptr),
|
||||
m_view(program)
|
||||
{
|
||||
}
|
||||
|
||||
View * ExecutorController::view() {
|
||||
return &m_view;
|
||||
}
|
||||
|
||||
bool ExecutorController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK) {
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef CODE_EXECUTOR_CONTROLLER_H
|
||||
#define CODE_EXECUTOR_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "program.h"
|
||||
|
||||
namespace Code {
|
||||
|
||||
class ExecutorController : public ViewController {
|
||||
public:
|
||||
ExecutorController(Program * program);
|
||||
View * view() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Program * program);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void print(const char * str) const;
|
||||
private:
|
||||
void runPython() const;
|
||||
void clearScreen(KDContext * ctx) const;
|
||||
Program * m_program;
|
||||
mutable KDPoint m_printLocation;
|
||||
};
|
||||
private:
|
||||
ContentView m_view;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,6 @@ MenuController::MenuController(Responder * parentResponder, Program * program) :
|
||||
ViewController(parentResponder),
|
||||
m_selectableTableView(this, this, 0, 1, Metric::CommonTopMargin, Metric::CommonRightMargin, Metric::CommonBottomMargin, Metric::CommonLeftMargin, this),
|
||||
m_editorController(program),
|
||||
m_executorController(program),
|
||||
m_consoleController(parentResponder)
|
||||
{
|
||||
}
|
||||
@@ -23,7 +22,7 @@ void MenuController::didBecomeFirstResponder() {
|
||||
}
|
||||
|
||||
bool MenuController::handleEvent(Ion::Events::Event event) {
|
||||
ViewController * vc[3] = {&m_editorController, &m_executorController, &m_consoleController};
|
||||
ViewController * vc[2] = {&m_editorController, &m_consoleController};
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
app()->displayModalViewController(vc[selectedRow()], 0.5f, 0.5f);
|
||||
return true;
|
||||
@@ -52,7 +51,7 @@ KDCoordinate MenuController::cellHeight() {
|
||||
|
||||
void MenuController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
MessageTableCell * myCell = (MessageTableCell *)cell;
|
||||
I18n::Message titles[k_totalNumberOfCells] = {I18n::Message::EditProgram, I18n::Message::ExecuteProgram, I18n::Message::Console};
|
||||
I18n::Message titles[k_totalNumberOfCells] = {I18n::Message::EditProgram, I18n::Message::Console};
|
||||
// TODO: translate Console in the .i18n
|
||||
myCell->setMessage(titles[index]);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <escher.h>
|
||||
#include "console_controller.h"
|
||||
#include "editor_controller.h"
|
||||
#include "executor_controller.h"
|
||||
#include "program.h"
|
||||
|
||||
namespace Code {
|
||||
@@ -21,11 +20,10 @@ public:
|
||||
int reusableCellCount() override;
|
||||
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
|
||||
private:
|
||||
constexpr static int k_totalNumberOfCells = 3;
|
||||
constexpr static int k_totalNumberOfCells = 2;
|
||||
MessageTableCell m_cells[k_totalNumberOfCells];
|
||||
SelectableTableView m_selectableTableView;
|
||||
EditorController m_editorController;
|
||||
ExecutorController m_executorController;
|
||||
ConsoleController m_consoleController;
|
||||
};
|
||||
|
||||
|
||||
@@ -106,3 +106,4 @@ AtanhCommandWithArg = "atanh(x)"
|
||||
Prediction95CommandWithArg = "prediction95(p,n)"
|
||||
PredictionCommandWithArg = "prediction(p,n)"
|
||||
ConfidenceCommandWithArg = "confidence(f,n)"
|
||||
ConsolePrompt = ">>> "
|
||||
|
||||
Reference in New Issue
Block a user