mirror of
https://gitlab.com/niansa/pilang3.git
synced 2025-03-06 20:49:20 +01:00
Implemented basic functions
This commit is contained in:
parent
0b4aa7cc31
commit
303c5f828b
5 changed files with 108 additions and 49 deletions
|
@ -17,13 +17,17 @@ namespace Pilang3 {
|
||||||
class BadArgs : public langException {};
|
class BadArgs : public langException {};
|
||||||
class NoSuchCommand : public langException {};
|
class NoSuchCommand : public langException {};
|
||||||
class NoSuchVariable : public langException {};
|
class NoSuchVariable : public langException {};
|
||||||
|
class UnexpectedEndOfExpression : public langException {};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Environment;
|
class Environment;
|
||||||
class Evaluation;
|
class Evaluation;
|
||||||
|
class Function;
|
||||||
struct Variable;
|
struct Variable;
|
||||||
|
using SharedEnvironment = std::shared_ptr<Environment>;
|
||||||
using SharedVariable = std::shared_ptr<Variable>;
|
using SharedVariable = std::shared_ptr<Variable>;
|
||||||
using SharedEvaluation = std::shared_ptr<Evaluation>;
|
using SharedEvaluation = std::shared_ptr<Evaluation>;
|
||||||
|
using SharedFunction = std::shared_ptr<Function>;
|
||||||
|
|
||||||
struct Variable {
|
struct Variable {
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -31,17 +35,19 @@ namespace Pilang3 {
|
||||||
id_integer,
|
id_integer,
|
||||||
id_reference,
|
id_reference,
|
||||||
id_evaluation,
|
id_evaluation,
|
||||||
|
id_function,
|
||||||
id_type [[maybe_unused]],
|
id_type [[maybe_unused]],
|
||||||
|
id_retval [[maybe_unused]],
|
||||||
id_any [[maybe_unused]],
|
id_any [[maybe_unused]],
|
||||||
id_null [[maybe_unused]]
|
id_null [[maybe_unused]]
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
using Data = std::variant<std::string, integer_type, SharedVariable, Type, SharedEvaluation>;
|
using Data = std::variant<std::string, integer_type, SharedVariable, SharedEvaluation, SharedFunction, Type>;
|
||||||
Data data;
|
Data data;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Cmdargs = std::vector<Variable>;
|
using Cmdargs = std::vector<Variable>;
|
||||||
using Cmdfnc = std::function<Variable (Environment&, Cmdargs&)>;
|
using Cmdfnc = std::function<Variable (SharedEnvironment, Cmdargs&)>;
|
||||||
using Cmddesc = std::tuple<Cmdfnc, uint16_t, std::vector<Variable::Type>, bool>;
|
using Cmddesc = std::tuple<Cmdfnc, uint16_t, std::vector<Variable::Type>, bool>;
|
||||||
|
|
||||||
extern std::unordered_map<std::string, Cmddesc> builtinCmds;
|
extern std::unordered_map<std::string, Cmddesc> builtinCmds;
|
||||||
|
@ -57,10 +63,17 @@ namespace Pilang3 {
|
||||||
Cmdargs arguments;
|
Cmdargs arguments;
|
||||||
Cmdfnc command = nullptr;
|
Cmdfnc command = nullptr;
|
||||||
std::string command_name;
|
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<SharedEvaluation> evalChain;
|
||||||
|
|
||||||
|
Variable execute(SharedEnvironment env);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
3
main.cpp
3
main.cpp
|
@ -1,4 +1,5 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include "pilang.hpp"
|
#include "pilang.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ int main() {
|
||||||
|
|
||||||
// Initialise
|
// Initialise
|
||||||
std::string line;
|
std::string line;
|
||||||
Environment env;
|
auto env = std::make_shared<Environment>();
|
||||||
|
|
||||||
// CLI loop
|
// CLI loop
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -1,20 +1,28 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <memory>
|
||||||
#include "pilang.hpp"
|
#include "pilang.hpp"
|
||||||
using namespace Pilang3;
|
using namespace Pilang3;
|
||||||
|
|
||||||
|
|
||||||
class Std {
|
class Std {
|
||||||
public:
|
public:
|
||||||
static Variable set(Environment& env, Cmdargs& args) {
|
static Variable retval(SharedEnvironment, Cmdargs& args) {
|
||||||
return *env.globalVars[std::get<std::string>(args[0].data)];
|
return Variable({
|
||||||
|
Variable::id_retval,
|
||||||
|
std::make_shared<Variable>(args[0])
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Variable get(Environment& env, Cmdargs& args) {
|
static Variable set(SharedEnvironment env, Cmdargs& args) {
|
||||||
env.globalVars[std::get<std::string>(args[0].data)] = std::make_shared<Variable>(args[1]);
|
env->globalVars[std::get<std::string>(args[0].data)] = std::make_shared<Variable>(args[1]);
|
||||||
return args[1];
|
return args[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Variable concat(Environment&, Cmdargs& args) {
|
static Variable get(SharedEnvironment env, Cmdargs& args) {
|
||||||
|
return *env->globalVars[std::get<std::string>(args[0].data)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static Variable concat(SharedEnvironment, Cmdargs& args) {
|
||||||
std::ostringstream fres;
|
std::ostringstream fres;
|
||||||
for (const auto& arg : args) {
|
for (const auto& arg : args) {
|
||||||
switch (arg.type) {
|
switch (arg.type) {
|
||||||
|
@ -32,8 +40,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Std() {
|
Std() {
|
||||||
Pilang3::builtinCmds["set"] = {concat, 2, {Variable::id_string, Variable::id_any}, true};
|
Pilang3::builtinCmds["return"] = {retval, 1, {Variable::id_any}, false};
|
||||||
Pilang3::builtinCmds["get"] = {concat, 1, {Variable::id_string}, true};
|
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};
|
Pilang3::builtinCmds["concat"] = {concat, 0, {}, true};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ using namespace Pilang3;
|
||||||
|
|
||||||
class StdIO {
|
class StdIO {
|
||||||
public:
|
public:
|
||||||
static Variable print(Environment&, Cmdargs& args) {
|
static Variable print(SharedEnvironment, Cmdargs& args) {
|
||||||
std::cout << std::get<std::string>(args[0].data) << std::endl;
|
std::cout << std::get<std::string>(args[0].data) << std::endl;
|
||||||
return Variable({
|
return Variable({
|
||||||
Variable::id_null,
|
Variable::id_null,
|
||||||
|
|
106
pilang.cpp
106
pilang.cpp
|
@ -12,26 +12,18 @@
|
||||||
|
|
||||||
|
|
||||||
namespace Pilang3 {
|
namespace Pilang3 {
|
||||||
std::unordered_map<std::string, std::tuple<Cmdfnc, uint16_t, std::vector<Variable::Type>, bool>> builtinCmds = {
|
std::unordered_map<std::string, std::tuple<Cmdfnc, uint16_t, std::vector<Variable::Type>, 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<integer_type>(arg.data); break;
|
|
||||||
case Variable::id_string: fres << std::get<std::string>(arg.data); break;
|
|
||||||
case Variable::id_reference: fres << std::get<SharedVariable>(arg.data).get(); break;
|
|
||||||
case Variable::id_type: fres << std::get<Variable::Type>(arg.data); break;
|
|
||||||
default: fres << "<ID" << arg.type << '>'; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Variable({
|
|
||||||
Variable::id_string,
|
|
||||||
fres.str()
|
|
||||||
});
|
|
||||||
}, 0, {}, true}}
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
// Parse arguments if any
|
||||||
if (not expression.empty()) {
|
if (not expression.empty()) {
|
||||||
Variable thisarg;
|
Variable thisarg;
|
||||||
|
@ -39,7 +31,7 @@ namespace Pilang3 {
|
||||||
bool newarg = false;
|
bool newarg = false;
|
||||||
bool escapenext = false;
|
bool escapenext = false;
|
||||||
std::string cache;
|
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;
|
char character = *characterit;
|
||||||
// Start new command name
|
// Start new command name
|
||||||
if (in_command_name) {
|
if (in_command_name) {
|
||||||
|
@ -49,6 +41,7 @@ namespace Pilang3 {
|
||||||
command_name = cache;
|
command_name = cache;
|
||||||
cache.clear();
|
cache.clear();
|
||||||
if (character == ';') {
|
if (character == ';') {
|
||||||
|
exprlen = std::distance(expression.begin(), characterit);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
in_command_name = false;
|
in_command_name = false;
|
||||||
|
@ -72,6 +65,9 @@ namespace Pilang3 {
|
||||||
} else if (character == '&') {
|
} else if (character == '&') {
|
||||||
// Expression
|
// Expression
|
||||||
thisarg.type = Variable::id_evaluation;
|
thisarg.type = Variable::id_evaluation;
|
||||||
|
} else if (character == '{') {
|
||||||
|
// Function
|
||||||
|
thisarg.type = Variable::id_function;
|
||||||
} else {
|
} else {
|
||||||
// Reference
|
// Reference
|
||||||
thisarg.type = Variable::id_reference;
|
thisarg.type = Variable::id_reference;
|
||||||
|
@ -112,8 +108,8 @@ namespace Pilang3 {
|
||||||
case Variable::id_reference: {
|
case Variable::id_reference: {
|
||||||
// Reference
|
// Reference
|
||||||
if (maybe_end_of_arg) {
|
if (maybe_end_of_arg) {
|
||||||
auto res = env.globalVars.find(cache);
|
auto res = env->globalVars.find(cache);
|
||||||
if (res == env.globalVars.end()) {
|
if (res == env->globalVars.end()) {
|
||||||
throw exceptions::NoSuchVariable();
|
throw exceptions::NoSuchVariable();
|
||||||
}
|
}
|
||||||
thisarg = *res->second;
|
thisarg = *res->second;
|
||||||
|
@ -141,6 +137,19 @@ namespace Pilang3 {
|
||||||
character = *(characterit += evaluation->exprlen + 1);
|
character = *(characterit += evaluation->exprlen + 1);
|
||||||
newarg = true;
|
newarg = true;
|
||||||
} break;
|
} break;
|
||||||
|
case Variable::id_function: {
|
||||||
|
auto thisfunc = std::make_shared<Function>();
|
||||||
|
while (character != '}') {
|
||||||
|
// Evaluate
|
||||||
|
auto evaluation = std::make_shared<Evaluation>(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
|
// Actually end argument if required
|
||||||
if (newarg) {
|
if (newarg) {
|
||||||
|
@ -154,32 +163,59 @@ namespace Pilang3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check exprlen
|
||||||
|
if (exprlen < 0) {
|
||||||
|
throw exceptions::UnexpectedEndOfExpression();
|
||||||
|
}
|
||||||
// Find command
|
// Find command
|
||||||
auto res = Pilang3::builtinCmds.find(command_name);
|
auto res = Pilang3::builtinCmds.find(command_name);
|
||||||
if (res == Pilang3::builtinCmds.end()) {
|
if (res == Pilang3::builtinCmds.end()) {
|
||||||
throw exceptions::NoSuchCommand();
|
// Find function
|
||||||
}
|
auto res = env->globalVars.find(command_name);
|
||||||
uint16_t argslen;
|
if (res == env->globalVars.end() or res->second->type != Variable::id_function) {
|
||||||
std::vector<Variable::Type> argstypes;
|
throw exceptions::NoSuchCommand();
|
||||||
bool anymoreopts;
|
}
|
||||||
std::tie(command, argslen, argstypes, anymoreopts) = res->second;
|
// Execute function
|
||||||
// Check args
|
command = [res] (SharedEnvironment env, Cmdargs&) {
|
||||||
if ((arguments.size() > argslen and not anymoreopts) or (arguments.size() < argslen)) {
|
return std::get<SharedFunction>(res->second->data)->execute(env);
|
||||||
throw exceptions::BadArgs();
|
};
|
||||||
}
|
} else {
|
||||||
for (uint16_t argidx = 0; argidx != argslen; argidx++) {
|
uint16_t argslen;
|
||||||
if (argstypes[argidx] != Variable::id_any and argstypes[argidx] != arguments[argidx].type) {
|
std::vector<Variable::Type> 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();
|
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) {
|
if (command) {
|
||||||
return command(env, arguments);
|
return command(env, arguments);
|
||||||
} else {
|
} else {
|
||||||
throw exceptions::NoSuchCommand();
|
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<SharedVariable>(fres.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Variable({
|
||||||
|
Variable::id_null,
|
||||||
|
0
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue