Skip to content

Commit

Permalink
Merge pull request #10 from treefrogframework/support_copypaste
Browse files Browse the repository at this point in the history
Support copy and paste
  • Loading branch information
treefrogframework authored Apr 13, 2024
2 parents 6469c38 + 4f022f8 commit 066d774
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 98 deletions.
8 changes: 4 additions & 4 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ environment:
# Qt6.2 / VisualStudio 2019 64bit
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
INIT_BAT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat
QT_PATH: C:\Qt\6.3\msvc2019_64
QT_PATH: C:\Qt\6.2\msvc2019_64

# scripts that are called at very beginning, before repo cloning
init:
Expand All @@ -44,6 +44,6 @@ build_script:
- cmd: echo %PATH%
- cmd: qmake CONFIG+=release
- cmd: nmake
- cmd: release\cpi.exe tests\helloworld.cpp
- cmd: release\cpi.exe tests\sqrt.cpp 7
- cmd: release\cpi.exe tests\fibonacci.cpp 10
- cmd: cpi.exe tests\helloworld.cpp
- cmd: cpi.exe tests\sqrt.cpp 7
- cmd: cpi.exe tests\fibonacci.cpp 10
37 changes: 37 additions & 0 deletions build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@echo off

set PATH=C:\Qt\6.7.0\msvc2019_64\bin;%PATH%
set CWD=%~dp0

set VCVARSBAT=""
set VSVER=2022 2019 2017
set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"

where cl.exe >NUL 2>&1
if ERRORLEVEL 1 (
if exist %VSWHERE% (
for %%v in (%VSVER%) do (
for /f "usebackq tokens=*" %%i in (`%VSWHERE% -find **\vcvarsall.bat`) do (
echo %%i | find "%%v" >NUL
if not ERRORLEVEL 1 (
set VCVARSBAT="%%i"
set VSVER=%%v
goto :break
)
)
)
)

:break
if exist %VCVARSBAT% (
echo Setting up environment for MSVC %VSVER% usage...
call %VCVARSBAT% amd64
)
)

cd /D %CWD%
qmake
nmake
if ERRORLEVEL 1 (
pause
)
23 changes: 9 additions & 14 deletions codegenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,19 @@ static QString modifyCode(const QString &code, bool safeCode = false)
}


QString CodeGenerator::generateMainFunc() const
QString CodeGenerator::generateMainFunc(bool safety) const
{
const QRegularExpression re(" main *(.*)");
QString src;
QString modified = modifyCode(_code, false);
if (Compiler::isSetQtOption()) {
src = QString(CPI_SRC).arg(_headers, modified, QT_HEADERS, QT_INIT, QT_PARSE);
} else {
src = QString(CPI_SRC).arg(_headers, modified, "", "", "");
}
return src;
}


if (_code.contains(re)) {
src += _headers;
src += "\n";
src += _code;
return src;
}

