initial import of python-console

This commit is contained in:
Miodrag Milanovic 2018-06-28 13:16:53 +02:00
parent 66670831b8
commit c63274342f
28 changed files with 2120 additions and 0 deletions

43
3rdparty/python-console/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,43 @@
cmake_minimum_required( VERSION 2.8 )
project( PythonInterpreter )
find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )
find_package( PythonLibs REQUIRED )
include_directories( ${PYTHON_INCLUDE_DIRS} )
add_executable( test_python_interpreter test_python_interpreter.cpp Interpreter.cpp )
target_link_libraries( test_python_interpreter ${PYTHON_LIBRARIES} )
qt4_wrap_cpp( Console_MOC Console.h )
add_executable( test_console test_console.cpp
Console.cpp ${Console_MOC}
ColumnFormatter.cpp
Interpreter.cpp
ParseHelper.cpp
ParseHelper.BlockParseState.cpp
ParseHelper.BracketParseState.cpp
ParseHelper.ContinuationParseState.cpp
ParseMessage.cpp
)
target_link_libraries( test_console ${QT_LIBRARIES} ${PYTHON_LIBRARIES} )
add_executable( test_parse_helper test_parse_helper.cpp
ParseHelper.cpp
ParseHelper.BlockParseState.cpp
ParseHelper.ContinuationParseState.cpp
ParseListener.cpp
ParseMessage.cpp
)
add_executable( test_cli test_cli.cpp
ParseHelper.cpp
ParseHelper.BlockParseState.cpp
ParseHelper.ContinuationParseState.cpp
ParseListener.cpp
ParseMessage.cpp
Interpreter.cpp
)
target_link_libraries( test_cli
${PYTHON_LIBRARIES}
)

View File

@ -0,0 +1,141 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ColumnFormatter.h"
#include <iomanip>
#include <iostream>
#include <list>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstdlib>
bool ColumnFormatter::load(const std::string& fn)
{
items.clear();
std::ifstream ifs(fn.c_str());
if (!ifs.is_open())
return false;
std::string str;
while (!ifs.eof())
{
std::getline( ifs, str );
if (!ifs.eof())
items.push_back(str);
}
return true;
}
int ColumnFormatter::solve(int width)
{
bool fits = true;
int i = 1;
while (fits)
{
++i;
std::vector<int> widths = divideItems(i);
int columnWidth = width / i;
for (int j = 0; j < widths.size(); ++j)
{
fits &= (widths[j] < columnWidth);
}
if (!fits)
{
--i;
}
}
return i;
}
std::vector<int> ColumnFormatter::divideItems(int numColumns)
{
columns.clear();
for (int i = 0; i < numColumns; ++i)
columns.push_back(std::list<std::string>());
for (int i = 0; i < items.size(); ++i)
{
columns[i % numColumns].push_back(items[i]);
}
// count the fattest item in each column
std::vector<int> res(numColumns);
for (int i = 0; i < numColumns; ++i)
{
for (std::list<std::string>::const_iterator it =
columns[i].begin(); it != columns[i].end(); ++it)
{
if (res[i] < it->size())
res[i] = it->size();
}
}
return res;
}
void ColumnFormatter::format(int width)
{
m_formattedOutput.clear();
int cols = solve(width);
std::vector<int> colWidths(cols, width / cols);
int rem = width % cols;
for (int i = 0; i < rem; ++i)
{
colWidths[i]++;
}
divideItems(cols);
std::vector< std::list<std::string>::const_iterator > its;
std::vector< std::list<std::string>::const_iterator > it_ends;
for (int i = 0; i < columns.size(); ++i)
{
its.push_back(columns[i].begin());
it_ends.push_back(columns[i].end());
}
bool done = false;
while (!done)
{
std::stringstream row_ss;
for (int i = 0; i < columns.size(); ++i)
{
std::stringstream item_ss;
std::string item;
if (its[i] != it_ends[i])
{
item = *its[i];
++its[i];
}
item_ss << std::left << std::setw(colWidths[i]) << item;
row_ss << item_ss.str();
}
m_formattedOutput.push_back(row_ss.str());
done = true;
for (int i = 0; i < columns.size(); ++i)
{
done &= (its[i] == it_ends[i]);
}
}
}
const std::list<std::string>& ColumnFormatter::formattedOutput() const
{
return m_formattedOutput;
}

View File

@ -0,0 +1,77 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef COLUMN_FORMATTER_H
#define COLUMN_FORMATTER_H
#include <list>
#include <string>
#include <vector>
/**
Format a list of items into as many columns as width permits.
*/
class ColumnFormatter
{
protected:
std::vector<std::string> items;
std::vector< std::list<std::string> > columns;
std::list< std::string > m_formattedOutput;
public:
/**
Load items from file, one item per line.
*/
bool load(const std::string& fn);
template <class InputIterator>
void setItems(InputIterator begin, InputIterator end)
{
items.clear();
for (InputIterator it = begin; it != end; ++it)
{
items.push_back(*it);
}
}
/**
Determine the number of columns that the items can be into, given a
width limit.
*/
int solve(int width);
/**
Divide items into numColumns.
*/
std::vector<int> divideItems(int numColumns);
/**
Generate formatted output, the items formatted into as many columns as can
be fit in width.
*/
void format(int width);
/**
Get output.
*/
const std::list<std::string>& formattedOutput() const;
};
#endif // COLUMN_FORMATTER_H

297
3rdparty/python-console/Console.cpp vendored Normal file
View File

