Фиксация мамы нолнан с сфере IT с симпатией к атусу стоещему на полигоне

с афроо лошадьми
This commit is contained in:
SkrinVex
2026-01-20 22:04:44 +05:00
parent 024444abdb
commit 4365a50cda
45 changed files with 2941 additions and 470 deletions
+412 -135
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
Binary file not shown.
+195
View File
@@ -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();
}
+17
View File
@@ -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;
}