QString CodeGenerator::generateMainFuncSafe() const
{
QString src;
QString modified = modifyCode(_code, true);
QString modified = modifyCode(_code, safety);
if (Compiler::isSetQtOption()) {
src = QString(CPI_SRC).arg(_headers, modified, QT_HEADERS, QT_INIT, QT_PARSE);
} else {
Expand Down
4 changes: 2 additions & 2 deletions codegenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
class CodeGenerator {
public:
CodeGenerator(const QString &headers, const QString &code);
QString generateMainFunc() const;
QString generateMainFuncSafe() const;
QString generateMainFunc(bool safety = false) const;
//QString generateMainFuncSafe() const;

private:
QString _headers;
Expand Down
50 changes: 20 additions & 30 deletions cpi.bat
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
@echo OFF
@echo off

set CWD=%~dp0
set VCVARSBAT=""
set VSVER=
set VSVER2022=2022
set VSVER2019=2019
set VSVER2017=2017
set VSWHERE="%PROGRAMFILES(X86)%\Microsoft Visual Studio\Installer\vswhere.exe"
set VSVER=2022 2019 2017
set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"

if exist %VSWHERE% (
for /f "usebackq tokens=*" %%i in (`%VSWHERE% -find **\vcvarsall.bat`) do (
echo %%i | find "%VSVER2022%" >NUL
if not ERRORLEVEL 1 (
set VCVARSBAT="%%i"
set VSVER=%VSVER2022%
goto :break
)
echo %%i | find "%VSVER2019%" >NUL
if not ERRORLEVEL 1 (
set VCVARSBAT="%%i"
set VSVER=%VSVER2019%
goto :break
)
echo %%i | find "%VSVER2017%" >NUL
if not ERRORLEVEL 1 (
set VCVARSBAT="%%i"
set VSVER=%VSVER2017%
goto :break
where cl.exe >NUL
if ERRORLEVEL 1 (
if exist %VSWHERE% (
for %%v in (%VSVER%) do (
for /f "usebackq tokens=*" %%i in (`%VSWHERE% -find **\vcvarsall.bat`) do (
echo %%i | find "%%v" >NUL
if not ERRORLEVEL 1 (
set VCVARSBAT="%%i"
goto :break
)
)
)
)
)

:break
if exist %VCVARSBAT% (
call %VCVARSBAT% amd64 >nul
echo Set up environment for MSVC %VSVER% usage
if exist %VCVARSBAT% (
echo Setting up environment for MSVC usage...
call %VCVARSBAT% amd64
)
)

@rem Run cpi
cd /D %CWD%
cpi.exe
11 changes: 3 additions & 8 deletions cpi.pro
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@ INCLUDEPATH += .


windows {
CONFIG(debug, debug|release) {
EXEFILE = $${OUT_PWD}/debug/cpi.exe
} else {
EXEFILE = $${OUT_PWD}/release/cpi.exe
}
DESTDIR = $${OUT_PWD}
EXEFILE = $${OUT_PWD}/cpi.exe
QMAKE_POST_LINK = windeployqt.exe \"$$EXEFILE\"
}

!windows {
} else {
isEmpty( target.path ) {
target.path = /usr/local/bin
}
Expand Down
136 changes: 96 additions & 40 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <iostream>
#include <list>
#ifdef Q_OS_WIN
#include <conio.h>
#include <windows.h>
#else
#include <csignal>
Expand All @@ -20,7 +21,7 @@ constexpr auto CPI_VERSION_STR = "2.1.0";
#ifdef Q_CC_MSVC
constexpr auto DEFAULT_CONFIG = "[General]\n"
"CXX=cl.exe\n"
"CXXFLAGS=\n"
"CXXFLAGS=/std:c++20\n"
"LDFLAGS=\n"
"COMMON_INCLUDES=\n";
#else
Expand Down Expand Up @@ -209,13 +210,71 @@ static void showCode()
}


static bool waitForReadyStdInputRead(int msecs)
{
QElapsedTimer timer;
timer.start();

#ifdef Q_OS_WIN
while (timer.elapsed() < msecs) {
if (_kbhit()) {
return true;
}
QThread::msleep(20);
}
return false;
#else
bool ret = false;
auto ready = [&]() {
ret = true;
};

QSocketNotifier notifier(fileno(stdin), QSocketNotifier::Read);
QObject::connect(&notifier, &QSocketNotifier::activated, ready);
qApp->processEvents();

while (timer.elapsed() < msecs && !ret) {
QThread::msleep(20);
qApp->processEvents();
}
return ret;
#endif
}


static void compile()
{
if (code.isEmpty()) {
return;
}

// compile
CodeGenerator cdgen(headers.join("\n"), code.join("\n"));
QString src = cdgen.generateMainFunc();

Compiler compiler;
int cpl = compiler.compileAndExecute(src);
if (cpl) {
// compile only once more
src = cdgen.generateMainFunc(true);
cpl = compiler.compileAndExecute(src);
}

if (cpl) {
compiler.printContextCompilationError();
// delete last line
if (lastLineNumber > 0) {
deleteLine(lastLineNumber);
}
}
};

static int interpreter()
{
print() << "Cpi " << CPI_VERSION_STR << endl;
print() << "cpi " << CPI_VERSION_STR << endl;
print() << "Type \".help\" for more information." << endl;
print() << "Loaded INI file: " << conf->fileName() << endl;
print().flush();
Compiler compiler;

QStringList includes = conf->value("COMMON_INCLUDES").toString().split(" ", SkipEmptyParts);
for (QStringListIterator i(includes); i.hasNext();) {
Expand All @@ -231,27 +290,35 @@ static int interpreter()
}

bool end = false;
auto readfunc = [&]() {
// read and write to the process
QString str;
auto readCodeAndCompile = [&]() {
QString line;
std::string s;

if (std::getline(std::cin, s)) {
str = QString::fromStdString(s);
line = QString::fromStdString(s);
} else {
end = true;
return;
}
line = line.trimmed();

if (line.isNull()) {
end = true;
return;
}

auto line = QString(str).trimmed();
line = line.trimmed();
if (line == ".quit" || line == ".q") {
end = true;
return;
}

class PromptOut {
public:
~PromptOut() { print() << "cpi> " << flush; }
~PromptOut() { print() << prompt << flush; }
void off() { prompt.clear(); }
private:
QByteArray prompt {"cpi> "};
} promptOut;

if (line == ".help" || line == "?") { // shows help
Expand Down Expand Up @@ -304,52 +371,41 @@ static int interpreter()
}
}

if (code.isEmpty())
if (waitForReadyStdInputRead(20)) {
// continue reading
promptOut.off();
return;

// compile
CodeGenerator cdgen(headers.join("\n"), code.join("\n"));
QString src = cdgen.generateMainFunc();

int cpl = compiler.compileAndExecute(src);
if (cpl) {
// compile only once more
src = cdgen.generateMainFuncSafe();
cpl = compiler.compileAndExecute(src);
}

if (cpl) {
compiler.printContextCompilationError();
// delete last line
if (lastLineNumber > 0) {
deleteLine(lastLineNumber);
}
}
// compile
compile();
};

print() << "cpi> " << flush;

#ifdef Q_OS_WIN
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
while (!end) {
if (WaitForSingleObject(h, 50) == WAIT_OBJECT_0) {
readfunc();
bool ready = waitForReadyStdInputRead(40);
if (ready) {
readCodeAndCompile();
}
}
#else
QSocketNotifier notifier(fileno(stdin), QSocketNotifier::Read);
QObject::connect(&notifier, &QSocketNotifier::activated, readfunc);
while (!end) {
QThread::msleep(50);
qApp->processEvents();
}
#endif

return 0;
}


int main(int argv, char *argc[])
{
QCoreApplication app(argv, argc);
app.setApplicationVersion(CPI_VERSION_STR);

QCommandLineParser parser;
parser.setApplicationDescription("Tiny C++ Interpreter.\nRuns in interactive mode by default.");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file", "File to compile.","[file]");
parser.addPositionalArgument("-", "Reads from stdin.","[-]");
parser.process(app);

#if (defined Q_OS_WIN) || (defined Q_OS_DARWIN)
conf = std::make_unique<QSettings>(QSettings::IniFormat, QSettings::UserScope, "cpi/cpi");
Expand Down Expand Up @@ -387,7 +443,7 @@ int main(int argv, char *argc[])
} else if (QCoreApplication::arguments().contains("-")) { // Check pipe option
QString src;
QTextStream tsstdin(stdin);
while(!tsstdin.atEnd()) {
while (!tsstdin.atEnd()) {
src += tsstdin.readLine();
src += "\n";
}
Expand Down

0 comments on commit 066d774

Please sign in to comment.