@ -0,0 +1,297 @@
#include "Console.h"
#include "Interpreter.h"
#include "ColumnFormatter.h"
#include <iostream>
#include <QKeyEvent>
#include <QFont>
#include "Utils.h"
const QString Console::PROMPT = ">>> ";
const QString Console::MULTILINE_PROMPT = "... ";
const QColor Console::NORMAL_COLOR = QColor::fromRgbF( 0, 0, 0 );
const QColor Console::ERROR_COLOR = QColor::fromRgbF( 1.0, 0, 0 );
const QColor Console::OUTPUT_COLOR = QColor::fromRgbF( 0, 0, 1.0 );
Console::Console( QWidget* parent ):
QTextEdit( parent ),
m_interpreter( new Interpreter )
{
QFont font;
font.setFamily("Courier New");
setFont(font);
m_parseHelper.subscribe( this );
displayPrompt( );
}
Console::~Console( )
{
delete m_interpreter;
}
void Console::keyPressEvent( QKeyEvent* e )
{
switch ( e->key() )
{
case Qt::Key_Return:
handleReturnKeyPress( );
return;
case Qt::Key_Tab:
autocomplete( );
return;
case Qt::Key_Backspace:
if ( ! canBackspace( ) )
return;
break;
case Qt::Key_Up:
previousHistory( );
return;
case Qt::Key_Down:
nextHistory( );
return;
case Qt::Key_Left:
if ( ! canGoLeft( ) )
return;
}
QTextEdit::keyPressEvent( e );
}
void Console::handleReturnKeyPress( )
{
if ( ! cursorIsOnInputLine( ) )
{
return;
}
QString line = getLine( );
#ifndef NDEBUG
std::cout << line.toStdString( ) << "\n";
#endif
m_parseHelper.process( line.toStdString( ) );
if ( m_parseHelper.buffered( ) )
{
append("");
displayPrompt( );
}
if ( line.size( ) )
{
m_historyBuffer.push_back( line.toStdString( ) );
m_historyIt = m_historyBuffer.end();
}
moveCursorToEnd( );
}
void Console::parseEvent( const ParseMessage& message )
{
// handle invalid user input
if ( message.errorCode )
{
setTextColor( ERROR_COLOR );
append(message.message.c_str());
setTextColor( NORMAL_COLOR );
append("");
displayPrompt( );
return;
}
// interpret valid user input
int errorCode;
std::string res;
if ( message.message.size() )
res = m_interpreter->interpret( message.message, &errorCode );
if ( errorCode )
{
setTextColor( ERROR_COLOR );
}
else
{
setTextColor( OUTPUT_COLOR );
}
if ( res.size( ) )
{
append(res.c_str());
}
setTextColor( NORMAL_COLOR );
// set up the next line on the console
append("");
displayPrompt( );
}
QString Console::getLine( )
{
QTextCursor cursor = textCursor();
cursor.movePosition( QTextCursor::StartOfLine );
cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, Console::PROMPT.size( ) );
cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
QString line = cursor.selectedText( );
cursor.clearSelection( );
return line;
}
bool Console::cursorIsOnInputLine( )
{
int cursorBlock = textCursor( ).blockNumber( );
QTextCursor bottomCursor = textCursor( );
bottomCursor.movePosition( QTextCursor::End );
int bottomBlock = bottomCursor.blockNumber( );
return ( cursorBlock == bottomBlock );
}
bool Console::inputLineIsEmpty( )
{
QTextCursor bottomCursor = textCursor( );
bottomCursor.movePosition( QTextCursor::End );
int col = bottomCursor.columnNumber( );
return ( col == Console::PROMPT.size( ) );
}
bool Console::canBackspace( )
{
if ( ! cursorIsOnInputLine( ) )
{
return false;
}
if ( inputLineIsEmpty( ) )
{
return false;
}
return true;
}
bool Console::canGoLeft( )
{
if ( cursorIsOnInputLine( ) )
{
QTextCursor bottomCursor = textCursor( );
int col = bottomCursor.columnNumber( );
return (col > Console::PROMPT.size( ));
}
return true;
}
void Console::displayPrompt( )
{
QTextCursor cursor = textCursor();
cursor.movePosition( QTextCursor::End );
if ( m_parseHelper.buffered( ) )
{
cursor.insertText( Console::MULTILINE_PROMPT );
}
else
{
cursor.insertText( Console::PROMPT );
}
cursor.movePosition( QTextCursor::EndOfLine );
}
void Console::autocomplete( )
{
if ( ! cursorIsOnInputLine( ) )
return;
QString line = getLine( );
const std::list<std::string>& suggestions =
m_interpreter->suggest( line.toStdString( ) );
if (suggestions.size() == 1)
{
line = suggestions.back().c_str();
}
else
{
// try to complete to longest common prefix
std::string prefix =
LongestCommonPrefix(suggestions.begin(), suggestions.end());
if (prefix.size() > line.size())
{
line = prefix.c_str();
}
else
{
ColumnFormatter fmt;
fmt.setItems(suggestions.begin(), suggestions.end());
fmt.format(width() / 10);
setTextColor( OUTPUT_COLOR );
const std::list<std::string>& formatted = fmt.formattedOutput();
for (std::list<std::string>::const_iterator it = formatted.begin();
it != formatted.end(); ++it)
{
append(it->c_str());
}
std::cout << width() << "\n";
setTextColor( NORMAL_COLOR );
}
}
// set up the next line on the console
append("");
displayPrompt( );
moveCursorToEnd( );
cursor.insertText( line );
moveCursorToEnd( );
}
void Console::previousHistory( )
{
if ( ! cursorIsOnInputLine( ) )
return;
if ( ! m_historyBuffer.size( ) )
return;
QTextCursor cursor = textCursor();
cursor.movePosition( QTextCursor::StartOfLine );
cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, Console::PROMPT.size( ) );
cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
cursor.removeSelectedText( );
if ( m_historyIt != m_historyBuffer.begin( ) )
{
--m_historyIt;
}
cursor.insertText( m_historyIt->c_str() );
}
void Console::nextHistory( )
{
if ( ! cursorIsOnInputLine( ) )
return;
if ( ! m_historyBuffer.size( ) )
return;
if ( m_historyIt == m_historyBuffer.end( ) )
{
return;
}
QTextCursor cursor = textCursor();
cursor.movePosition( QTextCursor::StartOfLine );
cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, Console::PROMPT.size( ) );
cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
cursor.removeSelectedText( );
++m_historyIt;
if ( m_historyIt == m_historyBuffer.end( ) )
{
return;
}
cursor.insertText( m_historyIt->c_str() );
}
void Console::moveCursorToEnd( )
{
QTextCursor cursor = textCursor();
cursor.movePosition( QTextCursor::End );
setTextCursor( cursor );
}

