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:
parent
484b47d725
commit
97b82d9a7a
3 changed files with 107 additions and 41 deletions
|
@ -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);
|
||||||
|
|
1
main.cpp
1
main.cpp
|
@ -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&) {
|
||||||
|
|
142
pilang.cpp
142
pilang.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue