upd lang and workflow

This commit is contained in:
SkrinVex
2026-02-05 15:11:05 +05:00
parent db71acacdd
commit d0e3601b48
3 changed files with 117 additions and 105 deletions
+45 -16
View File
@@ -1,46 +1,75 @@
name: Build FoxLang name: Build and Release FoxLang
on: on:
push: push:
branches: ["main", "master"] branches: ["main"]
pull_request: tags:
branches: ["main", "master"] - "v*" # Срабатывает, когда ты пушишь тег, например v5.0.2
permissions:
contents: write # Разрешаем создавать релизы
jobs: jobs:
# --- Сборка для Linux (Ubuntu) --- # --- 1. Сборка Linux ---
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - uses: actions/checkout@v4
uses: actions/checkout@v4
- name: Compile with G++ - name: Compile with G++
run: | run: |
g++ -std=c++17 src/main.cpp src/Lexer.cpp src/Parser.cpp -o foxlang # Создаем папку build, чтобы туда сложить бинарник
mkdir build
g++ -std=c++17 src/main.cpp src/Lexer.cpp src/Parser.cpp -o build/foxlang
- name: Upload Linux Artifact - name: Upload Linux Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: foxlang-linux name: foxlang-linux
path: foxlang path: build/foxlang
# --- Сборка для Windows (MSVC) --- # --- 2. Сборка Windows ---
build-windows: build-windows:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: Checkout code - uses: actions/checkout@v4
uses: actions/checkout@v4
- name: Setup MSVC - name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1 uses: ilammy/msvc-dev-cmd@v1
- name: Compile with CL (MSVC) - name: Compile with CL
# Используем флаги: /EHsc (обработка исключений), /std:c++17, /Fe (имя выходного файла) # Добавил создание папки build для порядка
run: | run: |
cl /EHsc /std:c++17 src/main.cpp src/Lexer.cpp src/Parser.cpp /Fefoxlang.exe mkdir build
cl /EHsc /std:c++17 src/main.cpp src/Lexer.cpp src/Parser.cpp /Febuild/foxlang.exe
- name: Upload Windows Artifact - name: Upload Windows Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: foxlang-windows name: foxlang-windows
path: foxlang.exe path: build/foxlang.exe
# --- 3. Публикация Релиза (Только если есть тег) ---
release:
needs: [build-linux, build-windows] # Ждем окончания сборок
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Download Linux Artifact
uses: actions/download-artifact@v4
with:
name: foxlang-linux
- name: Download Windows Artifact
uses: actions/download-artifact@v4
with:
name: foxlang-windows
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
foxlang
foxlang.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-23
View File
@@ -1,23 +0,0 @@
name: C/C++ CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
- name: make distcheck
run: make distcheck
+72 -66
View File
@@ -19,6 +19,12 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#ifdef _WIN32
#include <cstdio>
#define popen _popen
#define pclose _pclose
#endif
struct Node; struct Node;
struct FuncParam { struct FuncParam {
@@ -48,7 +54,7 @@ struct Context {
if (parent) return parent->getVar(name); if (parent) return parent->getVar(name);
throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!"); throw std::runtime_error("Runtime Error: Variable '" + name + "' not found!");
} }
std::vector<Value>& getArray(const std::string& name) { std::vector<Value>& getArray(const std::string& name) {
if (arrays.count(name)) return arrays[name]; if (arrays.count(name)) return arrays[name];
if (parent) return parent->getArray(name); if (parent) return parent->getArray(name);
@@ -70,9 +76,9 @@ struct Context {
} }
void setVar(const std::string& name, Value val) { void setVar(const std::string& name, Value val) {
if (variables.count(name)) { if (variables.count(name)) {
variables[name].value = val.value; variables[name].value = val.value;
return; return;
} }
if (parent) { parent->setVar(name, val); return; } if (parent) { parent->setVar(name, val); return; }
throw std::runtime_error("Error: Variable '" + name + "' not defined!"); throw std::runtime_error("Error: Variable '" + name + "' not defined!");
@@ -104,7 +110,7 @@ struct FuncDefNode : Node {
std::vector<FuncParam> params; std::vector<FuncParam> params;
std::shared_ptr<Node> body; std::shared_ptr<Node> body;
FuncDefNode(std::string rt, std::string n, std::vector<FuncParam> p, std::shared_ptr<Node> b) FuncDefNode(std::string rt, std::string n, std::vector<FuncParam> p, std::shared_ptr<Node> b)
: returnType(rt), name(n), params(p), body(b) {} : returnType(rt), name(n), params(p), body(b) {}
Value eval(Context& ctx) override { return {"void", ""}; } Value eval(Context& ctx) override { return {"void", ""}; }
@@ -115,7 +121,7 @@ struct ReturnNode : Node {
ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {} ReturnNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
Value result = expr ? expr->eval(ctx) : Value{"void", ""}; Value result = expr ? expr->eval(ctx) : Value{"void", ""};
throw ReturnValue{result}; throw ReturnValue{result};
} }
}; };
@@ -123,7 +129,7 @@ struct FuncCallNode : Node {
std::string name; std::string name;
std::vector<std::unique_ptr<Node>> args; std::vector<std::unique_ptr<Node>> args;
FuncCallNode(std::string n, std::vector<std::unique_ptr<Node>> a) FuncCallNode(std::string n, std::vector<std::unique_ptr<Node>> a)
: name(n), args(std::move(a)) {} : name(n), args(std::move(a)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
@@ -145,7 +151,7 @@ struct FuncCallNode : Node {
// Вывести приглашение // Вывести приглашение
std::cout << args[0]->eval(ctx).value; std::cout << args[0]->eval(ctx).value;
} }
std::string input; std::string input;
std::getline(std::cin, input); std::getline(std::cin, input);
return {"string", input}; return {"string", input};
} }
@@ -200,24 +206,24 @@ struct FuncCallNode : Node {
if (filenameVal.type != "string") { if (filenameVal.type != "string") {
throw std::runtime_error("read_file() requires string filename"); throw std::runtime_error("read_file() requires string filename");
} }
std::ifstream file(filenameVal.value); std::ifstream file(filenameVal.value);
if (!file.is_open()) { if (!file.is_open()) {
return {"string", ""}; // Возвращаем пустую строку при ошибке return {"string", ""}; // Возвращаем пустую строку при ошибке
} }
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
// Пропускаем комментарии и пустые строки // Пропускаем комментарии и пустые строки
if (line.empty() || line[0] == '#') continue; if (line.empty() || line[0] == '#') continue;
// Если строка не пустая и не комментарий, возвращаем её // Если строка не пустая и не комментарий, возвращаем её
if (!line.empty()) { if (!line.empty()) {
file.close(); file.close();
return {"string", line}; return {"string", line};
} }
} }
file.close(); file.close();
return {"string", ""}; return {"string", ""};
} }
@@ -226,30 +232,30 @@ struct FuncCallNode : Node {
if (urlVal.type != "string") { if (urlVal.type != "string") {
throw std::runtime_error("http_get() requires string URL"); throw std::runtime_error("http_get() requires string URL");
} }
// Простая реализация через system curl // Простая реализация через system curl
std::string cmd = "curl -s \"" + urlVal.value + "\""; std::string cmd = "curl -s \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) { if (!pipe) {
return {"string", ""}; return {"string", ""};
} }
std::string result; std::string result;
char buffer[128]; char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer; result += buffer;
} }
pclose(pipe); pclose(pipe);
return {"string", result}; return {"string", result};
} }
if (name == "json_get" && args.size() == 2) { if (name == "json_get" && args.size() == 2) {
Value jsonVal = args[0]->eval(ctx); Value jsonVal = args[0]->eval(ctx);
Value keyVal = args[1]->eval(ctx); Value keyVal = args[1]->eval(ctx);
std::string json = jsonVal.value; std::string json = jsonVal.value;
std::string key = keyVal.value; std::string key = keyVal.value;
// Простой JSON парсер для Telegram API // Простой JSON парсер для Telegram API
if (key == "chat_id") { if (key == "chat_id") {
size_t pos = json.find("\"chat\":{\"id\":"); size_t pos = json.find("\"chat\":{\"id\":");
@@ -279,7 +285,7 @@ struct FuncCallNode : Node {
lastPos = pos; lastPos = pos;
pos = json.find("\"update_id\":", pos + 1); pos = json.find("\"update_id\":", pos + 1);
} }
if (lastPos != 0) { if (lastPos != 0) {
lastPos += 12; // длина "\"update_id\":" lastPos += 12; // длина "\"update_id\":"
size_t end = json.find(",", lastPos); size_t end = json.find(",", lastPos);
@@ -288,16 +294,16 @@ struct FuncCallNode : Node {
} }
} }
} }
return {"string", ""}; return {"string", ""};
} }
if (name == "str_contains" && args.size() == 2) { if (name == "str_contains" && args.size() == 2) {
Value textVal = args[0]->eval(ctx); Value textVal = args[0]->eval(ctx);
Value substrVal = args[1]->eval(ctx); Value substrVal = args[1]->eval(ctx);
std::string text = textVal.value; std::string text = textVal.value;
std::string substr = substrVal.value; std::string substr = substrVal.value;
bool found = text.find(substr) != std::string::npos; bool found = text.find(substr) != std::string::npos;
return {"bool", found ? "true" : "false"}; return {"bool", found ? "true" : "false"};
} }
@@ -306,7 +312,7 @@ struct FuncCallNode : Node {
if (strVal.type != "string") { if (strVal.type != "string") {
return {"int", "0"}; return {"int", "0"};
} }
try { try {
int result = std::stoi(strVal.value); int result = std::stoi(strVal.value);
return {"int", std::to_string(result)}; return {"int", std::to_string(result)};
@@ -319,7 +325,7 @@ struct FuncCallNode : Node {
std::string cmd = "curl -s \"" + urlVal.value + "\""; std::string cmd = "curl -s \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""}; if (!pipe) return {"string", ""};
std::string result; std::string result;
char buffer[128]; char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
@@ -332,11 +338,11 @@ struct FuncCallNode : Node {
Value urlVal = args[0]->eval(ctx); Value urlVal = args[0]->eval(ctx);
Value dataVal = args[1]->eval(ctx); Value dataVal = args[1]->eval(ctx);
std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json"; std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json";
std::string cmd = "curl -s -X POST -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\""; std::string cmd = "curl -s -X POST -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""}; if (!pipe) return {"string", ""};
std::string result; std::string result;
char buffer[128]; char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
@@ -349,11 +355,11 @@ struct FuncCallNode : Node {
Value urlVal = args[0]->eval(ctx); Value urlVal = args[0]->eval(ctx);
Value dataVal = args[1]->eval(ctx); Value dataVal = args[1]->eval(ctx);
std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json"; std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json";
std::string cmd = "curl -s -X PUT -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\""; std::string cmd = "curl -s -X PUT -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""}; if (!pipe) return {"string", ""};
std::string result; std::string result;
char buffer[128]; char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
@@ -367,7 +373,7 @@ struct FuncCallNode : Node {
std::string cmd = "curl -s -X DELETE \"" + urlVal.value + "\""; std::string cmd = "curl -s -X DELETE \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""}; if (!pipe) return {"string", ""};
std::string result; std::string result;
char buffer[128]; char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
@@ -380,38 +386,38 @@ struct FuncCallNode : Node {
// FastAPI-подобные функции // FastAPI-подобные функции
if (name == "server_start" && args.size() == 1) { if (name == "server_start" && args.size() == 1) {
int port = std::stoi(args[0]->eval(ctx).value); int port = std::stoi(args[0]->eval(ctx).value);
// Простая заглушка сервера // Простая заглушка сервера
std::cout << "HTTP Server started on port " << port << std::endl; std::cout << "HTTP Server started on port " << port << std::endl;
std::cout << "Note: This is a simulation. Real server implementation requires additional setup." << std::endl; std::cout << "Note: This is a simulation. Real server implementation requires additional setup." << std::endl;
return {"string", "Server started on port " + std::to_string(port)}; return {"string", "Server started on port " + std::to_string(port)};
} }
if (name == "server_stop" && args.size() == 0) { if (name == "server_stop" && args.size() == 0) {
std::cout << "HTTP Server stopped" << std::endl; std::cout << "HTTP Server stopped" << std::endl;
return {"string", "Server stopped"}; return {"string", "Server stopped"};
} }
if (name == "route_get" && args.size() == 2) { if (name == "route_get" && args.size() == 2) {
Value pathVal = args[0]->eval(ctx); Value pathVal = args[0]->eval(ctx);
Value handlerVal = args[1]->eval(ctx); Value handlerVal = args[1]->eval(ctx);
std::cout << "Registered GET route: " << pathVal.value << " -> " << handlerVal.value << std::endl; std::cout << "Registered GET route: " << pathVal.value << " -> " << handlerVal.value << std::endl;
return {"string", "GET route registered: " + pathVal.value}; return {"string", "GET route registered: " + pathVal.value};
} }
if (name == "route_post" && args.size() == 2) { if (name == "route_post" && args.size() == 2) {
Value pathVal = args[0]->eval(ctx); Value pathVal = args[0]->eval(ctx);
Value handlerVal = args[1]->eval(ctx); Value handlerVal = args[1]->eval(ctx);
std::cout << "Registered POST route: " << pathVal.value << " -> " << handlerVal.value << std::endl; std::cout << "Registered POST route: " << pathVal.value << " -> " << handlerVal.value << std::endl;
return {"string", "POST route registered: " + pathVal.value}; return {"string", "POST route registered: " + pathVal.value};
} }
if (name == "send_response" && args.size() == 1) { if (name == "send_response" && args.size() == 1) {
Value responseVal = args[0]->eval(ctx); Value responseVal = args[0]->eval(ctx);
std::cout << "HTTP Response: " << responseVal.value << std::endl; std::cout << "HTTP Response: " << responseVal.value << std::endl;
return {"void", ""}; return {"void", ""};
} }
@@ -421,9 +427,9 @@ struct FuncCallNode : Node {
if (!funcNodeBase) { if (!funcNodeBase) {
throw std::runtime_error("Runtime Error: Function '" + name + "' not found!"); throw std::runtime_error("Runtime Error: Function '" + name + "' not found!");
} }
FuncDefNode* funcDef = static_cast<FuncDefNode*>(funcNodeBase.get()); FuncDefNode* funcDef = static_cast<FuncDefNode*>(funcNodeBase.get());
if (args.size() != funcDef->params.size()) { if (args.size() != funcDef->params.size()) {
throw std::runtime_error("Args count mismatch for '" + name + "'"); throw std::runtime_error("Args count mismatch for '" + name + "'");
} }
@@ -441,7 +447,7 @@ struct FuncCallNode : Node {
try { try {
funcDef->body->eval(funcScope); funcDef->body->eval(funcScope);
} catch (const ReturnValue& ret) { } catch (const ReturnValue& ret) {
return ret.value; return ret.value;
} }
return {"void", ""}; return {"void", ""};
@@ -478,7 +484,7 @@ struct VarAccessNode : Node {
struct VarDeclNode : Node { struct VarDeclNode : Node {
std::string type, name; std::string type, name;
std::unique_ptr<Node> expr; std::unique_ptr<Node> expr;
VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) VarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
: type(t), name(n), expr(std::move(e)) {} : type(t), name(n), expr(std::move(e)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
ctx.defineVar(name, type, expr->eval(ctx)); ctx.defineVar(name, type, expr->eval(ctx));
@@ -489,7 +495,7 @@ struct VarDeclNode : Node {
struct GlobalVarDeclNode : Node { struct GlobalVarDeclNode : Node {
std::string type, name; std::string type, name;
std::unique_ptr<Node> expr; std::unique_ptr<Node> expr;
GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e) GlobalVarDeclNode(std::string t, std::string n, std::unique_ptr<Node> e)
: type(t), name(n), expr(std::move(e)) {} : type(t), name(n), expr(std::move(e)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
Context* root = &ctx; Context* root = &ctx;
@@ -512,13 +518,13 @@ struct VarAssignNode : Node {
struct BinOpNode : Node { struct BinOpNode : Node {
char op; char op;
std::unique_ptr<Node> left, right; std::unique_ptr<Node> left, right;
BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r) BinOpNode(char o, std::unique_ptr<Node> l, std::unique_ptr<Node> r)
: op(o), left(std::move(l)), right(std::move(r)) {} : op(o), left(std::move(l)), right(std::move(r)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
Value lval = left->eval(ctx); Value lval = left->eval(ctx);
Value rval = right->eval(ctx); Value rval = right->eval(ctx);
if (op == '+') { if (op == '+') {
if (lval.type == "string" || rval.type == "string") { if (lval.type == "string" || rval.type == "string") {
return {"string", lval.value + rval.value}; return {"string", lval.value + rval.value};
@@ -530,24 +536,24 @@ struct BinOpNode : Node {
int l = std::stoi(lval.value), r = std::stoi(rval.value); int l = std::stoi(lval.value), r = std::stoi(rval.value);
return {"int", std::to_string(l + r)}; return {"int", std::to_string(l + r)};
} }
if (op == '-' || op == '*' || op == '/' || op == '%') { if (op == '-' || op == '*' || op == '/' || op == '%') {
if (lval.type == "float" || rval.type == "float") { if (lval.type == "float" || rval.type == "float") {
double l = std::stod(lval.value), r = std::stod(rval.value); double l = std::stod(lval.value), r = std::stod(rval.value);
double result = (op == '-') ? l - r : (op == '*') ? l * r : double result = (op == '-') ? l - r : (op == '*') ? l * r :
(op == '/') ? l / r : std::fmod(l, r); (op == '/') ? l / r : std::fmod(l, r);
return {"float", formatNumber(result)}; return {"float", formatNumber(result)};
} }
int l = std::stoi(lval.value), r = std::stoi(rval.value); int l = std::stoi(lval.value), r = std::stoi(rval.value);
int result = (op == '-') ? l - r : (op == '*') ? l * r : int result = (op == '-') ? l - r : (op == '*') ? l * r :
(op == '/') ? l / r : l % r; (op == '/') ? l / r : l % r;
return {"int", std::to_string(result)}; return {"int", std::to_string(result)};
} }
if (op == '=' || op == '!' || op == '<' || op == '>') { if (op == '=' || op == '!' || op == '<' || op == '>') {
bool result; bool result;
if (lval.type == "string" && rval.type == "string") { if (lval.type == "string" && rval.type == "string") {
result = (op == '=') ? lval.value == rval.value : result = (op == '=') ? lval.value == rval.value :
(op == '!') ? lval.value != rval.value : (op == '!') ? lval.value != rval.value :
(op == '<') ? lval.value < rval.value : lval.value > rval.value; (op == '<') ? lval.value < rval.value : lval.value > rval.value;
} else { } else {
@@ -557,13 +563,13 @@ struct BinOpNode : Node {
} }
return {"bool", result ? "true" : "false"}; return {"bool", result ? "true" : "false"};
} }
if (op == '&' || op == '|') { if (op == '&' || op == '|') {
bool l = (lval.value == "true"), r = (rval.value == "true"); bool l = (lval.value == "true"), r = (rval.value == "true");
bool result = (op == '&') ? l && r : l || r; bool result = (op == '&') ? l && r : l || r;
return {"bool", result ? "true" : "false"}; return {"bool", result ? "true" : "false"};
} }
return {"void", ""}; return {"void", ""};
} }
}; };
@@ -606,7 +612,7 @@ struct ArrayDeclNode : Node {
struct ArraySetNode : Node { struct ArraySetNode : Node {
std::string name; std::string name;
std::unique_ptr<Node> index, value; std::unique_ptr<Node> index, value;
ArraySetNode(std::string n, std::unique_ptr<Node> i, std::unique_ptr<Node> v) ArraySetNode(std::string n, std::unique_ptr<Node> i, std::unique_ptr<Node> v)
: name(n), index(std::move(i)), value(std::move(v)) {} : name(n), index(std::move(i)), value(std::move(v)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
int idx = std::stoi(index->eval(ctx).value); int idx = std::stoi(index->eval(ctx).value);
@@ -635,7 +641,7 @@ struct BlockNode : Node {
struct IfNode : Node { struct IfNode : Node {
std::unique_ptr<Node> condition, thenB, elseB; std::unique_ptr<Node> condition, thenB, elseB;
IfNode(std::unique_ptr<Node> c, std::unique_ptr<Node> t, std::unique_ptr<Node> e = nullptr) 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)) {} : condition(std::move(c)), thenB(std::move(t)), elseB(std::move(e)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
bool cond = (condition->eval(ctx).value == "true"); bool cond = (condition->eval(ctx).value == "true");
@@ -647,7 +653,7 @@ struct IfNode : Node {
struct WhileNode : Node { struct WhileNode : Node {
std::unique_ptr<Node> condition, body; std::unique_ptr<Node> condition, body;
WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b) WhileNode(std::unique_ptr<Node> c, std::unique_ptr<Node> b)
: condition(std::move(c)), body(std::move(b)) {} : condition(std::move(c)), body(std::move(b)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
while (condition->eval(ctx).value == "true") { while (condition->eval(ctx).value == "true") {
@@ -665,7 +671,7 @@ struct WhileNode : Node {
struct ForNode : Node { struct ForNode : Node {
std::unique_ptr<Node> init, condition, step, body; 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) 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)) {} : init(std::move(i)), condition(std::move(c)), step(std::move(s)), body(std::move(b)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
if (init) init->eval(ctx); if (init) init->eval(ctx);
@@ -709,14 +715,14 @@ struct SwitchNode : Node {
std::unique_ptr<Node> expr; std::unique_ptr<Node> expr;
std::vector<std::pair<std::unique_ptr<Node>, std::unique_ptr<Node>>> cases; // value, body std::vector<std::pair<std::unique_ptr<Node>, std::unique_ptr<Node>>> cases; // value, body
std::unique_ptr<Node> defaultCase; std::unique_ptr<Node> defaultCase;
SwitchNode(std::unique_ptr<Node> e) : expr(std::move(e)) {} SwitchNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
Value switchValue = expr->eval(ctx); Value switchValue = expr->eval(ctx);
bool executed = false; bool executed = false;
bool fallthrough = false; bool fallthrough = false;
for (auto& caseItem : cases) { for (auto& caseItem : cases) {
if (!executed && !fallthrough) { if (!executed && !fallthrough) {
Value caseValue = caseItem.first->eval(ctx); Value caseValue = caseItem.first->eval(ctx);
@@ -725,7 +731,7 @@ struct SwitchNode : Node {
fallthrough = true; fallthrough = true;
} }
} }
if (fallthrough) { if (fallthrough) {
try { try {
caseItem.second->eval(ctx); caseItem.second->eval(ctx);
@@ -735,11 +741,11 @@ struct SwitchNode : Node {
} }
} }
} }
if (!executed && defaultCase) { if (!executed && defaultCase) {
defaultCase->eval(ctx); defaultCase->eval(ctx);
} }
return {"void", ""}; return {"void", ""};
} }
}; };
@@ -754,32 +760,32 @@ struct InputNode : Node {
struct ReadFileNode : Node { struct ReadFileNode : Node {
std::unique_ptr<Node> filename; std::unique_ptr<Node> filename;
ReadFileNode(std::unique_ptr<Node> fn) : filename(std::move(fn)) {} ReadFileNode(std::unique_ptr<Node> fn) : filename(std::move(fn)) {}
Value eval(Context& ctx) override { Value eval(Context& ctx) override {
Value filenameVal = filename->eval(ctx); Value filenameVal = filename->eval(ctx);
if (filenameVal.type != "string") { if (filenameVal.type != "string") {
throw std::runtime_error("read_file() requires string filename"); throw std::runtime_error("read_file() requires string filename");
} }
std::ifstream file(filenameVal.value); std::ifstream file(filenameVal.value);
if (!file.is_open()) { if (!file.is_open()) {
return {"string", ""}; // Возвращаем пустую строку при ошибке return {"string", ""}; // Возвращаем пустую строку при ошибке
} }
std::string content; std::string content;
std::string line; std::string line;
bool first = true; bool first = true;
while (std::getline(file, line)) { while (std::getline(file, line)) {
// Пропускаем комментарии и пустые строки // Пропускаем комментарии и пустые строки
if (line.empty() || line[0] == '#') continue; if (line.empty() || line[0] == '#') continue;
// Если строка не пустая и не комментарий, возвращаем её // Если строка не пустая и не комментарий, возвращаем её
if (!line.empty()) { if (!line.empty()) {
file.close(); file.close();
return {"string", line}; return {"string", line};
} }
} }
file.close(); file.close();
return {"string", ""}; return {"string", ""};
} }