Skip to content

Commit

Permalink
ext/MiniScript: updated MiniScript
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasdr committed Jan 15, 2024
1 parent d24bf16 commit e9e34ec
Show file tree
Hide file tree
Showing 22 changed files with 400 additions and 142 deletions.
6 changes: 6 additions & 0 deletions README-MiniScript.md
Original file line number Diff line number Diff line change
Expand Up @@ -1292,8 +1292,12 @@ end
| <sub>bool($bool: Boolean): Boolean</sub> |
| Break out of current forCondition or forTime loop |
| <sub>break(): Null</sub> |
| Begins a case block within a switch block, which will be executed if the case value has matched |
| <sub>case($value: Mixed): Null</sub> |
| Continue to next iteration of forCondition or forTime loop |
| <sub>continue(): Null</sub> |
| Begins a default block within a switch block, which will be executed if no case value has matched|
| <sub>default(): Null</sub> |
| Divide |
| <sub>div($a: Mixed, $b: Mixed): Mixed</sub> |
| Else |
Expand Down Expand Up @@ -1342,6 +1346,8 @@ end
| <sub>return([$value: Mixed]): Null</sub> |
| Subtract |
| <sub>sub($a: Mixed, $b: Mixed): Mixed</sub> |
| Begins switch block to match a given value to case values or a default |
| <sub>switch($value: Mixed): Null</sub> |

## 7.2. Application methods