78
3rdparty/python-console/Console.h vendored Normal file
View File

@ -0,0 +1,78 @@
/**
python-console
Copyright (C) 2018 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef ATSUI_CONSOLE_H
#define ATSUI_CONSOLE_H
#include <QTextEdit>
#include <QColor>
#include "ParseHelper.h"
#include "ParseListener.h"
class QWidget;
class QKeyEvent;
class Interpreter;
class Console : public QTextEdit, ParseListener
{
Q_OBJECT
public:
Console( QWidget* parent = 0 );
virtual ~Console( );
protected:
// override QTextEdit
virtual void keyPressEvent( QKeyEvent* e );
virtual void handleReturnKeyPress( );
/**
Handle a compilable chunk of Python user input.
*/
virtual void parseEvent( const ParseMessage& message );
QString getLine( );
bool cursorIsOnInputLine( );
bool inputLineIsEmpty( );
bool canBackspace( );
bool canGoLeft( );
void displayPrompt( );
void autocomplete( );
void previousHistory( );
void nextHistory( );
void moveCursorToEnd( );
static const QString PROMPT;
static const QString MULTILINE_PROMPT;
static const QColor NORMAL_COLOR;
static const QColor ERROR_COLOR;
static const QColor OUTPUT_COLOR;
Interpreter* m_interpreter;
ParseHelper m_parseHelper;
std::list<std::string> m_historyBuffer;
std::list<std::string>::const_iterator m_historyIt;
};
#endif // ATSUI_CONSOLE_H

231
3rdparty/python-console/Interpreter.cpp vendored Normal file
View File

