upd lang and workflow
This commit is contained in:
+45
-16
@@ -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 }}
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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", ""};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user