Expand Down
165 changes: 130 additions & 35 deletions ext/miniscript/src/miniscript/miniscript/BaseMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
if (miniScript->getScriptState().blockStack.empty() == true) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": break without forXXX");
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": break without forCondition/forTime");
miniScript->startErrorScript();
} else {
auto& blockStack = miniScript->getScriptState().blockStack;
Expand All @@ -81,7 +81,7 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
}
}
if (endType.type == MiniScript::ScriptState::BLOCKTYPE_NONE) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": break without forXXX");
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": break without forCondition/forTime");
} else
if (endType.continueStatement != nullptr) {
miniScript->gotoStatement(*endType.breakStatement);
Expand All @@ -105,7 +105,7 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
if (miniScript->getScriptState().blockStack.empty() == true) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": continue without forXXX");
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": continue without forCondition, forTime");
miniScript->startErrorScript();
} else {
auto& blockStack = miniScript->getScriptState().blockStack;
Expand All @@ -118,7 +118,7 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
}
}
if (endType == nullptr) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": continue without forXXX");
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": continue without forCondition, forTime");
} else
if (endType->continueStatement != nullptr) {
miniScript->gotoStatement(*endType->continueStatement);
Expand All @@ -142,25 +142,21 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
if (miniScript->getScriptState().blockStack.empty() == true) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": end without block/forXXX/if");
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": end without if/elseif/else/switch/case/default/forCondition/forTime/end");
miniScript->startErrorScript();
} else {
auto& blockStack = miniScript->getScriptState().blockStack;
auto endType = blockStack[blockStack.size() - 1];
blockStack.erase(blockStack.begin() + blockStack.size() - 1);
switch(endType.type) {
auto& block = blockStack[blockStack.size() - 1];
switch(block.type) {
case MiniScript::ScriptState::BLOCKTYPE_BLOCK:
if (miniScript->isFunctionRunning() == true && miniScript->scriptStateStack.size() == 2) {
miniScript->stopRunning();
}
break;
case MiniScript::ScriptState::BLOCKTYPE_FOR:
// no op
break;
case MiniScript::ScriptState::BLOCKTYPE_IF:
miniScript->getScriptState().conditionStack.pop();
default:
break;
}
blockStack.erase(blockStack.begin() + blockStack.size() - 1);
if (statement.gotoStatementIdx != MiniScript::STATEMENTIDX_NONE) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
Expand Down Expand Up @@ -209,9 +205,11 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
miniScript->gotoStatementGoto(statement);
} else {
scriptState.blockStack.emplace_back(
MiniScript::ScriptState::BLOCKTYPE_FOR,
MiniScript::ScriptState::BLOCKTYPE_FORTIME,
false,
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx - 1],
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx]
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx],
MiniScript::Variable()
);
}
}
Expand Down Expand Up @@ -250,8 +248,10 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
auto& scriptState = miniScript->getScriptState();
scriptState.blockStack.emplace_back(
MiniScript::ScriptState::BLOCKTYPE_FOR,
false,
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx - 1],
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx]
&miniScript->getScripts()[scriptState.scriptIdx].statements[statement.gotoStatementIdx],
MiniScript::Variable()
);
}
}
Expand Down Expand Up @@ -282,8 +282,7 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
miniScript->startErrorScript();
} else {
auto& scriptState = miniScript->getScriptState();
scriptState.blockStack.emplace_back(MiniScript::ScriptState::BLOCKTYPE_IF, nullptr, nullptr);
scriptState.conditionStack.push(booleanValue);
scriptState.blockStack.emplace_back(MiniScript::ScriptState::BLOCKTYPE_IF, booleanValue, nullptr, nullptr, MiniScript::Variable());
if (booleanValue == false) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
Expand Down Expand Up @@ -314,20 +313,19 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
if (miniScript->getBooleanValue(arguments, 0, booleanValue, false) == false) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": argument mismatch: expected arguments: " + miniScript->getArgumentInformation(getMethodName()));
miniScript->startErrorScript();
} else
if (miniScript->getScriptState().conditionStack.empty() == true) {
_Console::println("MethodElseIfCondition::executeMethod(): elseif without if");
miniScript->startErrorScript();
} else {
//
auto conditionStackElement = miniScript->getScriptState().conditionStack.top();
if (conditionStackElement == false) {
miniScript->getScriptState().conditionStack.pop();
miniScript->getScriptState().conditionStack.push(booleanValue);
}
if (conditionStackElement == true || booleanValue == false) {
auto& scriptState = miniScript->getScriptState();
auto& blockStack = scriptState.blockStack[scriptState.blockStack.size() - 1];
if (blockStack.type != MiniScript::ScriptState::BlockType::BLOCKTYPE_IF) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": elseif without if");
miniScript->startErrorScript();
} else
if (blockStack.match == true || booleanValue == false) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
} else {
blockStack.match = booleanValue;
}
}
}
Expand All @@ -345,19 +343,116 @@ void BaseMethods::registerMethods(MiniScript* miniScript) {
return "else";
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
if (miniScript->getScriptState().conditionStack.empty() == true) {
_Console::println("MethodElse::executeMethod(): else without if");
auto& scriptState = miniScript->getScriptState();
auto& blockStack = scriptState.blockStack[scriptState.blockStack.size() - 1];
if (blockStack.type != MiniScript::ScriptState::BlockType::BLOCKTYPE_IF) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": else without if");
miniScript->startErrorScript();
} else
if (blockStack.match == true) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
}
}
};
miniScript->registerMethod(new MethodElse(miniScript));
}
// switch
{
//
class MethodSwitch: public MiniScript::Method {
private:
MiniScript* miniScript { nullptr };
public:
MethodSwitch(MiniScript* miniScript):
MiniScript::Method(
{
{ .type = MiniScript::TYPE_PSEUDO_MIXED, .name = "value", .optional = false, .reference = false, .nullable = false }
}
),
miniScript(miniScript) {}
const string getMethodName() override {
return "switch";
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
bool booleanValue;
if (arguments.size() != 1) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": argument mismatch: expected arguments: " + miniScript->getArgumentInformation(getMethodName()));
miniScript->startErrorScript();
} else {
auto conditionStackElement = miniScript->getScriptState().conditionStack.top();
if (conditionStackElement == true) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
auto& scriptState = miniScript->getScriptState();
scriptState.blockStack.emplace_back(MiniScript::ScriptState::BLOCKTYPE_SWITCH, booleanValue, nullptr, nullptr, arguments[0]);
}
}
};
miniScript->registerMethod(new MethodSwitch(miniScript));
}
{
//
class MethodCase: public MiniScript::Method {
private:
MiniScript* miniScript { nullptr };
public:
MethodCase(MiniScript* miniScript):
MiniScript::Method(
{
{ .type = MiniScript::TYPE_PSEUDO_MIXED, .name = "value", .optional = false, .reference = false, .nullable = false }
}
),
miniScript(miniScript) {}
const string getMethodName() override {
return "case";
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
if (arguments.size() != 1) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": argument mismatch: expected arguments: " + miniScript->getArgumentInformation(getMethodName()));
miniScript->startErrorScript();
} else {
//
auto& scriptState = miniScript->getScriptState();
auto& blockStack = scriptState.blockStack[scriptState.blockStack.size() - 1];
if (blockStack.type != MiniScript::ScriptState::BlockType::BLOCKTYPE_SWITCH) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": case without switch");
miniScript->startErrorScript();
} else {
auto match = arguments[0].getValueAsString() == blockStack.switchVariable.getValueAsString();
if (blockStack.match == true || match == false) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
} else {
blockStack.match = match;
scriptState.blockStack.emplace_back(MiniScript::ScriptState::BLOCKTYPE_CASE, false, nullptr, nullptr, MiniScript::Variable());
}
}
}
}
};
miniScript->registerMethod(new MethodElse(miniScript));
miniScript->registerMethod(new MethodCase(miniScript));
}
{
//
class MethodDefault: public MiniScript::Method {
private:
MiniScript* miniScript { nullptr };
public:
MethodDefault(MiniScript* miniScript): MiniScript::Method(), miniScript(miniScript) {}
const string getMethodName() override {
return "default";
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
auto& scriptState = miniScript->getScriptState();
auto& blockStack = scriptState.blockStack[scriptState.blockStack.size() - 1];
if (blockStack.type != MiniScript::ScriptState::BlockType::BLOCKTYPE_SWITCH) {
_Console::println(getMethodName() + "(): " + miniScript->getStatementInformation(statement) + ": default without switch");
miniScript->startErrorScript();
} else
if (blockStack.match == true) {
miniScript->setScriptStateState(MiniScript::STATEMACHINESTATE_NEXT_STATEMENT);
miniScript->gotoStatementGoto(statement);
}
}
};
miniScript->registerMethod(new MethodDefault(miniScript));
}
// equality
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ void HTTPDownloadClientClass::registerMethods(MiniScript* miniScript) const {
return "HTTPDownloadClient";
}
void executeMethod(span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) override {
auto& scriptContext = *static_cast<HTTPDownloadClientClass::ScriptContext*>(miniScript->getDataTypeScriptContext(MiniScript::TYPE_HTTPDOWNLOADCLIENT));
auto& scriptContext = *static_cast<HTTPDownloadClientClass::HTTPDownloadClientClassScriptContext*>(miniScript->getDataTypeScriptContext(MiniScript::TYPE_HTTPDOWNLOADCLIENT));
//
auto httpDownloadClient = make_shared<_HTTPDownloadClient>();
scriptContext.instances.push_back(httpDownloadClient);
scriptContext.getInstances().push_back(httpDownloadClient);
scriptContext.setRequiresGarbageCollection();
//
returnValue.setType(MiniScript::TYPE_HTTPDOWNLOADCLIENT);
returnValue.setValue(&httpDownloadClient);
Expand Down Expand Up @@ -715,22 +716,26 @@ const string HTTPDownloadClientClass::getValueAsString(const MiniScript::Variabl
return "HTTPDownloadClientClass(url: " + httpDownloadClient->getURL() + ", file: " + httpDownloadClient->getFile() + ")";
}

void* HTTPDownloadClientClass::createScriptContext() const {
return new ScriptContext();
MiniScript::DataType::ScriptContext* HTTPDownloadClientClass::createScriptContext() const {
return new HTTPDownloadClientClassScriptContext();
}

void HTTPDownloadClientClass::deleteScriptContext(void* context) const {
delete static_cast<ScriptContext*>(context);
void HTTPDownloadClientClass::deleteScriptContext(MiniScript::DataType::ScriptContext* context) const {
delete static_cast<HTTPDownloadClientClassScriptContext*>(context);
}

void HTTPDownloadClientClass::garbageCollection(void* context) const {
auto& scriptContext = *static_cast<ScriptContext*>(context);
for (auto i = 0; i < scriptContext.instances.size(); i++) {
auto& instance = scriptContext.instances[i];
void HTTPDownloadClientClass::garbageCollection(MiniScript::DataType::ScriptContext* context) const {
auto& scriptContext = *static_cast<HTTPDownloadClientClassScriptContext*>(context);
auto& instances = scriptContext.getInstances();
for (auto i = 0; i < instances.size(); i++) {
auto& instance = instances[i];
if (instance.use_count() == 1 && instance->isFinished() == true) {
instance->join();
scriptContext.instances.erase(scriptContext.instances.begin() + i);
instances.erase(instances.begin() + i);
i--;
}
}
if (instances.empty() == true) {
scriptContext.unsetRequiresGarbageCollection();
}
}
27 changes: 20 additions & 7 deletions ext/miniscript/src/miniscript/miniscript/HTTPDownloadClientClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,29 @@ class miniscript::miniscript::HTTPDownloadClientClass final: public MiniScript::
bool div(MiniScript* miniScript, const span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) const override;
bool add(MiniScript* miniScript, const span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) const override;
bool sub(MiniScript* miniScript, const span<MiniScript::Variable>& arguments, MiniScript::Variable& returnValue, const MiniScript::Statement& statement) const override;
void* createScriptContext() const override;
void deleteScriptContext(void* context) const override;
void garbageCollection(void* context) const override;
DataType::ScriptContext* createScriptContext() const override;
void deleteScriptContext(DataType::ScriptContext* context) const override;
void garbageCollection(DataType::ScriptContext* context) const override;

public:
/**
* Script context
*/
struct ScriptContext {
vector<shared_ptr<_HTTPDownloadClient>> instances;
class HTTPDownloadClientClassScriptContext final: public ScriptContext {
public:
/**
* Constructor
*/
HTTPDownloadClientClassScriptContext() {}

/**
* @return instances
*/
inline vector<shared_ptr<_HTTPDownloadClient>>& getInstances() {
return instances;
}
private:
vector<shared_ptr<_HTTPDownloadClient>> instances;
};

// forbid class copy
Expand Down Expand Up @@ -76,9 +89,9 @@ class miniscript::miniscript::HTTPDownloadClientClass final: public MiniScript::
}

/**
* MiniScript Vector2 data type
* MiniScript HTTP download client class
*/
HTTPDownloadClientClass(): MiniScript::DataType(false) {
HTTPDownloadClientClass(): MiniScript::DataType(false, true) {
//
}

Expand Down
Loading

0 comments on commit e9e34ec

Please sign in to comment.