Фиксация мамы нолнан с сфере IT с симпатией к атусу стоещему на полигоне
с афроо лошадьми
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
#include <random>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
// Forward declaration
|
||||
struct Node;
|
||||
|
||||
struct FuncParam {
|
||||
@@ -17,12 +17,16 @@ struct FuncParam {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// Контекст памяти (переменные и функции)
|
||||
struct Value {
|
||||
std::string type;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Context {
|
||||
Context* parent = nullptr; // Для глобальных переменных
|
||||
std::map<std::string, std::string> variables;
|
||||
std::map<std::string, std::shared_ptr<Node>> functions; // Храним функции
|
||||
std::map<std::string, std::vector<std::string>> arrays;
|
||||
Context* parent = nullptr;
|
||||
std::map<std::string, Value> variables;
|
||||
std::map<std::string, std::shared_ptr<Node>> functions;
|
||||
std::map<std::string, std::vector<Value>> arrays;
|
||||
|
||||
bool exists(const std::string& name) {
|
||||
if (variables.count(name) || arrays.count(name)) return true;
|
||||
@@ -30,50 +34,44 @@ struct Context {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getVar(const std::string& name) {
|
||||
Value getVar(const std::string& name) {
|
||||
if (variables.count(name)) return variables[name];
|
||||
if (parent) return parent->getVar(name);
|
||||
throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!");
|
||||
}
|
||||
|
||||
std::vector<std::string>& getArray(const std::string& name) {
|
||||
std::vector<Value>& getArray(const std::string& name) {
|
||||
if (arrays.count(name)) return arrays[name];
|
||||
if (parent) return parent->getArray(name);
|
||||
throw std::runtime_error("Runtime Error: Array '" + name + "' not found!");
|
||||
}
|
||||
|
||||
void setVar(const std::string& name, const std::string& val) {
|
||||
if (variables.count(name)) { variables[name] = val; return; }
|
||||
if (parent) { parent->setVar(name, val); return; }
|
||||
throw std::runtime_error("Error: Variable '" + name + "' not defined!");
|
||||
void defineFunc(const std::string& name, std::shared_ptr<Node> func) {
|
||||
functions[name] = func;
|
||||
}
|
||||
|
||||
void defineVar(const std::string& name, const std::string& val) {
|
||||
if (variables.count(name)) {
|
||||
throw std::runtime_error("Error: Variable '" + name + "' already defined!");
|
||||
}
|
||||
variables[name] = val;
|
||||
}
|
||||
|
||||
void defineGlobal(const std::string& name, const std::string& val) {
|
||||
if (parent) parent->defineGlobal(name, val);
|
||||
else defineVar(name, val);
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> getFunc(const std::string& name) {
|
||||
if (functions.count(name)) return functions[name];
|
||||
if (parent) return parent->getFunc(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void defineFunc(const std::string& name, std::shared_ptr<Node> body) {
|
||||
functions[name] = body;
|
||||
|
||||
void defineVar(const std::string& name, const std::string& type, const Value& value) {
|
||||
variables[name] = {type, value.value};
|
||||
}
|
||||
|
||||
void setVar(const std::string& name, Value val) {
|
||||
if (variables.count(name)) {
|
||||
variables[name].value = val.value;
|
||||
return;
|
||||
}
|
||||
if (parent) { parent->setVar(name, val); return; }
|
||||
throw std::runtime_error("Error: Variable '" + name + "' not defined!");
|
||||
}
|
||||
};
|
||||
|
||||
// Специальный тип для RETURN
|
||||
struct ReturnValue {
|
||||
std::string value;
|
||||
Value value;
|
||||
};
|
||||
|
||||
static std::string formatNumber(double val) {
|
||||
@@ -85,12 +83,9 @@ static std::string formatNumber(double val) {
|
||||
|
||||
struct Node {
|
||||
virtual ~Node() = default;
|
||||
virtual std::string eval(Context& ctx) = 0;
|
||||
virtual Value eval(Context& ctx) = 0;
|
||||
};
|
||||
|
||||
// --- ОСНОВНЫЕ УЗЛЫ ---
|
||||
|
||||
// Определение функции
|
||||
struct FuncDefNode : Node {
|
||||
std::string returnType;
|
||||
std::string name;
|
||||
@@ -100,21 +95,18 @@ struct FuncDefNode : Node {
|
||||
FuncDefNode(std::string rt, std::string n, std::vector<FuncParam> p, std::shared_ptr<Node> b)
|
||||
: returnType(rt), name(n), params(p), body(b) {}
|
||||
|
||||
// Eval ничего не делает, функция регистрируется Парсером
|
||||
std::string eval(Context& ctx) override { return ""; }
|
||||
Value eval(Context& ctx) override { return {"void", ""}; }
|
||||
};
|
||||
|
||||
// RETURN - выбрасывает исключение с значением
|
||||
struct ReturnNode : Node {
|
||||
std::unique_ptr<Node> expr;
|
||||
ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
std::string result = expr ? expr->eval(ctx) : "0";
|
||||
Value eval(Context& ctx) override {
|
||||
Value result = expr ? expr->eval(ctx) : Value{"void", ""};
|
||||
throw ReturnValue{result};
|
||||
}
|
||||
};
|
||||
|
||||
// ВЫЗОВ ФУНКЦИИ - самое важное для тебя!
|
||||
struct FuncCallNode : Node {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<Node>> args;
|
||||
@@ -122,7 +114,152 @@ struct FuncCallNode : Node {
|
||||
FuncCallNode(std::string n, std::vector<std::unique_ptr<Node>> a)
|
||||
: name(n), args(std::move(a)) {}
|
||||
|
||||
std::string eval(Context& ctx) override {
|
||||
Value eval(Context& ctx) override {
|
||||
// Встроенные функции
|
||||
if (name == "print" && args.size() == 1) {
|
||||
std::cout << args[0]->eval(ctx).value << std::endl;
|
||||
return {"void", ""};
|
||||
}
|
||||
if (name == "input" && args.size() == 0) {
|
||||
std::string input; std::getline(std::cin, input);
|
||||
return {"string", input};
|
||||
}
|
||||
if (name == "round" && args.size() == 1) {
|
||||
double val = std::stod(args[0]->eval(ctx).value);
|
||||
return {"int", std::to_string((int)std::round(val))};
|
||||
}
|
||||
if (name == "random" && args.size() == 2) {
|
||||
int min = std::stoi(args[0]->eval(ctx).value);
|
||||
int max = std::stoi(args[1]->eval(ctx).value);
|
||||
static std::random_device rd; static std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(min, max);
|
||||
return {"int", std::to_string(dis(gen))};
|
||||
}
|
||||
if (name == "fox" && args.size() == 0) {
|
||||
std::cout << "FoxLang" << std::endl;
|
||||
return {"void", ""};
|
||||
}
|
||||
if (name == "read_file" && args.size() == 1) {
|
||||
Value filenameVal = args[0]->eval(ctx);
|
||||
if (filenameVal.type != "string") {
|
||||
throw std::runtime_error("read_file() requires string filename");
|
||||
}
|
||||
|
||||
std::ifstream file(filenameVal.value);
|
||||
if (!file.is_open()) {
|
||||
return {"string", ""}; // Возвращаем пустую строку при ошибке
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
// Пропускаем комментарии и пустые строки
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Если строка не пустая и не комментарий, возвращаем её
|
||||
if (!line.empty()) {
|
||||
file.close();
|
||||
return {"string", line};
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return {"string", ""};
|
||||
}
|
||||
if (name == "http_get" && args.size() == 1) {
|
||||
Value urlVal = args[0]->eval(ctx);
|
||||
if (urlVal.type != "string") {
|
||||
throw std::runtime_error("http_get() requires string URL");
|
||||
}
|
||||
|
||||
// Простая реализация через system curl
|
||||
std::string cmd = "curl -s \"" + urlVal.value + "\"";
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe) {
|
||||
return {"string", ""};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
char buffer[128];
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
|
||||
result += buffer;
|
||||
}
|
||||
pclose(pipe);
|
||||
|
||||
return {"string", result};
|
||||
}
|
||||
if (name == "json_get" && args.size() == 2) {
|
||||
Value jsonVal = args[0]->eval(ctx);
|
||||
Value keyVal = args[1]->eval(ctx);
|
||||
|
||||
std::string json = jsonVal.value;
|
||||
std::string key = keyVal.value;
|
||||
|
||||
// Простой JSON парсер для Telegram API
|
||||
if (key == "chat_id") {
|
||||
size_t pos = json.find("\"chat\":{\"id\":");
|
||||
if (pos != std::string::npos) {
|
||||
pos += 13; // длина "\"chat\":{\"id\":"
|
||||
size_t end = json.find(",", pos);
|
||||
if (end != std::string::npos) {
|
||||
return {"string", json.substr(pos, end - pos)};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key == "text") {
|
||||
size_t pos = json.find("\"text\":\"");
|
||||
if (pos != std::string::npos) {
|
||||
pos += 8; // длина "\"text\":\""
|
||||
size_t end = json.find("\"", pos);
|
||||
if (end != std::string::npos) {
|
||||
return {"string", json.substr(pos, end - pos)};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key == "update_id") {
|
||||
// Ищем последний update_id в массиве
|
||||
size_t lastPos = 0;
|
||||
size_t pos = json.find("\"update_id\":");
|
||||
while (pos != std::string::npos) {
|
||||
lastPos = pos;
|
||||
pos = json.find("\"update_id\":", pos + 1);
|
||||
}
|
||||
|
||||
if (lastPos != 0) {
|
||||
lastPos += 12; // длина "\"update_id\":"
|
||||
size_t end = json.find(",", lastPos);
|
||||
if (end != std::string::npos) {
|
||||
return {"string", json.substr(lastPos, end - lastPos)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {"string", ""};
|
||||
}
|
||||
if (name == "str_contains" && args.size() == 2) {
|
||||
Value textVal = args[0]->eval(ctx);
|
||||
Value substrVal = args[1]->eval(ctx);
|
||||
|
||||
std::string text = textVal.value;
|
||||
std::string substr = substrVal.value;
|
||||
|
||||
bool found = text.find(substr) != std::string::npos;
|
||||
return {"bool", found ? "true" : "false"};
|
||||
}
|
||||
if (name == "str_to_int" && args.size() == 1) {
|
||||
Value strVal = args[0]->eval(ctx);
|
||||
if (strVal.type != "string") {
|
||||
return {"int", "0"};
|
||||
}
|
||||
|
||||
try {
|
||||
int result = std::stoi(strVal.value);
|
||||
return {"int", std::to_string(result)};
|
||||
} catch (...) {
|
||||
return {"int", "0"};
|
||||
}
|
||||
}
|
||||
|
||||
// Пользовательские функции
|
||||
auto funcNodeBase = ctx.getFunc(name);
|
||||
if (!funcNodeBase) {
|
||||
throw std::runtime_error("Runtime Error: Function '" + name + "' not found!");
|
||||
@@ -134,152 +271,292 @@ struct FuncCallNode : Node {
|
||||
throw std::runtime_error("Args count mismatch for '" + name + "'");
|
||||
}
|
||||
|
||||
std::vector<std::string> argValues;
|
||||
std::vector<Value> argValues;
|
||||
for (auto& arg : args) argValues.push_back(arg->eval(ctx));
|
||||
|
||||
// Находим глобальный контекст
|
||||
Context* root = &ctx;
|
||||
while (root->parent != nullptr) root = root->parent;
|
||||
|
||||
// Создаем локальную область видимости
|
||||
Context funcScope;
|
||||
funcScope.parent = root;
|
||||
funcScope.parent = &ctx;
|
||||
|
||||
for (size_t i = 0; i < funcDef->params.size(); i++) {
|
||||
funcScope.defineVar(funcDef->params[i].name, argValues[i]);
|
||||
funcScope.defineVar(funcDef->params[i].name, funcDef->params[i].type, argValues[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
funcDef->body->eval(funcScope);
|
||||
} catch (const ReturnValue& ret) {
|
||||
return ret.value; // ВОЗВРАЩАЕМ ЗНАЧЕНИЕ В ПЕРЕМЕННУЮ
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
return "0";
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct NumberNode : Node {
|
||||
std::string val;
|
||||
NumberNode(std::string v) : val(v) {}
|
||||
std::string eval(Context& ctx) override { return val; }
|
||||
bool isFloat;
|
||||
NumberNode(std::string v) : val(v) {
|
||||
isFloat = (v.find('.') != std::string::npos);
|
||||
}
|
||||
Value eval(Context& ctx) override { return {isFloat ? "float" : "int", val}; }
|
||||
};
|
||||
|
||||
struct StringNode : Node {
|
||||
std::string val;
|
||||
StringNode(std::string v) : val(v) {}
|
||||
std::string eval(Context& ctx) override { return val; }
|
||||
Value eval(Context& ctx) override { return {"string", val}; }
|
||||
};
|
||||
|
||||
struct BoolNode : Node {
|
||||
bool val;
|
||||
BoolNode(bool v) : val(v) {}
|
||||
Value eval(Context& ctx) override { return {"bool", val ? "true" : "false"}; }
|
||||
};
|
||||
|
||||
struct VarAccessNode : Node {
|
||||
std::string name;
|
||||
VarAccessNode(std::string n) : name(n) {}
|
||||
std::string eval(Context& ctx) override { return ctx.getVar(name); }
|
||||
Value eval(Context& ctx) override { return ctx.getVar(name); }
|
||||
};
|
||||
|
||||
struct VarDeclNode : Node {
|
||||
std::string type, name;
|
||||
std::unique_ptr<Node> expr;
|
||||
VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
|
||||
: type(t), name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.defineVar(name, type, expr->eval(ctx));
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct GlobalVarDeclNode : Node {
|
||||
std::string type, name; std::unique_ptr<Node> expr;
|
||||
GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) : type(t), name(n), expr(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
std::string type, name;
|
||||
std::unique_ptr<Node> expr;
|
||||
GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
|
||||
: type(t), name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Context* root = &ctx;
|
||||
while (root->parent != nullptr) root = root->parent;
|
||||
root->defineVar(name, expr->eval(ctx));
|
||||
return "";
|
||||
root->defineVar(name, type, expr->eval(ctx));
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
struct VarDeclNode : Node {
|
||||
std::string type, name; std::unique_ptr<Node> expr;
|
||||
VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) : type(t), name(n), expr(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
// Здесь expr->eval(ctx) может быть FuncCallNode, который вернет результат!
|
||||
ctx.defineVar(name, expr->eval(ctx));
|
||||
return "";
|
||||
}
|
||||
};
|
||||
struct AssignNode : Node {
|
||||
std::string name; std::unique_ptr<Node> expr;
|
||||
AssignNode(std::string n, std::unique_ptr<Node> e) : name(n), expr(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
|
||||
struct VarAssignNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> expr;
|
||||
VarAssignNode(std::string n, std::unique_ptr<Node> e) : name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.setVar(name, expr->eval(ctx));
|
||||
return "";
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct BinOpNode : Node {
|
||||
char op; std::unique_ptr<Node> left, right;
|
||||
BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r) : op(o), left(std::move(l)), right(std::move(r)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
std::string lStr = left->eval(ctx); std::string rStr = right->eval(ctx);
|
||||
bool isStr = (lStr.find_first_not_of("0123456789.-") != std::string::npos) || (rStr.find_first_not_of("0123456789.-") != std::string::npos);
|
||||
if (op == '+' && isStr) return lStr + rStr;
|
||||
double l = std::stod(lStr); double r = std::stod(rStr);
|
||||
if (op == '+') return formatNumber(l+r);
|
||||
if (op == '-') return formatNumber(l-r);
|
||||
if (op == '*') return formatNumber(l*r);
|
||||
if (op == '/') return formatNumber(r!=0 ? l/r : 0);
|
||||
if (op == '%') return formatNumber((int)l % (int)r);
|
||||
return "0";
|
||||
char op;
|
||||
std::unique_ptr<Node> left, right;
|
||||
BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r)
|
||||
: op(o), left(std::move(l)), right(std::move(r)) {}
|
||||
|
||||
Value eval(Context& ctx) override {
|
||||
Value lval = left->eval(ctx);
|
||||
Value rval = right->eval(ctx);
|
||||
|
||||
if (op == '+') {
|
||||
if (lval.type == "string" || rval.type == "string") {
|
||||
return {"string", lval.value + rval.value};
|
||||
}
|
||||
if (lval.type == "float" || rval.type == "float") {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
return {"float", formatNumber(l + r)};
|
||||
}
|
||||
int l = std::stoi(lval.value), r = std::stoi(rval.value);
|
||||
return {"int", std::to_string(l + r)};
|
||||
}
|
||||
|
||||
if (op == '-' || op == '*' || op == '/' || op == '%') {
|
||||
if (lval.type == "float" || rval.type == "float") {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
double result = (op == '-') ? l - r : (op == '*') ? l * r :
|
||||
(op == '/') ? l / r : std::fmod(l, r);
|
||||
return {"float", formatNumber(result)};
|
||||
}
|
||||
int l = std::stoi(lval.value), r = std::stoi(rval.value);
|
||||
int result = (op == '-') ? l - r : (op == '*') ? l * r :
|
||||
(op == '/') ? l / r : l % r;
|
||||
return {"int", std::to_string(result)};
|
||||
}
|
||||
|
||||
if (op == '=' || op == '!' || op == '<' || op == '>') {
|
||||
bool result;
|
||||
if (lval.type == "string" && rval.type == "string") {
|
||||
result = (op == '=') ? lval.value == rval.value :
|
||||
(op == '!') ? lval.value != rval.value :
|
||||
(op == '<') ? lval.value < rval.value : lval.value > rval.value;
|
||||
} else {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
result = (op == '=') ? l == r : (op == '!') ? l != r :
|
||||
(op == '<') ? l < r : l > r;
|
||||
}
|
||||
return {"bool", result ? "true" : "false"};
|
||||
}
|
||||
|
||||
if (op == '&' || op == '|') {
|
||||
bool l = (lval.value == "true"), r = (rval.value == "true");
|
||||
bool result = (op == '&') ? l && r : l || r;
|
||||
return {"bool", result ? "true" : "false"};
|
||||
}
|
||||
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
struct CompareNode : Node {
|
||||
std::string op; std::unique_ptr<Node> left, right;
|
||||
CompareNode(std::string o, std::unique_ptr<Node> l, std::unique_ptr<Node> r) : op(o), left(std::move(l)), right(std::move(r)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
double l = std::stod(left->eval(ctx)); double r = std::stod(right->eval(ctx));
|
||||
if (op == "==") return (std::abs(l - r) < 0.001) ? "1" : "0";
|
||||
if (op == "!=") return (std::abs(l - r) > 0.001) ? "1" : "0";
|
||||
if (op == "<") return (l < r) ? "1" : "0";
|
||||
if (op == ">") return (l > r) ? "1" : "0";
|
||||
return "0";
|
||||
|
||||
struct UnaryOpNode : Node {
|
||||
std::string op;
|
||||
std::unique_ptr<Node> operand;
|
||||
UnaryOpNode(std::string o, std::unique_ptr<Node> n) : op(o), operand(std::move(n)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Value val = operand->eval(ctx);
|
||||
if (op == "!") {
|
||||
bool b = (val.value == "true");
|
||||
return {"bool", b ? "false" : "true"};
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
struct IfNode : Node {
|
||||
std::unique_ptr<Node> cond, thenB, elseB;
|
||||
IfNode(std::unique_ptr<Node> c, std::unique_ptr<Node> t, std::unique_ptr<Node> e) : cond(std::move(c)), thenB(std::move(t)), elseB(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
if (cond->eval(ctx) == "1") thenB->eval(ctx);
|
||||
else if (elseB) elseB->eval(ctx);
|
||||
return "";
|
||||
|
||||
struct PostIncNode : Node {
|
||||
std::string name;
|
||||
PostIncNode(std::string n) : name(n) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Value current = ctx.getVar(name);
|
||||
int val = std::stoi(current.value);
|
||||
ctx.setVar(name, {"int", std::to_string(val + 1)});
|
||||
return {"int", std::to_string(val)};
|
||||
}
|
||||
};
|
||||
struct WhileNode : Node {
|
||||
std::unique_ptr<Node> cond, body;
|
||||
WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b) : cond(std::move(c)), body(std::move(b)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
while (cond->eval(ctx) == "1") body->eval(ctx);
|
||||
return "";
|
||||
|
||||
struct ArrayDeclNode : Node {
|
||||
std::string name;
|
||||
int size;
|
||||
ArrayDeclNode(std::string n, int s) : name(n), size(s) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.arrays[name] = std::vector<Value>(size, {"int", "0"});
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct ArraySetNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> index, value;
|
||||
ArraySetNode(std::string n, std::unique_ptr<Node> i, std::unique_ptr<Node> v)
|
||||
: name(n), index(std::move(i)), value(std::move(v)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
int idx = std::stoi(index->eval(ctx).value);
|
||||
ctx.getArray(name)[idx] = value->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct ArrayGetNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> index;
|
||||
ArrayGetNode(std::string n, std::unique_ptr<Node> i) : name(n), index(std::move(i)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
int idx = std::stoi(index->eval(ctx).value);
|
||||
return ctx.getArray(name)[idx];
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockNode : Node {
|
||||
std::vector<std::unique_ptr<Node>> stmts;
|
||||
std::string eval(Context& ctx) override {
|
||||
for(auto& s : stmts) s->eval(ctx);
|
||||
return "";
|
||||
Value eval(Context& ctx) override {
|
||||
for (auto& stmt : stmts) stmt->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
struct PrintNode : Node {
|
||||
std::unique_ptr<Node> expr;
|
||||
PrintNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
|
||||
std::string eval(Context& ctx) override { std::cout << expr->eval(ctx) << std::endl; return ""; }
|
||||
|
||||
struct IfNode : Node {
|
||||
std::unique_ptr<Node> condition, thenB, elseB;
|
||||
IfNode(std::unique_ptr<Node> c, std::unique_ptr<Node> t, std::unique_ptr<Node> e = nullptr)
|
||||
: condition(std::move(c)), thenB(std::move(t)), elseB(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
bool cond = (condition->eval(ctx).value == "true");
|
||||
if (cond) thenB->eval(ctx);
|
||||
else if (elseB) elseB->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct WhileNode : Node {
|
||||
std::unique_ptr<Node> condition, body;
|
||||
WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b)
|
||||
: condition(std::move(c)), body(std::move(b)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
while (condition->eval(ctx).value == "true") {
|
||||
body->eval(ctx);
|
||||
}
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct ForNode : Node {
|
||||
std::unique_ptr<Node> init, condition, step, body;
|
||||
ForNode(std::unique_ptr<Node> i, std::unique_ptr<Node> c, std::unique_ptr<Node> s, std::unique_ptr<Node> b)
|
||||
: init(std::move(i)), condition(std::move(c)), step(std::move(s)), body(std::move(b)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
if (init) init->eval(ctx);
|
||||
while (condition->eval(ctx).value == "true") {
|
||||
body->eval(ctx);
|
||||
if (step) step->eval(ctx);
|
||||
}
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct InputNode : Node {
|
||||
std::string eval(Context& ctx) override { std::string b; std::getline(std::cin, b); return b; }
|
||||
};
|
||||
struct ArrayDeclNode : Node {
|
||||
std::string name; std::unique_ptr<Node> size;
|
||||
ArrayDeclNode(std::string n, std::unique_ptr<Node> s) : name(n), size(std::move(s)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
ctx.arrays[name] = std::vector<std::string>(std::stoi(size->eval(ctx)), "0");
|
||||
return "";
|
||||
Value eval(Context& ctx) override {
|
||||
std::string input; std::getline(std::cin, input);
|
||||
return {"string", input};
|
||||
}
|
||||
};
|
||||
struct ArraySetNode : Node {
|
||||
std::string name; std::unique_ptr<Node> idx, val;
|
||||
ArraySetNode(std::string n, std::unique_ptr<Node> i, std::unique_ptr<Node> v) : name(n), idx(std::move(i)), val(std::move(v)) {}
|
||||
std::string eval(Context& ctx) override {
|
||||
auto& arr = ctx.getArray(name); arr[std::stoi(idx->eval(ctx))] = val->eval(ctx); return "";
|
||||
|
||||
struct ReadFileNode : Node {
|
||||
std::unique_ptr<Node> filename;
|
||||
ReadFileNode(std::unique_ptr<Node> fn) : filename(std::move(fn)) {}
|
||||
|
||||
Value eval(Context& ctx) override {
|
||||
Value filenameVal = filename->eval(ctx);
|
||||
if (filenameVal.type != "string") {
|
||||
throw std::runtime_error("read_file() requires string filename");
|
||||
}
|
||||
|
||||
std::ifstream file(filenameVal.value);
|
||||
if (!file.is_open()) {
|
||||
return {"string", ""}; // Возвращаем пустую строку при ошибке
|
||||
}
|
||||
|
||||
std::string content;
|
||||
std::string line;
|
||||
bool first = true;
|
||||
while (std::getline(file, line)) {
|
||||
// Пропускаем комментарии и пустые строки
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Если строка не пустая и не комментарий, возвращаем её
|
||||
if (!line.empty()) {
|
||||
file.close();
|
||||
return {"string", line};
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return {"string", ""};
|
||||
}
|
||||
};
|
||||
struct ArrayGetNode : Node {
|
||||
std::string name; std::unique_ptr<Node> idx;
|
||||
ArrayGetNode(std::string n, std::unique_ptr<Node> i) : name(n), idx(std::move(i)) {}
|
||||
std::string eval(Context& ctx) override { return ctx.getArray(name)[std::stoi(idx->eval(ctx))]; }
|
||||
|
||||
struct UsingNode : Node {
|
||||
std::string libName;
|
||||
UsingNode(std::string lib) : libName(lib) {}
|
||||
Value eval(Context& ctx) override { return {"void", ""}; }
|
||||
};
|
||||
struct IncludeNode : Node { std::string eval(Context& ctx) override { return ""; } };
|
||||
struct FoxNode : Node { std::string eval(Context& ctx) override { std::cout << "FoxLang" << std::endl; return ""; } };
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
// Forward declaration
|
||||
struct Node;
|
||||
|
||||
struct FuncParam {
|
||||
std::string type;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// Unified Value type for the language
|
||||
struct Value {
|
||||
std::string type; // "int", "float", "string", "bool", "void"
|
||||
std::string value;
|
||||
};
|
||||
|
||||
// Контекст памяти (переменные и функции)
|
||||
struct Context {
|
||||
Context* parent = nullptr; // Для глобальных переменных
|
||||
std::map<std::string, Value> variables; // Stores typed values
|
||||
std::map<std::string, std::shared_ptr<Node>> functions;
|
||||
std::map<std::string, std::vector<Value>> arrays;
|
||||
|
||||
bool exists(const std::string& name) {
|
||||
if (variables.count(name) || arrays.count(name)) return true;
|
||||
if (parent) return parent->exists(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Value getVar(const std::string& name) {
|
||||
if (variables.count(name)) return variables[name];
|
||||
if (parent) return parent->getVar(name);
|
||||
throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!");
|
||||
}
|
||||
|
||||
std::vector<Value>& getArray(const std::string& name) {
|
||||
if (arrays.count(name)) return arrays[name];
|
||||
if (parent) return parent->getArray(name);
|
||||
throw std::runtime_error("Runtime Error: Array '" + name + "' not found!");
|
||||
}
|
||||
|
||||
void defineFunc(const std::string& name, std::shared_ptr<Node> func) {
|
||||
functions[name] = func;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> getFunc(const std::string& name) {
|
||||
if (functions.count(name)) return functions[name];
|
||||
if (parent) return parent->getFunc(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void defineVar(const std::string& name, const std::string& type, const Value& value) {
|
||||
if (variables.count(name)) {
|
||||
throw std::runtime_error("Error: Variable '" + name + "' already defined!");
|
||||
}
|
||||
std::string finalVal = value.value;
|
||||
if (type == "int") {
|
||||
try {
|
||||
finalVal = std::to_string((int)std::stod(value.value));
|
||||
} catch(...) { finalVal = "0"; }
|
||||
}
|
||||
variables[name] = {type, finalVal};
|
||||
}
|
||||
|
||||
// Set variable with type checking/conversion
|
||||
void setVar(const std::string& name, Value val) {
|
||||
if (variables.count(name)) {
|
||||
std::string targetType = variables[name].type;
|
||||
|
||||
// Handle int/float conversion
|
||||
if (targetType == "int") {
|
||||
try {
|
||||
double d = std::stod(val.value);
|
||||
variables[name].value = std::to_string((int)d);
|
||||
} catch(...) { variables[name].value = "0"; }
|
||||
} else if (targetType == "float") {
|
||||
try {
|
||||
double d = std::stod(val.value);
|
||||
variables[name].value = formatNumber(d);
|
||||
} catch(...) { variables[name].value = "0.0"; }
|
||||
} else {
|
||||
variables[name].value = val.value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (parent) { parent->setVar(name, val); return; }
|
||||
throw std::runtime_error("Error: Variable '" + name + "' not defined!");
|
||||
}
|
||||
|
||||
void defineGlobal(const std::string& name, std::string type, Value val) {
|
||||
if (parent) parent->defineGlobal(name, type, val);
|
||||
else defineVar(name, type, val);
|
||||
}
|
||||
};
|
||||
|
||||
// Exception for return
|
||||
struct ReturnValue {
|
||||
Value value;
|
||||
};
|
||||
|
||||
static std::string formatNumber(double val) {
|
||||
std::string s = std::to_string(val);
|
||||
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
||||
if (s.back() == '.') s.pop_back();
|
||||
return s;
|
||||
}
|
||||
|
||||
struct Node {
|
||||
virtual ~Node() = default;
|
||||
virtual Value eval(Context& ctx) = 0;
|
||||
};
|
||||
|
||||
// --- ОСНОВНЫЕ УЗЛЫ ---
|
||||
|
||||
struct FuncDefNode : Node {
|
||||
std::string returnType;
|
||||
std::string name;
|
||||
std::vector<FuncParam> params;
|
||||
std::shared_ptr<Node> body;
|
||||
|
||||
FuncDefNode(std::string rt, std::string n, std::vector<FuncParam> p, std::shared_ptr<Node> b)
|
||||
: returnType(rt), name(n), params(p), body(b) {}
|
||||
|
||||
Value eval(Context& ctx) override { return {"void", ""}; }
|
||||
};
|
||||
|
||||
struct ReturnNode : Node {
|
||||
std::unique_ptr<Node> expr;
|
||||
ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Value result = expr ? expr->eval(ctx) : Value{"void", ""};
|
||||
throw ReturnValue{result};
|
||||
}
|
||||
};
|
||||
|
||||
struct FuncCallNode : Node {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<Node>> args;
|
||||
|
||||
FuncCallNode(std::string n, std::vector<std::unique_ptr<Node>> a)
|
||||
: name(n), args(std::move(a)) {}
|
||||
|
||||
Value eval(Context& ctx) override {
|
||||
// Встроенные функции
|
||||
if (name == "print" && args.size() == 1) {
|
||||
std::cout << args[0]->eval(ctx).value << std::endl;
|
||||
return {"void", ""};
|
||||
}
|
||||
if (name == "input" && args.size() == 0) {
|
||||
std::string input; std::getline(std::cin, input);
|
||||
return {"string", input};
|
||||
}
|
||||
if (name == "round" && args.size() == 1) {
|
||||
double val = std::stod(args[0]->eval(ctx).value);
|
||||
return {"int", std::to_string((int)std::round(val))};
|
||||
}
|
||||
if (name == "random" && args.size() == 2) {
|
||||
int min = std::stoi(args[0]->eval(ctx).value);
|
||||
int max = std::stoi(args[1]->eval(ctx).value);
|
||||
static std::random_device rd; static std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(min, max);
|
||||
return {"int", std::to_string(dis(gen))};
|
||||
}
|
||||
if (name == "fox" && args.size() == 0) {
|
||||
std::cout << "FoxLang" << std::endl;
|
||||
return {"void", ""};
|
||||
}
|
||||
|
||||
// Пользовательские функции
|
||||
auto funcNodeBase = ctx.getFunc(name);
|
||||
if (!funcNodeBase) {
|
||||
throw std::runtime_error("Runtime Error: Function '" + name + "' not found!");
|
||||
}
|
||||
|
||||
FuncDefNode* funcDef = static_cast<FuncDefNode*>(funcNodeBase.get());
|
||||
|
||||
if (args.size() != funcDef->params.size()) {
|
||||
throw std::runtime_error("Args count mismatch for '" + name + "'");
|
||||
}
|
||||
|
||||
std::vector<Value> argValues;
|
||||
for (auto& arg : args) argValues.push_back(arg->eval(ctx));
|
||||
|
||||
Context* root = &ctx;
|
||||
while (root->parent != nullptr) root = root->parent;
|
||||
|
||||
Context funcScope;
|
||||
funcScope.parent = root;
|
||||
|
||||
for (size_t i = 0; i < funcDef->params.size(); i++) {
|
||||
funcScope.defineVar(funcDef->params[i].name, funcDef->params[i].type, argValues[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
funcDef->body->eval(funcScope);
|
||||
} catch (const ReturnValue& ret) {
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
return {"void", "0"};
|
||||
}
|
||||
};
|
||||
|
||||
struct NumberNode : Node {
|
||||
std::string val;
|
||||
bool isFloat;
|
||||
NumberNode(std::string v) : val(v) {
|
||||
isFloat = (v.find('.') != std::string::npos);
|
||||
}
|
||||
Value eval(Context& ctx) override { return {isFloat ? "float" : "int", val}; }
|
||||
};
|
||||
|
||||
struct StringNode : Node {
|
||||
std::string val;
|
||||
StringNode(std::string v) : val(v) {}
|
||||
Value eval(Context& ctx) override { return {"string", val}; }
|
||||
};
|
||||
|
||||
struct BoolNode : Node {
|
||||
bool val;
|
||||
BoolNode(bool v) : val(v) {}
|
||||
Value eval(Context& ctx) override { return {"bool", val ? "true" : "false"}; }
|
||||
};
|
||||
|
||||
struct VarAccessNode : Node {
|
||||
std::string name;
|
||||
VarAccessNode(std::string n) : name(n) {}
|
||||
Value eval(Context& ctx) override { return ctx.getVar(name); }
|
||||
};
|
||||
|
||||
struct VarDeclNode : Node {
|
||||
std::string type, name;
|
||||
std::unique_ptr<Node> expr;
|
||||
VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
|
||||
: type(t), name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.defineVar(name, type, expr->eval(ctx));
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct GlobalVarDeclNode : Node {
|
||||
std::string type, name;
|
||||
std::unique_ptr<Node> expr;
|
||||
GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
|
||||
: type(t), name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Context* root = &ctx;
|
||||
while (root->parent != nullptr) root = root->parent;
|
||||
root->defineVar(name, type, expr->eval(ctx));
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct VarAssignNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> expr;
|
||||
VarAssignNode(std::string n, std::unique_ptr<Node> e) : name(n), expr(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.setVar(name, expr->eval(ctx));
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct BinOpNode : Node {
|
||||
char op;
|
||||
std::unique_ptr<Node> left, right;
|
||||
BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r)
|
||||
: op(o), left(std::move(l)), right(std::move(r)) {}
|
||||
|
||||
Value eval(Context& ctx) override {
|
||||
Value lval = left->eval(ctx);
|
||||
Value rval = right->eval(ctx);
|
||||
|
||||
if (op == '+') {
|
||||
if (lval.type == "string" || rval.type == "string") {
|
||||
return {"string", lval.value + rval.value};
|
||||
}
|
||||
if (lval.type == "float" || rval.type == "float") {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
return {"float", formatNumber(l + r)};
|
||||
}
|
||||
int l = std::stoi(lval.value), r = std::stoi(rval.value);
|
||||
return {"int", std::to_string(l + r)};
|
||||
}
|
||||
|
||||
if (op == '-' || op == '*' || op == '/' || op == '%') {
|
||||
if (lval.type == "float" || rval.type == "float") {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
double result = (op == '-') ? l - r : (op == '*') ? l * r :
|
||||
(op == '/') ? l / r : std::fmod(l, r);
|
||||
return {"float", formatNumber(result)};
|
||||
}
|
||||
int l = std::stoi(lval.value), r = std::stoi(rval.value);
|
||||
int result = (op == '-') ? l - r : (op == '*') ? l * r :
|
||||
(op == '/') ? l / r : l % r;
|
||||
return {"int", std::to_string(result)};
|
||||
}
|
||||
|
||||
if (op == '=' || op == '!' || op == '<' || op == '>') {
|
||||
bool result;
|
||||
if (lval.type == "string" && rval.type == "string") {
|
||||
result = (op == '=') ? lval.value == rval.value :
|
||||
(op == '!') ? lval.value != rval.value :
|
||||
(op == '<') ? lval.value < rval.value : lval.value > rval.value;
|
||||
} else {
|
||||
double l = std::stod(lval.value), r = std::stod(rval.value);
|
||||
result = (op == '=') ? l == r : (op == '!') ? l != r :
|
||||
(op == '<') ? l < r : l > r;
|
||||
}
|
||||
return {"bool", result ? "true" : "false"};
|
||||
}
|
||||
|
||||
if (op == '&' || op == '|') {
|
||||
bool l = (lval.value == "true"), r = (rval.value == "true");
|
||||
bool result = (op == '&') ? l && r : l || r;
|
||||
return {"bool", result ? "true" : "false"};
|
||||
}
|
||||
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct UnaryOpNode : Node {
|
||||
std::string op;
|
||||
std::unique_ptr<Node> operand;
|
||||
UnaryOpNode(std::string o, std::unique_ptr<Node> n) : op(o), operand(std::move(n)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Value val = operand->eval(ctx);
|
||||
if (op == "!") {
|
||||
bool b = (val.value == "true");
|
||||
return {"bool", b ? "false" : "true"};
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
struct PostIncNode : Node {
|
||||
std::string name;
|
||||
PostIncNode(std::string n) : name(n) {}
|
||||
Value eval(Context& ctx) override {
|
||||
Value current = ctx.getVar(name);
|
||||
int val = std::stoi(current.value);
|
||||
ctx.setVar(name, {"int", std::to_string(val + 1)});
|
||||
return {"int", std::to_string(val)};
|
||||
}
|
||||
};
|
||||
|
||||
struct ArrayDeclNode : Node {
|
||||
std::string name;
|
||||
int size;
|
||||
ArrayDeclNode(std::string n, int s) : name(n), size(s) {}
|
||||
Value eval(Context& ctx) override {
|
||||
ctx.arrays[name] = std::vector<Value>(size, {"int", "0"});
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct ArraySetNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> index, value;
|
||||
ArraySetNode(std::string n, std::unique_ptr<Node> i, std::unique_ptr<Node> v)
|
||||
: name(n), index(std::move(i)), value(std::move(v)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
int idx = std::stoi(index->eval(ctx).value);
|
||||
ctx.getArray(name)[idx] = value->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct ArrayGetNode : Node {
|
||||
std::string name;
|
||||
std::unique_ptr<Node> index;
|
||||
ArrayGetNode(std::string n, std::unique_ptr<Node> i) : name(n), index(std::move(i)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
int idx = std::stoi(index->eval(ctx).value);
|
||||
return ctx.getArray(name)[idx];
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockNode : Node {
|
||||
std::vector<std::unique_ptr<Node>> stmts;
|
||||
Value eval(Context& ctx) override {
|
||||
for (auto& stmt : stmts) stmt->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct IfNode : Node {
|
||||
std::unique_ptr<Node> condition, thenB, elseB;
|
||||
IfNode(std::unique_ptr<Node> c, std::unique_ptr<Node> t, std::unique_ptr<Node> e = nullptr)
|
||||
: condition(std::move(c)), thenB(std::move(t)), elseB(std::move(e)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
bool cond = (condition->eval(ctx).value == "true");
|
||||
if (cond) thenB->eval(ctx);
|
||||
else if (elseB) elseB->eval(ctx);
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct WhileNode : Node {
|
||||
std::unique_ptr<Node> condition, body;
|
||||
WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b)
|
||||
: condition(std::move(c)), body(std::move(b)) {}
|
||||
Value eval(Context& ctx) override {
|
||||
while (condition->eval(ctx).value == "true") {
|
||||
body->eval(ctx);
|
||||
}
|
||||
return {"void", ""};
|
||||
}
|
||||
};
|
||||
|
||||
struct InputNode : Node {
|
||||
Value eval(Context& ctx) override {
|
||||
std::string input; std::getline(std::cin, input);
|
||||
return {"string", input};
|
||||
}
|
||||
};
|
||||
|
||||
struct UsingNode : Node {
|
||||
std::string libName;
|
||||
UsingNode(std::string lib) : libName(lib) {}
|
||||
Value eval(Context& ctx) override { return {"void", ""}; }
|
||||
};
|
||||
+47
-3
@@ -23,7 +23,9 @@ std::vector<Token> Lexer::tokenize() {
|
||||
if (isdigit(current)) {
|
||||
std::string num;
|
||||
while (pos < source.length() && isdigit(source[pos])) num += source[pos++];
|
||||
if (pos < source.length() && source[pos] == '.') {
|
||||
// Проверяем точку только если после неё есть цифра (для float)
|
||||
if (pos < source.length() && source[pos] == '.' &&
|
||||
pos + 1 < source.length() && isdigit(source[pos + 1])) {
|
||||
num += source[pos++];
|
||||
while (pos < source.length() && isdigit(source[pos])) num += source[pos++];
|
||||
}
|
||||
@@ -31,7 +33,23 @@ std::vector<Token> Lexer::tokenize() {
|
||||
}
|
||||
else if (current == '"') {
|
||||
pos++; std::string str;
|
||||
while (pos < source.length() && source[pos] != '"') str += source[pos++];
|
||||
while (pos < source.length() && source[pos] != '"') {
|
||||
if (source[pos] == '\\' && pos + 1 < source.length()) {
|
||||
pos++; // Пропускаем обратный слеш
|
||||
char escaped = source[pos];
|
||||
switch (escaped) {
|
||||
case 'n': str += '\n'; break;
|
||||
case 't': str += '\t'; break;
|
||||
case 'r': str += '\r'; break;
|
||||
case '\\': str += '\\'; break;
|
||||
case '"': str += '"'; break;
|
||||
default: str += escaped; break;
|
||||
}
|
||||
} else {
|
||||
str += source[pos];
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
pos++;
|
||||
tokens.push_back({TokenType::STRING_LITERAL, str, line});
|
||||
}
|
||||
@@ -41,15 +59,28 @@ std::vector<Token> Lexer::tokenize() {
|
||||
id += source[pos++];
|
||||
}
|
||||
|
||||
if (id == "print") tokens.push_back({TokenType::PRINT, id, line});
|
||||
// Если идентификатор содержит подчеркивания, это точно не ключевое слово
|
||||
if (id.find('_') != std::string::npos) {
|
||||
tokens.push_back({TokenType::IDENTIFIER, id, line});
|
||||
}
|
||||
else if (id == "print") tokens.push_back({TokenType::PRINT, id, line});
|
||||
else if (id == "input") tokens.push_back({TokenType::INPUT, id, line});
|
||||
else if (id == "round") tokens.push_back({TokenType::ROUND, id, line});
|
||||
else if (id == "random") tokens.push_back({TokenType::RANDOM, id, line});
|
||||
else if (id == "fox") tokens.push_back({TokenType::FOX, id, line});
|
||||
else if (id == "read_file") tokens.push_back({TokenType::READ_FILE, id, line});
|
||||
else if (id == "json_get") tokens.push_back({TokenType::JSON_GET, id, line});
|
||||
else if (id == "str_contains") tokens.push_back({TokenType::STR_CONTAINS, id, line});
|
||||
else if (id == "str_to_int") tokens.push_back({TokenType::STR_TO_INT, id, line});
|
||||
else if (id == "int") tokens.push_back({TokenType::INT_KW, id, line});
|
||||
else if (id == "float") tokens.push_back({TokenType::FLOAT_KW, id, line});
|
||||
else if (id == "string") tokens.push_back({TokenType::STRING_KW, id, line});
|
||||
else if (id == "bool") tokens.push_back({TokenType::BOOL_KW, id, line});
|
||||
else if (id == "true") tokens.push_back({TokenType::TRUE_KW, id, line});
|
||||
else if (id == "false") tokens.push_back({TokenType::FALSE_KW, id, line});
|
||||
else if (id == "void") tokens.push_back({TokenType::VOID_KW, id, line});
|
||||
else if (id == "while") tokens.push_back({TokenType::WHILE, id, line});
|
||||
else if (id == "for") tokens.push_back({TokenType::FOR, id, line});
|
||||
else if (id == "if") tokens.push_back({TokenType::IF, id, line});
|
||||
else if (id == "else") tokens.push_back({TokenType::ELSE, id, line});
|
||||
else if (id == "array") tokens.push_back({TokenType::ARRAY, id, line});
|
||||
@@ -57,6 +88,7 @@ std::vector<Token> Lexer::tokenize() {
|
||||
else if (id == "get") tokens.push_back({TokenType::GET, id, line});
|
||||
else if (id == "size") tokens.push_back({TokenType::SIZE, id, line});
|
||||
else if (id == "include") tokens.push_back({TokenType::INCLUDE, id, line});
|
||||
else if (id == "using") tokens.push_back({TokenType::USING, id, line});
|
||||
else if (id == "return") tokens.push_back({TokenType::RETURN, id, line});
|
||||
else if (id == "global") tokens.push_back({TokenType::GLOBAL, id, line});
|
||||
else tokens.push_back({TokenType::IDENTIFIER, id, line});
|
||||
@@ -68,6 +100,15 @@ std::vector<Token> Lexer::tokenize() {
|
||||
if (current == '!' && pos+1 < source.length() && source[pos+1] == '=') {
|
||||
tokens.push_back({TokenType::NEQ, "!=", line}); pos+=2; continue;
|
||||
}
|
||||
if (current == '+' && pos+1 < source.length() && source[pos+1] == '+') {
|
||||
tokens.push_back({TokenType::INC, "++", line}); pos+=2; continue;
|
||||
}
|
||||
if (current == '&' && pos+1 < source.length() && source[pos+1] == '&') {
|
||||
tokens.push_back({TokenType::AND, "&&", line}); pos+=2; continue;
|
||||
}
|
||||
if (current == '|' && pos+1 < source.length() && source[pos+1] == '|') {
|
||||
tokens.push_back({TokenType::OR, "||", line}); pos+=2; continue;
|
||||
}
|
||||
|
||||
switch (current) {
|
||||
case '+': tokens.push_back({TokenType::PLUS, "+", line}); break;
|
||||
@@ -84,8 +125,11 @@ std::vector<Token> Lexer::tokenize() {
|
||||
case ';': tokens.push_back({TokenType::SEMICOLON, ";", line}); break;
|
||||
case ',': tokens.push_back({TokenType::COMMA, ",", line}); break;
|
||||
case '=': tokens.push_back({TokenType::ASSIGN, "=", line}); break;
|
||||
case '.': tokens.push_back({TokenType::DOT, ".", line}); break;
|
||||
case '!': tokens.push_back({TokenType::NOT, "!", line}); break;
|
||||
case '<': tokens.push_back({TokenType::LT, "<", line}); break;
|
||||
case '>': tokens.push_back({TokenType::GT, ">", line}); break;
|
||||
case ':': tokens.push_back({TokenType::COLON, ":", line}); break;
|
||||
default:
|
||||
throw std::runtime_error(std::string("Runtime Error: Unknown character '") + current + "' at line " + std::to_string(line));
|
||||
}
|
||||
|
||||
+135
-17
@@ -29,6 +29,12 @@ std::unique_ptr<Node> Parser::primary() {
|
||||
);
|
||||
}
|
||||
|
||||
// 1.5. УНАРНЫЙ НЕ (Обработка !condition)
|
||||
if (tokens[pos].type == TokenType::NOT) {
|
||||
consume(TokenType::NOT);
|
||||
return std::make_unique<UnaryOpNode>("!", primary());
|
||||
}
|
||||
|
||||
// 2. Числа
|
||||
if (tokens[pos].type == TokenType::NUMBER) {
|
||||
return std::make_unique<NumberNode>(consume(TokenType::NUMBER).value);
|
||||
@@ -39,7 +45,17 @@ std::unique_ptr<Node> Parser::primary() {
|
||||
return std::make_unique<StringNode>(consume(TokenType::STRING_LITERAL).value);
|
||||
}
|
||||
|
||||
// 4. Переменные и Вызовы функций
|
||||
// 4. Boolean литералы
|
||||
if (tokens[pos].type == TokenType::TRUE_KW) {
|
||||
consume(TokenType::TRUE_KW);
|
||||
return std::make_unique<BoolNode>(true);
|
||||
}
|
||||
if (tokens[pos].type == TokenType::FALSE_KW) {
|
||||
consume(TokenType::FALSE_KW);
|
||||
return std::make_unique<BoolNode>(false);
|
||||
}
|
||||
|
||||
// 5. Переменные и Вызовы функций
|
||||
if (tokens[pos].type == TokenType::IDENTIFIER) {
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
|
||||
@@ -57,6 +73,13 @@ std::unique_ptr<Node> Parser::primary() {
|
||||
consume(TokenType::RPAREN);
|
||||
return std::make_unique<FuncCallNode>(name, std::move(args));
|
||||
}
|
||||
|
||||
// Post increment operator (expression context: x = i++ + 5)
|
||||
if (tokens[pos].type == TokenType::INC) {
|
||||
consume(TokenType::INC);
|
||||
return std::make_unique<PostIncNode>(name);
|
||||
}
|
||||
|
||||
// Иначе это просто доступ к переменной
|
||||
return std::make_unique<VarAccessNode>(name);
|
||||
}
|
||||
@@ -74,6 +97,13 @@ std::unique_ptr<Node> Parser::primary() {
|
||||
return std::make_unique<InputNode>();
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::READ_FILE) {
|
||||
consume(TokenType::READ_FILE); consume(TokenType::LPAREN);
|
||||
auto filename = expression();
|
||||
consume(TokenType::RPAREN);
|
||||
return std::make_unique<ReadFileNode>(std::move(filename));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::LPAREN) {
|
||||
consume(TokenType::LPAREN);
|
||||
auto n = expression();
|
||||
@@ -108,7 +138,25 @@ std::unique_ptr<Node> Parser::comparison() {
|
||||
if (tokens[pos].type == TokenType::EQ || tokens[pos].type == TokenType::NEQ ||
|
||||
tokens[pos].type == TokenType::LT || tokens[pos].type == TokenType::GT) {
|
||||
std::string op = tokens[pos].value; pos++;
|
||||
return std::make_unique<CompareNode>(op, std::move(node), expression());
|
||||
return std::make_unique<BinOpNode>(op[0], std::move(node), expression());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::logicalAnd() {
|
||||
auto node = comparison();
|
||||
while (tokens[pos].type == TokenType::AND) {
|
||||
std::string op = tokens[pos].value; pos++;
|
||||
node = std::make_unique<BinOpNode>(op[0], std::move(node), comparison());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::logicalOr() {
|
||||
auto node = logicalAnd();
|
||||
while (tokens[pos].type == TokenType::OR) {
|
||||
std::string op = tokens[pos].value; pos++;
|
||||
node = std::make_unique<BinOpNode>(op[0], std::move(node), logicalAnd());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -144,20 +192,25 @@ void processInclude(std::string filename, Context& ctx, std::string currentFile)
|
||||
|
||||
Parser parser(tokens);
|
||||
|
||||
// 1. Копируем текущую память внутрь include, чтобы он видел глобальные переменные
|
||||
// Копируем контекст и устанавливаем режим импорта
|
||||
parser.globalContext = ctx;
|
||||
parser.currentFile = fullPath;
|
||||
|
||||
// ВАЖНО: Мы убрали parser.importMode = true;
|
||||
// Теперь код внутри lib.fox (например, print) БУДЕТ выполняться.
|
||||
parser.importMode = false;
|
||||
parser.importMode = true; // Только парсим функции, не выполняем код
|
||||
|
||||
parser.run();
|
||||
|
||||
// 2. Возвращаем память обратно (функции из lib.fox появятся в main)
|
||||
// Возвращаем обновленный контекст с новыми функциями
|
||||
ctx = parser.globalContext;
|
||||
}
|
||||
|
||||
void Parser::processUsing(const std::string& libName, Context& ctx) {
|
||||
if (libName == "net.fox" || libName == "net") {
|
||||
// Добавляем сетевые функции в контекст
|
||||
// Эти функции будут доступны как встроенные
|
||||
// Реализация уже есть в FuncCallNode
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> Parser::statement() {
|
||||
if (tokens[pos].type == TokenType::INCLUDE) {
|
||||
consume(TokenType::INCLUDE); consume(TokenType::LPAREN);
|
||||
@@ -167,11 +220,27 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
return std::make_unique<BlockNode>();
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::USING) {
|
||||
consume(TokenType::USING);
|
||||
std::string libName = consume(TokenType::IDENTIFIER).value;
|
||||
if (pos < tokens.size() && tokens[pos].type == TokenType::DOT) {
|
||||
consume(TokenType::DOT);
|
||||
if (pos < tokens.size() && tokens[pos].type == TokenType::IDENTIFIER) {
|
||||
libName += "." + consume(TokenType::IDENTIFIER).value;
|
||||
}
|
||||
}
|
||||
consume(TokenType::SEMICOLON);
|
||||
processUsing(libName, globalContext);
|
||||
return std::make_unique<UsingNode>(libName);
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::GLOBAL) {
|
||||
consume(TokenType::GLOBAL);
|
||||
std::string type;
|
||||
if (tokens[pos].type == TokenType::INT_KW) type = "int";
|
||||
else if (tokens[pos].type == TokenType::FLOAT_KW) type = "float";
|
||||
else if (tokens[pos].type == TokenType::STRING_KW) type = "string";
|
||||
else if (tokens[pos].type == TokenType::BOOL_KW) type = "bool";
|
||||
pos++;
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
consume(TokenType::ASSIGN);
|
||||
@@ -180,7 +249,7 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
return std::make_unique<GlobalVarDeclNode>(type, name, std::move(expr));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::INT_KW || tokens[pos].type == TokenType::STRING_KW || tokens[pos].type == TokenType::VOID_KW) {
|
||||
if (tokens[pos].type == TokenType::INT_KW || tokens[pos].type == TokenType::FLOAT_KW || tokens[pos].type == TokenType::STRING_KW || tokens[pos].type == TokenType::BOOL_KW || tokens[pos].type == TokenType::VOID_KW) {
|
||||
std::string type = tokens[pos].value; pos++;
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
|
||||
@@ -214,21 +283,56 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
std::unique_ptr<Node> expr = nullptr;
|
||||
if (tokens[pos].type != TokenType::SEMICOLON) expr = expression();
|
||||
consume(TokenType::SEMICOLON);
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<ReturnNode>(std::move(expr));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::WHILE) {
|
||||
consume(TokenType::WHILE); consume(TokenType::LPAREN);
|
||||
auto cond = comparison(); consume(TokenType::RPAREN);
|
||||
auto cond = logicalOr(); consume(TokenType::RPAREN);
|
||||
auto body = parseBlock();
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<WhileNode>(std::move(cond), std::move(body));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::FOR) {
|
||||
consume(TokenType::FOR); consume(TokenType::LPAREN);
|
||||
|
||||
std::unique_ptr<Node> init = nullptr;
|
||||
if (tokens[pos].type != TokenType::SEMICOLON) {
|
||||
init = statement();
|
||||
} else {
|
||||
consume(TokenType::SEMICOLON);
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> cond = nullptr;
|
||||
if (tokens[pos].type != TokenType::SEMICOLON) {
|
||||
cond = comparison();
|
||||
} else {
|
||||
cond = std::make_unique<NumberNode>("1");
|
||||
}
|
||||
consume(TokenType::SEMICOLON);
|
||||
|
||||
std::unique_ptr<Node> step = nullptr;
|
||||
if (tokens[pos].type != TokenType::RPAREN) {
|
||||
if (tokens[pos].type == TokenType::IDENTIFIER && tokens[pos+1].type == TokenType::ASSIGN) {
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
consume(TokenType::ASSIGN);
|
||||
auto expr = expression();
|
||||
step = std::make_unique<VarAssignNode>(name, std::move(expr));
|
||||
} else {
|
||||
step = expression();
|
||||
}
|
||||
}
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
auto body = parseBlock();
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<ForNode>(std::move(init), std::move(cond), std::move(step), std::move(body));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::IF) {
|
||||
consume(TokenType::IF); consume(TokenType::LPAREN);
|
||||
auto cond = comparison(); consume(TokenType::RPAREN);
|
||||
auto cond = logicalOr(); consume(TokenType::RPAREN);
|
||||
auto thenB = parseBlock();
|
||||
std::unique_ptr<Node> elseB = nullptr;
|
||||
if (tokens[pos].type == TokenType::ELSE) {
|
||||
@@ -244,21 +348,24 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
auto expr = expression();
|
||||
consume(TokenType::RPAREN); consume(TokenType::SEMICOLON);
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<PrintNode>(std::move(expr));
|
||||
std::vector<std::unique_ptr<Node>> args;
|
||||
args.push_back(std::move(expr));
|
||||
return std::make_unique<FuncCallNode>("print", std::move(args));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::FOX) {
|
||||
consume(TokenType::FOX); consume(TokenType::LPAREN); consume(TokenType::RPAREN); consume(TokenType::SEMICOLON);
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<FoxNode>();
|
||||
std::vector<std::unique_ptr<Node>> args;
|
||||
return std::make_unique<FuncCallNode>("fox", std::move(args));
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::ARRAY) {
|
||||
consume(TokenType::ARRAY);
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
auto size = expression();
|
||||
int size = std::stoi(consume(TokenType::NUMBER).value);
|
||||
consume(TokenType::SEMICOLON);
|
||||
return std::make_unique<ArrayDeclNode>(name, std::move(size));
|
||||
return std::make_unique<ArrayDeclNode>(name, size);
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::SET) {
|
||||
@@ -278,7 +385,7 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
auto expr = expression();
|
||||
consume(TokenType::SEMICOLON);
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<AssignNode>(name, std::move(expr));
|
||||
return std::make_unique<VarAssignNode>(name, std::move(expr));
|
||||
}
|
||||
if (tokens[pos+1].type == TokenType::LPAREN) {
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
@@ -295,6 +402,17 @@ std::unique_ptr<Node> Parser::statement() {
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<FuncCallNode>(name, std::move(args));
|
||||
}
|
||||
if (tokens[pos+1].type == TokenType::INC) {
|
||||
std::string name = consume(TokenType::IDENTIFIER).value;
|
||||
consume(TokenType::INC);
|
||||
consume(TokenType::SEMICOLON);
|
||||
if (importMode) return std::make_unique<BlockNode>();
|
||||
return std::make_unique<PostIncNode>(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens[pos].type == TokenType::LBRACE) {
|
||||
return parseBlock();
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown statement " + tokens[pos].value);
|
||||
|
||||
+11
-8
@@ -3,29 +3,32 @@
|
||||
#include "AST.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string> // Не забудь
|
||||
#include <string>
|
||||
|
||||
class Parser {
|
||||
std::vector<Token> tokens;
|
||||
size_t pos = 0;
|
||||
|
||||
|
||||
public:
|
||||
Context globalContext;
|
||||
|
||||
// НОВЫЕ ПОЛЯ ДЛЯ ПУТЕЙ И ИМПОРТА
|
||||
|
||||
|
||||
std::string currentFile; // Путь к файлу, который сейчас парсится
|
||||
bool importMode = false; // Если true, то выполняем только объявления (vars/funcs)
|
||||
|
||||
Parser(std::vector<Token> t);
|
||||
|
||||
|
||||
Token consume(TokenType type);
|
||||
std::unique_ptr<Node> primary();
|
||||
std::unique_ptr<Node> multiplication();
|
||||
std::unique_ptr<Node> expression();
|
||||
std::unique_ptr<Node> comparison();
|
||||
std::unique_ptr<Node> logicalAnd();
|
||||
std::unique_ptr<Node> logicalOr();
|
||||
|
||||
std::unique_ptr<Node> statement();
|
||||
std::unique_ptr<BlockNode> parseBlock();
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
void processUsing(const std::string& libName, Context& ctx);
|
||||
void run();
|
||||
};
|
||||
|
||||
+8
-7
@@ -3,17 +3,18 @@
|
||||
|
||||
enum class TokenType {
|
||||
NUMBER, STRING_LITERAL,
|
||||
PLUS, MINUS, STAR, SLASH, MOD,
|
||||
PLUS, MINUS, STAR, SLASH, MOD, INC,
|
||||
LPAREN, RPAREN, LBRACE, RBRACE, LBRACKET, RBRACKET,
|
||||
SEMICOLON, COMMA, ASSIGN,
|
||||
EQ, NEQ, LT, GT,
|
||||
SEMICOLON, COMMA, ASSIGN, DOT, COLON,
|
||||
EQ, NEQ, LT, GT, AND, OR, NOT,
|
||||
|
||||
// Ключевые слова
|
||||
PRINT, INPUT, ROUND, RANDOM, FOX,
|
||||
INT_KW, STRING_KW, VOID_KW, // Типы данных
|
||||
WHILE, IF, ELSE,
|
||||
PRINT, INPUT, ROUND, RANDOM, FOX, READ_FILE, JSON_GET, STR_CONTAINS, STR_TO_INT,
|
||||
INT_KW, FLOAT_KW, STRING_KW, BOOL_KW, VOID_KW, // Типы данных
|
||||
TRUE_KW, FALSE_KW, // Boolean литералы
|
||||
WHILE, FOR, IF, ELSE,
|
||||
ARRAY, SET, GET, SIZE,
|
||||
INCLUDE,
|
||||
INCLUDE, USING, // Подключение файлов
|
||||
|
||||
// НОВЫЕ: возврат и глобальные
|
||||
RETURN, GLOBAL,
|
||||
|
||||
Executable
BIN
Binary file not shown.
+195
@@ -0,0 +1,195 @@
|
||||
// net.fox - Продвинутая сетевая библиотека FoxLang
|
||||
// Подключается через: include("net.fox");
|
||||
|
||||
// === БАЗОВЫЕ СЕТЕВЫЕ ФУНКЦИИ (ЗАГЛУШКИ) ===
|
||||
|
||||
// HTTP GET запрос (встроенная функция)
|
||||
// string http_get(string url) - реализована в интерпретаторе
|
||||
|
||||
// HTTP POST запрос (заглушка)
|
||||
string http_post(string url, string data) {
|
||||
print("http_post not implemented yet");
|
||||
return "";
|
||||
}
|
||||
|
||||
// TCP сокет функции (заглушки)
|
||||
int tcp_socket() {
|
||||
print("tcp_socket not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool tcp_connect(int socket, string host, int port) {
|
||||
print("tcp_connect not implemented yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
void tcp_send(int socket, string message) {
|
||||
print("tcp_send not implemented yet");
|
||||
}
|
||||
|
||||
string tcp_receive(int socket, int size) {
|
||||
print("tcp_receive not implemented yet");
|
||||
return "";
|
||||
}
|
||||
|
||||
void tcp_close(int socket) {
|
||||
print("tcp_close not implemented yet");
|
||||
}
|
||||
|
||||
// === HTTP КЛИЕНТ С УДОБНЫМИ МЕТОДАМИ ===
|
||||
|
||||
// Простой GET с автоматической обработкой ошибок
|
||||
string http_get_simple(string url) {
|
||||
string response = http_get(url);
|
||||
if (response == "") {
|
||||
print("ERROR: Failed to fetch " + url);
|
||||
return "{}";
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// POST с JSON данными
|
||||
string post_json(string url, string json_data) {
|
||||
string response = http_post(url, json_data);
|
||||
if (response == "") {
|
||||
print("ERROR: Failed to POST to " + url);
|
||||
return "{}";
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// Загрузка файла по URL
|
||||
bool download_file(string url, string filename) {
|
||||
string content = http_get_simple(url);
|
||||
if (content == "{}") {
|
||||
return false;
|
||||
}
|
||||
// Здесь должна быть функция записи в файл
|
||||
print("Downloaded " + filename + " from " + url);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Проверка доступности сервера
|
||||
bool ping(string host, int port) {
|
||||
int socket = tcp_socket();
|
||||
bool connected = tcp_connect(socket, host, port);
|
||||
if (connected) {
|
||||
tcp_close(socket);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// === TCP КЛИЕНТ С АВТОМАТИЧЕСКИМ УПРАВЛЕНИЕМ ===
|
||||
|
||||
// Простая отправка сообщения с автозакрытием
|
||||
string send_message(string host, int port, string message) {
|
||||
int socket = tcp_socket();
|
||||
if (!tcp_connect(socket, host, port)) {
|
||||
print("ERROR: Cannot connect to " + host + ":" + port);
|
||||
return "";
|
||||
}
|
||||
|
||||
tcp_send(socket, message);
|
||||
string response = tcp_receive(socket, 1024);
|
||||
tcp_close(socket);
|
||||
return response;
|
||||
}
|
||||
|
||||
// Чат-клиент (отправка и получение)
|
||||
void chat_session(string host, int port) {
|
||||
int socket = tcp_socket();
|
||||
if (!tcp_connect(socket, host, port)) {
|
||||
print("ERROR: Cannot connect to chat server");
|
||||
return;
|
||||
}
|
||||
|
||||
print("Connected to chat! Type 'quit' to exit");
|
||||
string message = "";
|
||||
|
||||
while (message != "quit") {
|
||||
print("You: ");
|
||||
message = input();
|
||||
if (message != "quit") {
|
||||
tcp_send(socket, message);
|
||||
string response = tcp_receive(socket, 1024);
|
||||
print("Server: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
tcp_close(socket);
|
||||
print("Chat session ended");
|
||||
}
|
||||
|
||||
// === API HELPERS ===
|
||||
|
||||
// REST API клиент
|
||||
string api_get(string base_url, string endpoint) {
|
||||
return http_get_simple(base_url + endpoint);
|
||||
}
|
||||
|
||||
string api_post(string base_url, string endpoint, string data) {
|
||||
return post_json(base_url + endpoint, data);
|
||||
}
|
||||
|
||||
// Простой JSON парсер (базовый)
|
||||
string json_get_value(string json, string key) {
|
||||
// Простейший парсер для демонстрации
|
||||
string search = "\"" + key + "\":";
|
||||
// Здесь должна быть реальная логика парсинга
|
||||
return "value";
|
||||
}
|
||||
|
||||
// === УТИЛИТЫ ===
|
||||
|
||||
// Проверка интернет-соединения
|
||||
bool is_online() {
|
||||
return ping("8.8.8.8", 53); // Google DNS
|
||||
}
|
||||
|
||||
// Получение публичного IP
|
||||
string get_public_ip() {
|
||||
return http_get_simple("https://api.ipify.org");
|
||||
}
|
||||
|
||||
// Отправка webhook
|
||||
bool send_webhook(string url, string message) {
|
||||
string json = "{\"text\":\"" + message + "\"}";
|
||||
string response = post_json(url, json);
|
||||
return response != "{}";
|
||||
}
|
||||
|
||||
// === ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ ===
|
||||
|
||||
void demo_http() {
|
||||
print("=== HTTP Demo ===");
|
||||
|
||||
if (is_online()) {
|
||||
print("Internet connection: OK");
|
||||
string ip = get_public_ip();
|
||||
print("Your IP: " + ip);
|
||||
|
||||
string weather = http_get_simple("https://api.weather.com/current");
|
||||
print("Weather data: " + weather);
|
||||
} else {
|
||||
print("No internet connection");
|
||||
}
|
||||
}
|
||||
|
||||
void demo_tcp() {
|
||||
print("=== TCP Demo ===");
|
||||
|
||||
if (ping("localhost", 8080)) {
|
||||
print("Server is running on localhost:8080");
|
||||
string response = send_message("localhost", 8080, "Hello Server!");
|
||||
print("Server response: " + response);
|
||||
} else {
|
||||
print("Server not available");
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск демо
|
||||
void net_demo() {
|
||||
demo_http();
|
||||
demo_tcp();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// net.fox - Простая сетевая библиотека FoxLang
|
||||
|
||||
// HTTP POST запрос (заглушка)
|
||||
string http_post(string url, string data) {
|
||||
print("http_post not implemented yet");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Простой GET с обработкой ошибок
|
||||
string get_url(string url) {
|
||||
string response = http_get(url);
|
||||
if (response == "") {
|
||||
print("ERROR: Failed to fetch " + url);
|
||||
return "{}";
|
||||
}
|
||||
return response;
|
||||
}
|
||||
Reference in New Issue
Block a user