1
0
Fork 0
mirror of https://gitlab.com/niansa/pilang3.git synced 2025-03-06 20:49:20 +01:00

Further condition improvements

This commit is contained in:
niansa 2021-03-10 20:09:24 +01:00
parent 484b47d725
commit 97b82d9a7a
3 changed files with 107 additions and 41 deletions

View file

@ -45,6 +45,7 @@ namespace Pilang3 {
smallerthanorequals, smallerthanorequals,
ncpp_and, ncpp_and,
ncpp_or, ncpp_or,
ncpp_not,
_end _end
}; };
using array = std::vector<Variable*>; using array = std::vector<Variable*>;
@ -104,7 +105,7 @@ namespace Pilang3 {
std::string command_name; std::string command_name;
ssize_t exprlen = -1; ssize_t exprlen = -1;
Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval = true, const bool autoderef = true); Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval = true, const bool subderef = true);
void derefer(SharedEnvironment env); void derefer(SharedEnvironment env);
Variable execute(SharedEnvironment env); Variable execute(SharedEnvironment env);

View file

@ -20,6 +20,7 @@ int main() {
try { try {
Evaluation evaluation(env, line); Evaluation evaluation(env, line);
evaluation.derefer(env);
evaluation.execute(env); evaluation.execute(env);
line.clear(); line.clear();
} catch (exceptions::emptyExpr&) { } catch (exceptions::emptyExpr&) {

View file

@ -13,6 +13,9 @@
static inline bool is_sep(const char character) { static inline bool is_sep(const char character) {
return character == ' ' or character == '\t' or character == '\n'; return character == ' ' or character == '\t' or character == '\n';
} }
static inline bool is_end_of_arg(const char character) {
return character == ',' or character == ';';
}
namespace Pilang3 { namespace Pilang3 {
@ -28,7 +31,7 @@ namespace Pilang3 {
} }
} }
Evaluation::Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval, const bool autoderef) { Evaluation::Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval, const bool subderef) {
// Count off trailing spaces // Count off trailing spaces
ssize_t tspaces = 0; ssize_t tspaces = 0;
for (const auto& character : expression) { for (const auto& character : expression) {
@ -48,6 +51,7 @@ namespace Pilang3 {
bool is_condition = false; bool is_condition = false;
bool newarg = false; bool newarg = false;
bool escapenext = false; bool escapenext = false;
bool parsethis = true;
condition::array condition_cache; condition::array condition_cache;
std::string cache; std::string cache;
for (auto characterit = expression.begin() + tspaces; characterit < expression.end(); characterit++) { for (auto characterit = expression.begin() + tspaces; characterit < expression.end(); characterit++) {
@ -74,6 +78,7 @@ namespace Pilang3 {
if (is_sep(character)) continue; if (is_sep(character)) continue;
// Guess type by first character // Guess type by first character
newarg = false; newarg = false;
parsethis = true;
if (std::isdigit(character) or character == '-' or character == '+') { if (std::isdigit(character) or character == '-' or character == '+') {
// Integer // Integer
thisarg.type = Variable::id_integer; thisarg.type = Variable::id_integer;
@ -82,7 +87,6 @@ namespace Pilang3 {
// String // String
in_string = true; in_string = true;
thisarg.type = Variable::id_string; thisarg.type = Variable::id_string;
thisarg.data = std::string();
} else if (character == '&') { } else if (character == '&') {
// Expression // Expression
thisarg.type = Variable::id_evaluation; thisarg.type = Variable::id_evaluation;
@ -90,28 +94,33 @@ namespace Pilang3 {
// Function // Function
thisarg.type = Variable::id_function; thisarg.type = Variable::id_function;
goto parsechar; goto parsechar;
} else if (character == '!') { } else if (std::isalpha(character) or character == '_') {
// Condition
is_condition = true;
thisarg.type = Variable::id_null;
goto parsechar;
} else {
// Reference // Reference
thisarg.type = Variable::id_reference; thisarg.type = Variable::id_reference;
goto parsechar; goto parsechar;
} else {
// Condition
if (not is_condition) {
is_condition = true;
arguments.pop_back();
}
parsethis = false;
goto parsechar;
} }
} else { } else {
parsechar: parsechar:
bool maybe_end_of_arg = character == ',' or character == ';'; bool maybe_end_of_arg = is_end_of_arg(character);
// Do whatever (depends on type) // Do whatever (depends on type)
if (parsethis)
switch (thisarg.type) { switch (thisarg.type) {
case Variable::id_integer: { case Variable::id_integer: {
// Integer // Integer
if (is_sep(character)) continue; bool c_is_sep = is_sep(character);
else if (maybe_end_of_arg) { if (c_is_sep and cache.empty()) continue;
else if (maybe_end_of_arg or c_is_sep) {
// End argument // End argument
try { try {
thisarg.data = integer_type(std::stoi(cache)); thisarg.data = integer_type(std::stol(cache));
} catch (std::invalid_argument&) { } catch (std::invalid_argument&) {
throw exceptions::BadInteger(); throw exceptions::BadInteger();
} }
@ -123,24 +132,19 @@ namespace Pilang3 {
case Variable::id_string: { case Variable::id_string: {
// String // String
if (character == '"' and not escapenext) { if (character == '"' and not escapenext) {
std::get<std::string>(thisarg.data).append(cache); thisarg.data = cache;
cache.clear(); in_string = false;
in_string = not in_string; newarg = true;
} else if (in_string and character == '\\' and not escapenext) { } else if (in_string and character == '\\' and not escapenext) {
escapenext = true; escapenext = true;
} else if (in_string) { } else if (in_string) {
cache.push_back(character); cache.push_back(character);
} else if (maybe_end_of_arg) {
newarg = true;
} }
} break; } break;
case Variable::id_reference: { case Variable::id_reference: {
// Reference // Reference
if (maybe_end_of_arg) { if (maybe_end_of_arg or is_sep(character)) {
thisarg.data = cache; thisarg.data = cache;
if (autoderef) {
Variable::derefer(env, thisarg);
}
newarg = true; newarg = true;
} else { } else {
cache.push_back(character); cache.push_back(character);
@ -154,7 +158,11 @@ namespace Pilang3 {
characterit++; characterit++;
} }
// Evaluate // Evaluate
auto evaluation = std::make_shared<Evaluation>(env, std::string(characterit, expression.end()), autoeval, autoderef); auto evaluation = std::make_shared<Evaluation>(env, std::string(characterit, expression.end()), autoeval, subderef);
// Derefer if possible
if (subderef) {
evaluation->derefer(env);
}
// Execute if possible // Execute if possible
if (autoeval and not noexec) { if (autoeval and not noexec) {
thisarg = evaluation->execute(env); thisarg = evaluation->execute(env);
@ -222,16 +230,18 @@ namespace Pilang3 {
newarg = true; newarg = true;
} break; } break;
} }
if (not (in_string or newarg)) { if (not in_string) {
// Check if argument might be a condition
if (character == '!' or character == '=') {
is_condition = true;
}
// Continue building condition // Continue building condition
if (is_condition) { if (is_condition) {
uint64_t cond_extends = condition::_none; uint64_t cond_extends = condition::_none;
// Check if too close to end of expression
if (maybe_end_of_arg) {
goto cond_append;
} else if (characterit + 1 == expression.end()) {
throw exceptions::UnexpectedEndOfExpression();
}
// Equals // Equals
if (character == '=' and *(characterit + 1) == '=') { else if (character == '=' and *(characterit + 1) == '=') {
cond_extends = condition::equals; cond_extends = condition::equals;
} }
// Not equals // Not equals
@ -262,24 +272,36 @@ namespace Pilang3 {
else if (character == '|' and *(characterit + 1) == '|') { else if (character == '|' and *(characterit + 1) == '|') {
cond_extends = condition::ncpp_or; cond_extends = condition::ncpp_or;
} }
// Not
else if (character == '!') {
cond_extends = condition::ncpp_not;
}
// Something else
else {
throw exceptions::langException(); // TODO: proper exception
}
// Extend // Extend
if (cond_extends != condition::_none) { if (cond_extends != condition::_none) {
condition_cache.push_back(new Variable(thisarg));
condition_cache.push_back(reinterpret_cast<Variable*>(cond_extends));
newarg = true;
// Note: some conditional strings have just one character // Note: some conditional strings have just one character
if (cond_extends != condition::biggerthan and cond_extends != condition::smallerthan) { if (cond_extends != condition::biggerthan and cond_extends != condition::smallerthan and cond_extends != condition::ncpp_not) {
characterit += 1; characterit += 1;
} }
} // Append variable
} cond_append:
} else if (newarg and is_condition) {
// End condition
condition_cache.push_back(new Variable(thisarg)); condition_cache.push_back(new Variable(thisarg));
is_condition = false; newarg = true;
thisarg.type = Variable::id_condition; // If required end condition
if (maybe_end_of_arg) {
thisarg.data = condition_cache; thisarg.data = condition_cache;
thisarg.type = Variable::id_condition;
condition_cache.clear(); condition_cache.clear();
is_condition = false;
newarg = true;
} else {
condition_cache.push_back(reinterpret_cast<Variable*>(cond_extends));
}
}
}
} }
// Actually end argument if required // Actually end argument if required
if (newarg) { if (newarg) {
@ -329,6 +351,21 @@ namespace Pilang3 {
} }
} }
template<typename T>
static bool anycomp(const uint64_t comparator, const Variable& a, const Variable& b) {
T val[] = {std::get<T>(a.data), std::get<T>(b.data)};
switch (comparator) {
using namespace condition;
case equals: return val[0] == val[1]; break;
case not_equals: return val[0] != val[1]; break;
case biggerthan: return val[0] > val[1]; break;
case smallerthan: return val[0] < val[1]; break;
case biggerthanorequals: return val[0] >= val[1]; break;
case smallerthanorequals: return val[0] <= val[1]; break;
default: throw exceptions::langException(); // TODO: Proper exception
}
}
void Variable::derefer(SharedEnvironment env, Variable& var) { void Variable::derefer(SharedEnvironment env, Variable& var) {
switch (var.type) { switch (var.type) {
case Variable::id_evaluation: { case Variable::id_evaluation: {
@ -343,13 +380,40 @@ namespace Pilang3 {
} break; } break;
case Variable::id_reference: { case Variable::id_reference: {
auto &scope = env->currScope(); auto &scope = env->currScope();
auto x = std::get<std::string>(var.data);
auto res = scope.find(std::get<std::string>(var.data)); auto res = scope.find(std::get<std::string>(var.data));
if (res == scope.end()) { if (res == scope.end()) {
throw exceptions::NoSuchVariable(); throw exceptions::NoSuchVariable();
} }
var = *res->second; var = *res->second;
} break; } break;
case Variable::id_condition: {
auto condition = std::get<condition::array>(var.data);
// We only support a size of 3 (as of now)
if (condition.size() != 3) {
throw exceptions::langException(); // TODO: Proper exception
}
// Derefer both sides
Variable::derefer(env, *condition[0]);
Variable::derefer(env, *condition[2]);
// Both sides must be of the same type
if (condition[0]->type != condition[2]->type) {
throw exceptions::langException(); // TODO: Proper exception
}
auto type = condition[0]->type;
auto comparator = reinterpret_cast<uint64_t>(condition[1]);
bool fres = false;
// Compare integer
if (type == Variable::id_integer) {
fres = anycomp<integer_type>(comparator, *condition[0], *condition[2]);
}
// Compare string
else if (type == Variable::id_string) {
fres = anycomp<std::string>(comparator, *condition[0], *condition[2]);
}
// Store result
var.type = Variable::id_integer;
var.data = fres;
} break;
default: return; default: return;
} }
} }