From 303c5f828b915a980ecba23545e83611c7bc2ab5 Mon Sep 17 00:00:00 2001 From: niansa Date: Mon, 1 Feb 2021 15:24:40 +0100 Subject: [PATCH] Implemented basic functions --- include/pilang.hpp | 23 +++++++--- main.cpp | 3 +- modules/std.cpp | 23 +++++++--- modules/stdio.cpp | 2 +- pilang.cpp | 106 ++++++++++++++++++++++++++++++--------------- 5 files changed, 108 insertions(+), 49 deletions(-) diff --git a/include/pilang.hpp b/include/pilang.hpp index f68dce3..0bdca18 100644 --- a/include/pilang.hpp +++ b/include/pilang.hpp @@ -17,13 +17,17 @@ namespace Pilang3 { class BadArgs : public langException {}; class NoSuchCommand : public langException {}; class NoSuchVariable : public langException {}; + class UnexpectedEndOfExpression : public langException {}; } class Environment; class Evaluation; + class Function; struct Variable; + using SharedEnvironment = std::shared_ptr; using SharedVariable = std::shared_ptr; using SharedEvaluation = std::shared_ptr; + using SharedFunction = std::shared_ptr; struct Variable { enum Type { @@ -31,17 +35,19 @@ namespace Pilang3 { id_integer, id_reference, id_evaluation, + id_function, id_type [[maybe_unused]], + id_retval [[maybe_unused]], id_any [[maybe_unused]], id_null [[maybe_unused]] } type; - using Data = std::variant; + using Data = std::variant; Data data; }; using Cmdargs = std::vector; - using Cmdfnc = std::function; + using Cmdfnc = std::function; using Cmddesc = std::tuple, bool>; extern std::unordered_map builtinCmds; @@ -57,10 +63,17 @@ namespace Pilang3 { Cmdargs arguments; Cmdfnc command = nullptr; std::string command_name; - ssize_t exprlen; + ssize_t exprlen = -1; - Evaluation(Environment& env, const std::string &expression, const bool autoeval = true); + Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval = true); - Variable execute(Environment& env); + Variable execute(SharedEnvironment env); + }; + + class Function { + public: + std::vector evalChain; + + Variable execute(SharedEnvironment env); }; }; diff --git a/main.cpp b/main.cpp index fbdd659..595137b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "pilang.hpp" @@ -7,7 +8,7 @@ int main() { // Initialise std::string line; - Environment env; + auto env = std::make_shared(); // CLI loop while (true) { diff --git a/modules/std.cpp b/modules/std.cpp index 172f083..a053755 100644 --- a/modules/std.cpp +++ b/modules/std.cpp @@ -1,20 +1,28 @@ #include +#include #include "pilang.hpp" using namespace Pilang3; class Std { public: - static Variable set(Environment& env, Cmdargs& args) { - return *env.globalVars[std::get(args[0].data)]; + static Variable retval(SharedEnvironment, Cmdargs& args) { + return Variable({ + Variable::id_retval, + std::make_shared(args[0]) + }); } - static Variable get(Environment& env, Cmdargs& args) { - env.globalVars[std::get(args[0].data)] = std::make_shared(args[1]); + static Variable set(SharedEnvironment env, Cmdargs& args) { + env->globalVars[std::get(args[0].data)] = std::make_shared(args[1]); return args[1]; } - static Variable concat(Environment&, Cmdargs& args) { + static Variable get(SharedEnvironment env, Cmdargs& args) { + return *env->globalVars[std::get(args[0].data)]; + } + + static Variable concat(SharedEnvironment, Cmdargs& args) { std::ostringstream fres; for (const auto& arg : args) { switch (arg.type) { @@ -32,8 +40,9 @@ public: } Std() { - Pilang3::builtinCmds["set"] = {concat, 2, {Variable::id_string, Variable::id_any}, true}; - Pilang3::builtinCmds["get"] = {concat, 1, {Variable::id_string}, true}; + Pilang3::builtinCmds["return"] = {retval, 1, {Variable::id_any}, false}; + Pilang3::builtinCmds["set"] = {set, 2, {Variable::id_string, Variable::id_any}, false}; + Pilang3::builtinCmds["get"] = {get, 1, {Variable::id_string}, false}; Pilang3::builtinCmds["concat"] = {concat, 0, {}, true}; } }; diff --git a/modules/stdio.cpp b/modules/stdio.cpp index 9ac39ca..b86d765 100644 --- a/modules/stdio.cpp +++ b/modules/stdio.cpp @@ -5,7 +5,7 @@ using namespace Pilang3; class StdIO { public: - static Variable print(Environment&, Cmdargs& args) { + static Variable print(SharedEnvironment, Cmdargs& args) { std::cout << std::get(args[0].data) << std::endl; return Variable({ Variable::id_null, diff --git a/pilang.cpp b/pilang.cpp index 29930a5..98248dc 100644 --- a/pilang.cpp +++ b/pilang.cpp @@ -12,26 +12,18 @@ namespace Pilang3 { - std::unordered_map, bool>> builtinCmds = { - {"concat", {[] (Environment& env, Cmdargs& args) { - std::ostringstream fres; - for (const auto& arg : args) { - switch (arg.type) { - case Variable::id_integer: fres << std::get(arg.data); break; - case Variable::id_string: fres << std::get(arg.data); break; - case Variable::id_reference: fres << std::get(arg.data).get(); break; - case Variable::id_type: fres << std::get(arg.data); break; - default: fres << "'; break; - } - } - return Variable({ - Variable::id_string, - fres.str() - }); - }, 0, {}, true}} - }; + std::unordered_map, bool>> builtinCmds; - Evaluation::Evaluation(Environment& env, const std::string &expression, const bool autoeval) { + Evaluation::Evaluation(SharedEnvironment env, const std::string& expression, const bool autoeval) { + // Count off trailing spaces + ssize_t tspaces = 0; + for (const auto& character : expression) { + if (character == ' ' or character == '\t') { + tspaces++; + } else { + break; + } + } // Parse arguments if any if (not expression.empty()) { Variable thisarg; @@ -39,7 +31,7 @@ namespace Pilang3 { bool newarg = false; bool escapenext = false; std::string cache; - for (auto characterit = expression.begin(); characterit != expression.end(); characterit++) { + for (auto characterit = expression.begin() + tspaces; characterit != expression.end(); characterit++) { char character = *characterit; // Start new command name if (in_command_name) { @@ -49,6 +41,7 @@ namespace Pilang3 { command_name = cache; cache.clear(); if (character == ';') { + exprlen = std::distance(expression.begin(), characterit); break; } else { in_command_name = false; @@ -72,6 +65,9 @@ namespace Pilang3 { } else if (character == '&') { // Expression thisarg.type = Variable::id_evaluation; + } else if (character == '{') { + // Function + thisarg.type = Variable::id_function; } else { // Reference thisarg.type = Variable::id_reference; @@ -112,8 +108,8 @@ namespace Pilang3 { case Variable::id_reference: { // Reference if (maybe_end_of_arg) { - auto res = env.globalVars.find(cache); - if (res == env.globalVars.end()) { + auto res = env->globalVars.find(cache); + if (res == env->globalVars.end()) { throw exceptions::NoSuchVariable(); } thisarg = *res->second; @@ -141,6 +137,19 @@ namespace Pilang3 { character = *(characterit += evaluation->exprlen + 1); newarg = true; } break; + case Variable::id_function: { + auto thisfunc = std::make_shared(); + while (character != '}') { + // Evaluate + auto evaluation = std::make_shared(env, std::string(characterit, expression.end())); + thisfunc->evalChain.push_back(evaluation); + // Skip over expression in iteration + character = *(characterit += evaluation->exprlen + 1); + } + character = *(++characterit); + thisarg.data = thisfunc; + newarg = true; + } break; } // Actually end argument if required if (newarg) { @@ -154,32 +163,59 @@ namespace Pilang3 { } } } + // Check exprlen + if (exprlen < 0) { + throw exceptions::UnexpectedEndOfExpression(); + } // Find command auto res = Pilang3::builtinCmds.find(command_name); if (res == Pilang3::builtinCmds.end()) { - throw exceptions::NoSuchCommand(); - } - uint16_t argslen; - std::vector argstypes; - bool anymoreopts; - std::tie(command, argslen, argstypes, anymoreopts) = res->second; - // Check args - if ((arguments.size() > argslen and not anymoreopts) or (arguments.size() < argslen)) { - throw exceptions::BadArgs(); - } - for (uint16_t argidx = 0; argidx != argslen; argidx++) { - if (argstypes[argidx] != Variable::id_any and argstypes[argidx] != arguments[argidx].type) { + // Find function + auto res = env->globalVars.find(command_name); + if (res == env->globalVars.end() or res->second->type != Variable::id_function) { + throw exceptions::NoSuchCommand(); + } + // Execute function + command = [res] (SharedEnvironment env, Cmdargs&) { + return std::get(res->second->data)->execute(env); + }; + } else { + uint16_t argslen; + std::vector argstypes; + bool anymoreopts; + std::tie(command, argslen, argstypes, anymoreopts) = res->second; + // Check args + if ((arguments.size() > argslen and not anymoreopts) or (arguments.size() < argslen)) { throw exceptions::BadArgs(); } + for (uint16_t argidx = 0; argidx != argslen; argidx++) { + if (argstypes[argidx] != Variable::id_any and argstypes[argidx] != arguments[argidx].type) { + throw exceptions::BadArgs(); + } + } } } } - Variable Evaluation::execute(Environment& env) { + Variable Evaluation::execute(SharedEnvironment env) { if (command) { return command(env, arguments); } else { throw exceptions::NoSuchCommand(); } } + + Variable Function::execute(SharedEnvironment env) { + Variable fres; + for (auto& evaluation : evalChain) { + fres = evaluation->execute(env); + if (fres.type == Variable::id_retval) { + return *std::get(fres.data); + } + } + return Variable({ + Variable::id_null, + 0 + }); + } };