@ -0,0 +1,231 @@
#include "Interpreter.h"
#include <iostream>
#include <map>
#include <boost/format.hpp>
PyThreadState* Interpreter::MainThreadState = NULL;
Interpreter::Interpreter( )
{
PyEval_AcquireLock( );
m_threadState = Py_NewInterpreter( );
PyObject *module = PyImport_ImportModule("__main__");
loc = glb = PyModule_GetDict(module);
SetupRedirector( m_threadState );
PyRun_SimpleString("import sys\n"
"import redirector\n"
"sys.path.insert(0, \".\")\n" // add current path
"sys.stdout = redirector.redirector()\n"
"sys.stderr = sys.stdout\n"
"import rlcompleter\n"
"sys.completer = rlcompleter.Completer()\n"
);
PyEval_ReleaseThread( m_threadState );
}
Interpreter::~Interpreter( )
{
#ifndef NDEBUG
std::cout << "delete interpreter\n";
#endif
PyEval_AcquireThread( m_threadState );
Py_EndInterpreter( m_threadState );
PyEval_ReleaseLock( );
}
void
Interpreter::test( )
{
PyEval_AcquireThread( m_threadState );
PyObject* py_result;
PyObject* dum;
std::string command = "print 'Hello world'\n";
py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
if ( py_result == 0 )
{
std::cout << "Huh?\n";
PyEval_ReleaseThread( m_threadState );
return;
}
dum = PyEval_EvalCode ((PyCodeObject *)py_result, glb, loc);
Py_XDECREF (dum);
Py_XDECREF (py_result);
std::cout << GetResultString( m_threadState );
GetResultString( m_threadState ) = "";
PyEval_ReleaseThread( m_threadState );
}
std::string
Interpreter::interpret( const std::string& command, int* errorCode )
{
PyEval_AcquireThread( m_threadState );
*errorCode = 0;
PyObject* py_result;
PyObject* dum;
std::string res;
#ifndef NDEBUG
std::cout << "interpreting (" << command << ")\n";
#endif
py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
if ( py_result == 0 )
{
#ifndef NDEBUG
std::cout << "Huh?\n";
#endif
if ( PyErr_Occurred( ) )
{
*errorCode = 1;
PyErr_Print( );
res = GetResultString( m_threadState );
GetResultString( m_threadState ) = "";
}
PyEval_ReleaseThread( m_threadState );
return res;
}
dum = PyEval_EvalCode ((PyCodeObject *)py_result, glb, loc);
Py_XDECREF (dum);
Py_XDECREF (py_result);
if ( PyErr_Occurred( ) )
{
*errorCode = 1;
PyErr_Print( );
}
res = GetResultString( m_threadState );
GetResultString( m_threadState ) = "";
PyEval_ReleaseThread( m_threadState );
return res;
}
const std::list<std::string>& Interpreter::suggest( const std::string& hint )
{
PyEval_AcquireThread( m_threadState );
m_suggestions.clear();
int i = 0;
std::string command = boost::str(
boost::format("sys.completer.complete('%1%', %2%)\n")
% hint
% i);
#ifndef NDEBUG
std::cout << command << "\n";
#endif
std::string res;
do
{
PyObject* py_result;
PyObject* dum;
py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
dum = PyEval_EvalCode ((PyCodeObject *)py_result, glb, loc);
Py_XDECREF (dum);
Py_XDECREF (py_result);
res = GetResultString( m_threadState );
GetResultString( m_threadState ) = "";
++i;
command = boost::str(
boost::format("sys.completer.complete('%1%', %2%)\n")
% hint
% i);
if (res.size())
{
// throw away the newline
res = res.substr(1, res.size() - 3);
m_suggestions.push_back(res);
}
}
while (res.size());
PyEval_ReleaseThread( m_threadState );
return m_suggestions;
}
void
Interpreter::Initialize( )
{
Py_Initialize( );
PyEval_InitThreads( );
MainThreadState = PyEval_SaveThread( );
}
void
Interpreter::Finalize( )
{
PyEval_RestoreThread( MainThreadState );
Py_Finalize( );
}
std::string& Interpreter::GetResultString( PyThreadState* threadState )
{
static std::map< PyThreadState*, std::string > ResultStrings;
if ( !ResultStrings.count( threadState ) )
{
ResultStrings[ threadState ] = "";
}
return ResultStrings[ threadState ];
}
PyObject* Interpreter::RedirectorInit(PyObject *, PyObject *)
{
Py_INCREF(Py_None);
return Py_None;
}
PyObject* Interpreter::RedirectorWrite(PyObject *, PyObject *args)
{
char* output;
PyObject *selfi;
if (!PyArg_ParseTuple(args,"Os",&selfi,&output))
{
return NULL;
}
std::string outputString( output );
PyThreadState* currentThread = PyThreadState_Get( );
std::string& resultString = GetResultString( currentThread );
resultString = resultString + outputString;
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef Interpreter::ModuleMethods[] = { {NULL,NULL,0,NULL} };
PyMethodDef Interpreter::RedirectorMethods[] =
{
{"__init__", Interpreter::RedirectorInit, METH_VARARGS,
"initialize the stdout/err redirector"},
{"write", Interpreter::RedirectorWrite, METH_VARARGS,
"implement the write method to redirect stdout/err"},
{NULL,NULL,0,NULL},
};
void Interpreter::SetupRedirector( PyThreadState* threadState )
{
PyMethodDef *def;
/* create a new module and class */
PyObject *module = Py_InitModule("redirector", ModuleMethods);
PyObject *moduleDict = PyModule_GetDict(module);
PyObject *classDict = PyDict_New();
PyObject *className = PyString_FromString("redirector");
PyObject *fooClass = PyClass_New(NULL, classDict, className);
PyDict_SetItemString(moduleDict, "redirector", fooClass);
Py_DECREF(classDict);
Py_DECREF(className);
Py_DECREF(fooClass);
/* add methods to class */
for (def = RedirectorMethods; def->ml_name != NULL; def++) {
PyObject *func = PyCFunction_New(def, NULL);
PyObject *method = PyMethod_New(func, NULL, fooClass);
PyDict_SetItemString(classDict, def->ml_name, method);
Py_DECREF(func);
Py_DECREF(method);
}
}

97
3rdparty/python-console/Interpreter.h vendored Normal file
View File

@ -0,0 +1,97 @@
/**
python-console
Copyright (C) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef INTERPRETER_H
#define INTERPRETER_H
#include <string>
#include <list>
#include <Python.h>
#if defined(__APPLE__) && defined(__MACH__)
/*
* The following undefs for C standard library macros prevent
* build errors of the following type on mac ox 10.7.4 and XCode 4.3.3
*
/usr/include/c++/4.2.1/bits/localefwd.h:57:21: error: too many arguments provided to function-like macro invocation
isspace(_CharT, const locale&);
^
/usr/include/c++/4.2.1/bits/localefwd.h:56:5: error: 'inline' can only appear on functions
inline bool
^
/usr/include/c++/4.2.1/bits/localefwd.h:57:5: error: variable 'isspace' declared as a template
isspace(_CharT, const locale&);
^
*/
#undef isspace
#undef isupper
#undef islower
#undef isalpha
#undef isalnum
#undef toupper
#undef tolower
#endif
/**
Wraps a Python interpreter, which you can pass commands as strings to interpret
and get strings of output/error in return.
*/
class Interpreter
{
protected:
static PyThreadState* MainThreadState;
PyThreadState* m_threadState;
PyObject* glb;
PyObject* loc;
std::list< std::string > m_suggestions;
public:
/**
Instantiate a Python interpreter.
*/
Interpreter( );
virtual ~Interpreter( );
void test( );
std::string interpret( const std::string& command, int* errorCode );
const std::list<std::string>& suggest( const std::string& hint );
/**
Call this before constructing and using Interpreter.
*/
static void Initialize( );
/**
Call this when done using Interpreter.
*/
static void Finalize( );
protected:
static void SetupRedirector( PyThreadState* threadState );
static PyObject* RedirectorInit(PyObject *, PyObject *);
static PyObject* RedirectorWrite(PyObject *, PyObject *args);
static std::string& GetResultString( PyThreadState* threadState );
static PyMethodDef ModuleMethods[];
static PyMethodDef RedirectorMethods[];
};
#endif // INTERPRETER_H

19
3rdparty/python-console/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright 2018 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,174 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseHelper.h"
ParseHelper::BlockParseState::
BlockParseState( ParseHelper& parent ):
ParseState( parent )
{ }
ParseHelper::BlockParseState::
BlockParseState( ParseHelper& parent, const std::string& indent_ ):
ParseState( parent ),
indent( indent_ )
{ }
bool ParseHelper::BlockParseState::
process(const std::string& str)
{
bool ok = initializeIndent(str);
if ( ! ok )
{
// finish processing
return true;
}
Indent ind;
bool isIndented = PeekIndent( str, &ind );
if ( isIndented )
{
#ifndef NDEBUG
std::cout << "current line indent: ";
print( ind );
#endif
// check if indent matches
if ( ind.Token != indent.Token )
{
// dedent until we match or empty the stack
bool found = false;
while ( !found )
{
parent.stateStack.pop_back( );
if ( !parent.stateStack.size( ) )
break;
boost::shared_ptr<BlockParseState> parseState =
boost::dynamic_pointer_cast<BlockParseState>(
parent.stateStack.back( ));
found = ( ind.Token == parseState->indent.Token );
}
if ( ! found )
{
#ifndef NDEBUG
std::cout << "indent mismatch\n";
#endif
parent.reset( );
ParseMessage msg( 1, "IndentationError: unexpected indent");
parent.broadcast( msg );
return true;
}
}
// process command
// enter indented block state
if ( str[str.size()-1] == ':' )
{
parent.commandBuffer.push_back( str );
//parent.inBlock = (boost::dynamic_pointer_cast<BlockParseState>(
// parent.stateStack.back()));
//expectingIndent = true;
boost::shared_ptr<ParseState> parseState(
new BlockParseState( parent ) );
parent.stateStack.push_back( parseState );
return true;
}
if ( str[str.size()-1] == '\\' )
{
parent.commandBuffer.push_back( str );
boost::shared_ptr<ParseState> parseState(
new ContinuationParseState( parent ) );
parent.stateStack.push_back( parseState );
return true;
}
if (BracketParseState::HasOpenBrackets( str ))
{
// FIXME: Every parse state should have its own local buffer
boost::shared_ptr<ParseState> parseState(
new BracketParseState( parent, str ) );
parent.stateStack.push_back( parseState );
return true;
}
parent.commandBuffer.push_back( str );
return true;
}
else
{
if ( str.size() )
{
{
#ifndef NDEBUG
std::cout << "Expected indented block\n";
#endif
parent.reset( );
ParseMessage msg( 1, "IndentationError: expected an indented block" );
parent.broadcast( msg );
return false;
}
}
#ifndef NDEBUG
std::cout << "Leaving block\n";
#endif
parent.stateStack.pop_back();
parent.flush( );
parent.reset( );
return true;
}
}
bool ParseHelper::BlockParseState::
initializeIndent(const std::string& str)
{
bool expectingIndent = (indent.Token == "");
if ( !expectingIndent )
{
std::cout << "already initialized indent: ";
print( indent );
return true;
}
Indent ind;
bool isIndented = parent.PeekIndent( str, &ind );
if ( !isIndented )
{
#ifndef NDEBUG
std::cout << "Expected indented block\n";
#endif
parent.reset( );
ParseMessage msg( 1, "IndentationError: expected an indented block" );
parent.broadcast( msg );
return false;
}
indent = ind;
//parent.currentIndent = ind;
//parent.indentStack.push_back( parent.currentIndent );
//parent.expectingIndent = false;
#ifndef NDEBUG
std::cout << "initializing indent: ";
print( ind );
#endif
return true;
}

View File

@ -0,0 +1,127 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseHelper.h"
#include <string>
#include <sstream>
const std::string ParseHelper::BracketParseState::OpeningBrackets = "[({";
const std::string ParseHelper::BracketParseState::ClosingBrackets = "])}";
bool ParseHelper::BracketParseState::HasOpenBrackets(const std::string& str)
{
std::list<char> brackets;
bool hasOpenBrackets = LoadBrackets(str, &brackets);
return hasOpenBrackets;
}
bool ParseHelper::BracketParseState::LoadBrackets(const std::string& str,
std::list<char>* stack)
{
if ( !stack )
return false;
stack->clear();
for (int i = 0; i < str.size(); ++i)
{
if (OpeningBrackets.find_first_of(str[i]) != std::string::npos)
{
stack->push_back(str[i]);
}
else
{
size_t t = ClosingBrackets.find_first_of(str[i]);
if (t != std::string::npos)
{
if (t != OpeningBrackets.find_first_of(stack->back()))
return false;
stack->pop_back();
}
}
}
return stack->size();
}
ParseHelper::BracketParseState::BracketParseState( ParseHelper& parent, const std::string& firstLine ):
ParseState( parent )
{
bool hasOpenBrackets = LoadBrackets( firstLine, &brackets );
assert( hasOpenBrackets );
m_buffer.push_back( firstLine );
}
bool ParseHelper::BracketParseState::process(const std::string& str)
{
#ifndef NDEBUG
std::cout << "(BracketParseState) processing " << str << "\n";
#endif
// update brackets stack
for (int i = 0; i < str.size(); ++i)
{
if (OpeningBrackets.find_first_of(str[i]) != std::string::npos)
{
#ifndef NDEBUG
std::cout << "push " << str[i] << "\n";
#endif
brackets.push_back(str[i]);
}
else
{
size_t t = ClosingBrackets.find_first_of(str[i]);
if (t != std::string::npos)
{
#ifndef NDEBUG
std::cout << "pop " << str[i] << "\n";
#endif
// reset state if unmatched brackets seen
if (t != OpeningBrackets.find_first_of(brackets.back()))
{
parent.reset( );
ParseMessage msg(1, "Invalid syntax");
parent.broadcast( msg );
return true;
}
brackets.pop_back();
}
}
}
// if we've cleared the stack, we've finished accepting input here
if (!brackets.size())
{
// squash buffered lines and place it on parent::commandBuffer
std::stringstream ss;
for (std::list<std::string>::const_iterator it = m_buffer.begin();
it != m_buffer.end(); ++it )
{
ss << *it << "\n";
}
ss << str;
parent.commandBuffer.push_back(ss.str());
parent.stateStack.pop_back( );
return false;
}
else
{
// buffer and expect more lines
m_buffer.push_back( str );
return true;
}
}

View File

@ -0,0 +1,61 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseHelper.h"
#include <list>
#include <sstream>
ParseHelper::ContinuationParseState::
ContinuationParseState( ParseHelper& parent_ ):
ParseState( parent_ )
{ }
bool ParseHelper::ContinuationParseState::
process( const std::string& str )
{
if ( str.size() && str[str.size()-1] == '\\' )
{
parent.commandBuffer.push_back( str );
return true;
}
else
{
std::list<std::string> tmp_list;
tmp_list.push_back(str);
while (parent.commandBuffer.size() && parent.commandBuffer.back()[
parent.commandBuffer.back().size()-1] == '\\')
{
tmp_list.push_back(parent.commandBuffer.back());
parent.commandBuffer.pop_back();
}
std::stringstream ss;
while (tmp_list.size())
{
ss << tmp_list.back();
tmp_list.pop_back();
if (tmp_list.size())
ss << "\n";
}
parent.commandBuffer.push_back(ss.str());
parent.stateStack.pop_back();
return false;
}
}

225
3rdparty/python-console/ParseHelper.cpp vendored Normal file
View File

@ -0,0 +1,225 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseHelper.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <cstdlib>
#include "ParseListener.h"
#ifndef NDEBUG
void print(const ParseHelper::Indent& indent)
{
std::string str = indent.Token;
for (int i = 0; i < str.size(); ++i)
{
switch (str.at(i))
{
case ' ':
str[i] = 's';
break;
case '\t':
str[i] = 't';
break;
}
}
std::cout << str << "\n";
}
#endif
ParseHelper::Indent::
Indent( )
{ }
ParseHelper::Indent::
Indent( const std::string& indent ):
Token( indent )
{ }
ParseHelper::ParseState::
ParseState( ParseHelper& parent_ ): parent( parent_ )
{ }
ParseHelper::ParseState::
~ParseState( )
{ }
bool ParseHelper::PeekIndent( const std::string& str, Indent* indent )
{
if ( !str.size() || ! isspace(str[0]) )
return false;
int nonwhitespaceIndex = -1;
for (int i = 0; i < str.size(); ++i)
{
if (!isspace(str[i]))
{
nonwhitespaceIndex = i;
break;
}
}
if (nonwhitespaceIndex == -1)
{
return false;
}
std::string indentToken = str.substr(0, nonwhitespaceIndex);
indent->Token = indentToken;
return true;
}
ParseHelper::ParseHelper( )
{ }
void ParseHelper::process( const std::string& str )
{
#ifndef NDEBUG
std::cout << "processing: (" << str << ")\n";
#endif
std::string top;
commandBuffer.push_back(str);
//std::string top = commandBuffer.back();
//commandBuffer.pop_back();
boost::shared_ptr<ParseState> blockStatePtr;
while (stateStack.size())
{
top = commandBuffer.back();
commandBuffer.pop_back();
blockStatePtr = stateStack.back();
if (blockStatePtr->process(top))
return;
}
if ( ! commandBuffer.size() )
return;
// standard state
top = commandBuffer.back();
if ( !top.size() )
{
reset( );
broadcast( std::string() );
return;
}
#ifndef NDEBUG
std::cout << "now processing: (" << top << ")\n";
#endif
{ // check for unexpected indent
Indent ind;
bool isIndented = PeekIndent( top, &ind );
if ( isIndented &&
! isInContinuation( ) )
{
reset( );
ParseMessage msg( 1, "IndentationError: unexpected indent");
broadcast( msg );
return;
}
}
// enter indented block state
if ( top[top.size()-1] == ':' )
{
boost::shared_ptr<ParseState> parseState(
new BlockParseState( *this ) );
stateStack.push_back( parseState );
return;
}
if ( top[top.size()-1] == '\\' )
{
boost::shared_ptr<ParseState> parseState(
new ContinuationParseState( *this ) );
stateStack.push_back( parseState );
return;
}
if (BracketParseState::HasOpenBrackets( top ))
{
// FIXME: Every parse state should have its own local buffer
commandBuffer.pop_back( );
boost::shared_ptr<ParseState> parseState(
new BracketParseState( *this, top ) );
stateStack.push_back( parseState );
return;
}
// handle single-line statement
flush( );
}
bool ParseHelper::buffered( ) const
{
return commandBuffer.size( ) || stateStack.size( );
}
void ParseHelper::flush( )
{
std::stringstream ss;
for (int i = 0; i < commandBuffer.size(); ++i )
{
ss << commandBuffer[i] << "\n";
}
commandBuffer.clear();
broadcast( ss.str() );
// TODO: feed string to interpreter
}
void ParseHelper::reset( )
{
// inContinuation = false;
stateStack.clear( );
commandBuffer.clear( );
}
bool ParseHelper::isInContinuation( ) const
{
return (stateStack.size()
&& (boost::dynamic_pointer_cast<ContinuationParseState>(
stateStack.back())));
}
void ParseHelper::subscribe( ParseListener* listener )
{
listeners.push_back( listener );
}
void ParseHelper::unsubscribeAll( )
{
listeners.clear( );
}
void ParseHelper::broadcast( const ParseMessage& msg )
{
// broadcast signal
for (int i = 0; i < listeners.size(); ++i)
{
if (listeners[i])
{
listeners[i]->parseEvent(msg);
}
}
}

169
3rdparty/python-console/ParseHelper.h vendored Normal file
View File

@ -0,0 +1,169 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PARSE_HELPER_H
#define PARSE_HELPER_H
#include <string>
#include <vector>
#include <list>
#include <boost/shared_ptr.hpp>
#include "ParseMessage.h"
class ParseListener;
/**
Helps chunk lines of Python code into compilable statements.
*/
class ParseHelper
{
public:
struct Indent
{
std::string Token;
Indent( );
Indent( const std::string& indent );
};
/**
Handle different states of parsing. Subclasses override
process(const std::string&) to handle different types of multiline
statements.
*/
struct ParseState
{
ParseHelper& parent;
ParseState( ParseHelper& parent_ );
virtual ~ParseState( );
/**
Processes a single line of user input.
Subclasses should return false if further processing should be done. In
this case, the command buffer should be topped by the next statement to
parse.
\return whether processing of the line is done.
*/
virtual bool process(const std::string& str) = 0;
};
struct ContinuationParseState : public ParseState
{
using ParseState::parent;
ContinuationParseState( ParseHelper& parent_ );
virtual bool process( const std::string& str);
};
/**
Handle parsing a multiline indented block. Example of such a block:
for i in range(10):
print i
print i*i
*/
struct BlockParseState : public ParseState
{
Indent indent;
BlockParseState( ParseHelper& parent );
BlockParseState( ParseHelper& parent, const std::string& indent_ );
// return whether processing is finished
virtual bool process(const std::string& str);
// return if there was an error
bool initializeIndent(const std::string& str);
};
friend class BlockParseState;
struct BracketParseState : public ParseState
{
static const std::string OpeningBrackets;
static const std::string ClosingBrackets;
std::list<char> brackets;
std::list<std::string> m_buffer;
/**
Return whether open brackets remain unclosed in \a str.
*/
static bool HasOpenBrackets(const std::string& str);
static bool LoadBrackets(const std::string& str,
std::list<char>* stack);
BracketParseState( ParseHelper& parent, const std::string& firstLine );
virtual bool process(const std::string& str);
};
protected:
// TODO: Create a ContinuationParseState to handle this
bool inContinuation;
std::vector< ParseListener* > listeners;
std::vector< boost::shared_ptr< ParseState > > stateStack;
std::vector< std::string > commandBuffer;
public:
static bool PeekIndent( const std::string& str, Indent* indent );
public:
ParseHelper( );
public:
void process( const std::string& str );
bool buffered( ) const;
/**
Generate a parse event from the current command buffer.
*/
void flush( );
/**
Reset the state of the helper.
*/
void reset( );
bool isInContinuation( ) const;
void subscribe( ParseListener* listener );
void unsubscribeAll( );
void broadcast( const ParseMessage& msg );
}; // class ParseHelper
inline bool operator== ( const ParseHelper::Indent& a, const ParseHelper::Indent& b )
{
return a.Token == b.Token;
}
inline bool operator!= ( const ParseHelper::Indent& a, const ParseHelper::Indent& b )
{
return a.Token != b.Token;
}
#ifndef NDEBUG
void print(const ParseHelper::Indent& indent);
#endif
#endif // PARSE_HELPER_H

View File

@ -0,0 +1,29 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseListener.h"
#include <iostream>
void EchoListener::parseEvent( const ParseMessage& msg )
{
std::cout << "echo(" << msg.errorCode << "): " << msg.message << "\n";
}

42
3rdparty/python-console/ParseListener.h vendored Normal file
View File

@ -0,0 +1,42 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PARSE_LISTENER_H
#define PARSE_LISTENER_H
#include "ParseMessage.h"
/**
Interface to implement to receive parse events.
*/
struct ParseListener
{
virtual void parseEvent( const ParseMessage& msg ) = 0;
};
/**
Sample implementation of ParseListener that echoes messages.
*/
struct EchoListener : public ParseListener
{
virtual void parseEvent( const ParseMessage& msg );
};
#endif // PARSE_LISTENER_H

View File

@ -0,0 +1,31 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "ParseMessage.h"
ParseMessage::ParseMessage( const std::string& msg ):
errorCode( 0 ), message( msg )
{ }
ParseMessage::ParseMessage( int code, const std::string& msg ):
errorCode( code ), message( msg )
{ }

38
3rdparty/python-console/ParseMessage.h vendored Normal file
View File

@ -0,0 +1,38 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PARSE_MESSAGE_H
#define PARSE_MESSAGE_H
#include <string>
/**
Basically a string + error code pair. Generated from ParseHelper so error-free
codeblocks can be sent to the Interpreter.
*/
struct ParseMessage
{
int errorCode;
std::string message;
ParseMessage( const std::string& msg );
ParseMessage( int code, const std::string& msg );
};
#endif //PARSE_MESSAGE_H

17
3rdparty/python-console/README.md vendored Normal file
View File

@ -0,0 +1,17 @@
python-console
=====
This is the result of a small side project to write a Qt widget that
encapsulates an interactive Python shell.
Quickstart
-----
You should have Qt4 and Python libraries. You will need CMake to build this
project as follows:
1. mkdir build
2. cmake ..
3. make
License
-----
This project is licensed under the [MIT](http://opensource.org/licenses/MIT) license.

33
3rdparty/python-console/Utils.h vendored Normal file
View File

@ -0,0 +1,33 @@
#ifndef PYTHON_CONSOLE_UTILS_H
#define PYTHON_CONSOLE_UTILS_H
#include <string>
#include <vector>
/**
InputIterator has value type of std::string.
*/
template < class InputIterator >
std::string LongestCommonPrefix( InputIterator begin, InputIterator end )
{
if ( begin == end )
return "";
const std::string& str0 = *begin;
if ( ! str0.size() )
return "";
int endIndex = str0.size() - 1;
InputIterator it = begin; ++it;
for (; it != end; ++it)
{
const std::string& str = *it;
for (int j = 0; j <= endIndex; ++j)
{
if (j >= str.size() || str[j] != str0[j])
endIndex = j - 1;
}
}
return (endIndex > 0)? str0.substr(0, endIndex + 1) : "";
}
#endif // PYTHON_CONSOLE_UTILS_H

2
3rdparty/python-console/data/test.py vendored Normal file
View File

@ -0,0 +1,2 @@
for i in range(1, 10):
print i

6
3rdparty/python-console/data/test2.py vendored Normal file
View File

@ -0,0 +1,6 @@
for i in range(1, 10):
print i
for i in range(1, 10):
print i
print i

4
3rdparty/python-console/data/test3.py vendored Normal file
View File

@ -0,0 +1,4 @@
for i in range(1, 10):
print i
for i in range(1, 10):
print i

4
3rdparty/python-console/data/test4.py vendored Normal file
View File

@ -0,0 +1,4 @@
for i in range(2):
for j in range(3):
print j
print i

3
3rdparty/python-console/data/test5.py vendored Normal file
View File

@ -0,0 +1,3 @@
for i in range(2):
for j in range(3):
print i, j

63
3rdparty/python-console/test_cli.cpp vendored Normal file
View File

@ -0,0 +1,63 @@
#include <iostream>
#include <string>
#include "ParseHelper.h"
#include "ParseListener.h"
#include "Interpreter.h"
const std::string STD_PROMPT = ">>> ";
const std::string MULTILINE_PROMPT = "... ";
struct InterpreterRelay : public ParseListener
{
Interpreter* m_interpreter;
InterpreterRelay( ):
m_interpreter( new Interpreter )
{ }
virtual void parseEvent( const ParseMessage& msg )
{
if ( msg.errorCode )
{
std::cout << "(" << msg.errorCode << ") " << msg.message << "\n";
return;
}
else
{
int err;
std::string res = m_interpreter->interpret( msg.message, &err );
std::cout << "(" << msg.errorCode << ") " << res << "\n";
}
}
};
int main( int argc, char *argv[] )
{
Interpreter::Initialize( );
const std::string* prompt = &STD_PROMPT;
ParseHelper helper;
ParseListener* listener = new InterpreterRelay;
helper.subscribe( listener );
std::string str;
std::cout << *prompt;
std::getline( std::cin, str );
while ( str != "quit" )
{
std::cout << str << "\n";
helper.process( str );
if ( helper.buffered( ) )
{
prompt = &MULTILINE_PROMPT;
}
else
{
prompt = &STD_PROMPT;
}
std::cout << *prompt;
std::getline( std::cin, str );
}
Interpreter::Finalize( );
return 0;
}

View File

@ -0,0 +1,36 @@
#include <iostream>
#include <QApplication>
#include <QMainWindow>
#include <QWidget>
#include <QGridLayout>
#include <QTextEdit>
#include "Console.h"
#include "Interpreter.h"
Console* console;
void SetupWindow( int argc, char *argv[] )
{
QMainWindow* window = new QMainWindow;
window->resize( 800, 600 );
QWidget* centralWidget = new QWidget(window);
QGridLayout* layout = new QGridLayout(centralWidget);
console = new Console;
layout->addWidget(console, 0, 0, 1, 1);
window->setCentralWidget(centralWidget);
window->show( );
}
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
Interpreter::Initialize( );
SetupWindow( argc, argv );
bool res = app.exec( );
delete console;
Interpreter::Finalize( );
return res;
}

View File

@ -0,0 +1,51 @@
/**
Copyright (c) 2014 Alex Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <iostream>
#include <fstream>
#include "ParseHelper.h"
#include "ParseListener.h"
/**
Demonstrates the ParseHelper.
Call it with some of the python files in data/.
*/
int main( int argc, char *argv[] )
{
if ( argc < 2 )
{
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
ParseHelper helper;
helper.subscribe( new EchoListener );
std::ifstream ifs( argv[1] );
while ( ! ifs.eof( ) )
{
std::string str;
std::getline( ifs, str );
helper.process( str );
}
return 0;
}

View File

@ -0,0 +1,22 @@
#include <iostream>
#include "Interpreter.h"
int main( int argc, char *argv[] )
{
std::string commands[] = {
"from time import time,ctime\n",
"print 'Today is',ctime(time())\n"
};
Interpreter::Initialize( );
Interpreter* interpreter = new Interpreter;
for ( int i = 0; i < 2; ++i )
{
int err;
std::string res = interpreter->interpret( commands[i], &err );
std::cout << res;
}
delete interpreter;
Interpreter::Finalize( );
return 0;
}